You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1373 lines
42 KiB
Vue

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<!-- <div class="app-container" :style="{ transform: `scale(${scaleRatio})`,transformOrigin: `left top` }">-->
<!-- <div :style="{ transform: `scale(${scaleRatio})`,transformOrigin: `left top` }">-->
<div class="app-container">
<TOP/>
<LEFT/>
<RIGHT/>
<el-button style="position: fixed;top: 10px;right: 10px" type="primary" @click="toAdmin"></el-button>
</div>
<!-- </div>-->
</template>
<script setup lang="jsx">
import Ruler from "@/components/ruler.vue";
import {defineComponent, nextTick, onMounted, ref} from "vue";
import {
getParasPos,
getParasSignalpro,
setParasPos,
setParasSignalpro,
getShildList,
addShildData,
delShildData,
StartWork,
StopWork,
RestartWork,
ShutDownWork,
getAllAirPort,
getArea,
GetAllCData,
InsertCListData,
UpdateCData, DeleteCData
} from "@/api/api";
import {useRouter} from "vue-router";
import {ElMessage} from "element-plus";
const scaleRatio = ref(window.innerWidth / 1080)
const onSubmit = (e) => {
console.log(e)
}
const boxPos = ref({x: 100, y: 100, rotate: 0})
const TOP = defineComponent({
name: 'TOP',
setup() {
return () => (
<div class="top">
<div class="title">探测系统</div>
<div class="items">
<div
class={{item: true, click: itemsId.value === 1}}
onClick={() => setItemsId(1)}
>
<span>主界面</span>
</div>
<div
class={{item: true, click: itemsId.value === 2}}
onClick={() => setItemsId(2)}
>
<span>区域标定</span>
</div>
<div
class={{item: true, click: itemsId.value === 3}}
onClick={() => setItemsId(3)}
>
<span>软件设置</span>
</div>
<div
class={{item: true, click: itemsId.value === 4}}
onClick={() => setItemsId(4)}
>
<span>历史记录</span>
</div>
</div>
</div>
)
}
})
const LEFT = defineComponent({
name: 'LEFT',
setup() {
return () => (
<div class="left">
<Ruler
ref={rulerRef}
index={dotIndex.value}
width={areaData.value.width}
height={areaData.value.height}
boxPos={boxPos.value}
dots={dots.value}
dotIndex={dotIndex.value}
/>
</div>
)
}
})
const RIGHT = defineComponent({
name: 'RIGHT',
setup() {
return () => (
<div class="right">
{itemsId.value === 1 && (
<div class="tabsItem">
<ElCard shadow="always">
<ElForm inline model={form1.value} class="demo-form-inline">
<ElFormItem>
<ElSelect
modelValue={form1.value.region}
placeholder="请选择机场名称"
style={{width: "200px"}}
clearable
onUpdate:modelValue={val => selectUpdate(val)}
>
{
options1.value.map(i => {
return <ElOption label={i.name} value={i.id}/>
})
}
</ElSelect>
</ElFormItem>
<ElFormItem>
<ElSelect
modelValue={form1.value.region1}
placeholder="请选择区域名称"
style={{width: "200px"}}
clearable
onUpdate:modelValue={val => (form1.value.region1 = val)}
>
{
options2.value.map(i => {
return <ElOption label={i.name} value={i.id}/>
})
}
</ElSelect>
</ElFormItem>
<ElFormItem>
<ElButton type="primary" onClick={onSubmit}>固定目标</ElButton>
</ElFormItem>
</ElForm>
</ElCard>
<ElCard shadow="always" style={{marginTop: "12px"}}>
<ElButton
type="primary"
disabled={radarWorkState.value === 1}
onClick={StartWorkBtn}
>
启动雷达
</ElButton>
<ElButton
type="danger"
disabled={radarWorkState.value === 0}
onClick={StopWorkBtn}
>
关闭雷达
</ElButton>
<ElButton type="warning" onClick={RestartWorkBtn}>重启雷达</ElButton>
<ElButton type="info" onClick={ShutDownWorkBtn}>急停雷达</ElButton>
</ElCard>
<ElCard shadow="always" style={{marginTop: "12px"}}>
{radarWorkState.value === 1 && (
<div style={{
width: 'calc(50% - 50px)',
position: 'relative',
borderRadius: '5px',
backgroundColor: '#01CE69',
height: '44px',
display: 'inline-block',
padding: '0 20px',
marginRight: '20px'
}}>
<span style={{
position: 'absolute',
top: '50%',
transform: 'translateY(-50%)',
left: '20%',
color: '#fff',
letterSpacing: '2px'
}}>雷达通讯状态</span>
<ElIcon size="20px" style={{
position: 'absolute',
top: '50%',
transform: 'translateY(-50%)',
right: '40px'
}}>
<SuccessFilled color="#fff"/>
</ElIcon>
</div>
)}
{radarWorkState.value === 0 && (
<div style={{
width: 'calc(50% - 50px)',
position: 'relative',
borderRadius: '5px',
backgroundColor: '#E8370D',
height: '44px',
display: 'inline-block',
padding: '0 20px'
}}>
<span style={{
position: 'absolute',
top: '50%',
transform: 'translateY(-50%)',
left: '20%',
color: '#fff',
letterSpacing: '2px'
}}>雷达通讯状态</span>
<ElIcon size="20px" style={{
position: 'absolute',
top: '50%',
transform: 'translateY(-50%)',
right: '40px'
}}>
<WarningFilled color="#fff"/>
</ElIcon>
</div>
)}
</ElCard>
<ElCard shadow="always" style={{marginTop: "12px"}}>
<ElForm inline model={form2.value} class="demo-form-inline">
<ElFormItem>
<ElDatePicker
modelValue={form2.value.date}
type="date"
placeholder="选择时间"
clearable
onUpdate:modelValue={val => (form2.value.date = val)}
/>
</ElFormItem>
<ElFormItem>
<ElButton onClick={onSubmit}>停止检测</ElButton>
<ElButton type="primary" onClick={onSubmit}>批量操作</ElButton>
</ElFormItem>
</ElForm>
<ElTable
highlightCurrentRow
onCurrentChange={table1Current}
data={tableData1.value}
style={{width: "100%"}}
>
<ElTableColumn type="selection" width={55}/>
<ElTableColumn label="序号" type="index" width={60}/>
<ElTableColumn prop="Lon" label="目标经度" width={120}/>
<ElTableColumn prop="Lat" label="目标纬度" width={120}/>
<ElTableColumn label="告警等级" width={160}>
{{
default: scope => <ElRate modelValue={scope.row.rate || 3} disabled/>
}}
</ElTableColumn>
<ElTableColumn label="处理状态" showOverflowTooltip>
{{
default: scope => (
<>
<ElButton type="primary" link>已处理</ElButton>
<ElButton type="primary" link onClick={() => addShildItem()}>不处理</ElButton>
<ElButton type="primary" link>未发现</ElButton>
</>
)
}}
</ElTableColumn>
</ElTable>
</ElCard>
<ElCard shadow="always" style={{marginTop: "12px"}}>
<ElTable data={tableData2.value} style={{width: "100%"}}>
<ElTableColumn label="序号" type="index" width={60}/>
<ElTableColumn prop="name" label="目标名称" width={120}/>
<ElTableColumn prop="lon" label="目标经度" width={120}/>
<ElTableColumn prop="lat" label="目标纬度" width={120}/>
<ElTableColumn prop="deviation" label="deviation" width={120}/>
<ElTableColumn prop="shielding" label="shielding" width={120}/>
<ElTableColumn label="操作" showOverflowTooltip>
{{
default: scope => (
<ElButton type="primary" link onClick={() => delShildItem(scope.row)}>删除</ElButton>
)
}}
</ElTableColumn>
</ElTable>
</ElCard>
</div>
)}
{itemsId.value === 2 && (
<div class="tabsItem">
<ElCard shadow="always">
<ElForm inline model={form5.value} class="demo-form-inline">
<ElFormItem>
<ElInput
modelValue={form5.value.region}
placeholder="请输入机场名称"
style={{width: "200px"}}
onUpdate:modelValue={val => (form5.value.region = val)}
/>
</ElFormItem>
<ElFormItem>
<ElInput
modelValue={form5.value.region1}
placeholder="请输入区域名称"
style={{width: "200px"}}
onUpdate:modelValue={val => (form5.value.region1 = val)}
/>
</ElFormItem>
<ElFormItem>
<ElButton type="primary" onClick={onSubmit}>添加</ElButton>
</ElFormItem>
</ElForm>
<ElForm inline model={form6.value} class="demo-form-inline" style={{marginTop: "12px"}}>
<ElFormItem>
<ElSelect
modelValue={form6.value.region}
placeholder="请选择机场名称"
style={{width: "200px"}}
clearable
onUpdate:modelValue={val => select2Update(val)}
>
{
options1.value.map(i => {
return <ElOption label={i.name} value={i.id}/>
})
}
</ElSelect>
</ElFormItem>
<ElFormItem>
<ElSelect
modelValue={form6.value.region1}
placeholder="请选择区域名称"
style={{width: "200px"}}
clearable
onUpdate:modelValue={val => select3Update(val)}
>
{
options2.value.map(i => {
return <ElOption label={i.name} value={i.id}/>
})
}
</ElSelect>
</ElFormItem>
<ElFormItem>
<ElButton type="primary" onClick={getArea2}>确定</ElButton>
</ElFormItem>
</ElForm>
</ElCard>
<ElCard shadow="always" style={{marginTop: "12px"}}>
{areaPoints.value.map((i, k) => (
<div style={{marginBottom: "12px"}} key={k}>
<ElInput disabled onUpdate:modelValue={val => (areaPoints.value[k].name = val)}
modelValue={i.name}
placeholder="点位名称" style={{width: "100px"}}/>
<ElInput
modelValue={i.lon} placeholder="经度"
style={{width: "150px", marginLeft: "20px"}}
onUpdate:modelValue={val => (areaPoints.value[k].lon = val)}
/>
<ElInput
modelValue={i.lat} placeholder="纬度"
style={{width: "150px", marginLeft: "20px"}}
onUpdate:modelValue={val => (areaPoints.value[k].lat = val)}
/>
<ElButton type="primary" onClick={() => getPoint(k)}
style={{marginLeft: "20px"}}>获取</ElButton>
<ElButton type="danger"
onClick={() => DeleteCData({id: parseFloat(i.id)}).then(() => getArea2())}
style={{marginLeft: "20px"}}>删除</ElButton>
</div>
))}
<ElButton type="primary" onClick={() => {
InsertCListData([{
name: `点位${areaPoints.value.length + 1}`,
lon: '1',
lat: '1',
fodAreaId: form6.value.region1,
fodAirId: form6.value.region
}]).then(() => {
getArea2()
})
}}
style={{textAlign: "center"}}>添加</ElButton>
</ElCard>
<div style={{textAlign: "center", marginTop: "12px"}}>
<ElButton type="primary" onClick={saveAreaPoint} style={{marginLeft: "20px"}}>提交</ElButton>
</div>
</div>
)}
{itemsId.value === 3 && (
<div class="tabsItem">
<div>成像设置</div>
<ElForm model={parasSignalproForm.value} inline labelWidth="auto" labelPosition="top">
{["imaging_rangemin", "imaging_rangemax", "imaging_rangeres", "imaging_azimuthlength", "imaging_azimuthres"].map((key, idx) => (
<ElFormItem style={{width: "calc(33% - 32px)"}} label={key} key={idx}>
<ElInput
modelValue={(parasSignalproForm.value.imaging || {})[key]}
onUpdate:modelValue={val => ((parasSignalproForm.value.imaging ||= {})[key] = val)}
/>
</ElFormItem>
))}
</ElForm>
<div>检测设置</div>
<ElForm model={parasSignalproForm.value} inline labelWidth="auto" labelPosition="top">
{["alpha", "decstartr", "decwidth", "sk_r", "sk_a", "lk_r", "lk_a"].map((key, idx) => (
<ElFormItem style={{width: "calc(33% - 32px)"}} label={key} key={idx}>
<ElInput
modelValue={(parasSignalproForm.value.dectection || {})[key]}
onUpdate:modelValue={val => ((parasSignalproForm.value.dectection ||= {})[key] = val)}
/>
</ElFormItem>
))}
<ElFormItem style={{width: "100%"}}>
<div style={{textAlign: "center", width: "100%"}}>
<ElButton type="primary" onClick={saveParasSignalproForm}>保存</ElButton>
</div>
</ElFormItem>
</ElForm>
<div>路线设置</div>
<ElForm model={parasPosForm.value} inline labelWidth="auto" labelPosition="top">
<ElFormItem style={{width: "calc(33% - 32px)"}} label="路线数量">
<ElInputNumber
modelValue={(parasPosForm.value.runwaynum || {}).startpos_num}
precision={0}
step={1}
min={0}
onUpdate:modelValue={val => {
parasPosForm.value.runwaynum.startpos_num = val;
updateRunwayNum(val);
}}
/>
</ElFormItem>
{Array.from({length: (parasPosForm.value.runwaynum || {}).startpos_num || 0}).map((_, k) => (
<div key={k} style="width: 100%">
<div>路线{k + 1}设置</div>
{["startpos_lon_a", "startpos_lat_a", "startpos_alt_a", "startpos_lon_b", "startpos_lat_b", "startpos_alt_b", "startpos_ori"].map((field, idx) => (
<ElFormItem style={{width: "calc(33% - 32px)", display: "inline-block"}} label={field}
key={idx}>
<ElInput
modelValue={(parasPosForm.value.runwayedges[k] || {})[field]}
onUpdate:modelValue={val => (((parasPosForm.value.runwayedges[k] ||= {})[field] = val))}
/>
</ElFormItem>
))}
</div>
))}
<ElFormItem style={{width: "100%"}}>
<div style={{textAlign: "center", width: "100%"}}>
<ElButton type="primary" onClick={saveParasPosForm}>保存</ElButton>
</div>
</ElFormItem>
</ElForm>
</div>
)}
{itemsId.value === 4 && (
<div class="tabsItem">
<ElCard shadow="always">
<ElDatePicker
style={{width: "calc(100% - 20px)"}}
modelValue={date1.value}
type="datetimerange"
rangeSeparator="到"
startPlaceholder="选择开始时间"
endPlaceholder="选择结束时间"
onUpdate:modelValue={val => (date1.value = val)}
/>
</ElCard>
<ElCard shadow="always" style={{marginTop: "12px"}}>
<ElForm inline model={form3.value} class="demo-form-inline">
{["region", "region1", "region2"].map((key, idx) => (
<ElFormItem key={idx}>
{key === "region2" ? (
<ElSelect
modelValue={form3.value[key]}
placeholder="请选择固定目标"
style={{width: "170px"}}
clearable
onUpdate:modelValue={val => (form3.value[key] = val)}
>
<ElOption label="目标1" value="shanghai"/>
<ElOption label="目标2" value="beijing"/>
</ElSelect>
) : (
<ElSelect
modelValue={form3.value[key]}
placeholder={`请选择${key === "region" ? "机场" : "区域"}`}
style={{width: "170px"}}
clearable
onUpdate:modelValue={val => (form3.value[key] = val)}
>
<ElOption label="机场1" value="shanghai"/>
<ElOption label="机场2" value="beijing"/>
<ElOption label="区域1" value="shanghai"/>
<ElOption label="区域2" value="beijing"/>
</ElSelect>
)}
</ElFormItem>
))}
</ElForm>
</ElCard>
<ElCard shadow="always" style={{marginTop: "12px"}}>
<ElForm inline model={form4.value} class="demo-form-inline">
<ElFormItem>
<ElInput
modelValue={form4.value.input1}
placeholder="请输入检测序号"
style={{width: "170px"}}
onUpdate:modelValue={val => (form4.value.input1 = val)}
/>
</ElFormItem>
<ElFormItem>
<ElDatePicker
modelValue={form4.value.date1}
type="date"
placeholder="选择检测时间"
clearable
style={{width: "170px"}}
onUpdate:modelValue={val => (form4.value.date1 = val)}
/>
</ElFormItem>
<ElFormItem>
<ElInput
modelValue={form4.value.input2}
placeholder="请输入检测人员"
style={{width: "170px"}}
onUpdate:modelValue={val => (form4.value.input2 = val)}
/>
</ElFormItem>
</ElForm>
</ElCard>
<ElCard shadow="always" style={{marginTop: "12px"}}>
<ElTable data={tableData2.value} style={{width: "100%"}}>
<ElTableColumn label="序号" type="index" width={60}/>
<ElTableColumn prop="coordinate" label="目标坐标" width={120}/>
<ElTableColumn label="告警等级" width={160}>
{{default: scope => <ElRate modelValue={scope.row.rate} disabled/>}}
</ElTableColumn>
<ElTableColumn label="处理状态" showOverflowTooltip>
{{
default: scope => (
<>
<span>{scope.row.type === 1 ? "已处理" : ""}</span>
<span>{scope.row.type === 2 ? "不处理" : ""}</span>
<span>{scope.row.type === 3 ? "未发现" : ""}</span>
</>
)
}}
</ElTableColumn>
</ElTable>
</ElCard>
</div>
)}
</div>
)
}
})
const router = useRouter();
const toAdmin = () => {
router.push('/serve')
}
const areaType = ref(1)
// setTimeout(() => {
// setZoom({lon: 120.0005, lat: 30.005}, 2)
// }, 30000)
const socketData = [
{
"TimeQuality": 19124,
"GpsWeek": 2378,
"GpsSeconds": 443388.33,
"Latitude": 28.24388795549,
"Longitude": 113.00382002762,
"EllipsoidHeight": 14.6323,
"VelocityNorth": -0.1931,
"VelocityEast": 3.2447,
"ActualSpeed": 11.701587,
"RollAngle": 1.047412,
"HeadingAngle": 92.054855,
"IncludedAngle": 0.0,
"SolutionStatus": "",
"Fps": 3.485E-42,
"FpsNum": 0.0,
"MotorPitchAngle": 0.0,
"MotorAzimuthAngle": 0.0,
"ty": 3
},
{
"radar_type": 0,
"radar_ver": "0.1.1",
"arm_ver": "0.0.0",
"al_ver": "0.0.0",
"pwc_ver": "0.0.0",
"cd_ver": "0.0.0",
"v1": 0,
"v2": 0,
"v3": 0,
"v4": 0,
"radar_total_vol": 23.5,
"radar_total_cur": 0.0,
"nx_vol": 0.0,
"nx_cur": 0.0,
"nx_temp": 25.0,
"arm_vol": 23.5,
"arm_cur": 0.0,
"arm_temp": 25.0,
"ant_vol": 23.5,
"ant_cur": 0.0,
"ant_temp": 0.0,
"at_work_area_status": 0,
"pwb_err_code": 0,
"pwa_err_code": 0,
"al_err_code": 0,
"arm_err_code": 0,
"radar_err_code": 0,
"radar_work_state": 0,
"ty": 1
},
{
"Seq": 3.0,
"MD5": null,
"TimeStamp": 5.644776E+24,
"MissionID": 5.644776E+24,
"RngRes": 0.075,
"RngNum": 0.0,
"RngMin": 15.0,
"AziRes": 0.1,
"AziNum": 0.0,
"AziMin": 600.0,
"DataType": 2.8E-44,
"LonMin": 112.99582,
"LatMin": 28.242912,
"TarNum": 6E-45,
"ty": 4
}
]
let area = {
"LatMin": 0,
"LatMax": 0,
"LonMin": 0,
"LonMax": 0,
}
const dots = ref([
// {
// x: 150,
// y: 98
// },
// {
// x: 50,
// y: 102
// },
// {
// x: 75,
// y: 75
// },
// {
// x: 125,
// y: 125
// }
])
const points = ref([
{
lon: 120.38532472236,
lat: 36.14505053622,
name: '点位1',
},
{
lon: 120.38532472236,
lat: 36.15302618219,
name: '点位2',
},
{
lon: 120.39109582218,
lat: 36.15302618219,
name: '点位3',
},
{
lon: 120.39109582218,
lat: 36.14505053622,
name: '点位4',
},
])
const a = ref(window)
const list = ref([
{
value1: '点位1',
value2: '经纬度:(528,11)'
},
{
value1: '点位1',
value2: '经纬度:(528,11)'
},
{
value1: '点位1',
value2: '经纬度:(528,11)'
},
])
const rulerRef = ref()
const itemsId = ref(1)
const form1 = ref({})
const form2 = ref({})
const form3 = ref({})
const form4 = ref({})
const form5 = ref({})
const form6 = ref({})
const radarWorkState = ref(0)
const dotIndex = ref(-1)
const tableData1 = ref([])
const tableData2 = ref([
{
"id": 2,
"name": "测试",
"lon": 12.2299995,
"lat": 323.329987,
"deviation": 12,
"shielding": 20
},
{
"id": 1,
"name": "测试",
"lon": 12.2299995,
"lat": 323.329987,
"deviation": 12,
"shielding": 20
}
])
const date1 = ref([])
const setItemsId = (e) => {
itemsId.value = e
}
const locationData = ref({})
const currentPosition = ref({})
function calcRectangleFromPoints(points) {
if (!points || points.length !== 4) throw new Error("必须传入四个点");
const R = 111320;
const lat0 = points.reduce((a, b) => a + b.lat, 0) / 4;
const cosLat = Math.cos((lat0 * Math.PI) / 180);
// 经纬度转平面坐标
const toXY = p => ({
name: p.name,
x: p.lon * R * cosLat,
y: p.lat * R
});
const [p1, p2, p3, p4] = points.map(toXY);
// 距离函数
const dist = (a, b) => Math.sqrt((a.x - b.x) ** 2 + (a.y - b.y) ** 2);
// 各边长度
const top = dist(p2, p3);
const bottom = dist(p1, p4);
const left = dist(p4, p3);
const right = dist(p1, p2);
// 判断梯形上下边差异超过5%
const trapezoid = Math.abs(top - bottom) / Math.max(top, bottom) > 0.05;
let width, height;
if (trapezoid) {
// 使用平均宽高
width = (top + bottom) / 2;
height = (left + right) / 2;
} else {
width = bottom;
height = right;
}
// 计算旋转角度p1→p2
const angle = Math.atan2(p2.y - p1.y, p2.x - p1.x) * 180 / Math.PI;
return {
width: Math.floor(width.toFixed(2)),
height: Math.floor(height.toFixed(2)),
angle: Math.floor(angle.toFixed(2))
};
}
function getXYDistanceFromMin(current, minPoint) {
const R = 6371000; // 地球半径(米)
const toRad = deg => deg * Math.PI / 180;
// 计算两点之间某一维的距离
const haversineDistance = (lat1, lon1, lat2, lon2) => {
const dLat = toRad(lat2 - lat1);
const dLon = toRad(lon2 - lon1);
const a =
Math.sin(dLat / 2) ** 2 +
Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLon / 2) ** 2;
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return R * c;
};
// 横向距离(经度方向)
const xDistance = haversineDistance(minPoint.lat, minPoint.lon, minPoint.lat, current.lon);
// 纵向距离(纬度方向)
const yDistance = haversineDistance(minPoint.lat, minPoint.lon, current.lat, minPoint.lon);
return {xDistance, yDistance};
}
const processData = (data) => {
// console.log('data',data.ty)
// console.log('FodName', data.FodName)
if (data.FodName === '雷达信息') {
// console.log('雷达信息', data.radar_work_state)
radarWorkState.value = data.radar_work_state
}
if (data.FodName === '图像数据') {
}
if (data.FodName === 'fod信息') {
setDot(data)
}
if (data.ty === 3) {
}
if (data.FodName === '车辆信息') {
currentPosition.value = {
lon: data.Longitude,
lat: data.Latitude,
}
// boxPos.value = location
let data = getLocalPositionFromRect_Point1AsCenter({
lon: data.Longitude,
lat: data.Latitude,
rotate: data.HeadingAngle
}, areaPoints.value, areaData.value)
console.log(data)
}
};
const parasSignalproForm = ref({
imaging: {},
dectection: {}
})
const parasPosForm = ref({
runwaynum: {
startpos_num: 1
},
runwayedges: [
{
startpos_lon_a: '',
startpos_lat_a: '',
startpos_alt_a: '',
startpos_lon_b: '',
startpos_lat_b: '',
startpos_alt_b: '',
startpos_ori: ''
}
]
})
onMounted(() => {
getTableData()
ad()
getOption()
getShildTableList()
points.value = localStorage.getItem('points') ? JSON.parse(localStorage.getItem('points')) : [
{
lon: 117.213524,
lat: 36.837967,
name: '点位1',
},
{
lon: 117.213524,
lat: 36.847967,
name: '点位2',
},
{
lon: 117.223524,
lat: 36.847967,
name: '点位3',
},
{
lon: 117.223524,
lat: 36.837967,
name: '点位4',
},
]
getArea1()
// setDot({
// "DarDatas": [{"Lon": 117.213524, "Lat": 36.837967}, {"Lon": 0.0, "Lat": 0.0}, {
// "Lon": 0.0,
// "Lat": 0.0
// }, {"Lon": 0.0, "Lat": 0.0}, {"Lon": 117.2134, "Lat": 36.837967}, {"Lon": 0.0, "Lat": 0.0}, {
// "Lon": 0.0,
// "Lat": 0.0
// }, {"Lon": 0.0, "Lat": 0.0}, {"Lon": 117.21341, "Lat": 36.837986}, {"Lon": 0.0, "Lat": 0.0}, {
// "Lon": 0.0,
// "Lat": 0.0
// }, {"Lon": 0.0, "Lat": 0.0}, {"Lon": 117.21337, "Lat": 36.838}, {"Lon": 0.0, "Lat": 0.0}],
// "Seq": 0,
// "MD5": "038fb0493c415f58c703ab205f9f2c94",
// "TimeStamp": 1757556826,
// "MissionID": 1757556826,
// "RngRes": 0.075,
// "RngNum": 0,
// "RngMin": 10.0,
// "AziRes": 0.1,
// "AziNum": 0,
// "AziMin": 0.03593219,
// "DataType": 20,
// "LonMin": 117.213844,
// "LatMin": 36.83799,
// "TarNum": 14,
// "ty": 0,
// "FodName": "fod信息"
// })
})
const getOption = () => {
getParasPos().then((e) => {
parasPosForm.value = {
runwaynum: e.runwaynum,
runwayedges: e.runwayedges,
}
})
getParasSignalpro().then((e) => {
parasSignalproForm.value = {
imaging: e.imaging,
dectection: e.dectection,
}
})
}
const saveParasSignalproForm = () => {
setParasSignalpro(parasSignalproForm.value).then(e => {
console.log(e)
})
}
const saveParasPosForm = () => {
setParasPos(parasPosForm.value).then(e => {
console.log(e)
})
}
const updateRunwayNum = (e) => {
let arr = new Array(e).fill(0)
.map((item, index) => {
if (index <= parasPosForm.value.runwayedges.length - 1) {
return JSON.parse(JSON.stringify(parasPosForm.value.runwayedges[index]))
} else {
return {
startpos_lon_a: '',
startpos_lat_a: '',
startpos_alt_a: '',
startpos_lon_b: '',
startpos_lat_b: '',
startpos_alt_b: '',
startpos_ori: ''
}
}
})
console.log(arr)
parasPosForm.value.runwayedges = JSON.parse(JSON.stringify(arr))
}
const addShildItem = () => {
addShildData({
name: 'string',
lon: 123,
lat: 12,
deviation: 12,
shielding: 23
}).then(e => {
getShildTableList()
})
}
const delShildItem = (e) => {
delShildData(e).then(e => {
getShildTableList()
})
}
const getShildTableList = () => {
getShildList({
pageIndex: 1,
pageSize: 10,
name: 'string'
}).then((e) => {
tableData2.value = e.data
})
}
const ad = () => {
// 1. 创建 WebSocket 连接ws:// 或 wss://
// const socket = new WebSocket("ws://192.168.1.123:7789/ws");
const socket = new WebSocket("ws://192.168.1.123:7789/ws");
// 2. 连接成功时触发
socket.addEventListener("open", () => {
console.log("✅ WebSocket 连接成功");
});
// 3. 接收消息
socket.addEventListener("message", (event) => {
console.log(JSON.parse(event.data))
processData(JSON.parse(event.data))
});
// 4. 连接关闭时触发
socket.addEventListener("close", () => {
console.log("❌ WebSocket 已关闭");
});
// 5. 出错时触发
socket.addEventListener("error", (error) => {
console.error("⚠️ WebSocket 出错:", error);
});
}
const StartWorkBtn = () => {
StartWork()
rulerRef.value.setDot([], true)
tableData1.value = []
}
const StopWorkBtn = () => {
StopWork()
}
const RestartWorkBtn = () => {
RestartWork()
}
const ShutDownWorkBtn = () => {
ShutDownWork()
}
const getPoint = (k) => {
areaPoints.value[k].lon = currentPosition.value.lon || 0
areaPoints.value[k].lat = currentPosition.value.lat || 0
}
const getArea1 = () => {
if (points.value.length < 4) return
let data = points.value
let latMin = data[0].lat;
let latMax = data[0].lat;
let lonMin = data[0].lon;
let lonMax = data[0].lon;
for (let i = 1; i < data.length; i++) {
const p = data[i];
if (p.lat < latMin) latMin = p.lat;
if (p.lat > latMax) latMax = p.lat;
if (p.lon < lonMin) lonMin = p.lon;
if (p.lon > lonMax) lonMax = p.lon;
}
// area = {
// LatMin: latMin,
// LatMax: latMax,
// LonMin: lonMin,
// LonMax: lonMax,
// }
}
const savePoint = () => {
localStorage.setItem('points', JSON.stringify(points.value))
getArea1()
}
const setDot = (e) => {
let dots = e.DarDatas.map((v, k) => {
if (v.Lon == 0 && v.Lat == 0) return null
let xAndy = getXYDistanceFromMin({lon: v.Lon, lat: v.Lat}, {lon: area.LonMin, lat: area.LatMin})
let location = {}
if (areaType.value === 1) {
location = {
x: xAndy.xDistance,
y: xAndy.yDistance,
}
} else if (areaType.value === 2) {
location = {
x: areaData.value.width - xAndy.yDistance,
y: xAndy.xDistance,
}
} else if (areaType.value === 3) {
location = {
x: areaData.value.width - xAndy.xDistance,
y: areaData.value.height - xAndy.yDistance,
}
} else if (areaType.value === 4) {
location = {
x: xAndy.yDistance,
y: areaData.value.height - xAndy.xDistance,
}
} else {
location = {
x: xAndy.xDistance,
y: xAndy.yDistance,
}
}
return location
}).filter(v => v)
tableData1.value = [...tableData1.value, ...e.DarDatas.filter(v => v.Lon !== 0 && v.Lat !== 0).map((v, k) => {
return {...v, index: k}
})]
rulerRef.value.setDot(dots, false)
}
const table1Current = (e, v) => {
if (dotIndex.value === e.index) {
dotIndex.value = -1
} else {
dotIndex.value = e.index || 0
}
console.log(e)
}
const options1 = ref([])
const options2 = ref([])
const getTableData = async () => {
await getAllAirPort().then(e => {
options1.value = e.data
})
}
const selectUpdate = (val) => {
form1.value.region = val
getArea({airId: val}).then(e => {
options2.value = e.data
})
}
const select2Update = (val) => {
form6.value.region = val
getArea({airId: val}).then(e => {
options2.value = e.data
})
}
const select3Update = (val) => {
form6.value.region1 = val
}
const areaPoints = ref([])
const getArea2 = () => {
GetAllCData({areaId: form6.value.region1}).then((res) => {
areaPoints.value = res.data
})
}
function getBoundingBoxAndSize(pointsArr) {
if (!pointsArr || pointsArr.length === 0) {
throw new Error('pointsArr 不能为空');
}
let maxLon = Math.max(...pointsArr.map(p => p.lon));
let minLon = Math.min(...pointsArr.map(p => p.lon));
let maxLat = Math.max(...pointsArr.map(p => p.lat));
let minLat = Math.min(...pointsArr.map(p => p.lat));
const R = 6371000;
const toRad = deg => deg * Math.PI / 180;
// Haversine 距离计算
const haversineDistance = (lat1, lon1, lat2, lon2) => {
const dLat = toRad(lat2 - lat1);
const dLon = toRad(lon2 - lon1);
const a =
Math.sin(dLat / 2) ** 2 +
Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLon / 2) ** 2;
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return R * c;
};
// 宽度(东西方向)
const width = Math.round(haversineDistance(minLat, minLon, minLat, maxLon));
// 高度(南北方向)
const height = Math.round(haversineDistance(minLat, minLon, maxLat, minLon));
// 左下角参考点
const refPoint = {lon: maxLon, lat: minLat};
// 找出距离 refPoint 最近的点
let nearestPoint = null;
let nearestDistance = Infinity;
for (const p of pointsArr) {
const d = haversineDistance(refPoint.lat, refPoint.lon, p.lat, p.lon);
if (d < nearestDistance) {
nearestDistance = d;
nearestPoint = p;
}
}
if (nearestPoint.name === '点位1') {
areaType.value = 1
}
if (nearestPoint.name === '点位2') {
areaType.value = 2
}
if (nearestPoint.name === '点位3') {
areaType.value = 3
}
if (nearestPoint.name === '点位4') {
areaType.value = 4
}
console.log(nearestPoint)
return {
width: (areaType.value === 1 || areaType.value === 3) ? width : height,
height: (areaType.value === 1 || areaType.value === 3) ? height : width,
minLat,
minLon,
maxLat,
maxLon,
nearestPoint, // 距离左下角最近的点
nearestDistance: Math.round(nearestDistance) // 方便调试用
};
}
function getLocalPositionFromRect_Point1AsCenter(point, rectPoints, rectInfo) {
const R = 111320;
const lat0 = rectPoints.reduce((a, b) => a + b.lat, 0) / rectPoints.length;
const cosLat = Math.cos((lat0 * Math.PI) / 180);
const toXY = p => ({
name: p.name,
x: p.lon * R * cosLat,
y: p.lat * R
});
const pts = rectPoints.map(toXY);
const p1 = pts.find(p => p.name === "点位1"); // 右下角 ✅旋转中心
const p4 = pts.find(p => p.name === "点位4"); // 左下角 ✅原点
const p = toXY(point);
const angle = Number(rectInfo.angle);
const rad = (-angle * Math.PI) / 180;
// 1⃣ 先求相对于点位1的偏移
const dx1 = p.x - p1.x;
const dy1 = p.y - p1.y;
const x1_local = dx1 * Math.cos(rad) - dy1 * Math.sin(rad);
const y1_local = dx1 * Math.sin(rad) + dy1 * Math.cos(rad);
// 2⃣ 求点位4相对于点位1的局部坐标用来平移
const dx14 = p4.x - p1.x;
const dy14 = p4.y - p1.y;
const x14_local = dx14 * Math.cos(rad) - dy14 * Math.sin(rad);
const y14_local = dx14 * Math.sin(rad) + dy14 * Math.cos(rad);
// 3⃣ 相对于左下角(点4)
const x_local = x1_local - x14_local;
const y_local = y1_local - y14_local;
// 4⃣ 相对旋转角
const rotate_local = ((point.rotate ?? 0) - angle + 360) % 360;
return {
x: x_local.toFixed(2),
y: y_local.toFixed(2),
rotate: rotate_local.toFixed(2)
};
}
const areaData = ref({
width: 500,
height: 1000,
angle: 0
})
const saveAreaPoint = () => {
let arr = []
areaPoints.value.forEach((v, k) => {
arr.push(UpdateCData(v))
})
Promise.all(arr).then(() => {
ElMessage.success('保存成功')
let data = calcRectangleFromPoints(areaPoints.value)
console.log(data)
areaData.value = data
}).catch((err) => {
ElMessage.error(err)
})
}
</script>
<style>
.app-container {
width: 1080px;
min-width: 1080px;
height: 100vh;
margin: 0 auto;
}
.top {
width: 100%;
height: 80px;
font-size: 24px;
background-color: #202227;
position: relative;
}
.items {
position: absolute;
top: 15%;
left: 50%;
transform: translateX(-50%);
white-space: nowrap;
}
.item {
display: inline-block;
width: 120px;
height: 100%;
color: #8C9A9C;
line-height: 56px;
cursor: pointer;
font-size: 18px;
font-weight: 600;
letter-spacing: 2px;
}
.item span {
display: inline-block;
height: 100%;
}
.item.click span,
.item:hover span {
color: #0D52BF;
border-bottom: 2px solid #0D52BF;
}
.title {
line-height: 80px;
color: #fff;
margin-left: 20px;
display: inline-block;
text-align: left;
}
.left {
display: inline-block;
height: calc(100vh - 80px);
width: 34%;
vertical-align: top;
}
.right {
padding: 20px 20px 0 20px;
display: inline-block;
height: calc(100vh - 80px - 20px);
width: calc(66% - 40px);
background-color: #F6F7FB;
overflow: auto;
}
</style>