Compare commits

...

3 commits

Author SHA1 Message Date
dcf7393393 update 2024-02-02 21:26:30 +08:00
51397e4c84 update 2024-02-02 21:25:48 +08:00
2ebf1860b1 wip 2024-02-02 17:35:25 +08:00
2 changed files with 287 additions and 166 deletions

View file

@ -1,6 +1,6 @@
<template> <template>
<a-layout-footer class="footer"> <a-layout-footer class="footer">
<a href="https://github.com/silenty4ng/k5web" target="_blank">K5Web - V0.1.202402021050</a> <a href="https://github.com/silenty4ng/k5web" target="_blank">K5Web - V0.1.202402022130</a>
</a-layout-footer> </a-layout-footer>
</template> </template>

View file

@ -30,123 +30,56 @@
</a-space> </a-space>
</a-col> </a-col>
</a-row> </a-row>
<a-table <t-table
:loading="loading" :loading="loading"
size="large"
:columns="columns" :columns="columns"
:data="cstate.renderData" :data="cstate.renderData"
style="margin-top: 20px"
:pagination="{ :pagination="{
pageSize: cstate.pageSize, defaultPageSize: cstate.pageSize,
current: cstate.nowPage, total: cstate.renderData.length,
showPageSize: true, defaultCurrent: 1,
pageSizeOptions: [15, 30, 50] pageSizeOptions: [15, 30, 50, 100, 200]
}" }"
@page-change="(e)=>{cstate.nowPage = e;}" @change="(e: any)=>{cstate.pageSize = e.pagination.pageSize, cstate.nowPage = e.pagination.current}"
@page-size-change="(e)=>{cstate.pageSize = e;}" bordered
lazy-load
> >
<template #index="{ record, rowIndex }"> <template #index="{ row, rowIndex }">
{{ (cstate.nowPage - 1) * cstate.pageSize + rowIndex + 1 }} {{ (cstate.nowPage - 1) * cstate.pageSize + rowIndex + 1 }}
</template> </template>
<template #name="{ record, rowIndex }"> <template #reverse="{ row, rowIndex }">
<a-input v-model="record.name" /> <t-switch v-model="row.reverse" />
</template> </template>
<template #bandwidth="{ record, rowIndex }"> <template #busy="{ row, rowIndex }">
<a-select v-model="record.bandwidth" allow-clear> <t-switch v-model="row.busy" />
<a-option v-for="value of Object.keys(state.bandwidthOption)" :value="value">{{state.bandwidthOption[value]}}</a-option>
</a-select>
</template> </template>
<template #tx="{ record, rowIndex }"> <template #dtmf="{ row, rowIndex }">
<a-input-number v-model="record.tx" :precision="5" /> <t-switch v-model="row.dtmf" />
</template> </template>
<template #rx="{ record, rowIndex }"> <template #scanlist="{ row, rowIndex }">
<a-input-number v-model="record.rx" :precision="5" /> <t-checkbox-group v-model="row.scanlist">
<t-checkbox key="I" label="I" value="I" />
<t-checkbox key="II" label="II" value="II" />
</t-checkbox-group>
</template> </template>
<template #power="{ record, rowIndex }"> <template #operate="{ row, rowIndex }">
<a-select v-model="record.power" allow-clear> <t-button theme="default" variant="dashed" @click="clearRow((cstate.nowPage - 1) * cstate.pageSize + rowIndex)">清空</t-button>
<a-option v-for="value of Object.keys(state.powerOption)" :value="value">{{state.powerOption[value]}}</a-option>
</a-select>
</template> </template>
<template #rxTone="{ record, rowIndex }"> </t-table>
<a-select v-model="record.rxTone" allow-clear>
<a-option v-for="value of Object.keys(state.toneOption)" :value="value">{{state.toneOption[value]}}</a-option>
</a-select>
</template>
<template #rxCTCSS="{ record, rowIndex }">
<a-select v-model="record.rxCTCSS" allow-clear>
<a-option v-for="value of state.CTCSSOption" :value="value">{{value.toFixed(1)}}</a-option>
</a-select>
</template>
<template #rxDCS="{ record, rowIndex }">
<a-select v-model="record.rxDCS" allow-clear>
<a-option v-for="value of state.DCSOption" :value="value">{{"0" + value}}</a-option>
</a-select>
</template>
<template #txTone="{ record, rowIndex }">
<a-select v-model="record.txTone" allow-clear>
<a-option v-for="value of Object.keys(state.toneOption)" :value="value">{{state.toneOption[value]}}</a-option>
</a-select>
</template>
<template #txCTCSS="{ record, rowIndex }">
<a-select v-model="record.txCTCSS" allow-clear>
<a-option v-for="value of state.CTCSSOption" :value="value">{{value.toFixed(1)}}</a-option>
</a-select>
</template>
<template #txDCS="{ record, rowIndex }">
<a-select v-model="record.txDCS" allow-clear>
<a-option v-for="value of state.DCSOption" :value="value">{{"0" + value}}</a-option>
</a-select>
</template>
<template #step="{ record, rowIndex }">
<a-select v-model="record.step" allow-clear>
<a-option v-for="value of state.stepOption" :value="value">{{value.toFixed(1)}}</a-option>
</a-select>
</template>
<template #reverse="{ record, rowIndex }">
<a-switch v-model="record.reverse" />
</template>
<template #scramb="{ record, rowIndex }">
<a-select v-model="record.scramb" allow-clear>
<a-option v-for="value of state.scrambOption">{{value}}</a-option>
</a-select>
</template>
<template #busy="{ record, rowIndex }">
<a-switch v-model="record.busy" />
</template>
<template #pttid="{ record, rowIndex }">
<a-select v-model="record.pttid" allow-clear>
<a-option v-for="value of state.pttidOption">{{value}}</a-option>
</a-select>
</template>
<template #mode="{ record, rowIndex }">
<a-select v-model="record.mode" allow-clear>
<a-option v-for="value of Object.keys(state.modeOption)" :value="value">{{state.modeOption[value]}}</a-option>
</a-select>
</template>
<template #dtmf="{ record, rowIndex }">
<a-switch v-model="record.dtmf" />
</template>
<template #scanlist="{ record, rowIndex }">
<a-checkbox-group v-model="record.scanlist">
<a-checkbox value="I">I</a-checkbox>
<a-checkbox value="II">II</a-checkbox>
</a-checkbox-group>
</template>
<template #operate="{ record, rowIndex }">
<a-button @click="clearRow((cstate.nowPage - 1) * cstate.pageSize + rowIndex)">清空</a-button>
</template>
</a-table>
</a-card> </a-card>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { reactive } from 'vue'; import { ref, computed, reactive } from 'vue';
import { Input, Select } from 'tdesign-vue-next';
import useLoading from '@/hooks/loading'; import useLoading from '@/hooks/loading';
import { eeprom_read, uint8ArrayToHexReverseString, uint8ArrayToString, hexReverseStringToUint8Array, stringToUint8Array, eeprom_write, eeprom_reboot, eeprom_init } from '@/utils/serial.js'; import { eeprom_read, uint8ArrayToHexReverseString, uint8ArrayToString, hexReverseStringToUint8Array, stringToUint8Array, eeprom_write, eeprom_reboot, eeprom_init } from '@/utils/serial.js';
import { useAppStore } from '@/store'; import { useAppStore } from '@/store';
const appStore = useAppStore(); const appStore = useAppStore();
const { loading, setLoading } = useLoading(true); const { loading, setLoading } = useLoading(false);
const state = { const state = {
bandwidthOption: {'0': '25KHz', '1': '12.5KHz'}, bandwidthOption: {'0': '25KHz', '1': '12.5KHz'},
modeOption: {'0': 'FM', '1': 'AM', '2': 'USB'}, modeOption: {'0': 'FM', '1': 'AM', '2': 'USB'},
@ -179,144 +112,330 @@
pageSize: number, pageSize: number,
nowPage: number nowPage: number
} = reactive({ } = reactive({
renderData: [], renderData: Array.from({length: 200}).map(e=>{return {}}),
pageSize: 15, pageSize: 15,
nowPage: 1, nowPage: 1,
}) })
setTimeout(() => { const columns = computed(() => [
cstate.renderData = Array.from({length: 200}).map(e=>{return {}});
setLoading(false)
}, 1);
const columns = [
{ {
title: '#', title: '#',
dataIndex: 'index', colKey: 'index',
slotName: 'index', align: 'left',
width: 70 width: 100
}, },
{ {
title: '信道名称', title: '信道名称',
dataIndex: 'name', colKey: 'name',
slotName: 'name', width: 150,
width: 200 align: 'left',
edit: {
component: Input,
props: {
clearable: true
},
onEdited: (context: any) => {
const newData = [...cstate.renderData];
newData.splice(context.rowIndex, 1, context.newRowData);
cstate.renderData = newData;
},
},
}, },
{ {
title: '带宽', title: '带宽',
dataIndex: 'bandwidth', colKey: 'bandwidth',
slotName: 'bandwidth', align: 'left',
width: 150 width: 150,
cell: (h, { row }) => state.bandwidthOption[row.bandwidth] ?? "",
edit: {
component: Select,
props: {
clearable: true,
options: Object.keys(state.bandwidthOption).map(e=>{return {value: e, label: state.bandwidthOption[e]}}),
},
onEdited: (context: any) => {
const newData = [...cstate.renderData];
newData.splice(context.rowIndex, 1, context.newRowData);
cstate.renderData = newData;
}
},
}, },
{ {
title: '接收频率', title: '接收频率',
dataIndex: 'rx', colKey: 'rx',
slotName: 'rx', align: 'left',
width: 150 width: 200,
cell: (h, { row }) => parseFloat(row.rx) ? parseFloat(row.rx).toFixed(5) : undefined,
edit: {
component: Input,
props: {
clearable: true
},
onEdited: (context: any) => {
context.newRowData.rx = context.newRowData.rx ? context.newRowData.rx : undefined
const newData = [...cstate.renderData];
newData.splice(context.rowIndex, 1, context.newRowData);
cstate.renderData = newData;
},
},
}, },
{ {
title: '发送频率', title: '发送频率',
dataIndex: 'tx', colKey: 'tx',
slotName: 'tx', align: 'left',
width: 150 width: 200,
cell: (h, { row }) => parseFloat(row.tx) ? parseFloat(row.tx).toFixed(5) : undefined,
edit: {
component: Input,
props: {
clearable: true
},
onEdited: (context: any) => {
context.newRowData.tx = context.newRowData.tx ? context.newRowData.tx : undefined
const newData = [...cstate.renderData];
newData.splice(context.rowIndex, 1, context.newRowData);
cstate.renderData = newData;
},
},
}, },
{ {
title: '发送功率', title: '发送功率',
dataIndex: 'power', colKey: 'power',
slotName: 'power', align: 'left',
width: 150 width: 150,
cell: (h, { row }) => state.powerOption[row.power] ?? "",
edit: {
component: Select,
props: {
clearable: true,
options: Object.keys(state.powerOption).map(e=>{return {value: e, label: state.powerOption[e]}}),
},
onEdited: (context: any) => {
const newData = [...cstate.renderData];
newData.splice(context.rowIndex, 1, context.newRowData);
cstate.renderData = newData;
}
},
}, },
{ {
title: '接收亚音类型', title: '接收亚音类型',
dataIndex: 'rxTone', colKey: 'rxTone',
slotName: 'rxTone', align: 'left',
width: 150 width: 180,
cell: (h, { row }) => state.toneOption[row.rxTone] ?? "",
edit: {
component: Select,
props: {
clearable: true,
options: Object.keys(state.toneOption).map(e=>{return {value: e, label: state.toneOption[e]}}),
},
onEdited: (context: any) => {
const newData = [...cstate.renderData];
newData.splice(context.rowIndex, 1, context.newRowData);
cstate.renderData = newData;
}
},
}, },
{ {
title: '接收亚音频Hz', title: '接收亚音频Hz',
dataIndex: 'rxCTCSS', colKey: 'rxCTCSS',
slotName: 'rxCTCSS', align: 'left',
width: 150 width: 150,
cell: (h, { row }) => state.CTCSSOption.indexOf(row.rxCTCSS) >= 0 ? row.rxCTCSS?.toFixed(1) : undefined,
edit: {
component: Select,
props: {
clearable: true,
options: state.CTCSSOption.map(e=>{return {value: e, label: e.toFixed(1)}}),
},
onEdited: (context: any) => {
const newData = [...cstate.renderData];
newData.splice(context.rowIndex, 1, context.newRowData);
cstate.renderData = newData;
}
},
}, },
{ {
title: '接收亚音数码', title: '接收亚音数码',
dataIndex: 'rxDCS', colKey: 'rxDCS',
slotName: 'rxDCS', align: 'left',
width: 150 width: 150,
cell: (h, { row }) => state.DCSOption.indexOf(row.rxDCS) >= 0 ? "0" + row.rxDCS : undefined,
edit: {
component: Select,
props: {
clearable: true,
options: state.DCSOption.map(e=>{return {value: e, label: "0" + e}}),
},
onEdited: (context: any) => {
const newData = [...cstate.renderData];
newData.splice(context.rowIndex, 1, context.newRowData);
cstate.renderData = newData;
}
},
}, },
{ {
title: '发送亚音类型', title: '发送亚音类型',
dataIndex: 'txTone', colKey: 'txTone',
slotName: 'txTone', align: 'left',
width: 150 width: 180,
cell: (h, { row }) => state.toneOption[row.txTone] ?? "",
edit: {
component: Select,
props: {
clearable: true,
options: Object.keys(state.toneOption).map(e=>{return {value: e, label: state.toneOption[e]}}),
},
onEdited: (context: any) => {
const newData = [...cstate.renderData];
newData.splice(context.rowIndex, 1, context.newRowData);
cstate.renderData = newData;
}
},
}, },
{ {
title: '发送亚音频Hz', title: '发送亚音频Hz',
dataIndex: 'txCTCSS', colKey: 'txCTCSS',
slotName: 'txCTCSS', align: 'left',
width: 150 width: 150,
cell: (h, { row }) => state.CTCSSOption.indexOf(row.txCTCSS) >= 0 ? row.txCTCSS?.toFixed(1) : undefined,
edit: {
component: Select,
props: {
clearable: true,
options: state.CTCSSOption.map(e=>{return {value: e, label: e.toFixed(1)}}),
},
onEdited: (context: any) => {
const newData = [...cstate.renderData];
newData.splice(context.rowIndex, 1, context.newRowData);
cstate.renderData = newData;
}
},
}, },
{ {
title: '发送亚音数码', title: '发送亚音数码',
dataIndex: 'txDCS', colKey: 'txDCS',
slotName: 'txDCS', align: 'left',
width: 150 width: 150,
cell: (h, { row }) => state.DCSOption.indexOf(row.txDCS) >= 0 ? "0" + row.txDCS : undefined,
edit: {
component: Select,
props: {
clearable: true,
options: state.DCSOption.map(e=>{return {value: e, label: "0" + e}}),
},
onEdited: (context: any) => {
const newData = [...cstate.renderData];
newData.splice(context.rowIndex, 1, context.newRowData);
cstate.renderData = newData;
}
},
}, },
{ {
title: '频率步进', title: '频率步进',
dataIndex: 'step', colKey: 'step',
slotName: 'step', align: 'left',
width: 150 width: 150,
cell: (h, { row }) => state.stepOption.indexOf(row.step) >= 0 ? row.step?.toFixed(1) : undefined,
edit: {
component: Select,
props: {
clearable: true,
options: state.stepOption.map(e=>{return {value: e, label: e.toFixed(1)}}),
},
onEdited: (context: any) => {
const newData = [...cstate.renderData];
newData.splice(context.rowIndex, 1, context.newRowData);
cstate.renderData = newData;
}
},
}, },
{ {
title: '倒频', title: '倒频',
dataIndex: 'reverse', colKey: 'reverse',
slotName: 'reverse', align: 'left',
width: 150 width: 150
}, },
{ {
title: '加密', title: '加密',
dataIndex: 'scramb', colKey: 'scramb',
slotName: 'scramb', align: 'left',
width: 150 width: 150,
edit: {
component: Select,
props: {
clearable: true,
options: state.scrambOption.map(e=>{return {value: e, label: e}}),
},
onEdited: (context: any) => {
const newData = [...cstate.renderData];
newData.splice(context.rowIndex, 1, context.newRowData);
cstate.renderData = newData;
}
},
}, },
{ {
title: '繁忙禁发', title: '繁忙禁发',
dataIndex: 'busy', colKey: 'busy',
slotName: 'busy', align: 'left',
width: 150 width: 150
}, },
{ {
title: '信令码', title: '信令码',
dataIndex: 'pttid', colKey: 'pttid',
slotName: 'pttid', align: 'left',
width: 150 width: 150,
edit: {
component: Select,
props: {
clearable: true,
options: state.pttidOption.map(e=>{return {value: e, label: e}}),
},
onEdited: (context: any) => {
const newData = [...cstate.renderData];
newData.splice(context.rowIndex, 1, context.newRowData);
cstate.renderData = newData;
}
},
}, },
{ {
title: '信道模式', title: '信道模式',
dataIndex: 'mode', colKey: 'mode',
slotName: 'mode', align: 'left',
width: 150 width: 150,
cell: (h, { row }) => state.modeOption[row.mode] ?? "",
edit: {
component: Select,
props: {
clearable: true,
options: Object.keys(state.modeOption).map(e=>{return {value: e, label: state.modeOption[e]}}),
},
onEdited: (context: any) => {
const newData = [...cstate.renderData];
newData.splice(context.rowIndex, 1, context.newRowData);
cstate.renderData = newData;
}
},
}, },
{ {
title: 'DTMF解码', title: 'DTMF解码',
dataIndex: 'dtmf', colKey: 'dtmf',
slotName: 'dtmf', align: 'left',
width: 150 width: 150
}, },
{ {
title: '扫描列表', title: '扫描列表',
dataIndex: 'scanlist', colKey: 'scanlist',
slotName: 'scanlist', align: 'left',
width: 150 width: 150
}, },
{ {
title: '操作', title: '操作',
dataIndex: 'operate', colKey: 'operate',
slotName: 'operate', align: 'left',
width: 150 width: 150
} }
]; ]);
const readChannel = async() => { const readChannel = async() => {
if(appStore.connectState != true){alert('请先连接手台!'); return;}; if(appStore.connectState != true){alert('请先连接手台!'); return;};
@ -463,14 +582,14 @@
if(_channel.scanlist?.indexOf('I') >= 0) scanlist += 8; if(_channel.scanlist?.indexOf('I') >= 0) scanlist += 8;
if(_channel.scanlist?.indexOf('II') >= 0) scanlist += 4; if(_channel.scanlist?.indexOf('II') >= 0) scanlist += 4;
console.log((scanlist << 4) + 0) console.log((scanlist << 4) + 0)
rawEEPROM2.set([(scanlist << 4) + 0], i >> 4) rawEEPROM2.set([(scanlist << 4) + 0], i / 0x10)
const mergedArray = new Uint8Array(0x10); const mergedArray = new Uint8Array(0x10);
mergedArray.set(stringToUint8Array(_channel.name ?? "", appStore.configuration?.charset).subarray(0, 0x10), 0); mergedArray.set(stringToUint8Array(_channel.name ?? "", appStore.configuration?.charset).subarray(0, 0x10), 0);
rawEEPROM3.set(mergedArray, i) rawEEPROM3.set(mergedArray, i)
}else{ }else{
rawEEPROM.set(hexReverseStringToUint8Array("ffffffffffffffffffffffffffffffff"), i) rawEEPROM.set(hexReverseStringToUint8Array("ffffffffffffffffffffffffffffffff"), i)
rawEEPROM2.set([0xFF], i >> 4) rawEEPROM2.set([0xFF], i / 0x10)
rawEEPROM3.set(hexReverseStringToUint8Array("ffffffffffffffffffffffffffffffff"), i) rawEEPROM3.set(hexReverseStringToUint8Array("ffffffffffffffffffffffffffffffff"), i)
} }
i += 0x10 i += 0x10
@ -486,7 +605,9 @@
setLoading(false) setLoading(false)
} }
const clearRow = async (row: any) =>{ const clearRow = async (row: any) =>{
cstate.renderData[row] = {} const newData = [...cstate.renderData];
newData.splice(row, 1, {});
cstate.renderData = newData;
} }
const saveChannel = () => { const saveChannel = () => {
const _data = JSON.stringify(cstate.renderData); const _data = JSON.stringify(cstate.renderData);