Compare commits

...

47 Commits

Author SHA1 Message Date
fhysy d66df5e2cf refactor(config): 更新配置信息和软件版本
- 修改了资源和服务配置文件中的 URL 和端口设置
- 更新了主进程启动参数,增加了用户数据路径
-调整了校准参数中的电流值
- 降低了软件版本号
- 新增了串口通信配置文件
2025-08-01 11:39:44 +08:00
fhysy 7d53c34651 feat(calibration): 添加标定后检测步骤功能
- 新增标定后检测步骤表格和相关功能
- 优化标定步骤界面布局和交互
- 修复部分组件样式问题
- 版本号升级到 1.0.12
2025-07-31 10:16:05 +08:00
fhysy a929a7b47d feat(renderer): 更新图标字体并添加生产统计功能,升级1.0.10版本
- 更新图标字体文件版本
- 添加展开/收起图标
- 在校准页面添加生产总数/合格数/不合格次数统计
- 优化校准设备列表渲染逻辑
- 调整输入框样式
2025-07-29 15:39:45 +08:00
fhysy 7c8b2477d5 feat(export): 实现生产数据导出功能,解决日志滚动不到底部bug,升级1.0.9
- 添加导出生产数据的接口和相关逻辑
- 新增导出时间范围选择功能
- 优化日志滚动和结果显示
- 调整标定日志结构判断逻辑
- 更新 UI 样式,增加配置密钥功能
2025-07-24 09:31:37 +08:00
fhysy 95f8374a13 feat(renderer): 新增方案管理功能并优化界面
- 新增方案复制、导入、导出功能
- 添加错误日志展示
- 优化方案配置界面布局
- 调整图标样式
- 修复部分功能逻辑
2025-07-15 16:56:19 +08:00
fhysy 1b9ff88922 feat(calibration): 增加日志搜索功能并优化用户界面
- 添加日志搜索功能,支持快捷键操作
- 优化设备参数显示,隐藏 reserve 字段
- 调整日志高亮显示,增加搜索结果导航
- 重新布局快捷键提示和版本信息
- 优化方案列表获取逻辑,确保数据同步- 校验标定中检测和标定后检测至少选择一个
- 优化断路器校准参数显示样式
- 更新软件版本号至 1.0.6
2025-07-11 17:36:20 +08:00
fhysy a08559f55f fix(calibration): 优化电流显示和日志功能
- 修复了电流显示错误的问题,增加了对漏电流的特殊处理
- 扩大了设备日志窗口的大小,提高了可读性
- 优化了参数误差的计算和显示逻辑
- 增加了对方案列表获取逻辑的改进,确保选中方案与实际方案一致
- 提升了日志缓存的长度,从800增加到2000
2025-07-10 10:09:38 +08:00
fhysy b71aaf4ff7 feat(calibration): 重构标定功能并添加新配置项
- 重新设计了标定页面布局和功能
- 添加了操作员编号输入字段
- 新增了标定中和标定后检测的配置项
- 优化了设备列表和日志的显示方式
- 重构了日志处理和设备信息更新的逻辑
- 新增了漏电检测相关的配置项
2025-07-08 17:00:43 +08:00
fhysy 9646a4ae8c feat(config): 动态加载配置文件并支持远程和本地路径
- 在 preload 中添加 readConfig函数,动态加载 config.js
- 修改 logWebSocket 和 socket 以使用动态加载的配置
- 更新 calibration 页面以使用新配置
- 添加资源目录下的 config.js 文件,包含不同环境的 API URL
2025-06-30 16:39:32 +08:00
fhysy f697d427ad feat(renderer): 优化标定结果展示、socket日志记录功能、socket日志结果处理接口、调整标定日志结构
- 更新 iconfont 文件,增加新的图标
- 优化标定结果展示,增加未标定状态
- 重构日志记录功能,支持不同类型的标定结果
- 修复设备信息同步问题
- socket日志结果处理接口
- 调整标定日志结构
2025-06-30 11:49:35 +08:00
fhysy 34108a2186 refactor(calibration): 添加日志-标定日志获取、调整ui状态、添加socket重连功能、格式化日志数据
- 更新标定结果展示逻辑,使用数值判断成功与否
- 优化日志状态显示,增加重连功能
- 调整设备信息展示样式,突出标定结果
- 新增设备日志数据获取和处理逻辑
2025-06-27 11:55:50 +08:00
fhysy 4d0d6c2ab9 feat(main): 添加获取应用版本功能并优化日志功能
- 在主进程中添加 get-app-version 的 IPC 处理程序,返回应用版本号
- 在预加载脚本中暴露 getAppVersion 方法给渲染进程
- 在 calibration 页面中添加版本信息显示
- 优化日志显示功能,增加日志转置和分页显示
- 添加清空日志功能
- 调整设备卡片样式,增加选中状态
2025-06-25 18:13:40 +08:00
fhysy cd708e9eb9 build(electron): 更新软件版本和环境变量处理
- 移除环境变量 VITE_APP_VERSION 的定义和使用
- 将软件版本从 1.0.9 修改为 1.0.0
- 调整方案列表背景色从 #ccc 改为 #ddd
2025-06-20 17:46:24 +08:00
fhysy 902ba88c2f feat(renderer): 优化日志功能和界面布局
- 更新 iconfont 文件,添加新的图标
- 重构日志显示逻辑,支持不同类型的消息
- 添加方案详情展示区域
- 优化方案编辑界面布局
- 实现日志滚动和展开/收缩功能
- 添加版本号动态显示
- 优化 WebSocket 连接管理
2025-06-20 15:24:40 +08:00
fhysy fa641c5a28 feat/calibration: 对接后端接口和调整界面
- 添加了获取默认断路器标准参数和标定参数接口
- 实现了方案的添加、编辑、删除等api操作
- 实现参数精度提交之前的回填
- 增加了与后端API的交互,支持数据的加载和保存
2025-06-18 17:49:17 +08:00
fhysy 68e29d3ace feat(calibration): 新增方案配置功能
- 添加方案配置抽屉和对话框
- 实现方案列表加载、查看、新增、删除功能
- 添加校准参数、设备参数、校准精度、标定步骤等配置项
- 优化界面样式,增加面包屑导航
2025-06-17 17:47:34 +08:00
fhysy 16c8adc1f4 feat(calibration): 调整标定页面样式 2025-06-16 11:15:07 +08:00
fhysy 57cf6523ef refactor(layout): 重构整体布局并移除未使用的组件和页面,调整应用配置,添加断路器标定页面
- 删除了 无用组件和页面
- 调整了 Layout 组件的样式
- 更新了路由配置,重定向到新的 calibration 页面
- 调整应用配置
- 添加断路器标定页面
2025-06-06 16:39:43 +08:00
fhysy e97b8516ae fast(dev): 调整config配置 2025-06-06 10:22:35 +08:00
fhysy 20a8a95141 fast(dev): 开发环境添加vite-plugin-vue-devtools 查看插件 2025-06-06 10:09:48 +08:00
fhysy c8dd26aec2 fast(ui): 更新图标库和菜单图标 2025-03-27 15:23:25 +08:00
fhysy d36ad16535 fast(扫码录入): 添加扫码枪串口录入 2025-03-27 15:15:17 +08:00
fhysy 6c6a3ba4e7 refactor(layout): 添加扫码录入页面和菜单 2025-03-25 10:34:24 +08:00
fhysy 3bb9a938d5 refactor(layout): 注释掉部分菜单项并更新默认 MQTT 服务器地址
- 注释掉了视频监控、北向任务配置和采集数据监视等菜单项
- 将断路器调试页面的 MQTT 服务器地址修改为 digital.drgyen.com
2025-03-11 10:03:08 +08:00
fhysy 297d998365 fix(网关调试):调整设备基础参数字段,升级1.0.8 2024-12-06 15:33:42 +08:00
fhysy 9a143c26b0 fix(网关调试):对接采集数据监视接口、调整南北向页面显示 2024-11-26 10:40:00 +08:00
fhysy b38b07e5bb fix(网关调试): 调整南向北向逻辑 2024-11-22 17:26:51 +08:00
fhysy 5c8ec926f9 fix(网关调试): 初始化刷新table宽度,解决导出表格错误 2024-11-20 14:23:29 +08:00
fhysy 2d4d509ef0 fast(网关相关): 添加南向、北向、数据采集页面,及南向和北向部分接口对接 2024-11-15 17:54:05 +08:00
fhysy 9364ef8412 fast(串口调试): 添加串口通用调试(地址读写指令)、打包1.0.7 2024-11-07 11:01:20 +08:00
fhysy 1c024beeb8 fast(串口调试): 增加串口连接功能、设备参数获取写入、断路器标定功能、解决相关bug、打包1.0.6 2024-10-31 14:02:42 +08:00
fhysy d12381feb3 fast(断路器): 增加日志类型图标提示、解决websocket报错、日志自动清理上限改为400条 2024-10-21 14:21:40 +08:00
fhysy 1d67888b56 fast(断路器): 增加日志反选功能、添加断路器“实时采集(1次/分钟)”功能预设,打包 2024-09-04 14:44:27 +08:00
fhysy 3af303b605 fix(断路器): 日志上限改成200条,格式化代码 2024-08-20 11:10:35 +08:00
fhysy 6257501187 feat(断路器): 修复日志缺少类型,添加日志类型过滤 2024-08-16 17:09:33 +08:00
fhysy 69756af817 feat(断路器): 修复日志复制斜杠,添加日志查询、clientId 随机生成的防止冲突,开发环境自动弹出调试功能 2024-08-16 15:42:21 +08:00
fhysy b9f2b30c57 feat(断路器): 配置预设属性和功能 2024-08-13 15:26:15 +08:00
fhysy d56f84f631 feat(断路器): 解决功能设备idbug,调整后端插件 2024-08-12 17:38:32 +08:00
fhysy 06edc35679 feat(视频监控): 添加视频监控模块,屏蔽部分打包文件,更新后端exe和插件,取消csp屏蔽 2024-08-09 09:20:04 +08:00
fhysy 5a0304a8d6 feat(断路器): 添加断路器调试固件升级,调整页面布局 2024-08-06 17:13:27 +08:00
fhysy 206de9e618 feat(页面布局): 调整头部菜单的路由控制,删除dist目录 2024-07-22 15:51:51 +08:00
fhysy 57d766fab0 feat(断路器): 调整样式、更换插件socket 2024-07-22 10:37:55 +08:00
fhysy 8567ec8c2e feat(断路器): 调整样式、格式化文件 2024-07-15 17:41:47 +08:00
fhysy 17164687b6 feat(断路器): 调整后端服务路径、页面添加缓存、断路器连接、主题数据添加缓存 2024-07-15 16:52:03 +08:00
fhysy 1152321c30 feat(应用程序): 更新后端服务目录 2024-07-15 14:50:58 +08:00
fhysy 7b98fca398 💥 feat(断路器): 调整侧边菜单样式、默认选中菜单、添加应用程序退出关闭后端服务及插件 2024-07-15 13:57:35 +08:00
fhysy 9bb8ff8942 💥 feat(断路器): 完成断路器调试开发及打包 2024-07-12 16:16:48 +08:00
50 changed files with 5968 additions and 1155 deletions

4
.gitignore vendored
View File

@ -1,5 +1,7 @@
node_modules
dist
out
.DS_Store
*.log*
/dist/
/dist.zip
.idea

View File

@ -2,14 +2,12 @@
<code_scheme name="Project" version="173">
<HTMLCodeStyleSettings>
<option name="HTML_SPACE_INSIDE_EMPTY_TAG" value="true" />
<option name="HTML_QUOTE_STYLE" value="Single" />
<option name="HTML_ENFORCE_QUOTES" value="true" />
</HTMLCodeStyleSettings>
<JSCodeStyleSettings version="0">
<option name="USE_SEMICOLON_AFTER_STATEMENT" value="false" />
<option name="FORCE_SEMICOLON_STYLE" value="true" />
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
<option name="USE_DOUBLE_QUOTES" value="false" />
<option name="FORCE_QUOTE_STYlE" value="true" />
<option name="ENFORCE_TRAILING_COMMA" value="Remove" />
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />

View File

@ -5,7 +5,9 @@
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
<excludeFolder url="file://$MODULE_DIR$/node_modules" />
</content>
<content url="file://$MODULE_DIR$/node_modules" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>

6
.idea/misc.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptSettings">
<option name="languageLevel" value="FLOW" />
</component>
</project>

View File

@ -1,4 +1,18 @@
#singleQuote: true
#semi: false
#printWidth: 100
#trailingComma: none
printWidth: 220
tabWidth: 4
useTabs: true
semi: true
singleQuote: true
semi: false
printWidth: 100
trailingComma: none
quoteProps: "as-needed"
trailingComma: "none"
bracketSpacing: true
jsxBracketSameLine: false
arrowParens: "avoid"
endOfLine: "lf"
jsxSingleQuote: false
vueIndentScriptAndStyle: false
Prettier:HTMLWhitespaceSensitivity: 'ignore'

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
</dict>
</plist>

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

View File

@ -1,44 +1,76 @@
appId: com.electron.app
productName: gateway-ui
# 应用程序的唯一标识符
appId: gy.calibration.pc
# 应用程序的名称
productName: 谷云校表产测
# 定义构建资源和输出文件的目录
directories:
buildResources: build
# 定义要包含或排除在构建输出中的文件
files:
- '!**/.vscode/*'
- '!src/*'
- '!electron.vite.config.{js,ts,mjs,cjs}'
- '!{.eslintignore,.eslintrc.cjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}'
- '!{.env,.env.*,.npmrc,pnpm-lock.yaml}'
- '!**/.vscode/*' # 排除VSCode配置文件
- '!**/.cursor/*' # 排除cursor配置文件
- '!**/.idea/*' # 排除idea配置文件
- '!src/*' # 排除源代码目录
- '!**/*.log' # 排除日志文件
- '!electron.vite.config.{js,ts,mjs,cjs}' # 排除Electron构建配置文件
- '!{.eslintignore,.eslintrc.cjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}' # 排除开发和文档文件
- '!{.env,.env.*,.npmrc,pnpm-lock.yaml,*.zip,app.log}' # 排除环境和包管理配置文件
# 定义需要解压的asar文件
asarUnpack:
- resources/**
- resources/** # 解压资源目录下的所有文件
# 针对Windows平台的配置
win:
executableName: gateway-ui
icon: resources/icon.png # 应用程序图标的路径
# 针对NSIS安装程序的配置
nsis:
artifactName: ${name}-${version}-setup.${ext}
shortcutName: ${productName}
uninstallDisplayName: ${productName}
createDesktopShortcut: always
artifactName: ${productName}-${version}-setup.${ext} # 安装程序的文件名格式
shortcutName: ${productName} # 快捷方式的名称
uninstallDisplayName: ${productName} # 卸载程序显示的名称
createDesktopShortcut: always # 总是在桌面创建快捷方式
allowToChangeInstallationDirectory: true # 允许用户选择安装目录
oneClick: false # 设置为非一键安装
installerIcon: resources/icon.ico # 安装程序的图标
uninstallerIcon: resources/icon.ico # 卸载程序的图标
installerHeader: resources/icon.png # 安装程序头部的图像
installerHeaderIcon: resources/icon.png # 安装程序头部图标的路径
# 针对macOS平台的配置
mac:
entitlementsInherit: build/entitlements.mac.plist
extendInfo:
- NSCameraUsageDescription: Application requests access to the device's camera.
- NSMicrophoneUsageDescription: Application requests access to the device's microphone.
- NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder.
- NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder.
notarize: false
entitlementsInherit: build/entitlements.mac.plist # 继承权限配置文件
extendInfo: # 添加macOS应用的元数据
- NSCameraUsageDescription: Application requests access to the device's camera. # 摄像头使用权限描述
- NSMicrophoneUsageDescription: Application requests access to the device's microphone. # 麦克风使用权限描述
- NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder. # 文档夹使用权限描述
- NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder. # 下载夹使用权限描述
notarize: false # 是否进行苹果的公证
icon: resources/icon.png # 应用程序的图标路径
identity: null # 签名身份
# 针对dmg安装包的配置
dmg:
artifactName: ${name}-${version}.${ext}
artifactName: ${name}-${version}.${ext} # dmg文件的命名格式
# 针对Linux平台的配置
linux:
target:
target: # 目标包类型
- AppImage
- snap
- deb
maintainer: electronjs.org
category: Utility
maintainer: GuyunDevelopment # 维护者信息
category: Utility # 应用程序类别
icon: resources/icon.png # 应用程序图标路径
# 针对AppImage包的配置
appImage:
artifactName: ${name}-${version}.${ext}
artifactName: ${name}-${version}.${ext} # AppImage文件的命名格式
# 是否在npm安装时重建asar包
npmRebuild: false
# 配置自动更新的信息
publish:
provider: generic
url: https://example.com/auto-updates
provider: generic # 更新服务提供者
url: https://example.com/auto-updates # 更新信息的URL
# provider: github # 更新服务提供者
# owner: fanhuayishiy # GitHub用户名
# repo: mygit1 # GitHub仓库名称
# token: ${env:GITHUB_TOKEN}
# releaseType: release
# 配置Electron下载的镜像地址
electronDownload:
mirror: https://npmmirror.com/mirrors/electron/
mirror: https://npmmirror.com/mirrors/electron/ # Electron下载的镜像地址

View File

@ -1,6 +1,7 @@
import { resolve } from 'path'
import { defineConfig, externalizeDepsPlugin } from 'electron-vite'
import vue from '@vitejs/plugin-vue'
import VueDevTools from 'vite-plugin-vue-devtools';
export default defineConfig({
main: {
@ -15,6 +16,9 @@ export default defineConfig({
'@renderer': resolve('src/renderer/src')
}
},
plugins: [vue()]
plugins: [
vue(),
VueDevTools()
]
}
})

View File

@ -1,7 +1,7 @@
{
"name": "gateway-ui",
"name": "gy-calibration",
"version": "1.0.0",
"description": "An Electron application with Vue",
"description": "谷云开发部开发的断路器标定软件",
"main": "./out/main/index.js",
"author": "example.com",
"homepage": "https://electron-vite.org",
@ -21,10 +21,13 @@
"@electron-toolkit/preload": "^3.0.1",
"@electron-toolkit/utils": "^3.0.0",
"axios": "^1.7.2",
"dayjs": "^1.11.13",
"electron-updater": "^6.1.7",
"element-plus": "^2.7.6",
"file-saver": "^2.0.5",
"pinia": "^2.1.7",
"vue-router": "^4.4.0"
"vue-router": "^4.4.0",
"xlsx": "^0.18.5"
},
"devDependencies": {
"@electron-toolkit/eslint-config": "^1.0.2",
@ -36,8 +39,11 @@
"electron-vite": "^2.3.0",
"eslint": "^8.57.0",
"eslint-plugin-vue": "^9.26.0",
"less": "^4.2.0",
"prettier": "^3.3.2",
"sass": "^1.77.6",
"vite": "^5.3.1",
"vite-plugin-vue-devtools": "^7.7.6",
"vue": "^3.4.30"
}
}

View File

@ -0,0 +1,20 @@
module.exports = {
//打包配置
url: 'http://127.0.0.1:8000',
wsUrl: 'ws://127.0.0.1:8000',
swichWsUrl: 'ws://127.0.0.1:8001',
serialPortUrl: 'http://127.0.0.1:8000',
//开发配置
// url: 'http://192.168.1.17:8000',
// wsUrl: 'ws://192.168.1.17:8000',
// swichWsUrl: 'ws://192.168.1.17:8001',
// serialPortUrl: 'http://192.168.1.17:8000',
// 远程连接串口使用
// serialPortUrl: 'http://120.77.172.42:7202',
// serialPortUrl: 'http://192.168.1.17:8888',
}

View File

@ -0,0 +1 @@
[{"name":"属性1","addr":"60000","len":"2","data":"15"},{"name":"属性2","addr":"50000","len":"1","data":"1"}]

BIN
resources/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 45 KiB

View File

@ -0,0 +1,21 @@
server:
serverMain:
address: "8000"
#serverRoot: "resource/public"
logger:
path: "logs"
level: "info"
#台体编号
equipment: HS-9203M-0001
#设备总数
totalNum: 16
#起始端口号
startAddr: 22
#测试源电压波动比例
fluctuateRatioU: 90
#测试源电压波动比例
fluctuateRatioI: 90
#配置密钥
secretKey: "1dd53c82958d1de56df4035d3ed9fd82"

BIN
resources/service/data.db Normal file

Binary file not shown.

BIN
resources/service/hscom.dll Normal file

Binary file not shown.

View File

@ -0,0 +1,29 @@
[Delay]
ErrWaittime=0.5
SourceWaittime=1
StdmeterWaittime=2
Waittime4open=0.2
PurgeCommDelay=0.05
SampleTIME=3
HarmStableTime=3
HarmReviseTime=2
IntervalWaitTime=0.05
BpGrade1=0.05
BpGrade2=0.1
DelayAfterGearChange=0.5
IFCheckGear=0
CheckGearIntervalTime=1
CheckGearMaxWaitTIme=7
ReviseTIme=0
[System]
SetMode5300b=0
ReadMode5300b=1
HarmReviseMode=0
IfHarmRevise=1
HS5300ReadUacSupport=1
ifThreadLog=1
HS5300UURevise=0
[Debug]
Mode=0

View File

@ -0,0 +1,28 @@
server:
address: ":8888"
staticRoot: "./resource/template"
apiPrefix: "/api/v1"
pluginPrefix: "/plugins"
file:
upload_path: "./resource/upload"
dir_mode: "byDate"
logger:
level: debug
path: "./resource/logs/server.log"
max_size: 10
max_age: 30
database:
default:
kind: "mysql"
dsn: "root:mysql_YiniNx@tcp(123.60.30.87:3306)/goside?charset=utf8mb4&parseTime=True&loc=Local"
max_idle_conns: 10
max_open_conns: 100
# kind: "SQLite"
# dsn: "./resource/db/db.db"
# max_idle_conns: 10

View File

@ -0,0 +1,713 @@
[
{
"key": "c_id",
"name": "芯片id",
"addr": 0,
"len": 4,
"dataType": "string",
"rwType": "R",
"default": "0",
"precision": "",
"unit": ""
},
{
"id": 0,
"key": "calibration_conf",
"name": "标定参数",
"addr": 30018,
"len": 5,
"dataType": "struct",
"rwType": "R",
"default": "",
"precision": "",
"unit": "",
"format": [
{
"index": 0,
"size": 16,
"key": "ec",
"name": "脉冲常数",
"unit": "",
"value": "3200"
},
{
"index": 16,
"size": 16,
"key": "u",
"name": "电压",
"unit": "V",
"value": "220"
},
{
"index": 32,
"size": 16,
"key": "i",
"name": "电流",
"unit": "A",
"value": "10"
},
{
"index": 48,
"size": 16,
"key": "pt",
"name": "电压比",
"unit": "",
"value": "1981"
},
{
"index": 64,
"size": 16,
"key": "ct",
"name": "电流比",
"unit": "",
"value": "2000"
},
{
"index": 80,
"size": 16,
"key": "ileak",
"name": "漏电流",
"unit": "mA",
"value": "20"
},
{
"index": 96,
"size": 8,
"key": "ig",
"name": "电流通道放大倍数",
"unit": "",
"value": "0"
},
{
"index": 104,
"size": 8,
"key": "vg",
"name": "电压通道放大倍数",
"unit": "",
"value": "0"
},
{
"index": 112,
"size": 8,
"key": "ilg",
"name": "漏电流通道放大倍数",
"unit": "",
"value": "3"
},
{
"index": 120,
"size": 8,
"key": "reserve",
"name": "保留位",
"unit": "",
"value": "0"
},
{
"index": 128,
"size": 32,
"key": "isr",
"name": "电流采样电阻",
"unit": "10mΩ",
"value": "440"
}
]
},
{
"key": "last_event",
"name": "事件",
"addr": 50000,
"len": 1,
"dataType": "string",
"rwType": "R",
"default": "0",
"precision": "",
"unit": ""
},
{
"key": "last_event_time",
"name": "事件发生时间",
"addr": 50001,
"len": 1,
"dataType": "time",
"rwType": "R",
"default": "0",
"precision": "",
"unit": ""
},
{
"key": "update_time",
"name": "时间戳",
"addr": 50002,
"len": 1,
"dataType": "time",
"rwType": "R",
"default": "0",
"precision": "",
"unit": ""
},
{
"key": "switch",
"name": "开关状态",
"addr": 50003,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "",
"precision": "",
"unit": ""
},
{
"key": "Freq",
"name": "电网频率",
"addr": 50004,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "0.01",
"unit": "Hz"
},
{
"key": "Leak_I",
"name": "漏电流/N相电流",
"addr": 50005,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "1",
"unit": "mA"
},
{
"key": "Tn_1",
"name": "N相进线温度",
"addr": 50006,
"len": 1,
"dataType": "int32",
"rwType": "R",
"default": "0",
"precision": "0.1",
"unit": "℃"
},
{
"key": "Tn_2",
"name": "N相出线温度",
"addr": 50007,
"len": 1,
"dataType": "int32",
"rwType": "R",
"default": "0",
"precision": "0.1",
"unit": "℃"
},
{
"key": "Ua",
"name": "A/L相电压",
"addr": 50008,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "0.01",
"unit": "V"
},
{
"key": "Ia",
"name": "A/L相电流",
"addr": 50009,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "0.001",
"unit": "A",
"critical": "0.2"
},
{
"key": "Pa",
"name": "A/L相有功功率",
"addr": 50010,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "0.001",
"unit": "W"
},
{
"key": "Qa",
"name": "A/L相无功功率",
"addr": 50011,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "0.001",
"unit": "var"
},
{
"key": "Sa",
"name": "A/L相视在功率",
"addr": 50012,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "0.001",
"unit": "va"
},
{
"key": "Pfa",
"name": "A/L相功率因数",
"addr": 50013,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "0.001",
"unit": ""
},
{
"key": "EPa_H",
"name": "A/L相有功电能高32位",
"addr": 50014,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "1",
"unit": "Wh"
},
{
"key": "EPa_L",
"name": "A/L相有功电能低32位",
"addr": 50015,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "1",
"unit": "Wh"
},
{
"key": "EQa_H",
"name": "A/L相无功电能高32位",
"addr": 50016,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "1",
"unit": "varh"
},
{
"key": "EQa_L",
"name": "A/L相无功电能低32位",
"addr": 50017,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "1",
"unit": "varh"
},
{
"key": "Ta_1",
"name": "L/A相进线温度",
"addr": 50018,
"len": 1,
"dataType": "int32",
"rwType": "R",
"default": "0",
"precision": "0.1",
"unit": "℃"
},
{
"key": "Ta_2",
"name": "L/A相出线温度",
"addr": 50019,
"len": 1,
"dataType": "int32",
"rwType": "R",
"default": "0",
"precision": "0.1",
"unit": "℃"
},
{
"key": "Ub",
"name": "B相电压",
"addr": 50020,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "0.01",
"unit": "V"
},
{
"key": "Ib",
"name": "B相电流",
"addr": 50021,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "0.001",
"unit": "A",
"critical": "0.2"
},
{
"key": "Pb",
"name": "B相有功功率 ",
"addr": 50022,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "0.001",
"unit": "W"
},
{
"key": "Qb",
"name": "B相无功功率",
"addr": 50023,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "0.001",
"unit": "var"
},
{
"key": "Sb",
"name": "B相视在功率",
"addr": 50024,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "0.001",
"unit": "va"
},
{
"key": "Pfb",
"name": "B相功率因数",
"addr": 50025,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "0.001",
"unit": ""
},
{
"key": "EPb_H",
"name": "B相有功电能高32位",
"addr": 50026,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "1",
"unit": "Wh"
},
{
"key": "EPb_L",
"name": "B相有功电能低32位",
"addr": 50027,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "1",
"unit": "Wh"
},
{
"key": "EQb_H",
"name": "B相无功电能高32位",
"addr": 50028,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "1",
"unit": "varh"
},
{
"key": "EQb_L",
"name": "B相无功电能低32位",
"addr": 50029,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "1",
"unit": "varh"
},
{
"key": "Tb_1",
"name": "B相进线温度",
"addr": 50030,
"len": 1,
"dataType": "int32",
"rwType": "R",
"default": "0",
"precision": "0.1",
"unit": "℃"
},
{
"key": "Tb_2",
"name": "B相出线温度",
"addr": 50031,
"len": 1,
"dataType": "int32",
"rwType": "R",
"default": "0",
"precision": "0.1",
"unit": "℃"
},
{
"key": "Uc",
"name": "C相电压",
"addr": 50032,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "0.01",
"unit": "V"
},
{
"key": "Ic",
"name": "C相电流",
"addr": 50033,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "0.001",
"unit": "A",
"critical": "0.2"
},
{
"key": "Pc",
"name": "C相有功功率 ",
"addr": 50034,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "0.001",
"unit": "W"
},
{
"key": "Qc",
"name": "C相无功功率",
"addr": 50035,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "0.001",
"unit": "var"
},
{
"key": "Sc",
"name": "C相视在功率",
"addr": 50036,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "0.001",
"unit": "va"
},
{
"key": "Pfc",
"name": "C相功率因数",
"addr": 50037,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "0.001",
"unit": ""
},
{
"key": "EPc_H",
"name": "C相有功电能高32位",
"addr": 50038,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "1",
"unit": "Wh"
},
{
"key": "EPc_L",
"name": "C相有功电能低32位",
"addr": 50039,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "1",
"unit": "Wh"
},
{
"key": "EQc_H",
"name": "C相无功电能高32位",
"addr": 50040,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "1",
"unit": "varh"
},
{
"key": "EQc_L",
"name": "C相无功电能低32位",
"addr": 50041,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "1",
"unit": "varh"
},
{
"key": "Tc_1",
"name": "C相进线温度",
"addr": 50042,
"len": 1,
"dataType": "int32",
"rwType": "R",
"default": "0",
"precision": "0.1",
"unit": "℃"
},
{
"key": "Tc_2",
"name": "C相出线温度",
"addr": 50043,
"len": 1,
"dataType": "int32",
"rwType": "R",
"default": "0",
"precision": "0.1",
"unit": "℃"
},
{
"key": "Usum",
"name": "合相电压",
"addr": 50044,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "0.01",
"unit": "V"
},
{
"key": "Isum",
"name": "合相电流/剩余电流",
"addr": 50045,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "0.001",
"unit": "A",
"critical": "0.2"
},
{
"key": "Psum",
"name": "合相有功功率",
"addr": 50046,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "0.001",
"unit": "W"
},
{
"key": "Qsum",
"name": "合相无功功率",
"addr": 50047,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "0.001",
"unit": "var"
},
{
"key": "Ssum",
"name": "RMS 合相视在功率",
"addr": 50048,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "0.001",
"unit": "va"
},
{
"key": "Pfsum",
"name": "RMS 合相功率因数",
"addr": 50049,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "0.001",
"unit": ""
},
{
"key": "EPsum_H;",
"name": "合相有功电能高32位",
"addr": 50050,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "1",
"unit": "Wh"
},
{
"key": "EPsum_L;",
"name": "合相有功电能低32位",
"addr": 50051,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "1",
"unit": "Wh"
},
{
"key": "EQsum_H,;",
"name": "合相无功电能高32位",
"addr": 50052,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "1",
"unit": "varh"
},
{
"key": "EQsum_L;",
"name": "合相无功电能低32位",
"addr": 50053,
"len": 1,
"dataType": "uint32",
"rwType": "R",
"default": "0",
"precision": "1",
"unit": "varh"
}
]

View File

@ -1,75 +1,229 @@
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'
import { app, shell, BrowserWindow, ipcMain, globalShortcut, dialog } from 'electron';
import { join } from 'path';
import { electronApp, optimizer, is } from '@electron-toolkit/utils';
import icon from '../../resources/icon.png?asset';
function createWindow() {
// Create the browser window.
const 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.webContents.openDevTools()
mainWindow.on('ready-to-show', () => {
mainWindow.show()
})
//关闭exe命令
function killProcessByName(processName) {
const command = `taskkill /IM ${processName} /F`;
const { exec } = require('child_process');
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'))
}
exec(command, (error, stdout, stderr) => {
if (error) {
console.error(`执行的错误: ${error}`);
return;
}
console.log(`stdout: ${stdout}`);
console.error(`stderr: ${stderr}`);
});
}
// 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.whenReady().then(() => {
// Set app user model id for windows
electronApp.setAppUserModelId('com.electron')
app.commandLine.appendSwitch('disable-web-security');
function createWindow() {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 1280,
height: 1024,
show: false,
autoHideMenuBar: true,
icon,
webPreferences: {
preload: join(__dirname, '../preload/index.js'),
sandbox: false,
nodeIntegration: true,
// 禁用同源策略,允许跨域请求
webSecurity: false,
contextIsolation: false,
// csp: "default-src 'self'; connect-src 'self' *",
// 禁止build环境使用DevTool
// devTools: is.dev ? true : false
devTools: true
}
});
//开发模式 开启调试
if (is.dev) {
mainWindow.webContents.openDevTools();
}
// Default open or close DevTools by F12 in development
// and ignore CommandOrControl + R in production.
// see https://github.com/alex8088/electron-toolkit/tree/master/packages/utils
app.on('browser-window-created', (_, window) => {
optimizer.watchWindowShortcuts(window)
})
mainWindow.on('ready-to-show', () => {
mainWindow.show();
});
// IPC test
ipcMain.on('ping', () => console.log('pong'))
mainWindow.webContents.setWindowOpenHandler(details => {
shell.openExternal(details.url);
return { action: 'deny' };
});
//基于electronic-vite-cli的渲染器HMR。
//加载用于开发的远程URL或用于生产的本地html文件。
if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL']);
} else {
mainWindow.loadFile(join(__dirname, '../renderer/index.html'));
}
createWindow()
// 设置DevTools快捷键
// 设置DevTools快捷键
globalShortcut.register('CommandOrControl+Shift+i', function () {
mainWindow.webContents.openDevTools();
});
return mainWindow;
}
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.
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
// 程序单例模式
let myWindow = null;
const gotTheLock = app.requestSingleInstanceLock();
if (!gotTheLock) {
// 如果已经有同样的该程序正在运行,则不启动
app.quit();
} else {
// 如果检测到有同样的该程序正在试图启动...
app.on('second-instance', () => {
if (myWindow) {
// 弹出系统提示对话框
dialog.showMessageBox({
message: '此程序已经正在运行'
});
// 如果该程序窗口处于最小化状态,则恢复窗口
if (myWindow.isMinimized()) myWindow.restore();
// 将该程序窗口置为当前聚焦态
myWindow.focus();
}
});
// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
//当Electron完成时将调用此方法
//初始化并准备创建浏览器窗口。
//某些API只能在此事件发生后使用。
const { spawn } = require('child_process');
let child = null;
let exePluginsExeList = [];
app.whenReady().then(() => {
const fs = require('fs');
const path = require('path');
// In this file you can include the rest of your app"s specific main process
// code. You can also put them in separate files and require them here.
const logStream = fs.createWriteStream('app.log', { flags: 'a' }); // 日志文件
let exePath = path.resolve('./resources/app.asar.unpacked/resources/service');
let exePluginsPath = path.resolve('./resources/app.asar.unpacked/resources/service/plugins');
//单独配置测试环境
if (process.env.NODE_ENV === 'development') {
exePath = path.resolve('./resources/service');
exePluginsPath = path.resolve('./resources/service/plugins');
}
//查询所有插件目录下的exe文件
fs.readdir(exePluginsPath, (err, files) => {
if (err) {
return console.log('Unable to scan directory: ' + err);
}
// 筛选出以.exe结尾的文件
exePluginsExeList = files.filter(file => path.extname(file).toLowerCase() === '.exe');
});
const userDataPath = app.getPath('userData');
child = spawn('./main.exe', ['--args', userDataPath], { cwd: exePath, stdio: ['ignore', 'pipe', 'pipe'] });
//监听进程的输出
child.stdout.on('data', data => {
console.log('stdout:', data.toString());
logStream.write(data);
});
child.stderr.on('data', data => {
console.error('stderr:', data.toString());
logStream.write(data);
});
child.on('close', code => {
console.log(`子进程已退出,退出码 ${code}`);
logStream.end();
});
child.on('exit', (code, signal) => {
console.log(`子进程已退出,退出码 ${code},信号: ${signal}`);
logStream.write(`子进程已退出,退出码 ${code},信号: ${signal}`);
logStream.end();
});
// Set app user model id for windows
electronApp.setAppUserModelId('com.electron');
//开发中默认按F12打开或关闭DevTools
//在生产中忽略CommandOrControl+R。
//看https://github.com/alex8088/electron-toolkit/tree/master/packages/utils
app.on('browser-window-created', (_, window) => {
optimizer.watchWindowShortcuts(window);
});
// IPC test
ipcMain.on('ping', () => console.log('pong'));
myWindow = createWindow();
app.on('activate', function () {
//在macOS上当出现以下情况时通常会在应用程序中重新创建窗口
//单击dock图标后没有其他打开的窗口。
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
});
// 处理来自渲染进程的请求
// ipcMain.handle('readFile', async (event, path) => {
// return new Promise((resolve, reject) => {
// fs.readFile(join(__dirname, path), 'utf8', (err, data) => {
// if (err) {
// reject(err);
// } else {
// resolve(data);
// }
// });
// });
// });
//
// ipcMain.handle('writeFile', async (event, path, content) => {
// return new Promise((resolve, reject) => {
// fs.writeFile(join(__dirname, path), content, 'utf8', (err) => {
// if (err) {
// reject(err);
// } else {
// resolve();
// }
// });
// });
// });
//
// // 处理来自渲染进程的请求
// ipcMain.handle('readDirectory', async (event, directoryPath) => {
// return new Promise((resolve, reject) => {
// fs.readdir(join(__dirname, directoryPath), (err, files) => {
// if (err) {
// reject(err);
// } else {
// resolve(files);
// }
// });
// });
// });
//关闭所有窗口后退出macOS除外。在那里这很常见
//让应用程序及其菜单栏保持活动状态,直到用户退出
//显式使用Cmd+Q。
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
// 循环关闭插件 EXE 列表
exePluginsExeList.forEach(exe => {
killProcessByName(exe);
});
// child.kill('SIGTERM'); // 或者使用 'SIGKILL' 来强制关闭
// killProcessByName('gateway.exe');
// 循环关闭后端服务
killProcessByName('main.exe');
app.quit();
}
});
}
//在此文件中,您可以包含应用程序的其他特定主进程
//代码。您也可以将它们放在单独的文件中,并在此处要求它们。
//获取应用程序版本
ipcMain.handle('get-app-version', () => {
return app.getVersion();
});

View File

@ -1,20 +1,103 @@
import { contextBridge } from 'electron'
import { contextBridge, ipcRenderer } from 'electron'
import { electronAPI } from '@electron-toolkit/preload'
const fs = require('fs');
const path = require('path');
const { shell } = require('electron');
// Custom APIs for renderer
const api = {}
// 自定义的主进程方法API
// const api = {
// readFile: async (path) => {
// const result = await ipcRenderer.invoke('readFile', path);
// return result;
// },
// writeFile: async (path, content) => {
// await ipcRenderer.invoke('writeFile', path, content);
// },
// readDirectory: async (directoryPath) => {
// const result = await ipcRenderer.invoke('readDirectory', directoryPath);
// return result;
// }
// }
// // 暴露获取版本号的方法
// ipcMain.handle('get-app-version', () => {
// return app.getVersion(); // 返回当前应用版本(来自 package.json
// });
// 获取config.js的绝对路径
function getConfigPath() {
// __dirname 是 win-unpacked/resources/app
let configPath = path.resolve('./resources/app.asar.unpacked/resources/config/config.js');
//单独配置测试环境
if (process.env.NODE_ENV === 'development') {
configPath = path.resolve('./resources/config/config.js');
}
return configPath;
}
function getExportPath() {
// __dirname 是 win-unpacked/resources/app
let configPath = path.resolve('./resources/app.asar.unpacked/resources/service');
//单独配置测试环境
if (process.env.NODE_ENV === 'development') {
configPath = path.resolve('./resources/service');
}
return configPath;
}
// Use `contextBridge` APIs to expose Electron APIs to
// renderer only if context isolation is enabled, otherwise
// just add to the DOM global.
// 使用contextBridge将Electron API和自定义的主进程方法API暴露给渲染进程页面。
if (process.contextIsolated) {
try {
contextBridge.exposeInMainWorld('electron', electronAPI)
contextBridge.exposeInMainWorld('api', api)
contextBridge.exposeInMainWorld('electron', {
...electronAPI,
getAppVersion: async () => {
return await ipcRenderer.invoke('get-app-version');
},
readConfig: () => {
const configPath = getConfigPath();
if (fs.existsSync(configPath)) {
// 用require动态加载确保每次都是最新内容
delete require.cache[require.resolve(configPath)];
return require(configPath);
}
return {};
},
shell: {
openPath: shell.openPath
},
exePath: getExportPath()
})
// contextBridge.exposeInMainWorld('api', api)
} catch (error) {
console.error(error)
}
} else {
window.electron = electronAPI
window.api = api
window.electron = {
...electronAPI,
getAppVersion: async () => {
return await ipcRenderer.invoke('get-app-version');
},
readConfig: () => {
const configPath = getConfigPath();
if (fs.existsSync(configPath)) {
// 用require动态加载确保每次都是最新内容
delete require.cache[require.resolve(configPath)];
return require(configPath);
}
return {};
},
shell: {
openPath: shell.openPath
},
exePath: getExportPath()
}
// window.api = api
}

View File

@ -2,12 +2,13 @@
<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"
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:"
/>
<link rel="stylesheet" href="/src/assets/iconfont/iconfont.css">
<!-- <meta-->
<!-- http-equiv="Content-Security-Policy"-->
<!-- content="default-src 'self'; connect-src 'self' *; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:"-->
<!-- />-->
</head>
<body>

View File

@ -1,11 +1,52 @@
<script setup>
import { RouterView } from "vue-router"
import { RouterView } from 'vue-router'
</script>
<template>
<RouterView></RouterView>
</template>
<script setup lang="ts">
<style lang="scss">
:root {
--el-input-height: 36px;
--el-color-primary: #0066cc;
--el-fill-color-blank: #e6e6e6;
--el-disabled-bg-color: #f7f7f7;
}
::-webkit-scrollbar {
width: 5px;
}
</script>
::-webkit-scrollbar-thumb {
border-radius: 5px;
box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
background: #ddd;
}
::-webkit-scrollbar-track {
width: 5px;
}
/*全局覆盖样式*/
.el-collapse-item {
color: #333333;
.el-collapse-item__header {
font-family: Source Han Sans CN;
background: #e6e6e6;
padding: 0 30px;
color: #333333;
font-size: 16px;
height: 42px;
line-height: 42px;
font-weight: 500;
&.is-active {
color: #0066cc;
}
}
.el-collapse-item__wrap {
background-color: #f2f2f2 !important;
}
.el-input__wrapper {
background: #e6e6e6;
}
}
</style>

View File

@ -0,0 +1,183 @@
@font-face {
font-family: "iconfont"; /* Project id 4622943 */
src: url('iconfont.woff2?t=1753694081375') format('woff2'),
url('iconfont.woff?t=1753694081375') format('woff'),
url('iconfont.ttf?t=1753694081375') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-zhakai:before {
content: "\e797";
}
.icon-zhahe:before {
content: "\e798";
}
.icon-kuaijiejian:before {
content: "\e603";
}
.icon-sousuo:before {
content: "\e60e";
}
.icon-xwtubiaoku-13:before {
content: "\e61a";
}
.icon-xwtubiaoku-15:before {
content: "\e61d";
}
.icon-rizhi:before {
content: "\e61c";
}
.icon-bug:before {
content: "\e725";
}
.icon-caozuorizhi:before {
content: "\e610";
}
.icon-rizhishenji:before {
content: "\e666";
}
.icon-chenggong:before {
content: "\e615";
}
.icon-rizhi1:before {
content: "\e613";
}
.icon-chenggong1:before {
content: "\e616";
}
.icon-bug-fill:before {
content: "\e773";
}
.icon-bug-line:before {
content: "\e774";
}
.icon-kongtiaoguizhuduanluqiAA:before {
content: "\e68e";
}
.icon--_saomaqiang:before {
content: "\e640";
}
.icon-qianzhaoyiqibiaoding:before {
content: "\e633";
}
.icon-zuobiaobiaoding:before {
content: "\e602";
}
.icon-com001:before {
content: "\e62c";
}
.icon-chuankou:before {
content: "\e6be";
}
.icon-chuankou1:before {
content: "\e60a";
}
.icon-chuankoushezhi:before {
content: "\e600";
}
.icon-chuankou2:before {
content: "\e6fc";
}
.icon-shousuoshangjiantou:before {
content: "\e9b6";
}
.icon-up-arrow:before {
content: "\e9c1";
}
.icon-unlock:before {
content: "\e882";
}
.icon-gexinghuabobao:before {
content: "\e66d";
}
.icon-icon_suoding:before {
content: "\e76c";
}
.icon-icon_shanchu:before {
content: "\e76d";
}
.icon-icon_shanghang:before {
content: "\e76e";
}
.icon-icon_xiahang:before {
content: "\e76f";
}
.icon-icon_shezhi:before {
content: "\e770";
}
.icon-icon_xitong:before {
content: "\e771";
}
.icon-icon_jiankong:before {
content: "\e772";
}
.icon-icon_duanluqi2:before {
content: "\e9c2";
}
.icon-icon_caid:before {
content: "\e75f";
}
.icon-icon_chajian:before {
content: "\e767";
}
.icon-icon_xiaoxi:before {
content: "\e768";
}
.icon-icon_gengxin:before {
content: "\e769";
}
.icon-icon_fuzhi:before {
content: "\e76a";
}
.icon-icon_duanluqi:before {
content: "\e76b";
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 45 KiB

View File

@ -31,7 +31,8 @@ code {
align-items: center;
justify-content: center;
flex-direction: column;
margin-bottom: 80px;
width: 100%;
height: 100%;
}
.logo {

View File

@ -13,13 +13,13 @@ const settings = defineProps({
<el-aside :width="settings.width">
<el-scrollbar>
<el-menu
:default-openeds="['1', '3']"
default-active="/switch"
:collapse="settings.collapse"
router="true"
:router="true"
>
<el-menu-item index="/versions"><el-icon> <House /> </el-icon></el-menu-item>
<el-menu-item index="/about"><el-icon> <Menu /> </el-icon></el-menu-item>
<el-menu-item index="/test"><el-icon> <Menu /> </el-icon></el-menu-item>
<el-menu-item index="/switch"><el-icon> <Connection /> </el-icon></el-menu-item>
<!-- <el-menu-item index="/about"><el-icon> <Menu /> </el-icon></el-menu-item>-->
<!-- <el-menu-item index="/test"><el-icon> <Menu /> </el-icon></el-menu-item>-->
</el-menu>
</el-scrollbar>
</el-aside>
@ -29,7 +29,23 @@ const settings = defineProps({
.el-aside {
height: 100vh;
overflow: hidden;
box-shadow: var(--el-box-shadow-lighter);
border-right: 1px solid #e6e6e6;
background-color: #f6f6f6;
padding-top: 10px;
}
.el-menu{
background: #f6f6f6;
padding: 0 10px;
}
.el-menu-item{
border-radius: 10px;
/*padding-left: 5px !important;*/
}
.el-menu-item.is-active{
background: #c8cde4;
border-radius: 10px;
/*margin: 0 10px;*/
color: #0066cc;
}
.el-scrollbar {

View File

@ -5,9 +5,5 @@ const versions = reactive({ ...window.electron.process.versions })
</script>
<template>
<ul class="versions">
<li class="electron-version">Electron v{{ versions.electron }}</li>
<li class="chrome-version">Chromium v{{ versions.chrome }}</li>
<li class="node-version">Node v{{ versions.node }}</li>
</ul>
view
</template>

View File

@ -0,0 +1,33 @@
<template>
<el-container direction="vertical" style="height: 100%; width: 100%; ">
<el-main>
<router-view v-slot="{ Component }">
<keep-alive>
<component :is="Component" />
</keep-alive>
</router-view>
</el-main>
</el-container>
</template>
<script setup>
//
</script>
<style scoped>
body {
background-color: #eee;
max-width: 100vw;
}
.el-container {
/*padding: 10px 0;*/
}
.el-main {
width: 100%;
padding: 0;
/*height: 100vh;*/
overflow-x: hidden;
background: #fff;
/*padding-right: 10px;*/
}
</style>

View File

@ -2,21 +2,26 @@ import '@renderer/assets/main.css'
import { createPinia } from 'pinia'
import { createApp } from 'vue'
import dayjs from 'dayjs'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import ElementPlus from 'element-plus'
import zhCn from 'element-plus/es/locale/lang/zh-cn'
import 'element-plus/dist/index.css'
import App from '@renderer/App.vue'
import router from '@renderer/router'
const app = createApp(App)
app.config.globalProperties.$dayjs = dayjs
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
app.use(createPinia())
app.use(ElementPlus)
app.use(ElementPlus, {
locale: zhCn,
})
app.use(router)
app.mount('#app')

View File

@ -1,46 +1,32 @@
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '@renderer/views/HomeView.vue'
import { createRouter, createWebHistory } from 'vue-router';
import Layout from '@renderer/layout/index.vue';
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/',
name: 'home',
component: HomeView,
redirect: {name: 'versions'},
children:[
{
path: 'versions',
name: 'versions',
component: () => import("@renderer/components/Versions.vue"),
meta: {
menu: 'versions',
keepAlive: true,
}
},
{
path: 'about',
name: 'about',
component: () => import("@renderer/views/AboutView.vue"),
meta: {
menu: 'about',
keepAlive: true,
}
},
{
path: 'test',
name: 'test',
component: () => import("@renderer/views/test.vue"),
meta: {
menu: 'test',
keepAlive: true,
}
},
]
},
{ path: '/:pathMatch(.*)', redirect: '/' },
]
})
history: createWebHistory(),
routes: [
{
path: '/',
component: Layout,
meta: { title: '整体页面布局' },
redirect: '/calibration',
children: [
{
path: 'calibration',
name: 'calibration',
component: () => import('@renderer/views/calibration/index.vue'),
meta: {
menu: 'calibration',
keepAlive: true
}
}
]
},
{
path: '/', // 这个是根路由,现在我们让它重定向到 /system
redirect: '/calibration'
},
{ path: '/:pathMatch(.*)', redirect: '/' }
]
});
export default router
export default router;

View File

@ -0,0 +1,97 @@
import { defineStore } from 'pinia'
// import config from '@renderer/util/config.js'
const config = window.electron.readConfig();
// 定义一个名为logWebSocketStore的store用于管理WebSocket连接的状态和操作
export const logWebSocketStore = defineStore('websocket', {
state: () => ({
websocket: null, // WebSocket实例
connectURL: config.wsUrl + '/ws/log', // WebSocket连接的URL
socket_open: false, // 标记WebSocket是否连接
hearbeat_timer: null, // 心跳检测的定时器
hearbeat_interval: 2 * 1000, // 心跳检测的间隔时间
is_reonnect: true, // 是否尝试重新连接
reconnect_count: 3, // 最大重连次数
reconnect_current: 1, // 当前重连次数
reconnect_timer: null, // 重连定时器
reconnect_interval: 5 * 1000, // 重连间隔时间
}),
actions: {
// 初始化WebSocket连接
init(overrideReceiveMessage) {
let receiveMessage = overrideReceiveMessage || (() => {})
// 检查浏览器是否支持WebSocket
if (!('WebSocket' in window)) {
this.$router.push({ name: 'ErrorPage', params: { error: '浏览器不支持WebSocket' } })
return null
}
// 创建WebSocket实例并设置事件处理函数
this.websocket = new WebSocket(this.connectURL)
this.websocket.onmessage = (e) => {
receiveMessage(e)
}
this.websocket.onclose = () => {
console.log('socket连接关闭----------------------')
this.socket_open = false
// 尝试重新连接
if (this.is_reonnect) {
this.reconnect_timer = setTimeout(() => {
if (this.reconnect_current > this.reconnect_count) {
clearTimeout(this.reconnect_timer)
this.is_reonnect = false
return
}
console.log('socket重连次数' + this.reconnect_current)
this.reconnect_current++
this.reconnect()
}, this.reconnect_interval)
}
}
this.websocket.onopen = () => {
this.socket_open = true
this.is_reonnect = true
// this.heartbeat()
}
this.websocket.onerror = () => {}
},
// 发送心跳包
heartbeat() {
this.hearbeat_timer && clearInterval(this.hearbeat_timer)
this.hearbeat_timer = setInterval(() => {
let data = {}
this.send(data)
}, this.hearbeat_interval)
},
// 发送数据
send(data, callback = null) {
// 如果WebSocket连接已建立则发送数据
if (this.websocket.readyState === this.websocket.OPEN) {
this.websocket.send(JSON.stringify(data))
callback && callback()
} else {
// 如果WebSocket连接断开则跳转到错误页面
clearInterval(this.hearbeat_timer)
this.$router.push({ name: 'ErrorPage', params: { error: 'socket链接已断开' } })
}
},
// 关闭WebSocket连接
close() {
this.is_reonnect = false
this.websocket.close()
},
// 重新连接WebSocket
reconnect() {
// 如果已存在WebSocket实例且不尝试重新连接则关闭连接
if (this.websocket && !this.is_reonnect) {
this.close()
}
// 初始化WebSocket连接
this.init()
},
},
})

View File

@ -0,0 +1,18 @@
import { defineStore } from 'pinia';
export const useSerialPortStore = defineStore('seralPort', {
state: () => ({
serialport: {
port: '',
baudrate: 115200,
databits: 8,
parity: 0,
stopbits: 0
}
}),
actions: {
setSerialport(data) {
this.serialport = data;
}
}
});

View File

@ -0,0 +1,42 @@
// // // 手动配置的地址
// window.config = {
// url: 'http://192.168.1.17:8000',
// wsUrl: 'ws://192.168.1.17:8000',
// ws1Url: 'ws://192.168.1.17:8001',
// }
// 手动配置的地址
// window.config = {
// url: 'http://127.0.0.1:8000',
// wsUrl: 'ws://127.0.0.1:8000',
// }
// export default {
// url: 'http://127.0.0.1:8000',
// wsUrl: 'ws://127.0.0.1:8000'
// }
export default {
// url: 'http://127.0.0.1:8000',
// wsUrl: 'ws://127.0.0.1:8000',
// swichWsUrl: 'ws://127.0.0.1:8001',
// serialPortUrl: 'http://127.0.0.1:8000',
url: 'http://192.168.1.17:8000',
wsUrl: 'ws://192.168.1.17:8000',
swichWsUrl: 'ws://192.168.1.17:8001',
serialPortUrl: 'http://192.168.1.17:8000',
// 远程连接串口使用
// serialPortUrl: 'http://120.77.172.42:7202',
// serialPortUrl: 'http://192.168.1.17:8888',
}
// 手动配置的地址
// export default {
// url: 'http://192.168.1.17:8000',
// wsUrl: 'ws://192.168.1.17:8000',
// swichWsUrl: 'ws://192.168.1.17:8001',
// serialPortUrl: 'http://192.168.1.17:8000',
// }

View File

@ -0,0 +1,6 @@
export function guidGenerator() {
var S4 = function() {
return ((1 + Math.random())*0X10000|0).toString(16).substring(1);
};
return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
}

View File

@ -0,0 +1,107 @@
import { ElMessage as message } from 'element-plus'
// import storage from 'store'
// import config from '@renderer/util/config.js'
const config = window.electron.readConfig();
let receiveMessage = null
import { reactive } from 'vue'
const socket = reactive({
websocket: null,
connectURL: config.swichWsUrl + '/ws/log',
// 开启标识
socket_open: false,
// 心跳timer
hearbeat_timer: null,
// 心跳发送频率
hearbeat_interval: 2 * 1000,
// 是否自动重连
is_reonnect: true,
// 重连次数
reconnect_count: 3,
// 已发起重连次数
reconnect_current: 1,
// 重连timer
reconnect_timer: null,
// 重连频率
reconnect_interval: 5 * 1000,
init: (overrideReceiveMessage) => {
if (overrideReceiveMessage) {
receiveMessage = overrideReceiveMessage
}
if (!('WebSocket' in window)) {
message.warning('浏览器不支持WebSocket')
return null
}
socket.websocket = new WebSocket(socket.connectURL)
socket.websocket.onmessage = (e) => {
if (receiveMessage) {
receiveMessage(e)
}
}
socket.websocket.onclose = () => {
console.log('socket连接关闭----------------------')
socket.socket_open = false
// 需要重新连接
if (socket.is_reonnect) {
socket.reconnect_timer = setTimeout(() => {
// 超过重连次数
if (socket.reconnect_current > socket.reconnect_count) {
clearTimeout(socket.reconnect_timer)
socket.is_reonnect = false
return
}
console.log('socket重连次数' + socket.reconnect_current)
// 记录重连次数
socket.reconnect_current++
socket.reconnect()
}, socket.reconnect_interval)
}
}
// 连接成功
socket.websocket.onopen = function () {
socket.socket_open = true
socket.is_reonnect = true
// 开启心跳
// socket.heartbeat()
}
// 连接发生错误
socket.websocket.onerror = function () {}
},
heartbeat: () => {
socket.hearbeat_timer && clearInterval(socket.hearbeat_timer)
socket.hearbeat_timer = setInterval(() => {
let data = {
// token: storage.get('token')
}
socket.send(data)
}, socket.hearbeat_interval)
},
send: (data, callback = null) => {
// 开启状态直接发送
if (socket.websocket.readyState === socket.websocket.OPEN) {
socket.websocket.send(JSON.stringify(data))
callback && callback()
} else {
clearInterval(socket.hearbeat_timer)
message({
type: 'warning',
message: 'socket链接已断开',
duration: 1000
})
}
},
close: () => {
socket.is_reonnect = false
socket.websocket.close()
},
/**
* 重新连接
*/
reconnect: () => {
if (socket.websocket && !socket.is_reonnect) {
socket.close()
}
socket.init(receiveMessage)
}
})
export default socket

View File

@ -1,15 +0,0 @@
<template>
<div class="about">
<h1>This is an about page</h1>
</div>
</template>
<style>
@media (min-width: 1024px) {
.about {
min-height: 100vh;
display: flex;
align-items: center;
}
}
</style>

View File

@ -1,59 +0,0 @@
<script setup>
import { ref } from 'vue'
//
import Header from '@renderer/components/Header.vue'
import Aside from '@renderer/components/Aside.vue'
const asideSettings = ref({
isCollapse:true,
width:'200'
})
// emit
const changeAside = ()=>{
asideSettings.value.isCollapse = !asideSettings.value.isCollapse
if(asideSettings.value.isCollapse){
asideSettings.value.width = "64"
}else{
asideSettings.value.width = "200"
}
}
</script>
<template>
<el-container direction="vertical" style="min-height: 100vh;min-width: 100vw;overflow: hidden;">
<Header></Header>
<el-container >
<Aside :width="200"></Aside>
<el-main>
<RouterView/>
</el-main>
</el-container>
</el-container>
</template>
<style scoped>
body{
background-color: #eee;
max-width: 100vw;
overflow: hidden;
}
.el-main {
width: 100%;
padding: 0;
height: 100vh;
overflow-x: hidden;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,296 @@
/*
* @Descripttion:
* @version:
* @Author: lfzxs@qq.com
* @Date: 2024-10-16 13:52:11
* @LastEditors: lfzxs@qq.com
* @LastEditTime: 2024-10-18 16:33:31
*/
export function buildHead(d_length,d_remote_id,d_local_id,d_cmd,d_dev_type,d_data_type,dataStart,dataLength,dataValue,activeData) {
// 初始化data为一个32位2进制数
let data = "0000" + d_data_type + d_dev_type + d_cmd + toBinaryString(d_local_id,9) + toBinaryString(d_remote_id,9) + d_length;
console.log("获取头部",data);
let hex_data = binaryToHex(data);
let dataBuffer = '';
let buffer = hexToBuffer(hex_data);
//根据d_cmd的值拼接命令格式
switch (d_cmd) {
case "0000"://特殊指令
break;
case "0011"://地址读
buffer = concatenateBuffers(htonl(buffer),htonl(toFixedSizeBuffer(parseInt(dataStart),4)),htonl(toFixedSizeBuffer(parseInt(dataLength),4)));
break;
case "0100"://地址写
if(activeData.dataType === 'hex'){
dataValue = rearrangeHexStr(dataValue);
dataBuffer = hexToBuffer(dataValue);
}else if(activeData.dataType === 'hexString'){
dataBuffer = hexToBuffer(dataValue);
}else{
dataBuffer = stringToHexBuffer(dataValue,dataLength*4*2);
}
console.log("dataBuffer",dataBuffer)
buffer = concatenateBuffers(htonl(buffer),htonl(toFixedSizeBuffer(parseInt(dataStart),4)),htonl(toFixedSizeBuffer(parseInt(dataLength),4)),dataBuffer)
break;
}
console.log("dataValue-buffer",dataValue,buffer)
let result = bufferToHex(buffer);
return result;
}
export function allBuildHead(d_length,d_remote_id,d_local_id,d_cmd,d_dev_type,d_data_type,dataStart,dataLength,dataValue,allList) {
// 初始化data为一个32位2进制数
let data = "0000" + d_data_type + d_dev_type + d_cmd + toBinaryString(d_local_id,9) + toBinaryString(d_remote_id,9) + d_length;
console.log("获取头部",data);
let hex_data = binaryToHex(data);
let buffer = hexToBuffer(hex_data);
let allBufferList = [];
//根据d_cmd的值拼接命令格式
switch (d_cmd) {
case "0000"://特殊指令
break;
case "0011"://地址读
buffer = concatenateBuffers(htonl(buffer),htonl(toFixedSizeBuffer(parseInt(dataStart),4)),htonl(toFixedSizeBuffer(parseInt(dataLength),4)));
break;
case "0100"://地址写
allBufferList = allList.map(item=>{
return stringToHexBuffer(item.inputValue,item.lengthValue*4*2);
})
buffer = concatenateBuffers(htonl(buffer),htonl(toFixedSizeBuffer(parseInt(dataStart),4)),htonl(toFixedSizeBuffer(parseInt(dataLength),4)),...allBufferList)
break;
}
let result = bufferToHex(buffer);
return result;
}
export function bufferToHex(buffer) {
let hexString = '';
const view = new Uint8Array(buffer);
for (let i = 0; i < view.length; i++) {
const hex = view[i].toString(16).padStart(2, '0');
hexString += hex;
}
return hexString;
}
export function toBinaryString(number, length) {
let binaryString = number.toString(2);
return binaryString.padStart(length, '0');
}
export function binaryToHex(binaryStr) {
// 确保二进制字符串长度是4的倍数
if (binaryStr.length % 4 !== 0) {
binaryStr = binaryStr.padStart(binaryStr.length + 4 - (binaryStr.length % 4), '0');
}
let hexStr = '';
for (let i = 0; i < binaryStr.length; i += 4) {
// 取出每4位二进制字符串
const binaryChunk = binaryStr.slice(i, i + 4);
// 转换成十六进制字符并追加到结果字符串中
hexStr += parseInt(binaryChunk, 2).toString(16);
}
return hexStr;
}
export function hexToBuffer(hexStr) {
if (hexStr.length % 2 !== 0) {
throw new Error('Invalid hex string');
}
let buffer = new ArrayBuffer(hexStr.length / 2);
let view = new Uint8Array(buffer);
for (let i = 0; i < hexStr.length; i += 2) {
view[i / 2] = parseInt(hexStr.substr(i, 2), 16);
}
return buffer;
}
export function swapEndian(buffer) {
const swappedBuffer = new ArrayBuffer(buffer.byteLength);
const view = new DataView(buffer);
const swappedView = new DataView(swappedBuffer);
for (let i = 0; i < buffer.byteLength; i++) {
swappedView.setUint8(i, view.getUint8(buffer.byteLength - 1 - i));
}
return swappedBuffer;
}
export function htonl(buffer) {
if (buffer.byteLength !== 4) {
throw new Error('Buffer must be exactly 4 bytes.');
}
let view = new DataView(buffer);
let number = view.getUint32(0);
let swappedNumber = ((number & 0xFF) << 24) |
((number & 0xFF00) << 8) |
((number & 0xFF0000) >> 8) |
((number >> 24) & 0xFF);
let swappedBuffer = new ArrayBuffer(4);
let swappedView = new DataView(swappedBuffer);
swappedView.setUint32(0, swappedNumber);
return swappedBuffer;
}
//将数字转换成指定字节大小的buffer
export function toFixedSizeBuffer(number, byteSize) {
if (byteSize <= 0) {
throw new Error('Byte size must be greater than zero.');
}
let buffer = new ArrayBuffer(byteSize);
let view = new DataView(buffer);
// 根据指定字节数设置数值到缓冲区中
for (let i = 0; i < byteSize; i++) {
view.setUint8(byteSize - 1 - i, number & 0xFF);
number = number >> 8;
}
return buffer;
}
export function concatenateBuffers(...buffers) {
// 确保所有元素均为 ArrayBuffer
buffers.forEach(buffer => {
if (!(buffer instanceof ArrayBuffer)) {
throw new TypeError('All arguments must be ArrayBuffers');
}
});
// 计算总长度
let totalLength = buffers.reduce((sum, buffer) => sum + buffer.byteLength, 0);
// 创建一个新的 ArrayBuffer 并使用 Uint8Array 进行操作
let concatenatedBuffer = new Uint8Array(totalLength);
let offset = 0;
// 逐个复制每个缓冲区的内容
buffers.forEach(buffer => {
concatenatedBuffer.set(new Uint8Array(buffer), offset);
offset += buffer.byteLength;
});
return concatenatedBuffer.buffer;
}
export function stringToHexBuffer(str,length) {
// return new TextEncoder().encode(str).buffer;
const bufferView = new TextEncoder().encode(str);
// 计算需要补充的00的数量
const targetLength = length / 2; // 目标长度(字节数)
const paddingLength = targetLength - bufferView.length;
// 创建一个新的Uint8Array长度为目标长度
const paddedBufferView = new Uint8Array(targetLength);
// 将原始Uint8Array的内容复制到新的Uint8Array中
paddedBufferView.set(bufferView);
// 填充00
if (paddingLength > 0) {
paddedBufferView.fill(0, bufferView.length, targetLength);
}
// 返回格式化后的Uint8Array
return paddedBufferView.buffer;
}
export function hexToString(hexStr) {
let str = '';
for (let i = 0; i < hexStr.length; i += 2) {
if(hexStr.substr(i, 2)!=='00'){
str += String.fromCharCode(parseInt(hexStr.substr(i, 2), 16));
}
}
return str;
}
export function rearrangeHexStr(hexStr) {
// 将输入的十六进制字符串解析为字节数组
// 将输入的十六进制字符串按每8位分组
const groups = [];
for (let i = 0; i < hexStr.length; i += 8) {
groups.push(hexStr.slice(i, i + 8));
}
// 对每个组内的每两位进行倒序拼接
const rearrangedGroups = groups.map(group => {
let rearrangedGroup = '';
for (let i = 0; i < group.length; i += 2) {
rearrangedGroup = group.substr(i, 2) + rearrangedGroup;
}
return rearrangedGroup;
});
// 将所有组重新拼接成一个字符串
const rearrangedHexStr = rearrangedGroups.join('');
return rearrangedHexStr;
}
//高低位交换
export function rearrangeHexStr4(hexStr) {
let rearrangedGroup = '';
for (let i = 0; i < hexStr.length; i += 2) {
rearrangedGroup = hexStr.substr(i, 2) + rearrangedGroup;
}
return rearrangedGroup;
}
export function hexToVersion(hexStr) {
let str = rearrangeHexStr(hexStr);
str = hexToDec(str);
return str;
}
export function versionToHex(hexStr) {
let str = decToHex(hexStr);
str = rearrangeHexStr(str);
return str;
}
// 十六进制转十进制
export function hexToDec(hexStr) {
// 去除前缀 "0x"(如果存在)
hexStr = hexStr.replace(/^0x/, '');
// 将十六进制字符串转换为十进制数字
return parseInt(hexStr, 16);
}
// 十进制转十六进制
export function decToHex(decNum) {
// 将十进制数字转换为十六进制字符串
let hexStr = decNum.toString(16);
// 可选:添加前缀 "0x"
return `0x${hexStr}`;
}

View File

@ -1,13 +0,0 @@
<template>
<div>测试test</div>
</template>
<script>
export default {
name: 'test'
}
</script>
<style scoped>
</style>

2459
yarn.lock

File diff suppressed because it is too large Load Diff