From 70792767d47c000bc55327a75e1d27f4512447d7 Mon Sep 17 00:00:00 2001 From: qubiaobiao <3294694717@qq.com> Date: Wed, 18 Mar 2026 16:40:36 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8C=97=E6=96=97=E5=8D=AB=E6=98=9F=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E7=9B=91=E6=B5=8B=E5=B1=95=E7=A4=BA=E4=BA=92=E5=8A=A8?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 68 +++++++-- package.json | 6 +- src/main/KeyWord.js | 4 +- src/main/api/NMEAHandler.js | 76 +++++----- src/main/app.ts | 176 ++++++++++++---------- src/main/config.js | 10 +- src/main/ipcRendererManager.js | 24 +-- src/main/load-serialport.js | 52 +++---- src/main/preload.js | 16 +- src/render/App.vue | 53 ++++--- src/render/api/util.js | 115 +++++++------- src/render/components/BaseInfoView.vue | 72 +++++---- src/render/components/NMEAView.vue | 10 +- src/render/components/PlanisphereView.vue | 32 ++-- src/render/components/SNRView.vue | 27 ++-- src/render/components/SubTitleView.vue | 2 +- src/render/main.ts | 16 +- 17 files changed, 429 insertions(+), 330 deletions(-) diff --git a/index.html b/index.html index a82fdaa..163f4d1 100644 --- a/index.html +++ b/index.html @@ -1,13 +1,59 @@ - - - - - 北斗卫星数据监测展示软件 - - -
- - - + + + + + + + 北斗卫星数据监测展示软件 + + + +
+ + + + \ No newline at end of file diff --git a/package.json b/package.json index 2a3825d..5d5e326 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,8 @@ "echarts": "^5.1.0", "electron-store": "^8.0.0", "nmea": "http://git.hwasmart.com/bd_group/node-nmea.git", + "node-gyp": "^10.0.1", + "node-pre-gyp": "^0.17.0", "serialport": "^12.0.0", "through": "^2.3.8", "vue": "^3.2.26", @@ -31,9 +33,9 @@ "@vue/compiler-sfc": "^3.2.26", "autoprefixer": "^10.2.5", "cross-env": "^7.0.3", - "electron": "^19.0.3", + "electron": "^22.0.0", "electron-builder": "^25.0.5", - "electron-rebuild": "2.3.5", + "electron-rebuild": "^2.3.5", "postcss": "^8.2.10", "rimraf": "^3.0.2", "rollup-plugin-copy": "^3.4.0", diff --git a/src/main/KeyWord.js b/src/main/KeyWord.js index 0fa0b9d..8417da3 100644 --- a/src/main/KeyWord.js +++ b/src/main/KeyWord.js @@ -1,3 +1,3 @@ // 加密关键字 -const keyword = 'BD' -export { keyword } \ No newline at end of file +const keyword = 'BD'; +export { keyword }; \ No newline at end of file diff --git a/src/main/api/NMEAHandler.js b/src/main/api/NMEAHandler.js index 79313b3..ae78bef 100644 --- a/src/main/api/NMEAHandler.js +++ b/src/main/api/NMEAHandler.js @@ -1,89 +1,89 @@ -import { parse, Helpers } from 'nmea' +import { parse, Helpers } from 'nmea'; -let events = {} +let events = {}; const on = (eventName, callback) => { if (!(eventName in events)) { - events[eventName] = [] + events[eventName] = []; } - events[eventName].push(callback) -} + events[eventName].push(callback); +}; const emit = (eventName, ...args) => { if (!(eventName in events)) { - return + return; } - const cbs = events[eventName] + const cbs = events[eventName]; cbs.forEach(cb => { - cb.call(this, ...args) + cb.call(this, ...args); }); -} +}; const handle = (value) => { - if (value.length <= 0) return + if (value.length <= 0) return; - emit('received', value) - nmeaObj = resetNMEAObj() + emit('received', value); + nmeaObj = resetNMEAObj(); - const strArr = value.split('\r\n') + const strArr = value.split('\r\n'); for (let i = 0; i < strArr.length; i++) { const element = strArr[i]; - doHandle(element) + doHandle(element); } - emit('handled', nmeaObj) -} + emit('handled', nmeaObj); +}; const doHandle = (value) => { if (!verify(value)) { - return + return; } - const result = parse(value) + const result = parse(value); switch (result.sentence) { case 'GGA': - nmeaObj.GGA = result + nmeaObj.GGA = result; break; case 'GLL': - nmeaObj.GLL = result + nmeaObj.GLL = result; break; case 'RMC': - nmeaObj.RMC = result + nmeaObj.RMC = result; break; case 'VTG': - nmeaObj.VTG = result + nmeaObj.VTG = result; break; case 'ZDA': - nmeaObj.ZDA = result + nmeaObj.ZDA = result; break; case 'TXT': - nmeaObj.TXT = result + nmeaObj.TXT = result; break; case 'GSA': - nmeaObj.GSA.push(result) + nmeaObj.GSA.push(result); break; case 'GSV': - nmeaObj.GSV.push(result) + nmeaObj.GSV.push(result); break; } -} +}; const verify = (value) => { if (!value) { - return false + return false; } - const dollar_index = value.indexOf('$') - const star_index = value.indexOf('*') + const dollar_index = value.indexOf('$'); + const star_index = value.indexOf('*'); if (value.indexOf('$') !== 0 || star_index <= dollar_index) { - return false + return false; } - const [sentence, checksum, ] = value.split('*') - return Helpers.verifyChecksum(sentence, checksum) -} + const [sentence, checksum, ] = value.split('*'); + return Helpers.verifyChecksum(sentence, checksum); +}; const resetNMEAObj = () => { return { @@ -95,9 +95,9 @@ const resetNMEAObj = () => { TXT: null, GSA: [], GSV: [] - } -} + }; +}; -let nmeaObj = resetNMEAObj() +let nmeaObj = resetNMEAObj(); -export default { on, handle } +export default { on, handle }; diff --git a/src/main/app.ts b/src/main/app.ts index 94a5ef7..df6116a 100644 --- a/src/main/app.ts +++ b/src/main/app.ts @@ -1,80 +1,80 @@ -import { app, screen, globalShortcut, BrowserWindow, ipcMain, dialog } from 'electron' -import { join } from "path" -import config from './config.js' -import './load-serialport' -import { keyword } from './KeyWord' +import { app, screen, globalShortcut, BrowserWindow, ipcMain, dialog } from 'electron'; +import { join } from "path"; +import config from './config.js'; +import './load-serialport'; +import { keyword } from './KeyWord'; -import child_process from 'child_process' -import crypto from 'crypto' +import child_process from 'child_process'; +import crypto from 'crypto'; function queryPass(passPath: string, passValue: string) { return new Promise(function (resolve, reject) { try { child_process.exec(`reg query ${passPath} /v ${passValue}`, (error: Error | null, stdout: string, stderr: string) => { if (error) { - reject(error) - return + reject(error); + return; } - resolve({stdout, stderr}) + resolve({stdout, stderr}); }) } catch (error) { - reject(error) + reject(error); } }) -} +}; function queryKey(keyPath: string, keyValue: string) { return new Promise(function (resolve, reject) { try { child_process.exec(`reg query ${keyPath} /v ${keyValue}`, (error: Error | null, stdout: string, stderr: string) => { if (error) { - reject(error) - return + reject(error); + return; } - resolve({stdout, stderr}) + resolve({stdout, stderr}); }) } catch (error) { - reject(error) + reject(error); } }) -} +}; function cryptMD5(GUID: string) { - let md5 = crypto.createHash('md5') - let ciphertext = md5.update(GUID).digest('hex') - return ciphertext.slice(0,8)+'-'+ciphertext.slice(8,12)+'-'+ciphertext.slice(12,16)+'-'+ciphertext.slice(16,20)+'-'+ciphertext.slice(20,32) -} + let md5 = crypto.createHash('md5'); + let ciphertext = md5.update(GUID).digest('hex'); + return ciphertext.slice(0,8)+'-'+ciphertext.slice(8,12)+'-'+ciphertext.slice(12,16)+'-'+ciphertext.slice(16,20)+'-'+ciphertext.slice(20,32); +}; -const passPath = 'HKEY_CURRENT_USER\\SOFTWARE\\HwaSmart' -const passValue = 'BDAuthorization' -const keyPath = 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography' -const keyValue = 'MachineGuid' +const passPath = 'HKEY_CURRENT_USER\\SOFTWARE\\HwaSmart'; +const passValue = 'BDAuthorization'; +const keyPath = 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography'; +const keyValue = 'MachineGuid'; async function checkLaunchEnv() { try { - const passResult: any = await queryPass(passPath, passValue) - const keyResult: any = await queryKey(keyPath, keyValue) + const passResult: any = await queryPass(passPath, passValue); + const keyResult: any = await queryKey(keyPath, keyValue); if(cryptMD5(keyResult.stdout.slice(83,119) + keyword) == passResult.stdout.slice(72,108)){ - return true + return true; }else{ - return false + return false; } // 成功 // 查询到 有这个app启动项 } catch (error) { // 没有查询到该app启动项目 - return false + return false; } -} +}; async function main() { // 异步代码 -const checkReault: any = await checkLaunchEnv() -console.log('env right:', checkReault) +const checkReault: any = await checkLaunchEnv(); +console.log('env right:', checkReault); // 异步代码执行完毕后执行的代码 if (checkReault) { -const URl_REGEX = /[a-zA-z]+:\/\/[^\s]*/ +const URl_REGEX = /[a-zA-z]+:\/\/[^\s]*/; const DEFAULT_OPTION = { fullscreen: true, frame: false, @@ -82,57 +82,75 @@ const DEFAULT_OPTION = { nodeIntegration: true, preload: join(__dirname, 'preload.js') } -} +}; const launch = () => { - const extend_tdt_window = config.get('extend_tdt_window') - const displays = screen.getAllDisplays() - - const { option, url } = getMonitorWindowArguments(displays[0]) - createWindow(option, url) + const showMode = config.get('showMode'); + const extend_tdt_window = config.get('extend_tdt_window'); + const displays = screen.getAllDisplays(); - if (extend_tdt_window) { - const { option, url } = getTDTWindowArguments(displays[displays.length - 1]) - createWindow(option, url) + if (showMode == "showPositive") { + const { option, url } = getMonitorWindowArguments(displays[0]); + createWindow(option, url); + + if (extend_tdt_window) { + const { option, url } = getTDTWindowArguments(displays[displays.length - 1]); + createWindow(option, url); + } + } else if (showMode == "showReverse") { + const { option, url } = getTDTWindowArguments(displays[0]); + createWindow(option, url); + + if (extend_tdt_window) { + const { option, url } = getMonitorWindowArguments(displays[displays.length - 1]); + createWindow(option, url); + } } -} +}; const getMonitorWindowArguments = (display: any) => { - const option = getOption(display) - const url = process.env.NODE_ENV === 'development' ? 'http://localhost:3000/' : 'dist/render/index.html' + const option = getOption(display); + const url = process.env.NODE_ENV === 'development' ? 'http://localhost:3000/' : 'dist/render/index.html'; - return { option, url } -} + return { option, url }; +}; + const getTDTWindowArguments = (display: any) => { - const option = getOption(display) - const url = 'http://gd.map.hwasmart.com/' + const option = getOption(display); + const url = 'http://gd.map.hwasmart.com/'; - return { option, url } -} + return { option, url }; +}; const getOption = (display: any) => { - const origin = getDisplayOrigin(display) - const option = Object.assign({}, DEFAULT_OPTION, origin) - return option -} + const origin = getDisplayOrigin(display); + const option = Object.assign({}, DEFAULT_OPTION, origin); + return option; +}; const getDisplayOrigin = (display: any) => { - const origin = !display ? {x: 0, y: 0} : {x: display.bounds.x, y: display.bounds.y} - return origin -} + const origin = !display ? {x: 0, y: 0} : {x: display.bounds.x, y: display.bounds.y}; + return origin; +}; var windows:Array = []; function createWindow(option: any, url: any) { - const win = new BrowserWindow(option) + const win = new BrowserWindow(option); if (URl_REGEX.test(url)) { - win.loadURL(url) + win.loadURL(url); } else { - win.loadFile(url) + win.loadFile(url); } - if(process.env.NODE_ENV === 'development') win.webContents.openDevTools() + if(process.env.NODE_ENV === 'development') win.webContents.openDevTools(); windows.push(win); -} +}; + +ipcMain.on("APP_MOUNTED", (event) => { + const { sender } = event; + let softwareName = config.get('softwareName'); + sender.send('softwareName', softwareName); +}); ipcMain.on('CLOSE', (event) => { const res = dialog.showMessageBox({ @@ -143,7 +161,7 @@ ipcMain.on('CLOSE', (event) => { cancelId: 1, // 按esc默认点击索引按钮 defaultId: 0, // 默认高亮的按钮下标 buttons: ['确认', '取消'], // 按钮按索引从右往左排序 - }) + }); res.then((data)=>{ if(data.response == 0){ @@ -152,33 +170,33 @@ ipcMain.on('CLOSE', (event) => { }); windows = []; }else{ - console.log('not close software') + console.log('not close software'); } - }) -}) + }); +}); app.whenReady().then(() => { - launch() + launch(); // 屏蔽 F11 进入/退出全屏功能 - globalShortcut.register('F11', () => {return}) -}) + globalShortcut.register('F11', () => {return}); +}); app.on('window-all-closed', () => { if (process.platform !== 'darwin') { - app.quit() + app.quit(); } -}) +}); app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) { - launch() + launch(); } -}) +}); } else { - dialog.showErrorBox('系统提示', '软件启动出错,请联系售后技术支持人员') - process.exit(1) -} + dialog.showErrorBox('系统提示', '软件启动出错,请联系售后技术支持人员'); + process.exit(1); } +}; -main() +main(); diff --git a/src/main/config.js b/src/main/config.js index 0861130..e35b5e3 100644 --- a/src/main/config.js +++ b/src/main/config.js @@ -1,10 +1,10 @@ // import Store from 'electron-store' -const Store = require('electron-store') +const Store = require('electron-store'); -const store = new Store() -const set = (key, val) => store.set(key, val) +const store = new Store(); +const set = (key, val) => store.set(key, val); -const get = (key) => store.get(key) +const get = (key) => store.get(key); // export default {set, get} -module.exports = { set, get } \ No newline at end of file +module.exports = { set, get }; \ No newline at end of file diff --git a/src/main/ipcRendererManager.js b/src/main/ipcRendererManager.js index 9fdcbe7..743218d 100644 --- a/src/main/ipcRendererManager.js +++ b/src/main/ipcRendererManager.js @@ -1,26 +1,26 @@ -import { ipcMain } from 'electron' +import { ipcMain } from 'electron'; -const senders = [] +const senders = []; ipcMain.on("APP_MOUNTED", (event) => { - const { sender } = event - senders.push(sender) + const { sender } = event; + senders.push(sender); sender.once('destroyed', () => { - const index = senders.indexOf(sender) - if (index >= 0) senders.splice(index, 1) + const index = senders.indexOf(sender); + if (index >= 0) senders.splice(index, 1); }) -}) +}); const sendMsg = (channel, msg) => { - if (senders.length <= 0) return + if (senders.length <= 0) return; try { senders.forEach((sender) => { - sender.send(channel, msg) + sender.send(channel, msg); }) } catch (error) { - console.error(error) + console.error(error); } -} +}; -export default sendMsg +export default sendMsg; diff --git a/src/main/load-serialport.js b/src/main/load-serialport.js index 71fb24d..220d613 100644 --- a/src/main/load-serialport.js +++ b/src/main/load-serialport.js @@ -1,49 +1,49 @@ -import { SerialPort } from 'serialport' -import { InterByteTimeoutParser } from '@serialport/parser-inter-byte-timeout' -import config from './config.js' -import sendMsg from './ipcRendererManager' -import NMEAHandler from './api/NMEAHandler' +import { SerialPort } from 'serialport'; +import { InterByteTimeoutParser } from '@serialport/parser-inter-byte-timeout'; +import config from './config.js'; +import sendMsg from './ipcRendererManager'; +import NMEAHandler from './api/NMEAHandler'; -const DEFAULT_BAUDRATE = 115200 +const DEFAULT_BAUDRATE = 115200; const getSerialPortConstructorArguments = (ports) => { // 很多电脑自带COM1接口,过滤掉COM1口 - ports = ports.filter((port) => port.path != 'COM1') - if (ports.length == 0) return + ports = ports.filter((port) => port.path != 'COM1'); + if (ports.length == 0) return; - const serialport = config.get('serialport') - const path = ( serialport && serialport.path ) ? serialport.path : ports[0].path - const baudRate = ( serialport && serialport.baudRate ) ? serialport.baudRate : DEFAULT_BAUDRATE - return { path, baudRate } -} + const serialport = config.get('serialport'); + const path = ( serialport && serialport.path ) ? serialport.path : ports[0].path; + const baudRate = ( serialport && serialport.baudRate ) ? serialport.baudRate : DEFAULT_BAUDRATE; + return { path, baudRate }; +}; const openSerialport = (ports) => { try { - const constructorArguments = getSerialPortConstructorArguments(ports) + const constructorArguments = getSerialPortConstructorArguments(ports); if (!constructorArguments) { - console.error('设备未连接') - return + console.error('设备未连接'); + return; } - const { path, baudRate } = constructorArguments + const { path, baudRate } = constructorArguments; - const serialPort = new SerialPort({ path, baudRate }) - const parser = serialPort.pipe(new InterByteTimeoutParser({interval: 300})) + const serialPort = new SerialPort({ path, baudRate }); + const parser = serialPort.pipe(new InterByteTimeoutParser({interval: 300})); NMEAHandler.on('received' , (nmeaStr) => { - sendMsg('NMEA_RECEIVED', nmeaStr) - }) + sendMsg('NMEA_RECEIVED', nmeaStr); + }); NMEAHandler.on('handled' , (nmeaObj) => { - sendMsg('NMEA_HANDLED', JSON.stringify(nmeaObj)) - }) + sendMsg('NMEA_HANDLED', JSON.stringify(nmeaObj)); + }); - parser.on('data', (data) => NMEAHandler.handle(data.toString())) + parser.on('data', (data) => NMEAHandler.handle(data.toString())); } catch (error) { console.error(error); } -} +}; SerialPort.list().then( ports => openSerialport(ports), err => console.error(err) -) +); diff --git a/src/main/preload.js b/src/main/preload.js index c1e0c9a..6b91de8 100644 --- a/src/main/preload.js +++ b/src/main/preload.js @@ -1,20 +1,20 @@ -const { ipcRenderer, contextBridge } = require('electron') +const { ipcRenderer, contextBridge } = require('electron'); contextBridge.exposeInMainWorld('ipcRenderer', { send: (channel, data) => { // whitelist channels - let validChannels = ['toMain'] + let validChannels = ['toMain']; if (validChannels.includes(channel)) { - ipcRenderer.send(channel, data) + ipcRenderer.send(channel, data); } - ipcRenderer.send(channel, data) + ipcRenderer.send(channel, data); }, receive: (channel, func) => { - let validChannels = ['fromMain'] + let validChannels = ['fromMain']; if (validChannels.includes(channel)) { // Deliberately strip event as it includes `sender` - ipcRenderer.on(channel, (event, ...args) => func(...args)) + ipcRenderer.on(channel, (event, ...args) => func(...args)); } - ipcRenderer.on(channel, (event, ...args) => func(...args)) + ipcRenderer.on(channel, (event, ...args) => func(...args)); } -}) \ No newline at end of file +}); \ No newline at end of file diff --git a/src/render/App.vue b/src/render/App.vue index 8ed5282..c44192e 100644 --- a/src/render/App.vue +++ b/src/render/App.vue @@ -16,43 +16,46 @@
- 北斗卫星数据监测展示互动系统V1.0 + {{ softwareName }}
diff --git a/src/render/components/NMEAView.vue b/src/render/components/NMEAView.vue index 041a45b..49f53c1 100644 --- a/src/render/components/NMEAView.vue +++ b/src/render/components/NMEAView.vue @@ -10,11 +10,11 @@ \ No newline at end of file diff --git a/src/render/components/PlanisphereView.vue b/src/render/components/PlanisphereView.vue index be805ac..2e9a9f3 100644 --- a/src/render/components/PlanisphereView.vue +++ b/src/render/components/PlanisphereView.vue @@ -6,12 +6,12 @@ \ No newline at end of file diff --git a/src/render/components/SNRView.vue b/src/render/components/SNRView.vue index 1b38aaa..347edaa 100644 --- a/src/render/components/SNRView.vue +++ b/src/render/components/SNRView.vue @@ -6,11 +6,11 @@ \ No newline at end of file diff --git a/src/render/components/SubTitleView.vue b/src/render/components/SubTitleView.vue index 90ff81f..da643ef 100644 --- a/src/render/components/SubTitleView.vue +++ b/src/render/components/SubTitleView.vue @@ -5,5 +5,5 @@ \ No newline at end of file diff --git a/src/render/main.ts b/src/render/main.ts index 8b75fc9..7c3f71c 100644 --- a/src/render/main.ts +++ b/src/render/main.ts @@ -1,11 +1,11 @@ -import { createApp } from 'vue' -import App from './App.vue' +import { createApp } from 'vue'; +import App from './App.vue'; -import 'vue-cesium/dist/index.css' -import { VcConfigProvider, VcViewer, VcEntity, VcLayerImagery, VcImageryProviderSingletile, VcGraphicsBillboard } from 'vue-cesium' +import 'vue-cesium/dist/index.css'; +import { VcConfigProvider, VcViewer, VcEntity, VcLayerImagery, VcImageryProviderSingletile, VcGraphicsBillboard } from 'vue-cesium'; -import './main.css' +import './main.css'; -const app = createApp(App) -app.use(VcConfigProvider).use(VcViewer).use(VcEntity).use(VcLayerImagery).use(VcImageryProviderSingletile).use(VcGraphicsBillboard) -app.mount('#app') \ No newline at end of file +const app = createApp(App); +app.use(VcConfigProvider).use(VcViewer).use(VcEntity).use(VcLayerImagery).use(VcImageryProviderSingletile).use(VcGraphicsBillboard); +app.mount('#app'); \ No newline at end of file