feat(main): 添加获取应用版本功能并优化日志功能

- 在主进程中添加 get-app-version 的 IPC 处理程序,返回应用版本号
- 在预加载脚本中暴露 getAppVersion 方法给渲染进程
- 在 calibration 页面中添加版本信息显示
- 优化日志显示功能,增加日志转置和分页显示
- 添加清空日志功能
- 调整设备卡片样式,增加选中状态
This commit is contained in:
fhysy 2025-06-25 18:13:40 +08:00
parent 9bc4e481e5
commit 8a7e53bc97
4 changed files with 593 additions and 190 deletions

View File

@ -8,7 +8,10 @@ directories:
# 定义要包含或排除在构建输出中的文件
files:
- '!**/.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}' # 排除环境和包管理配置文件

View File

@ -91,9 +91,9 @@ if (!gotTheLock) {
}
});
// 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.
//当Electron完成时将调用此方法
//初始化并准备创建浏览器窗口。
//某些API只能在此事件发生后使用。
const { spawn } = require('child_process');
let child = null;
let exePluginsExeList = [];
@ -220,5 +220,10 @@ if (!gotTheLock) {
}
});
}
// 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.
ipcMain.handle('get-app-version', () => {
return app.getVersion();
});

View File

@ -1,4 +1,4 @@
import { contextBridge, ipcRenderer } from 'electron'
import { contextBridge, ipcRenderer } from 'electron'
import { electronAPI } from '@electron-toolkit/preload'
// Custom APIs for renderer
@ -16,6 +16,10 @@ import { electronAPI } from '@electron-toolkit/preload'
// return result;
// }
// }
// // 暴露获取版本号的方法
// ipcMain.handle('get-app-version', () => {
// return app.getVersion(); // 返回当前应用版本(来自 package.json
// });
// Use `contextBridge` APIs to expose Electron APIs to
// renderer only if context isolation is enabled, otherwise
@ -23,12 +27,22 @@ import { electronAPI } from '@electron-toolkit/preload'
// 使用contextBridge将Electron API和自定义的主进程方法API暴露给渲染进程页面。
if (process.contextIsolated) {
try {
contextBridge.exposeInMainWorld('electron', electronAPI)
contextBridge.exposeInMainWorld('electron', {
...electronAPI,
getAppVersion: async () => {
return await ipcRenderer.invoke('get-app-version');
}
})
// contextBridge.exposeInMainWorld('api', api)
} catch (error) {
console.error(error)
}
} else {
window.electron = electronAPI
window.electron = {
...electronAPI,
getAppVersion: async () => {
return await ipcRenderer.invoke('get-app-version');
}
}
// window.api = api
}

View File

@ -2,7 +2,7 @@
<div class="calibration-page">
<el-header class="calibration-header">
<div class="header-left">
<el-select v-model="selectedScheme" placeholder="选择方案" style="width: 200px; margin-right: 15px" @change="schemeChange">
<el-select v-model="selectedScheme" placeholder="选择方案" :disabled="playState" style="width: 200px; margin-right: 15px" @change="schemeChange">
<el-option v-for="(item, index) in schemeList" :key="index" :label="item.schemeName" :value="item.id"></el-option>
</el-select>
<el-button icon="CaretRight" type="primary" :disabled="playState" @click="startExecution">开始执行</el-button>
@ -10,10 +10,10 @@
</div>
<div class="header-right">
<el-button icon="RefreshRight" type="primary" :disabled="playState" @click="generateDeviceList">刷新列表</el-button>
<el-button icon="Setting" :disabled="playState" @click="openSettings">设置</el-button>
<el-button icon="Setting" :disabled="playState" @click="openSettings">配置方案</el-button>
</div>
</el-header>
<div class="scheme-list" v-if="activeScheme && activeScheme.series">
<div v-if="activeScheme && activeScheme.series" class="scheme-list list-one">
<span class="scheme-item"
>系列: <span class="scheme-value">{{ activeScheme.series }}</span></span
>
@ -21,8 +21,13 @@
>框架: <span class="scheme-value">{{ activeScheme.framework }}</span></span
>
<span class="scheme-item"
>类型: <span class="scheme-value">{{ activeScheme.schemeType }}</span></span
>P位: <span class="scheme-value">{{ activeScheme.schemeType }}</span></span
>
<span class="scheme-item"
>额定电流(A): <span class="scheme-value">{{ activeScheme.configParam.format[2].value }}</span></span
>
</div>
<div v-if="activeScheme && activeScheme.series" class="scheme-list list-two">
<span v-for="(item, index) in activeScheme.configParam.format" :key="index" class="scheme-item"
>{{ item.unit ? item.name + '(' + item.unit + ')' : item.name }}: <span class="scheme-value">{{ item.value }}</span></span
>
@ -30,25 +35,25 @@
<el-main class="calibration-main">
<div class="device-grid">
<el-card v-for="(device, index) in devices" :key="device.id" class="device-card">
<el-card v-for="(device, index) in devices" :key="device.id" class="device-card" :class="activeDeviceIndex === index ? 'active' : ''" @click="selectDevice(device, index)">
<template #header>
<div class="device-card-header">
<!-- <span>{{ device.code }}</span>-->
<span>设备{{ device.id }}</span>
<el-tag :type="device.status === 1 ? 'success' : 'info'" size="small">
{{ device.status === 1 ? '已连接' : '未连接' }}
<el-tag :type="device.connectStatus === 1 ? 'success' : 'info'" size="small">
{{ device.connectStatus === 1 ? '已连接' : '未连接' }}
</el-tag>
</div>
</template>
<div class="device-card-body">
<div :class="['iconfont', 'icon-icon_duanluqi', 'circuit-breaker', device.result === '成功' ? 'color-green' : device.result === '失败' ? 'color-red' : '']"></div>
<p>设备码: {{ device.deviceSN || '无' }}</p>
<p>芯片ID: {{ device.deviceSN || '无' }}</p>
<p>设备端口: {{ device.devicePort || '无' }}</p>
<p>
标定结果: <span :class="['device-result', device.result === '成功' ? 'color-green' : device.result === '失败' ? 'color-red' : '']">{{ device.result || '无' }}</span>
</p>
<p>
失败描述:
结果描述:
<span
><el-tooltip class="box-item" effect="dark" :content="device.resultTxt" placement="top-start">
{{ device.resultTxt || '无' }}
@ -104,6 +109,11 @@
<span class="iconfont icon-icon_suoding"></span>
</el-tooltip>
</view>
<view class="log-box-operate-item" @click="clearLog">
<el-tooltip class="box-item" content="清空日志" effect="dark" placement="bottom">
<span class="iconfont icon-icon_shanchu"></span>
</el-tooltip>
</view>
<view class="log-box-operate-item" @click="toggleOpenLog">
<el-tooltip v-if="isOpenLog" class="box-item" content="收缩日志" effect="dark" placement="bottom">
<span class="iconfont icon-up-arrow"></span>
@ -113,153 +123,192 @@
</el-tooltip>
</view>
</div>
<div class="version-info">{{ version }}</div>
<div class="version-info">V{{ version }}</div>
</div>
</el-footer>
<!-- 方案配置抽屉 -->
<el-drawer v-model="schemeDrawerVisible" title="方案配置" size="80%" :destroy-on-close="true">
<div class="scheme-drawer-content">
<div class="scheme-list">
<div class="scheme-list-header">
<el-button type="primary" @click="addScheme">新增方案</el-button>
<el-button type="primary" @click="loadSchemes">刷新</el-button>
<div class="scheme-list-header">
<el-button type="primary" @click="addScheme">新增方案</el-button>
<el-button type="primary" @click="loadSchemes">刷新</el-button>
</div>
<el-table v-loading="loading" :data="schemeList" style="width: 100%">
<el-table-column type="index" width="50" />
<el-table-column prop="schemeName" label="方案名称" />
<el-table-column prop="schemeType" label="断路器类型"></el-table-column>
<el-table-column label="操作" width="200">
<template #default="scope">
<el-button type="primary" link @click="viewScheme(scope.row)">修改</el-button>
<el-button type="danger" link @click="deleteScheme(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</el-drawer>
<!-- 方案详情对话框 -->
<el-dialog v-model="schemeDetailVisible" :title="currentScheme.schemeName" width="95%" :destroy-on-close="true" align-center :close-on-click-modal="false">
<el-form :model="currentScheme" label-width="120px">
<el-form-item label="方案名称">
<el-input v-model="currentScheme.schemeName" />
</el-form-item>
<el-row>
<el-col :span="8">
<el-form-item label="系列">
<el-select v-model="currentScheme.series" placeholder="请选择系列">
<el-option label="B7" value="B7" />
<el-option label="B7L" value="B7L" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="框架">
<el-select v-model="currentScheme.framework" placeholder="请选择框架">
<el-option label="100ZS" value="100ZS" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="断路器类型">
<el-select v-model="currentScheme.schemeType" placeholder="请选择断路器类型">
<el-option label="1p" value="1p" />
<el-option label="2p" value="2p" />
<el-option label="3p" value="3p" />
<el-option label="4p" value="4p" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-divider>断路器校准参数</el-divider>
<div class="calibrate-params">
<el-form-item v-for="(item, index) in defaultConfList.format" :key="item.key" :label="item.unit ? item.name + '(' + item.unit + ')' : item.name" :label-width="140">
<el-input v-model="currentScheme.configParam.format[index].value"> </el-input>
</el-form-item>
</div>
<!-- <el-divider>断路器类型参数</el-divider>
<div class="device-params">
<div v-for="item in currentScheme.propertyParam" :key="item.id" class="device-param-item">
<span class="param-label">{{ item.unit ? item.name + '(' + item.unit + ')' : item.name }}</span>
</div>
</div> -->
<el-divider>校准精度(%)</el-divider>
<div class="accuracy-params">
<el-form-item v-for="(value, key) in currentScheme.errorRange" :key="key" label-width="80px" :label="accuracyType[key]">
<el-input-number v-model="currentScheme.errorRange[key]" :min="0" :max="100" :precision="2" />
</el-form-item>
</div>
<el-divider>标定步骤</el-divider>
<div class="calibration-steps">
<div class="steps-header">
<el-button type="primary" @click="addCalibrationStep">添加步骤</el-button>
</div>
<el-table v-loading="loading" :data="schemeList" style="width: 100%">
<el-table-column type="index" width="50" />
<el-table-column prop="schemeName" label="方案名称" />
<el-table-column prop="schemeType" label="断路器类型"></el-table-column>
<el-table-column label="操作" width="200">
<el-table :data="currentScheme.steps" style="width: 100%">
<!-- <el-table-column type="index" width="50" />-->
<el-table-column prop="id" align="center" label="排序" width="80" />
<!-- <el-table-column prop="id" align="center" label="步骤值">-->
<!-- <template #default="scope">-->
<!-- <el-input-number v-model="scope.row.id" :min="0" />-->
<!-- </template>-->
<!-- </el-table-column>-->
<el-table-column prop="step" align="center" label="步骤值">
<template #default="scope">
<el-button type="primary" link @click="viewScheme(scope.row)">修改</el-button>
<el-button type="danger" link @click="deleteScheme(scope.row)">删除</el-button>
<el-input-number v-model="scope.row.step" :min="1" />
</template>
</el-table-column>
<el-table-column prop="voltage" align="center" label="电压Un(%)">
<template #default="scope">
<el-input-number v-model="scope.row.voltage" :min="0" :precision="1" />
</template>
</el-table-column>
<el-table-column prop="current" align="center" label="电流Ib(%)">
<template #default="scope">
<el-input-number v-model="scope.row.current" :min="0" :precision="1" />
</template>
</el-table-column>
<el-table-column prop="powerFactor" align="center" label="功率因数">
<template #default="scope">
<el-select v-model="scope.row.powerFactor">
<el-option label="0.5L" value="0.5L" />
<el-option label="0.8L" value="0.8L" />
<el-option label="1" value="1" />
<el-option label="0.5C" value="0.5C" />
<el-option label="0.8C" value="0.8C" />
</el-select>
</template>
</el-table-column>
<el-table-column prop="isILeak" align="center" label="检测漏电" width="120">
<template #default="scope">
<el-switch v-model="scope.row.isILeak" />
</template>
</el-table-column>
<el-table-column label="操作" width="80">
<template #default="scope">
<el-button type="danger" link @click="deleteCalibrationStep(scope.$index)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="schemeDetailVisible = false">取消</el-button>
<el-button type="primary" @click="saveScheme">保存</el-button>
</span>
</template>
</el-dialog>
<!-- 方案详情对话框 -->
<el-dialog v-model="schemeDetailVisible" :title="currentScheme.schemeName" width="95%" :destroy-on-close="true" align-center :close-on-click-modal="false">
<el-form :model="currentScheme" label-width="120px">
<el-form-item label="方案名称">
<el-input v-model="currentScheme.schemeName" />
</el-form-item>
<el-row>
<el-col :span="8">
<el-form-item label="系列">
<el-select v-model="currentScheme.series" placeholder="请选择系列">
<el-option label="B7" value="B7" />
<el-option label="B7L" value="B7L" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="框架">
<el-select v-model="currentScheme.framework" placeholder="请选择框架">
<el-option label="100ZS" value="100ZS" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="断路器类型">
<el-select v-model="currentScheme.schemeType" placeholder="请选择断路器类型">
<el-option label="1p" value="1p" />
<el-option label="2p" value="2p" />
<el-option label="3p" value="3p" />
<el-option label="4p" value="4p" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<!-- 方案配置抽屉 -->
<el-drawer v-model="logVisible" title="设备日志" size="80%" :destroy-on-close="true">
<div class="scheme-drawer-content log-content">
<div class="device-info">
<div class="device-info-item">设备: {{ activeDeviceInfo.id || '-' }}</div>
<div class="device-info-item">芯片ID: {{ activeDeviceInfo.deviceSN || '-' }}</div>
<div class="device-info-item">设备端口: {{ activeDeviceInfo.devicePort || '-' }}</div>
<div class="device-info-item">标定结果: {{ activeDeviceInfo.result || '-' }}</div>
<div class="device-info-item">结果描述: {{ activeDeviceInfo.resultTxt || '-' }}</div>
</div>
<el-tabs v-model="logTabActive" class="demo-tabs" @tab-click="logTabChange">
<el-tab-pane label="标定日志" name="log">
<el-table :data="transposedLogList" style="width: 100%" size="small" scrollbar-always-on resizable empty-text="暂无日志">
<el-table-column prop="name" label="参数" fixed align="center" />
<el-table-column v-for="(item, index) in logList" :key="index" :label="item.name" align="center">
<el-table-column prop="name" label="结果" align="center" min-width="80">
<template #default="scope">
<span :style="{ color: scope.row.data[index].result != 1 ? 'red' : 'green' }">{{ scope.row.data[index].value || '-' }}</span>
<el-icon v-if="scope.row.data[index].result === 2" style="color: red"><Top /></el-icon>
<el-icon v-if="scope.row.data[index].result === 0" style="color: red"><Bottom /></el-icon>
</template>
</el-table-column>
<el-table-column label="范围" align="errLog">
<template #default="scope">
<span style="margin-left: 8px; color: #888; font-size: 12px">{{
scope.row.data[index].minValue && scope.row.data[index].maxValue ? scope.row.data[index].minValue + ' ~ ' + scope.row.data[index].maxValue : '-'
}}</span>
</template>
</el-table-column>
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="错误日志" name="second">
错误日志
</el-tab-pane>
</el-tabs>
<el-divider>断路器校准参数</el-divider>
<div class="calibrate-params">
<el-form-item v-for="(item, index) in defaultConfList.format" :key="item.key" :label="item.unit ? item.name + '(' + item.unit + ')' : item.name" :label-width="140">
<el-input v-model="currentScheme.configParam.format[index].value"> </el-input>
</el-form-item>
</div>
<!-- <el-divider>断路器类型参数</el-divider>
<div class="device-params">
<div v-for="item in currentScheme.propertyParam" :key="item.id" class="device-param-item">
<span class="param-label">{{ item.unit ? item.name + '(' + item.unit + ')' : item.name }}</span>
</div>
</div> -->
<el-divider>校准精度(%)</el-divider>
<div class="accuracy-params">
<el-form-item v-for="(value, key) in currentScheme.errorRange" :key="key" label-width="80px" :label="accuracyType[key]">
<el-input-number v-model="currentScheme.errorRange[key]" :min="0" :max="100" :precision="2" />
</el-form-item>
</div>
<el-divider>标定步骤</el-divider>
<div class="calibration-steps">
<div class="steps-header">
<el-button type="primary" @click="addCalibrationStep">添加步骤</el-button>
</div>
<el-table :data="currentScheme.steps" style="width: 100%">
<!-- <el-table-column type="index" width="50" />-->
<el-table-column prop="id" align="center" label="排序" width="80" />
<!-- <el-table-column prop="id" align="center" label="步骤值">-->
<!-- <template #default="scope">-->
<!-- <el-input-number v-model="scope.row.id" :min="0" />-->
<!-- </template>-->
<!-- </el-table-column>-->
<el-table-column prop="step" align="center" label="步骤值">
<template #default="scope">
<el-input-number v-model="scope.row.step" :min="1" />
</template>
</el-table-column>
<el-table-column prop="voltage" align="center" label="电压Un(%)">
<template #default="scope">
<el-input-number v-model="scope.row.voltage" :min="0" :precision="1" />
</template>
</el-table-column>
<el-table-column prop="current" align="center" label="电流Ib(%)">
<template #default="scope">
<el-input-number v-model="scope.row.current" :min="0" :precision="1" />
</template>
</el-table-column>
<el-table-column prop="powerFactor" align="center" label="功率因数">
<template #default="scope">
<el-select v-model="scope.row.powerFactor">
<el-option label="0.5L" value="0.5L" />
<el-option label="0.8L" value="0.8L" />
<el-option label="1" value="1" />
<el-option label="0.5C" value="0.5C" />
<el-option label="0.8C" value="0.8C" />
</el-select>
</template>
</el-table-column>
<el-table-column prop="isILeak" align="center" label="检测漏电" width="120">
<template #default="scope">
<el-switch v-model="scope.row.isILeak" />
</template>
</el-table-column>
<el-table-column label="操作" width="80">
<template #default="scope">
<el-button type="danger" link @click="deleteCalibrationStep(scope.$index)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="schemeDetailVisible = false">取消</el-button>
<el-button type="primary" @click="saveScheme">保存</el-button>
</span>
</template>
</el-dialog>
</div>
</el-drawer>
</div>
</template>
<script setup>
import { ref, onMounted, computed, onUnmounted } from 'vue';
import { ref, onMounted, onUnmounted, computed } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import { throttle } from 'lodash-es';
import dayjs from 'dayjs';
import axios from 'axios';
import config from '@renderer/util/config.js';
@ -273,6 +322,7 @@ const devices = ref([]);
const isScroll = ref(true);
const logs = ref([]);
const version = ref('V1.0.0');
const logTabActive = ref('log')
const loading = ref(true);
const isOpenLog = ref(false);
@ -307,6 +357,236 @@ const defaultConfList = ref({
format: []
});
const logVisible = ref(false);
const logList = ref([
{
name: '标定1',
dataList: [
{
id: 1,
name: '电压',
value: 220,
unit: 'V',
accuracy: 1,
result: 0,
minValue: '210',
maxValue: '230'
},
{
id: 2,
name: '电流',
value: 5,
unit: 'A',
accuracy: 1,
result: 0,
minValue: '7.5',
maxValue: '12.5'
},
{
id: 3,
name: '漏电流',
value: 1,
unit: 'A',
accuracy: 1,
result: 2,
minValue: '0',
maxValue: '0'
}
]
},
{
name: '标定1重复1',
dataList: [
{
id: 1,
name: '电压',
value: 220,
unit: 'V',
accuracy: 1,
result: 1,
minValue: '210',
maxValue: '230'
},
{
id: 2,
name: '电流',
value: 10,
unit: 'A',
accuracy: 1,
result: 1,
minValue: '7.5',
maxValue: '12.5'
},
{
id: 3,
name: '漏电流',
value: 0,
unit: 'A',
accuracy: 1,
result: 1,
minValue: '0',
maxValue: '0'
}
]
},
{
name: '标定2',
dataList: [
{
id: 1,
name: '电压',
value: 220,
unit: 'V',
accuracy: 1,
result: 1,
minValue: '210',
maxValue: '230'
},
{
id: 2,
name: '电流',
value: 10,
unit: 'A',
accuracy: 1,
result: 1,
minValue: '7.5',
maxValue: '12.5'
},
{
id: 3,
name: '漏电流',
value: 0,
unit: 'A',
accuracy: 1,
result: 1,
minValue: '0',
maxValue: '0'
}
]
},
{
name: '标定3',
dataList: [
{
id: 1,
name: '电压',
value: 220,
unit: 'V',
accuracy: 1,
result: 1,
minValue: '210',
maxValue: '230'
},
{
id: 2,
name: '电流',
value: 10,
unit: 'A',
accuracy: 1,
result: 1,
minValue: '7.5',
maxValue: '12.5'
},
{
id: 3,
name: '漏电流',
value: 0,
unit: 'A',
accuracy: 1,
result: 1,
minValue: '0',
maxValue: '0'
}
]
},
{
name: '标定4',
dataList: [
{
id: 1,
name: '电压',
value: 220,
unit: 'V',
accuracy: 1,
result: 1,
minValue: '210',
maxValue: '230'
},
{
id: 2,
name: '电流',
value: 10,
unit: 'A',
accuracy: 1,
result: 1,
minValue: '7.5',
maxValue: '12.5'
},
{
id: 3,
name: '漏电流',
value: 0,
unit: 'A',
accuracy: 1,
result: 1,
minValue: '0',
maxValue: '0'
}
]
},
{
name: '标定5',
dataList: [
{
id: 1,
name: '电压',
value: 220,
unit: 'V',
accuracy: 1,
result: 1,
minValue: '210',
maxValue: '230'
},
{
id: 2,
name: '电流',
value: 10,
unit: 'A',
accuracy: 1,
result: 1,
minValue: '7.5',
maxValue: '12.5'
},
{
id: 3,
name: '漏电流',
value: 0,
unit: 'A',
accuracy: 1,
result: 1,
minValue: '0',
maxValue: '0'
}
]
}
]);
const logBoxRef = ref(null);
const MAX_LOG_LENGTH = 800;
const activeDeviceIndex = ref(0);
const activeDeviceInfo = ref({
id: 0,
devicePort: '',
deviceSN: '',
connectStatus: 0,
switch: 0,
result: 0,
resultTxt: ''
});
const defaultPropList = ref([]);
const currentScheme = ref({
@ -328,16 +608,29 @@ const currentScheme = ref({
steps: []
});
const logTabChange = (tab, event) => {
console.log(tab, event)
}
const selectDevice = (item, index) => {
activeDeviceInfo.value = item;
activeDeviceIndex.value = index;
//
// logList.value = [];
logVisible.value = true;
};
const generateMockDevices = () => {
const mockDevices = [];
for (let i = 1; i <= 16; i++) {
mockDevices.push({
id: i,
code: `设备 ${i}`,
deviceCode: Math.floor(1000000000000 + Math.random() * 9000000000000).toString(),
address: `192.168.1.${i}`,
status: i % 3 === 0 ? 'disconnected' : 'connected', // Mock status
result: i % 3 !== 0 ? (i % 2 === 0 ? '' : '成功') : '失败' // Mock result
deviceSN: Math.floor(1000000000000 + Math.random() * 9000000000000).toString(),
devicePort: `192.168.1.${i}`,
connectStatus: i % 3 === 0 ? 1 : 0,
result: i % 3 !== 0 ? (i % 2 === 0 ? '' : '成功') : '失败',
resultTxt: i % 3 !== 0 ? (i % 2 === 0 ? '' : '成功') : '失败'
});
}
devices.value = mockDevices;
@ -419,33 +712,58 @@ const generateLogs = () => {
}
};
// JSON
const tryParseJSON = data => {
try {
return JSON.parse(data);
} catch {
return data;
}
};
//
const throttledScroll = throttle(() => {
logBoxRef.value.scrollTop = logBoxRef.value.scrollHeight;
}, 100);
const getSocketMeassage = message => {
let msg = JSON.parse(message.data);
if (msg.msgType !== undefined) {
if (logs.value.length > 400) {
logs.value.shift();
}
logs.value.push({
time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
msg: msg.data,
type: msg.msgType
});
} else {
if (logs.value.length > 400) {
logs.value.shift();
}
logs.value.push({
time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
msg,
type: null
});
}
if (isScroll.value) {
setTimeout(() => {
let div = document.querySelector('#log-box-main');
div.scrollTop = div.scrollHeight;
}, 200);
}
const msg = tryParseJSON(message.data);
const newLog = {
time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
msg: msg.data ?? msg,
type: msg.msgType ?? null
};
//
logs.value = [...logs.value.slice(-MAX_LOG_LENGTH + 1), newLog];
//
if (isScroll.value) throttledScroll();
// let msg = JSON.parse(message.data);
// if (msg.msgType !== undefined) {
// if (logs.value.length > 400) {
// logs.value.shift();
// }
// logs.value.push({
// time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
// msg: msg.data,
// type: msg.msgType
// });
// } else {
// if (logs.value.length > 400) {
// logs.value.shift();
// }
// logs.value.push({
// time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
// msg,
// type: null
// });
// }
// if (isScroll.value) {
// requestAnimationFrame(() => {
// logBoxRef.value.scrollTop = logBoxRef.value.scrollHeight;
// });
// }
};
const initSocket = () => {
@ -458,7 +776,14 @@ const socketStatus = computed(() => {
});
onMounted(() => {
logBoxRef.value = document.querySelector('#log-box-main');
initSocket();
if (window.electron && typeof window.electron.getAppVersion === 'function') {
window.electron.getAppVersion().then(v => {
version.value = v;
});
}
// generateMockDevices();
getSchemeDefaultConf();
getSchemeDefaultProp();
generateDeviceList();
@ -675,6 +1000,10 @@ const toggleOpenLog = () => {
isOpenLog.value = !isOpenLog.value;
};
const clearLog = () => {
logs.value = [];
};
//
const deleteCalibrationStep = index => {
currentScheme.value.steps.splice(index, 1);
@ -683,6 +1012,22 @@ const deleteCalibrationStep = index => {
step.id = idx + 1;
});
};
// 便
const transposedLogList = computed(() => {
if (!logList.value.length) return [];
// dataList
const paramCount = logList.value[0].dataList.length;
const result = [];
for (let i = 0; i < paramCount; i++) {
const param = {
name: logList.value[0].dataList[i].name + (logList.value[0].dataList[i].unit ? '(' + logList.value[0].dataList[i].unit + ')' : ''),
data: logList.value.map(log => log.dataList[i])
};
result.push(param);
}
return result;
});
</script>
<style scoped lang="scss">
@ -709,7 +1054,9 @@ const deleteCalibrationStep = index => {
font-size: 13px;
display: flex;
align-items: center;
justify-content: space-between;
&.list-two {
justify-content: space-between;
}
.scheme-item {
margin-left: 10px;
&:first-child {
@ -719,6 +1066,12 @@ const deleteCalibrationStep = index => {
font-weight: bold;
}
}
&.list-one {
padding-bottom: 0;
.scheme-item {
margin-right: 55px;
}
}
}
.header-left,
@ -745,7 +1098,12 @@ const deleteCalibrationStep = index => {
}
.device-card {
cursor: pointer;
/* background-color: #ffffff; */ /* Default card color is fine */
border: 1px solid #e6e6e6;
&.active {
border: 1px solid #67c23a;
}
}
.device-card-header {
@ -770,11 +1128,13 @@ const deleteCalibrationStep = index => {
}
.color-green {
color: #67c23a; /* Green for connected */
color: #67c23a;
/* Green for connected */
}
.color-red {
color: #f56c6c; /* Red for disconnected */
color: #f56c6c;
/* Red for disconnected */
}
.calibration-footer {
@ -785,6 +1145,7 @@ const deleteCalibrationStep = index => {
display: flex;
flex-direction: column;
flex-shrink: 0;
&.open-log {
height: 350px;
}
@ -795,7 +1156,8 @@ const deleteCalibrationStep = index => {
overflow-y: auto;
font-family: 'Courier New', Courier, monospace;
font-size: 12px;
white-space: pre-wrap; /* Ensures logs wrap and preserve formatting */
white-space: pre-wrap;
/* Ensures logs wrap and preserve formatting */
border: 1px solid #555;
padding: 5px;
background-color: #202020;
@ -805,6 +1167,7 @@ const deleteCalibrationStep = index => {
margin: 2px 0;
color: #dcdcdc;
}
.log-box-main {
font-family: 'Courier New', Courier, monospace;
padding: 5px;
@ -816,6 +1179,7 @@ const deleteCalibrationStep = index => {
background-color: #202020;
color: #dcdcdc;
scroll-behavior: smooth;
.log-item {
word-wrap: break-word;
word-break: break-all;
@ -824,6 +1188,7 @@ const deleteCalibrationStep = index => {
line-height: 18px;
font-weight: 500;
margin-left: 8px;
.iconfont {
&.icon-icon_fuzhi {
line-height: 26px;
@ -835,26 +1200,31 @@ const deleteCalibrationStep = index => {
}
}
}
.calibration-footer-btn {
font-size: 12px;
padding-top: 5px;
display: flex;
align-items: center;
justify-content: space-between;
.btn-box {
display: flex;
align-items: center;
.log-box-operate-item {
display: flex;
align-items: center;
margin-right: 10px;
cursor: pointer;
.icon-icon_gengxin {
margin-left: 2px;
}
}
}
}
.version-info {
text-align: right;
color: #888;
@ -862,34 +1232,34 @@ const deleteCalibrationStep = index => {
/* Element Plus component overrides if needed */
.el-header {
--el-header-padding: 0 20px; /* Adjust if necessary */
--el-header-height: 60px; /* Ensure this matches fixed height */
--el-header-padding: 0 20px;
/* Adjust if necessary */
--el-header-height: 60px;
/* Ensure this matches fixed height */
}
.el-footer {
--el-footer-padding: 0px; /* Adjust if necessary */
--el-footer-height: 200px; /* Ensure this matches fixed height */
--el-footer-padding: 0px;
/* Adjust if necessary */
--el-footer-height: 200px;
/* Ensure this matches fixed height */
}
.el-main {
--el-main-padding: 20px; /* Adjust if necessary */
--el-main-padding: 20px;
/* Adjust if necessary */
}
.el-select .el-input__inner {
background-color: #555; /* Darker input fields */
background-color: #555;
/* Darker input fields */
color: white;
border-color: #666;
}
//.el-button--primary {
// background-color: #007bff; /* Example primary button color */
// border-color: #007bff;
//}
//
//.el-button--danger {
// background-color: #dc3545; /* Example danger button color */
// border-color: #dc3545;
//}
:deep(.log-content .el-table .cell) {
padding: 0 !important;
}
:deep(.device-grid .el-card__header) {
padding: 10px 5px;
@ -903,6 +1273,17 @@ const deleteCalibrationStep = index => {
.scheme-drawer-content {
padding: 20px;
.device-info {
display: flex;
flex-wrap: wrap;
background: #ddd;
padding: 10px;
font-size: 13px;
align-items: center;
.device-info-item {
margin-right: 10px;
}
}
}
.scheme-list-header {