1
0
Fork 0
mirror of https://github.com/silenty4ng/k5web synced 2025-04-13 14:30:33 +00:00
This commit is contained in:
Silent YANG 2024-05-13 00:15:03 +08:00
parent 3b97001dd8
commit 37a6ee5953
16 changed files with 338 additions and 156 deletions
src
App.vue
components/navbar
locale
router/routes/modules
views
dashboard/workplace
list

View file

@ -1,29 +1,18 @@
<template>
<a-config-provider :locale="locale">
<router-view />
<global-setting />
</a-config-provider>
<!-- <t-sticky-tool
:style="{ overflow: 'hidden' }"
:offset="[-20, 140]"
>
<t-sticky-item label="问题反馈" :popup="renderQa" :popup-props="{ overlayInnerStyle: { margin: '10px', height: '450px' } }">
<template #icon><chat-icon /></template>
</t-sticky-item>
<t-sticky-item label="扫码红包" :popup="renderPopup" :popup-props="{ overlayInnerStyle: { margin: '10px', height: '450px' } }">
<template #icon><qrcode-icon /></template>
</t-sticky-item>
<t-sticky-item label="打赏" :popup="renderShang" :popup-props="{ overlayInnerStyle: { margin: '10px', height: '450px' } }">
<template #icon><fish-icon /></template>
</t-sticky-item>
</t-sticky-tool> -->
<t-config-provider v-if="reloadLang" :global-config="locale">
<a-config-provider :locale="locale">
<router-view />
<global-setting />
</a-config-provider>
</t-config-provider>
</template>
<script lang="ts" setup>
import { ChatIcon, QrcodeIcon, FishIcon } from 'tdesign-icons-vue-next';
import { computed, h } from 'vue';
import { computed, h, ref } from 'vue';
import zhCN from '@arco-design/web-vue/es/locale/lang/zh-cn';
import tdesignZhCN from 'tdesign-vue-next/esm/locale/zh_CN';
import enUS from '@arco-design/web-vue/es/locale/lang/en-us';
import tdesignEnUS from 'tdesign-vue-next/esm/locale/en_US';
import GlobalSetting from '@/components/global-setting/index.vue';
import useLocale from '@/hooks/locale';
import Aegis from 'aegis-web-sdk';
@ -62,12 +51,26 @@
}
const { currentLocale } = useLocale();
const reloadLang = ref(true);
const locale = computed(() => {
let lang = undefined;
reloadLang.value = false;
switch (currentLocale.value) {
case 'zh-CN':
return zhCN;
sessionStorage.setItem('noticeConnectK5', '请先连接手台!')
sessionStorage.setItem('noticeVersionNoSupport', '固件版本不匹配')
lang = {...zhCN, ...tdesignZhCN};
break;
default:
return enUS;
sessionStorage.setItem('noticeConnectK5', 'Connect first!')
sessionStorage.setItem('noticeVersionNoSupport', 'Firmware not supported')
lang = {...enUS, ...tdesignEnUS};
}
setTimeout(() => {
reloadLang.value = true;
}, 1000);
return lang;
});
</script>

View file

@ -110,6 +110,8 @@
import useUser from '@/hooks/user';
import Menu from '@/components/menu/index.vue';
import { connect, disconnect, eeprom_init } from '@/utils/serial.js';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const drivers = import.meta.glob('@/drivers/*.json', { eager: true });
const appStore = useAppStore();
@ -194,7 +196,7 @@
}
if(!_connect){
alert('连接失败');
alert(t('global.connectFail'));
return;
}
appStore.updateSettings({ connectPort: _connect });

View file

@ -50,6 +50,92 @@ export default {
'navbar.connect': 'Connect',
'navbar.disconnect': 'Disconnect',
'navbar.qa': 'Feedback',
'global.8kb': '8KB (64Kbit)',
'global.128kb': '128KB (1Mbit)',
'global.256kb': '256KB (2Mbit)',
'global.512kb': '512KB (4Mbit)',
'menu.rb': 'Backup/Restore',
'menu.flash': 'Flasher',
'menu.image': 'Startup Image',
'menu.font': 'Chinese',
'menu.satellite': 'Doppler',
'global.onStart': ' (Put the UV-K5 into normral mode)',
'global.onBoot': ' (Put the UV-K5 into programming mode)',
'cps.onDeviceRead': 'Read from device',
'cps.onDeviceWrite': 'Write to device',
'cps.downloadImportTemplate': 'Download Import Templates',
'cps.import': 'Import',
'cps.export': 'Export',
'cps.save': 'Save',
'cps.load': 'Load',
'cps.line1': 'First line of text on startup screen',
'cps.line2': 'Second line of text on startup screen',
'cps.mdclocplay': 'Local MDC Play (Only support my firmware)',
'cps.sort': 'Sort',
'cps.name': 'Name',
'cps.bandwidth': 'Bandwidth',
'cps.tx': 'TX Frequency',
'cps.rx': 'RX Frequency',
'cps.power': 'Power',
'cps.rxToneType': 'RX Tone Type',
'cps.rxToneCTCSS': 'RX CTCSSHz',
'cps.rxToneDCS': 'RX DCS',
'cps.txToneType': 'TX Tone Type',
'cps.txToneCTCSS': 'TX CTCSSHz',
'cps.txToneDCS': 'TX DCS',
'cps.step': 'Frequency Step',
'cps.reverse': 'Reverse',
'cps.scramb': 'Scramb',
'cps.busy': 'Busy',
'cps.pttid': 'PTTID',
'cps.mode': 'Mode',
'cps.dtmf': 'DTMF Decode',
'cps.scanlist': 'Scanlist',
'cps.operate': 'Operate',
'cps.clear': 'Clear',
'tool.quickbackup': 'Quick Backup',
'tool.fullbackup': 'Full Backup',
'tool.cleardata': 'Clear EEPROM',
'tool.backupConfig': 'Backup Config',
'tool.restoreConfig': 'Restore Config',
'tool.backupCalibration': 'Backup Calibration',
'tool.restoreCalibration': 'Restore Calibration',
'tool.backup': 'Backup',
'tool.restore': 'Restore',
'tool.autocheck': 'AUTO',
'tool.selectSize': 'Select EEPROM size',
'tool.first': 'Warning ',
'tool.firstTitle': '',
'tool.last': 'LAST WARNING',
'tool.clearMessage': 'This will clear the EEPROM of all contents, including configuration and calibration data!!!!',
'tool.selectFirmware': 'Select Firmware',
'tool.flash': 'FLASH',
'tool.selectImage': 'Select Image',
'tool.write': 'Write',
'tool.fontwrite': 'LOSEHU Firmware Character Set Write',
'tool.pinyinwrite': 'LOSEHU H Firmware Pinyin Set Write',
'tool.writefontwrite': 'Character Set Write',
'tool.writepinyin': 'Pinyin Set Write',
'tool.brtime': 'Browser Time',
'tool.selectSatellite': 'Select satellite',
'tool.longitude': 'Longitude',
'tool.latitude': 'Latitude',
'tool.altitude': 'Altitude',
'tool.brlonlat': 'Get browser location',
'tool.phonelonlat': 'Get phone location',
'tool.satpasstime': 'Get satellite pass time',
'tool.selectPassTime': 'Select pass time',
'tool.txFreq': 'TX Frequency',
'tool.txTone': 'TX Tone',
'tool.rxFreq': 'RX Frequency',
'tool.rxTone': 'RX Tone',
'tool.writeData': 'Write Doppler',
'tool.off': 'Off',
'tool.scanqr': 'Scan QR Code',
'tool.scannotice': 'Uploaded location information will be cached by the server for 10 minutes',
'tool.scaned': 'Scanned and uploaded',
'global.nosupport': 'Current browser does not support WebSerial function, please use Chrome, Edge, Opera browser.',
'global.connectFail': 'Connect Fail',
...localeSettings,
...localeMessageBox,
...localeLogin,

View file

@ -50,6 +50,92 @@ export default {
'navbar.connect': '连接',
'navbar.disconnect': '断开',
'navbar.qa': '问题反馈',
'global.8kb': '8KB64Kbit',
'global.128kb': '128KB1Mbit',
'global.256kb': '256KB2Mbit',
'global.512kb': '512KB4Mbit',
'menu.rb': '备份/还原',
'menu.flash': '固件升级',
'menu.image': '开机图片',
'menu.font': '字库写入',
'menu.satellite': '多普勒写入',
'global.onStart': '(手台应在开机状态下)',
'global.onBoot': '(手台应在刷机模式下)',
'cps.onDeviceRead': '从设备读取',
'cps.onDeviceWrite': '写入设备',
'cps.downloadImportTemplate': '下载导入模板',
'cps.import': '导入',
'cps.export': '导出',
'cps.save': '保存',
'cps.load': '加载',
'cps.line1': '启动画面首行文字',
'cps.line2': '启动画面次行文字',
'cps.mdclocplay': '本地播放首尾音仅117P6',
'cps.sort': '排序',
'cps.name': '信道名称',
'cps.bandwidth': '带宽',
'cps.tx': '发送频率',
'cps.rx': '接收频率',
'cps.power': '发送功率',
'cps.rxToneType': '接收亚音类型',
'cps.rxToneCTCSS': '接收亚音频Hz',
'cps.rxToneDCS': '接收亚音数码',
'cps.txToneType': '发送亚音类型',
'cps.txToneCTCSS': '发送亚音频Hz',
'cps.txToneDCS': '发送亚音数码',
'cps.step': '频率步进',
'cps.reverse': '倒频',
'cps.scramb': '加密',
'cps.busy': '繁忙禁发',
'cps.pttid': '信令码',
'cps.mode': '信道模式',
'cps.dtmf': 'DTMF解码',
'cps.scanlist': '扫描列表',
'cps.operate': '操作',
'cps.clear': '清空',
'tool.quickbackup': '快捷备份',
'tool.fullbackup': '完整备份',
'tool.cleardata': '清空数据',
'tool.backupConfig': '备份配置',
'tool.restoreConfig': '恢复配置',
'tool.backupCalibration': '备份校准',
'tool.restoreCalibration': '恢复校准',
'tool.backup': '备份',
'tool.restore': '恢复',
'tool.autocheck': '自动检测',
'tool.selectSize': '选择 EEPROM 大小',
'tool.first': '第 ',
'tool.firstTitle': ' 次警告',
'tool.last': '(最后警告)',
'tool.clearMessage': '这将会清空 EEPROM 所有内容,包括配置及校准数据!!!',
'tool.selectFirmware': '选择固件',
'tool.flash': '更新',
'tool.selectImage': '选择图片',
'tool.write': '写入',
'tool.fontwrite': 'LOSEHU 固件字库写入',
'tool.pinyinwrite': 'LOSEHU H 版固件拼音索引表',
'tool.writefontwrite': '自动写入字库',
'tool.writepinyin': '写入拼音检索表',
'tool.brtime': '浏览器时间',
'tool.selectSatellite': '选择卫星',
'tool.longitude': '经度',
'tool.latitude': '纬度',
'tool.altitude': '海拔',
'tool.brlonlat': '浏览器获取经纬度',
'tool.phonelonlat': '手机扫码获取经纬度',
'tool.satpasstime': '获取卫星过境时间',
'tool.selectPassTime': '选择过境时间',
'tool.txFreq': '上行频率',
'tool.txTone': '上行亚音',
'tool.rxFreq': '下行频率',
'tool.rxTone': '下行亚音',
'tool.writeData': '写入数据',
'tool.off': '关闭',
'tool.scanqr': '手机扫码获取经纬度',
'tool.scannotice': '上传经纬度信息将被服务器缓存十分钟',
'tool.scaned': '已扫码上传',
'global.nosupport': '当前浏览器不支持网页串口功能,请使用 Chrome, Edge, Opera 浏览器。',
'global.connectFail': '连接失败',
...localeSettings,
...localeMessageBox,
...localeLogin,

View file

@ -17,7 +17,7 @@ const LIST: AppRouteRecordRaw = {
name: 'Backup',
component: () => import('@/views/list/card/index.vue'),
meta: {
locale: '备份/还原',
locale: 'menu.rb',
requiresAuth: true,
roles: ['*'],
},
@ -27,7 +27,7 @@ const LIST: AppRouteRecordRaw = {
name: 'Flash',
component: () => import('@/views/list/flash/index.vue'),
meta: {
locale: '固件升级',
locale: 'menu.flash',
requiresAuth: true,
roles: ['*'],
},
@ -37,7 +37,7 @@ const LIST: AppRouteRecordRaw = {
name: 'Image',
component: () => import('@/views/list/image/index.vue'),
meta: {
locale: '开机图片',
locale: 'menu.image',
requiresAuth: true,
roles: ['*'],
},
@ -47,7 +47,7 @@ const LIST: AppRouteRecordRaw = {
name: 'Chi',
component: () => import('@/views/list/chi/index.vue'),
meta: {
locale: '字库写入',
locale: 'menu.font',
requiresAuth: true,
roles: ['*'],
},
@ -57,7 +57,7 @@ const LIST: AppRouteRecordRaw = {
name: 'Sat',
component: () => import('@/views/list/sat/index.vue'),
meta: {
locale: '星历写入',
locale: 'menu.satellite',
requiresAuth: true,
roles: ['*'],
},

View file

@ -33,7 +33,7 @@
})
const checkEeprom = async () => {
let eepromSize = '未知、故障、不可用';
let eepromSize = t('workplace.unk');
const random = [
Math.round(Math.random() * 256),
Math.round(Math.random() * 256),
@ -51,7 +51,7 @@
await eeprom_write(appStore.connectPort, 0, rawEEPROM, 0x08, appStore.configuration?.uart);
const check1 = await eeprom_read(appStore.connectPort, 0, 0x08, appStore.configuration?.uart);
if(rawEEPROM.toString() == check1.toString()){
eepromSize = '8KB64Kbit'
eepromSize = t('global.8kb')
}
await eeprom_write(appStore.connectPort, 0, bk1, 0x08, appStore.configuration?.uart);
}else{
@ -59,7 +59,7 @@
await eeprom_write(appStore.connectPort, 0, rawEEPROM, 0x08, appStore.configuration?.uart);
const check1 = await eeprom_read(appStore.connectPort, 0, 0x08, appStore.configuration?.uart);
if(rawEEPROM.toString() == check1.toString()){
eepromSize = '8KB64Kbit'
eepromSize = t('global.8kb')
}
await eeprom_write(appStore.connectPort, 0, bk1, 0x08, appStore.configuration?.uart);
@ -67,7 +67,7 @@
await eeprom_write(appStore.connectPort, 0x1FFF8, rawEEPROM, 0x08, appStore.configuration?.uart);
const check2 = await eeprom_read(appStore.connectPort, 0x1FFF8, 0x08, appStore.configuration?.uart);
if(rawEEPROM.toString() == check2.toString()){
eepromSize = '128KB1Mbit'
eepromSize = t('global.128kb')
}
await eeprom_write(appStore.connectPort, 0x1FFF8, bk2, 0x08, appStore.configuration?.uart);
@ -75,7 +75,7 @@
await eeprom_write(appStore.connectPort, 0x3FFF8, rawEEPROM, 0x08, appStore.configuration?.uart);
const check3 = await eeprom_read(appStore.connectPort, 0x3FFF8, 0x08, appStore.configuration?.uart);
if(rawEEPROM.toString() == check3.toString()){
eepromSize = '256KB2Mbit'
eepromSize = t('global.256kb')
}
await eeprom_write(appStore.connectPort, 0x3FFF8, bk3, 0x08, appStore.configuration?.uart);
@ -83,7 +83,7 @@
await eeprom_write(appStore.connectPort, 0x7FFF8, rawEEPROM, 0x08, appStore.configuration?.uart);
const check4 = await eeprom_read(appStore.connectPort, 0x7FFF8, 0x08, appStore.configuration?.uart);
if(rawEEPROM.toString() == check4.toString()){
eepromSize = '512KB4Mbit'
eepromSize = t('global.512kb')
}
await eeprom_write(appStore.connectPort, 0x7FFF8, bk4, 0x08, appStore.configuration?.uart);
}

View file

@ -8,6 +8,7 @@ export default {
'workplace.eepromSize': 'EEPROM Size: ',
'workplace.clickCheck': 'Click the TEST button to test',
'workplace.checkIt': 'TEST',
'workplace.unk': 'Unknown / Faulty / Unavailable',
'workplace.balance': 'Balance (CNY)',
'workplace.order.pending': 'Pending',
'workplace.order.pendingRenewal': 'Renewal Order',

View file

@ -8,6 +8,7 @@ export default {
'workplace.eepromSize': '存储大小:',
'workplace.clickCheck': '点击检测按钮检测',
'workplace.checkIt': '检测',
'workplace.unk': '未知、故障、不可用',
'workplace.balance': '余额(元)',
'workplace.order.pending': '待支付',
'workplace.order.pendingRenewal': '待续费订单',

View file

@ -1,38 +1,38 @@
<template>
<div class="container">
<Breadcrumb :items="['小工具', '备份/还原']" />
<Breadcrumb :items="[$t('menu.list'), $t('menu.rb')]" />
<a-row :gutter="20" align="stretch">
<a-col :span="24">
<a-card class="general-card">
<template #title>
<span @click="()=>{state.showHide += 1}">备份/还原手台应在开机状态下</span>
<span @click="()=>{state.showHide += 1}">{{ $t('menu.rb') + $t('global.onStart') }}</span>
</template>
<a-tabs default-active-key="1">
<a-tab-pane key="1" title="快捷备份">
<a-tab-pane key="1" :title="$t('tool.quickbackup')">
<a-space>
<a-button type="primary" @click="backupConfig">备份配置</a-button>
<a-button @click="restoreConfig">恢复配置</a-button>
<a-button type="primary" @click="backupCalibration">备份校准</a-button>
<a-button @click="restoreCalibration">恢复校准</a-button>
<a-button type="primary" @click="backupConfig">{{ $t('tool.backupConfig') }}</a-button>
<a-button @click="restoreConfig">{{ $t('tool.restoreConfig') }}</a-button>
<a-button type="primary" @click="backupCalibration">{{ $t('tool.backupCalibration') }}</a-button>
<a-button @click="restoreCalibration">{{ $t('tool.restoreCalibration') }}</a-button>
</a-space>
</a-tab-pane>
<a-tab-pane key="2" title="完整备份">
<a-tab-pane key="2" :title="$t('tool.fullbackup')">
<a-space>
<a-button type="primary" @click="backup">备份</a-button>
<a-button type="primary" @click="backup">{{ $t('tool.backup') }}</a-button>
<a-input v-show="state.showHide >= 5" v-model="state.startInfo" />
<a-button @click="restore">恢复</a-button>
<a-select v-model="state.eepromType" :style="{width:'320px'}" placeholder="选择EEPROM大小">
<a-option value="1">8KB64Kbit</a-option>
<a-option value="2">128KB1Mbit</a-option>
<a-option value="3">256KB2Mbit</a-option>
<a-option value="4">512KB4Mbit</a-option>
<a-button @click="restore">{{ $t('tool.restore') }}</a-button>
<a-select v-model="state.eepromType" :style="{width:'320px'}" :placeholder="$t('tool.selectSize')">
<a-option value="1">{{ $t('global.8kb') }}</a-option>
<a-option value="2">{{ $t('global.128kb') }}</a-option>
<a-option value="3">{{ $t('global.256kb') }}</a-option>
<a-option value="4">{{ $t('global.512kb') }}</a-option>
</a-select>
<a-button type="text" @click="checkEeprom">自动检测</a-button>
<a-button type="text" @click="checkEeprom">{{ $t('tool.autocheck') }}</a-button>
</a-space>
</a-tab-pane>
<a-tab-pane key="3" title="清空数据">
<a-tab-pane key="3" :title="$t('tool.cleardata')">
<a-space>
<a-button type="primary" @click="showClearDialog">清空数据</a-button>
<a-button type="primary" @click="showClearDialog">{{ $t('tool.cleardata') }}</a-button>
</a-space>
</a-tab-pane>
</a-tabs>
@ -44,8 +44,8 @@
<t-dialog
v-model:visible="state.showDialog"
theme="warning"
:header="state.dialogTitle >= 3 ? '第 ' + state.dialogTitle + ' 次警告(最后警告)' : '第 ' + state.dialogTitle + ' 次警告'"
body="这将会清空 EEPROM 所有内容,包括配置及校准数据!!!"
:header="state.dialogTitle >= 3 ? $t('tool.first') + state.dialogTitle + $t('tool.firstTitle') + $t('tool.last') : $t('tool.first') + state.dialogTitle + $t('tool.firstTitle')"
:body="$t('tool.clearMessage')"
@confirm="onClickConfirm"
/>
</div>
@ -82,7 +82,7 @@ const showClearDialog = () => {
}
const checkEeprom = async () => {
if(appStore.connectState != true){alert('请先连接手台!'); return;};
if(appStore.connectState != true){alert(sessionStorage.getItem('noticeConnectK5')); return;};
const eepromSize = await check_eeprom(appStore.connectPort, appStore.configuration?.uart);
switch(eepromSize){
case 0x2000:
@ -103,7 +103,7 @@ const checkEeprom = async () => {
}
const clearEEPROM = async () => {
if(appStore.connectState != true){alert('请先连接手台!'); return;};
if(appStore.connectState != true){alert(sessionStorage.getItem('noticeConnectK5')); return;};
const eepromSize = await check_eeprom(appStore.connectPort, appStore.configuration?.uart);
let rawEEPROM = new Uint8Array(0x80);
for (let i = 0; i < eepromSize; i += 0x80) {
@ -168,25 +168,25 @@ const restoreRange = async (start: any = 0) => {
}
const backupConfig = async() => {
if(appStore.connectState != true){alert('请先连接手台!'); return;};
if(appStore.connectState != true){alert(sessionStorage.getItem('noticeConnectK5')); return;};
await backupRange(0, 0x1E00, 'config.bin')
}
const backupCalibration = async() => {
if(appStore.connectState != true){alert('请先连接手台!'); return;};
if(appStore.connectState != true){alert(sessionStorage.getItem('noticeConnectK5')); return;};
await backupRange(0x1E00, 0x2000, 'calibration.bin')
}
const restoreConfig = async() =>{
if(appStore.connectState != true){alert('请先连接手台!'); return;};
if(appStore.connectState != true){alert(sessionStorage.getItem('noticeConnectK5')); return;};
await restoreRange()
}
const restoreCalibration = async() =>{
if(appStore.connectState != true){alert('请先连接手台!'); return;};
if(appStore.connectState != true){alert(sessionStorage.getItem('noticeConnectK5')); return;};
await restoreRange(0x1E00)
}
const backup = async() => {
if(appStore.connectState != true){alert('请先连接手台!'); return;};
if(appStore.connectState != true){alert(sessionStorage.getItem('noticeConnectK5')); return;};
let _max = 0x2000;
switch(state.eepromType){
case "1":
@ -212,7 +212,7 @@ const backup = async() => {
}
const restore = async() => {
if(appStore.connectState != true){alert('请先连接手台!'); return;};
if(appStore.connectState != true){alert(sessionStorage.getItem('noticeConnectK5')); return;};
await restoreRange(parseInt(state.startInfo))
}
</script>

View file

@ -1,25 +1,25 @@
<template>
<div class="container">
<Breadcrumb :items="['小工具', '字库写入']" />
<Breadcrumb :items="[$t('menu.list'), $t('menu.font')]" />
<a-row :gutter="20" align="stretch">
<a-col :span="24">
<a-card class="general-card">
<template #title>
<span @click="()=>{state.showHide += 1}">字库写入手台应在开机状态下</span>
<span @click="()=>{state.showHide += 1}">{{ $t('menu.font') + $t('global.onStart') }}</span>
</template>
<a-space>
<t-card bordered>
<template #header>
LOSEHU 固件字库写入
{{ $t('tool.fontwrite') }}
</template>
<a-button @click="restore(1)">自动写入字库</a-button>
<a-button @click="restore(1)">{{ $t('tool.writefontwrite') }}</a-button>
</t-card>
<t-card bordered>
<template #header>
LOSEHU H 版固件拼音索引表
{{ $t('tool.pinyinwrite') }}
</template>
<a-space>
<a-button @click="restore(4)">写入拼音检索表</a-button>
<a-button @click="restore(4)">{{ $t('tool.writepinyin') }}</a-button>
</a-space>
</t-card>
</a-space>
@ -59,9 +59,9 @@ const restoreRange = async (start: any = 0, uint8Array: any) => {
}
const restore = async(type: any = 1) => {
if(appStore.connectState != true){alert('请先连接手台!'); return;};
if(appStore.connectState != true){alert(sessionStorage.getItem('noticeConnectK5')); return;};
if(appStore.configuration?.uart == "official"){
alert('固件版本不匹配');
alert(sessionStorage.getItem('noticeVersionNoSupport'));
return;
}
state.status = state.status + "正在下载字库...<br />"

View file

@ -1,12 +1,12 @@
<template>
<div class="container">
<Breadcrumb :items="['小工具', '固件升级']" />
<Breadcrumb :items="[$t('menu.list'), $t('menu.flash')]" />
<a-row :gutter="20" align="stretch">
<a-col :span="24">
<a-card class="general-card" title="固件升级(手台应在刷机模式下)">
<a-card class="general-card" :title="$t('menu.flash') + $t('global.onBoot')">
<a-space>
<a-button @click="selectFile">{{ state.binaryFile ? state.binaryName : '选择固件' }}</a-button>
<a-button type="primary" :disabled="!state.binaryFile" @click="flashIt">更新</a-button>
<a-button @click="selectFile">{{ state.binaryFile ? state.binaryName : $t('tool.selectFirmware') }}</a-button>
<a-button type="primary" :disabled="!state.binaryFile" @click="flashIt">{{ $t('tool.flash') }}</a-button>
</a-space>
<a-divider />
<div id="statusArea" style="height: 20em; background-color: azure; color: silver; overflow: auto; padding: 20px"

View file

@ -1,10 +1,10 @@
<template>
<div class="container">
<Breadcrumb :items="['小工具', '开机图片']" />
<Breadcrumb :items="[$t('menu.list'), $t('menu.image')]" />
<a-row :gutter="20" align="stretch">
<a-col :span="24">
<a-spin :loading="state.loading" tip="写入中..." style="width: 100%;">
<a-card class="general-card" title="开机图片(手台应在开机状态下)">
<a-card class="general-card" :title="$t('menu.image') + $t('global.onStart')">
<a-row :gutter="20">
<a-col :span="4" v-for="i in [
{ name: '罗狮虎', url: '/img1.png'},
@ -39,8 +39,8 @@
<div id="canvasDiv" style="zoom: 250%;"></div>
<br>
<a-space>
<a-button @click="selectFile">选择图片</a-button>
<a-button type="primary" :disabled="!state.binaryFile" @click="flashIt">写入</a-button>
<a-button @click="selectFile">{{ $t('tool.selectImage') }}</a-button>
<a-button type="primary" :disabled="!state.binaryFile" @click="flashIt">{{ $t('tool.write') }}</a-button>
</a-space>
</a-card>
</a-spin>
@ -186,13 +186,13 @@ const selectFile = () => {
}
const flashIt = async () => {
if(appStore.connectState != true){alert('请先连接手台!'); return;};
if(appStore.connectState != true){alert(sessionStorage.getItem('noticeConnectK5')); return;};
if(appStore.configuration?.uart == "official"){
alert('固件版本不匹配');
alert(sessionStorage.getItem('noticeVersionNoSupport'));
return;
}
if(appStore.configuration?.charset != "losehu" && appStore.configuration?.charset != "gb2312"){
alert('固件版本不匹配');
alert(sessionStorage.getItem('noticeVersionNoSupport'));
return;
}
state.loading = true

View file

@ -1,20 +1,20 @@
<template>
<div class="container">
<a-modal v-model:visible="state.visible" @ok="handleOk" ok-text="已扫码上传">
<a-modal v-model:visible="state.visible" @ok="handleOk" ok-text="Scanned and uploaded">
<template #title>
手机扫码获取经纬度
{{ $t('tool.scanqr') }}
</template>
<div style="text-align: center;">
<img :src="state.qrcode" /><br>
上传经纬度信息将被服务器缓存十分钟
{{ $t('tool.scannotice') }}
</div>
</a-modal>
<Breadcrumb :items="['小工具', '星历写入']" />
<Breadcrumb :items="[$t('menu.list'), $t('menu.satellite')]" />
<a-row :gutter="20" align="stretch">
<a-col :span="24">
<a-card class="general-card" title="星历写入(手台应在开机状态下)">
<a-card class="general-card" :title="$t('menu.satellite') + $t('global.onStart')">
<a-spin :loading="loading" style="width: 100%;" tip="正在处理 ...">
<a-form-item :label-col-style="{ width: '25%' }" field="dt" label="浏览器时间" @click="()=>{state.showHide += 1}">
<a-form-item :label-col-style="{ width: '25%' }" field="dt" :label="$t('tool.brtime')" @click="()=>{state.showHide += 1}">
{{ state.dt }}
</a-form-item>
<a-form-item v-show="state.showHide >= 5" :label-col-style="{ width: '25%' }" field="dtCustom" label="自定义时间">
@ -29,28 +29,28 @@
&nbsp;&nbsp;<t-button size="small" theme="success" @click="writeTime">写入时间到台站</t-button>
</div>
</a-form-item>
<a-form-item :label-col-style="{ width: '25%' }" field="sat" label="选择卫星">
<a-select v-model="state.sat" @change="changeSat" placeholder="选择卫星 ..." allow-search allow-clear>
<a-form-item :label-col-style="{ width: '25%' }" field="sat" :label="$t('tool.selectSatellite')">
<a-select v-model="state.sat" @change="changeSat" :placeholder="$t('tool.selectSatellite') + '...'" allow-search allow-clear>
<a-option v-for="item in state.satData" :key="item.name" :value="item.name">{{ item.name }}</a-option>
</a-select>
</a-form-item>
<a-form-item :label-col-style="{ width: '25%' }" field="lng" label="台站经度">
<a-form-item :label-col-style="{ width: '25%' }" field="lng" :label="$t('tool.longitude')">
<a-input-number :precision="6" v-model="state.lng" />
</a-form-item>
<a-form-item :label-col-style="{ width: '25%' }" field="lat" label="台站纬度">
<a-form-item :label-col-style="{ width: '25%' }" field="lat" :label="$t('tool.latitude')">
<a-input-number :precision="6" v-model="state.lat" />
</a-form-item>
<a-form-item :label-col-style="{ width: '25%' }" field="alt" label="台站海拔">
<a-form-item :label-col-style="{ width: '25%' }" field="alt" :label="$t('tool.altitude')">
<a-input-number :precision="0" v-model="state.alt" />
</a-form-item>
<a-form-item :label-col-style="{ width: '25%' }" label="">
<a-space>
<a-button @click="getLocation">浏览器获取经纬度</a-button>
<a-button @click="scanLocation">手机扫码获取经纬度</a-button>
<a-button @click="getPass">获取卫星过境时间</a-button>
<a-button @click="getLocation">{{ $t('tool.brlonlat') }}</a-button>
<a-button @click="scanLocation">{{ $t('tool.phonelonlat') }}</a-button>
<a-button @click="getPass">{{ $t('tool.satpasstime') }}</a-button>
</a-space>
</a-form-item>
<a-form-item :label-col-style="{ width: '25%' }" field="pass" label="选择过境时间">
<a-form-item :label-col-style="{ width: '25%' }" field="pass" :label="$t('tool.selectPassTime')">
<a-select v-model="state.pass" allow-search allow-clear>
<a-option v-for="item in state.passOption" :key="item[0] + '|' + item[1]"
:value="item[0] + '|' + item[1]">{{ item[0] + " - " + item[1] }}</a-option>
@ -65,26 +65,26 @@
v-model="state.passCustom"
/>
</a-form-item>
<a-form-item :label-col-style="{ width: '25%' }" field="tx" label="上行频率">
<a-form-item :label-col-style="{ width: '25%' }" field="tx" :label="$t('tool.txFreq')">
<a-input-number :precision="5" v-model="state.tx" />
</a-form-item>
<a-form-item :label-col-style="{ width: '25%' }" field="txTone" label="上行亚音">
<a-form-item :label-col-style="{ width: '25%' }" field="txTone" :label="$t('tool.txTone')">
<a-select v-model="state.txTone" allow-search allow-clear>
<a-option :value="0">关闭</a-option>
<a-option :value="0">{{ $t('tool.off') }}</a-option>
<a-option v-for="item in state.CTCSSOption" :key="item" :value="item">{{ item.toFixed(1) }}</a-option>
</a-select>
</a-form-item>
<a-form-item :label-col-style="{ width: '25%' }" field="rx" label="下行频率">
<a-form-item :label-col-style="{ width: '25%' }" field="rx" :label="$t('tool.rxFreq')">
<a-input-number :precision="5" v-model="state.rx" />
</a-form-item>
<a-form-item :label-col-style="{ width: '25%' }" field="rxTone" label="下行亚音">
<a-form-item :label-col-style="{ width: '25%' }" field="rxTone" :label="$t('tool.rxTone')">
<a-select v-model="state.rxTone" allow-search allow-clear>
<a-option :value="0">关闭</a-option>
<a-option :value="0">{{ $t('tool.off') }}</a-option>
<a-option v-for="item in state.CTCSSOption" :key="item" :value="item">{{ item.toFixed(1) }}</a-option>
</a-select>
</a-form-item>
<a-form-item :label-col-style="{ width: '25%' }" label="">
<a-button @click="writeIt">写入数据</a-button>
<a-button @click="writeIt">{{ $t('tool.writeData') }}</a-button>
</a-form-item>
<a-divider />
<div id="statusArea"
@ -177,7 +177,7 @@ onUnmounted(()=>{
})
const writeTime = async () => {
if (appStore.connectState != true) { alert('请先连接手台!'); return; };
if (appStore.connectState != true) { alert(sessionStorage.getItem('noticeConnectK5')); return; };
setLoading(true)
await eeprom_init(appStore.connectPort);
await syncTime();
@ -345,9 +345,9 @@ const getPass = async () => {
}
const writeIt = async () => {
if (appStore.connectState != true) { alert('请先连接手台!'); return; };
if (appStore.connectState != true) { alert(sessionStorage.getItem('noticeConnectK5')); return; };
if(appStore.configuration?.sat != true){
alert('固件版本不匹配');
alert(sessionStorage.getItem('noticeVersionNoSupport'));
return;
}
if (!state.sat) { alert('请选择卫星!'); return; };

View file

@ -1,26 +1,27 @@
<template>
<div class="container">
<div style="background-color: #fff; padding: 10%;" v-show="state.type != 0">
请点击网页已扫码上传按钮
请点击网页已扫码上传按钮 <br>
Please click on the "Scanned and Uploaded" button on PC page.
</div>
<div style="background-color: #fff; padding: 10%;" v-show="state.type == 0">
<p style="font-size: 1.5rem; font-weight: bold;">
获取信息
获取信息Information
</p>
<a-divider />
<p>
台站经度{{ state.lng }}
台站经度Longitude{{ state.lng }}
</p>
<a-divider />
<p>
台站纬度{{ state.lat }}
台站纬度Latitude{{ state.lat }}
</p>
<a-divider />
<p>
台站海拔{{ state.alt }}
台站海拔Altitude{{ state.alt }}
</p>
<a-divider />
<a-button type="primary" @click="upload">上传</a-button>
<a-button type="primary" @click="upload">上传Upload</a-button>
</div>
</div>
</template>

View file

@ -1,9 +1,9 @@
<template>
<div class="container">
<Breadcrumb :items="['写频', '信道管理']" />
<Breadcrumb :items="[$t('menu.dashboard'), $t('menu.cps.channel')]" />
<a-card class="general-card">
<template #title>
<span @click="()=>{istate.showHide += 1}">信道管理手台应在开机状态下</span>
<span @click="()=>{istate.showHide += 1}">{{ $t('menu.cps.channel') + $t('global.onStart') }}</span>
</template>
<a-row style="margin-bottom: 16px">
<a-col :span="12">
@ -12,13 +12,13 @@
<template #icon>
<icon-plus />
</template>
从设备读取
{{ $t('cps.onDeviceRead') }}
</a-button>
<a-button @click="writeChannel">
<template #icon>
<icon-plus />
</template>
写入设备
{{ $t('cps.onDeviceWrite') }}
</a-button>
</a-space>
</a-col>
@ -39,13 +39,13 @@
</template>
</a-dropdown>
<a-button type="text" @click="downloadExcelTemplate">
下载导入模板
{{ $t('cps.downloadImportTemplate') }}
</a-button>
<a-button type="primary" @click="restoreExcelChannel">
导入
{{ $t('cps.import') }}
</a-button>
<a-button @click="saveExcelChannel">
导出
{{ $t('cps.export') }}
</a-button>
</a-space>
</a-col>
@ -94,7 +94,7 @@
</t-checkbox-group>
</template>
<template #operate="{ row, rowIndex }">
<t-button theme="default" variant="dashed" @click="clearRow((cstate.nowPage - 1) * cstate.pageSize + rowIndex)">清空</t-button>
<t-button theme="default" variant="dashed" @click="clearRow((cstate.nowPage - 1) * cstate.pageSize + rowIndex)">{{ $t('cps.clear') }}</t-button>
</template>
</t-table>
</a-card>
@ -110,6 +110,8 @@
import { MoveIcon } from 'tdesign-icons-vue-next';
import { toSimplified } from 'chinese-simple2traditional';
import { read as xlsxRead, writeFile as xlsxWrite, utils as xlsxUtils } from "xlsx";
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const appStore = useAppStore();
@ -162,7 +164,7 @@
const columns = computed(() => [
{
colKey: 'drag', //
title: '排序',
title: t('cps.sort'),
width: 46,
},
{
@ -172,7 +174,7 @@
width: 100
},
{
title: '信道名称',
title: t('cps.name'),
colKey: 'name',
width: 250,
align: 'left',
@ -189,7 +191,7 @@
},
},
{
title: '带宽',
title: t('cps.bandwidth'),
colKey: 'bandwidth',
align: 'left',
width: 150,
@ -208,7 +210,7 @@
},
},
{
title: '接收频率',
title: t('cps.rx'),
colKey: 'rx',
align: 'left',
width: 200,
@ -227,7 +229,7 @@
},
},
{
title: '发送频率',
title: t('cps.tx'),
colKey: 'tx',
align: 'left',
width: 200,
@ -246,7 +248,7 @@
},
},
{
title: '发送功率',
title: t('cps.power'),
colKey: 'power',
align: 'left',
width: 150,
@ -265,7 +267,7 @@
},
},
{
title: '接收亚音类型',
title: t('cps.rxToneType'),
colKey: 'rxTone',
align: 'left',
width: 180,
@ -284,7 +286,7 @@
},
},
{
title: '接收亚音频Hz',
title: t('cps.rxToneCTCSS'),
colKey: 'rxCTCSS',
align: 'left',
width: 150,
@ -303,7 +305,7 @@
},
},
{
title: '接收亚音数码',
title: t('cps.rxToneDCS'),
colKey: 'rxDCS',
align: 'left',
width: 150,
@ -322,7 +324,7 @@
},
},
{
title: '发送亚音类型',
title: t('cps.txToneType'),
colKey: 'txTone',
align: 'left',
width: 180,
@ -341,7 +343,7 @@
},
},
{
title: '发送亚音频Hz',
title: t('cps.txToneCTCSS'),
colKey: 'txCTCSS',
align: 'left',
width: 150,
@ -360,7 +362,7 @@
},
},
{
title: '发送亚音数码',
title: t('cps.txToneDCS'),
colKey: 'txDCS',
align: 'left',
width: 150,
@ -379,7 +381,7 @@
},
},
{
title: '频率步进',
title: t('cps.step'),
colKey: 'step',
align: 'left',
width: 150,
@ -398,13 +400,13 @@
},
},
{
title: '倒频',
title: t('cps.reverse'),
colKey: 'reverse',
align: 'left',
width: 150
},
{
title: '加密',
title: t('cps.scramb'),
colKey: 'scramb',
align: 'left',
width: 150,
@ -422,13 +424,13 @@
},
},
{
title: '繁忙禁发',
title: t('cps.busy'),
colKey: 'busy',
align: 'left',
width: 150
},
{
title: '信令码',
title: t('cps.pttid'),
colKey: 'pttid',
align: 'left',
width: 150,
@ -446,7 +448,7 @@
},
},
{
title: '信道模式',
title: t('cps.mode'),
colKey: 'mode',
align: 'left',
width: 150,
@ -465,19 +467,19 @@
},
},
{
title: 'DTMF解码',
title: t('cps.dtmf'),
colKey: 'dtmf',
align: 'left',
width: 150
},
{
title: '扫描列表',
title: t('cps.scanlist'),
colKey: 'scanlist',
align: 'left',
width: 150
},
{
title: '操作',
title: t('cps.operate'),
colKey: 'operate',
align: 'left',
width: 150
@ -489,7 +491,7 @@
];
const readChannel = async() => {
if(appStore.connectState != true){alert('请先连接手台!'); return;};
if(appStore.connectState != true){alert(sessionStorage.getItem('noticeConnectK5')); return;};
await eeprom_init(appStore.connectPort);
setLoading(true)
let rawEEPROM = new Uint8Array(0x0C80);
@ -563,7 +565,7 @@
setLoading(false)
}
const writeChannel = async() =>{
if(appStore.connectState != true){alert('请先连接手台!'); return;};
if(appStore.connectState != true){alert(sessionStorage.getItem('noticeConnectK5')); return;};
await eeprom_init(appStore.connectPort);
setLoading(true)
let rawEEPROM = new Uint8Array(0x0C80);

View file

@ -1,9 +1,9 @@
<template>
<div class="container">
<Breadcrumb :items="['小工具', '设置管理']" />
<Breadcrumb :items="[$t('menu.dashboard'), $t('menu.cps.settings')]" />
<a-row :gutter="20" align="stretch">
<a-col :span="24">
<a-card class="general-card" title="设置管理(手台应在开机状态下)">
<a-card class="general-card" :title="$t('menu.cps.settings') + $t('global.onStart')">
<a-row style="margin-bottom: 16px">
<a-col :span="12">
<a-space>
@ -11,35 +11,35 @@
<template #icon>
<icon-plus />
</template>
从设备读取
{{ $t('cps.onDeviceRead') }}
</a-button>
<a-button @click="writeChannel">
<template #icon>
<icon-plus />
</template>
写入设备
{{ $t('cps.onDeviceWrite') }}
</a-button>
</a-space>
</a-col>
<a-col :span="12" style="text-align: right;">
<!-- <a-col :span="12" style="text-align: right;">
<a-space>
<a-button type="primary" @click="saveChannel">
保存
{{ $t('cps.save') }}
</a-button>
<a-button @click="restoreChannel">
加载
{{ $t('cps.load') }}
</a-button>
</a-space>
</a-col>
</a-col> -->
</a-row>
<a-spin :loading="loading" style="width: 100%;">
<a-form-item :label-col-style="{width: '25%'}" field="logo_line1" label="启动画面首行文字">
<a-form-item :label-col-style="{width: '25%'}" field="logo_line1" :label="$t('cps.line1')">
<a-input v-model="state.logo_line1" />
</a-form-item>
<a-form-item :label-col-style="{width: '25%'}" field="logo_line2" label="启动画面次行文字">
<a-form-item :label-col-style="{width: '25%'}" field="logo_line2" :label="$t('cps.line2')">
<a-input v-model="state.logo_line2" />
</a-form-item>
<a-form-item :label-col-style="{width: '25%'}" field="logo_line2" label="本地播放首尾音仅117P6">
<a-form-item :label-col-style="{width: '25%'}" field="logo_line2" :label="$t('cps.mdclocplay')">
<a-switch v-model="state.mdc_audio_local" type="round"/>
</a-form-item>
</a-spin>
@ -65,7 +65,7 @@ const state = reactive({
})
const readChannel = async() => {
if(appStore.connectState != true){alert('请先连接手台!'); return;};
if(appStore.connectState != true){alert(sessionStorage.getItem('noticeConnectK5')); return;};
await eeprom_init(appStore.connectPort);
setLoading(true)
if(appStore.configuration?.charset == "losehu"){
@ -95,7 +95,7 @@ const readChannel = async() => {
}
const writeChannel = async() => {
if(appStore.connectState != true){alert('请先连接手台!'); return;};
if(appStore.connectState != true){alert(sessionStorage.getItem('noticeConnectK5')); return;};
setLoading(true)
await eeprom_init(appStore.connectPort);
if(appStore.configuration?.charset == "losehu"){