{
"name": "test",
"version": "1.0.0",
"description": "test",
"author": "tzc",
"license": "MIT",
"main": "background.js",
"scripts": {
"dev": "vue-cli-service serve",
"build:prod": "vue-cli-service build",
"build:stage": "vue-cli-service build --mode staging",
"build:dev": "vue-cli-service build --mode development",
"preview": "node build/index.js --preview",
"lint": "eslint --ext .js,.vue src",
"electron:serve": "vue-cli-service electron .",
"electron:build": "vue-cli-service electron:build",
"electron:build32": "vue-cli-service electron:build --win --ia32"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"src/**/*.{js,vue}": [
"eslint --fix",
"git add"
]
},
"keywords": [
"vue",
"admin",
"dashboard",
"element-ui",
"boilerplate",
"admin-template",
"management-system"
],
"repository": {
"type": "git",
"url": "https://gitee.com/dromara/Vue-Plus.git"
},
"dependencies": {
"@riophae/vue-treeselect": "0.4.0",
"axios": "0.24.0",
"clipboard": "2.0.8",
"core-js": "3.25.3",
"echarts": "5.4.0",
"electron": "20.3.8",
"electron-devtools-installer": "^3.2.0",
"electron-log": "^4.0.0",
"electron-store": "^8.1.0",
"element-ui": "2.15.13",
"ffi-napi": "^4.0.3",
"file-saver": "2.0.5",
"fuse.js": "6.4.3",
"highlight.js": "9.18.5",
"js-beautify": "1.13.0",
"js-cookie": "3.0.1",
"jsencrypt": "3.0.0-rc.1",
"nprogress": "0.2.0",
"quill": "1.3.7",
"ref-array-di": "^1.2.2",
"ref-array-napi": "^1.2.2",
"ref-napi": "^3.0.3",
"ref-struct-di": "^1.1.1",
"ref-struct-napi": "^1.1.1",
"screenfull": "5.0.2",
"serialport": "^12.0.0",
"sortablejs": "1.10.2",
"vue": "2.6.12",
"vue-cli-plugin-electron-builder": "^2.1.1",
"vue-count-to": "1.0.13",
"vue-cropper": "0.5.5",
"vue-meta": "2.4.0",
"vue-router": "3.4.9",
"vuedraggable": "2.24.3",
"vuex": "3.6.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "4.4.6",
"@vue/cli-plugin-eslint": "4.4.6",
"@vue/cli-service": "4.4.6",
"babel-eslint": "10.1.0",
"babel-plugin-dynamic-import-node": "2.3.3",
"chalk": "4.1.0",
"compression-webpack-plugin": "5.0.2",
"connect": "3.6.6",
"eslint": "7.15.0",
"eslint-plugin-vue": "7.2.0",
"lint-staged": "10.5.3",
"runjs": "4.4.2",
"sass": "1.32.13",
"sass-loader": "10.1.1",
"script-ext-html-webpack-plugin": "2.1.5",
"svg-sprite-loader": "5.1.1",
"vue-template-compiler": "2.6.12"
},
"engines": {
"node": ">=8.9",
"npm": ">= 3.0.0"
},
"browserslist": [
"> 1%",
"last 2 versions"
]
}
VUE_APP_BASE_API = 'http://localhost:8080'
VUE_APP_CONTEXT_PATH = './'
整个文件全部注释掉
pluginOptions是module.exports下最顶级的属性:
pluginOptions: {
electronBuilder: {
nodeIntegration: true,
//因为这两个模块中包含原生 C代码,所以要在运行的时候再获取,而不是被webpack打包到bundle中
externals: ['ffi-napi', 'ref-napi','ref-struct-di','ref-array-di','serialport'],
contextIsolation: false,
enableRemoteModule: true,
publish: [{
"provider": "xx公司",
"url": "https://www.xxx.cn/"
}],
"copyright": "Copyright © 2023",
builderOptions:{
appId: 'com.xxx',
productName: 'Xxx',
asar:false,
"extraResources": [
{
"from": "./src/usb/exe/ControlCAN64.dll",
"to": "./usb/exe/ControlCAN64.dll"
},
{
"from": "./src/usb/conf/data_init.json",
"to": "./usb/conf/data_init.json"
},
{
"from": "./src/usb/conf/data_zh_cn.json",
"to": "./usb/conf/data_zh_cn.json"
},
],
nsis:{
"oneClick": false,
"guid": "idea",
"perMachine": true,
"allowElevation": true,
"allowToChangeInstallationDirectory": true,
"installerIcon": "build/app.ico",
"uninstallerIcon": "build/app.ico",
"installerHeaderIcon": "build/app.ico",
"createDesktopShortcut": true,
"createStartMenuShortcut": true,
"shortcutName": "Xxx"
},
win: {
"icon": "build/app.ico",
"target": [
{
"target": "nsis", //使用nsis打成安装包,"portable"打包成免安装版
"arch": [
"ia32", //32位
"x64" //64位
]
}
]
},
},
},
},
Cookies.get替换为localStorage.getItem
Cookies.set替换为localStorage.setItem
Cookies.remove替换为localStorage.removeItem
src/views/login.vue 去掉过期时间
全局修改path.resolve为path.posix.resolve
改为 hash 模式
'use strict'
import { app, protocol, BrowserWindow, ipcMain } from 'electron'
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'
import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'
const isDevelopment = process.env.NODE_ENV !== 'production'
const Store = require('electron-store');
// Scheme must be registered before the app is ready
protocol.registerSchemesAsPrivileged([
{ scheme: 'app', privileges: { secure: true, standard: true } }
])
async function createWindow() {
// Create the browser window.
const win = 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
contextIsolation:false, //上下文隔离
enableRemoteModule: true, //启用远程模块
nodeIntegration: true, //开启自带node环境
webviewTag: true, //开启webview
webSecurity: false,
allowDisplayingInsecureContent: true,
allowRunningInsecureContent: true
}
})
win.maximize()
win.show()
win.webContents.openDevTools()
ipcMain.on('getUsbConnectionStatus', (event, arg) => {
global.usbConnectionStatus=new Date().getTime()-global.usbConnectionTime<5000?true:false;//5秒内有数据表示连接成功
event.returnValue = global.usbConnectionStatus;
});
ipcMain.on('openUsb', (event) => {
let res=UsbCanUtils.openUsb();
event.returnValue = res;
});
if (process.env.WEBPACK_DEV_SERVER_URL) {
// Load the url of the dev server if in development mode
await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
if (!process.env.IS_TEST) win.webContents.openDevTools()
} else {
createProtocol('app')
// Load the index.html when not in development
win.loadURL('app://./index.html')
}
}
// Quit when all windows are closed.
app.on('window-all-closed', () => {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', async () => {
Store.initRenderer();
if (isDevelopment && !process.env.IS_TEST) {
// Install Vue Devtools
try {
await installExtension(VUEJS_DEVTOOLS)
} catch (e) {
console.error('Vue Devtools failed to install:', e.toString())
}
}
createWindow()
})
// Exit cleanly on request from parent process in development mode.
if (isDevelopment) {
if (process.platform === 'win32') {
process.on('message', (data) => {
if (data === 'graceful-exit') {
app.quit()
}
})
} else {
process.on('SIGTERM', () => {
app.quit()
})
}
}
ipcMain.on('getUsbConnectionStatus', (event, arg) => {
global.usbConnectionStatus=new Date().getTime()-global.usbConnectionTime<5000?true:false;//5秒内有数据表示连接成功
event.returnValue = global.usbConnectionStatus;
});
ipcMain.on('openUsb', (event) => {
let res=UsbCanUtils.openUsb();
event.returnValue = res;
});
methods: {
getUsbConnectionStatus: function() {
const result = ipcRenderer.sendSync('getUsbConnectionStatus', '');
console.log("连接状态:"+result);
this.usbConnectionStatus=result;
},
openUsb: function() {
if(this.usbConnectionStatus){
return;
}
ipcRenderer.send('openUsb', '');
}
}
UsbCanTypes.js
const ffi = require("ffi-napi");
const ref = require("ref-napi");
const Struct = require('ref-struct-di')(ref);
const ArrayType = require('ref-array-di')(ref);
var VCI_INIT_CONFIG = Struct({
AccCode: ref.types.uint32,
AccMask: ref.types.uint32,
Reserved: ref.types.uint32,
Filter: ref.types.uchar,
Timing0: ref.types.uchar,
Timing1: ref.types.uchar,
Mode: ref.types.uchar
})
var VCI_CAN_OBJ = Struct({
ID: ref.types.uint32,
TimeStamp: ref.types.uint32,
TimeFlag: ref.types.byte,
SendType: ref.types.byte,
RemoteFlag: ref.types.byte,
ExternFlag: ref.types.byte,
DataLen: ref.types.byte,
Data: ArrayType(ref.types.byte, 8),
Reserved: ArrayType(ref.types.byte, 3)
})
let StructArray = ArrayType(VCI_CAN_OBJ);
export default {
VCI_INIT_CONFIG,
VCI_CAN_OBJ,
StructArray,
}
UsbCanConfigs.js
import path from 'path';
import UsbCanTypes from './UsbCanTypes';
const VCI_USBCAN2=4
const canIndex=0
const SendType=0
const ExternFlag=1
let vci_initconfig = new UsbCanTypes.VCI_INIT_CONFIG({
AccCode: 0x80000008,
AccMask: 0xFFFFFFFF,
Reserved: 0,
Filter: 0,
Timing0: 0x01,
Timing1: 0x1C,
Mode: 0
})//波特率250k,正常模式
export default {
VCI_USBCAN2,
vci_initconfig,
SendType,
ExternFlag,
canIndex,
}
UsbCanUtils.js
const path = require('path')
const ffi = require("ffi-napi");
const ref = require("ref-napi");
const log = typeof process !== 'undefined' && process.versions && process.versions.electron?require('electron-log'):console;
import CommUtils from './CommUtils';
import UsbCanTypes from './UsbCanTypes';
import UsbCanConfigs from './UsbCanConfigs';
import UsbCanProtocol from './UsbCanProtocol';
import { setInterval, setTimeout } from 'core-js';
// const UsbCanTypes = require('./UsbCanTypes.js');
// const UsbCanConfigs = require('./UsbCanConfigs');
// const UsbCanProtocol = require('./UsbCanProtocol.js');
const STATUS_OK = 1
let canDLL = null;
function create() {
if(canDLL!=null){
return
}
canDLL = ffi.Library(path.join(process.cwd(), '/resources/usb/exe/ControlCAN64.dll'), {
'VCI_OpenDevice': [ref.types.int, [ref.types.int, ref.types.int, ref.types.int]],
'VCI_InitCAN': [ref.types.int, [ref.types.int, ref.types.int, ref.types.int,ref.refType('void')]],
'VCI_StartCAN': [ref.types.int, [ref.types.int, ref.types.int, ref.types.int]],
'VCI_Transmit': [ref.types.int, [ref.types.int, ref.types.int, ref.types.int,ref.refType('void'), ref.types.int]],
'VCI_Receive': [ref.types.int, [ref.types.int, ref.types.int, ref.types.int,ref.refType('void'),ref.types.ulong,ref.types.int]]
});
}
function open() {
let ret = canDLL.VCI_OpenDevice(UsbCanConfigs.VCI_USBCAN2,0,0)
return ret== STATUS_OK
}
function init(canIndex) {
let ret = canDLL.VCI_InitCAN(UsbCanConfigs.VCI_USBCAN2, 0, canIndex, UsbCanConfigs.vci_initconfig.ref())
return ret== STATUS_OK
}
function start(canIndex) {
let ret = canDLL.VCI_StartCAN(UsbCanConfigs.VCI_USBCAN2, 0, canIndex)
return ret== STATUS_OK
}
function send(canIndex,id,dataLen,data) {
//log.info('CAN'+canIndex+'通道准备发送')
let d={
ID: id,
TimeStamp: 0,
TimeFlag: 0,
SendType: UsbCanConfigs.SendType,
RemoteFlag: 0,
ExternFlag: UsbCanConfigs.ExternFlag,
DataLen: dataLen,
Data: data,
Reserved: [0,0,0]
};
let vci_can_obj = new UsbCanTypes.VCI_CAN_OBJ();
vci_can_obj.ID=d.ID;
vci_can_obj.TimeStamp=d.TimeStamp;
vci_can_obj.TimeFlag=d.TimeFlag;
vci_can_obj.SendType=d.SendType;
vci_can_obj.RemoteFlag=d.RemoteFlag;
vci_can_obj.ExternFlag=d.ExternFlag;
vci_can_obj.DataLen=d.DataLen;
for(let i=0;i<dataLen;i++){
vci_can_obj.Data[i]=d.Data[i]
}
for(let i=0;i<3;i++){
vci_can_obj.Reserved[i]=d.Reserved[i]
}
let ret = canDLL.VCI_Transmit(UsbCanConfigs.VCI_USBCAN2, 0, canIndex, vci_can_obj.ref(), 1)
//log.info('CAN'+canIndex+'通道发送完成'+ret)
return ret== STATUS_OK
}
function receive(canIndex) {
const rx_vci_can_obj = new UsbCanTypes.StructArray(2500);
let usbInterval=setInterval(() => {
if(global.windowClosed){
return;
}
let ret = canDLL.VCI_Receive(UsbCanConfigs.VCI_USBCAN2, 0, canIndex, rx_vci_can_obj.buffer, 2500, 0)
// //log.info('CAN1通道接收'+ret)
if (ret > 0){//接收到数据
global.usbConnectionTime=new Date().getTime();
for(let i=0;i<ret;i++){
// //log.info('ID:')
// //log.info(CommUtils.toHexString(rx_vci_can_obj[i].ID))
// //log.info('DataLen:')
// //log.info(CommUtils.toHexString(rx_vci_can_obj[i].DataLen))
// //log.info('Data:')
// //log.info(CommUtils.listToHexString(rx_vci_can_obj[i].Data))
UsbCanProtocol.parseData(canIndex,rx_vci_can_obj[i].ID,rx_vci_can_obj[i].DataLen,rx_vci_can_obj[i].Data.toArray())
}
}
}, 10);
return usbInterval;
// while(true){//一直循环查询接收。
// let ret = canDLL.VCI_Receive(UsbCanConfigs.VCI_USBCAN2, 0, canIndex, rx_vci_can_obj.buffer, 2500, 0)
// //log.info('CAN1通道接收'+ret)
// if (ret > 0){//接收到数据
// global.usbConnectionTime=new Date().getTime();
// for(let i=0;i
// // //log.info('CAN1通道接收成功')
// // //log.info('ID:')
// // //log.info(CommUtils.toHexString(rx_vci_can_obj[i].ID))
// // //log.info('DataLen:')
// // //log.info(CommUtils.toHexString(rx_vci_can_obj[i].DataLen))
// // //log.info('Data:')
// // //log.info(CommUtils.listToHexString(rx_vci_can_obj[i].Data))
// // //log.info('\r\n')
// UsbCanProtocol.parseData(canIndex,rx_vci_can_obj[i].ID,rx_vci_can_obj[i].DataLen,rx_vci_can_obj[i].Data.toArray())
// }
// }
// }
}
export default {
openUsb:function(){
global.usbConnectionTime=0;
//log.info("create USB ing...")
create();
//log.info("create USB success")
let res=open();
if(res){
//log.info("open USB success")
}else{
//log.info("open USB fail")
return false;
}
res=init(UsbCanConfigs.canIndex);
if(res){
//log.info("init USB success")
}else{
//log.info("init USB fail")
return false;
}
res=start(UsbCanConfigs.canIndex);
if(res){
//log.info("start USB success")
global.usbConnectionTime=new Date().getTime();
}else{
//log.info("start USB fail")
return false;
}
return true;
},
send:send,
receive:function(){
setTimeout(function(){
global.usbInterval=receive(UsbCanConfigs.canIndex);
},10);
},
}
SerialUtils.js
const {SerialPort} = require('serialport');
// const Readline = require('@serialport/parser-readline');
import CommUtils from './CommUtils';
const log = typeof process !== 'undefined' && process.versions && process.versions.electron?require('electron-log'):console;
let port=null;
let parser = null;
async function getPortList() {
try {
// 获取可用串口列表,并等待Promise解析
const ports = await SerialPort.list();
// ports 是一个包含可用串口信息的数组
// log.info('Available Serial Ports:', (typeof ports));
log.info('Available Serial Ports:', ports);
// 返回解析后的串口列表
return ports;
} catch (e) {
// 处理错误
log.error(`Error while getting serial port list:${e}>>>${e.stack}`);
throw e; // 将错误继续抛出,让调用者处理
}
}
function open(serialName,baudRate) {
try {
port = new SerialPort({
path: serialName,
baudRate: baudRate,
// highWaterMark:32,
autoOpen: true,
dataBits: 8, // 8位数据位
parity: 'none', // 无奇偶校验
stopBits: 1, // 1个停止位
flowControl: false,
platformOptions: {
vmin: 1, // 读取的最小字节数
vtime: 1, // 读取操作的超时时间(以十毫秒为单位)
ctsFlowControl: false, // 是否启用 CTS 流控制
autoOpen: true // 是否自动打开串口
}
});
port.on('error', err => {
console.log(err);
});
return true;
} catch (e) {
// log.error(`打开串口报错:${e}>>>${e.stack}`);
return false;
}
}
function close() {
try {
port.close();
global.usbConnectionTime=0;
global.usbConnectionStatus=false;
setTimeout(() => {
global.usbConnectionTime=0;
global.usbConnectionStatus=false;
},100);
return true;
} catch (e) {
// log.error(`关闭串口报错:${e}>>>${e.stack}`);
return false;
}
}
function start() {
// try {
// // 使用 Readline parser 以行为单位读取数据
// parser = port.pipe(new Readline({ delimiter: '\n' }));
// return true;
// } catch (e) {
// log.error(`初始化串口报错:${e}>>>${e.stack}`);
// return false;
// }
return true;
}
function mysend(data) {
port.write(Buffer.from(data), (e,r) => {
if(e){
log.error("New发送串口数据>>>"+CommUtils.listToHexString(data))
}else{
// log.info("New发送串口数据>>>"+CommUtils.listToHexString(data))
}
});
}
//发送并返回发送的结果
function send(data) {
try {
mysend(data);
// log.info(`发送串口数据`+CommUtils.listToHexString(data));
return true;
} catch (e) {
// log.error(`发送数据给串口报错:`+CommUtils.listToHexString(data)+`>>>${e.stack}`);
return false;
}
}
function receive(callback) {
try {
// 监听串口数据接收事件
port.on('data', (data) => {
// let x1=data.indexOf(0x2A);
// let x2=data.indexOf(0x04);
// if(x1!=-1&&x2!=-1&&x1==x2-1){
// log.info("收到串口数据"+CommUtils.listToHexString(data))
// }
try {
log.info("New收到串口数据>>>"+CommUtils.listToHexString(data))
global.usbConnectionTime=new Date().getTime();
callback(data);
} catch (e2) {
log.error(`接收数据串口报错2:${e2.stack}`);
}
});
} catch (e) {
log.error(`接收数据串口报错:${e.stack}`);
}
}
export default {
openSerial:function(serialName){
//460800
//921600
let res=open(serialName,460800);
if(res){
log.info("open Serial success")
}else{
log.info("open Serial fail")
return false;
}
res=start();
if(res){
log.info("start Serial success")
}else{
log.info("start Serial fail")
return false;
}
return true;
},
getPortList,
send,
close,
receive
}
win.webContents.send('usbDataUpdate', global.json_data);
mounted() {
ipcRenderer.on('usbDataUpdate', (event, arg) => {
this.usbDataUpdate(arg);
});
},
beforeDestroy() {
ipcRenderer.removeAllListeners('usbDataUpdate');
},
methods: {
usbDataUpdate: function(json_data) {
this.usbData=json_data;
// console.log("更新USB数据"+typeof(json_data));
// console.log("更新USB数据"+JSON.stringify(json_data));
},
}