学习机3.4.0版本

This commit is contained in:
2023-11-29 16:08:12 +08:00
parent 770ca0df44
commit 4e86989fcd
3688 changed files with 3708 additions and 1839 deletions

View File

@@ -29,20 +29,18 @@
import { ref, watch, onMounted } from 'vue'
import { NGi, NGrid, NDatePicker, NButton, useMessage } from 'naive-ui'
import { Clock } from '@/components/Charts'
import { useSerialPortStore, SerialPortEventType } from '@/stores/serialPort'
import { useNMEAStore, NMEADataSource } from '@/stores/nmea'
import { actions } from './data'
import { LineBreakParser } from '@/utils/parser'
const serialPort = useSerialPortStore()
const nmea = useNMEAStore()
const message = useMessage()
const dataSource = new NMEADataSource()
nmea.bindDataSource(dataSource)
const decoder = new TextDecoder()
const parser = new LineBreakParser()
const onSerialPortData = (data: Uint8Array) => {
const lineArr = parser.parse(decoder.decode(data))
const onSerialPortData = (value: Uint8Array) => {
const lineArr = parser.parse(decoder.decode(value))
lineArr.forEach(line => dataSource.emit('data', line))
}
@@ -56,6 +54,7 @@ let firstintv
let currentTimeStamp = (new Date()).valueOf()+1000
onMounted(() => {
window.ipcRenderer.send('COM_SPEACIE')
console.log(currentTimeStamp)
firstintv =setInterval(() => {
currentTimeStamp += 1000
@@ -108,29 +107,65 @@ const onDatePickerTimingBtnClick = () => {
}, 1000)
}
const resettime = () => {
if(serialPort.isOpen){
console.log('now open')
}else{
console.log('not open')
const connectErrMsg = (value: Boolean) => {
disabled.value = true
message.error('无法连接到串口设备')
}
window.ipcRenderer.receive('COM_JUDGE', (value: Boolean) => {
disabled.value = !value
})
window.ipcRenderer.receive('CANNOT_CONNECT',connectErrMsg)
window.ipcRenderer.send('COM_ON')
window.ipcRenderer.receive('COM_LISTENER', (value) => {
onSerialPortData(value)
const BJDateTime = nmea.dateTime
console.log(BJDateTime)
if (BJDateTime === undefined) {
disabled.value = true
if(clearset.value){
clearInterval(firstintv)
currentTimeStamp = new Date(currentTimeStamp).getTime()
firstintv = firstintv =setInterval(() => {
currentTimeStamp += 1000
system_clock.value.update(currentTimeStamp)
}, 1000)
}
}
else {
disabled.value = false
BJ_clock.value.update(BJDateTime)
if(clearset.value){
clearInterval(firstintv)
system_clock.value.update(BJDateTime)
currentTimeStamp = BJDateTime
}else{
if(mark.value){
system_clock.value.update(BJDateTime)
currentTimeStamp = new Date(currentTimeStamp).getTime()+1000
mark.value = false
clearInterval(firstintv)
firstintv = firstintv =setInterval(() => {
currentTimeStamp += 1000
system_clock.value.update(currentTimeStamp)
}, 1000)
}
}
}
})
window.ipcRenderer.receive('COM_CLOSE', (value) => {
disabled.value = true
if(clearset.value){
clearInterval(firstintv)
currentTimeStamp = new Date(currentTimeStamp).getTime()
clearset.value = false
disabled.value = true
firstintv = firstintv =setInterval(() => {
currentTimeStamp += 1000
system_clock.value.update(currentTimeStamp)
}, 1000)
}
}
}
serialPort.addEventListener(SerialPortEventType.data, onSerialPortData)
// serialPort.addEventListener(SerialPortEventType.beforeOpen, resettime)
serialPort.addEventListener(SerialPortEventType.afterOpen, resettime)
// serialPort.addEventListener(SerialPortEventType.beforeClose, resettime)
serialPort.addEventListener(SerialPortEventType.afterClose, resettime)
})
</script>
<style scoped lang="less">

View File

@@ -11,15 +11,17 @@
<script setup lang="ts">
import { ref, computed } from 'vue'
import { useMessage } from 'naive-ui'
import { Map, MapInfoWindow, lonlat2Position } from '@/components/Map'
import { weatherInfoView , weatherRegExp , weatherType } from './weatherInfoView'
import { velocityInfoView , velocityRegExp , velocityType } from './velocityInfoView'
import { disasterInfoView , disasterRegExp , disasterType } from './disasterInfoView'
import { elevationInfoView, elevationRegExp, elevationType } from './elevationInfoView'
import { useSerialPortStore, SerialPortEventType } from '@/stores/serialPort'
import { LineBreakParser } from '@/utils/parser'
const message = useMessage()
const longitude = ref(NaN)
const latitude = ref(NaN)
const date = ref('')
@@ -57,8 +59,8 @@ const handle = data => {
}
const decoder = new TextDecoder()
const parser = new LineBreakParser()
const onSerialPortData = (data: Uint8Array) => {
const lineArr = parser.parse(decoder.decode(data))
const onSerialPortData = (value: Uint8Array) => {
const lineArr = parser.parse(decoder.decode(value))
lineArr.forEach(line => handle(line))
}
@@ -108,7 +110,11 @@ const handleElevation = dataArray => {
elevation.value = JSON.parse(dataArray[8]).elevation
}
const connectErrMsg = (value: Boolean) => {
message.error('无法连接到串口设备')
}
const serialPort = useSerialPortStore()
serialPort.addEventListener(SerialPortEventType.data, onSerialPortData)
window.ipcRenderer.receive('CANNOT_CONNECT',connectErrMsg)
window.ipcRenderer.send('COM_ON')
window.ipcRenderer.receive('COM_LISTENER',onSerialPortData)
</script>

View File

@@ -19,16 +19,29 @@
</template>
<script lang="ts" setup>
import { ref, watch } from 'vue'
import { NDescriptions, NDescriptionsItem, NTime } from 'naive-ui'
import { ref, watch, onMounted } from 'vue'
import { NDescriptions, NDescriptionsItem, NTime, useMessage } from 'naive-ui'
import { useNMEAStore } from '@/stores/nmea'
const message = useMessage()
const dateTime = ref()
const longitude = ref()
const latitude = ref()
const altitude = ref()
const nmea = useNMEAStore()
const connectErrMsg = (value: Boolean) => {
message.error('无法连接到串口设备')
}
window.ipcRenderer.receive('CANNOT_CONNECT',connectErrMsg)
onMounted(() => {
window.ipcRenderer.send('COM_READY')
})
watch(() => nmea.handled, (value) => {
if (!value) return

View File

@@ -5,7 +5,7 @@
</template>
<script setup lang="ts">
import { ref, watch } from 'vue'
import { ref, watch, onMounted } from 'vue'
import { Map, MapMarker, lonlat2Position } from '@/components/Map'
import { useNMEAStore } from '@/stores/nmea'
@@ -13,6 +13,11 @@ const nmea = useNMEAStore()
const position = ref()
const mapRef = ref()
onMounted(() => {
window.ipcRenderer.send('COM_READY')
})
watch(() => nmea.handled, (value) => {
if (!value || !nmea.longitude || !nmea.latitude) return

View File

@@ -5,7 +5,7 @@
</template>
<script lang="ts" setup>
import { watch } from "vue"
import { watch, onMounted } from "vue"
import { use } from "echarts/core"
import { CanvasRenderer } from "echarts/renderers"
import { ScatterChart } from "echarts/charts"
@@ -22,6 +22,10 @@ use([
PolarComponent
])
onMounted(() => {
window.ipcRenderer.send('COM_READY')
})
const nmea = useNMEAStore()
watch(() => nmea.handled, (value) => {
if (!value) return

View File

@@ -5,7 +5,7 @@
</template>
<script lang="ts" setup>
import { watch } from "vue"
import { watch, onMounted } from "vue"
import { use } from "echarts/core"
import { CanvasRenderer } from "echarts/renderers"
import { BarChart } from "echarts/charts"
@@ -16,13 +16,16 @@ import { useNMEAStore } from "@/stores/nmea"
import { option } from './data'
use([
CanvasRenderer,
BarChart,
GridComponent
])
onMounted(() => {
window.ipcRenderer.send('COM_READY')
})
const nmea = useNMEAStore()
watch(() => nmea.handled, (value) => {
if (!value) return

View File

@@ -8,11 +8,13 @@
<script setup lang="ts">
import { ref, computed } from 'vue'
import { useMessage } from 'naive-ui'
import { Map, MapInfoWindow, lonlat2Position } from '@/components/Map'
import MeteorologicalDataView from './MeteorologicalDataView.vue'
import { useSerialPortStore, SerialPortEventType } from '@/stores/serialPort'
import { LineBreakParser } from '@/utils/parser'
const message = useMessage()
const longitude = ref(NaN)
const latitude = ref(NaN)
const date = ref('')
@@ -53,11 +55,16 @@ const handle = data => {
const decoder = new TextDecoder()
const parser = new LineBreakParser()
const onSerialPortData = (data: Uint8Array) => {
const lineArr = parser.parse(decoder.decode(data))
const onSerialPortData = (value: Uint8Array) => {
const lineArr = parser.parse(decoder.decode(value))
lineArr.forEach(line => handle(line))
}
const serialPort = useSerialPortStore()
serialPort.addEventListener(SerialPortEventType.data, onSerialPortData)
const connectErrMsg = (value: Boolean) => {
message.error('无法连接到串口设备')
}
window.ipcRenderer.receive('CANNOT_CONNECT',connectErrMsg)
window.ipcRenderer.send('COM_ON')
window.ipcRenderer.receive('COM_LISTENER',onSerialPortData)
</script>

View File

@@ -1,6 +1,6 @@
<template>
<n-space :item-style="itemStyle" class="verification-result-view">
<n-card title="时间数据">
<n-card header-style="padding-top:14px;padding-bottom:14px;" content-style="padding-bottom:14px;" title="时间数据">
<n-descriptions label-placement="top" :column="1">
<n-descriptions-item label="日 期:">
{{ data.date }}
@@ -10,7 +10,7 @@
</n-descriptions-item>
</n-descriptions>
</n-card>
<n-card title="位置数据">
<n-card header-style="padding-top:14px;padding-bottom:14px;" content-style="padding-bottom:14px;" title="位置数据">
<n-descriptions :column="1">
<n-descriptions-item label="经 度:">
{{ data.lon ? data.lon + '° ' + data.uLon : '' }}
@@ -20,7 +20,7 @@
</n-descriptions-item>
</n-descriptions>
</n-card>
<n-card title="气象数据">
<n-card header-style="padding-top:14px;padding-bottom:14px;" content-style="padding-bottom:14px;" title="气象数据">
<n-descriptions label-placement="left" :column="1">
<n-descriptions-item label="温 度">
{{ data.tem ? data.tem + ' ℃' : '' }}

View File

@@ -5,8 +5,8 @@
:rules="rules"
class="data-form-view">
<n-space :item-style="itemStyle">
<n-card title="时间数据">
<n-form-item path="date_picker_timestamp">
<n-card header-style="padding-top:14px;padding-bottom:14px;" content-style="padding-bottom:14px;" title="时间数据">
<n-form-item label="年月日时分秒:" path="date_picker_timestamp">
<n-date-picker
panel
input-readonly
@@ -20,7 +20,7 @@
</n-form-item>
</n-card>
<n-card title="位置数据">
<n-card header-style="padding-top:14px;padding-bottom:14px;" content-style="padding-bottom:14px;" title="位置数据">
<n-space justify="space-around" vertical class="h-full">
<n-form-item :show-feedback="false" label="经度:" path="ulon">
<n-radio-group v-model:value="modelRef.uLon">
@@ -68,7 +68,7 @@
</n-space>
</n-card>
<n-card title="气象数据">
<n-card header-style="padding-top:14px;padding-bottom:14px;" content-style="padding-bottom:14px;" title="气象数据">
<n-space justify="space-around" vertical class="h-full">
<n-form-item label="温度:" path="tem">
<n-input-number :show-button="false"

View File

@@ -10,7 +10,7 @@
<n-text>删除前</n-text>
<n-input-number placeholder="请输入删除点的数量" min="1" v-model:value="delPointCount" :show-button="false" />
<n-text>个点</n-text>
<n-button type="warning" size="large" @click="deleteBtnClick">删除</n-button>
<n-button type="error" size="large" @click="deleteBtnClick">删除</n-button>
</n-space>
</n-space>
</template>

View File

@@ -1,5 +1,5 @@
<template>
<Map ref="mapRef" :dragEnable="false" :animateEnable="false">
<Map ref="mapRef" :dragEnable="nodrag" :animateEnable="false">
<el-amap-loca @init="initLoca" /> <!-- 高德地图数据可视化库,不可用于其他地图开发框架 -->
<MapMarker :position="position" />
<MapPolyline :path="path" />
@@ -18,6 +18,8 @@ let mapInstance = null // 地图对象实例
let viewControl = null // 镜头控制器
let finished = true // 轨迹回放动画是否结束
const nodrag = ref(true)
const initLoca = loca => {
mapInstance = loca.map
viewControl = loca.viewControl
@@ -31,7 +33,7 @@ watch(
reset()
if (value && value.length > 0) {
mapRef.value.setZoomAndCenter(16, value[0])
mapRef.value.setZoomAndCenter(16.75, value[0])
}
},
{ deep: true }
@@ -53,7 +55,6 @@ run()
const play = () => {
if (!props.path || props.path.length === 0) return
playTrackAnimate()
}
@@ -61,6 +62,7 @@ const timing = [[0, 0.3], [1, 0.7]]
const rotationSpeed = 10
const duration = 50000
const playTrackAnimate = () => {
nodrag.value = false
finished = false
viewControl?.addTrackAnimate({
@@ -69,7 +71,10 @@ const playTrackAnimate = () => {
timing, // 速率控制器
rotationSpeed, // 每秒旋转多少度
},
() => finished = true // 动画节后后的回到函数
() => {
finished = true // 动画节后后的回到函数
nodrag.value = true
}
)}

View File

@@ -9,8 +9,6 @@ import * as THREE from 'three'
import { MTLLoader } from 'three/examples/jsm/loaders/MTLLoader.js'
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js'
import { useSerialPortStore } from '@/stores/serialPort'
const satelliteRef = ref(null)
const accRate = 16384.0
@@ -220,8 +218,6 @@ const data2AccGyr = data => {
gyr[2] = dataArr[5] / gyrRate
}
const serialPort = useSerialPortStore()
onMounted(() => {
init()
animate()

View File

@@ -4,14 +4,16 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useMessage } from 'naive-ui'
import * as THREE from 'three'
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'
import { RGBELoader } from 'three/addons/loaders/RGBELoader.js'
import { useSerialPortStore, SerialPortEventType } from '@/stores/serialPort'
import { LineBreakParser } from '@/utils/parser'
const message = useMessage()
const accRate = 16384.0
const gyrRate = 131.072
@@ -199,8 +201,8 @@ const data2AccGyr = data => {
const decoder = new TextDecoder()
const parser = new LineBreakParser()
const onSerialPortData = (data: Uint8Array) => {
const lineArr = parser.parse(decoder.decode(data))
const onSerialPortData = (value: Uint8Array) => {
const lineArr = parser.parse(decoder.decode(value))
lineArr.forEach(line => {
if (!isValidFormat(line)) return
@@ -208,8 +210,13 @@ const onSerialPortData = (data: Uint8Array) => {
})
}
const serialPort = useSerialPortStore()
serialPort.addEventListener(SerialPortEventType.data, onSerialPortData)
const connectErrMsg = (value: Boolean) => {
message.error('无法连接到串口设备')
}
window.ipcRenderer.receive('CANNOT_CONNECT',connectErrMsg)
window.ipcRenderer.send('COM_ON')
window.ipcRenderer.receive('COM_LISTENER',onSerialPortData)
onMounted(() => {
initSatellite()

View File

@@ -5,8 +5,21 @@
</template>
<script lang="ts" setup>
import { NSpace } from 'naive-ui'
import { onMounted } from 'vue'
import { NSpace, useMessage } from 'naive-ui'
import { MotorControlView } from '../components/MotorControlView'
const message = useMessage()
const connectErrMsg = (value: Boolean) => {
message.error('无法连接到串口设备')
}
window.ipcRenderer.receive('CANNOT_CONNECT',connectErrMsg)
onMounted(() => {
window.ipcRenderer.send('COM_READY')
})
</script>
<style scoped lang="less">

View File

@@ -7,7 +7,7 @@
</template>
</n-slider>
<n-button secondary type="primary" size="large" :disabled="!serialPort.isOpen" @click="onBtnClick">设置 {{ props.index + 1 }} 号电机速度</n-button>
<n-button class="setbutton" secondary type="primary" size="large" @click="onBtnClick">设置 {{ props.index + 1 }} 号电机速度</n-button>
</n-space>
</template>
@@ -15,7 +15,6 @@
<script setup lang="ts">
import { ref } from 'vue'
import { NSpace, NSlider, NButton, useMessage } from 'naive-ui'
import { useSerialPortStore } from '@/stores/serialPort'
import { MIN, MAX } from './data'
const props = defineProps({
@@ -25,19 +24,11 @@ const props = defineProps({
},
})
const message = useMessage()
const serialPort = useSerialPortStore()
const speed = ref(MIN)
const onBtnClick = () => {
if (!serialPort.isOpen) {
message.error('请先连接无线通信模块并打开串口')
return
}
const value = speed.value === MIN ? 0 : speed.value
const commond = `$MOTOR,${props.index},${value}*${value.toString().length + 10}\r\n`
serialPort.write(commond)
window.ipcRenderer.send('COM_WRITE',commond)
}
</script>
@@ -47,4 +38,7 @@ const onBtnClick = () => {
margin: 0 auto;
box-sizing: content-box;
}
.setbutton {
margin-top:2vh;
}
</style>

View File

@@ -37,11 +37,12 @@
<script lang="ts" setup>
import { ref } from 'vue'
import { NCard, NSpace, NDescriptions, NDescriptionsItem } from 'naive-ui'
import { NCard, NSpace, NDescriptions, NDescriptionsItem, useMessage } from 'naive-ui'
import { useSerialPortStore, SerialPortEventType } from '@/stores/serialPort'
import { LineBreakParser } from '@/utils/parser'
const message = useMessage()
const x_angular_acceleration = ref()
const y_angular_acceleration = ref()
const z_angular_acceleration = ref()
@@ -75,13 +76,18 @@ const handle = (data: string) => {
const decoder = new TextDecoder()
const parser = new LineBreakParser()
const onSerialPortData = (data: Uint8Array) => {
const lineArr = parser.parse(decoder.decode(data))
const onSerialPortData = (value: Uint8Array) => {
const lineArr = parser.parse(decoder.decode(value))
lineArr.forEach(line => handle(line))
}
const serialPort = useSerialPortStore()
serialPort.addEventListener(SerialPortEventType.data, onSerialPortData)
const connectErrMsg = (value: Boolean) => {
message.error('无法连接到串口设备')
}
window.ipcRenderer.receive('CANNOT_CONNECT',connectErrMsg)
window.ipcRenderer.send('COM_ON')
window.ipcRenderer.receive('COM_LISTENER',onSerialPortData)
</script>
<style scoped lang="less">

View File

@@ -17,9 +17,8 @@
<script lang="ts" setup>
import { ref } from 'vue'
import { NCard, NSpace, NDescriptions, NDescriptionsItem } from 'naive-ui'
import { NCard, NSpace, NDescriptions, NDescriptionsItem, useMessage } from 'naive-ui'
import { useSerialPortStore, SerialPortEventType } from '@/stores/serialPort'
import { LineBreakParser } from '@/utils/parser'
const date = ref()
@@ -45,13 +44,13 @@ const handle = (data: string) => {
const decoder = new TextDecoder()
const parser = new LineBreakParser()
const onSerialPortData = (data: Uint8Array) => {
const lineArr = parser.parse(decoder.decode(data))
const onSerialPortData = (value: Uint8Array) => {
const lineArr = parser.parse(decoder.decode(value))
lineArr.forEach(line => handle(line))
}
const serialPort = useSerialPortStore()
serialPort.addEventListener(SerialPortEventType.data, onSerialPortData)
window.ipcRenderer.send('COM_ON')
window.ipcRenderer.receive('COM_LISTENER',onSerialPortData)
</script>
<style scoped lang="less">

View File

@@ -24,7 +24,6 @@
import { ref } from 'vue'
import { NCard, NSpace, NDescriptions, NDescriptionsItem } from 'naive-ui'
import { useSerialPortStore, SerialPortEventType } from '@/stores/serialPort'
import { LineBreakParser } from '@/utils/parser'
const solar_panel_one_voltage = ref()
@@ -52,13 +51,13 @@ const handle = (data: string) => {
const decoder = new TextDecoder()
const parser = new LineBreakParser()
const onSerialPortData = (data: Uint8Array) => {
const lineArr = parser.parse(decoder.decode(data))
const onSerialPortData = (value: Uint8Array) => {
const lineArr = parser.parse(decoder.decode(value))
lineArr.forEach(line => handle(line))
}
const serialPort = useSerialPortStore()
serialPort.addEventListener(SerialPortEventType.data, onSerialPortData)
window.ipcRenderer.send('COM_ON')
window.ipcRenderer.receive('COM_LISTENER',onSerialPortData)
</script>
<style scoped lang="less">

View File

@@ -10,7 +10,7 @@
:time-picker-props="timePickerProps"
v-model:value="dateTime" />
<n-button type="primary" size="large" :disabled="!serialPort.isOpen || !dateTime" @click="onTimingBtnClick">
<n-button type="primary" size="large" :disabled="!dateTime" @click="onTimingBtnClick">
通过控件给卫星授时
</n-button>
</n-card>
@@ -18,25 +18,17 @@
<script lang="ts" setup>
import { ref } from 'vue'
import { NCard, NDatePicker, NButton, useMessage } from 'naive-ui'
import { useSerialPortStore } from '@/stores/serialPort'
import { NCard, NDatePicker, NButton } from 'naive-ui'
import { actions, timePickerProps } from './data'
const datePickerRef = ref(null)
const dateTime = ref(null) // 值为时间戳
const serialPort = useSerialPortStore()
const message = useMessage()
const onTimingBtnClick = async () => {
if (!serialPort.isOpen) {
message.error('请先连接无线通信模块并打开串口')
return
}
const dateTimeString = datePickerRef.value?.displayTime.replace(' ', ',')
await serialPort.write(`$TIME,${dateTimeString}*26\r\n`)
await window.ipcRenderer.send('COM_WRITE',`$TIME,${dateTimeString}*26\r\n`)
}
</script>

View File

@@ -9,7 +9,7 @@
</n-descriptions-item>
</n-descriptions>
<n-button type="primary" size="large" :disabled="!serialPort.isOpen" @click="onTimingBtnClick">
<n-button type="primary" size="large" @click="onTimingBtnClick">
通过控件给卫星授时
</n-button>
</n-card>
@@ -19,30 +19,29 @@
import { ref, computed, onMounted } from 'vue'
import { NCard, NDescriptions, NDescriptionsItem, NButton, NTime, useMessage } from 'naive-ui'
import { useSerialPortStore } from '@/stores/serialPort'
import { weekdays } from './data'
const serialPort = useSerialPortStore()
const time = ref(new Date().valueOf())
const weekday = computed(() => weekdays[new Date(time.value).getDay()])
onMounted(() => {
setInterval(() => time.value += 1000, 1000)
window.ipcRenderer.send('COM_READY')
})
const timeRef = ref(null)
const message = useMessage()
const onTimingBtnClick = async () => {
if (!serialPort.isOpen) {
message.error('请先连接无线通信模块并打开串口')
return
}
const dateTimeString = timeRef.value?.$el.getInnerHTML().replace(' ', ',')
await serialPort.write(`$TIME,${dateTimeString}*26\r\n`)
await window.ipcRenderer.send('COM_WRITE',`$TIME,${dateTimeString}*26\r\n`)
}
const connectErrMsg = (value: Boolean) => {
message.error('无法连接到串口设备')
}
window.ipcRenderer.receive('CANNOT_CONNECT',connectErrMsg)
</script>
<style scoped lang="less">

View File

@@ -1,38 +1,48 @@
<template>
<n-grid style="width: 96vw;" class="mx-auto" :cols="2">
<n-gi style="padding-top: 0; padding-bottom: 0;" class="w-h-full p">
<n-scrollbar style="max-height: 49vh; border: 1px solid #eee">
<n-gi style="padding-top: 1.5vh; padding-bottom: 0;" class="w-h-full p">
<n-scrollbar style="max-height: 48vh; border: 1px solid #eee">
<n-dynamic-input
v-model:value="geodata"
:on-create="onCreate"
:on-remove="onRemove"
>
<template #default="{ value }">
<template #default="{ value, index }">
<div style="display: flex; align-items: flex-start; width: 100%">
<div style="width: 50%">
<n-input maxlength="13" clearable v-model:value="value.lat" type="text" placeholder="经度" @input="handleInput" :status="value.latStatus" />
<n-gradient-text :size="12" type="error" v-show="value.latCheck">
<div v-html="value.lat == '' ? '经度不能为空' : '数据格式错误'"></div>
<div v-html="value.latErrMsg"></div>
</n-gradient-text>
</div>
<div style="width: 50%">
<n-input maxlength="12" clearable v-model:value="value.lng" type="text" placeholder="纬度" @input="handleInput" :status="value.lngStatus" />
<n-gradient-text :size="12" type="error" v-show="value.lngCheck">
<div v-html="value.lng == '' ? '纬度不能为空' : '数据格式错误'"></div>
<div v-html="value.lngErrMsg"></div>
</n-gradient-text>
</div>
</div>
<n-button style="padding: 0 5px;font-size: 24px;" @click="move('up', index)">
<n-icon>
<UpIcon />
</n-icon>
</n-button>
<n-button style="padding: 0 5px;font-size: 24px;" @click="move('down', index)">
<n-icon>
<DownIcon />
</n-icon>
</n-button>
</template>
</n-dynamic-input>
</n-scrollbar>
<v-chart style="max-height: 39vh; border: 1px solid #eee" class="chart" id="chart" :option="option" />
<v-chart style="max-height: 38vh; border: 1px solid #eee" class="chart" id="chart" :option="option" />
<div style="margin-top: 1vh;" class="w-full flex flex-1">
<n-button class="mx-auto" :disabled="geodata.length == 0 ? true : false" size="large" type="primary" @click="calculation">计  算</n-button>
<n-button class="mx-auto" :disabled="geodata.length == 0 ? true : false" size="large" type="error" @click="delgeo">清空输入</n-button>
</div>
</n-gi>
<n-gi style="padding-top: 0; padding-bottom: 0;" class="w-h-full p">
<n-data-table :columns="columns" :data="data" :single-line="false" :pagination="pagination" :style="{ height: '88vh' }" flex-height />
<n-gi style="padding-top: 1.5vh; padding-bottom: 0;" class="w-h-full p">
<n-data-table :columns="columns" :data="data" :single-line="false" :pagination="pagination" :style="{ height: '86vh' }" flex-height />
<div style="margin-top: 1vh;" class="w-full flex flex-1">
<div style="width: 128px" class="mx-auto">
<n-select v-model:value="unit" :options="options" />
@@ -50,7 +60,8 @@ import { use, registerMap } from "echarts/core"
import { CanvasRenderer } from 'echarts/renderers'
import { MapChart, ScatterChart } from 'echarts/charts'
import VChart from "vue-echarts"
import { NGi, NGrid, NButton, NDynamicInput, NDataTable, NScrollbar, NInput, NGradientText, NSelect, useMessage, useDialog } from "naive-ui"
import { NGi, NGrid, NButton, NDynamicInput, NDataTable, NScrollbar, NInput, NGradientText, NIcon, NSelect, useMessage, useDialog } from "naive-ui"
import { KeyboardArrowUpRound as UpIcon, KeyboardArrowDownRound as DownIcon } from '@vicons/material'
const message = useMessage()
@@ -61,9 +72,11 @@ const geodata = ref([
lat: "",
latStatus: "",
latCheck: "",
latErrMsg:"",
lng: "",
lngStatus: "",
lngCheck: ""
lngCheck: "",
lngErrMsg:""
}
])
@@ -72,9 +85,11 @@ const onCreate = () => {
lat: "",
latStatus: "",
latCheck: "",
latErrMsg:"",
lng: "",
lngStatus: "",
lngCheck: ""
lngCheck: "",
lngErrMsg:""
}
}
@@ -89,6 +104,26 @@ const options = [
label:"平方千米/km²",
value:'平方千米/km²'
}]
const move = (updown, index) => {
let moveit
if(updown == 'up'){
if(index !== 0){
moveit = geodata.value[index]
geodata.value[index] = geodata.value[index - 1]
geodata.value[index - 1] = moveit
moveit = null
}
}
if(updown == 'down'){
if(index !== geodata.value.length-1){
moveit = geodata.value[index]
geodata.value[index] = geodata.value[index + 1]
geodata.value[index + 1] = moveit
moveit = null
}
}
}
const columns = ref([
{
@@ -250,9 +285,14 @@ window.addEventListener('resize', () => {
chart.resize()
})
const rerender = (mapName,mapArea,mapGeo) => {
const rerender = (mapName,mapArea,mapGeo,initialize) => {
if(mapGeo){
geoObj.features[0].properties.cp = centerPoint(mapGeo)
if(initialize){
geoObj.features[0].properties.cp = [15,12]
}
else{
geoObj.features[0].properties.cp = centerPoint(mapGeo)
}
geoObj.features[0].geometry.coordinates[0][0] = mapGeo
}
geoObj.features[0].properties.name = mapArea
@@ -262,7 +302,7 @@ const rerender = (mapName,mapArea,mapGeo) => {
const onRemove = () => {
if(geodata.value.length < 3){
rerender('nowin','经纬度数据',[[15,30],[0,0],[15,10],[30,0]])
rerender('nowin','经纬度数据',[[15,30],[0,0],[15,10],[30,0]],true)
}
}
@@ -273,11 +313,13 @@ const inputFilter = (inputData) => {
if(item !== '\u00A0' && item !== '\u0020' && item !== '\u3000'){
if(!isNaN(Number(item))){
infilter.push(item)
}else if(item == '.'){
}
else if(item == '.'){
if(infilter.indexOf('.') == '-1'){
infilter.push(item)
}
}else if(item == '-'){
}
else if(item == '-'){
if(infilter.indexOf('-') == '-1'){
infilter.push(item)
}
@@ -287,68 +329,50 @@ const inputFilter = (inputData) => {
return infilter.join('')
}
const stuck = (dataObj,dataItem,Status,Check,ErrMsg,throwMsg) => {
dataObj[dataItem + 'Status'] = Status
dataObj[dataItem + 'Check'] = Check
dataObj[dataItem + 'ErrMsg'] = ErrMsg
if(throwMsg){
message.error(ErrMsg)
throw new Error(ErrMsg)
}
}
const judgment = (dataObj,dataItem,ErrMsg,throwMsg) => {
let toJudgment
if(dataItem == 'lat'){
toJudgment = Number(dataObj[dataItem]).toFixed(8) > 180 || Number(dataObj[dataItem]).toFixed(8) < -180
}
else if(dataItem == "lng"){
toJudgment = Number(dataObj[dataItem]).toFixed(8) > 90 || Number(dataObj[dataItem]).toFixed(8) < -90
}
if(dataObj[dataItem] == ''){
stuck(dataObj,dataItem,'error',true,ErrMsg+'不能为空',throwMsg)
}
else if(dataObj[dataItem].indexOf('-') !== -1 && dataObj[dataItem].indexOf('-') !== 0 || dataObj[dataItem].indexOf('.') == dataObj[dataItem].length-1 || dataObj[dataItem].indexOf('-')+1 == dataObj[dataItem].indexOf('.')){
stuck(dataObj,dataItem,'error',true,ErrMsg+'数据格式错误',throwMsg)
}
else if(toJudgment){
stuck(dataObj,dataItem,'error',true,'非法的'+ErrMsg+'数据',throwMsg)
}
else{
stuck(dataObj,dataItem,'success',false,'',false)
if(throwMsg){
dataObj[dataItem] = Number(dataObj[dataItem]).toString()
}
}
}
const handleInput = () => {
geodata.value.forEach((element,index) => {
element.lat = inputFilter(element.lat)
element.lng = inputFilter(element.lng)
if(element.lat == ''){
element.latStatus = 'error'
element.latCheck = true
}
else{
element.latStatus = 'success'
element.latCheck = false
}
if(element.lng == ''){
element.lngStatus = 'error'
element.lngCheck = true
}
else {
element.lngStatus = 'success'
element.lngCheck = false
}
judgment(element,'lat','经度',false)
judgment(element,'lng','纬度',false)
})
}
const inputCheck = (inputValue) => {
if(inputValue.lat == ''){
message.error('经度不能为空')
inputValue.latStatus = 'error'
inputValue.latCheck = true
throw new Error("经度不能为空")
}
if(inputValue.lng == ''){
message.error('纬度不能为空')
inputValue.lngStatus = 'error'
inputValue.lngCheck = true
throw new Error("纬度不能为空")
}
if(inputValue.lat.indexOf('-') !== -1 && inputValue.lat.indexOf('-') !== 0 || inputValue.lat.indexOf('.') == inputValue.lat.length-1 || inputValue.lat.indexOf('-')+1 == inputValue.lat.indexOf('.')){
message.error('数据格式错误')
inputValue.latStatus = 'error'
inputValue.latCheck = true
throw new Error("数据格式错误")
}
if(inputValue.lng.indexOf('-') !== -1 && inputValue.lng.indexOf('-') !== 0 || inputValue.lng.indexOf('.') == inputValue.lng.length-1 || inputValue.lng.indexOf('-')+1 == inputValue.lng.indexOf('.')){
message.error('数据格式错误')
inputValue.lngStatus = 'error'
inputValue.lngCheck = true
throw new Error("数据格式错误")
}
if(Number(inputValue.lat).toFixed(8) > 180 || Number(inputValue.lat).toFixed(8) < -180){
message.error('非法的经度数据')
inputValue.latStatus = 'error'
inputValue.latCheck = true
throw new Error("非法的经度数据")
}
if(Number(inputValue.lng).toFixed(8) > 90 || Number(inputValue.lng).toFixed(8) < -90){
message.error('非法的纬度数据')
inputValue.lngStatus = 'error'
inputValue.lngCheck = true
throw new Error("非法的纬度数据")
}
}
//地球赤道半径 6378.137
//地球平均半径 6371.004
//弧度转角度 Math.PI / 180.0
@@ -395,8 +419,8 @@ const diffData = (areaResult) => {
})
if(allowCalaulation){
data.value.push(areaResult)
rerender('nowin','经纬度数据',[[15,30],[0,0],[15,10],[30,0]])
rerender('updataGeo',data.value[data.value.length-1].area,data.value[data.value.length-1].latandlng)
rerender('nowin','经纬度数据',[[15,30],[0,0],[15,10],[30,0]],true)
rerender('updataGeo',data.value[data.value.length-1].area,data.value[data.value.length-1].latandlng,false)
}
}
@@ -407,8 +431,9 @@ const calculation = () => {
}
let pointArr = []
geodata.value.forEach((element,index) => {
inputCheck(element)
pointArr.push([element.lat.length>8?Number(element.lat).toFixed(8):element.lat, element.lng.length>8?Number(element.lng).toFixed(8):element.lng])
judgment(element,'lat','经度',true)
judgment(element,'lng','纬度',true)
pointArr.push([element.lat.length>8?Number(element.lat).toFixed(8):Number(element.lat), element.lng.length>8?Number(element.lng).toFixed(8):Number(element.lng)])
})
let areaData = {
latandlng: pointArr,
@@ -434,7 +459,7 @@ const delgeo = () => {
lngCheck: ""
}
]
rerender('nowin','经纬度数据',[[15,30],[0,0],[15,10],[30,0]])
rerender('nowin','经纬度数据',[[15,30],[0,0],[15,10],[30,0]],true)
},
onNegativeClick: () => {
message.error('已返回')
@@ -443,17 +468,16 @@ const delgeo = () => {
}
const drawContour = (row) => {
rerender('nowin','经纬度数据',[[15,30],[0,0],[15,10],[30,0]])
rerender('updataGeo',row.area,row.latandlng)
rerender('nowin','经纬度数据',[[15,30],[0,0],[15,10],[30,0]],true)
rerender('updataGeo',row.area,row.latandlng,false)
}
const deldata = (row) => {
data.value.filter((item,index,array)=>{
if(item == row){
array.splice(index,1)
console.log(data.value.length)
if(data.value.length == 0){
rerender('nowin','经纬度数据',[[15,30],[0,0],[15,10],[30,0]])
rerender('nowin','经纬度数据',[[15,30],[0,0],[15,10],[30,0]],true)
}
}
})
@@ -467,7 +491,7 @@ const delall = () => {
negativeText: '返回',
onPositiveClick: () => {
data.value = []
rerender('nowin','经纬度数据',[[15,30],[0,0],[15,10],[30,0]])
rerender('nowin','经纬度数据',[[15,30],[0,0],[15,10],[30,0]],true)
},
onNegativeClick: () => {
message.error('已返回')

View File

@@ -1,7 +1,7 @@
<template>
<n-grid style="width: 96vw;" class="mx-auto" :cols="2">
<n-gi style="padding-top: 0; padding-bottom: 0;" class="w-h-full p">
<n-scrollbar style="max-height: 88vh; border: 1px solid #eee">
<n-gi style="padding-top: 1.5vh; padding-bottom: 0;" class="w-h-full p">
<n-scrollbar style="max-height: 86vh; border: 1px solid #eee">
<n-dynamic-input
v-model:value="geodata"
:on-create="onCreate"
@@ -11,25 +11,25 @@
<div style="width: 25%">
<n-input maxlength="13" clearable v-model:value="value.lat1" type="text" placeholder="经度1" @input="handleInput" :status="value.lat1Status" />
<n-gradient-text :size="12" type="error" v-show="value.lat1Check">
<div v-html="value.lat1 == '' ? '经度1不能为空' : '数据格式错误'"></div>
<div v-html="value.lat1ErrMsg"></div>
</n-gradient-text>
</div>
<div style="width: 25%">
<n-input maxlength="12" clearable v-model:value="value.lng1" type="text" placeholder="纬度1" @input="handleInput" :status="value.lng1Status" />
<n-gradient-text :size="12" type="error" v-show="value.lng1Check">
<div v-html="value.lng1 == '' ? '纬度1不能为空' : '数据格式错误'"></div>
<div v-html="value.lng1ErrMsg"></div>
</n-gradient-text>
</div>
<div style="width: 25%">
<n-input maxlength="13" clearable v-model:value="value.lat2" type="text" placeholder="经度2" @input="handleInput" :status="value.lat2Status" />
<n-gradient-text :size="12" type="error" v-show="value.lat2Check">
<div v-html="value.lat2 == '' ? '经度2不能为空' : '数据格式错误'"></div>
<div v-html="value.lat2ErrMsg"></div>
</n-gradient-text>
</div>
<div style="width: 25%">
<n-input maxlength="12" clearable v-model:value="value.lng2" type="text" placeholder="纬度2" @input="handleInput" :status="value.lng2Status" />
<n-gradient-text :size="12" type="error" v-show="value.lng2Check">
<div v-html="value.lng2 == '' ? '纬度2不能为空' : '数据格式错误'"></div>
<div v-html="value.lng2ErrMsg"></div>
</n-gradient-text>
</div>
</div>
@@ -41,8 +41,8 @@
<n-button class="mx-auto" :disabled="geodata.length == 0 ? true : false" size="large" type="error" @click="delgeo">清空输入</n-button>
</div>
</n-gi>
<n-gi style="padding-top: 0; padding-bottom: 0;" class="w-h-full p">
<n-data-table :columns="columns" :data="data" :single-line="false" :pagination="pagination" :style="{ height: '88vh' }" flex-height />
<n-gi style="padding-top: 1.5vh; padding-bottom: 0;" class="w-h-full p">
<n-data-table :columns="columns" :data="data" :single-line="false" :pagination="pagination" :style="{ height: '86vh' }" flex-height />
<div style="margin-top: 1vh;" class="w-full flex flex-1">
<div style="width: 100px" class="mx-auto">
<n-select v-model:value="unit" :options="options" />
@@ -64,34 +64,42 @@ const dialog = useDialog()
const geodata = ref([
{
lat1:"",
lat1Status:"",
lat1Check:"",
lat1Status:"success",
lat1Check:false,
lat1ErrMsg:"",
lng1:"",
lng1Status:"",
lng1Check:"",
lng1Status:"success",
lng1Check:false,
lng1ErrMsg:"",
lat2:"",
lat2Status:"",
lat2Check:"",
lat2Status:"success",
lat2Check:false,
lat2ErrMsg:"",
lng2:"",
lng2Status:"",
lng2Check:""
lng2Status:"success",
lng2Check:false,
lng2ErrMsg:""
}
])
const onCreate = () => {
return {
lat1:"",
lat1Status:"",
lat1Check:"",
lat1Status:"success",
lat1Check:false,
lat1ErrMsg:"",
lng1:"",
lng1Status:"",
lng1Check:"",
lng1Status:"success",
lng1Check:false,
lng1ErrMsg:"",
lat2:"",
lat2Status:"",
lat2Check:"",
lat2Status:"success",
lat2Check:false,
lat2ErrMsg:"",
lng2:"",
lng2Status:"",
lng2Check:""
lng2Status:"success",
lng2Check:false,
lng2ErrMsg:""
}
}
@@ -171,122 +179,54 @@ const inputFilter = (inputData) => {
return infilter.join('')
}
const stuck = (dataObj,dataItem,Status,Check,ErrMsg,throwMsg) => {
dataObj[dataItem + 'Status'] = Status
dataObj[dataItem + 'Check'] = Check
dataObj[dataItem + 'ErrMsg'] = ErrMsg
if(throwMsg){
message.error(ErrMsg)
throw new Error(ErrMsg)
}
}
const judgment = (dataType,dataObj,dataItem,ErrMsg,throwMsg) => {
let toJudgment
if(dataType == 'lat'){
toJudgment = Number(dataObj[dataItem]).toFixed(8) > 180 || Number(dataObj[dataItem]).toFixed(8) < -180
}
else if(dataType == "lng"){
toJudgment = Number(dataObj[dataItem]).toFixed(8) > 90 || Number(dataObj[dataItem]).toFixed(8) < -90
}
if(dataObj[dataItem] == ''){
stuck(dataObj,dataItem,'error',true,ErrMsg+'不能为空',throwMsg)
}
else if(dataObj[dataItem].indexOf('-') !== -1 && dataObj[dataItem].indexOf('-') !== 0 || dataObj[dataItem].indexOf('.') == dataObj[dataItem].length-1 || dataObj[dataItem].indexOf('-')+1 == dataObj[dataItem].indexOf('.')){
stuck(dataObj,dataItem,'error',true,ErrMsg+'数据格式错误',throwMsg)
}
else if(toJudgment){
stuck(dataObj,dataItem,'error',true,'非法的'+ErrMsg+'数据',throwMsg)
}
else{
stuck(dataObj,dataItem,'success',false,'',false)
if(throwMsg){
dataObj[dataItem] = Number(dataObj[dataItem]).toString()
}
}
}
const handleInput = () => {
geodata.value.forEach((element,index) => {
element.lat1 = inputFilter(element.lat1)
element.lng1 = inputFilter(element.lng1)
element.lat2 = inputFilter(element.lat2)
element.lng2 = inputFilter(element.lng2)
if(element.lat1 == ''){
element.lat1Status = 'error'
element.lat1Check = true
}
else{
element.lat1Status = 'success'
element.lat1Check = false
}
if(element.lng1 == ''){
element.lng1Status = 'error'
element.lng1Check = true
}
else {
element.lng1Status = 'success'
element.lng1Check = false
}
if(element.lat2 == ''){
element.lat2Status = 'error'
element.lat2Check = true
}
else {
element.lat2Status = 'success'
element.lat2Check = false
}
if(element.lng2 == ''){
element.lng2Status = 'error'
element.lng2Check = true
}
else{
element.lng2Status = 'success'
element.lng2Check = false
}
judgment('lat',element,'lat1','经度1',false)
judgment('lng',element,'lng1','纬度1',false)
judgment('lat',element,'lat2','经度2',false)
judgment('lng',element,'lng2','纬度2',false)
})
}
const inputCheck = (inputValue) => {
if(inputValue.lat1 == ''){
message.error('经度1不能为空')
inputValue.lat1Status = 'error'
inputValue.lat1Check = true
throw new Error("经度1不能为空")
}
if(inputValue.lng1 == ''){
message.error('纬度1不能为空')
inputValue.lng1Status = 'error'
inputValue.lng1Check = true
throw new Error("纬度1不能为空")
}
if(inputValue.lat2 == ''){
message.error('经度2不能为空')
inputValue.lat2Status = 'error'
inputValue.lat2Check = true
throw new Error("经度2不能为空")
}
if(inputValue.lng2 == ''){
message.error('纬度2不能为空')
inputValue.lng2Status = 'error'
inputValue.lng2Check = true
throw new Error("纬度2不能为空")
}
if(inputValue.lat1.indexOf('-') !== -1 && inputValue.lat1.indexOf('-') !== 0 || inputValue.lat1.indexOf('.') == inputValue.lat1.length-1 || inputValue.lat1.indexOf('-')+1 == inputValue.lat1.indexOf('.')){
message.error('数据格式错误')
inputValue.lat1Status = 'error'
inputValue.lat1Check = true
throw new Error("数据格式错误")
}
if(inputValue.lng1.indexOf('-') !== -1 && inputValue.lng1.indexOf('-') !== 0 || inputValue.lng1.indexOf('.') == inputValue.lng1.length-1 || inputValue.lng1.indexOf('-')+1 == inputValue.lng1.indexOf('.')){
message.error('数据格式错误')
inputValue.lng1Status = 'error'
inputValue.lng1Check = true
throw new Error("数据格式错误")
}
if(inputValue.lat2.indexOf('-') !== -1 && inputValue.lat2.indexOf('-') !== 0 || inputValue.lat2.indexOf('.') == inputValue.lat2.length-1 || inputValue.lat2.indexOf('-')+1 == inputValue.lat2.indexOf('.')){
message.error('数据格式错误')
inputValue.lat2Status = 'error'
inputValue.lat2Check = true
throw new Error("数据格式错误")
}
if(inputValue.lng2.indexOf('-') !== -1 && inputValue.lng2.indexOf('-') !== 0 || inputValue.lng2.indexOf('.') == inputValue.lng2.length-1 || inputValue.lng2.indexOf('-')+1 == inputValue.lng2.indexOf('.')){
message.error('数据格式错误')
inputValue.lng2Status = 'error'
inputValue.lng2Check = true
throw new Error("数据格式错误")
}
if(Number(inputValue.lat1).toFixed(8) > 180 || Number(inputValue.lat1).toFixed(8) < -180){
message.error('非法的经度1数据')
inputValue.lat1Status = 'error'
inputValue.lat1Check = true
throw new Error("非法的经度1数据")
}
if(Number(inputValue.lng1).toFixed(8) > 90 || Number(inputValue.lng1).toFixed(8) < -90){
message.error('非法的纬度1数据')
inputValue.lng1Status = 'error'
inputValue.lng1Check = true
throw new Error("非法的纬度1数据")
}
if(Number(inputValue.lat2).toFixed(8) > 180 || Number(inputValue.lat2).toFixed(8) < -180){
message.error('非法的经度2数据')
inputValue.lat2Status = 'error'
inputValue.lat2Check = true
throw new Error("非法的经度2数据")
}
if(Number(inputValue.lng2).toFixed(8) > 90 || Number(inputValue.lng2).toFixed(8) < -90){
message.error('非法的纬度2数据')
inputValue.lng2Status = 'error'
inputValue.lng2Check = true
throw new Error("非法的纬度2数据")
}
}
//弧度转角度 Math.PI / 180.0
//角度转弧度 180.0 / Math.PI
//米转角度 2.0 * Math.PI * 6371.004 / 360.0
@@ -341,12 +281,15 @@ const diffData = (geoResult) => {
const calculation = () => {
geodata.value.forEach((element,index) => {
inputCheck(element)
judgment('lat',element,'lat1','经度1',true)
judgment('lng',element,'lng1','纬度1',true)
judgment('lat',element,'lat2','经度2',true)
judgment('lng',element,'lng2','纬度2',true)
let geobox = {
latitude1:element.lat1.length>8?Number(element.lat1).toFixed(8):element.lat1,
longitude1:element.lng1.length>8?Number(element.lng1).toFixed(8):element.lng1,
latitude2:element.lat2.length>8?Number(element.lat2).toFixed(8):element.lat2,
longitude2:element.lng2.length>8?Number(element.lng2).toFixed(8):element.lng2,
latitude1:element.lat1.length>8?Number(element.lat1).toFixed(8):Number(element.lat1),
longitude1:element.lng1.length>8?Number(element.lng1).toFixed(8):Number(element.lng1),
latitude2:element.lat2.length>8?Number(element.lat2).toFixed(8):Number(element.lat2),
longitude2:element.lng2.length>8?Number(element.lng2).toFixed(8):Number(element.lng2),
distance:calculationDistance(element.lat1,element.lng1,element.lat2,element.lng2)
}
diffData(geobox)

View File

@@ -1,7 +1,7 @@
<template>
<n-grid style="width: 96vw;" class="mx-auto" :cols="2">
<n-gi style="padding-top: 0; padding-bottom: 0;" class="w-h-full p">
<n-scrollbar style="max-height: 88vh; border: 1px solid #eee">
<n-gi style="padding-top: 1.5vh; padding-bottom: 0;" class="w-h-full p">
<n-scrollbar style="max-height: 86vh; border: 1px solid #eee">
<n-dynamic-input
v-model:value="satellite"
:on-create="onCreate"
@@ -10,26 +10,26 @@
<div style="display: flex; align-items: flex-start; width: 100%">
<div style="width: 25%">
<n-input maxlength="2" clearable v-model:value="value.number" type="text" placeholder="卫星编号" @input="handleInput" :status="value.numberStatus" />
<n-gradient-text :size="12" type="error" v-show="value.numberCheck">
<div v-html="value.number == '' ? '卫星编号不能为空' : '卫星编号不能为0'"></div>
<n-gradient-text :size="12" :type="value.numberStatus" v-show="value.numberCheck">
<div v-html="value.numberErrMsg"></div>
</n-gradient-text>
</div>
<div style="width: 25%">
<n-input maxlength="2" clearable v-model:value="value.elevation" type="text" placeholder="仰角" @input="handleInput" :status="value.elevationStatus" />
<n-gradient-text :size="12" :type="value.elevation == '' ? 'error' : 'warning'" v-show="value.elevationCheck">
<div v-html="value.elevation == '' ? '仰角不能为空' : '仰角和方位角同时为0,<br>该数据可能是无效数据,<br>建议修改或删除'"></div>
<n-gradient-text :size="12" :type="value.elevationStatus" v-show="value.elevationCheck">
<div v-html="value.elevationErrMsg"></div>
</n-gradient-text>
</div>
<div style="width: 25%">
<n-input maxlength="7" clearable v-model:value="value.azimuth" type="text" placeholder="方位角" @input="handleInput" :status="value.azimuthStatus" />
<n-gradient-text :size="12" :type="value.azimuth == '' ? 'error' : 'warning'" v-show="value.azimuthCheck">
<div v-html="value.azimuth == '' ? '方位角不能为空' : ''"></div>
<n-gradient-text :size="12" :type="value.azimuthStatus" v-show="value.azimuthCheck">
<div v-html="value.azimuthErrMsg"></div>
</n-gradient-text>
</div>
<div style="width: 25%">
<n-input maxlength="2" clearable v-model:value="value.signal" type="text" placeholder="信号强度" @input="handleInput" :status="value.signalStatus" />
<n-gradient-text :size="12" :type="value.signal == '' ? 'error' : 'warning'" v-show="value.signalCheck">
<div v-html="value.signal == '' ? '信号强度不能为空' : '信号强度为0,<br>该数据可能是无效数据,<br>建议修改或删除'"></div>
<n-gradient-text :size="12" :type="value.signalStatus" v-show="value.signalCheck">
<div v-html="value.signalErrMsg"></div>
</n-gradient-text>
</div>
</div>
@@ -41,8 +41,8 @@
<n-button class="mx-auto" :disabled="satellite.length==0?true:false" size="large" type="error" @click="delgeo">清空输入</n-button>
</div>
</n-gi>
<n-gi style="padding-top: 0; padding-bottom: 0;" class="w-h-full p">
<n-data-table :columns="columns" :data="data" :single-line="false" :pagination="pagination" :style="{ height: '88vh' }" flex-height />
<n-gi style="padding-top: 1.5vh; padding-bottom: 0;" class="w-h-full p">
<n-data-table :columns="columns" :data="data" :single-line="false" :pagination="pagination" :style="{ height: '86vh' }" flex-height />
<div style="margin-top: 1vh;" class="w-full flex flex-1">
<div style="width: 165px" class="mx-auto">
<n-select v-model:value="version" :options="options" />
@@ -66,15 +66,19 @@ const satellite = ref([
number: "",
numberStatus: "success",
numberCheck: false,
numberErrMsg: "",
elevation: "",
elevationStatus: "success",
elevationCheck: false,
elevationErrMsg: "",
azimuth: "",
azimuthStatus: "success",
azimuthCheck: false,
azimuthErrMsg: "",
signal: "",
signalStatus: "success",
signalCheck: false
signalCheck: false,
signalErrMsg: ""
}
])
@@ -83,15 +87,19 @@ const onCreate = () => {
number: "",
numberStatus: "success",
numberCheck: false,
numberErrMsg: "",
elevation: "",
elevationStatus: "success",
elevationCheck: false,
elevationErrMsg: "",
azimuth: "",
azimuthStatus: "success",
azimuthCheck: false,
azimuthErrMsg: "",
signal: "",
signalStatus: "success",
signalCheck: false
signalCheck: false,
signalErrMsg: ""
}
}
@@ -173,7 +181,7 @@ const data = ref([])
const allowCalaulation = ref(true)
const inputFilter = (inputData) => {
const inputFilter = (inputData,point) => {
let infilter = []
let beffilter = [...inputData]
beffilter.forEach(item => {
@@ -181,81 +189,99 @@ const inputFilter = (inputData) => {
if(!isNaN(Number(item))){
infilter.push(item)
}
else if(item == '.' && point){
if(infilter.indexOf('.') == '-1'){
infilter.push(item)
}
}
}
})
return infilter.join('')
}
const stuck = (dataObj,dataItem,Status,Check,ErrMsg,throwMsg) => {
dataObj[dataItem + 'Status'] = Status
dataObj[dataItem + 'Check'] = Check
dataObj[dataItem + 'ErrMsg'] = ErrMsg
if(throwMsg){
message.error(ErrMsg)
throw new Error(ErrMsg)
}
}
const judgment = (dataObj,dataItem,ErrMsg,throwMsg) => {
let toJudgment
if(dataItem == 'number'){
toJudgment = dataObj[dataItem] > 99 || dataObj[dataItem] < 1
}
else if(dataItem == "elevation"){
toJudgment = dataObj[dataItem] > 90 || dataObj[dataItem] < 0
}
else if(dataItem == "azimuth"){
toJudgment = dataObj[dataItem] > 359.999 || dataObj[dataItem] < 0 || dataObj[dataItem].indexOf('.') == '0'
}
else if(dataItem == "signal"){
toJudgment = dataObj[dataItem] > 99 || dataObj[dataItem] < 0
}
if(dataObj[dataItem] == ''){
stuck(dataObj,dataItem,'error',true,ErrMsg+'不能为空',throwMsg)
}
else if(toJudgment){
stuck(dataObj,dataItem,'error',true,'非法的'+ErrMsg+'数据',throwMsg)
}
else{
stuck(dataObj,dataItem,'success',false,'',false)
if(throwMsg && Number(dataObj[dataItem]) < 10){
dataObj[dataItem] = '0' + Number(dataObj[dataItem])
}
}
}
const handleInput = () => {
satellite.value.forEach((element,index) => {
let elevationMark = false
let azimuthMark = false
let signalMark = false
element.number = inputFilter(element.number)
element.elevation = inputFilter(element.elevation)
element.azimuth = inputFilter(element.azimuth)
element.signal = inputFilter(element.signal)
if(element.number == ''){
element.numberStatus = 'error'
element.numberCheck = true
}
else if(Number(element.number) == '0'){
element.numberStatus = 'error'
element.numberCheck = true
element.number = inputFilter(element.number,false)
element.elevation = inputFilter(element.elevation,false)
element.azimuth = inputFilter(element.azimuth,true)
element.signal = inputFilter(element.signal,false)
if(Number(element.number) == '0' && element.number !== ''){
stuck(element,'number','error',true,'卫星编号不能为0',false)
}
else{
element.numberStatus = 'success'
element.numberCheck = false
judgment(element,'number','卫星编号',false)
}
if(element.elevation == ''){
element.elevationStatus = 'error'
element.elevationCheck = true
}
else if(Number(element.elevation) == '0'){
if(Number(element.elevation) == '0' && element.elevation !== ''){
stuck(element,'elevation','success',false,'',false)
elevationMark = true
element.elevationStatus = 'success'
element.elevationCheck = false
}
else {
element.elevationStatus = 'success'
element.elevationCheck = false
judgment(element,'elevation','仰角',false)
}
if(element.azimuth == ''){
element.azimuthStatus = 'error'
element.azimuthCheck = true
}
else if(Number(element.azimuth) == '0'){
if(Number(element.azimuth) == '0' && element.azimuth !== ''){
stuck(element,'azimuth','success',false,'',false)
azimuthMark = true
element.azimuthStatus = 'success'
element.azimuthCheck = false
}
else {
element.azimuthStatus = 'success'
element.azimuthCheck = false
judgment(element,'azimuth','方位角',false)
}
if(elevationMark && azimuthMark){
element.elevationStatus = 'warning'
element.elevationCheck = true
element.azimuthStatus = 'warning'
element.azimuthCheck = true
}
if(element.signal == ''){
element.signalStatus = 'error'
element.signalCheck = true
}
else if(Number(element.signal) == '0'){
element.signalStatus = 'warning'
element.signalCheck = true
if(Number(element.signal) == '0' && element.signal !== ''){
stuck(element,'signal','warning',true,'信号强度为0,<br>该数据可能是无效数据,<br>建议修改或删除',false)
signalMark = true
}
else{
element.signalStatus = 'success'
element.signalCheck = false
signalMark = false
judgment(element,'signal','信号强度',false)
}
if(elevationMark && azimuthMark){
stuck(element,'elevation','warning',true,'仰角和方位角同时为0,<br>该数据可能是无效数据,<br>建议修改或删除',false)
stuck(element,'azimuth','warning',true,'',false)
}
if(elevationMark && azimuthMark || signalMark){
allowCalaulation.value = false
}else{
}
else{
allowCalaulation.value = true
}
})
@@ -339,72 +365,17 @@ const calculation = () => {
let satelliteBox = {}
let satelliteGSV = []
satellite.value.forEach((element,index) => {
if(element.number == ''){
message.error('卫星编号不能为空')
element.numberStatus = 'error'
element.numberCheck = true
throw new Error("卫星编号不能为空")
}
if(element.elevation == ''){
message.error('仰角不能为空')
element.elevationStatus = 'error'
element.elevationCheck = true
throw new Error("仰角不能为空")
}
if(element.azimuth == ''){
message.error('方位角不能为空')
element.azimuthStatus = 'error'
element.azimuthCheck = true
throw new Error("方位角不能为空")
}
if(element.signal == ''){
message.error('信号强度不能为空')
element.signalStatus = 'error'
element.signalCheck = true
throw new Error("信号强度不能为空")
}
if(Number(element.number) == '0'){
message.error('卫星编号不能为0')
element.numberStatus = 'error'
element.numberCheck = true
throw new Error("卫星编号不能为0")
}
if(Number(element.number) > 99 || Number(element.number) < 1){
message.error('非法的卫星编号')
inputValue.numberStatus = 'error'
inputValue.numberCheck = true
throw new Error("非法的卫星编号")
}
if(Number(element.elevation) > 90 || Number(element.elevation) < 0){
message.error('非法的仰角数据')
inputValue.elevationStatus = 'error'
inputValue.elevationCheck = true
throw new Error("非法的仰角数据")
}
if(Number(element.azimuth) > 359.999 || Number(element.azimuth) < 0){
message.error('非法的方位角数据')
inputValue.azimuthStatus = 'error'
inputValue.azimuthCheck = true
throw new Error("非法的方位角数据")
}
if(Number(element.signal) > 99 || Number(element.signal) < 0){
message.error('非法的信号强度数据')
inputValue.signalStatus = 'error'
inputValue.signalCheck = true
throw new Error("非法的信号强度数据")
}
if(element.number.length < 2){
element.number = '0' + element.number
}
if(element.elevation.length < 2){
element.elevation = '0' + element.elevation
judgment(element,'number','卫星编号',true)
judgment(element,'elevation','仰角',true)
judgment(element,'azimuth','方位角',true)
judgment(element,'signal','信号强度',true)
if(Number(element.number) == '0' && element.number !== ''){
stuck(element,'number','error',true,'卫星编号不能为0',true)
}
element.azimuth = Number(element.azimuth).toString()
if(element.azimuth.length < 2){
element.azimuth = '0' + element.azimuth
}
if(element.signal.length < 2){
element.signal = '0' + element.signal
}
satelliteBox[element.number] = element.number + ',' + element.elevation + ',' + element.azimuth + ',' + element.signal
satelliteGSV.push(satelliteBox[element.number])
})

View File

@@ -1,7 +1,7 @@
<template>
<n-grid style="width: 96vw;" class="mx-auto" :cols="2">
<n-gi style="padding-top: 0; padding-bottom: 0;" class="w-h-full p">
<n-scrollbar style="max-height: 88vh; border: 1px solid #eee">
<n-gi style="padding-top: 1.5vh; padding-bottom: 0;" class="w-h-full p">
<n-scrollbar style="max-height: 86vh; border: 1px solid #eee">
<n-dynamic-input
v-model:value="check"
:on-create="onCreate"
@@ -21,8 +21,8 @@
<n-button class="mx-auto" :disabled="check.length == 0 ? true : false" size="large" type="error" @click="delgeo">清空输入</n-button>
</div>
</n-gi>
<n-gi style="padding-top: 0; padding-bottom: 0;" class="w-h-full p">
<n-data-table :columns="columns" :data="data" :single-line="false" :pagination="pagination" :style="{ height: '88vh' }" flex-height />
<n-gi style="padding-top: 1.5vh; padding-bottom: 0;" class="w-h-full p">
<n-data-table :columns="columns" :data="data" :single-line="false" :pagination="pagination" :style="{ height: '86vh' }" flex-height />
<div style="margin-top: 1vh;" class="w-full flex flex-1">
<div style="width: 165px" class="mx-auto">
<n-select v-model:value="base" :options="options" />
@@ -35,7 +35,7 @@
<script setup lang="ts">
import { ref, h, watch } from "vue"
import { NGi, NGrid, NButton, NDynamicInput, NDataTable, NScrollbar, NInput, NSelect, NGradientText, useMessage, useDialog } from "naive-ui"
import { NGi, NGrid, NButton, NDynamicInput, NDataTable, NScrollbar, NInput, NSelect, NGradientText, useMessage, useDialog } from "naive-ui"
const message = useMessage()

View File

@@ -2,7 +2,6 @@
<n-space vertical justify="space-around" align="center" item-style="width: 50%;" class="gesture-recognition-config-view">
<n-form-item size="large" label-placement="left" label="翻页动画时长:" path="animationDuration">
<n-select
:disabled="!serialPort.isOpen"
placeholder="请选择翻页动画时长"
v-model:value="model.animationDuration"
:options="animationDurationOptions"
@@ -16,7 +15,6 @@
<n-form-item size="large" label-placement="left" label="日期显示时长:" path="dateDisplayDuration">
<n-select
:disabled="!serialPort.isOpen"
placeholder="请选择日期显示时长"
v-model:value="model.dateDisplayDuration"
:options="dateDisplayDurationOptions"
@@ -36,43 +34,27 @@
<script setup lang="ts">
import { ref } from 'vue'
import { NSpace, NFormItem, NSelect, useMessage } from 'naive-ui'
import { NSpace, NFormItem, NSelect } from 'naive-ui'
import ResetButtonView from '../ResetButtonView.vue'
import { animationDurationOptions, dateDisplayDurationOptions } from './data'
import { useSerialPortStore } from '@/stores/serialPort'
const message = useMessage()
const serialPort = useSerialPortStore()
const model = ref({
animationDuration : null,
dateDisplayDuration: null,
})
const onAnimationDurationUpdate = () => {
if (!serialPort.isOpen) {
message.error('请先连接无线通信模块并打开串口')
return
}
let cmd = `$SCANSP,${model.value.animationDuration}*`
cmd += cmd.length
cmd += '\r\n'
serialPort.write(cmd)
window.ipcRenderer.send('COM_WRITE',cmd)
}
const onDateDisplayDurationUpdate = () => {
if (!serialPort.isOpen) {
message.error('请先连接无线通信模块并打开串口')
return
}
let cmd = `$SETSDT,${model.value.dateDisplayDuration}*`
cmd += cmd.length
cmd += '\r\n'
serialPort.write(cmd)
window.ipcRenderer.send('COM_WRITE',cmd)
}
</script>

View File

@@ -51,7 +51,7 @@
</n-form-item>
<div class="text-center">
<n-button :disabled="!serialPort.isOpen" type="primary" size="large" @click="onClick">发送手势识别设置命令</n-button>
<n-button type="primary" size="large" @click="onClick">发送手势识别设置命令</n-button>
</div>
<ResetButtonView />
@@ -63,7 +63,6 @@ import { ref } from 'vue'
import { NSpace, NFormItem, NSlider, NSelect, NButton, useMessage } from 'naive-ui'
import ResetButtonView from '../ResetButtonView.vue'
import { MAX_DISTANCE, MIN_DISTANCE, timeOutOptions, intervalOptions, eventOptions } from './data'
import { useSerialPortStore } from '@/stores/serialPort'
const model = ref({
distance: -300,
@@ -74,13 +73,7 @@ const model = ref({
})
const message = useMessage()
const serialPort = useSerialPortStore()
const onClick = () => {
if (!serialPort.isOpen) {
message.error('请先连接无线通信模块并打开串口')
return
}
const value = model.value
if (!value.timeOut) {
message.error('请设置超时时间')
@@ -105,8 +98,7 @@ const onClick = () => {
let cmd = `$GESTE,0,1,${-value.distance},${value.timeOut},5,${value.interval},${value.ltr},${value.rtl}*`
cmd += cmd.length
cmd += '\r\n'
serialPort.write(cmd)
window.ipcRenderer.send('COM_WRITE',cmd)
}
</script>

View File

@@ -1,22 +1,23 @@
<template>
<div class="reset-button-container">
<n-button :disabled="!serialPort.isOpen" type="primary" size="large" @click="onResetBtnClick">恢复默认设置</n-button>
<n-button type="primary" size="large" @click="onResetBtnClick">恢复默认设置</n-button>
</div>
</template>
<script setup lang="ts">
import { onMounted } from 'vue'
import { NButton } from 'naive-ui'
import { useSerialPortStore } from '@/stores/serialPort'
const serialPort = useSerialPortStore()
const onResetBtnClick = () => {
if (!serialPort.isOpen) return
let cmd = `$RECOVERY,1*`
cmd += cmd.length
cmd += '\r\n'
serialPort.write(cmd)
window.ipcRenderer.send('COM_WRITE',cmd)
}
onMounted(() => {
window.ipcRenderer.send('COM_READY')
})
</script>
<style scoped lang="less">

View File

@@ -18,7 +18,7 @@
</template>
</n-slider>
<n-button :disabled="!serialPort.isOpen" type="primary" size="large" secondary @click="onBrightnessBtnClick">发送亮度设置命令</n-button>
<n-button type="primary" size="large" secondary @click="onBrightnessBtnClick">发送亮度设置命令</n-button>
</n-space>
</n-card>
@@ -29,35 +29,34 @@
<script setup lang="ts">
import { ref } from 'vue'
import { NSpace, NCard, NGrid, NGi, NP, NSlider, NButton } from 'naive-ui'
import { NSpace, NCard, NGrid, NGi, NP, NSlider, NButton, useMessage } from 'naive-ui'
import convert from 'color-convert'
import ResetButtonView from '../ResetButtonView.vue'
import { count, MIN, MAX } from './data'
import { useSerialPortStore } from '@/stores/serialPort'
const serialPort = useSerialPortStore()
const message = useMessage()
const onColorInputChange = (color, index) => {
if (!serialPort.isOpen) return
const rgb = convert.hex.rgb(color)
let cmd = `$LEDRGB,${index},${rgb[0]},${rgb[1]},${rgb[2]}*`
cmd += cmd.length
cmd += '\r\n'
serialPort.write(cmd)
window.ipcRenderer.send('COM_WRITE',cmd)
}
const brightness = ref(MIN)
const onBrightnessBtnClick = () => {
if (!serialPort.isOpen) return
let cmd = `$LEDBT,${brightness.value}*`
cmd += cmd.length
cmd += '\r\n'
serialPort.write(cmd)
window.ipcRenderer.send('COM_WRITE',cmd)
}
const connectErrMsg = (value: Boolean) => {
message.error('无法连接到串口设备')
}
window.ipcRenderer.receive('CANNOT_CONNECT',connectErrMsg)
</script>
<style scoped lang="less">

View File

@@ -16,26 +16,16 @@
<script setup lang="ts">
import { ref } from 'vue'
import { NSpace, NSelect, useMessage } from 'naive-ui'
import { NSpace, NSelect } from 'naive-ui'
import ResetButtonView from '../ResetButtonView.vue'
import { options } from './data'
import { useSerialPortStore } from '@/stores/serialPort'
const message = useMessage()
const serialPort = useSerialPortStore()
const value = ref(null)
const onSelectUpdate = () => {
if (!serialPort.isOpen) {
message.error('请先连接无线通信模块并打开串口')
return
}
let cmd = `$SDEVENT,${value.value}*`
cmd += cmd.length
cmd += '\r\n'
serialPort.write(cmd)
window.ipcRenderer.send('COM_WRITE',cmd)
}
</script>

View File

@@ -75,13 +75,15 @@
<script lang="ts" setup>
import { ref } from 'vue'
import { NForm, NFormItem, NGrid, NFormItemGi, NSpace, NInputNumber, NButton, FormRules, useMessage } from 'naive-ui'
import { NForm, NFormItem, NGrid, NFormItemGi, NSpace, NInputNumber, NButton, FormRules, useMessage, useDialog } from 'naive-ui'
import { MAX_LNG, MIN_LNG, MAX_LAT, MIN_LAT } from './data'
const emit = defineEmits([ 'submit', 'reset' ])
const message = useMessage()
const dialog = useDialog()
interface ModelType {
start_point: {
lng: number | null,
@@ -150,13 +152,22 @@ const handleCalculateButtonClick = (e: MouseEvent) => {
const handleClearButtonClick = (e: MouseEvent) => {
e.preventDefault()
model.value.start_point.lng = null
model.value.start_point.lat = null
model.value.end_point.lng = null
model.value.end_point.lat = null
emit('reset')
dialog.warning({
title: '警告',
content: '确定要清除数据吗?',
positiveText: '确定',
negativeText: '返回',
onPositiveClick: () => {
model.value.start_point.lng = null
model.value.start_point.lat = null
model.value.end_point.lng = null
model.value.end_point.lat = null
emit('reset')
},
onNegativeClick: () => {
message.error('已返回')
}
})
}
</script>

View File

@@ -1,24 +1,27 @@
<template>
<n-button :disabled="!serialPort.isOpen" type="primary" size="large" @click="onClick">清理屏幕</n-button>
<n-button type="primary" size="large" @click="onClick">清理屏幕</n-button>
</template>
<script setup lang="ts">
import { onMounted } from 'vue'
import { NButton, useMessage } from 'naive-ui'
import { useSerialPortStore } from '@/stores/serialPort'
const emit = defineEmits([ 'clear' ])
const message = useMessage()
const serialPort = useSerialPortStore()
const onClick = () => {
if (!serialPort.isOpen) {
message.error('请连接并打开串口设备')
return
}
serialPort.write('$LEDCL,0*9\r\n')
window.ipcRenderer.send('COM_WRITE','$LEDCL,0*9\r\n')
emit('clear')
}
const connectErrMsg = (value: Boolean) => {
message.error('无法连接到串口设备')
}
window.ipcRenderer.receive('CANNOT_CONNECT',connectErrMsg)
onMounted(() => {
window.ipcRenderer.send('COM_READY')
})
</script>

View File

@@ -8,14 +8,11 @@
<script setup lang="ts">
import { ref } from 'vue'
import { NGrid, NGi, useMessage } from 'naive-ui'
import { NGrid, NGi } from 'naive-ui'
import convert from 'color-convert'
import LED from './components/LED.vue'
import { useSerialPortStore } from '@/stores/serialPort'
import { ROWS, COLS } from './data'
const message = useMessage()
let color
const changeColor = (value) => {
if (!value) return
@@ -30,12 +27,7 @@ const clear = () => {
ledRef.changeColor('#000000')
});
}
const serialPort = useSerialPortStore()
const onClick = (index: number) => {
if (!serialPort.isOpen) {
message.error('请连接并打开串口设备')
return
}
if (!color) return
ledRefs.value[index].changeColor(color)
@@ -49,7 +41,7 @@ const onClick = (index: number) => {
cmd += cmd.length
cmd += '\r\n'
serialPort.write(cmd)
window.ipcRenderer.send('COM_WRITE',cmd)
}
defineExpose( { changeColor, clear })

View File

@@ -7,27 +7,19 @@
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { ref, onMounted } from 'vue'
import { NGrid, NGi, useMessage } from 'naive-ui'
import convert from 'color-convert'
import LED from './components/LED.vue'
import { useSerialPortStore } from '@/stores/serialPort'
import { ROWS, COLS } from './data'
const message = useMessage()
const ledRefs = ref()
const serialPort = useSerialPortStore()
const showChar = (index, data, color) => {
if (!data) return
if (!serialPort.isOpen) {
message.error('请连接并打开串口设备')
return
}
clearArea(index)
if (!color) return
@@ -70,7 +62,7 @@ const showChar = (index, data, color) => {
let cmd = `$LEDAREA,${origin},0,${I},${II},${III},${IV},${rgb[0]},${rgb[1]},${rgb[2]}*`
cmd += cmd.length
cmd += '\r\n'
serialPort.write(cmd)
window.ipcRenderer.send('COM_WRITE',cmd)
}
}
@@ -85,19 +77,25 @@ const clearArea = (areaIndex) => {
let cmd = `$LEDAREA,${origin},0,0,0,0,0,0,0,0*`
cmd += cmd.length
cmd += '\r\n'
serialPort.write(cmd)
window.ipcRenderer.send('COM_WRITE',cmd)
}
const clearAll = () => {
if (!serialPort.isOpen) {
message.error('请连接并打开串口设备')
return
}
ledRefs.value.forEach(ledRef => {
ledRef.$el.children[0].style.backgroundColor = 'black'
})
serialPort.write('$LEDCL,0*9\r\n')
window.ipcRenderer.send('COM_WRITE','$LEDCL,0*9\r\n')
}
const connectErrMsg = (value: Boolean) => {
message.error('无法连接到串口设备')
}
window.ipcRenderer.receive('CANNOT_CONNECT',connectErrMsg)
onMounted(() => {
window.ipcRenderer.send('COM_READY')
})
defineExpose( { showChar, clearArea, clearAll })
</script>

View File

@@ -1,51 +1,93 @@
<template>
<n-space justify="space-around" class="control-button-group-view">
<n-button size="large" @click="onAdd" >添加</n-button>
<n-button size="large" @click="onSubmit">提交</n-button>
<n-button size="large" @click="onClear" >清除</n-button>
<n-button size="large" type="info" @click="onAdd" >添加</n-button>
<n-button size="large" type="primary" @click="onSubmit">提交</n-button>
<n-button size="large" type="error" @click="onClear" >清除</n-button>
</n-space>
</template>
<script setup lang="ts">
import { inject } from 'vue'
import { NSpace, NButton, useMessage } from 'naive-ui'
import { NSpace, NButton, useMessage, useDialog } from 'naive-ui'
import { Satellite } from '@/api/satellite/type.d'
const emit = defineEmits([ 'submit', 'clear' ])
const message = useMessage()
const dialog = useDialog()
const satellites = inject('satellites')
const onAdd = () => satellites.value.push(new Satellite())
const onClear = () => {
satellites.value.splice(1, satellites.value.length - 1)
satellites.value[0].svid = null
satellites.value[0].cn0 = null
satellites.value[0].ele = null
satellites.value[0].az = null
emit('clear')
dialog.warning({
title: '警告',
content: '确定要清除数据吗?',
positiveText: '确定',
negativeText: '返回',
onPositiveClick: () => {
satellites.value.splice(1, satellites.value.length - 1)
satellites.value[0].svid = null
satellites.value[0].cn0 = null
satellites.value[0].ele = null
satellites.value[0].az = null
satellites.value.forEach(satellite => {
satellite.svidcheck = ''
satellite.cn0check = ''
satellite.elecheck = ''
satellite.azcheck = ''
})
emit('clear')
},
onNegativeClick: () => {
message.error('已返回')
}
})
}
const onSubmit = () => {
try {
let nowsate = []
satellites.value.forEach(satellite => {
if (!satellite.svid || isNaN(satellite.svid)) {
satellite.svidcheck = 'error'
satellite.svidmsg = false
throw new Error('卫星编号数据有误')
}
else{
if(nowsate.indexOf(satellite.svid) == -1){
satellite.svidcheck = ''
nowsate.push(satellite.svid)
}else{
satellite.svidcheck = 'error'
satellite.svidmsg = true
throw new Error('卫星编号数据重复')
}
}
if (!satellite.cn0 || isNaN(satellite.cn0)) {
satellite.cn0check = 'error'
throw new Error('载噪比数据有误')
}
else{
satellite.cn0check = ''
}
if (!satellite.ele || isNaN(satellite.ele)) {
satellite.elecheck = 'error'
throw new Error('仰角数据有误')
}
else{
satellite.elecheck = ''
}
if (!satellite.az || isNaN(satellite.az)) {
satellite.azcheck = 'error'
throw new Error('方位角数据有误')
}
else{
satellite.azcheck = ''
}
})
emit('submit')
} catch (e) {
console.error(e)

View File

@@ -1,24 +1,46 @@
<template>
<n-grid :cols="24" :x-gap="18">
<n-form-item-gi ref="svidFormItemGiRef" :span="12" label="编 号">
<n-input-number :show-button="false" v-model:value="satellite.svid" placeholder="请输入卫星编号" />
<div>
<n-input-number :show-button="false" :status="satellite.svidcheck" v-model:value="satellite.svid" placeholder="请输入卫星编号" min="0" max="99" />
<n-gradient-text :size="12" type="error" v-show="satellite.svidcheck == '' || satellite.svidcheck == undefined ? false : true">
<div v-html="satellite.svidmsg ? '卫星编号数据重复' : '卫星编号数据有误'"></div>
</n-gradient-text>
</div>
</n-form-item-gi>
<n-form-item-gi :span="12" label="载噪比" path="cn0">
<n-input-number :show-button="false" v-model:value="satellite.cn0" placeholder="请输入载噪比" />
<div>
<n-input-number :show-button="false" :status="satellite.cn0check" v-model:value="satellite.cn0" placeholder="请输入载噪比" min="0" max="60" />
<n-gradient-text :size="12" type="error" v-show="satellite.cn0check == '' || satellite.cn0check == undefined ? false : true">
载噪比数据有误
</n-gradient-text>
</div>
</n-form-item-gi>
<n-form-item-gi :span="12" label="仰 角" path="ele">
<n-input-number :show-button="false" v-model:value="satellite.ele" placeholder="请输入仰角" min="0" max="90" />
<div>
<n-input-number :show-button="false" :status="satellite.elecheck" v-model:value="satellite.ele" placeholder="请输入仰角" min="0" max="90" />
<n-gradient-text :size="12" type="error" v-show="satellite.elecheck == '' || satellite.elecheck == undefined ? false : true">
仰角数据有误
</n-gradient-text>
</div>
</n-form-item-gi>
<n-form-item-gi :span="12" label="方位角" path="az">
<n-input-number :show-button="false" v-model:value="satellite.az" placeholder="请输入方位角" min="0" max="360" />
<div>
<n-input-number :show-button="false" :status="satellite.azcheck" v-model:value="satellite.az" placeholder="请输入方位角" min="0" max="360" />
<n-gradient-text :size="12" type="error" v-show="satellite.azcheck == '' || satellite.azcheck == undefined ? false : true">
方位角数据有误
</n-gradient-text>
</div>
</n-form-item-gi>
</n-grid>
</template>
<script setup lang="ts">
import { NGrid, NFormItemGi, NInputNumber } from 'naive-ui'
import { NGrid, NFormItemGi, NInputNumber, NGradientText, useMessage } from 'naive-ui'
import { Satellite } from '@/api/satellite/type.d'
const message = useMessage()
defineProps({
satellite: Satellite
})

View File

@@ -8,7 +8,6 @@ import left from '@/assets/left.png'
import right from '@/assets/right.png'
import { LineBreakParser } from '@/utils/parser'
import { useSerialPortStore, SerialPortEventType } from '@/stores/serialPort'
let timeOutID
const src = ref(null)
@@ -31,8 +30,8 @@ const showAnimation = (type: number) => {
const decoder = new TextDecoder()
const parser = new LineBreakParser()
const onSerialPortData = (data: Uint8Array) => {
const lineArr = parser.parse(decoder.decode(data))
const onSerialPortData = (value: Uint8Array) => {
const lineArr = parser.parse(decoder.decode(value))
if (lineArr.length === 0) return
const infoArr = lineArr[0].split(',')
@@ -42,8 +41,8 @@ const onSerialPortData = (data: Uint8Array) => {
showAnimation(parseInt(infoArr[1][0]))
}
const serialPort = useSerialPortStore()
serialPort.addEventListener(SerialPortEventType.data, onSerialPortData)
window.ipcRenderer.send('COM_ON')
window.ipcRenderer.receive('COM_LISTENER',onSerialPortData)
</script>
<style lang="less" scoped>

View File

@@ -38,7 +38,7 @@
</n-form-item>
<div class="text-right">
<n-button :disabled="!serialPort.isOpen" type="primary" size="large" @click="onClick">发送配置指令</n-button>
<n-button type="primary" size="large" @click="onClick">发送配置指令</n-button>
</div>
</n-space>
@@ -48,7 +48,6 @@
import { ref, onMounted } from 'vue'
import { NSpace, NFormItem, NSlider, NSelect, NButton, useMessage } from 'naive-ui'
import { MAX_DISTANCE, MIN_DISTANCE, timeOutOptions, intervalOptions } from './data'
import { useSerialPortStore, SerialPortEventType } from '@/stores/serialPort'
import { LineBreakParser } from '@/utils/parser'
const message = useMessage()
@@ -59,13 +58,7 @@ const model = ref({
interval: null,
})
const serialPort = useSerialPortStore()
const onClick = () => {
if (!serialPort.isOpen) {
message.error('请先连接无线通信模块并打开串口')
return
}
const value = model.value
if (!value.timeOut) {
message.error('请设置超时时间')
@@ -80,14 +73,13 @@ const onClick = () => {
let cmd = `$GESTE,0,1,${-value.distance},${value.timeOut},5,${value.interval},0,1*`
cmd += cmd.length
cmd += '\r\n'
serialPort.write(cmd)
window.ipcRenderer.send('COM_WRITE',cmd)
}
const decoder = new TextDecoder()
const parser = new LineBreakParser()
const onSerialPortData = (data: Uint8Array) => {
const result: Array<String> = parser.parse(decoder.decode(data))
const onSerialPortData = (value: Uint8Array) => {
const result: Array<String> = parser.parse(decoder.decode(value))
if (result.length === 0) return
const infoArr: Array<String> = result[0].split(',')
@@ -101,7 +93,16 @@ const onSerialPortData = (data: Uint8Array) => {
}
}
onMounted(() => serialPort.addEventListener(SerialPortEventType.data, onSerialPortData))
const connectErrMsg = (value: Boolean) => {
message.error('无法连接到串口设备')
}
window.ipcRenderer.receive('CANNOT_CONNECT',connectErrMsg)
onMounted(() => {
window.ipcRenderer.send('COM_ON')
window.ipcRenderer.receive('COM_LISTENER',onSerialPortData)
})
</script>
<style lang="less" scoped>

View File

@@ -1,12 +1,12 @@
<template>
<n-button type="primary" size="large" :disabled="!serialPort.isOpen" @click="onBtnClick">发送配置命令</n-button>
<n-button type="primary" size="large" @click="onBtnClick">发送配置命令</n-button>
</template>
<script setup lang="ts">
import { inject } from 'vue'
import { NButton } from 'naive-ui'
import { useSerialPortStore } from '@/stores/serialPort'
import { inject, onMounted } from 'vue'
import { NButton, useMessage } from 'naive-ui'
const message = useMessage()
const dataArr = inject('dataArr')
const current = inject('current')
@@ -25,16 +25,22 @@ const onBtnClick = () => {
}
}
const serialPort = useSerialPortStore()
const sendCMD = (num: number, index: number, value: string) => {
if (!value) return
if (!serialPort.isOpen) return
let cmd = `$DIGITCTL,${num},${index},${value}*`
cmd += cmd.length
cmd += '\r\n'
serialPort.write(cmd)
window.ipcRenderer.send('COM_WRITE',cmd)
}
const connectErrMsg = (value: Boolean) => {
message.error('无法连接到串口设备')
}
window.ipcRenderer.receive('CANNOT_CONNECT',connectErrMsg)
onMounted(() => {
window.ipcRenderer.send('COM_READY')
})
</script>

View File

@@ -8,14 +8,16 @@
import { reactive } from "vue"
import { use } from "echarts/core"
import { useMessage } from 'naive-ui'
import { CanvasRenderer } from "echarts/renderers"
import { LineChart } from "echarts/charts"
import { GridComponent, LegendComponent } from "echarts/components"
import VChart from "vue-echarts"
import { useSerialPortStore, SerialPortEventType } from '@/stores/serialPort'
import { LineBreakParser } from '@/utils/parser'
const message = useMessage()
// TODO: 调研是否需要以及如何释放echart对象
use([
CanvasRenderer,
@@ -87,13 +89,18 @@ const handle = (data: string) => {
const decoder = new TextDecoder()
const parser = new LineBreakParser()
const onSerialPortData = (data: Uint8Array) => {
const lineArr = parser.parse(decoder.decode(data))
const onSerialPortData = (value: Uint8Array) => {
const lineArr = parser.parse(decoder.decode(value))
lineArr.forEach(line => handle(line))
}
const serialPort = useSerialPortStore()
serialPort.addEventListener(SerialPortEventType.data, onSerialPortData)
const connectErrMsg = (value: Boolean) => {
message.error('无法连接到串口设备')
}
window.ipcRenderer.receive('CANNOT_CONNECT',connectErrMsg)
window.ipcRenderer.send('COM_ON')
window.ipcRenderer.receive('COM_LISTENER',onSerialPortData)
const resetOption = (pins) => {
option.legend.data = pins

View File

@@ -4,7 +4,7 @@
<n-button
type="primary"
class="w-full"
:disabled="!serialPort.isOpen || !option"
:disabled="!option"
@click="onBtnClick">
监控选择的设备
</n-button>
@@ -17,16 +17,13 @@ import { NSpace, NSelect, NButton, useMessage } from 'naive-ui'
import { options } from './data'
import { useSerialPortStore, SerialPortEventType } from '@/stores/serialPort'
import { LineBreakParser } from '@/utils/parser'
const message = useMessage()
const serialPort = useSerialPortStore()
const option = ref(null)
const onBtnClick = async () => {
if ( !serialPort.isOpen || !option.value) return
if (!option.value) return
const dataArr = option.value.split(';')
if (dataArr.length != 2) return
@@ -36,14 +33,14 @@ const onBtnClick = async () => {
const count = portArrStr.split(',').length
const command = `$MONITOR,${type},${count},${portArrStr}*${type.length + count.toString().length + portArrStr.length + 12}\r\n`
await serialPort.write(command)
await window.ipcRenderer.send('COM_WRITE',command)
}
const decoder = new TextDecoder()
const parser = new LineBreakParser()
const onSerialPortData = (data: Uint8Array) => {
const onSerialPortData = (value: Uint8Array) => {
debugger
const result: Array<String> = parser.parse(decoder.decode(data))
const result: Array<String> = parser.parse(decoder.decode(value))
if (result.length === 0) return
const infoArr: Array<String> = result[0].split(',')
@@ -56,7 +53,10 @@ const onSerialPortData = (data: Uint8Array) => {
message.error('配置失败')
}
}
onMounted(() => serialPort.addEventListener(SerialPortEventType.data, onSerialPortData))
onMounted(() => {
window.ipcRenderer.send('COM_ON')
window.ipcRenderer.receive('COM_LISTENER',onSerialPortData)
})
</script>
<style scoped>

View File

@@ -1,5 +1,5 @@
<template>
<n-form ref="formRef" :disabled="!serialPort.isOpen" :model="modelRef" :rules="rules">
<n-form ref="formRef" :model="modelRef" :rules="rules">
<n-form-item path="netid" label="组网ID">
<n-input
v-model:value="modelRef.netid"
@@ -26,7 +26,7 @@
/>
</n-form-item>
<n-form-item>
<n-button :disabled="!serialPort.isOpen" size="large" type="primary" @click="handleValidateButtonClick">
<n-button size="large" type="primary" @click="handleValidateButtonClick">
配 置
</n-button>
</n-form-item>
@@ -34,13 +34,11 @@
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { ref, onMounted } from 'vue'
import { NForm, NFormItem, NInput, NSelect, NButton, useMessage } from 'naive-ui'
import type {FormRules, FormItemRule } from 'naive-ui'
import { channelOptions, baudRateOptions, queryCMD, configCMD } from './data'
import { useSerialPortStore, SerialPortEventType } from '@/stores/serialPort'
const message = useMessage()
interface ModelType {
@@ -73,11 +71,23 @@ const rules: FormRules = {
channel: [
{
required: true,
validator (_: FormItemRule, value: string) {
if (!value) {
return new Error('请选择信道')
}
return true
},
}
],
baudRate: [
{
required: true,
validator (_: FormItemRule, value: string) {
if (!value) {
return new Error('请选择波特率')
}
return true
},
}
]
}
@@ -94,19 +104,15 @@ const handleValidateButtonClick = (e: MouseEvent) => {
return
}
if (!serialPort.isOpen) {
message.error('请先连接无线通信模块并打开串口')
return
}
configWireless()
})
}
const queryWireless = async () => {
await serialPort.write(queryCMD)
const queryWireless = (value: Boolean) => {
window.ipcRenderer.send('COM_WRITE',queryCMD)
}
const configWireless = async () => {
const configWireless = () => {
const netid = parseInt(modelRef.value.netid as string)
configCMD[4] = netid / 100
configCMD[5] = netid % 100
@@ -114,8 +120,9 @@ const configWireless = async () => {
configCMD[11] = modelRef.value.channel as number
configCMD[17] = getCheckSum(configCMD)
await serialPort.write(configCMD)
window.ipcRenderer.send('COM_WRITE',configCMD)
}
const getCheckSum = (cmd: Uint8Array) => {
let checkbyte = 0
// 指令的最后一位是存储前面所有位的校验和
@@ -126,17 +133,25 @@ const getCheckSum = (cmd: Uint8Array) => {
return checkbyte & 0x00FF
}
const serialPort = useSerialPortStore()
serialPort.addEventListener(SerialPortEventType.afterOpen, queryWireless)
serialPort.addEventListener(SerialPortEventType.data, (data: Uint8Array) => {
switch (data[1]) {
const connectErrMsg = (value: Boolean) => {
message.error('无法连接到串口设备')
}
onMounted(() => {
queryWireless()
})
window.ipcRenderer.receive('CANNOT_CONNECT',connectErrMsg)
window.ipcRenderer.receive('NOW_OPEN',queryWireless)
window.ipcRenderer.receive('COM_LISTENER', (value: Uint8Array) => {
switch (value[1]) {
case 0x5B:
message.success('配置设备信息成功')
break;
case 0x5D:
modelRef.value.netid = ('0000' + (Number(data[4])*100 + data[5])).slice(-4)
modelRef.value.channel = data[11]
modelRef.value.baudRate = data[9]
modelRef.value.netid = ('0000' + (Number(value[4])*100 + value[5])).slice(-4)
modelRef.value.channel = value[11]
modelRef.value.baudRate = value[9]
break;
}
})

View File

@@ -47,7 +47,7 @@ const show = computed(() => route.path != '/' && route.path != '/category' )
.button-background {
background-color: rgba(0,0,0,0.4);
border-radius: 48px;
padding-top: 6px;
padding-top: 5px;
.router-back-button {
margin-left: 18px;

View File

@@ -1,5 +1,5 @@
<template>
<router-link :to="`/course/${course.id}`">
<router-link v-if="course.thumbnail=='semester'?false:true" :to="`/course/${course.id}`">
<n-card
v-if="course.thumbnail=='Placeholder'?false:true"
embedded
@@ -12,6 +12,7 @@
<!-- {{ course.description }} -->
</n-card>
</router-link>
<h2 class="semester" v-if="course.thumbnail=='semester'?true:false">{{ course.name }}</h2>
</template>
<script setup lang="ts">
@@ -40,4 +41,8 @@ const getImageUrl = (imageFileName: string) => {
padding-bottom: 12px;
}
}
.semester {
color: #fafafc;
font-size:36px;
}
</style>

View File

@@ -5,26 +5,26 @@
<n-carousel ref="carouselRef" show-arrow :show-dots="false" :loop="false" @update:current-index="onCurrentIndexUpdate">
<template #arrow="{ prev, next }">
<div class="custom-arrow">
<n-button text class="custom-arrow-left" @click="prev">
<n-button text :style="isFullscreen ? 'margin-left: 0;' : ''" class="custom-arrow-left" @click="prev">
<n-icon>
<ArrowBack />
</n-icon>
</n-button>
<n-button text class="custom-arrow-right" @click="next">
<n-button text :style="isFullscreen ? 'margin-right: 0;' : ''" class="custom-arrow-right" @click="next">
<n-icon>
<ArrowForward />
</n-icon>
</n-button>
</div>
<n-button text class="fullscreen" @click="onFullscreenClick">
<n-button text :style="isFullscreen ? 'margin-top: 5vh;margin-right:-1.88vw;' : ''" class="fullscreen" @click="onFullscreenClick">
<n-icon>
<component :is="isFullscreen ? ZoomIn : ZoomOut"/>
</n-icon>
</n-button>
</template>
<img v-for="n in course.imageCount" :src="getImageUrl(n + '.JPG')">
<img :style="isFullscreen ? 'width:100vw;margin-top:5vh;' : ''" v-for="n in course.imageCount" :src="getImageUrl(n + '.JPG')">
</n-carousel>
<n-scrollbar ref="scrollbarRef" x-scrollable trigger="none">
@@ -44,8 +44,8 @@
import { ref, watch, onMounted } from 'vue'
import { NSpace, NScrollbar, NH2, NCarousel, NButton, NIcon } from 'naive-ui'
import {
ArrowBackIosFilled as ArrowBack,
ArrowForwardIosFilled as ArrowForward,
ArrowBackIosTwotone as ArrowBack,
ArrowForwardIosTwotone as ArrowForward,
ZoomOutMapFilled as ZoomOut,
ZoomInMapFilled as ZoomIn,
} from '@vicons/material'
@@ -55,8 +55,6 @@ const props = defineProps({
course: Course
})
const isFullscreen = ref<Boolean>(document.fullscreenElement != null)
const carouselRef = ref<HTMLElement | null>(null)
const index = ref()
@@ -113,9 +111,10 @@ const getImageUrl = (imageFileName: string) => {
}
.fullscreen {
background-color: rgba(0,0,0,0.4);
position: absolute;
top: 0;
right: 24px;
right: 1.92vw;
}
.custom-arrow {
@@ -129,10 +128,12 @@ const getImageUrl = (imageFileName: string) => {
align-items: center;
.custom-arrow-left {
margin-left: 34px;
background-color: rgba(0,0,0,0.4);
margin-left: 1.95vw;
}
.custom-arrow-right {
margin-right: 24px;
background-color: rgba(0,0,0,0.4);
margin-right: 1.95vw;
}
}