feat(uart) make settings use localStorage for make settings persistent

This commit is contained in:
kerms 2024-07-31 20:34:38 +08:00
parent 6a7ec54ce8
commit 85864823af
2 changed files with 138 additions and 108 deletions

View File

@ -5,10 +5,10 @@ import {
type ShallowReactive, type ShallowReactive,
ref, ref,
shallowReactive, shallowReactive,
watch, reactive watch,
} from "vue"; } from "vue";
import {AnsiUp} from 'ansi_up' import {AnsiUp} from 'ansi_up'
import {debouncedWatch} from "@vueuse/core"; import {debouncedWatch, useStorage} from "@vueuse/core";
import {type IUartConfig, uart_send_msg} from "@/api/apiUart"; import {type IUartConfig, uart_send_msg} from "@/api/apiUart";
import {isDevMode} from "@/composables/buildMode"; import {isDevMode} from "@/composables/buildMode";
import {useUartStore} from "@/stores/useUartStore"; import {useUartStore} from "@/stores/useUartStore";
@ -270,10 +270,10 @@ export const useDataViewerStore = defineStore('text-viewer', () => {
generateBaudArr(uartBaudList); generateBaudArr(uartBaudList);
/* public value */ /* public value */
const configPanelTab = ref("second"); const configPanelTab = useStorage("configTab" ,"second");
const configPanelShow = ref(true); const configPanelShow = ref(true);
const quickAccessPanelShow = ref(true); const quickAccessPanelShow = ref(true);
const enableAnsiDecode = ref(true); const enableAnsiDecode = useStorage("decodeANSI", true);
/* /*
@ -283,12 +283,12 @@ export const useDataViewerStore = defineStore('text-viewer', () => {
let RxSegment: Uint8Array = new Uint8Array(0); let RxSegment: Uint8Array = new Uint8Array(0);
const RxRemainHexdump = ref(""); const RxRemainHexdump = ref("");
const frameBreakSequence = ref("\\n"); const frameBreakSequence = useStorage("frameBreakSequence", "\\n");
const frameBreakAfterSequence = ref(true); const frameBreakAfterSequence = useStorage("frameBreakAfterSequence", true);
const frameBreakSequenceNormalized = computed(() => { const frameBreakSequenceNormalized = computed(() => {
return unescapeString(frameBreakSequence.value); return unescapeString(frameBreakSequence.value);
}); });
const frameBreakDelay = ref(0); const frameBreakDelay = useStorage("frameBreakDelay", 0);
let frameBreakDelayTimeoutID: number = -1; let frameBreakDelayTimeoutID: number = -1;
function frameBreakFlush() { function frameBreakFlush() {
@ -326,22 +326,34 @@ export const useDataViewerStore = defineStore('text-viewer', () => {
const frameBreakSize = ref(0); const frameBreakSize = useStorage("frameBreakSize", 0);
const frameBreakRules = reactive([{ const frameBreakRules = useStorage("breakRules", [{
ref: frameBreakDelay, ref: frameBreakDelay,
name: '超时(ms)', name: '超时(ms)',
type: 'number', type: 'number',
min: -1, min: -1,
draggable: false, draggable: false,
transformData: () => { transformData: breakDelay,
return {result: [] as Uint8Array[], remain: true};
}
}, { }, {
ref: frameBreakSequence, ref: frameBreakSequence,
name: '匹配', name: '匹配',
type: 'text', type: 'text',
draggable: true, draggable: true,
transformData: (inputArray: Uint8Array[]) => { transformData: breakDelay,
}, {
ref: frameBreakSize,
name: '字节(B)',
type: 'number',
min: 0,
draggable: true,
transformData: breakDelay,
},])
function breakDelay(inputArray: Uint8Array[]) {
return {result: [] as Uint8Array[], remain: true};
}
function breakSequence(inputArray: Uint8Array[]) {
if (frameBreakSequenceNormalized.value.length <= 0) { if (frameBreakSequenceNormalized.value.length <= 0) {
return {result: inputArray, remain: true}; return {result: inputArray, remain: true};
} }
@ -373,13 +385,8 @@ export const useDataViewerStore = defineStore('text-viewer', () => {
const remain = startIndex < inputArray[inputArray.length - 1].length; const remain = startIndex < inputArray[inputArray.length - 1].length;
return {result, remain}; return {result, remain};
} }
}, {
ref: frameBreakSize, function breakSize(inputArray: Uint8Array[]) {
name: '字节(B)',
type: 'number',
min: 0,
draggable: true,
transformData: (inputArray: Uint8Array[]) => {
if (frameBreakSize.value <= 0) { if (frameBreakSize.value <= 0) {
return {result: inputArray, remain: true}; return {result: inputArray, remain: true};
} }
@ -393,7 +400,24 @@ export const useDataViewerStore = defineStore('text-viewer', () => {
const remain = result[result.length - 1].length < frameBreakSize.value; const remain = result[result.length - 1].length < frameBreakSize.value;
return {result, remain}; return {result, remain};
} }
},])
function reloadFrameBreak() {
/* function and ref can not be stored in localStorage */
for (let i = 0; i < frameBreakRules.value.length; i++) {
if (frameBreakRules.value[i].name === "超时(ms)") {
frameBreakRules.value[i].transformData = breakDelay;
frameBreakRules.value[i].ref = frameBreakDelay;
} else if (frameBreakRules.value[i].name === "匹配") {
frameBreakRules.value[i].transformData = breakSequence;
frameBreakRules.value[i].ref = frameBreakSequence;
} else {
frameBreakRules.value[i].transformData = breakSize;
frameBreakRules.value[i].ref = frameBreakSize;
}
}
}
reloadFrameBreak();
function addStringMessage(input: string, isRX: boolean, doSend: boolean = false) { function addStringMessage(input: string, isRX: boolean, doSend: boolean = false) {
const unescaped = unescapeString(input); const unescaped = unescapeString(input);
@ -417,8 +441,8 @@ export const useDataViewerStore = defineStore('text-viewer', () => {
frames.push(RxSegment); frames.push(RxSegment);
/* ready for adding new items */ /* ready for adding new items */
for (let i = 1; i < frameBreakRules.length; i++) { for (let i = 1; i < frameBreakRules.value.length; i++) {
const ret: {result: Uint8Array[], remain: boolean} = frameBreakRules[i].transformData(frames); const ret: {result: Uint8Array[], remain: boolean} = frameBreakRules.value[i].transformData(frames);
/* check if last item changed */ /* check if last item changed */
if (!ret.remain || ret.result[ret.result.length - 1].length !== frames[frames.length - 1].length) { if (!ret.remain || ret.result[ret.result.length - 1].length !== frames[frames.length - 1].length) {
remain = ret.remain; remain = ret.remain;
@ -454,20 +478,21 @@ export const useDataViewerStore = defineStore('text-viewer', () => {
RxRemainHexdump, RxRemainHexdump,
addStringMessage, addStringMessage,
addSegment, addSegment,
reloadFrameBreak,
} }
const showText = ref(true); const showText = useStorage('showText', true);
const showHex = ref(false); const showHex = useStorage('showHex', false);
const showHexdump = ref(false); const showHexdump = useStorage('showHexdump', false);
const enableLineWrap = ref(true); const enableLineWrap = useStorage('lineWrap', false);
const showTimestamp = ref(true); const showTimestamp = useStorage('showTimestamp', true);
const showVirtualScroll = ref(true); const showVirtualScroll = ref(true);
const RxHexdumpColor = ref("#f0f9eb"); const RxHexdumpColor = useStorage('RxHexdumpColor', "#f0f9eb");
const RxTotalByteCount = ref(0); const RxTotalByteCount = ref(0);
const RxByteCount = ref(0); const RxByteCount = ref(0);
const TxHexdumpColor = ref("#ecf4ff"); const TxHexdumpColor = useStorage('TxHexdumpColor', "#ecf4ff");
const TxTotalByteCount = ref(0); const TxTotalByteCount = ref(0);
const TxByteCount = ref(0); const TxByteCount = ref(0);
@ -490,8 +515,8 @@ export const useDataViewerStore = defineStore('text-viewer', () => {
const forceToBottom = ref(true); const forceToBottom = ref(true);
const filterChanged = ref(false); const filterChanged = ref(false);
const textPrefixValue = ref("") const textPrefixValue = useStorage('sendFramePrefix', "");
const textSuffixValue = ref("\\r\\n") const textSuffixValue = useStorage('sendFrameSuffix', "\\r\\n");
const hasAddedText = computed(() => { const hasAddedText = computed(() => {
return textPrefixValue.value.length > 0 || textSuffixValue.value.length > 0; return textPrefixValue.value.length > 0 || textSuffixValue.value.length > 0;
}); });
@ -504,7 +529,7 @@ export const useDataViewerStore = defineStore('text-viewer', () => {
stop_bits: 1, stop_bits: 1,
}); });
const filterValue = ref(""); const filterValue = useStorage('frameFilterValue', '');
const computedFilterValue = computed(() => { const computedFilterValue = computed(() => {
return unescapeString(filterValue.value); return unescapeString(filterValue.value);
}) })
@ -522,7 +547,7 @@ export const useDataViewerStore = defineStore('text-viewer', () => {
/* actual data shown on screen */ /* actual data shown on screen */
const dataFiltered: ShallowReactive<IDataBuf[]> = shallowReactive([]); const dataFiltered: ShallowReactive<IDataBuf[]> = shallowReactive([]);
const dataFilterAutoUpdate = ref(true); const dataFilterAutoUpdate = useStorage("autoUpdate", true);
const acceptIncomingData = ref(false); const acceptIncomingData = ref(false);
// let frameBreakReady = false; // let frameBreakReady = false;
@ -534,7 +559,7 @@ export const useDataViewerStore = defineStore('text-viewer', () => {
}, {debounce: 300}); }, {debounce: 300});
let batchDataUpdateIntervalID: number = -1; let batchDataUpdateIntervalID: number = -1;
const batchUpdateTime = ref(80); /* ms */ const batchUpdateTime = useStorage('updateInterval', 80); /* ms */
let batchStartIndex: number = 0; let batchStartIndex: number = 0;
watch(batchUpdateTime, () => { watch(batchUpdateTime, () => {
@ -755,10 +780,10 @@ export const useDataViewerStore = defineStore('text-viewer', () => {
const enableLoopSend = ref(false); const enableLoopSend = ref(false);
const loopSendFreq = ref(1000); const loopSendFreq = useStorage('loopSendInterval', 1000);
let loopSendIntervalID: number = -1; let loopSendIntervalID: number = -1;
const uartInputTextBox = ref(""); const uartInputTextBox = useStorage('sendBox', "");
const isSendTextFormat = ref(true); const isSendTextFormat = useStorage('sendBoxIsText', true);
const isHexStringValid = ref(false); const isHexStringValid = ref(false);
function loopSend() { function loopSend() {

View File

@ -1,29 +1,33 @@
<template> <template>
<div class="flex items-center mb-2"> <div class="flex items-center mb-2">
<el-button class="mr-2" type="primary" @click="() => { <el-button class="mr-2" type="primary" @click="() => {
<div class="flex items-center mb-2 flex-wrap gap-2">
<el-button type="primary" @click="() => {
macroData.push({ macroData.push({
input: '', value: '',
btn_label: '发送', label: '发送',
id: macroId, id: macroId,
}) })
macroId++; macroId++;
}">添加 }">添加
</el-button> </el-button>
<el-checkbox v-model="editMode" class="mr-2" border>编辑</el-checkbox> <el-checkbox v-model="editMode" border>编辑</el-checkbox>
<el-checkbox v-model="draggableEnabled" class="mr-2" border>拖拽</el-checkbox> <el-checkbox v-model="draggableEnabled" border>拖拽</el-checkbox>
</div> </div>
<el-alert>IP地址改变会导致配置丢失</el-alert>
<VueDraggable v-model="macroData" handle=".sort-target" <VueDraggable v-model="macroData" handle=".sort-target"
:animation="150" class="break-input"> :animation="150" class="break-input">
<div v-for="(item, index) in macroData" :key="item.id" class="w-full text-xs flex items-center py-0.5" <div v-for="(item, index) in macroData" :key="item.id" class="w-full text-xs flex items-center py-0.5"
:class="editMode ? 'macroBtnList' : ''"> :class="editMode ? 'macroButtons' : ''">
<el-tag size="large" type="success" v-if="draggableEnabled" class="sort-target mr-1"> <el-tag size="large" type="success" v-if="draggableEnabled" class="sort-target mr-1">
= =
</el-tag> </el-tag>
<el-input v-model="item.input" class="font-mono"> <el-input v-model="item.value" class="font-mono">
<template #append> <template #append>
<el-input v-if="editMode" v-model="item.btn_label"></el-input> <el-input v-if="editMode" v-model="item.label"></el-input>
<el-button v-else @click="onSendClick(item.input)" type="primary">{{ item.btn_label }}</el-button> <el-button v-else @click="onSendClick(item.value)" type="primary">{{ item.label }}</el-button>
</template> </template>
</el-input> </el-input>
<el-link :underline="false" @click="macroData.splice(index, 1);"> <el-link :underline="false" @click="macroData.splice(index, 1);">
@ -38,61 +42,62 @@
<script setup lang="ts"> <script setup lang="ts">
import {VueDraggable} from "vue-draggable-plus"; import {VueDraggable} from "vue-draggable-plus";
import {type Ref, ref} from "vue"; import {type Ref, ref} from "vue";
import {globalNotify} from "@/composables/notification"; import {globalNotify, globalNotifyRightSide} from "@/composables/notification";
import {useDataViewerStore} from "@/stores/dataViewerStore"; import {useDataViewerStore} from "@/stores/dataViewerStore";
import {useStorage} from '@vueuse/core';
const editMode = ref(false); const editMode = ref(false);
const draggableEnabled = ref(true); const draggableEnabled = ref(true);
const store = useDataViewerStore(); const store = useDataViewerStore();
interface macroItem { interface macroItem {
input: string; value: string;
btn_label: string; label: string;
id: number; id: number;
} }
let macroId = 3; const macroDataDefault: Ref<macroItem[]> = ref([
const macroData: Ref<macroItem[]> = ref([
{ {
input: 'AT', value: 'AT',
btn_label: '测试AT', label: '测试AT',
id: 1, id: 1,
},{ },{
input: 'AT+CSQ', value: 'AT+CSQ',
btn_label: '询信号强度', label: '询信号强度',
id: 2, id: 2,
},{ },{
input: 'AT+CGSN', value: 'AT+CGSN',
btn_label: '询序列号', label: '询序列号',
id: 3, id: 3,
}, { }, {
input: 'AT+CGMR', value: 'AT+CGMR',
btn_label: '询固件版本', label: '询固件版本',
id: 4, id: 4,
}, { }, {
input: 'AT+CMEE', value: 'AT+CMEE',
btn_label: '询终端报错', label: '询终端报错',
id: 5, id: 5,
}, { }, {
input: 'AT+NRB', value: 'AT+NRB',
btn_label: '重启', label: '重启',
id: 6, id: 6,
}, { }, {
input: 'AT+CGATT', value: 'AT+CGATT',
btn_label: '询网络激活状态', label: '询网络激活状态',
id: 7, id: 7,
}, { }, {
input: 'AT+CEREG', value: 'AT+CEREG',
btn_label: '询网络注册状态', label: '询网络注册状态',
id: 8, id: 8,
}, { }, {
input: 'AT+CSCON', value: 'AT+CSCON',
btn_label: '询网络连接状态', label: '询网络连接状态',
id: 9, id: 9,
} }
]); ]);
const macroData = useStorage('macroItems', macroDataDefault);
let macroId = macroData.value.reduce((max, item) => Math.max(max, item.id), 0) + 1;
function onSendClick(val: string) { function onSendClick(val: string) {
if (!val && !store.hasAddedText) { if (!val && !store.hasAddedText) {
@ -119,7 +124,7 @@ function onSendClick(val: string) {
cursor: move; cursor: move;
} }
.macroBtnList :deep(.el-input-group__append) { .macroButtons :deep(.el-input-group__append) {
padding: 0; padding: 0;
} }