feat(export): 实现生产数据导出功能,解决日志滚动不到底部bug,升级1.0.9
- 添加导出生产数据的接口和相关逻辑 - 新增导出时间范围选择功能 - 优化日志滚动和结果显示 - 调整标定日志结构判断逻辑 - 更新 UI 样式,增加配置密钥功能
This commit is contained in:
parent
95f8374a13
commit
7c8b2477d5
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "gy-calibration",
|
||||
"version": "1.0.7",
|
||||
"version": "1.0.9",
|
||||
"description": "谷云开发部开发的断路器标定软件",
|
||||
"main": "./out/main/index.js",
|
||||
"author": "example.com",
|
||||
|
|
|
@ -16,4 +16,6 @@ startAddr: 3
|
|||
#测试源电压波动比例
|
||||
fluctuateRatioU: 90
|
||||
#测试源电压波动比例
|
||||
fluctuateRatioI: 90
|
||||
fluctuateRatioI: 90
|
||||
#配置密钥
|
||||
secretKey: "1dd53c82958d1de56df4035d3ed9fd82"
|
|
@ -2,6 +2,7 @@ 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
|
||||
// 自定义的主进程方法API
|
||||
|
@ -36,6 +37,18 @@ function getConfigPath() {
|
|||
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
|
||||
|
@ -56,7 +69,11 @@ if (process.contextIsolated) {
|
|||
return require(configPath);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
},
|
||||
shell: {
|
||||
openPath: shell.openPath
|
||||
},
|
||||
exePath: getExportPath()
|
||||
})
|
||||
// contextBridge.exposeInMainWorld('api', api)
|
||||
} catch (error) {
|
||||
|
@ -76,7 +93,11 @@ if (process.contextIsolated) {
|
|||
return require(configPath);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
},
|
||||
shell: {
|
||||
openPath: shell.openPath
|
||||
},
|
||||
exePath: getExportPath()
|
||||
}
|
||||
// window.api = api
|
||||
}
|
||||
|
|
|
@ -12,8 +12,7 @@
|
|||
</div>
|
||||
<div class="header-right">
|
||||
<el-button icon="RefreshRight" type="primary" :disabled="playState" @click="generateDeviceList">刷新列表</el-button>
|
||||
<el-button icon="Download" type="success" style="margin-left: 10px" @click="showExportProdDialog = true">导出生产数据</el-button>
|
||||
<el-button icon="Setting" :disabled="playState" @click="openSettings">配置方案</el-button>
|
||||
<el-button icon="Setting" :disabled="playState" style="margin-left: 10px" @click="openSettings">配置</el-button>
|
||||
</div>
|
||||
</el-header>
|
||||
<div v-if="activeScheme && activeScheme.series" class="scheme-list list-one">
|
||||
|
@ -42,7 +41,7 @@
|
|||
<span v-if="item.key !== 'reserve' && index !== 1 && index !== 2 && index !== 5" :key="index" class="scheme-item"
|
||||
>{{ item.unit ? item.name + '(' + item.unit + ')' : item.name }}:
|
||||
<span v-if="index === 6 || index === 7 || index === 8" class="scheme-value"
|
||||
>2<sup style="margin-left:1px;font-size:10px">{{ item.value }}</sup></span
|
||||
>2<sup style="margin-left: 1px; font-size: 10px">{{ item.value }}</sup></span
|
||||
><span v-else class="scheme-value">{{ item.value }}</span></span
|
||||
>
|
||||
</template>
|
||||
|
@ -138,7 +137,8 @@
|
|||
class="log-item"
|
||||
:class="{
|
||||
'search-highlight': isSearchActive && searchResults.some(result => result.originalIndex === index),
|
||||
'search-current': isSearchActive && searchResults[currentSearchIndex] && searchResults[currentSearchIndex].originalIndex === index
|
||||
'search-current': isSearchActive && searchResults[currentSearchIndex] && searchResults[currentSearchIndex].originalIndex === index,
|
||||
'finish-txt': item.type == 'calibrate_finish'
|
||||
}"
|
||||
>
|
||||
<el-tooltip v-if="item.type == 'calibrate_error'" effect="light" content="错误信息" placement="top">
|
||||
|
@ -220,6 +220,7 @@
|
|||
<el-button type="primary" @click="addScheme">新增方案</el-button>
|
||||
<el-button type="success" @click="exportSelectedSchemes">导出方案</el-button>
|
||||
<el-button type="warning" @click="importSchemes">导入方案</el-button>
|
||||
<el-button icon="Download" type="success" style="margin-left: 10px" @click="showExportProdDialog = true">导出生产数据</el-button>
|
||||
<input ref="importInputRef" type="file" accept="application/json" style="display: none" @change="handleImportFile" />
|
||||
</div>
|
||||
<el-button type="primary" @click="loadSchemes">刷新</el-button>
|
||||
|
@ -519,7 +520,7 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted, computed } from 'vue';
|
||||
import { ref, onMounted, onUnmounted, computed, watch, nextTick } from 'vue';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import { Search, ArrowUp, ArrowDown, Top, Bottom, Close } from '@element-plus/icons-vue';
|
||||
import { throttle } from 'lodash-es';
|
||||
|
@ -624,6 +625,10 @@ const shortcutKeyList = ref([
|
|||
label: '↓',
|
||||
action: '下一个日志(查询时)'
|
||||
},
|
||||
{
|
||||
label: 'Enter',
|
||||
action: '下一个日志(查询时)'
|
||||
},
|
||||
{
|
||||
label: 'Esc',
|
||||
action: '退出查询'
|
||||
|
@ -745,7 +750,20 @@ const processLogData = apiData => {
|
|||
paramMapRow[item.valueKey] = item;
|
||||
});
|
||||
// 结果判定
|
||||
const allOk = logParamColumns.value.every(col => paramMapRow[col.valueKey]?.result === 1);
|
||||
// 检查是否有任何参数的result为0,如果有则直接判定为失败
|
||||
// const hasFailure = logParamColumns.value.some(col => paramMapRow[col.valueKey]?.result === 0);
|
||||
// if (hasFailure) return {
|
||||
// step,
|
||||
// paramMap: paramMapRow,
|
||||
// result: 0
|
||||
// };
|
||||
// }
|
||||
// 检查所有有result值的参数是否都为1
|
||||
const allOk = logParamColumns.value.every(col => {
|
||||
const param = paramMapRow[col.valueKey];
|
||||
// 没有result值的参数不参与判断
|
||||
return param?.result === undefined || param?.result === 1;
|
||||
});
|
||||
return {
|
||||
step,
|
||||
paramMap: paramMapRow,
|
||||
|
@ -789,6 +807,8 @@ const setDeviceInfo = msg => {
|
|||
type = 'calibrate_result_error';
|
||||
} else if (deviceInfo.result === 1) {
|
||||
type = 'calibrate_result_success';
|
||||
} else {
|
||||
type = 'calibrate_result_hidden';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -807,8 +827,10 @@ const getSocketMeassage = message => {
|
|||
|
||||
if (msg.msgType === 'calibrate_result') {
|
||||
let resultType = setDeviceInfo(msg.data);
|
||||
if (resultType) {
|
||||
if (resultType !== 'calibrate_result_hidden') {
|
||||
newLog.type = resultType;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -821,7 +843,7 @@ const getSocketMeassage = message => {
|
|||
logs.value = [...logs.value.slice(-MAX_LOG_LENGTH + 1), newLog];
|
||||
|
||||
// 按需触发滚动
|
||||
if (isScroll.value) throttledScroll();
|
||||
// if (isScroll.value) throttledScroll();
|
||||
|
||||
// let msg = JSON.parse(message.data);
|
||||
// if (msg.msgType !== undefined) {
|
||||
|
@ -965,18 +987,16 @@ const openSettings = () => {
|
|||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
inputType: 'password',
|
||||
inputValue: 'gy999',
|
||||
inputValue: '',
|
||||
inputPlaceholder: '请输入密码',
|
||||
closeOnClickModal: false
|
||||
// inputValidator: (value) => {
|
||||
// if (!value) return '请输入密码';
|
||||
// if (value !== 'gy999') return '密码错误';
|
||||
// return true;
|
||||
// }
|
||||
inputValidator: value => {
|
||||
if (!value.trim()) return '请输入密码';
|
||||
return true;
|
||||
}
|
||||
})
|
||||
.then(async ({ value }) => {
|
||||
try {
|
||||
const response = await axios.post(config.url + '/master/scheme/auth?secret=' + value);
|
||||
const response = await axios.post(config.url + '/master/scheme/auth?secret=' + value.trim());
|
||||
if (response.data.code === 0) {
|
||||
if (response.data.data.result) {
|
||||
schemeDrawerVisible.value = true;
|
||||
|
@ -1063,7 +1083,7 @@ const loadSchemes = async () => {
|
|||
const saveScheme = async () => {
|
||||
// 新增校验:标定中检测和标定后检测必须至少有一个为true
|
||||
if (!currentScheme.value.middleDetect && !currentScheme.value.laterDetect) {
|
||||
ElMessage.error('“标定中检测”和“标定后检测”必须至少选择一个');
|
||||
ElMessage.error('"标定中检测"和"标定后检测"必须至少选择一个');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
|
@ -1458,6 +1478,15 @@ const exportSelectedSchemes = () => {
|
|||
const showExportProdDialog = ref(false);
|
||||
const exportProdRange = ref([]);
|
||||
const exportProdPickerOptions = [
|
||||
{
|
||||
text: '本日',
|
||||
value: () => {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
// start.setTime(start.getTime() - 3600 * 1000 * 24);
|
||||
return [start, end];
|
||||
}
|
||||
},
|
||||
{
|
||||
text: '最近一周',
|
||||
value: () => {
|
||||
|
@ -1487,16 +1516,49 @@ const exportProdPickerOptions = [
|
|||
}
|
||||
];
|
||||
|
||||
const handleExportProd = () => {
|
||||
const handleExportProd = async () => {
|
||||
console.log(window.electron);
|
||||
if (!exportProdRange.value || exportProdRange.value.length !== 2) {
|
||||
ElMessage.warning('请选择导出时间范围');
|
||||
return;
|
||||
}
|
||||
// TODO: 调用实际导出生产数据接口
|
||||
// exportProdRange.value[0]、exportProdRange.value[1] 为起止时间
|
||||
const [start, end] = exportProdRange.value;
|
||||
// 补全时间
|
||||
const beginTime = new Date(dayjs(start).format('YYYY-MM-DD') + ' 00:00:00').getTime();
|
||||
const endTime = new Date(dayjs(end).format('YYYY-MM-DD') + ' 23:59:59').getTime();
|
||||
try {
|
||||
const response = await axios.get(config.url + `/master/calibrate/resultExport?beginTime=${beginTime}&endTime=${endTime}`);
|
||||
if (response.data.code === 0) {
|
||||
ElMessage.success('生成成功');
|
||||
// 打开exePath/export目录
|
||||
if (window.electron && window.electron.shell && window.electron.exePath) {
|
||||
window.electron.shell.openPath(window.electron.exePath + '/export');
|
||||
} else {
|
||||
ElMessage.info('请手动前往导出目录"软件安装目录/resources/service/export"');
|
||||
}
|
||||
} else {
|
||||
ElMessage.error(response.data.message || '导出失败');
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error('导出失败');
|
||||
}
|
||||
showExportProdDialog.value = false;
|
||||
ElMessage.success('导出请求已发起(请补充实际导出逻辑)');
|
||||
};
|
||||
|
||||
// 监听日志变化滚到到底部
|
||||
watch(
|
||||
logs,
|
||||
() => {
|
||||
if (isScroll.value) {
|
||||
nextTick(() => {
|
||||
throttledScroll();
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
deep: true
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
@ -1522,10 +1584,11 @@ const handleExportProd = () => {
|
|||
}
|
||||
.scheme-list {
|
||||
background: #ddd;
|
||||
padding: 10px;
|
||||
padding: 6px;
|
||||
font-size: 13px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
user-select: text;
|
||||
&.list-two {
|
||||
// justify-content: space-between;
|
||||
}
|
||||
|
@ -1789,6 +1852,7 @@ const handleExportProd = () => {
|
|||
|
||||
.scheme-drawer-content {
|
||||
padding: 20px;
|
||||
user-select: text;
|
||||
.device-info {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
@ -1940,6 +2004,9 @@ const handleExportProd = () => {
|
|||
border-radius: 2px;
|
||||
font-weight: bold;
|
||||
}
|
||||
&.finish-txt {
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.dark-table {
|
||||
|
|
Loading…
Reference in New Issue