完成初始页面,将要更改打开逻辑

This commit is contained in:
Smile-Xin 2025-05-07 09:50:52 +08:00
parent 1663ae7376
commit b39006c5e3
26 changed files with 5714 additions and 984 deletions

View File

@ -1,3 +0,0 @@
{
"recommendations": ["dbaeumer.vscode-eslint"]
}

39
.vscode/launch.json vendored
View File

@ -1,39 +0,0 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug Main Process",
"type": "node",
"request": "launch",
"cwd": "${workspaceRoot}",
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron-vite",
"windows": {
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron-vite.cmd"
},
"runtimeArgs": ["--sourcemap"],
"env": {
"REMOTE_DEBUGGING_PORT": "9222"
}
},
{
"name": "Debug Renderer Process",
"port": 9222,
"request": "attach",
"type": "chrome",
"webRoot": "${workspaceFolder}/src/renderer",
"timeout": 60000,
"presentation": {
"hidden": true
}
}
],
"compounds": [
{
"name": "Debug All",
"configurations": ["Debug Main Process", "Debug Renderer Process"],
"presentation": {
"order": 1
}
}
]
}

View File

@ -1,11 +1,2 @@
{
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascript]": {
"editor.defaultFormatter": "vscode.typescript-language-features"
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}

44
forge.config.js Normal file
View File

@ -0,0 +1,44 @@
const { FusesPlugin } = require('@electron-forge/plugin-fuses');
const { FuseV1Options, FuseVersion } = require('@electron/fuses');
module.exports = {
packagerConfig: {
asar: true,
},
rebuildConfig: {},
makers: [
{
name: '@electron-forge/maker-squirrel',
config: {},
},
{
name: '@electron-forge/maker-zip',
platforms: ['darwin','linux'],
},
{
name: '@electron-forge/maker-deb',
config: {},
},
{
name: '@electron-forge/maker-rpm',
config: {},
},
],
plugins: [
{
name: '@electron-forge/plugin-auto-unpack-natives',
config: {},
},
// Fuses are used to enable/disable various Electron functionality
// at package time, before code signing the application
new FusesPlugin({
version: FuseVersion.V1,
[FuseV1Options.RunAsNode]: false,
[FuseV1Options.EnableCookieEncryption]: true,
[FuseV1Options.EnableNodeOptionsEnvironmentVariable]: false,
[FuseV1Options.EnableNodeCliInspectArguments]: false,
[FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: true,
[FuseV1Options.OnlyLoadAppFromAsar]: true,
}),
],
};

5332
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -8,35 +8,49 @@
"scripts": {
"format": "prettier --write .",
"lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix",
"start": "electron-vite preview",
"start": "electron-forge start",
"dev": "electron-vite dev",
"build": "electron-vite build",
"postinstall": "electron-builder install-app-deps",
"build:unpack": "npm run build && electron-builder --dir",
"build:win": "npm run build && electron-builder --win",
"build:win": "npm run build && electron-builder --win --config",
"build:mac": "npm run build && electron-builder --mac",
"build:linux": "npm run build && electron-builder --linux"
},
"dependencies": {
"@electron-toolkit/preload": "^3.0.1",
"@electron-toolkit/utils": "^3.0.0",
"chart.js": "^4.4.7",
"element-plus": "^2.9.2",
"modbus-serial": "^8.0.17",
"vue-router": "^4.5.0"
"build:linux": "npm run build && electron-builder --linux",
"package": "electron-forge package",
"make": "electron-forge make"
},
"devDependencies": {
"@electron-forge/cli": "^7.8.0",
"@electron-forge/maker-deb": "^7.8.0",
"@electron-forge/maker-rpm": "^7.8.0",
"@electron-forge/maker-squirrel": "^7.8.0",
"@electron-forge/maker-zip": "^7.8.0",
"@electron-forge/plugin-auto-unpack-natives": "^7.8.0",
"@electron-forge/plugin-fuses": "^7.8.0",
"@electron-toolkit/eslint-config": "^1.0.2",
"@electron-toolkit/preload": "^3.0.1",
"@electron-toolkit/utils": "^3.0.0",
"@electron/fuses": "^1.8.0",
"@rushstack/eslint-patch": "^1.10.3",
"@serialport/parser-byte-length": "^13.0.0",
"@vitejs/plugin-vue": "^5.0.5",
"@vue/eslint-config-prettier": "^9.0.0",
"electron": "^31.0.2",
"electron-builder": "^24.13.3",
"chart.js": "^4.4.7",
"electron": "^35.1.4",
"electron-builder": "^26.0.12",
"electron-squirrel-startup": "^1.0.1",
"electron-vite": "^2.3.0",
"element-plus": "^2.9.2",
"eslint": "^8.57.0",
"eslint-plugin-vue": "^9.26.0",
"highcharts": "^12.1.2",
"highcharts-vue": "^2.0.1",
"prettier": "^3.3.2",
"vite": "^5.3.1",
"vue": "^3.4.30"
"vue": "^3.4.30",
"vue-router": "^4.5.0"
},
"dependencies": {
"modbus-serial": "^8.0.20"
}
}

28
src/main/IPC.js Normal file
View File

@ -0,0 +1,28 @@
const { ipcMain } = require('electron')
import { link, read, stopRead } from './modbus'
import { login } from './windows'
export function initIPC() {
// 登录后发送登录成功回复
ipcMain.on('login', (event, message) => {
login(event, message)
// link(event, message)
})
// 接收渲染进程发送的link请求
ipcMain.on('link', (event, message) => {
link(event, message)
})
// 读取寄存器
ipcMain.on('read', (event, message) => {
read(event, message)
console.log('pong')
})
// 停止modbus读取
ipcMain.on('stop', (event) => {
stopRead(event)
})
}

View File

@ -1,175 +1,26 @@
import { app, shell, BrowserWindow, ipcMain } from 'electron'
import { join } from 'path'
import { electronApp, optimizer, is } from '@electron-toolkit/utils'
import icon from '../../resources/icon.png?asset'
const { app, BrowserWindow } = require('electron')
const { electronApp, optimizer } = require('@electron-toolkit/utils')
import { createWindow, createChildWindow } from './windows'
import { initIPC } from './IPC'
// 模拟配置的modbus配置单
const modbusConfig = {
name: [
'风速',
'风向',
'温度',
'湿度',
'气压',
'光照',
'雨量',
'PM2.5',
'PM10',
'噪音',
], // 名称
}
var ModbusRTU = require('modbus-serial')
var client = new ModbusRTU()
// 寄存器循环
var time = null
// 主窗口
var mainWindow
// 登录窗口
var loginWindow
// 连接后读取modbus从机的连接
var readClient
// var realTimeData = []
// 读取寄存器
ipcMain.on('read', (event, message) => {
read(event, message)
console.log('pong')
})
// 登录后开启modbus连接
ipcMain.on('login', (event, message) => {
// login(event, message)
mainWindow.webContents.send('loginReply', 1)
loginWindow.close()
})
// 登录
// function login(event, message) {
// // 登录业务代码
// console.log('login', message, event)
// }
// 接收渲染进程发送的link请求
ipcMain.on('link', (event, message) => {
link(event, message)
})
// 连接modbus
function link(event, message) {
// 连接modbus
client.connectTCP(message.ip, { port: 502 })
// 连接成功后读取寄存器方法
readClient = (event, message) => {
client.readHoldingRegisters(message.startAddress, message.quantity, function (err, data) {
if (err) {
event.reply('readReply', err)
return
}
event.reply('readReply', dataHandle(data.data))
})
}
read(event, message)
}
// 通过功能码03读取寄存器
function read(event, message) {
if (!(time == null)) {
console.log('重复读取数据', time)
return
}
// 循环读取寄存器
time = setInterval(() => {
readClient(event, message)
}, 500)
}
// 数据处理
function dataHandle(data) {
let result = []
for (let i = 0; i < modbusConfig.name.length; i++) {
result[i] = {
name: modbusConfig.name[i],
data: data[i]
}
}
// function dataHandle(data) {
// let result = []
// for (let i = 0; i < modbusConfig.name.length; i++) {
// result[i] = {
// name: modbusConfig.name[i],
// data: data[i]
// }
// }
return result
}
// return result
// }
// 停止modbus读取
ipcMain.on('stop', (event) => {
clearInterval(time)
time = null
console.log('stop')
// 返回数据给渲染进程
event.reply('readReply', [])
})
// 创建主窗口
function createWindow() {
// Create the browser window.
mainWindow = new BrowserWindow({
width: 900,
height: 670,
show: false,
autoHideMenuBar: true,
...(process.platform === 'linux' ? { icon } : {}),
webPreferences: {
preload: join(__dirname, '../preload/index.js'),
sandbox: false
}
})
mainWindow.on('ready-to-show', () => {
mainWindow.show()
})
mainWindow.webContents.setWindowOpenHandler((details) => {
shell.openExternal(details.url)
return { action: 'deny' }
})
// HMR for renderer base on electron-vite cli.
// Load the remote URL for development or the local html file for production.
if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL'])
} else {
mainWindow.loadFile(join(__dirname, '../renderer/index.html'))
}
}
// 创建子窗口
function createChildWindow() {
loginWindow = new BrowserWindow({
parent: mainWindow,
width: 500,
height: 400,
show: false,
autoHideMenuBar: true,
...(process.platform === 'linux' ? { icon } : {}),
webPreferences: {
preload: join(__dirname, '../preload/index.js'),
sandbox: false
}
})
loginWindow.on('ready-to-show', () => {
loginWindow.show()
})
loginWindow.webContents.setWindowOpenHandler((details) => {
// console.log('details.url', details.url)
shell.openExternal(details.url)
return { action: 'deny' }
})
// HMR for renderer base on electron-vite cli.
// Load the remote URL for development or the local html file for production.
if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
// console.log(process.env['ELECTRON_RENDERER_URL'] + '/#/login')
loginWindow.loadURL(process.env['ELECTRON_RENDERER_URL'] + '/#/login')
} else {
// loginWindow.loadURL(join(__dirname, '../renderer/login.html'))
}
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
@ -186,7 +37,9 @@ app.whenReady().then(() => {
})
createWindow()
createChildWindow()
// createChildWindow()
initIPC()
app.on('activate', function () {
// 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.

0
src/main/init.js Normal file
View File

60
src/main/modbus.js Normal file
View File

@ -0,0 +1,60 @@
const ModbusRTU = require('modbus-serial')
let client
// 寄存器循环
let time = null
// 连接modbus
export function link(event, message) {
// 创建modbus连接
client = new ModbusRTU()
// 根据IP连接modbus
client.connectTCP(message.ip, { port: 502 }, function (err) {
if (err) {
console.log('连接失败', err)
event.reply('linkReply', { code: 4, message: '连接失败', err })
return
}
console.log('连接成功')
event.reply('linkReply', { code: 200, message: '连接成功' })
}
)
read(event, message)
}
// 根据页面需要的数据读取寄存器(定义一个读取寄存器并返回数据到渲染进程的方法)
function readClient(event, message) {
// 连接成功后定义读取寄存器方法
client.readHoldingRegisters(message.startAddress, message.quantity, function (err, data) {
if (err) {
event.reply('readReply', err)
return
}
// realTimeData[0].push(data.data[0])
//console.log('data',data.data)
event.reply('readReply', data.data)
})
}
// 调用根据页面需要的数据读取寄存器的方法
export function read(event, message) {
if (!(time == null)) {
console.log('重复读取数据', time)
return
}
// 循环读取寄存器
time = setInterval(() => {
readClient(event, message)
}, 1000)
}
export function stopRead(event) {
clearInterval(time)
time = null
console.log('stop')
// 返回数据给渲染进程
event.reply('readReply', [])
}

96
src/main/windows.js Normal file
View File

@ -0,0 +1,96 @@
import { shell, BrowserWindow } from 'electron'
import { join } from 'path'
import { is } from '@electron-toolkit/utils'
import icon from '../../resources/icon.png?asset'
// 主窗口
let mainWindow
// 登录窗口
let loginWindow
// 创建主窗口
export function createWindow() {
// Create the browser window.
mainWindow = new BrowserWindow({
width: 900,
height: 670,
show: false,
autoHideMenuBar: true,
...(process.platform === 'linux' ? { icon } : {}),
webPreferences: {
preload: join(__dirname, '../preload/index.js'),
sandbox: false
}
})
mainWindow.on('ready-to-show', () => {
mainWindow.show()
})
mainWindow.webContents.setWindowOpenHandler((details) => {
shell.openExternal(details.url)
return { action: 'deny' }
})
// HMR for renderer base on electron-vite cli.
// Load the remote URL for development or the local html file for production.
if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL'] + '/#/login')
// mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL'] + '/#/main/index')
} else {
mainWindow.loadFile(join(__dirname, '../renderer/index.html'), { hash: 'login' })
// mainWindow.loadFile(join(__dirname, '../renderer/index.html'), { hash: 'main/index' })
}
}
// 创建子窗口
export function createChildWindow() {
loginWindow = new BrowserWindow({
parent: mainWindow,
width: 500,
height: 400,
show: false,
autoHideMenuBar: true,
...(process.platform === 'linux' ? { icon } : {}),
webPreferences: {
preload: join(__dirname, '../preload/index.js'),
sandbox: false
}
})
loginWindow.on('ready-to-show', () => {
loginWindow.show()
})
loginWindow.webContents.setWindowOpenHandler((details) => {
// console.log('details.url', details.url)
shell.openExternal(details.url)
return { action: 'deny' }
})
// HMR for renderer base on electron-vite cli.
// Load the remote URL for development or the local html file for production.
if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
// console.log(process.env['ELECTRON_RENDERER_URL'] + '/#/login')
loginWindow.loadURL(process.env['ELECTRON_RENDERER_URL'] + '/#/login')
} else {
loginWindow.loadURL(join(__dirname, '../renderer/index.html'), { hash: 'login' })
}
}
// export function login(event, message){
// mainWindow.webContents.send('loginReply', message.ip)
// loginWindow.close()
// }
export function login(event, message){
mainWindow.webContents.send('loginReply', message.ip)
loginWindow.close()
}
// 返回主窗口
export function getMainWindow() {
return mainWindow
}
// 返回登录子窗口
export function getLoginWindow() {
return loginWindow
}

View File

@ -2,7 +2,7 @@
<html>
<head>
<meta charset="UTF-8" />
<title>Electron</title>
<title>风机单机控制软件</title>
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta
http-equiv="Content-Security-Policy"

View File

@ -1,5 +1,4 @@
<script setup>
</script>
<template>

View File

@ -5,7 +5,8 @@ body {
align-items: center;
justify-content: center; */
overflow: hidden;
background-image: url('./wavy-lines.svg');
/* background-image: url('./wavy-lines.svg'); */
background-color: aliceblue;
background-size: cover;
user-select: none;
}

View File

@ -1,8 +1,10 @@
<template>
<div class="topBar">
<el-menu :default-active="activeIndex" class="el-menu-demo" mode="horizontal" @select="handleSelect">
<el-menu-item index="/">modbus测试</el-menu-item>
<el-menu-item index="chart">可视化图表</el-menu-item>
<el-menu-item index="index" class="index">主界面</el-menu-item>
<el-menu-item index="chart" class="chart">浏览</el-menu-item>
<el-menu-item index="login_info" class="login">登录</el-menu-item>
<el-menu-item index="logout" class="logout">注销</el-menu-item>
</el-menu>
</div>
</template>
@ -18,5 +20,25 @@ const handleSelect = (key, heyPath) => {
}
</script>
<style scoped>
.el-menu-demo {
background-color: rgb(6, 63, 80);
border-bottom: 0;
height:5vh;
}
.index {
color: #409eff;
height:5vh
}
.chart {
color: #67c23a;
height:5vh
}
.login {
color: #909399;
height:5vh
}
.logout {
color: #f56c6c;
height:5vh
}
</style>

View File

@ -1,9 +1,18 @@
import { createRouter, createWebHashHistory } from 'vue-router'
const routes = [
{ path: '/', component: () => import('../view/index.vue') },
{ path: '/login', component: () => import('../view/login.vue') },
{ path: '/chart', component: () => import('../view/LineChart.vue') }
{
path: '/main', component: () => import('../view/MainView.vue'),
children: [
{ path: 'index', component: () => import('../view/index.vue') },
{ path: 'chart', component: () => import('../view/LineChart.vue') },
{ path: 'logout', component: () => import('../view/logout.vue') },
{ path: 'login_info', component: () => import('../view/login.vue') }
]
},
{ path: '/login', component: () => import('../view/Connect.vue') },
{ path: '/*', component: () => import('../view/Connect.vue') },
{ path: '/', component: () => import('../view/Connect.vue') }
]
const router = createRouter({

View File

@ -0,0 +1,58 @@
<template>
<div>
<div class="fromDiv">
<div class="fromLable">
<p>ip地址</p> <input v-model="parameters.ip" type="text" /> <br />
</div>
<div class="fromLable">
<button class="linkBtn" @click="login">连接</button>
</div>
</div>
</div>
</template>
<script setup>
import { reactive, toRaw } from 'vue'
let parameters = reactive({
ip: '192.168.151.59'
})
function login() {
window.electron.ipcRenderer.send('login', toRaw(parameters))
}
</script>
<style scoped>
.fromLable {
margin-top: 20%;
}
p {
display: inline-block;
/* width: 100px; */
}
.fromDiv {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
width: 100%;
height: 100%;
}
.linkBtn {
width: 100px;
height: 40px;
background-color: #1c2834;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
display: inline-block;
text-align: center;
line-height: 40px;
font-size: 16px;
transition: 3s;
}
</style>

View File

@ -1,42 +1,53 @@
<template>
<Topbar />
<!-- <Topbar /> -->
<div>
<div id="test"></div>
<canvas id="myChart" width="400" height="400"></canvas>
<div id="main"></div>
<div id="myChart"></div>
</div>
</template>
<script setup>
import { Chart, LineController, LineElement, PointElement } from 'chart.js'
import Topbar from '../components/topBar.vue'
import { onMounted } from 'vue'
import { onMounted, ref } from 'vue'
import Highcharts from 'highcharts'
const data = {
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [
{
label: 'My First dataset',
backgroundColor: 'rgb(255, 99, 132)',
borderColor: 'rgb(255, 99, 132)',
data: [0, 10, 5, 2, 20, 30, 45],
},
],
}
// import Topbar from '../components/Topbar.vue'
onMounted(() => {
const chart = document.getElementById("myChart")
console.log("✈···", chart)
new Chart(
chart,
{
type: 'line',
data: data,
const chartContainer = document.getElementById("myChart")
console.log("✈···", chartContainer)
new Highcharts.Chart(chartContainer, {
chart: {
type: 'line'
},
title: {
text: 'Line Chart'
},
xAxis: {
categories: ['A', 'B', 'C', 'D', 'E']
},
yAxis: {
title: {
text: 'Fruit eaten'
}
);
},
series: [{
name: 'Jane',
data: [1, 0, 4, 5, 2]
}, {
name: 'John',
data: [5, 7, 3, 2, 1]
}]
})
})
</script>
<style scoped></style>
<style scoped>
#myChart {
z-index: 99;
width: 600px;
height: 300px;
}
</style>

View File

@ -0,0 +1,10 @@
<template>
<TopBar />
<router-view />
</template>
<script setup>
import TopBar from '../components/topBar.vue'
</script>
<style scoped></style>

View File

@ -1,76 +1,413 @@
<template>
<TopBar />
<!-- <TopBar /> -->
<div>
<p class="tip">modbus测试</p>
<el-table :data="modbusData" style="width: 100%">
<el-table-column prop="name" label="变量名"></el-table-column>
<el-table-column prop="data" label="数值"></el-table-column>
</el-table>
<div class="container">
<div class = "top">
<table id="customers" class="head" >
<tbody>
<tr>
<th>用户</th>
<div class="actions">
<div class="action">
<a target="_blank" rel="noreferrer" @click="ipcHandle">继续</a>
<a target="_blank" rel="noreferrer" @click="ipcModbus">停止</a>
<th class="alt1">09</th>
<th>权限</th>
<th class="alt1">管理员</th>
<th >登录位置</th>
<th class="alt1">{{ parameters.ip }}</th>
</tr>
<tr>
<td class="alt">当天电量</td>
<td> {{modbusData[109]}} kwh</td>
<td class="alt">当天运行时间</td>
<td> {{modbusData[112]}} h</td>
<td class="alt">当天可利用率</td>
<td>{{(0.1 * modbusData[106]).toFixed(2)}}%</td>
</tr>
<tr >
<td class="alt">累计电量</td>
<td>{{(modbusData[111])}}kwh</td>
<td class="alt">累计运行时间</td>
<td> {{(modbusData[114])}} h</td>
<td class="alt">累计可利用率</td>
<td>{{(0.1 * modbusData[107]).toFixed(2)}}%</td>
</tr>
</tbody>
</table>
</div>
<div class="main">
<div class="main_left">
<table id="customers" >
<caption>Active Statuscodes</caption>
<tbody>
<tr class="table_statuscodes">
<td></td>
</tr>
<tr class="table_statuscodes">
<td></td>
</tr>
<tr class="table_statuscodes">
<td></td>
</tr>
<tr class="table_statuscodes">
<td></td>
</tr>
<tr class="table_statuscodes">
<td></td>
</tr>
<tr class="table_statuscodes">
<td></td>
</tr>
<tr class="table_statuscodes">
<td></td>
</tr>
<tr class="table_statuscodes">
<td></td>
</tr>
<tr class="table_statuscodes">
<td></td>
</tr>
<tr class="table_statuscodes">
<td></td>
</tr>
<tr class="table_statuscodes">
<td></td>
</tr>
<tr class="table_statuscodes">
<td></td>
</tr>
<tr class="table_statuscodes">
<td></td>
</tr>
<tr class="table_statuscodes">
<td></td>
</tr>
<tr class="table_statuscodes">
<td></td>
</tr>
</tbody>
</table>
</div>
<div class="main_right">
<div class="main_info_caption">主要信息</div>
<table id="customers" class="main_info">
<tbody>
<tr>
<th>测点</th>
<th>实时值</th>
<th>1秒平均值</th>
<th>30秒平均值</th>
<th>设定值</th>
</tr>
<tr class="alt3">
<td>有功功率</td>
<td>{{(0.1 * modbusData[1]).toFixed(1)}}KW</td>
<td>{{(0.1 * modbusData[9]).toFixed(1)}}KW</td>
<td>KW</td>
<td>{{(0.1 * modbusData[18]).toFixed(1)}}KW</td>
</tr>
<tr class="alt2">
<td>风速</td>
<td>{{(0.01 * modbusData[2]).toFixed(2)}}m/s</td>
<td>{{(0.01 * modbusData[10]).toFixed(2)}}m/s</td>
<td>m/s</td>
<td>m/s</td>
</tr>
<tr class="alt3">
<td>发电机转速</td>
<td>{{(0.1 * modbusData[0]).toFixed(0)}}rpm</td>
<td>{{(0.1 * modbusData[8]).toFixed(0)}}rpm</td>
<td>rpm</td>
<td>{{(0.1 * modbusData[17]).toFixed(0)}}rpm</td>
</tr>
<tr class="alt2">
<td>浆叶角度</td>
<td>{{(0.01 * modbusData[19]).toFixed(0)}}deg</td>
<td>{{(0.01 * modbusData[20]).toFixed(0)}}deg</td>
<td>{{(0.01 * modbusData[21]).toFixed(0)}}deg</td>
<td>{{(0.01 * modbusData[18]).toFixed(0)}}deg</td>
</tr>
</tbody>
</table>
<div class="power_grid_head">电网</div>
<table id="customers" class="power_grid">
<tbody>
<tr class="alt3">
<td>有功功率</td>
<td>{{(0.1 * modbusData[1]).toFixed(1)}}KW</td>
<td>L1电压</td>
<td>{{(0.1 * modbusData[52]).toFixed(1)}}V</td>
</tr>
<tr class="alt2">
<td>无功功率</td>
<td>{{(0.1 * modbusData[14]).toFixed(1)}}KVar</td>
<td>L2电压</td>
<td>{{(0.1 * modbusData[53]).toFixed(1)}}V</td>
</tr>
<tr class="alt3">
<td>功率因数</td>
<td>{{(0.001 * modbusData[64]).toFixed(1)}}</td>
<td>L3电压</td>
<td>{{(0.1 * modbusData[54]).toFixed(1)}}V</td>
</tr>
<tr class="alt2">
<td>频率</td>
<td>{{(0.1 * modbusData[51]).toFixed(1)}}HZ</td>
<td>线电流</td>
<td>{{(0.1 * modbusData[56]).toFixed(1)}}A</td>
</tr>
</tbody>
</table>
<div class="yaw">
<div class="yaw_head">偏航</div>
<div class="btn-group1">
<button id="button1" class="button1">手动偏航</button>
<button id="button2" class="button1">停止偏航</button>
<button id="button3" class="button1">瞬时针</button>
<button id="button4" class="button1">逆时针>></button>
</div>
<div class="box">
<table id="customers">
<tbody>
<tr class="alt3">
<td>机舱方向角度</td>
<td>{{(0.1 * modbusData[25]).toFixed(1)}}deg</td>
</tr>
<tr class="alt2">
<td>机舱总角度</td>
<td>{{(0.1 * modbusData[70]).toFixed(1)}}deg</td>
</tr>
<tr class="alt3">
<td>扭揽角度</td>
<td>{{(0.1 * modbusData[69]).toFixed(1)}}deg</td>
</tr>
<tr class="alt2">
<td>风向角度</td>
<td>{{(0.1 * modbusData[26]).toFixed(1)}}deg</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="control">
<div class="control_head">控制</div>
<div class="btn-group2">
<button id="button5" class="button2">停止</button>
<button id="button6" class="button2">代码复位</button>
<button id="button7" class="button2">安全链复位</button>
<button id="button8" class="button2">快速启动</button>
<button id="button5" class="button2">趋势</button>
<button id="button6" class="button2">状态码记录</button>
<button id="button7" class="button2">特殊功能</button>
<button id="button8" class="button2">台风模式</button>
</div>
</div>
</div>
</div>
<div class="footer">
<div class="btn-group3">
</div>
</div>
</div>
<!-- <p>{{ modbusData }}</p> -->
</div>
</template>
<script setup>
import { reactive, toRaw } from 'vue'
import TopBar from '../components/topBar.vue'
import { reactive, toRaw, onMounted, onBeforeUnmount } from 'vue';
import TopBar from '../components/topBar.vue';
let modbusData = reactive([])
let modbusData = reactive([]);
let parameters = reactive({
ip: '192.168.151.59',
ip: '',
slaveId: 1,
startAddress: 600,
quantity: 10,
// unitId: 1,
quantity: 127,
functionCode: 3,
})
});
//
onMounted(() => {
const savedParameters = localStorage.getItem('parameters');
if (savedParameters) {
Object.assign(parameters, JSON.parse(savedParameters));
}
});
//
onBeforeUnmount(() => {
localStorage.setItem('parameters', JSON.stringify(parameters));
});
const ipcHandle = () => window.electron.ipcRenderer.send('read', toRaw(parameters));
const ipcModbus = () => window.electron.ipcRenderer.send('stop');
const ipcHandle = () => window.electron.ipcRenderer.send('read', toRaw(parameters))
const ipcModbus = () => window.electron.ipcRenderer.send('stop')
//
window.electron.ipcRenderer.on('loginReply', (event, message) => {
if (message) {
// modbus
window.electron.ipcRenderer.send('link', toRaw(parameters))
parameters.ip = message;
localStorage.setItem('parameters', JSON.stringify(parameters));
window.electron.ipcRenderer.send('link', toRaw(parameters));
} else {
console.log('连接失败')
console.log('连接失败');
}
})
});
// modbus
window.electron.ipcRenderer.on('readReply', (event, message) => {
for (let i = 0; i < message.length; i++) {
modbusData[i] = {
name: message[i].name,
data: message[i].data
modbusData[i] = message[i];
}
}
})
// const handleClick = (tab, event) => {
// console.log(tab, event)
// }
//console.log(modbusData);
});
</script>
<style scoped>
.tabs {
position: absolute;
top: 0;
left: 0;
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-size: 12px;
}
.container{
height: 100vh;
.top{
height: 13vh;
color: #000000;
.head{
height: 100%;
}
}
.main{
display: grid;
grid-template-columns: 2fr 3fr;
gap: 1px; /* 列间距 */
height: 80.5vh; /* 容器高度 */
.main_left{
background-color: rgb(204, 233, 242);
.table_statuscodes{
height: 5.15vh; /* 固定行高 */
}
}
.main_right{
background-color: rgb(204, 233, 242);
height:100%;
.fromDiv>p {
.power_grid{
height: 20%;
}
.yaw{
display: grid;
height: 25%;
grid-template-columns: 1fr 1fr ; /* 创建2列1:2 */
margin-top: 0.5vh;
.yaw_head{
grid-column: 1 / span 2; /* 从第1列开始跨越2列 */
text-align:center;
background-color: rgb(6, 63, 80);
color: red;
font-weight: bold;
}
}
.control{
height: 15%;
margin-top: 0.5vh;
.control_head{
grid-column: 1 / span 2; /* 从第1列开始跨越2列 */
text-align:center;
background-color: rgb(6, 63, 80);
color: red;
font-weight: bold;
}
}
}
}
.footer{
height: 6.5vh;
background-color: rgb(6, 63, 80);
.btn_group3{
height: 100%;
width: 50%;
}
}
}
.main_info{
height: 30%;
}
.power_grid_head{
display: inline-block;
width: 100px;
width: 100%;
background-color: rgb(6, 63, 80);
color: #f20909;
font-weight: bold;
text-align: center;
margin-top: 0.5vh;
}
.fromDiv>input {
/* width: 200px; */
.main_info_caption{
display: inline-block;
width: 100%;
background-color: rgb(6, 63, 80);
color: #f20909;
font-weight: bold;
text-align: center;
}
#customers
{
font-family:"Trebuchet MS", Arial, Helvetica, sans-serif;
width:100%;
text-align:center;
border-collapse:collapse;
}
#customers td, #customers th
{
font-size:1em;
border:1px solid rgb(16, 180, 231);
padding:3px 7px 2px 7px;
}
#customers caption{
background-color:rgb(6, 63, 80);
color:#f20909;
font-weight: bold;
}
#customers th
{
font-size:1.1em;
padding-top:5px;
padding-bottom:4px;
background-color:rgb(6, 63, 80);
color:#ffffff;
}
#customers tr.alt2
{
color:#000000;
background-color:#EAF2D3;
}
#customers tr.alt3
{
color:#000000;
background-color:#ffffff;
}
#customers td.alt
{
color:#000000;
background-color:#EAF2D3;
}
#customers th.alt1
{
color:greenyellow;
}
.button1{
width: 80%;
margin-left: 10%;
margin-top: 1.6%;
background-color: #EAF2D3;
}
.button2{
width: 20%;
margin-left: 4%;
margin-top: 1%;
height: 3%;
background-color:#EAF2D3;
}
</style>

View File

@ -1,58 +1,53 @@
<template>
<!-- <Topbar /> -->
<div>
<div class="fromDiv">
<div class="fromLable">
<p>ip地址</p> <input v-model="parameters.ip" type="text" /> <br />
</div>
<div class="fromLable">
<button class="linkBtn" @click="login">连接</button>
</div>
</div>
<div id="main"></div>
<div id="myChart"></div>
</div>
</template>
<script setup>
import { reactive, toRaw } from 'vue'
let parameters = reactive({
ip: '192.168.151.59'
import { onMounted, ref } from 'vue'
import Highcharts from 'highcharts'
// import Topbar from '../components/Topbar.vue'
onMounted(() => {
const chartContainer = document.getElementById("myChart")
console.log("✈···", chartContainer)
new Highcharts.Chart(chartContainer, {
chart: {
type: 'line'
},
title: {
text: 'Line Chart'
},
xAxis: {
categories: ['A', 'B', 'C', 'D', 'E']
},
yAxis: {
title: {
text: 'Fruit eaten'
}
},
series: [{
name: 'Jane',
data: [1, 0, 4, 5, 2]
}, {
name: 'John',
data: [5, 7, 3, 2, 1]
}]
})
})
function login() {
window.electron.ipcRenderer.send('login', toRaw(parameters))
}
</script>
<style scoped>
.fromLable {
margin-top: 20%;
}
p {
display: inline-block;
/* width: 100px; */
}
.fromDiv {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
width: 100%;
height: 100%;
}
.linkBtn {
width: 100px;
height: 40px;
background-color: #1c2834;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
display: inline-block;
text-align: center;
line-height: 40px;
font-size: 16px;
transition: 3s;
#myChart {
z-index: 99;
width: 600px;
height: 300px;
}
</style>

View File

@ -0,0 +1,53 @@
<template>
<!-- <Topbar /> -->
<div>
<div id="main"></div>
<div id="myChart"></div>
</div>
</template>
<script setup>
import { onMounted, ref } from 'vue'
import Highcharts from 'highcharts'
// import Topbar from '../components/Topbar.vue'
onMounted(() => {
const chartContainer = document.getElementById("myChart")
console.log("✈···", chartContainer)
new Highcharts.Chart(chartContainer, {
chart: {
type: 'line'
},
title: {
text: 'Line Chart'
},
xAxis: {
categories: ['A', 'B', 'C', 'D', 'E']
},
yAxis: {
title: {
text: 'Fruit eaten'
}
},
series: [{
name: 'Jane',
data: [1, 0, 4, 5, 2]
}, {
name: 'John',
data: [5, 7, 3, 2, 1]
}]
})
})
</script>
<style scoped>
#myChart {
z-index: 99;
width: 600px;
height: 300px;
}
</style>

7
研发.md Normal file
View File

@ -0,0 +1,7 @@
# electron
## modbus
1. 页面输入IP
2. 主进程拿到IP创建连接
3. IP输入页面关闭首页打开
4. 首页打开自动向主进程发送信息
5. 主进程收到信息用modbus连接读首页需要的信息