Commit e6e58286 by wusiyi

fix: 修复查询订单有中文报错问题

parent 31c91d05
### 前言: ### 前言:
本文讲述 Vue 3.0 + Electron + Express + Lowdb 框架搭建过程, 以及少量示例代码; 本文讲述 Vue 3.0 + Electron + Express + Lowdb 框架搭建过程, 以及少量示例代码;
重点讲解框架部分如何衔接和配合形成一个整体: 重点讲解框架部分如何衔接和配合形成一个整体:
顺序: 顺序:
1. 先保证让Vue的Web形式能正常运行 1. 先保证让 Vue 的 Web 形式能正常运行
2. 通过Electron给Vue套一层App外壳, 变为App程序 2. 通过 Electron 给 Vue 套一层 App 外壳, 变为 App 程序
3. 部署Express充当Vue+Electron的Web Restful Api后端, 并通过Lowdb记录一些App的系统设置信息到文件中, 以便于下一次启动时仍能访问(不同于Browser端保存)。 3. 部署 Express 充当 Vue+Electron 的 Web Restful Api 后端, 并通过 Lowdb 记录一些 App 的系统设置信息到文件中, 以便于下一次启动时仍能访问(不同于 Browser 端保存)。
4. 让Vue+Electron+Express三者共同协作, 看起来是某一个云上服务的App形式的Client端。 4. 让 Vue+Electron+Express 三者共同协作, 看起来是某一个云上服务的 App 形式的 Client 端。
### 准备部分: ### 准备部分:
- 安装node.js - 安装 node.js
```shell ```shell
官网下载安装 官网下载安装
https://nodejs.org/zh-cn/ https://nodejs.org/zh-cn/
安装完毕查看版本号: 安装完毕查看版本号:
node -v node -v
``` ```
- 设置npm代理
- 设置 npm 代理
- (推荐) 使用淘宝镜像: - (推荐) 使用淘宝镜像:
```shell ```shell
npm config set proxy http://"username:pass"@server:port npm config set proxy http://"username:pass"@server:port
...@@ -34,10 +33,9 @@ ...@@ -34,10 +33,9 @@
npm config set registry=https://registry.npm.taobao.org npm config set registry=https://registry.npm.taobao.org
``` ```
* 安装 vue-cli3:
- 安装 vue-cli3: ```shell
``` shell
# 卸载1.x或2.x旧版本 # 卸载1.x或2.x旧版本
npm uninstall vue-cli-g npm uninstall vue-cli-g
# 安装@vue/cli ( 即 vue-cli3 ) # 安装@vue/cli ( 即 vue-cli3 )
...@@ -46,8 +44,6 @@ ...@@ -46,8 +44,6 @@
vue -V vue -V
``` ```
### 前端部分(Vue3.0) ### 前端部分(Vue3.0)
- 创建项目 - 创建项目
...@@ -65,79 +61,79 @@ ...@@ -65,79 +61,79 @@
npm run serve npm run serve
``` ```
访问 localhost:8080 出现web界面, 即为OK 访问 localhost:8080 出现 web 界面, 即为 OK
- 增加 ElementUI支持 - 增加 ElementUI 支持
```shell ```shell
npm install -S element-ui npm install -S element-ui
``` ```
- 增加 axios 支持, 用于前端发起ajax请求 - 增加 axios 支持, 用于前端发起 ajax 请求
```shell ```shell
npm install -S axios npm install -S axios
``` ```
- 增加normalize.css 支持, 用户前端页面整体的规整化 - 增加 normalize.css 支持, 用户前端页面整体的规整化
```shell ```shell
npm install -S normalize.css npm install -S normalize.css
``` ```
- 增加 pug/jade 的HTML模板语法支持: - 增加 pug/jade 的 HTML 模板语法支持:
```shell ```shell
npm install -D pug pug-html-loader pug-plain-loader npm install -D pug pug-html-loader pug-plain-loader
``` ```
- 增加 sass/scss 的CSS模板语法支持支持: - 增加 sass/scss 的 CSS 模板语法支持支持:
```shell ```shell
npm install -D node-sass sass-loader npm install -D node-sass sass-loader
``` ```
- 生成 src/styles/main.scss 和 src/styles/config.css, 作为预装载全局css定义 - 生成 src/styles/main.scss 和 src/styles/config.css, 作为预装载全局 css 定义
main.scss: 内容暂时为空,仅仅引入 config.scss, 后续根据业务需要添加 main.scss: 内容暂时为空,仅仅引入 config.scss, 后续根据业务需要添加
```scss ```scss
// 全局CSS常量定义 // 全局CSS常量定义
@import "./config.scss"; @import './config.scss';
// 所有修改element-ui的样式, 以避免单页面scoped中修改权限不够的问题 // 所有修改element-ui的样式, 以避免单页面scoped中修改权限不够的问题
//@import "./elementui.scss" //@import "./elementui.scss"
``` ```
config.scss: 内容暂时为空, 后续根据需要业务添加 config.scss: 内容暂时为空, 后续根据需要业务添加
```scss ```scss
// 定义全局CSS常亮, 便于在各CSS中统一共享 // 定义全局CSS常亮, 便于在各CSS中统一共享
``` ```
- 增加 Vue 3.0 @vue/composition-api 支持 - 增加 Vue 3.0 @vue/composition-api 支持
```shell ```shell
npm install -S @vue/composition-api npm install -S @vue/composition-api
``` ```
- 修改 src/main.js, 其中的 行首 + 表示为新增行, - 表示删除行, M 表示修改行( 下同, 不赘述) - 修改 src/main.js, 其中的 行首 + 表示为新增行, - 表示删除行, M 表示修改行( 下同, 不赘述)
```javascript ```javascript
import Vue from "vue"; import Vue from "vue";
import App from "./App.vue"; import App from "./App.vue";
import router from "./router"; import router from "./router";
import store from "./store"; import store from "./store";
+ import "normalize.css"; + import "normalize.css";
+ import ElementUI from 'element-ui'; + import ElementUI from 'element-ui';
+ import 'element-ui/lib/theme-chalk/index.css'; + import 'element-ui/lib/theme-chalk/index.css';
+ import VueCompositionApi from "@vue/composition-api"; + import VueCompositionApi from "@vue/composition-api";
+ Vue.use(ElementUI); + Vue.use(ElementUI);
+ Vue.use(VueCompositionApi); + Vue.use(VueCompositionApi);
Vue.config.productionTip = false; Vue.config.productionTip = false;
new Vue({ new Vue({
router, router,
store, store,
...@@ -150,115 +146,114 @@ ...@@ -150,115 +146,114 @@
```shell ```shell
npm run serve npm run serve
``` ```
访问浏览器地址展示默认Vue Web 界面 访问浏览器地址展示默认 Vue Web 界面
- 手工生成vue.config.js - 手工生成 vue.config.js
```javascript ```javascript
const path = require("path"); const path = require('path')
module.exports = { module.exports = {
// 基本路径 // 基本路径
publicPath: process.env.NODE_ENV === "production" ? "" : "/", publicPath: process.env.NODE_ENV === 'production' ? '' : '/',
// 输出文件目录 // 输出文件目录
outputDir: process.env.NODE_ENV === "production" ? "dist" : "devdist", outputDir: process.env.NODE_ENV === 'production' ? 'dist' : 'devdist',
// eslint-loader 是否在保存的时候检查 // eslint-loader 是否在保存的时候检查
lintOnSave: false, lintOnSave: false,
/** vue3.0内置了webpack所有东西, /** vue3.0内置了webpack所有东西,
* webpack配置,see https://github.com/vuejs/vue-cli/blob/dev/docs/webpack.md * webpack配置,see https://github.com/vuejs/vue-cli/blob/dev/docs/webpack.md
**/ **/
chainWebpack: config => { chainWebpack: (config) => {
const svgRule = config.module.rule("svg"); const svgRule = config.module.rule('svg')
svgRule.uses.clear(); svgRule.uses.clear()
svgRule svgRule
.use("svg-sprite-loader") .use('svg-sprite-loader')
.loader("svg-sprite-loader") .loader('svg-sprite-loader')
.options({ .options({
symbolId: "icon-[name]", symbolId: 'icon-[name]',
include: ["./src/icons" ] include: ['./src/icons'],
}); })
config.module config.module
.rule("pug") .rule('pug')
.test(/\.pug$/) .test(/\.pug$/)
.use("pug-html-loader") .use('pug-html-loader')
.loader("pug-html-loader") .loader('pug-html-loader')
.end(); .end()
}, },
configureWebpack: config => { configureWebpack: (config) => {
config.resolve = { config.resolve = {
// 配置解析别名 // 配置解析别名
extensions: [".js", ".json", ".vue"], // 自动添加文件名后缀 extensions: ['.js', '.json', '.vue'], // 自动添加文件名后缀
alias: { alias: {
vue: "vue/dist/vue.js", vue: 'vue/dist/vue.js',
"@": path.resolve(__dirname, "./src"), '@': path.resolve(__dirname, './src'),
"@c": path.resolve(__dirname, "./src/components") '@c': path.resolve(__dirname, './src/components'),
} },
}; }
}, },
// 生产环境是否生成 sourceMap 文件 // 生产环境是否生成 sourceMap 文件
productionSourceMap: false, productionSourceMap: false,
// css相关配置 // css相关配置
css: { css: {
// 是否使用css分离插件 ExtractTextPlugin // 是否使用css分离插件 ExtractTextPlugin
extract: true, extract: true,
// 开启 CSS source maps? // 开启 CSS source maps?
sourceMap: false, sourceMap: false,
// css预设器配置项 // css预设器配置项
loaderOptions: { loaderOptions: {
sass: { sass: {
prependData: `@import "./src/styles/main.scss";` prependData: `@import "./src/styles/main.scss";`,
} },
}, },
// 启用 CSS modules for all css / pre-processor files. // 启用 CSS modules for all css / pre-processor files.
requireModuleExtension: true, // 是否开启支持‘foo.module.css’样式 requireModuleExtension: true, // 是否开启支持‘foo.module.css’样式
}, },
// use thread-loader for babel & TS in production build // use thread-loader for babel & TS in production build
// enabled by default if the machine has more than 1 cores // enabled by default if the machine has more than 1 cores
parallel: require("os").cpus().length > 1, parallel: require('os').cpus().length > 1,
/** /**
* PWA 插件相关配置,see https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa * PWA 插件相关配置,see https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa
*/ */
pwa: {}, pwa: {},
// webpack-dev-server 相关配置 // webpack-dev-server 相关配置
devServer: { devServer: {
open: false, // 编译完成是否打开网页 open: false, // 编译完成是否打开网页
host: "0.0.0.0", // 指定使用地址,默认localhost,0.0.0.0代表可以被外界访问 host: '0.0.0.0', // 指定使用地址,默认localhost,0.0.0.0代表可以被外界访问
port: 8090, // 访问端口 port: 8090, // 访问端口
https: false, // 编译失败时刷新页面 https: false, // 编译失败时刷新页面
hot: true, // 开启热加载 hot: true, // 开启热加载
hotOnly: false, hotOnly: false,
proxy: { proxy: {
// 配置跨域 // 配置跨域
"/devApi": { '/devApi': {
//要访问的跨域的api的域名 //要访问的跨域的api的域名
target: "http://www.web-jshtml.cn", target: 'http://www.web-jshtml.cn',
ws: true, ws: true,
changOrigin: true, changOrigin: true,
pathRewrite: { pathRewrite: {
"^/devApi": "/productapi" '^/devApi': '/productapi',
} },
} },
}, },
overlay: { overlay: {
// 全屏模式下是否显示脚本错误 // 全屏模式下是否显示脚本错误
warnings: true, warnings: true,
errors: true errors: true,
}, },
// before: app => {} // before: app => {}
}, },
/** /**
* 第三方插件配置 * 第三方插件配置
*/ */
pluginOptions: {} pluginOptions: {},
}; }
```
```
- 改造其中的 vue 为 pug 格式
- 改造其中的vue为pug格式
以 App.vue 为例, 改写后如下:
以App.vue为例, 改写后如下:
```jade ```jade
<template lang="pug"> <template lang="pug">
...@@ -268,11 +263,11 @@ ...@@ -268,11 +263,11 @@
| &nbsp; | &nbsp; | &nbsp; | &nbsp;
router-line( to="/about" ) About router-line( to="/about" ) About
router-view router-view
</template> </template>
``` ```
- 添加vue对i18n的支持 - 添加 vue 对 i18n 的支持
- 执行命令行安装包 - 执行命令行安装包
...@@ -281,29 +276,30 @@ ...@@ -281,29 +276,30 @@
``` ```
- 准备语言文件 - 准备语言文件
- 建立 src/i18n/en.js 和 src/i18n/zh.js - 建立 src/i18n/en.js 和 src/i18n/zh.js
- zh.js文件内容如下,en.js和zh.js一一对应, 但value不同 - zh.js 文件内容如下,en.js 和 zh.js 一一对应, 但 value 不同
```javascript ```javascript
export const lang = { export const lang = {
slice: { slice: {
placeholder: { placeholder: {
name: "请输出切片名称", name: '请输出切片名称',
nst: "请选择NST模板" nst: '请选择NST模板',
}, },
tips: { tips: {
sla: "带宽:{0} Mbps, 时延: {1} ms" sla: '带宽:{0} Mbps, 时延: {1} ms',
} },
} },
} }
``` ```
-i18n加入到Vue, 修改 src/main.js: - 把 i18n 加入到 Vue, 修改 src/main.js:
```javascript ```javascript
import VueI18n from 'vue-i18n'; import VueI18n from 'vue-i18n';
... ...
Vue.use(VueI18n); Vue.use(VueI18n);
const i18n = new VueI18n({ const i18n = new VueI18n({
...@@ -317,20 +313,18 @@ ...@@ -317,20 +313,18 @@
new Vue({ new Vue({
router, router,
store, store,
i18n, i18n,
render: h => h(App) render: h => h(App)
}).$mount("#app"); }).$mount("#app");
``` ```
-Vue文件中, 在template渲染部分可以使用 {{ \$('lang.slice.tips.sla') }} 来引用; 如果是在script部分使用, 则应使用 root.​\$t() 函数来访问; - 在 Vue 文件中, 在 template 渲染部分可以使用 {{ \$('lang.slice.tips.sla') }} 来引用; 如果是在 script 部分使用, 则应使用 root.​\$t() 函数来访问;
- 使用 root.$i18n.locale 来获知当前语言 - 使用 root.\$i18n.locale 来获知当前语言
- 添加路由和路由动画 - 添加路由和路由动画
- 添加Vuex支持 - 添加 Vuex 支持
### 前端部分(Electron) ### 前端部分(Electron)
...@@ -341,135 +335,134 @@ ...@@ -341,135 +335,134 @@
```shell ```shell
npm config set registry http://registry.npm.taobao.org/ npm config set registry http://registry.npm.taobao.org/
npm install -g electron npm install -g electron
electron -v electron -v
``` ```
注: 如果一直卡在 node install.js, 可以设置%USERPROFILE%/.npmrc文件, 加入一行: 注: 如果一直卡在 node install.js, 可以设置%USERPROFILE%/.npmrc 文件, 加入一行:
```ini ```ini
ELECTRON_MIRROR="https://npm.taobao.org/mirrors/electron/" ELECTRON_MIRROR="https://npm.taobao.org/mirrors/electron/"
``` ```
2025.4.14 更新 npm 安装 Electron 项目失败报错问题和解决办法 1.打开 npm 的配置文件
2025.4.14更新npm安装Electron 项目失败报错问题和解决办法
1.打开npm的配置文件 ```shell
```shell
npm config edit npm config edit
```
```
2.在打开的配置文件空白处将下面几个配置添加上去,注意如果有原有的这几项配置,就修改 2.在打开的配置文件空白处将下面几个配置添加上去,注意如果有原有的这几项配置,就修改
``` ```
registry=https://registry.npmmirror.com
electron_mirror=https://cdn.npmmirror.com/binaries/electron/ registry=https://registry.npmmirror.com
electron_builder_binaries_mirror=https://npmmirror.com/mirrors/electron-builder-binaries/ electron_mirror=https://cdn.npmmirror.com/binaries/electron/
electron_builder_binaries_mirror=https://npmmirror.com/mirrors/electron-builder-binaries/
``` ```
3、然后关闭该窗口,重启命令行,删除node_modules文件夹,并执行下面命令清除缓存,再重新安装依赖 3、然后关闭该窗口,重启命令行,删除 node_modules 文件夹,并执行下面命令清除缓存,再重新安装依赖
- 新增 vue-cli方面的plug支持, 即vue-cli-plugin-electron-builder 支持, 主要作用是修改package.json, 并新增一个electron主程序入口文件 src/background.js - 新增 vue-cli 方面的 plug 支持, 即 vue-cli-plugin-electron-builder 支持, 主要作用是修改 package.json, 并新增一个 electron 主程序入口文件 src/background.js
```shell ```shell
vue add electron-builder vue add electron-builder
``` ```
选择Electron Version时, 选择 ^6.0.0; 选择 Electron Version 时, 选择 ^6.0.0;
修改后的package.json变化如下: 修改后的 package.json 变化如下:
```json ```json
"scripts": { "scripts": {
"serve": "vue-cli-service serve", "serve": "vue-cli-service serve",
"build": "vue-cli-service build", "build": "vue-cli-service build",
"lint": "vue-cli-service lint", "lint": "vue-cli-service lint",
+ "electron:build": "vue-cli-service electron:build", + "electron:build": "vue-cli-service electron:build",
+ "electron:serve": "vue-cli-service electron:serve", + "electron:serve": "vue-cli-service electron:serve",
+ "postinstall": "electron-builder install-app-deps", + "postinstall": "electron-builder install-app-deps",
+ "postuninstall": "electron-builder install-app-deps" + "postuninstall": "electron-builder install-app-deps"
}, },
+ "main": "background.js", + "main": "background.js",
... ...
"devDependencies":{
...
+ "vue-cli-plugin-electron-builder": "^1.4.6",
+ "electron": "^6.0.0",
}
```
"devDependencies":{
...
- 新生成的src/background.js内容如下, 修改为如下代码, 相比自动生成代码, 多了如下功能: + "vue-cli-plugin-electron-builder": "^1.4.6",
+ "electron": "^6.0.0",
}
```
修改了App窗口大小, 取消了跨域限制, 取消了菜单栏, 修改了App的窗口Icon: - 新生成的 src/background.js 内容如下, 修改为如下代码, 相比自动生成代码, 多了如下功能:
修改了 App 窗口大小, 取消了跨域限制, 取消了菜单栏, 修改了 App 的窗口 Icon:
```javascript ```javascript
"use strict"; 'use strict'
import { app, protocol, BrowserWindow, Menu } from "electron"; import { app, protocol, BrowserWindow, Menu } from 'electron'
import { createProtocol } from "vue-cli-plugin-electron-builder/lib"; import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'
const isDevelopment = process.env.NODE_ENV !== "production"; const isDevelopment = process.env.NODE_ENV !== 'production'
let win; let win
protocol.registerSchemesAsPrivileged([ protocol.registerSchemesAsPrivileged([
{ scheme: "app", privileges: { secure: true, standard: true } } { scheme: 'app', privileges: { secure: true, standard: true } },
]); ])
function createWindow() { function createWindow() {
win = new BrowserWindow({ win = new BrowserWindow({
width: 1200, width: 1200,
height: 800, height: 800,
icon: "./src/assets/logo.png", icon: './src/assets/logo.png',
webPreferences: { webPreferences: {
webSecurity: false, webSecurity: false,
nodeIntegration: true nodeIntegration: true,
} },
}); })
// 取消菜单 // 取消菜单
Menu.setApplicationMenu( null ); Menu.setApplicationMenu(null)
if (process.env.WEBPACK_DEV_SERVER_URL) { if (process.env.WEBPACK_DEV_SERVER_URL) {
win.loadURL(process.env.WEBPACK_DEV_SERVER_URL); win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
if (!process.env.IS_TEST) win.webContents.openDevTools(); if (!process.env.IS_TEST) win.webContents.openDevTools()
} else { } else {
createProtocol("app"); createProtocol('app')
win.loadURL("app://./index.html"); win.loadURL('app://./index.html')
} }
win.on("closed", () => { win.on('closed', () => {
win = null; win = null
}); })
} }
app.on("activate", () => { app.on('activate', () => {
if (win === null) { if (win === null) {
createWindow(); createWindow()
} }
}); })
app.on("ready", async () => { app.on('ready', async () => {
createWindow(); createWindow()
}); })
if (isDevelopment) { if (isDevelopment) {
if (process.platform === "win32") { if (process.platform === 'win32') {
process.on("message", data => { process.on('message', (data) => {
if (data === "graceful-exit") { if (data === 'graceful-exit') {
app.quit(); app.quit()
} }
}); })
} else { } else {
process.on("SIGTERM", () => { process.on('SIGTERM', () => {
app.quit(); app.quit()
}); })
} }
} }
``` ```
其中, 修改App窗口大小, 取消跨域限制, 取消菜单栏, 修改App图标 的代码集中在createWindow()中: 其中, 修改 App 窗口大小, 取消跨域限制, 取消菜单栏, 修改 App 图标 的代码集中在 createWindow()中:
```javascript ```javascript
function createWindow () { function createWindow () {
...@@ -477,7 +470,7 @@ electron_builder_binaries_mirror=https://npmmirror.com/mirrors/electron-builder- ...@@ -477,7 +470,7 @@ electron_builder_binaries_mirror=https://npmmirror.com/mirrors/electron-builder-
win = new BrowserWindow({ win = new BrowserWindow({
M width: 1200, M width: 1200,
M height: 800, M height: 800,
+ icon: "./src/assets/logo.png", + icon: "./src/assets/logo.png",
webPreferences: { webPreferences: {
+ webSecurity: false, + webSecurity: false,
nodeIntegration: true nodeIntegration: true
...@@ -487,7 +480,7 @@ electron_builder_binaries_mirror=https://npmmirror.com/mirrors/electron-builder- ...@@ -487,7 +480,7 @@ electron_builder_binaries_mirror=https://npmmirror.com/mirrors/electron-builder-
注: 还可以参考 https://www.jianshu.com/p/9e066a57de1a, https://www.jianshu.com/p/f3e69b4f1827, 加入托盘,消息闪烁,全局快捷键等 注: 还可以参考 https://www.jianshu.com/p/9e066a57de1a, https://www.jianshu.com/p/f3e69b4f1827, 加入托盘,消息闪烁,全局快捷键等
- 测试electron 运行 - 测试 electron 运行
```shell ```shell
# 运行 # 运行
...@@ -496,13 +489,13 @@ electron_builder_binaries_mirror=https://npmmirror.com/mirrors/electron-builder- ...@@ -496,13 +489,13 @@ electron_builder_binaries_mirror=https://npmmirror.com/mirrors/electron-builder-
npm run electron:build npm run electron:build
``` ```
此时出现的界面和之前用web浏览器打开的一样, 只是被装在窗口中. 此时出现的界面和之前用 web 浏览器打开的一样, 只是被装在窗口中.
### 后端部分(Express) ### 后端部分(Express)
- 后端目录准备: - 后端目录准备:
建立src/backend目录, 作为整个后台(含Electron, lowdb, Express等, 不含Vue)的目录. 后台目录: 建立 src/backend 目录, 作为整个后台(含 Electron, lowdb, Express 等, 不含 Vue)的目录. 后台目录:
```shell ```shell
backend backend
...@@ -515,10 +508,10 @@ electron_builder_binaries_mirror=https://npmmirror.com/mirrors/electron-builder- ...@@ -515,10 +508,10 @@ electron_builder_binaries_mirror=https://npmmirror.com/mirrors/electron-builder-
be_sysConfig.js 系统设置 be_sysConfig.js 系统设置
routes 目录: 存放 exporess 路由 routes 目录: 存放 exporess 路由
index.js 路由定义 index.js 路由定义
index.js express 服务器 index.js express 服务器
``` ```
- 增加 lowdb 支持 - 增加 lowdb 支持
```shell ```shell
npm install -S lowdb npm install -S lowdb
...@@ -532,138 +525,161 @@ electron_builder_binaries_mirror=https://npmmirror.com/mirrors/electron-builder- ...@@ -532,138 +525,161 @@ electron_builder_binaries_mirror=https://npmmirror.com/mirrors/electron-builder-
npm install -S express npm install -S express
npm install -D nodemon npm install -D nodemon
``` ```
- src/backend/store/db.js: 提供数据对象访问能力 - src/backend/store/db.js: 提供数据对象访问能力
```javascript ```javascript
import Datastore from "lowdb"; import Datastore from 'lowdb'
import FileSync from "lowdb/adapters/FileSync"; import FileSync from 'lowdb/adapters/FileSync'
import path from "path"; import path from 'path'
import fs from "fs-extra"; import fs from 'fs-extra'
import LodashId from "lodash-id"; import LodashId from 'lodash-id'
// 引入remote模块 // 引入remote模块
import { app, remote } from "electron"; import { app, remote } from 'electron'
// 根据process.type来分辨在哪种模式使用哪种模块, // 根据process.type来分辨在哪种模式使用哪种模块,
// 在主进程调用 为 browser, 在渲染进程调用为 renderer // 在主进程调用 为 browser, 在渲染进程调用为 renderer
const APP = process.type === "renderer" ? remote.app : app; const APP = process.type === 'renderer' ? remote.app : app
// 获取用户目录 C:\Users\shihe\AppData\Roaming\vue-node-lowdb // 获取用户目录 C:\Users\shihe\AppData\Roaming\vue-node-lowdb
const STORE_PATH = APP.getPath("userData"); const STORE_PATH = APP.getPath('userData')
if (process.type !== "renderer") { if (process.type !== 'renderer') {
// 如果不存在路径,创建 // 如果不存在路径,创建
if (!fs.pathExistsSync(STORE_PATH)) { if (!fs.pathExistsSync(STORE_PATH)) {
fs.mkdirpSync(STORE_PATH); fs.mkdirpSync(STORE_PATH)
} }
} }
const adapter = new FileSync(path.join(STORE_PATH, "database.json")); // 初始化lowdb读写的json文件名以及存储路径 const adapter = new FileSync(path.join(STORE_PATH, 'database.json')) // 初始化lowdb读写的json文件名以及存储路径
const db = Datastore(adapter); // lowdb接管该文件 const db = Datastore(adapter) // lowdb接管该文件
//通过lodash-id这个插件可以很方便地为每个新增的数据自动加上一个唯一标识的id字段 //通过lodash-id这个插件可以很方便地为每个新增的数据自动加上一个唯一标识的id字段
db._.mixin(LodashId); db._.mixin(LodashId)
// 初始化 ( 示例 ) // 初始化 ( 示例 )
if ( !db.read().has("NSTs").value()) { if (
db.set("NSTs", []).write(); !db
db.get("NSTs").insert({ label: "差动保护", value: "nst_001"}).write(); .read()
db.get("NSTs").insert({ label: "龙门吊", value: "nst_002" }).write(); .has('NSTs')
.value()
) {
db.set('NSTs', []).write()
db.get('NSTs')
.insert({ label: '差动保护', value: 'nst_001' })
.write()
db.get('NSTs')
.insert({ label: '龙门吊', value: 'nst_002' })
.write()
} }
if (!db.read().has("PLMNs").value()) { if (
db.read().set("PLMNs", []).write(); !db
db.read().get("PLMNs").insert({ label: "中国移动01", value: "960-001" }).write(); .read()
db.read().get("PLMNs").insert({ label: "中国联通03", value: "960-003" }).write(); .has('PLMNs')
db.read().get("PLMNs").insert({ label: "中国电信07", value: "960-007" }).write(); .value()
) {
db.read()
.set('PLMNs', [])
.write()
db.read()
.get('PLMNs')
.insert({ label: '中国移动01', value: '960-001' })
.write()
db.read()
.get('PLMNs')
.insert({ label: '中国联通03', value: '960-003' })
.write()
db.read()
.get('PLMNs')
.insert({ label: '中国电信07', value: '960-007' })
.write()
} }
// ES6写法: 暴露 // ES6写法: 暴露
export { db as default }; export { db as default }
``` ```
其他lowdb的详细信息可以参考 LowDB.md文件, 以及网址: https://www.jianshu.com/p/d46abfa4ddc9
- Express Web Restful API 服务器:
注: 如果是全新项目, 则可以借助如下命令来快速生成应用的骨架, 但这个项目已经存在, 因此只能手工方式把express的 WebServer, routes, 路由响应函数 等添加到项目中: 其他 lowdb 的详细信息可以参考 LowDB.md 文件, 以及网址: https://www.jianshu.com/p/d46abfa4ddc9
* Express Web Restful API 服务器:
注: 如果是全新项目, 则可以借助如下命令来快速生成应用的骨架, 但这个项目已经存在, 因此只能手工方式把 express 的 WebServer, routes, 路由响应函数 等添加到项目中:
```shell ```shell
npx express-generator npx express-generator
``` ```
- Web Server 服务器 * Web Server 服务器
代码: src/backend/webserver/index.js: 代码: src/backend/webserver/index.js:
```javascript ```javascript
import express from "express"; import express from 'express'
import router from "./routes/index.js"; import router from './routes/index.js'
const PORT = 3000; const PORT = 3000
const webApp = express(); const webApp = express()
//webApp.use(logger("./logs")); //webApp.use(logger("./logs"));
webApp.use(express.json()); webApp.use(express.json())
webApp.use(express.urlencoded({ extended: false })); webApp.use(express.urlencoded({ extended: false }))
webApp.use("/", router); webApp.use('/', router)
// catch 404 // catch 404
webApp.use((req, res, next) => { webApp.use((req, res, next) => {
res.status(404).send("Sorry! 404 Error."); res.status(404).send('Sorry! 404 Error.')
}); })
// error handler, 4个参数 // error handler, 4个参数
webApp.use((err, req, res, next) => { webApp.use((err, req, res, next) => {
// set locals, only providing error in development // set locals, only providing error in development
res.locals.message = err.message; res.locals.message = err.message
res.locals.error = req.app.get("env") === "development" ? err : {}; res.locals.error = req.app.get('env') === 'development' ? err : {}
// render the error page // render the error page
res.status(err.status || 500); res.status(err.status || 500)
res.json({ res.json({
message: err.message, message: err.message,
error: err error: err,
}); })
}); })
webApp.set("port", PORT); webApp.set('port', PORT)
webApp.listen(PORT, () => console.log(`App listening on port ${PORT}`)); webApp.listen(PORT, () => console.log(`App listening on port ${PORT}`))
export { webApp as default }; export { webApp as default }
``` ```
- Express的API 路由: * Express 的 API 路由:
代码: src/backend/webserver/routes/index.js 代码: src/backend/webserver/routes/index.js
```javascript ```javascript
import express from "express"; import express from 'express'
// 导入slice mgt的具体数据操作函数 // 导入slice mgt的具体数据操作函数
import sliceMgt from "../entity/function.js"; import sliceMgt from '../entity/function.js'
// 导入system config 的具体数据操作函数 // 导入system config 的具体数据操作函数
// let sysConfig = require("../entity/be_sysConfig.js"); // let sysConfig = require("../entity/be_sysConfig.js");
import sysConfig from "../entity/be_sysConfig.js"; import sysConfig from '../entity/be_sysConfig.js'
// 生成路由对象 // 生成路由对象
let router = express.Router(); let router = express.Router()
// 设置路由 // 设置路由
router.get("/nsmf/v1/nsts", sliceMgt.getNSTs); router.get('/nsmf/v1/nsts', sliceMgt.getNSTs)
router.get("/nsmf/v1/plmns", sliceMgt.getPLMNs); router.get('/nsmf/v1/plmns', sliceMgt.getPLMNs)
router.get("/nsmf/v1/nsmfConfig", sysConfig.getNSMFConfig); router.get('/nsmf/v1/nsmfConfig', sysConfig.getNSMFConfig)
router.put("/nsmf/v1/nsmfConfig", sysConfig.setNSMFConfig); router.put('/nsmf/v1/nsmfConfig', sysConfig.setNSMFConfig)
// ES6写法: 暴露路由 // ES6写法: 暴露路由
export { router as default }; export { router as default }
``` ```
- sliceMgt实体文件: * sliceMgt 实体文件:
代码: src/backend/webserver/entity/function.js 代码: src/backend/webserver/entity/function.js
```javascript ```javascript
import db from "@/backend/store/db.js"; import db from '@/backend/store/db.js'
let sliceMgt = new Object(); let sliceMgt = new Object()
// wrap函数把不支持promise的库转为支持, 可以支持异步 // wrap函数把不支持promise的库转为支持, 可以支持异步
// const wrap = fn => (...args) => fn(...args).catch(args[2]); // const wrap = fn => (...args) => fn(...args).catch(args[2]);
// router.get( // router.get(
...@@ -674,73 +690,60 @@ electron_builder_binaries_mirror=https://npmmirror.com/mirrors/electron-builder- ...@@ -674,73 +690,60 @@ electron_builder_binaries_mirror=https://npmmirror.com/mirrors/electron-builder-
// res.send("Hello World!"); // res.send("Hello World!");
// }) // })
// ); // );
sliceMgt.getNSTs = (req, res) => { sliceMgt.getNSTs = (req, res) => {
console.log("GET: NST List"); console.log('GET: NST List')
// 查询数据 // 查询数据
let data = db.get("NSTs").value(); let data = db.get('NSTs').value()
res.json(data); res.json(data)
}; }
sliceMgt.getPLMNs = (req, res) => { sliceMgt.getPLMNs = (req, res) => {
console.log("GET: PLMN List"); console.log('GET: PLMN List')
res.send("getPLMNs"); res.send('getPLMNs')
}; }
export { sliceMgt as default }; export { sliceMgt as default }
``` ```
be_sysConfig.js类似处理 be_sysConfig.js 类似处理
- 准备完毕后, 在 src/background.js 中加入Express Webserver的启动: * 准备完毕后, 在 src/background.js 中加入 Express Webserver 的启动:
```javascript ```javascript
"use strict"; "use strict";
import { app, protocol, BrowserWindow, Menu } from "electron"; import { app, protocol, BrowserWindow, Menu } from "electron";
import { createProtocol } from "vue-cli-plugin-electron-builder/lib"; import { createProtocol } from "vue-cli-plugin-electron-builder/lib";
+ import webApp from "@/backend/webserver/index.js"; + import webApp from "@/backend/webserver/index.js";
... ...
``` ```
由于 webApp 本身在模块中就会执行, 因此import即可 由于 webApp 本身在模块中就会执行, 因此 import 即可
- 启动 Vue + Electron + Express * 启动 Vue + Electron + Express
```shell ```shell
npm run electron:serve npm run electron:serve
``` ```
Vue+Electron部分应该保持和之前一样, 是一个带窗口的App, 同时console窗口会打印Express WebServer启动的信息: Vue+Electron 部分应该保持和之前一样, 是一个带窗口的 App, 同时 console 窗口会打印 Express WebServer 启动的信息:
```shell ```shell
App listening on port 3000 App listening on port 3000
``` ```
通过浏览器访问 Express 的API接口: 通过浏览器访问 Express 的 API 接口:
```shell ```shell
http://localhost:3000/nsmf/v1/nsts http://localhost:3000/nsmf/v1/nsts
``` ```
浏览器会展示返回的json结构: 浏览器会展示返回的 json 结构:
```json ```json
[{"label":"差动保护","value":"nst_001","id":"007b1880-f259-4993-b786-a5d93310b306"},{"label":"龙门吊","value":"nst_002","id":"1ff1f498-b308-4649-a42e-77e7293e42b6"}] [
{ "label": "差动保护", "value": "nst_001", "id": "007b1880-f259-4993-b786-a5d93310b306" },
{ "label": "龙门吊", "value": "nst_002", "id": "1ff1f498-b308-4649-a42e-77e7293e42b6" }
]
``` ```
...@@ -188,7 +188,21 @@ export default { ...@@ -188,7 +188,21 @@ export default {
return res.json(data); return res.json(data);
} }
// 替换中文
if (data.message) {
// data.message = data.message
// .replace(/正面/g, "A")
// .replace(/反面/g, "B")
// .replace(/正/g, "A")
// .replace(/反/g, "B")
// .replace(/前/g, "A")
// .replace(/后/g, "B")
// .replace(/B面/g, "B")
// .replace(/A面/g, "A");
}
let files = data.data || [data.message]; let files = data.data || [data.message];
files = files.map((el) => ({ url: `${fileEnv}${el}` })); files = files.map((el) => ({ url: `${fileEnv}${el}` }));
const downloadFunc = const downloadFunc =
...@@ -250,7 +264,7 @@ export default { ...@@ -250,7 +264,7 @@ export default {
res.json({ code: 500, msg: err }); res.json({ code: 500, msg: err });
} }
}, },
commitApply: async () => {}, commitApply: async () => { },
completeDelivery: async (req, res) => { completeDelivery: async (req, res) => {
const token = req.headers["jwt-token"]; const token = req.headers["jwt-token"];
const params = req.body; const params = req.body;
...@@ -329,7 +343,7 @@ export default { ...@@ -329,7 +343,7 @@ export default {
console.log(fileName); console.log(fileName);
const form = new multiparty.Form({ uploadDir: p }); const form = new multiparty.Form({ uploadDir: p });
form.parse(req, function(err, fields, files) { form.parse(req, function (err, fields, files) {
console.log(fields, files, err); console.log(fields, files, err);
if (err) { if (err) {
res.send({ code: 500, err }); res.send({ code: 500, err });
...@@ -365,10 +379,10 @@ export default { ...@@ -365,10 +379,10 @@ export default {
let responseData = []; //存储文件流 let responseData = []; //存储文件流
if (stream) { if (stream) {
//判断状态 //判断状态
stream.on("data", function(chunk) { stream.on("data", function (chunk) {
responseData.push(chunk); responseData.push(chunk);
}); });
stream.on("end", function() { stream.on("end", function () {
const finalData = Buffer.concat(responseData); const finalData = Buffer.concat(responseData);
res.write(finalData); res.write(finalData);
res.end(); res.end();
...@@ -433,7 +447,7 @@ export default { ...@@ -433,7 +447,7 @@ export default {
console.log(req.body.url, "下载zip地址"); console.log(req.body.url, "下载zip地址");
request(req.body.url) request(req.body.url)
.pipe(stream) .pipe(stream)
.on("close", function() { .on("close", function () {
compressing.zip compressing.zip
.uncompress(from, dirName, { zipFileNameEncoding: "gbk" }) .uncompress(from, dirName, { zipFileNameEncoding: "gbk" })
.then(() => { .then(() => {
...@@ -517,7 +531,7 @@ export default { ...@@ -517,7 +531,7 @@ export default {
try { try {
const p = path.join(process.cwd(), `./${getCurrentVersion()}/Input/`); const p = path.join(process.cwd(), `./${getCurrentVersion()}/Input/`);
const form = new multiparty.Form({ uploadDir: p }); const form = new multiparty.Form({ uploadDir: p });
form.parse(req, function(err, fields, files) { form.parse(req, function (err, fields, files) {
console.log(367, fields, files, err); console.log(367, fields, files, err);
if (err) { if (err) {
res.send({ code: 500, err }); res.send({ code: 500, err });
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment