新版本学习机
This commit is contained in:
1
src/render/views/CalculationArea/index.ts
Normal file
1
src/render/views/CalculationArea/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default as CalculationArea } from './index.vue'
|
||||
507
src/render/views/CalculationArea/index.vue
Normal file
507
src/render/views/CalculationArea/index.vue
Normal file
@@ -0,0 +1,507 @@
|
||||
<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-dynamic-input
|
||||
v-model:value="geodata"
|
||||
:on-create="onCreate"
|
||||
:on-remove="onRemove"
|
||||
>
|
||||
<template #default="{ value }">
|
||||
<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>
|
||||
</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>
|
||||
</n-gradient-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</n-dynamic-input>
|
||||
</n-scrollbar>
|
||||
<v-chart style="max-height: 39vh; 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 />
|
||||
<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" />
|
||||
</div>
|
||||
<n-button class="mx-auto" :disabled="data.length == 0 ? true : false" size="large" type="error" @click="delall">清除数据</n-button>
|
||||
</div>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, h, watch, reactive } from "vue"
|
||||
import * as echarts from "echarts"
|
||||
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"
|
||||
|
||||
const message = useMessage()
|
||||
|
||||
const dialog = useDialog()
|
||||
|
||||
const geodata = ref([
|
||||
{
|
||||
lat: "",
|
||||
latStatus: "",
|
||||
latCheck: "",
|
||||
lng: "",
|
||||
lngStatus: "",
|
||||
lngCheck: ""
|
||||
}
|
||||
])
|
||||
|
||||
const onCreate = () => {
|
||||
return {
|
||||
lat: "",
|
||||
latStatus: "",
|
||||
latCheck: "",
|
||||
lng: "",
|
||||
lngStatus: "",
|
||||
lngCheck: ""
|
||||
}
|
||||
}
|
||||
|
||||
const unit = ref('平方米/m²')
|
||||
|
||||
const options = [
|
||||
{
|
||||
label:"平方米/m²",
|
||||
value:'平方米/m²'
|
||||
},
|
||||
{
|
||||
label:"平方千米/km²",
|
||||
value:'平方千米/km²'
|
||||
}]
|
||||
|
||||
const columns = ref([
|
||||
{
|
||||
title: '经纬度数据',
|
||||
key: 'latandlng',
|
||||
render (row) {
|
||||
const tags = row.latandlng.map((DataTag) => {
|
||||
return h(
|
||||
NScrollbar,
|
||||
{
|
||||
style: {
|
||||
whiteSpace: 'pre-wrap'
|
||||
}
|
||||
},
|
||||
{
|
||||
default: () => `经度:${DataTag[0]}\n纬度:${DataTag[1]}\n\n`
|
||||
}
|
||||
)
|
||||
})
|
||||
return tags
|
||||
}
|
||||
},
|
||||
{
|
||||
title: `面积(单位:${ unit.value })`,
|
||||
key: 'area'
|
||||
},
|
||||
{
|
||||
title: '轮廓',
|
||||
key: 'operate',
|
||||
fixed: 'right',
|
||||
align: 'center',
|
||||
render (row) {
|
||||
return h(
|
||||
NButton,
|
||||
{
|
||||
strong: true,
|
||||
tertiary: true,
|
||||
size: 'large',
|
||||
type: 'info',
|
||||
onClick: () => drawContour(row)
|
||||
},
|
||||
{ default: () => '生成轮廓' }
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'operate',
|
||||
fixed: 'right',
|
||||
align: 'center',
|
||||
render (row) {
|
||||
return h(
|
||||
NButton,
|
||||
{
|
||||
strong: true,
|
||||
tertiary: true,
|
||||
size: 'large',
|
||||
type: 'error',
|
||||
onClick: () => deldata(row)
|
||||
},
|
||||
{ default: () => '删除' }
|
||||
)
|
||||
}
|
||||
}])
|
||||
|
||||
const data = ref([])
|
||||
|
||||
const geoObj = reactive({
|
||||
"type":"FeatureCollection",
|
||||
"features":[{
|
||||
"type":"Feature",
|
||||
"properties":{
|
||||
"adcode":0,
|
||||
"name":"经纬度数据",
|
||||
"center":[0,0],
|
||||
"centroid":[0,0],
|
||||
"cp":[15,12],
|
||||
"childrenNum":0,
|
||||
"level":"city",
|
||||
"acroutes":[0,0],
|
||||
"parent":{"adcode":0}
|
||||
},
|
||||
"geometry":{
|
||||
"type":"MultiPolygon",
|
||||
"coordinates":[[[[15,30],[0,0],[15,10],[30,0]]]]
|
||||
}
|
||||
}]
|
||||
})
|
||||
|
||||
use([ CanvasRenderer, MapChart, ScatterChart ])
|
||||
registerMap('nowin',geoObj)
|
||||
const option = reactive({
|
||||
geo: [
|
||||
{
|
||||
zlevel:3,
|
||||
map: 'nowin',
|
||||
label: {
|
||||
show: true,
|
||||
color: 'black',
|
||||
fontSize: 18
|
||||
},
|
||||
itemStyle: {
|
||||
normal: {
|
||||
areaColor: '#26c4eb',
|
||||
shadowColor:"#01273F",
|
||||
shadowOffsetX: 0,
|
||||
shadowOffsetY: 0,
|
||||
borderWidth:0.5,
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
series: [{
|
||||
//设置为分散点
|
||||
type: 'scatter',
|
||||
//series坐标系类型
|
||||
coordinateSystem: 'geo',
|
||||
//设置图形 'circle', 'rect', 'roundRect', 'triangle', 'diamond', 'pin', 'arrow'
|
||||
symbol: 'pin',
|
||||
// //标记的大小,可以设置成诸如 10 这样单一的数字,也可以用数组分开表示宽和高,例如 [20, 10] 表示标记宽为20,高为10
|
||||
symbolSize: [40,40],
|
||||
//气泡字体设置
|
||||
label: {
|
||||
normal: {
|
||||
show: false,//是否显示
|
||||
textStyle: {
|
||||
color: '#000',//字体颜色
|
||||
fontSize: 8,//字体大小
|
||||
},
|
||||
//返回气泡数据
|
||||
formatter (value){
|
||||
return value.data.value[2]
|
||||
}
|
||||
}
|
||||
},
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: '#1E90FF', //标志颜色
|
||||
areaColor: '#26c4eb',
|
||||
borderWidth: 0.5,
|
||||
borderColor: "#ffffff",
|
||||
shadowColor:"#01273F",
|
||||
shadowBlur: 6
|
||||
}
|
||||
},
|
||||
// //给区域赋值
|
||||
data: [],
|
||||
showEffectOn: 'render',//配置何时显示特效。可选:'render' 绘制完成后显示特效。'emphasis' 高亮(hover)的时候显示特效。
|
||||
rippleEffect: {//涟漪特效相关配置。
|
||||
brushType: 'stroke'//波纹的绘制方式,可选 'stroke' 和 'fill'
|
||||
},
|
||||
hoverAnimation: true,//是否开启鼠标 hover 的提示动画效果。
|
||||
zlevel: 3//所属图形的 zlevel 值
|
||||
}]
|
||||
})
|
||||
|
||||
window.addEventListener('resize', () => {
|
||||
let chart = echarts.init(document.getElementById('chart'))
|
||||
chart.resize()
|
||||
})
|
||||
|
||||
const rerender = (mapName,mapArea,mapGeo) => {
|
||||
if(mapGeo){
|
||||
geoObj.features[0].properties.cp = centerPoint(mapGeo)
|
||||
geoObj.features[0].geometry.coordinates[0][0] = mapGeo
|
||||
}
|
||||
geoObj.features[0].properties.name = mapArea
|
||||
registerMap(mapName, geoObj)
|
||||
option.geo[0].map = mapName
|
||||
}
|
||||
|
||||
const onRemove = () => {
|
||||
if(geodata.value.length < 3){
|
||||
rerender('nowin','经纬度数据',[[15,30],[0,0],[15,10],[30,0]])
|
||||
}
|
||||
}
|
||||
|
||||
const inputFilter = (inputData) => {
|
||||
let infilter = []
|
||||
let beffilter = [...inputData]
|
||||
beffilter.forEach(item => {
|
||||
if(item !== '\u00A0' && item !== '\u0020' && item !== '\u3000'){
|
||||
if(!isNaN(Number(item))){
|
||||
infilter.push(item)
|
||||
}else if(item == '.'){
|
||||
if(infilter.indexOf('.') == '-1'){
|
||||
infilter.push(item)
|
||||
}
|
||||
}else if(item == '-'){
|
||||
if(infilter.indexOf('-') == '-1'){
|
||||
infilter.push(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
return infilter.join('')
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
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
|
||||
//角度转弧度 180.0 / Math.PI
|
||||
//米转角度 2.0 * Math.PI * 6371.004 / 360.0
|
||||
|
||||
//需求决定了输入的经纬度距离不会太远,近似为求平面多边形的面积
|
||||
const calculationArea = (points) => {
|
||||
let area = 0
|
||||
//将多边形分解为三角形
|
||||
points.forEach((item,index) => {
|
||||
let j = (index + 1) % points.length
|
||||
let xi = points[index][0] * (2.0 * Math.PI * 6371004.0 / 360.0) * Math.cos(points[index][1] * (Math.PI / 180.0))
|
||||
let yi = points[index][1] * (2.0 * Math.PI * 6371004.0 / 360.0)
|
||||
let xj = points[j][0] * (2.0 * Math.PI * 6371004.0 / 360.0) * Math.cos(points[j][1] * (Math.PI / 180.0))
|
||||
let yj = points[j][1] * (2.0 * Math.PI * 6371004.0 / 360.0)
|
||||
area += xi * yj - xj * yi
|
||||
})
|
||||
//计算结果为平方米
|
||||
if(unit.value == '平方米/m²'){
|
||||
return Math.abs(area / 2).toFixed(4) + unit.value
|
||||
}
|
||||
else{
|
||||
return (Math.abs(area / 2) / 1000000).toFixed(9) + unit.value
|
||||
}
|
||||
}
|
||||
|
||||
const centerPoint = (allPoint) => {
|
||||
let averagelat = 0
|
||||
let averagelng = 0
|
||||
allPoint.forEach(item => {
|
||||
averagelat = Number(item[0]) + averagelat
|
||||
averagelng = Number(item[1]) + averagelng
|
||||
})
|
||||
return [averagelat/allPoint.length,averagelng/allPoint.length]
|
||||
}
|
||||
|
||||
const diffData = (areaResult) => {
|
||||
let allowCalaulation = true
|
||||
data.value.forEach(items => {
|
||||
if(items.latandlng.join(';') == areaResult.latandlng.join(';')){
|
||||
allowCalaulation = false
|
||||
}
|
||||
})
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
const calculation = () => {
|
||||
if(geodata.value.length <= 2){
|
||||
message.error('经纬度数据对的数量不能满足运算')
|
||||
return
|
||||
}
|
||||
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])
|
||||
})
|
||||
let areaData = {
|
||||
latandlng: pointArr,
|
||||
area: calculationArea(pointArr)
|
||||
}
|
||||
diffData(areaData)
|
||||
}
|
||||
|
||||
const delgeo = () => {
|
||||
dialog.warning({
|
||||
title: '警告',
|
||||
content: '确定要清除全部输入吗?',
|
||||
positiveText: '确定',
|
||||
negativeText: '返回',
|
||||
onPositiveClick: () => {
|
||||
geodata.value = [
|
||||
{
|
||||
lat: "",
|
||||
latStatus: "",
|
||||
latCheck: "",
|
||||
lng: "",
|
||||
lngStatus: "",
|
||||
lngCheck: ""
|
||||
}
|
||||
]
|
||||
rerender('nowin','经纬度数据',[[15,30],[0,0],[15,10],[30,0]])
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
message.error('已返回')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const drawContour = (row) => {
|
||||
rerender('nowin','经纬度数据',[[15,30],[0,0],[15,10],[30,0]])
|
||||
rerender('updataGeo',row.area,row.latandlng)
|
||||
}
|
||||
|
||||
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]])
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const delall = () => {
|
||||
dialog.warning({
|
||||
title: '警告',
|
||||
content: '确定要清除全部数据吗?',
|
||||
positiveText: '确定',
|
||||
negativeText: '返回',
|
||||
onPositiveClick: () => {
|
||||
data.value = []
|
||||
rerender('nowin','经纬度数据',[[15,30],[0,0],[15,10],[30,0]])
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
message.error('已返回')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
watch(unit,(value) => {
|
||||
columns.value[1].title = `面积(单位:${ value })`
|
||||
if(data.value.length !== 0){
|
||||
data.value.forEach(element => {
|
||||
if(value == '平方米/m²'){
|
||||
rerender('updataGeo',element.area)
|
||||
element.area = (element.area.slice(0,element.area.length-8) * 1000000).toFixed(4) + value
|
||||
rerender('change',element.area)
|
||||
}else{
|
||||
rerender('updataGeo',element.area)
|
||||
element.area = (element.area.slice(0,element.area.length-6) / 1000000).toFixed(9) + value
|
||||
rerender('change',element.area)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.n-grid {
|
||||
place-items: center
|
||||
}
|
||||
.p {
|
||||
padding: 1%;
|
||||
padding-top: 2%
|
||||
}
|
||||
.mt {
|
||||
margin-top:2%
|
||||
}
|
||||
</style>
|
||||
1
src/render/views/CalculationDistance/index.ts
Normal file
1
src/render/views/CalculationDistance/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default as CalculationDistance } from './index.vue'
|
||||
436
src/render/views/CalculationDistance/index.vue
Normal file
436
src/render/views/CalculationDistance/index.vue
Normal file
@@ -0,0 +1,436 @@
|
||||
<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-dynamic-input
|
||||
v-model:value="geodata"
|
||||
:on-create="onCreate"
|
||||
>
|
||||
<template #default="{ value }">
|
||||
<div style="display: flex; align-items: flex-start; width: 100%">
|
||||
<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>
|
||||
</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>
|
||||
</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>
|
||||
</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>
|
||||
</n-gradient-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</n-dynamic-input>
|
||||
</n-scrollbar>
|
||||
<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 />
|
||||
<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" />
|
||||
</div>
|
||||
<n-button class="mx-auto" :disabled="data.length == 0 ? true : false" size="large" type="error" @click="delall">清除数据</n-button>
|
||||
</div>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, h, watch } from "vue"
|
||||
import { NGi, NGrid, NButton, NDynamicInput, NDataTable, NScrollbar, NInput, NGradientText, NSelect, useMessage, useDialog } from "naive-ui"
|
||||
|
||||
const message = useMessage()
|
||||
|
||||
const dialog = useDialog()
|
||||
|
||||
const geodata = ref([
|
||||
{
|
||||
lat1:"",
|
||||
lat1Status:"",
|
||||
lat1Check:"",
|
||||
lng1:"",
|
||||
lng1Status:"",
|
||||
lng1Check:"",
|
||||
lat2:"",
|
||||
lat2Status:"",
|
||||
lat2Check:"",
|
||||
lng2:"",
|
||||
lng2Status:"",
|
||||
lng2Check:""
|
||||
}
|
||||
])
|
||||
|
||||
const onCreate = () => {
|
||||
return {
|
||||
lat1:"",
|
||||
lat1Status:"",
|
||||
lat1Check:"",
|
||||
lng1:"",
|
||||
lng1Status:"",
|
||||
lng1Check:"",
|
||||
lat2:"",
|
||||
lat2Status:"",
|
||||
lat2Check:"",
|
||||
lng2:"",
|
||||
lng2Status:"",
|
||||
lng2Check:""
|
||||
}
|
||||
}
|
||||
|
||||
const unit = ref('米/m')
|
||||
|
||||
const options = [
|
||||
{
|
||||
label:"米/m",
|
||||
value:'米/m'
|
||||
},
|
||||
{
|
||||
label:"千米/km",
|
||||
value:'千米/km'
|
||||
}]
|
||||
|
||||
const columns = ref([
|
||||
{
|
||||
title: '经度1',
|
||||
key: 'latitude1'
|
||||
},
|
||||
{
|
||||
title: '纬度1',
|
||||
key: 'longitude1'
|
||||
},
|
||||
{
|
||||
title: '经度2',
|
||||
key: 'latitude2'
|
||||
},
|
||||
{
|
||||
title: '纬度2',
|
||||
key: 'longitude2'
|
||||
},
|
||||
{
|
||||
title: `距离(单位:${ unit.value})`,
|
||||
key: 'distance'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'operate',
|
||||
fixed: 'right',
|
||||
align: 'center',
|
||||
render (row) {
|
||||
return h(
|
||||
NButton,
|
||||
{
|
||||
strong: true,
|
||||
tertiary: true,
|
||||
size: 'large',
|
||||
type: 'error',
|
||||
onClick: () => deldata(row)
|
||||
},
|
||||
{ default: () => '删除' }
|
||||
)
|
||||
}
|
||||
}])
|
||||
|
||||
const data = ref([])
|
||||
|
||||
const inputFilter = (inputData) => {
|
||||
let infilter = []
|
||||
let beffilter = [...inputData]
|
||||
beffilter.forEach(item => {
|
||||
if(item !== '\u00A0' && item !== '\u0020' && item !== '\u3000'){
|
||||
if(!isNaN(Number(item))){
|
||||
infilter.push(item)
|
||||
}else if(item == '.'){
|
||||
if(infilter.indexOf('.') == '-1'){
|
||||
infilter.push(item)
|
||||
}
|
||||
}else if(item == '-'){
|
||||
if(infilter.indexOf('-') == '-1'){
|
||||
infilter.push(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
return infilter.join('')
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
const calculationDistance = (lat1,lng1,lat2,lng2) => {
|
||||
let radLat1 = (Math.PI / 180.0) * lat1
|
||||
let radLat2 = (Math.PI / 180.0) * lat2
|
||||
let radLng1 = (Math.PI / 180.0) * lng1
|
||||
let radLng2 = (Math.PI / 180.0) * lng2
|
||||
|
||||
let a = radLat1 - radLat2
|
||||
let b = radLng1 - radLng2
|
||||
|
||||
let s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(b / 2), 2) + Math.cos(radLng1) * Math.cos(radLng2) * Math.pow(Math.sin(a / 2), 2))) * 6371.004
|
||||
//使用Haversine公式计算
|
||||
//haversin(纬度差) + cos(纬度1)*cos(纬度2)*haversin(经度差)
|
||||
//haversin(Ø) = sin²(Ø/2) = (1-cos(Ø))/2
|
||||
//地球赤道半径 6378.137
|
||||
//地球平均半径 6371.004
|
||||
|
||||
s = (Math.round(s * 10000) / 10000).toFixed(5)
|
||||
//计算结果单位为千米
|
||||
|
||||
if(unit.value == '米/m'){
|
||||
return (s * 1000).toFixed(2) + unit.value
|
||||
}else{
|
||||
return s + unit.value
|
||||
}
|
||||
}
|
||||
|
||||
const diffData = (geoResult) => {
|
||||
let startpoint = true
|
||||
let endpoint = true
|
||||
data.value.forEach(items => {
|
||||
if(items.latitude1 === geoResult.latitude1 && items.longitude1 === geoResult.longitude1){
|
||||
startpoint = false
|
||||
if(items.latitude2 === geoResult.latitude2 && items.longitude2 === geoResult.longitude2){
|
||||
endpoint = false
|
||||
}
|
||||
}
|
||||
else if(items.latitude1 === geoResult.latitude2 && items.longitude1 === geoResult.longitude2){
|
||||
startpoint = false
|
||||
if(items.latitude2 === geoResult.latitude1 && items.longitude1 === geoResult.longitude2){
|
||||
endpoint = false
|
||||
}
|
||||
}
|
||||
})
|
||||
if(startpoint || endpoint){
|
||||
data.value.push(geoResult)
|
||||
}
|
||||
}
|
||||
|
||||
const calculation = () => {
|
||||
geodata.value.forEach((element,index) => {
|
||||
inputCheck(element)
|
||||
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,
|
||||
distance:calculationDistance(element.lat1,element.lng1,element.lat2,element.lng2)
|
||||
}
|
||||
diffData(geobox)
|
||||
})
|
||||
}
|
||||
|
||||
const delgeo = () => {
|
||||
dialog.warning({
|
||||
title: '警告',
|
||||
content: '确定要清除全部输入吗?',
|
||||
positiveText: '确定',
|
||||
negativeText: '返回',
|
||||
onPositiveClick: () => {
|
||||
geodata.value = [
|
||||
{
|
||||
lat1:"",
|
||||
lat1Status:"",
|
||||
lat1Check:"",
|
||||
lng1:"",
|
||||
lng1Status:"",
|
||||
lng1Check:"",
|
||||
lat2:"",
|
||||
lat2Status:"",
|
||||
lat2Check:"",
|
||||
lng2:"",
|
||||
lng2Status:"",
|
||||
lng2Check:""
|
||||
}
|
||||
]
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
message.error('已返回')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const deldata = (row) => {
|
||||
data.value.filter((item,index,array)=>{
|
||||
if(item == row){
|
||||
array.splice(index,1)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const delall = () => {
|
||||
dialog.warning({
|
||||
title: '警告',
|
||||
content: '确定要清除全部数据吗?',
|
||||
positiveText: '确定',
|
||||
negativeText: '返回',
|
||||
onPositiveClick: () => {
|
||||
data.value = []
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
message.error('已返回')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
watch(unit,(value) => {
|
||||
columns.value[4].title = `距离(单位:${ value })`
|
||||
if(data.value.length !== 0){
|
||||
data.value.forEach(element => {
|
||||
if(value == '米/m'){
|
||||
console.log(element.distance.slice(0,element.distance.length-3))
|
||||
element.distance = (element.distance.slice(0,element.distance.length-5) * 1000).toFixed(2) + value
|
||||
}else{
|
||||
console.log(element.distance.slice(0,element.distance.length-5))
|
||||
element.distance = (element.distance.slice(0,element.distance.length-3) / 1000).toFixed(5) + value
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.n-grid {
|
||||
place-items: center
|
||||
}
|
||||
.p {
|
||||
padding: 1%;
|
||||
padding-top: 2%
|
||||
}
|
||||
.mt {
|
||||
margin-top:2%
|
||||
}
|
||||
</style>
|
||||
1
src/render/views/CalculationGSV/index.ts
Normal file
1
src/render/views/CalculationGSV/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default as CalculationGSV } from './index.vue'
|
||||
519
src/render/views/CalculationGSV/index.vue
Normal file
519
src/render/views/CalculationGSV/index.vue
Normal file
@@ -0,0 +1,519 @@
|
||||
<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-dynamic-input
|
||||
v-model:value="satellite"
|
||||
:on-create="onCreate"
|
||||
>
|
||||
<template #default="{ value }">
|
||||
<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>
|
||||
</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>
|
||||
</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>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</n-dynamic-input>
|
||||
</n-scrollbar>
|
||||
<div style="margin-top: 1vh;" class="w-full flex flex-1">
|
||||
<n-button class="mx-auto" :disabled="satellite.length==0?true:false" size="large" type="primary" @click="calculation">生 成</n-button>
|
||||
<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 />
|
||||
<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" />
|
||||
</div>
|
||||
<n-button class="mx-auto" :disabled="data.length==0?true:false" size="large" type="error" @click="delall">清除数据</n-button>
|
||||
</div>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, h, watch } from "vue"
|
||||
import { NGi, NGrid, NButton, NDynamicInput, NInput, NDataTable, NScrollbar, NSelect, NGradientText, useMessage, useDialog } from "naive-ui"
|
||||
|
||||
const message = useMessage()
|
||||
|
||||
const dialog = useDialog()
|
||||
|
||||
const satellite = ref([
|
||||
{
|
||||
number: "",
|
||||
numberStatus: "success",
|
||||
numberCheck: false,
|
||||
elevation: "",
|
||||
elevationStatus: "success",
|
||||
elevationCheck: false,
|
||||
azimuth: "",
|
||||
azimuthStatus: "success",
|
||||
azimuthCheck: false,
|
||||
signal: "",
|
||||
signalStatus: "success",
|
||||
signalCheck: false
|
||||
}
|
||||
])
|
||||
|
||||
const onCreate = () => {
|
||||
return {
|
||||
number: "",
|
||||
numberStatus: "success",
|
||||
numberCheck: false,
|
||||
elevation: "",
|
||||
elevationStatus: "success",
|
||||
elevationCheck: false,
|
||||
azimuth: "",
|
||||
azimuthStatus: "success",
|
||||
azimuthCheck: false,
|
||||
signal: "",
|
||||
signalStatus: "success",
|
||||
signalCheck: false
|
||||
}
|
||||
}
|
||||
|
||||
const version = ref('NMEA 0183 V3.x')
|
||||
|
||||
const options = [
|
||||
{
|
||||
label:"NMEA 0183 V3.x",
|
||||
value:'NMEA 0183 V3.x'
|
||||
},
|
||||
{
|
||||
label:"NMEA 0183 V4.0x",
|
||||
value:'NMEA 0183 V4.0x'
|
||||
},
|
||||
{
|
||||
label:"NMEA 0183 V4.1x",
|
||||
value:'NMEA 0183 V4.1x'
|
||||
}]
|
||||
|
||||
const columns = ref([
|
||||
{
|
||||
title: '卫星数据',
|
||||
key: 'satelliteData',
|
||||
render (row) {
|
||||
const tags = row.satelliteData.map((DataTag) => {
|
||||
return h(
|
||||
NScrollbar,
|
||||
{
|
||||
style: {}
|
||||
},
|
||||
{
|
||||
default: () => DataTag
|
||||
}
|
||||
)
|
||||
})
|
||||
return tags
|
||||
}
|
||||
},
|
||||
{
|
||||
title: `GSV语句(版本:${ version.value })`,
|
||||
key: 'GSVStatement',
|
||||
render (row) {
|
||||
const tags = row.GSVStatement.map((GSVTag) => {
|
||||
return h(
|
||||
NScrollbar,
|
||||
{
|
||||
style: {}
|
||||
},
|
||||
{
|
||||
default: () => GSVTag
|
||||
}
|
||||
)
|
||||
})
|
||||
return tags
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'operate',
|
||||
fixed: 'right',
|
||||
align: 'center',
|
||||
render (row) {
|
||||
return h(
|
||||
NButton,
|
||||
{
|
||||
strong: true,
|
||||
tertiary: true,
|
||||
size: 'large',
|
||||
type: 'error',
|
||||
onClick: () => deldata(row)
|
||||
},
|
||||
{ default: () => '删除' }
|
||||
)
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
const data = ref([])
|
||||
|
||||
const allowCalaulation = ref(true)
|
||||
|
||||
const inputFilter = (inputData) => {
|
||||
let infilter = []
|
||||
let beffilter = [...inputData]
|
||||
beffilter.forEach(item => {
|
||||
if(item !== '\u00A0' && item !== '\u0020' && item !== '\u3000'){
|
||||
if(!isNaN(Number(item))){
|
||||
infilter.push(item)
|
||||
}
|
||||
}
|
||||
})
|
||||
return infilter.join('')
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
else{
|
||||
element.numberStatus = 'success'
|
||||
element.numberCheck = false
|
||||
}
|
||||
if(element.elevation == ''){
|
||||
element.elevationStatus = 'error'
|
||||
element.elevationCheck = true
|
||||
}
|
||||
else if(Number(element.elevation) == '0'){
|
||||
elevationMark = true
|
||||
element.elevationStatus = 'success'
|
||||
element.elevationCheck = false
|
||||
}
|
||||
else {
|
||||
element.elevationStatus = 'success'
|
||||
element.elevationCheck = false
|
||||
}
|
||||
if(element.azimuth == ''){
|
||||
element.azimuthStatus = 'error'
|
||||
element.azimuthCheck = true
|
||||
}
|
||||
else if(Number(element.azimuth) == '0'){
|
||||
azimuthMark = true
|
||||
element.azimuthStatus = 'success'
|
||||
element.azimuthCheck = false
|
||||
}
|
||||
else {
|
||||
element.azimuthStatus = 'success'
|
||||
element.azimuthCheck = 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
|
||||
signalMark = true
|
||||
}
|
||||
else{
|
||||
element.signalStatus = 'success'
|
||||
element.signalCheck = false
|
||||
signalMark = false
|
||||
}
|
||||
if(elevationMark && azimuthMark || signalMark){
|
||||
allowCalaulation.value = false
|
||||
}else{
|
||||
allowCalaulation.value = true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const checkit = (acheck) => {
|
||||
let checkArr = acheck.split('')
|
||||
let resultBox
|
||||
checkArr.forEach(element => {
|
||||
if(resultBox == undefined){
|
||||
resultBox = element.charCodeAt()
|
||||
}else{
|
||||
resultBox = resultBox ^ element.charCodeAt()
|
||||
}
|
||||
})
|
||||
let toOver = resultBox.toString(16).toUpperCase()
|
||||
if(resultBox.toString(16).toUpperCase().length < 2){
|
||||
toOver = '0' + toOver
|
||||
}
|
||||
return toOver
|
||||
}
|
||||
|
||||
const generate = (dataBox) => {
|
||||
let keyArr = []
|
||||
for (const key in dataBox) {
|
||||
keyArr.push(key)
|
||||
}
|
||||
keyArr.sort((a, b) => a - b)
|
||||
let valueArr = []
|
||||
keyArr.forEach(element => {
|
||||
valueArr.push(dataBox[element])
|
||||
})
|
||||
keyArr = null
|
||||
let GSVBox = []
|
||||
let GSVNum = valueArr.length
|
||||
if(GSVNum <= 4){
|
||||
GSVBox.push(valueArr.join())
|
||||
}else{
|
||||
for (let index = 0; index < Math.ceil(GSVNum / 4); index++) {
|
||||
if(GSVNum <= 4){
|
||||
GSVBox.push(valueArr.join())
|
||||
}else{
|
||||
GSVBox.push(valueArr.splice(0,4))
|
||||
}
|
||||
}
|
||||
}
|
||||
valueArr = null
|
||||
let GSVArr = []
|
||||
let statementNum = GSVBox.length
|
||||
for (let index = 0; index < statementNum; index++) {
|
||||
let statementId = index
|
||||
let GSVData = GSVBox[index];
|
||||
let waitCheck = `${ version.value == 'NMEA 0183 V3.x' ? 'BD' : 'GB' }GSV,${ statementNum },${ statementId + 1 },${ GSVNum < 10 ? '0' + GSVNum : GSVNum },${ GSVData }${ version.value == 'NMEA 0183 V4.1x' ? ',1' : '' }`
|
||||
GSVArr.push(`$${ waitCheck }*${ checkit(waitCheck) }`)
|
||||
}
|
||||
GSVBox = null
|
||||
return GSVArr
|
||||
}
|
||||
|
||||
const toGenerate = (satelliteGSV,GSVResult) => {
|
||||
let allowGenerate = true
|
||||
data.value.forEach(items => {
|
||||
let compare = []
|
||||
for (const key in items.GSVStatement) {
|
||||
compare.push(items.GSVStatement[key])
|
||||
}
|
||||
if(compare.join() == GSVResult.join()){
|
||||
allowGenerate = false
|
||||
}
|
||||
compare = null
|
||||
})
|
||||
if(allowGenerate){
|
||||
data.value.push({
|
||||
satelliteData:satelliteGSV,
|
||||
GSVStatement:GSVResult
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
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])
|
||||
})
|
||||
let GSVResult = generate(satelliteBox)
|
||||
satelliteBox = null
|
||||
if(allowCalaulation.value){
|
||||
toGenerate(satelliteGSV,GSVResult)
|
||||
}else{
|
||||
dialog.warning({
|
||||
title: '警告',
|
||||
content: '检查到某些数据可能是无效数据,确定要继续生成吗?',
|
||||
positiveText: '确定',
|
||||
negativeText: '返回',
|
||||
onPositiveClick: () => {
|
||||
toGenerate(satelliteGSV,GSVResult)
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
message.error('已返回')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const delgeo = () => {
|
||||
dialog.warning({
|
||||
title: '警告',
|
||||
content: '确定要清除全部输入吗?',
|
||||
positiveText: '确定',
|
||||
negativeText: '返回',
|
||||
onPositiveClick: () => {
|
||||
satellite.value = [
|
||||
{
|
||||
number: "",
|
||||
numberStatus: "success",
|
||||
numberCheck: false,
|
||||
elevation: "",
|
||||
elevationStatus: "success",
|
||||
elevationCheck: false,
|
||||
azimuth: "",
|
||||
azimuthStatus: "success",
|
||||
azimuthCheck: false,
|
||||
signal: "",
|
||||
signalStatus: "success",
|
||||
signalCheck: false
|
||||
}
|
||||
]
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
message.error('已返回')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const deldata = (row) => {
|
||||
data.value.filter((item,index,array)=>{
|
||||
if(item == row){
|
||||
array.splice(index,1)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const delall = () => {
|
||||
dialog.warning({
|
||||
title: '警告',
|
||||
content: '确定要清除全部数据吗?',
|
||||
positiveText: '确定',
|
||||
negativeText: '返回',
|
||||
onPositiveClick: () => {
|
||||
data.value = []
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
message.error('已返回')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
watch(version,(value) => {
|
||||
columns.value[1].title = `GSV语句(版本:${ value })`
|
||||
if(data.value.length !== 0){
|
||||
data.value.forEach(element => {
|
||||
element.GSVStatement.forEach((item,index) => {
|
||||
let params
|
||||
if((item.substring(3,item.length - 3).length - 1) - item.substring(3,item.length - 3).lastIndexOf(',') == '1'){
|
||||
params = item.substring(3,item.length - 5)
|
||||
}else{
|
||||
params = item.substring(3,item.length - 3)
|
||||
}
|
||||
if(value == 'NMEA 0183 V3.x'){
|
||||
element.GSVStatement[index] = `$${ 'BD' + params }*${ checkit('BD' + params) }`
|
||||
}else if(value == 'NMEA 0183 V4.0x'){
|
||||
element.GSVStatement[index] = `$${ 'GB' + params }*${ checkit('GB' + params) }`
|
||||
}else{
|
||||
element.GSVStatement[index] = `$${ 'GB' + params + ',1' }*${ checkit('GB' + params + ',1') }`
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.n-grid {
|
||||
place-items: center
|
||||
}
|
||||
.p {
|
||||
padding: 1%;
|
||||
padding-top: 2%
|
||||
}
|
||||
.mt {
|
||||
margin-top:2%
|
||||
}
|
||||
</style>
|
||||
1
src/render/views/CalculationXOR/index.ts
Normal file
1
src/render/views/CalculationXOR/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default as CalculationXOR } from './index.vue'
|
||||
252
src/render/views/CalculationXOR/index.vue
Normal file
252
src/render/views/CalculationXOR/index.vue
Normal file
@@ -0,0 +1,252 @@
|
||||
<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-dynamic-input
|
||||
v-model:value="check"
|
||||
:on-create="onCreate"
|
||||
>
|
||||
<template #default="{ value }">
|
||||
<div class="w-full">
|
||||
<n-input clearable v-model:value="value.checkItem" type="text" placeholder="校验数据" @input="handleInput" :status="toCheck ? value.checkItem == '' ? 'error' : 'success' : 'success'" />
|
||||
<n-gradient-text :size="12" type="error" v-show="toCheck ? value.checkItem == '' ? true : false : false">
|
||||
校验数据不能为空
|
||||
</n-gradient-text>
|
||||
</div>
|
||||
</template>
|
||||
</n-dynamic-input>
|
||||
</n-scrollbar>
|
||||
<div style="margin-top: 1vh;" class="w-full flex flex-1">
|
||||
<n-button class="mx-auto" :disabled="check.length == 0 ? true : false" size="large" type="primary" @click="calculation">校 验</n-button>
|
||||
<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 />
|
||||
<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" />
|
||||
</div>
|
||||
<n-button class="mx-auto" :disabled="data.length == 0 ? true : false" size="large" type="error" @click="delall">清除数据</n-button>
|
||||
</div>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
</template>
|
||||
|
||||
<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"
|
||||
|
||||
const message = useMessage()
|
||||
|
||||
const dialog = useDialog()
|
||||
|
||||
const check = ref([{checkItem:""}])
|
||||
|
||||
const onCreate = () => {
|
||||
return {
|
||||
checkItem:""
|
||||
}
|
||||
}
|
||||
|
||||
const base = ref('16进制/Hex')
|
||||
|
||||
const options = [
|
||||
{
|
||||
label:"16进制/Hex",
|
||||
value:'16进制/Hex'
|
||||
},
|
||||
{
|
||||
label:"二进制/Binary",
|
||||
value:'二进制/Binary'
|
||||
}]
|
||||
|
||||
const columns = ref([
|
||||
{
|
||||
title: '校验数据',
|
||||
key: 'checkData'
|
||||
},
|
||||
{
|
||||
title: `校验结果(${ base.value })`,
|
||||
key: 'checkResult'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'operate',
|
||||
fixed: 'right',
|
||||
align: 'center',
|
||||
render (row) {
|
||||
return h(
|
||||
NButton,
|
||||
{
|
||||
strong: true,
|
||||
tertiary: true,
|
||||
size: 'large',
|
||||
type: 'error',
|
||||
onClick: () => deldata(row)
|
||||
},
|
||||
{ default: () => '删除' }
|
||||
)
|
||||
}
|
||||
}])
|
||||
|
||||
const data = ref([])
|
||||
|
||||
const toCheck = ref(false)
|
||||
|
||||
|
||||
// 判断字符是否为简体汉字
|
||||
const isChinese = (s) => {
|
||||
return /[\u4e00-\u9fa5]/.test(s)
|
||||
}
|
||||
|
||||
const inputFilter = (inputData) => {
|
||||
let infilter = []
|
||||
inputData.forEach(item => {
|
||||
if(!isChinese(item)){
|
||||
infilter.push(item)
|
||||
}
|
||||
})
|
||||
return infilter.join('')
|
||||
}
|
||||
|
||||
const handleInput = () => {
|
||||
check.value.forEach(element => {
|
||||
let itemArr = element.checkItem.split('')
|
||||
element.checkItem = inputFilter(itemArr)
|
||||
})
|
||||
}
|
||||
|
||||
const checkit = (acheck) => {
|
||||
let checkArr = acheck.split('')
|
||||
let resultBox
|
||||
checkArr.forEach(element => {
|
||||
if(resultBox == undefined){
|
||||
resultBox = element.charCodeAt()
|
||||
}else{
|
||||
resultBox = resultBox ^ element.charCodeAt()
|
||||
}
|
||||
})
|
||||
let toOver
|
||||
if(base.value == '16进制/Hex'){
|
||||
toOver = resultBox.toString(16).toUpperCase()
|
||||
if(resultBox.toString(16).toUpperCase().length < 2){
|
||||
toOver = '0' + toOver
|
||||
}
|
||||
}else{
|
||||
toOver = resultBox.toString(2)
|
||||
if(resultBox.toString(2).length < 8){
|
||||
for(let i=0; i < 8-resultBox.toString(2).length; i++){
|
||||
toOver = '0' + toOver
|
||||
}
|
||||
}
|
||||
}
|
||||
return toOver
|
||||
}
|
||||
|
||||
const calculation = () => {
|
||||
check.value.forEach((element,index) => {
|
||||
if(element.checkItem == ""){
|
||||
message.error('校验数据不能为空')
|
||||
toCheck.value = true
|
||||
throw new Error("校验数据不能为空")
|
||||
}
|
||||
let allowCheck = true
|
||||
data.value.forEach(items => {
|
||||
if(items.checkData == element.checkItem){
|
||||
allowCheck = false
|
||||
}
|
||||
})
|
||||
if(allowCheck){
|
||||
data.value.push({
|
||||
checkData:element.checkItem,
|
||||
checkResult:checkit(element.checkItem)
|
||||
})
|
||||
}
|
||||
toCheck.value = false
|
||||
})
|
||||
}
|
||||
|
||||
const delgeo = () => {
|
||||
dialog.warning({
|
||||
title: '警告',
|
||||
content: '确定要清除全部输入吗?',
|
||||
positiveText: '确定',
|
||||
negativeText: '返回',
|
||||
onPositiveClick: () => {
|
||||
check.value = [{checkItem:""}]
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
message.error('已返回')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const deldata = (row) => {
|
||||
data.value.filter((item,index,array)=>{
|
||||
if(item == row){
|
||||
array.splice(index,1)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const delall = () => {
|
||||
dialog.warning({
|
||||
title: '警告',
|
||||
content: '确定要清除全部数据吗?',
|
||||
positiveText: '确定',
|
||||
negativeText: '返回',
|
||||
onPositiveClick: () => {
|
||||
data.value = []
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
message.error('已返回')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
watch(base,(value) => {
|
||||
columns.value[1].title = `校验结果(${ value })`
|
||||
if(data.value.length !== 0){
|
||||
data.value.forEach(element => {
|
||||
let toBase
|
||||
let checkArr = element.checkData.split('')
|
||||
checkArr.forEach(item => {
|
||||
if(toBase == undefined){
|
||||
toBase = item.charCodeAt()
|
||||
}else{
|
||||
toBase = toBase ^ item.charCodeAt()
|
||||
}
|
||||
})
|
||||
let toOver
|
||||
if(value == '16进制/Hex'){
|
||||
toOver = toBase.toString(16).toUpperCase()
|
||||
if(toBase.toString(16).toUpperCase().length < 2){
|
||||
toOver = '0' + toOver
|
||||
}
|
||||
}else{
|
||||
toOver = toBase.toString(2)
|
||||
if(toBase.toString(2).length < 8){
|
||||
for(let i=0; i < 8-toBase.toString(2).length; i++){
|
||||
toOver = '0' + toOver
|
||||
}
|
||||
}
|
||||
}
|
||||
element.checkResult = toOver
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.n-grid {
|
||||
place-items: center
|
||||
}
|
||||
.p {
|
||||
padding: 1%;
|
||||
padding-top: 2%
|
||||
}
|
||||
.mt {
|
||||
margin-top:2%
|
||||
}
|
||||
</style>
|
||||
1
src/render/views/LatitudeAndLongitudeMap/index.ts
Normal file
1
src/render/views/LatitudeAndLongitudeMap/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default as LatitudeAndLongitudeMap } from './index.vue'
|
||||
19
src/render/views/LatitudeAndLongitudeMap/index.vue
Normal file
19
src/render/views/LatitudeAndLongitudeMap/index.vue
Normal file
@@ -0,0 +1,19 @@
|
||||
<template>
|
||||
<div>
|
||||
<iframe
|
||||
id="LatitudeAndLongitudeMap"
|
||||
title="经纬度地图"
|
||||
class="w-h-full"
|
||||
src="http://test.map.hwasmart.com"
|
||||
>
|
||||
</iframe>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
||||
</style>
|
||||
@@ -7,7 +7,7 @@
|
||||
<script setup lang="ts">
|
||||
import { useRouter } from 'vue-router'
|
||||
import { NIcon } from 'naive-ui'
|
||||
import { ArrowBackIosFilled as ArrowBack } from '@vicons/material'
|
||||
import { ArrowBackIosRound as ArrowBack } from '@vicons/material'
|
||||
|
||||
const router = useRouter()
|
||||
const onClick = () => router.back()
|
||||
|
||||
@@ -3,8 +3,10 @@
|
||||
|
||||
<n-space :wrap-item="false" class="navigation-bar">
|
||||
<Logo v-if="!show" />
|
||||
<RouterBackButton v-if="show" class="router-back-button" />
|
||||
<HomeButton v-if="show" />
|
||||
<div class="button-background">
|
||||
<RouterBackButton v-if="show" class="router-back-button" />
|
||||
<HomeButton v-if="show" class="home-button" />
|
||||
</div>
|
||||
</n-space>
|
||||
|
||||
<n-space align="center" :wrap-item="false" class="status-bar" >
|
||||
@@ -42,9 +44,28 @@ const show = computed(() => route.path != '/' && route.path != '/category' )
|
||||
.navigation-bar {
|
||||
font-size: 32px;
|
||||
|
||||
.router-back-button {
|
||||
margin-left: 18px;
|
||||
.button-background {
|
||||
background-color: rgba(0,0,0,0.4);
|
||||
border-radius: 48px;
|
||||
padding-top: 6px;
|
||||
|
||||
.router-back-button {
|
||||
margin-left: 18px;
|
||||
margin-right: 9px;
|
||||
}
|
||||
.home-button{
|
||||
margin-left: 9px;
|
||||
margin-right: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.status-bar {
|
||||
padding-bottom: 6px;
|
||||
padding-left:12px;
|
||||
padding-right:12px;
|
||||
background-color: rgba(0,0,0,0.4);
|
||||
border-radius: 20px;
|
||||
padding-top: 6px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<n-space class="toolbar">
|
||||
|
||||
<div class="button-background">
|
||||
<n-popover :show="!network.isOnLine" placement="bottom">
|
||||
<template #trigger>
|
||||
<n-button size="large" circle type="info" @click="emit('systemSettings')">
|
||||
@@ -37,6 +37,7 @@
|
||||
</n-icon>
|
||||
</template>
|
||||
</n-button>
|
||||
</div>
|
||||
</n-space>
|
||||
</template>
|
||||
|
||||
@@ -88,7 +89,16 @@ const onPowerBtnMouseup = () => clearTimeout(rebootTimeoutID)
|
||||
|
||||
<style scoped lang="less">
|
||||
.toolbar {
|
||||
|
||||
.button-background {
|
||||
width:244px;
|
||||
background-color: rgba(0,0,0,0.4);
|
||||
border-radius: 48px;
|
||||
padding-top: 6px;
|
||||
padding-bottom: 6px;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
}
|
||||
.n-button {
|
||||
box-shadow: rgb(0 0 0 / 12%) 0px 2px 8px 0px;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<template>
|
||||
<router-link :to="`/course/${course.id}`">
|
||||
<n-card
|
||||
v-if="course.thumbnail=='Placeholder'?false:true"
|
||||
embedded
|
||||
bordered
|
||||
:title="course.name">
|
||||
@@ -23,7 +24,7 @@ const props = defineProps({
|
||||
|
||||
const COURSE_IMAGE_ROOT_PATH = process.env.NODE_ENV === 'development' ? '/img/course/course/' : '../img/course/course/'
|
||||
const getImageUrl = (imageFileName: string) => {
|
||||
return new URL(COURSE_IMAGE_ROOT_PATH + `${props.course.dir}/${imageFileName}`, import.meta.url).href
|
||||
return new URL(COURSE_IMAGE_ROOT_PATH + `${props.course.dir}/${imageFileName}`, import.meta.url).href
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user