媒体库-历史路径展示-第二版

main
滕嵩 2 months ago
parent d268f408f4
commit 2b8470cd06

@ -244,7 +244,7 @@
:mask="false"
:maskClosable="false"
>
<Path @closePathModal="closePathModal" />
<Path :pathRecord="pathRecord" @closePathModal="closePathModal" />
</a-modal>
</PageWrapper>
</template>
@ -820,11 +820,14 @@
// ----------------------------------------------------------------------
const pathOpen = ref(false);
//
const pathRecord = ref({});
function openPathModal(record) {
pathRecord.value = record;
pathOpen.value = true;
}
//
function closePathModal() {
pathRecord.value = {};
pathOpen.value = false;
}
</script>

@ -1,88 +1,230 @@
<template>
<div class="pathModal">
<!-- 左侧目录 -->
<div
class="leftMenuDiv"
:style="{
width: leftMenuShow ? '300px' : '40px',
width: leftMenuShow ? '340px' : '64px',
}"
>
<PathLeftMenu
ref="pathLeftMenuRef"
:pathRecord="props.pathRecord"
:leftMenuShow="leftMenuShow"
:allImageDataList="dataJson"
:allMarkDataList="allMarkDataList"
:nowShowMarkData="nowShowMarkData"
:allAreaDataList="allAreaDataList"
:nowShowAreaData="nowShowAreaData"
:allImageDataList="allImageDataList"
:nowShowImageData="nowShowImageData"
@changeLeftMenuShow="changeLeftMenuShow"
@handlerLocation="handlerLocation"
@closePathModal="closePathModal"
@changeMarkInfoShow="changeMarkInfoShow"
@setNowShowMarkData="setNowShowMarkData"
@setNowShowImageData="setNowShowImageData"
@setNowShowAreaData="setNowShowAreaData"
@deleteMark="deleteMark"
@deleteArea="deleteArea"
/>
</div>
<!-- 地图 -->
<div class="mapDiv" :style="{ width: dynamicWidth }">
<PathMap
ref="pathMapRef"
:allImageDataList="dataJson"
:allMarkDataList="allMarkDataList"
:nowShowMarkData="nowShowMarkData"
:allAreaDataList="allAreaDataList"
:nowShowAreaData="nowShowAreaData"
:allImageDataList="allImageDataList"
:nowShowImageData="nowShowImageData"
@setNowShowMarkData="setNowShowMarkData"
@setNowShowImageData="setNowShowImageData"
@closePathImage="closePathImage"
@setNowShowAreaData="setNowShowAreaData"
@closePathImageInfo="closePathImageInfo"
/>
</div>
<!-- 地图标注 -->
<div class="markInfoDiv" v-if="markInfoShow">
<PathMarkInfo
:allMarkDataList="allMarkDataList"
:nowShowMarkData="nowShowMarkData"
@setNowShowMarkData="setNowShowMarkData"
@closePathMarkInfo="closePathMarkInfo"
@handlerLocation="handlerLocation"
@deleteMark="deleteMark"
/>
</div>
<!-- 地图作业区域 -->
<div class="areaInfoDiv" v-if="areaInfoShow">
<PathAreaInfo
:allAreaDataList="allAreaDataList"
:nowShowAreaData="nowShowAreaData"
@setNowShowAreaData="setNowShowAreaData"
@closePathAreaInfo="closePathAreaInfo"
@handlerLocation="handlerLocation"
@deleteArea="deleteArea"
/>
</div>
<div class="imageShowDiv" v-if="pathImageShow">
<PathImageShow
:allImageDataList="dataJson"
<!-- 地图照片 -->
<div class="imageInfoDiv" v-if="imageInfoShow">
<PathImageInfo
:allImageDataList="allImageDataList"
:nowShowImageData="nowShowImageData"
@setNowShowImageData="setNowShowImageData"
@closePathImage="closePathImage"
@closePathImageInfo="closePathImageInfo"
@handlerLocation="handlerLocation"
/>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, computed } from 'vue';
import { PathLeftMenu, PathMap, PathImageShow } from './path';
import dataJson from './data.json';
import { ref, computed, onMounted } from 'vue';
import { PathLeftMenu, PathMap, PathMarkInfo, PathAreaInfo, PathImageInfo } from './path';
import { cloneDeep } from 'lodash-es';
import markJson from './json/mark.json';
import areaJson from './json/area.json';
import imageJson from './json/image.json';
import { useMessage } from '@/hooks/web/useMessage';
const { createMessage, createConfirm } = useMessage();
const props = defineProps(['']);
const props = defineProps(['pathRecord']);
const emits = defineEmits(['closePathModal']);
//
const dynamicWidth = computed(() => {
let width = 0;
//
if (leftMenuShow.value) {
return pathImageShow.value ? 'calc(100% - 1020px)' : 'calc(100% - 300px)';
width += 340;
} else {
return pathImageShow.value ? 'calc(100% - 760px)' : 'calc(100% - 40px)';
width += 64;
}
//
if (markInfoShow.value) {
width += 320;
}
//
if (areaInfoShow.value) {
width += 320;
}
//
if (imageInfoShow.value) {
width += 720;
}
return 'calc(100% - ' + width + 'px)';
});
// ref
const pathMapRef = ref();
// ----------------------------------------------------
const pathLeftMenuRef = ref();
const leftMenuShow = ref(true);
function changeLeftMenuShow() {
leftMenuShow.value = !leftMenuShow.value;
}
// ----------------------------------------------------
const markInfoShow = ref(false);
function changeMarkInfoShow() {
markInfoShow.value = !markInfoShow.value;
}
//
function closePathMarkInfo() {
markInfoShow.value = false;
nowShowMarkData.value = {};
}
//
const nowShowMarkData = ref();
const allMarkDataList = ref(markJson);
//
function setNowShowMarkData(value) {
if (value) {
markInfoShow.value = true;
} else {
markInfoShow.value = false;
}
nowShowMarkData.value = value;
}
//
function deleteMark(value) {
allMarkDataList.value = cloneDeep(allMarkDataList.value).filter((item) => item.id != value.id);
markInfoShow.value = false;
nowShowMarkData.value = {};
setTimeout(() => {
pathLeftMenuRef.value.updateShowMenuInfoList('地图标注');
}, 50);
createMessage.success('标注删除成功');
}
// ----------------------------------------------------
const areaInfoShow = ref(false);
function changeAreaInfoShow() {
areaInfoShow.value = !areaInfoShow.value;
}
//
function closePathAreaInfo() {
areaInfoShow.value = false;
nowShowAreaData.value = {};
}
//
const nowShowAreaData = ref();
const allAreaDataList = ref(areaJson);
//
function setNowShowAreaData(value) {
if (value) {
areaInfoShow.value = true;
} else {
areaInfoShow.value = false;
}
nowShowAreaData.value = value;
}
//
function deleteArea(value) {
allAreaDataList.value = cloneDeep(allAreaDataList.value).filter((item) => item.id != value.id);
areaInfoShow.value = false;
nowShowAreaData.value = {};
setTimeout(() => {
pathLeftMenuRef.value.updateShowMenuInfoList('地图作业区域');
}, 50);
}
// ----------------------------------------------------
const imageInfoShow = ref(false);
//
function closePathImageInfo() {
imageInfoShow.value = false;
}
//
const nowShowImageData = ref();
const pathMapRef = ref();
const allImageDataList = ref(imageJson);
//
function setNowShowImageData(value) {
if (value) {
pathImageShow.value = true;
imageInfoShow.value = true;
} else {
pathImageShow.value = false;
imageInfoShow.value = false;
}
nowShowImageData.value = value;
pathMapRef.value.setNowShowImageByRight();
}
//
const leftMenuShow = ref(false);
function changeLeftMenuShow() {
leftMenuShow.value = !leftMenuShow.value;
}
//
const pathImageShow = ref(false);
//
function closePathImage() {
pathImageShow.value = false;
}
// -----------------------------------------------------------------
//
function closePathModal() {
emits('closePathModal');
}
//
function handlerLocation(position) {
pathMapRef.value.handlerLocation([position.lng, position.lat]);
}
onMounted(() => {
nowShowMarkData.value = markJson[1];
});
</script>
<style lang="less" scoped>
.pathModal {
@ -94,7 +236,6 @@
.leftMenuDiv {
position: relative;
height: 100%;
width: 300px;
}
.mapDiv {
@ -103,7 +244,19 @@
// width: auto;
}
.imageShowDiv {
.markInfoDiv {
position: relative;
height: 100%;
width: 320px;
}
.areaInfoDiv {
position: relative;
height: 100%;
width: 320px;
}
.imageInfoDiv {
position: relative;
height: 100%;
// width: 37%;

@ -0,0 +1,302 @@
[
{
"id": "f8a1ba2f-3d75-45e3-8c37-c305b8a8a18f",
"name": "noland-2025-07-03 09:37",
"status": "enable",
"type": "noland",
"content": {
"type": "Feature",
"geometry": {
"type": "Polyline",
"coordinates": [
[
[
113.94250795742009,
22.58060189921086
],
[
113.94251951924755,
22.580338767560157
],
[
113.94278841610303,
22.580473014976874
],
[
113.94264963349448,
22.580583102519093
],
[
113.9425571112225,
22.580658284012188
]
]
]
},
"properties": {
"color": "#FF9900",
"width": 50,
"clampToGround": true
}
},
"area_hash": "enable_noland_64e037d7470402c7ab2fac8e314dcfd6",
"created_time": 1751506632716,
"created_by": "1921832882836627456",
"created_nickname": "17854119262",
"updated_time": 1751506632716,
"updated_by": "1921832882836627456",
"updated_nickname": "17854119262"
},
{
"id": "4b312405-a1f9-4326-b7ad-f684912931c7",
"name": "fence-2025-07-03 09:36",
"status": "enable",
"type": "dfence",
"content": {
"type": "Feature",
"geometry": {
"type": "Circle",
"radius": 15.568918453415524,
"coordinates": [
113.94244540081064,
22.581260697110643
]
},
"properties": {
"color": "#00FF00"
}
},
"area_hash": "enable_dfence_cec1fe6f1bdf6ba3de183332ec941336",
"created_time": 1751506620283,
"created_by": "1921832882836627456",
"created_nickname": "17854119262",
"updated_time": 1751699622015,
"updated_by": "1921832882836627456",
"updated_nickname": "17854119262"
},
{
"id": "5ef9074f-332e-4c2c-8caf-0d5e9c2d4bb0",
"name": "fence-2025-07-03 09:36",
"status": "enable",
"type": "dfence",
"content": {
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
113.94217071448199,
22.580710270949893
],
[
113.94234419200872,
22.580557223329823
],
[
113.94234708696375,
22.580804244635136
],
[
113.942101324811,
22.580866002541086
],
[
113.94217071448199,
22.580710270949893
]
]
]
},
"properties": {
"color": "#00FF00",
"width": 50,
"clampToGround": true
}
},
"area_hash": "enable_dfence_491bd3ba995a30b943fce12cd277f319",
"created_time": 1751506610758,
"created_by": "1921832882836627456",
"created_nickname": "17854119262",
"updated_time": 1751506610758,
"updated_by": "1921832882836627456",
"updated_nickname": "17854119262"
},
{
"id": "c30566e1-efcd-4d23-9f7e-d103816ebf22",
"name": "nfz-2025-07-03 09:36",
"status": "enable",
"type": "nfz",
"content": {
"type": "Feature",
"geometry": {
"type": "Circle",
"radius": 21.689063819799266,
"coordinates": [
113.94177749877194,
22.58107812199575
]
},
"properties": {
"color": "#FF0000"
}
},
"area_hash": "enable_nfz_d1da0a6137ef50153537ee83155f5cef",
"created_time": 1751506599545,
"created_by": "1921832882836627456",
"created_nickname": "17854119262",
"updated_time": 1751506599545,
"updated_by": "1921832882836627456",
"updated_nickname": "17854119262"
},
{
"id": "8fb48c63-b840-448d-b331-0e0dd505cdb2",
"name": "nfz-2025-07-03 09:36",
"status": "enable",
"type": "nfz",
"content": {
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
113.94081757610996,
22.581070072300122
],
[
113.94103442563689,
22.580927765651026
],
[
113.94117610149931,
22.581056645867445
],
[
113.94095925169468,
22.58111303220476
],
[
113.94081757610996,
22.581070072300122
]
]
]
},
"properties": {
"color": "#FF0000",
"width": 50,
"clampToGround": true
}
},
"area_hash": "enable_nfz_069b0cdcae471e9849ff2af1c407cb63",
"created_time": 1751506590102,
"created_by": "1921832882836627456",
"created_nickname": "17854119262",
"updated_time": 1751506590102,
"updated_by": "1921832882836627456",
"updated_nickname": "17854119262"
},
{
"id": "53d34e36-83a1-4f27-9379-59916ac22f94",
"name": "作业区",
"status": "disable",
"type": "dfence",
"content": {
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
113.93691743280002,
22.580990598743295,
13.105187747054286
],
[
113.93696596905927,
22.57814717285005,
50.58228204435394
],
[
113.9391350491713,
22.57816355777337,
62.20456885650349
],
[
113.93905350496071,
22.5810254053995,
14.889189566602015
],
[
113.93691743280002,
22.580990598743295,
13.105187747054286
]
]
]
},
"properties": {
"color": "#00FF00"
}
},
"area_hash": "disable_dfence_d0dc9ea80f32a4ddf9737ed27059da89",
"created_time": 1747035695040,
"created_by": "",
"created_nickname": "",
"updated_time": 1751700024743,
"updated_by": "1921832882836627456",
"updated_nickname": "17854119262"
},
{
"id": "189b2247-a5be-49ef-83cb-768056a00ed6",
"name": "限飞区",
"status": "disable",
"type": "nfz",
"content": {
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
113.93818303751036,
22.57955559024499
],
[
113.93817466012537,
22.579329971314916
],
[
113.93810624285746,
22.579017475880626
],
[
113.93833802482754,
22.57902266288293
],
[
113.93833942091635,
22.57956207360456
],
[
113.93818303751036,
22.57955559024499
]
]
]
},
"properties": {
"color": "#FF0000",
"clampToGround": true
}
},
"area_hash": "disable_nfz_d362c13ac83407d94d7e8754f25b1f8d",
"created_time": 1747035694853,
"created_by": "",
"created_nickname": "",
"updated_time": 1751700027203,
"updated_by": "1921832882836627456",
"updated_nickname": "17854119262"
}
]

@ -0,0 +1,348 @@
[
{
"id": "302914d9-cb64-42b6-b149-504a8da5fc57",
"name": "限时通行",
"order": 0,
"status": 1,
"display": 1,
"resource": {
"content": {
"type": "Feature",
"properties": {
"color": "#2D8CF0",
"is3d": false,
"font_size": 24,
"line_width": 13,
"line_start_cap": 0,
"line_end_cap": 3
},
"geometry": {
"type": "LineString",
"coordinates": [
[
113.93791036656113,
22.580846919934572,
16.289661439575617
],
[
113.93790662794272,
22.58080525893029,
16.978841881531686
],
[
113.93793537498757,
22.580571144993392,
20.678091836753808
],
[
113.93771086752942,
22.580362654641405,
24.05391008697749
],
[
113.93799551314106,
22.58016161251263,
26.888214419326214
],
[
113.93793224643738,
22.579899786408422,
31.450909981361924
]
]
}
},
"type": 1,
"user_name": "",
"user_id": "",
"remark": ""
},
"update_time": 1751619820885,
"create_time": 1729664978199,
"elevation_load_status": 0
},
{
"id": "5f26f8ac-5a35-4254-93a0-0bfc73765c78",
"name": "禁止停车区域",
"order": 0,
"status": 1,
"display": 1,
"resource": {
"content": {
"type": "Feature",
"properties": {
"color": "#B620E0",
"is3d": false
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
113.93710053086316,
22.579672717186753,
23.320508205597196
],
[
113.93794932236936,
22.579691102044677,
34.89822401294342
],
[
113.93880753828225,
22.579712215916796,
27.103696311361936
],
[
113.93880540494872,
22.579771626594315,
25.942309355632386
],
[
113.93709983416198,
22.579734423484975,
23.235941922329605
]
]
]
}
},
"type": 2,
"user_name": "",
"user_id": "",
"remark": ""
},
"update_time": 1751620038100,
"create_time": 1729664978199,
"elevation_load_status": 0
},
{
"id": "f52f7506-8b18-4447-a323-8c49033de5c8",
"name": "出入口2",
"order": 0,
"status": 1,
"display": 1,
"resource": {
"content": {
"type": "Feature",
"properties": {
"color": "#19BE6B",
"is3d": false,
"font_size": 16,
"clampToGround": false
},
"geometry": {
"type": "Point",
"coordinates": [
113.938434636,
22.580695156,
8982.852151371233
]
}
},
"type": 0,
"user_name": "",
"user_id": "",
"remark": ""
},
"update_time": 1751593215069,
"create_time": 1729664978199,
"elevation_load_status": 0
},
{
"id": "05739f91-a6c3-4ba4-9e95-57c75e099a94",
"name": "17854119262 1",
"order": 0,
"status": 0,
"display": 1,
"resource": {
"content": {
"type": "Feature",
"properties": {
"color": "#B620E0",
"clampToGround": true,
"is3d": false,
"font_size": 16,
"icon": -4
},
"geometry": {
"type": "Point",
"coordinates": [
113.9406391943762,
22.580527744164762,
21.51958588283192
],
"breadCrumbs": null
}
},
"type": 0,
"user_name": "17854119262",
"user_id": "1921832882836627456",
"remark": ""
},
"update_time": 1751685220114,
"create_time": 1751448270707,
"elevation_load_status": 0
},
{
"id": "9c991a85-8d8f-476f-bece-67ce0c554d55",
"name": "17854119262 2123",
"order": 0,
"status": 0,
"display": 1,
"resource": {
"content": {
"type": "Feature",
"properties": {
"color": "#2D8CF0",
"is3d": false,
"line_width": 5,
"line_start_cap": 3,
"line_end_cap": 3
},
"geometry": {
"type": "LineString",
"coordinates": [
[
113.94138861698154,
22.580643029700447,
20.832049922045826
],
[
113.9413698107081,
22.5800551336431,
23.231842464666247
],
[
113.94119605807259,
22.579448966138774,
26.76552516976654
],
[
113.94156736523672,
22.579691602916927,
28.181016541167885
]
]
}
},
"type": 1,
"user_name": "17854119262",
"user_id": "1921832882836627456",
"remark": "线"
},
"update_time": 1751685219204,
"create_time": 1751506017591,
"elevation_load_status": 0
},
{
"id": "1e1a0eb8-22af-41b0-ad3a-f79292e128c5",
"name": "17854119262 1",
"order": 0,
"status": 0,
"display": 1,
"resource": {
"content": {
"type": "Feature",
"properties": {
"color": "#2D8CF0",
"is3d": false
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
113.94179483601683,
22.5803370571891,
24.600344506309114
],
[
113.94193361411388,
22.579958468841305,
29.67288586963777
],
[
113.94226611869635,
22.58025381696287,
28.052565527104434
]
]
]
}
},
"type": 2,
"user_name": "17854119262",
"user_id": "1921832882836627456",
"remark": "矩"
},
"update_time": 1751685218498,
"create_time": 1751506060690,
"elevation_load_status": 0
},
{
"id": "92c3fb1e-fa82-48bf-911d-af742c737c96",
"name": "17854119262 2",
"order": 0,
"status": 0,
"display": 1,
"resource": {
"content": {
"type": "Feature",
"properties": {
"color": "#2D8CF0",
"clampToGround": true,
"is3d": false
},
"geometry": {
"radius": 23.519013068778005,
"type": "Circle",
"coordinates": [
113.94093593815374,
22.58033819250183
],
"breadCrumbs": null
}
},
"type": 3,
"user_name": "17854119262",
"user_id": "1921832882836627456",
"remark": "圈"
},
"update_time": 1751685217792,
"create_time": 1751530265940,
"elevation_load_status": 0
},
{
"id": "6d522cc6-3d9e-4b08-9b7c-b578314e8b50",
"name": "出入口1",
"order": 0,
"status": 1,
"display": 1,
"resource": {
"content": {
"type": "Feature",
"properties": {
"color": "#2D8CF0",
"clampToGround": false,
"is3d": false
},
"geometry": {
"type": "Point",
"coordinates": [
113.93743037203272,
22.580735812179856,
8985.824886104954
]
}
},
"type": 0,
"user_name": "",
"user_id": "",
"remark": "点"
},
"update_time": 1751611711104,
"create_time": 1729664978199,
"elevation_load_status": 0
}
]

@ -1,3 +1,5 @@
export { default as PathLeftMenu } from './pathLeftMenu.vue';
export { default as PathImageShow } from './pathImageShow.vue';
export { default as PathMap } from './pathMap.vue';
export { default as PathImageInfo } from './pathImageInfo.vue';
export { default as PathMarkInfo } from './pathMarkInfo.vue';
export { default as PathAreaInfo } from './pathAreaInfo.vue';

@ -0,0 +1,437 @@
<template>
<div class="areaInfo">
<a-row>
<a-col :span="24">
<div class="markTitle"> 自定义飞行区 </div>
</a-col>
<a-col :span="24">
<div class="markTitle">
<!-- 自定义限飞区 -->
<div
v-if="props.nowShowAreaData.type == 'noland'"
:style="{
width: '13px',
height: '13px',
outline: `2px solid ${props.nowShowAreaData.content.properties.color}`,
'margin-left': '2px',
'margin-right': '12px',
}"
/>
<!-- 自定义作业区 -->
<div
v-if="props.nowShowAreaData.type == 'dfence'"
:style="{
width: '13px',
height: '13px',
outline: `2px solid ${props.nowShowAreaData.content.properties.color}`,
'margin-left': '2px',
'margin-right': '12px',
'border-radius':
props.nowShowAreaData.content.geometry.type == 'Circle' ? '6.5px' : '0px',
}"
/>
<!-- 自定义禁降区 -->
<div
v-if="props.nowShowAreaData.type == 'nfz'"
:style="{
width: '13px',
height: '13px',
outline: `2px solid ${props.nowShowAreaData.content.properties.color}`,
background: `${props.nowShowAreaData.content.properties.color}55`,
'margin-left': '2px',
'margin-right': '12px',
'border-radius':
props.nowShowAreaData.content.geometry.type == 'Circle' ? '6.5px' : '0px',
}"
/>
<a-input v-model:value="nowAreaData.name" style="width: 65%" size="small"></a-input>
<div class="markTitleButton" @click="handlerLocation">
<AimOutlined />
</div>
<div class="markTitleButton" @click="deleteArea">
<DeleteOutlined />
</div>
</div>
</a-col>
<a-col :span="24">
<div class="markPrompt" v-if="props.nowShowAreaData.type == 'noland'">
自定义作业区绘制后飞行器只能在该区域内飞行
</div>
<div class="markPrompt" v-if="props.nowShowAreaData.type == 'dfence'">
自定义禁降区绘制后飞行器不能在绘制区域内自动降落
</div>
<div class="markPrompt" v-if="props.nowShowAreaData.type == 'nfz'">
自定义作业区绘制后飞行器只能在该区域内飞行
</div>
</a-col>
<a-col :span="24">
<div class="markTitle"> 更多信息 </div>
</a-col>
<!-- 启用状态 -->
<a-col :span="6">
<div class="markTitle">启用状态</div>
</a-col>
<a-col :span="18">
<div class="markContent">
{{ props.nowShowAreaData.status == 'enable' ? '已启用' : '已禁用' }}
</div>
</a-col>
<!-- 水平距离 -->
<a-col :span="6" v-if="props.nowShowAreaData.type == 'noland'">
<div class="markTitle">水平距离</div>
</a-col>
<a-col :span="18" v-if="props.nowShowAreaData.type == 'noland'">
<div class="markContent"> m</div>
</a-col>
<!-- 水平面积 -->
<a-col :span="6">
<div class="markTitle">水平面积</div>
</a-col>
<a-col :span="18">
<div class="markContent"> </div>
</a-col>
<!-- 水平周长 -->
<a-col :span="6" v-if="props.nowShowAreaData.content.geometry.type == 'Polygon'">
<div class="markTitle">水平周长</div>
</a-col>
<a-col :span="18" v-if="props.nowShowAreaData.content.geometry.type == 'Polygon'">
<div class="markContent"> m</div>
</a-col>
<!-- 半径 -->
<a-col :span="6" v-if="props.nowShowAreaData.content.geometry.type == 'Circle'">
<div class="markTitle">半径</div>
</a-col>
<a-col :span="18" v-if="props.nowShowAreaData.content.geometry.type == 'Circle'">
<div class="markContent">
<a-input
v-model:value="nowAreaData.content.geometry.radius"
style="width: 100%"
size="small"
>
<template #addonAfter> <span style="color: white">m</span> </template>
</a-input>
</div>
</a-col>
<!-- 宽度 -->
<a-col :span="6" v-if="props.nowShowAreaData.type == 'noland'">
<div class="markTitle">宽度</div>
</a-col>
<a-col :span="18" v-if="props.nowShowAreaData.type == 'noland'">
<div class="markContent">
<div
class="button"
:class="{ disabled: nowAreaData.content.properties.width == 10 }"
@click="removeRecordNum"
>
<MinusOutlined style="font-size: 20px; color: #ffffff" />
</div>
<div class="numDiv">
<span v-if="!numInputFlag" class="numSpan" @click="focusInput">
{{ nowAreaData.content.properties.width }}
</span>
<a-input
v-if="numInputFlag"
ref="focusInputRef"
v-model:value="nowAreaData.content.properties.width"
style="width: 50%"
@blur="blurInput"
@keypress.enter="blurInput"
/>
<span style="margin-left: 10px; font-size: 18px; color: #ffffff">m</span>
</div>
<div
class="button"
:class="{ disabled: nowAreaData.content.properties.width == 100 }"
@click="addRecordNum"
>
<PlusOutlined style="font-size: 20px; color: #ffffff" />
</div>
</div>
</a-col>
<!-- 绘制者 -->
<a-col :span="6">
<div class="markTitle">绘制者</div>
</a-col>
<a-col :span="18">
<div class="markContent"> {{ props.nowShowAreaData.created_nickname }}</div>
</a-col>
<a-col :span="24">
<div class="area_buttons">
<div class="cancelDiv" @click="closePathAreaInfo"></div>
<div class="startDiv" :class="{ disabled: props.nowShowAreaData }">确认</div>
</div>
</a-col>
</a-row>
</div>
</template>
<script lang="ts" setup>
import { ref, watch, nextTick } from 'vue';
import {
CloseOutlined,
DeleteOutlined,
CheckOutlined,
AimOutlined,
AlignLeftOutlined,
InfoCircleOutlined,
AntDesignOutlined,
ExpandAltOutlined,
BorderOutlined,
LogoutOutlined,
MinusOutlined,
PlusOutlined,
} from '@ant-design/icons-vue';
import { cloneDeep } from 'lodash-es';
const props = defineProps(['allAreaDataList', 'nowShowAreaData']);
const emits = defineEmits([
'setNowShowAreaData',
'closePathAreaInfo',
'handlerLocation',
'deleteArea',
]);
const nowAreaData: any = ref(props.nowShowAreaData);
// ----------------------------------------------------------------------
const numInputFlag = ref(false);
const focusInputRef = ref();
// input
function focusInput() {
numInputFlag.value = true;
nextTick(() => {
if (focusInputRef.value && focusInputRef.value.focus) {
focusInputRef.value.focus();
}
});
}
// inputorEnter
function blurInput() {
numInputFlag.value = false;
//
if (/^-?\d+(\.\d+)?$/.test(nowAreaData.value.content.properties.width.toString())) {
if (nowAreaData.value.content.properties.width > 100) {
// 100
nowAreaData.value.content.properties.width = 100;
} else if (nowAreaData.value.content.properties.width < 10) {
// 10
nowAreaData.value.content.properties.width = 10;
} else {
//
let newnum = cloneDeep(nowAreaData.value.content.properties.width);
nowAreaData.value.content.properties.width = parseFloat(parseFloat(newnum).toFixed(2));
}
} else {
//
nowAreaData.value.content.properties.width = 10;
}
}
// -
function removeRecordNum() {
let newnum = cloneDeep(nowAreaData.value.content.properties.width);
if (newnum == 10) {
return;
}
newnum -= 5;
nowAreaData.value.content.properties.width = parseFloat(newnum.toFixed(2));
}
// -
function addRecordNum() {
let newnum = cloneDeep(nowAreaData.value.content.properties.width);
if (newnum == 100) {
return;
}
newnum += 5;
nowAreaData.value.content.properties.width = parseFloat(newnum.toFixed(2));
}
//
function closePathAreaInfo() {
emits('closePathAreaInfo');
}
//
function handlerLocation() {
let coordinates = props.nowShowAreaData.content.geometry.coordinates;
if (props.nowShowAreaData.content.geometry.type == 'Circle') {
emits('handlerLocation', {
lng: coordinates[0],
lat: coordinates[1],
});
} else {
emits('handlerLocation', {
lng: coordinates[0][0][0],
lat: coordinates[0][0][1],
});
}
}
//
function deleteArea() {
emits('deleteArea', props.nowShowAreaData);
}
watch(
() => props.nowShowAreaData,
() => {
nowAreaData.value = props.nowShowAreaData;
},
{
deep: true,
immediate: true,
},
);
</script>
<style lang="less" scoped>
.areaInfo {
//
-webkit-user-select: none; /* Safari */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* IE/Edge */
user-select: none;
position: relative;
width: 100%;
height: 100%;
background: #232323;
padding: 15px;
}
.markTitle {
display: flex;
align-items: center;
justify-content: flex-start;
color: #ffffff;
font-size: 14px;
min-height: 45px;
height: auto;
width: 100%;
flex-wrap: wrap;
.markTitleButton_right {
height: 20px;
width: 20px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 12px;
font-size: 18px;
}
.markTitleButton {
height: 20px;
width: 20px;
display: flex;
align-items: center;
justify-content: center;
margin-left: 12px;
font-size: 18px;
}
}
.markContent {
display: flex;
align-items: center;
justify-content: flex-start;
min-height: 45px;
height: auto;
width: 100%;
flex-wrap: wrap;
color: #ffffff;
}
.markButton {
display: flex;
align-items: center;
justify-content: flex-start;
min-height: 45px;
height: auto;
width: 100%;
flex-wrap: wrap;
}
.markPrompt {
display: flex;
align-items: center;
justify-content: flex-start;
min-height: 45px;
height: auto;
width: 100%;
flex-wrap: wrap;
color: #ffffff55;
}
.button {
display: flex;
align-items: center;
justify-content: center;
width: 35px;
height: 35px;
background: #3c3c3c;
border-radius: 2px;
&:hover {
background: #5d5f61;
}
}
.button.disabled {
cursor: not-allowed;
opacity: 0.5;
background-color: #ccc;
}
.numDiv {
width: calc(80% - 70px);
display: flex;
align-items: center;
justify-content: center;
.numSpan {
color: #2d8cf0;
font-size: 26px;
font-weight: bold;
&:hover {
text-decoration: underline;
text-decoration-color: #2d8cf0;
}
}
}
//
.area_buttons {
display: flex;
align-items: center;
justify-content: center;
border-top: 1px solid #ffffff55;
width: 100%;
height: 68px;
gap: 20px;
.cancelDiv {
display: flex;
align-items: center;
justify-content: center;
background: #3c3c3c;
color: #ffffff;
width: 40%;
height: 32px;
border-radius: 5px;
&:hover {
background: #5d5f61;
}
}
.startDiv {
display: flex;
align-items: center;
justify-content: center;
background: #0960bd;
color: #ffffff;
width: 40%;
height: 32px;
border-radius: 5px;
&:hover {
background: #2a7dc9;
}
}
}
</style>

@ -1,5 +1,5 @@
<template>
<div class="imageShow">
<div class="imageInfo">
<!-- 标题 -->
<div class="titleDiv">
<div class="titleName">
@ -52,7 +52,7 @@
</div>
<!-- 关闭按钮 -->
<div class="closeButton">
<CloseOutlined @click="closePathImage" style="font-size: 20px; color: white" />
<CloseOutlined @click="closePathImageInfo" style="font-size: 20px; color: white" />
</div>
<!-- 上一张下一张图片 -->
<div class="leftButton" @click="clickLeftOrRightButton('left')">
@ -122,8 +122,8 @@
position: 'relative',
transform: `scale(${scale}) rotate(${rotationAngle}deg)`,
transition: 'transform 0.2s',
width: `720px`,
height: `${540}px`,
width: `${imageWidth}px`,
height: `${imageHeight}px`,
background: `url(${props.nowShowImageData.original_url ? 'https://m.tuniucdn.com/fb2/t1/G5/M00/44/52/Cii-s1soezyIF2UxABn76u-yKl8AAIwBgB34jAAGfwC3020871' : props.nowShowImageData.original_url}) no-repeat`,
}"
>
@ -401,7 +401,7 @@
<template #title>
<span>100%比例</span>
</template>
<OneToOneOutlined @click="rotateClockwise" />
<OneToOneOutlined @click="setProportion" />
</a-tooltip>
</div>
<!-- 顺时针旋转 -->
@ -445,11 +445,11 @@
<a-tooltip placement="top">
<template #title>
<span>
{{ props.nowShowImageData.addOrRemoveToMap ? '在地图上取消加载' : '在地图上加载' }}
{{ props.nowShowImageData.show_on_map ? '在地图上取消加载' : '在地图上加载' }}
</span>
</template>
<svg
v-if="props.nowShowImageData.addOrRemoveToMap"
v-if="props.nowShowImageData.show_on_map"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 24 24"
@ -462,7 +462,7 @@
></path>
</svg>
<svg
v-if="!props.nowShowImageData.addOrRemoveToMap"
v-if="!props.nowShowImageData.show_on_map"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 24 24"
@ -479,14 +479,17 @@
</div>
<div class="imageChooseList">
<div v-for="li in props.allImageDataList" :key="li.id" @click="setNowShowImageData(li)">
<div
:class="li.id == props.nowShowImageData.id ? 'bottom_div_choose' : 'bottom_div'"
:style="{
width: `75px`,
height: `50px`,
background: `url(${li.preview_url ? 'https://m.tuniucdn.com/fb2/t1/G5/M00/44/52/Cii-s1soezyIF2UxABn76u-yKl8AAIwBgB34jAAGfwC3020871' : li.preview_url}) no-repeat`,
}"
/>
<div :class="li.id == props.nowShowImageData.id ? 'bottom_div_choose' : 'bottom_div'">
<img
:src="
li.preview_url
? 'https://m.tuniucdn.com/fb2/t1/G5/M00/44/52/Cii-s1soezyIF2UxABn76u-yKl8AAIwBgB34jAAGfwC3020871'
: li.preview_url
"
width="75"
height="50"
/>
</div>
</div>
</div>
</div>
@ -542,7 +545,7 @@
</div>
</template>
<script lang="ts" setup>
import { ref, watch, nextTick, onMounted, onBeforeUnmount } from 'vue';
import { ref, watch, onMounted, onBeforeUnmount } from 'vue';
import {
CloseOutlined,
RightOutlined,
@ -571,7 +574,7 @@
const { createMessage, createConfirm } = useMessage();
const props = defineProps(['nowShowImageData', 'allImageDataList']);
const emits = defineEmits(['setNowShowImageData', 'closePathImage', 'handlerLocation']);
const emits = defineEmits(['setNowShowImageData', 'closePathImageInfo', 'handlerLocation']);
// --------------------------------
const editNameFlag = ref(true);
@ -581,11 +584,11 @@
if (props.nowShowImageData.name.split('.').length <= 1) {
editName.value = props.nowShowImageData.name;
}
nextTick(() => {
setTimeout(() => {
if (focusInputRef.value && focusInputRef.value.focus) {
focusInputRef.value.focus(); // focus
}
});
}, 300);
editNameFlag.value = false;
}
//
@ -685,8 +688,8 @@
}
// --------------------------------------------------------------
function closePathImage() {
emits('closePathImage');
function closePathImageInfo() {
emits('closePathImageInfo');
}
// --------------------------------------------------------------
@ -696,26 +699,21 @@
if (list[index].id == props.nowShowImageData.id) {
if (direction == 'left') {
if (index == 0) {
console.log(list[list.length - 1]);
setNowShowImageData(list[list.length - 1]);
} else {
console.log(list[list - 1]);
setNowShowImageData(list[index - 1]);
}
}
if (direction == 'right') {
if (index == list.length - 1) {
console.log(list[0]);
setNowShowImageData(list[0]);
} else {
console.log(list[list + 1]);
setNowShowImageData(list[index + 1]);
}
}
}
}
}
//
const fullscreenFlag = ref(false);
function clickExpandButton() {
@ -731,8 +729,10 @@
}
}
// -----------------------------------
// ----------------------------------------------------------------------
//
const scale = ref(1);
//
function zoomIn() {
if (scale.value < 3) {
@ -747,8 +747,14 @@
scale.value -= 0.1;
}
}
// -----------------------------------
const imageWidth = ref(720);
const imageHeight = ref(540);
// 100%
function setProportion() {
imageWidth.value = 1440;
imageHeight.value = 1080;
}
//
const rotationAngle = ref(0);
//
function rotateClockwise() {
@ -758,12 +764,13 @@
function rotateCounterClockwise() {
rotationAngle.value -= 90; // -90
}
//
function refresh() {
scale.value = 1;
rotationAngle.value = 0;
graffitiFlag.value = false;
imageWidth.value = 720;
imageHeight.value = 540;
//
const dragDocument: any = document.querySelector('.dragModal');
if (dragDocument) {
@ -771,16 +778,14 @@
dragDocument.style.top = 0 + 'px';
}
}
//
function handlerLocation() {
emits('handlerLocation', props.nowShowImageData.photo_position);
}
//
function funAddOrRemoveToMap() {
props.nowShowImageData.addOrRemoveToMap = !props.nowShowImageData.addOrRemoveToMap;
if (props.nowShowImageData.addOrRemoveToMap) {
props.nowShowImageData.show_on_map = !props.nowShowImageData.show_on_map;
if (props.nowShowImageData.show_on_map) {
createMessage.success('在地图上加载成功');
} else {
createMessage.success('在地图上取消加载成功');
@ -1088,7 +1093,6 @@
watch(
() => props.nowShowImageData.id,
() => {
console.log(props.nowShowImageData.graffitiJson);
if (props.nowShowImageData.graffitiJson) {
graffitis.value = JSON.parse(props.nowShowImageData.graffitiJson);
} else {
@ -1110,7 +1114,7 @@
});
</script>
<style lang="less" scoped>
.imageShow {
.imageInfo {
//
-webkit-user-select: none; /* Safari */
-moz-user-select: none; /* Firefox */
@ -1208,7 +1212,7 @@
}
.bottom_div_choose {
outline: 2px solid #1088f2;
outline: 3px solid #1088f2;
border-radius: 5px;
margin-left: 10px;
margin-right: 10px;

@ -1,8 +1,384 @@
<template>
<div class="leftMenu">
<div>
<CloseOutlined style="font-size: 24px; margin: 8px; color: white" @click="closePathModal" />
<div
class="leftMenuTitle"
:style="{
width: leftMenuShow ? '340px' : '64px',
}"
>
<a-tooltip placement="right">
<template #title> {{ props.pathRecord.name }} </template>
<div class="title">{{ props.pathRecord.name }}</div>
</a-tooltip>
</div>
<div class="leftMenuContent">
<div class="leftMenuContent_1">
<div class="leftMenu_closeButton">
<a-tooltip placement="right">
<template #title> 关闭弹窗 </template>
<CloseOutlined
style="font-size: 24px; margin: 8px; color: white"
@click="closePathModal"
/>
</a-tooltip>
</div>
<div class="leftMenu_buttonList">
<div
class="leftMenu_buttonList_mark"
:style="{
background: showMenuInfoName == '地图标注' ? '#2D8CF0' : '#1a375a',
}"
@click="
showMenuInfoName = '地图标注';
updateShowMenuInfoList(showMenuInfoName);
"
>
<a-tooltip placement="right">
<template #title> 地图标注 </template>
<AntDesignOutlined style="font-size: 24px; margin: 8px; color: white" />
</a-tooltip>
</div>
<div
class="leftMenu_buttonList_image"
:style="{
background: showMenuInfoName == '地图照片' ? '#2D8CF0' : '#1a375a',
}"
@click="
showMenuInfoName = '地图照片';
updateShowMenuInfoList(showMenuInfoName);
"
>
<a-tooltip placement="right">
<template #title> 地图照片 </template>
<EnvironmentOutlined style="font-size: 24px; margin: 8px; color: white" />
</a-tooltip>
</div>
<div
class="leftMenu_buttonList_area"
:style="{
background: showMenuInfoName == '地图作业区域' ? '#2D8CF0' : '#1a375a',
}"
@click="
showMenuInfoName = '地图作业区域';
updateShowMenuInfoList(showMenuInfoName);
showMenuInfoList = filterAfterAreaDataList;
"
>
<a-tooltip placement="right">
<template #title> 地图作业区域 </template>
<CodeSandboxOutlined style="font-size: 24px; margin: 8px; color: white" />
</a-tooltip>
</div>
</div>
</div>
<div class="leftMenuContent_2" v-if="leftMenuShow">
<div class="leftMenuContent_title">
{{ showMenuInfoName }}
</div>
<div class="leftMenuContent_list">
<!-- 地图作业区域 -->
<div v-if="showMenuInfoName == '地图作业区域'" style="margin: 10px">
<a-select
v-model:value="areatype"
style="width: 120px; margin-right: 15px"
@change="handleChangeAreaSelect"
>
<a-select-option value="all">全部类型</a-select-option>
<a-select-option value="dfence">全部作业区</a-select-option>
<a-select-option value="nfz">全部限飞区</a-select-option>
<a-select-option value="noland">全部禁降区</a-select-option>
</a-select>
<a-select
v-model:value="areastatus"
style="width: 120px"
@change="handleChangeAreaSelect"
>
<a-select-option value="all">全部状态</a-select-option>
<a-select-option value="enable">已启用</a-select-option>
<a-select-option value="disable">已禁用</a-select-option>
</a-select>
</div>
<!-- 列表 -->
<div
v-for="show in showMenuInfoList"
:key="show.id"
@mouseenter="
show.mouse = true;
show.deleteClickNum = 0;
"
@mouseleave="
show.mouse = false;
show.deleteClickNum = 0;
"
>
<!-- 地图标注 -->
<div
v-if="showMenuInfoName == '地图标注'"
class="showMenuInfo_mark"
:style="{
background:
props.nowShowMarkData && props.nowShowMarkData.id == show.id
? '#274D75'
: show.mouse
? '#393939'
: '',
}"
>
<div @click="setNowShowMarkData(show)">
<AntDesignOutlined v-if="show.resource.type == '0'" />
<ExpandAltOutlined v-if="show.resource.type == '1'" />
<BorderOutlined v-if="show.resource.type == '2'" />
<LogoutOutlined v-if="show.resource.type == '3'" />
</div>
<div
class="eye"
@click="show.status = !show.status"
:style="{ background: show.status ? '#2d8cf0' : '#000000' }"
>
<EyeOutlined v-if="show.status" style="color: #ffffff; font-size: 16px" />
<EyeInvisibleOutlined v-if="!show.status" style="color: #ffffff; font-size: 16px" />
</div>
<div @click="setNowShowMarkData(show)">{{ show.name }}</div>
<div class="buttonRight2" v-if="show.mouse">
<a-tooltip placement="top">
<template #title>
<span>回中</span>
</template>
<AimOutlined @click="handlerLocation(show)" />
</a-tooltip>
</div>
<div
class="buttonRight1"
v-if="show.mouse"
:style="{ background: show.deleteClickNum == 1 ? '#FF0000' : '' }"
>
<a-tooltip placement="top">
<template #title>
<span>删除</span>
</template>
<DeleteOutlined
@click="show.deleteClickNum == 1 ? deleteMark(show) : show.deleteClickNum++"
/>
</a-tooltip>
</div>
</div>
<!-- 地图照片 -->
<div
class="showMenuInfo_image"
v-if="showMenuInfoName == '地图照片'"
:style="{
background:
props.nowShowImageData && props.nowShowImageData.id == show.id
? '#274D75'
: show.mouse
? '#393939'
: '',
}"
>
<FileImageOutlined />
<div
class="eye"
@click="show.is_displayed = !show.is_displayed"
:style="{ background: show.is_displayed ? '#2d8cf0' : '#000000' }"
>
<EyeOutlined v-if="show.is_displayed" style="color: #ffffff; font-size: 16px" />
<EyeInvisibleOutlined
v-if="!show.is_displayed"
style="color: #ffffff; font-size: 16px"
/>
</div>
<a-tooltip placement="top">
<template #title>
<span> {{ show.name }}</span>
</template>
<div
:style="{
width: show.mouse ? '160px' : '210px',
'white-space': 'nowrap',
overflow: 'hidden',
'text-overflow': 'ellipsis',
}"
@click="setNowShowImageData(show)"
>
{{ show.name }}
</div>
</a-tooltip>
<div class="buttonRight2" v-if="show.mouse">
<a-tooltip placement="top">
<template #title>
<span>回中</span>
</template>
<AimOutlined @click="handlerLocation(show)" />
</a-tooltip>
</div>
<div class="buttonRight1" v-if="show.mouse">
<a-tooltip placement="top">
<template #title>
<span>
{{ show.show_on_map ? '在地图上取消加载' : '在地图上加载' }}
</span>
</template>
<div style="display: flex; align-items: center">
<svg
v-if="show.show_on_map"
@click="funAddOrRemoveToMap(show)"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 24 24"
width="18"
height="18"
>
<path
d="M19 5v11.17l2 2V5c0-1.1-.9-2-2-2H5.83l2 2H19zM2.81 2.81L1.39 4.22L3 5.83V19c0 1.1.9 2 2 2h13.17l1.61 1.61l1.41-1.41L2.81 2.81zM5 19V7.83l7.07 7.07l-.82 1.1L9 13l-3 4h8.17l2 2H5z"
fill="#ffffff"
></path>
</svg>
<svg
v-if="!show.show_on_map"
@click="funAddOrRemoveToMap(show)"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 24 24"
width="18"
height="18"
>
<path
d="M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-4.86 8.86l-3 3.87L9 13.14L6 17h12l-3.86-5.14z"
fill="#ffffff"
></path>
</svg>
</div>
</a-tooltip>
</div>
</div>
<!-- 地图作业区域 -->
<div
v-if="showMenuInfoName == '地图作业区域'"
class="showMenuInfo_area"
:style="{
outline:
props.nowShowAreaData && props.nowShowAreaData.id == show.id
? '2px solid #2D8CF0'
: '',
background:
props.nowShowAreaData && show.status == 'enable' ? '#3c3c3c' : '#3c3c3c55',
}"
>
<div
class="name"
@click="setNowShowAreaData(show)"
:style="{
color: show.status == 'enable' ? '#ffffff' : '#ffffff55',
}"
>
{{ show.name }}
</div>
<div
class="type"
@click="setNowShowAreaData(show)"
:style="{
color: show.status == 'enable' ? '#ffffff' : '#ffffff55',
}"
>
<!-- 自定义限飞区 -->
<div
v-if="show.type == 'noland'"
:style="{
width: '13px',
height: '13px',
outline: `2px solid ${show.content.properties.color}`,
'margin-right': '6px',
}"
/>
<!-- 自定义作业区 -->
<div
v-if="show.type == 'dfence'"
:style="{
width: '13px',
height: '13px',
outline: `2px solid ${show.content.properties.color}`,
'margin-right': '6px',
'border-radius': show.content.geometry.type == 'Circle' ? '6.5px' : '0px',
}"
/>
<!-- 自定义禁降区 -->
<div
v-if="show.type == 'nfz'"
:style="{
width: '13px',
height: '13px',
outline: `2px solid ${show.content.properties.color}`,
background: `${show.content.properties.color}55`,
'margin-right': '6px',
'border-radius': show.content.geometry.type == 'Circle' ? '6.5px' : '0px',
}"
/>
<span>{{ getType(show.type) }}</span>
</div>
<div class="buttonlist">
<div class="button" v-if="show.status == 'disable'">
<a-popconfirm
title="将会影响到项目内设备的作业范围,是否启用该区域?"
ok-text="启用"
cancel-text="取消"
placement="right"
@confirm="enableThisArea(show)"
>
<a-tooltip placement="top">
<template #title>
<span>可点击启用该区域</span>
</template>
<CheckCircleOutlined />
</a-tooltip>
</a-popconfirm>
</div>
<div class="button" v-if="show.status == 'enable'">
<a-popconfirm
title="将会影响到项目内设备的作业范围,是否禁用该区域?"
ok-text="禁用"
cancel-text="取消"
placement="right"
@confirm="disableThisArea(show)"
>
<a-tooltip placement="top">
<template #title>
<span>可点击禁用该区域</span>
</template>
<StopOutlined />
</a-tooltip>
</a-popconfirm>
</div>
<div class="button">
<a-tooltip placement="top">
<template #title>
<span>回中</span>
</template>
<AimOutlined @click="handlerLocation(show)" />
</a-tooltip>
</div>
<div class="button">
<a-popconfirm
title="将会影响到项目内设备的作业范围,是否删除该区域?"
ok-text="删除"
cancel-text="取消"
placement="right"
@confirm="deleteArea(show)"
>
<a-tooltip placement="top">
<template #title>
<span>删除</span>
</template>
<DeleteOutlined />
</a-tooltip>
</a-popconfirm>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="suojinButton" @click="changeLeftMenuShow">
<DoubleLeftOutlined v-if="leftMenuShow" style="font-size: 16px" />
<DoubleRightOutlined v-if="!leftMenuShow" style="font-size: 16px" />
@ -11,18 +387,211 @@
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { CloseOutlined, DoubleLeftOutlined, DoubleRightOutlined } from '@ant-design/icons-vue';
const props = defineProps(['leftMenuShow', 'allImageDataList', 'nowShowImageData']);
const emits = defineEmits(['changeLeftMenuShow', 'closePathModal']);
import {
CloseOutlined,
AntDesignOutlined,
DoubleLeftOutlined,
DoubleRightOutlined,
EnvironmentOutlined,
CodeSandboxOutlined,
ExpandAltOutlined,
BorderOutlined,
LogoutOutlined,
EyeOutlined,
EyeInvisibleOutlined,
AimOutlined,
DeleteOutlined,
FileImageOutlined,
CheckCircleOutlined,
StopOutlined,
} from '@ant-design/icons-vue';
import { cloneDeep } from 'lodash-es';
import { useMessage } from '@/hooks/web/useMessage';
const { createMessage, createConfirm } = useMessage();
const props = defineProps([
'pathRecord',
'leftMenuShow',
'allMarkDataList',
'nowShowMarkData',
'allImageDataList',
'nowShowImageData',
'allAreaDataList',
'nowShowAreaData',
]);
const emits = defineEmits([
'changeLeftMenuShow',
'handlerLocation',
'closePathModal',
'changeMarkInfoShow',
'setNowShowMarkData',
'setNowShowImageData',
'setNowShowAreaData',
'deleteMark',
'deleteArea',
]);
const showMenuInfoList = ref(props.allMarkDataList);
const showMenuInfoName = ref('地图标注');
function updateShowMenuInfoList(type) {
console.log(type);
if (type == '地图标注') {
showMenuInfoList.value = props.allMarkDataList;
}
if (type == '地图照片') {
showMenuInfoList.value = props.allImageDataList;
}
if (type == '地图作业区域') {
handleChangeAreaSelect();
}
}
//
// -
function changeLeftMenuShow() {
emits('changeLeftMenuShow');
}
//
// -
function closePathModal() {
emits('closePathModal');
}
// -
function funAddOrRemoveToMap(show) {
show.show_on_map = !show.show_on_map;
if (show.show_on_map) {
createMessage.success('在地图上加载成功');
} else {
createMessage.success('在地图上取消加载成功');
}
}
// -
function deleteMark(show) {
emits('deleteMark', show);
}
// -------------------------------------------------
// -
const areatype = ref('all');
const areastatus = ref('all');
// -
function getType(type) {
let name = '';
switch (type) {
case 'nfz':
name = '自定义限飞区';
break;
case 'dfence':
name = '自定义作业区';
break;
case 'noland':
name = '自定义禁降区';
break;
}
return name;
}
// -
const filterAfterAreaDataList = ref(props.allAreaDataList);
function handleChangeAreaSelect() {
let filterAreaData = props.allAreaDataList;
if (areatype.value !== 'all') {
filterAreaData = filterAreaData.filter((item) => item.type == areatype.value);
}
if (areastatus.value !== 'all') {
filterAreaData = filterAreaData.filter((item) => item.status == areastatus.value);
}
filterAfterAreaDataList.value = filterAreaData;
showMenuInfoList.value = filterAfterAreaDataList.value;
}
// -
function enableThisArea(value) {
setNowShowAreaData({
...value,
status: 'enable',
});
}
// -
function disableThisArea(value) {
setNowShowAreaData({
...value,
status: 'disable',
});
}
// -
function deleteArea(show) {
emits('deleteArea', show);
}
//
function setNowShowMarkData(value) {
emits('setNowShowMarkData', value);
}
//
function setNowShowImageData(value) {
emits('setNowShowImageData', value);
}
//
function setNowShowAreaData(value) {
emits('setNowShowAreaData', value);
}
// ------------------------------------------------------------------
//
function handlerLocation(position) {
if (showMenuInfoName.value == '地图标注') {
let coordinates = position.resource.content.geometry.coordinates;
switch (position.resource.type) {
case 0:
emits('handlerLocation', {
lng: coordinates[0],
lat: coordinates[1],
});
break;
case 1:
emits('handlerLocation', {
lng: coordinates[0][0],
lat: coordinates[0][1],
});
break;
case 2:
emits('handlerLocation', {
lng: coordinates[0][0][0],
lat: coordinates[0][0][1],
});
break;
case 3:
emits('handlerLocation', {
lng: coordinates[0],
lat: coordinates[1],
});
break;
}
}
if (showMenuInfoName.value == '地图照片') {
emits('handlerLocation', {
lng: position.photo_position.lng,
lat: position.photo_position.lat,
});
}
if (showMenuInfoName.value == '地图作业区域') {
let coordinates = position.content.geometry.coordinates;
if (position.content.geometry.type == 'Circle') {
emits('handlerLocation', {
lng: coordinates[0],
lat: coordinates[1],
});
} else {
emits('handlerLocation', {
lng: coordinates[0][0][0],
lat: coordinates[0][0][1],
});
}
}
}
defineExpose({
updateShowMenuInfoList,
});
</script>
<style lang="less" scoped>
.leftMenu {
@ -30,6 +599,229 @@
width: 100%;
height: 100%;
background: #232323;
.leftMenuTitle {
position: relative;
width: 100%;
height: 50px;
padding: 10px;
border-bottom: 1px solid #ffffff55;
.title {
display: flex;
align-items: center;
justify-content: flex-start;
font-size: 20px;
color: #ffffff;
width: 100%;
/* 关键属性 */
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
.leftMenuContent {
position: relative;
display: flex;
width: 100%;
height: calc(100%-50px);
// height: 800px;
.leftMenuContent_1 {
position: relative;
width: 64px;
height: 100%;
border-right: 1px solid #ffffff55;
// padding-top: 10px;
// padding-bottom: 10px;
.leftMenu_closeButton {
position: relative;
padding-top: 7px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 10px;
}
.leftMenu_buttonList {
position: relative;
width: 50px;
height: 100%;
border-radius: 10px;
background: #1a375a;
margin-top: 15px;
margin-left: 7px;
margin-right: 7px;
padding-top: 5px;
padding-bottom: 5px;
gap: 10px;
.leftMenu_buttonList_mark {
position: relative;
border-radius: 5px;
height: 40px;
width: 40px;
margin: 5px;
display: flex;
align-items: center;
justify-content: center;
}
.leftMenu_buttonList_image {
position: relative;
border-radius: 5px;
height: 40px;
width: 40px;
margin: 5px;
display: flex;
align-items: center;
justify-content: center;
}
.leftMenu_buttonList_area {
position: relative;
border-radius: 5px;
height: 40px;
width: 40px;
margin: 5px;
display: flex;
align-items: center;
justify-content: center;
}
}
}
.leftMenuContent_2 {
position: relative;
width: 275px;
height: 100%;
.leftMenuContent_title {
margin-top: 10px;
margin-left: 10px;
color: #ffffff;
font-size: 16px;
}
.leftMenuContent_list {
overflow-y: auto;
max-height: 800px;
//
.showMenuInfo_mark {
position: relative;
display: flex;
align-items: center;
justify-content: flex-start;
color: #ffffff;
height: 30px;
padding-left: 15px;
gap: 10px;
.eye {
display: flex;
align-items: center;
justify-content: center;
width: 20px;
height: 20px;
}
.buttonRight2 {
position: absolute;
right: 30px;
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
}
.buttonRight1 {
position: absolute;
right: 5px;
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
}
}
//
.showMenuInfo_image {
display: flex;
align-items: center;
justify-content: flex-start;
color: #ffffff;
height: 30px;
padding-left: 15px;
gap: 10px;
.eye {
display: flex;
align-items: center;
justify-content: center;
width: 20px;
height: 20px;
}
.buttonRight2 {
position: absolute;
right: 35px;
}
.buttonRight1 {
position: absolute;
right: 10px;
}
}
//
.showMenuInfo_area {
position: relative;
display: flex;
align-items: center;
justify-content: flex-start;
height: 70px;
margin: 10px 15px;
.name {
position: absolute;
top: 6px;
left: 6px;
color: #ffffff;
font-size: 15px;
width: 240px;
height: 29px;
}
.type {
position: absolute;
display: inline-flex;
align-items: center;
justify-content: flex-start;
bottom: 6px;
left: 8px;
color: #ffffff;
font-size: 15px;
width: 165px;
}
.buttonlist {
position: absolute;
bottom: 6px;
right: 6px;
width: 75px;
height: 25px;
display: flex;
gap: 1px;
.button {
display: flex;
align-items: center;
justify-content: center;
color: #ffffff;
font-size: 16px;
width: 25px;
height: 25px;
}
}
}
}
}
}
}
.suojinButton {

@ -5,21 +5,44 @@
import { ref, onMounted, defineEmits } from 'vue';
import * as mars3d from 'mars3d';
import * as Cesium from 'mars3d-cesium';
const props = defineProps(['allImageDataList', 'nowShowImageData']);
const emits = defineEmits(['mapOnLoad', 'setNowShowImageData', 'closePathImage']);
import { circle, rect, triangle } from './svg';
const props = defineProps([
'allMarkDataList',
'nowShowMarkData',
'allImageDataList',
'nowShowImageData',
'allAreaDataList',
'nowShowAreaData',
]);
const emits = defineEmits([
'setNowShowMarkData',
'setNowShowImageData',
'setNowShowAreaData',
'closePathImageInfo',
]);
const vChartRef: any = ref<HTMLElement>();
let map: mars3d.Map; //
let graphicLayers = new mars3d.layer.GraphicLayer();
//
let bottomPointGraphicData: any = [];
//
let flightointGraphicData: any = [];
// 线
let bottomImagePolylineGraphicData: any = [];
//
let imageGraphicData: any = [];
//
// -
let mark_PointGraphicData: any = [];
// -线
let mark_LineStringGraphicData: any = [];
// -
let mark_PolygonGraphicData: any = [];
// -
let mark_CircleGraphicData: any = [];
//
// -
let image_bottomPointGraphicData: any = [];
// -
let image_flightointGraphicData: any = [];
// -线
let image_bottomImagePolylineGraphicData: any = [];
// -
let image_imageGraphicData: any = [];
onMounted(() => {
initMap();
@ -250,36 +273,236 @@
],
layers: [],
});
addImage();
handlerLocation([118.29853, 35.134608]);
// showAllImageDataList();
showAllMarkDataList();
handlerLocation([113.93791036656113, 22.580846919934572]);
};
//
// const nowShowImageData = ref();
const addImage = async () => {
// --------------------------------------------------------------------
// --
const showAllMarkDataList = async () => {
//
bottomPointGraphicData?.forEach((graphicLayer) => {
mark_PointGraphicData?.forEach((graphicLayer) => {
graphicLayers.removeGraphic(graphicLayer);
});
flightointGraphicData?.forEach((graphicLayer) => {
mark_LineStringGraphicData?.forEach((graphicLayer) => {
graphicLayers.removeGraphic(graphicLayer);
});
bottomImagePolylineGraphicData?.forEach((graphicLayer) => {
mark_PolygonGraphicData?.forEach((graphicLayer) => {
graphicLayers.removeGraphic(graphicLayer);
});
imageGraphicData?.forEach((graphicLayer) => {
mark_CircleGraphicData?.forEach((graphicLayer) => {
graphicLayers.removeGraphic(graphicLayer);
});
//
map.addLayer(graphicLayers);
//
bottomPointGraphicData = [];
flightointGraphicData = [];
bottomImagePolylineGraphicData = [];
imageGraphicData = [];
mark_PointGraphicData = [];
mark_LineStringGraphicData = [];
mark_PolygonGraphicData = [];
mark_CircleGraphicData = [];
// -
props.allMarkDataList.forEach((item, index) => {
let content = item.resource.content;
// -线
if (content.geometry.type == 'LineString') {
let lineGraphic = new mars3d.graphic.PolylineEntity({
id: item.id,
positions: content.geometry.coordinates,
style: {
color: Cesium.Color.fromCssColorString(content.properties.color),
width: content.properties.line_width,
outlineColor: '#ffffff',
outlineWidth: 2,
outline: false,
label: {
text: `${item.name}`,
font_size: content.properties.font_size,
color: '#000000',
outline: true,
outlineColor: '#ffffff',
outlineWidth: 6,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
horizontalOrigin: Cesium.HorizontalOrigin.LEFT,
pixelOffset: [25, -5],
},
},
//
defaultColor: Cesium.Color.fromCssColorString(content.properties.color),
defaultWidth: content.properties.line_width,
});
if (content.properties.line_start_cap != 0) {
//
const positions = lineGraphic.options.positions;
if (positions.length >= 2) {
const start = positions[0];
const end = positions[positions.length - 1];
const image = new Image();
image.crossOrigin = 'Anonymous';
// SVGData URL
if (content.properties.line_start_cap == 1) {
image.src = svgToDataURL(triangle.replace('#000000', content.properties.color));
} else if (content.properties.line_start_cap == 2) {
image.src = svgToDataURL(rect.replace('#000000', content.properties.color));
} else if (content.properties.line_start_cap == 3) {
image.src = svgToDataURL(circle.replace('#000000', content.properties.color));
}
image.onload = () => {
// Canvas
const canvas = document.createElement('canvas');
canvas.width = content.properties.line_width * 5;
canvas.height = content.properties.line_width * 5;
// Canvas
const ctx = canvas.getContext('2d');
// Canvas
ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
// CanvasURL
const dataURL_svg = canvas.toDataURL('image/png');
const startIcon = new mars3d.graphic.BillboardEntity({
position: start,
style: {
image: dataURL_svg,
scale: 0.5,
rotation: 0,
},
});
graphicLayers.addGraphic(startIcon);
};
}
}
// mouseover
lineGraphic.on(mars3d.EventType.mouseOver, function () {
if (!props.nowShowMarkData || props.nowShowMarkData.id !== item.id) {
lineGraphic.setStyle({
color: Cesium.Color.fromCssColorString(content.properties.color + 'cc'),
width: content.properties.line_width,
outlineColor: '#ffffff',
outlineWidth: 2,
outline: true,
label: {
color: content.properties.color,
},
});
}
});
// mouseout
lineGraphic.on(mars3d.EventType.mouseOut, function () {
if (!props.nowShowMarkData || props.nowShowMarkData.id !== item.id) {
lineGraphic.setStyle({
color: Cesium.Color.fromCssColorString(content.properties.color),
width: content.properties.line_width,
outlineWidth: 0,
outline: false,
label: {
color: '#000000',
},
});
}
});
//
lineGraphic.on(mars3d.EventType.click, function () {
//
markRestoreDefault();
lineGraphic.show = false;
let distanceMeasure = new mars3d.graphic.DistanceMeasure({
id: item.id,
positions: content.geometry.coordinates,
style: {
color: '#ff0000',
width: 3,
clampToGround: true,
// outline: true,
// outlineColor: '',
label: {
font_size: 18,
color: '#ffffff',
outline: true,
outlineColor: '#000000',
},
},
});
graphicLayers.addGraphic(distanceMeasure);
emits('setNowShowMarkData', item);
});
// 线
graphicLayers.addGraphic(lineGraphic);
//
mark_LineStringGraphicData.push(lineGraphic);
}
});
};
// -
function markRestoreDefault() {
// 线-
for (let i = 0; i < mark_LineStringGraphicData.length; i++) {
let lineGraphic = mark_LineStringGraphicData[i];
let defaultColor = lineGraphic.options.defaultColor;
let defaultWidth = lineGraphic.options.defaultWidth;
lineGraphic.setStyle({
color: defaultColor,
width: defaultWidth,
outline: false,
label: {
color: '#000000',
},
});
}
}
// -SVG
function svgToDataURL(svgString) {
return 'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(svgString)));
}
//
props.allImageDataList.forEach((item) => {
//
function createTrianglePoints(center, size = 10) {
const heading = 0; //
const h = Math.PI / 2 - heading;
return [
Cesium.Cartesian3.add(center, new Cesium.Cartesian3(0, size, 0), new Cesium.Cartesian3()),
Cesium.Cartesian3.add(
center,
new Cesium.Cartesian3(-size * 0.4, -size * 0.7, 0),
new Cesium.Cartesian3(),
),
Cesium.Cartesian3.add(
center,
new Cesium.Cartesian3(size * 0.4, -size * 0.7, 0),
new Cesium.Cartesian3(),
),
];
}
// --------------------------------------------------------------------
// --
const showAllImageDataList = async () => {
//
image_bottomPointGraphicData?.forEach((graphicLayer) => {
graphicLayers.removeGraphic(graphicLayer);
});
image_flightointGraphicData?.forEach((graphicLayer) => {
graphicLayers.removeGraphic(graphicLayer);
});
image_bottomImagePolylineGraphicData?.forEach((graphicLayer) => {
graphicLayers.removeGraphic(graphicLayer);
});
image_imageGraphicData?.forEach((graphicLayer) => {
graphicLayers.removeGraphic(graphicLayer);
});
//
map.addLayer(graphicLayers);
//
image_bottomPointGraphicData = [];
image_flightointGraphicData = [];
image_bottomImagePolylineGraphicData = [];
image_imageGraphicData = [];
// -
let rotation = 0;
props.allImageDataList.forEach((item, index) => {
if (
item.photo_position &&
item.photo_position.lng &&
@ -337,6 +560,14 @@
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
},
});
if (index + 1 < props.allImageDataList.length) {
const afterItem = props.allImageDataList[index + 1];
let lng = afterItem.photo_position.lng - item.photo_position.lng;
let lat = afterItem.photo_position.lat - item.photo_position.lat;
let angleARad = Math.atan(lng / lat);
let angleA = (angleARad * 180) / Math.PI;
rotation = angleA;
}
//
let flightointGraphic = new mars3d.graphic.BillboardEntity({
id: item.id + '_flight',
@ -346,6 +577,7 @@
clampToGround: false,
scale: 1,
verticalOrigin: Cesium.VerticalOrigin.CENTER,
rotation: rotation,
},
show: false,
});
@ -375,6 +607,17 @@
clampToGround: false,
scale: 1,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
label: {
text: `${item.name}`,
font_size: 14,
color: '#2d8cf0',
outline: true,
outlineColor: '#ffffff',
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
horizontalOrigin: Cesium.HorizontalOrigin.LEFT,
pixelOffset: [25, -5],
show: false,
},
},
//
defaultImage: dataURL1,
@ -388,6 +631,9 @@
imageGraphic.setStyle({
image: dataURL2,
scale: 1.1,
label: {
show: true,
},
});
}
});
@ -398,6 +644,9 @@
imageGraphic.setStyle({
image: dataURL1,
scale: 1,
label: {
show: false,
},
});
}
});
@ -406,13 +655,13 @@
//
if (props.nowShowImageData && props.nowShowImageData.id == item.id) {
//
restoreDefault();
imageRestoreDefault();
emits('setNowShowImageData', {});
emits('closePathImage');
emits('closePathImageInfo');
} else if (!props.nowShowImageData || props.nowShowImageData.id !== item.id) {
//
//
restoreDefault();
imageRestoreDefault();
//
// PolylineEntity
bottomImagePolylineGraphic.positions = [
@ -428,10 +677,11 @@
//
imageGraphic.setStyle({
image: dataURL2,
label: {
show: true,
},
});
emits('setNowShowImageData', item);
// //
// handlerLocation([item.photo_position.lng, item.photo_position.lat, point.height]);
}
});
//
@ -443,26 +693,26 @@
//
graphicLayers.addGraphic(imageGraphic);
//
bottomPointGraphicData.push(bottomPointGraphic);
flightointGraphicData.push(flightointGraphic);
bottomImagePolylineGraphicData.push(bottomImagePolylineGraphic);
imageGraphicData.push(imageGraphic);
image_bottomPointGraphicData.push(bottomPointGraphic);
image_flightointGraphicData.push(flightointGraphic);
image_bottomImagePolylineGraphicData.push(bottomImagePolylineGraphic);
image_imageGraphicData.push(imageGraphic);
});
};
}
});
};
//
function restoreDefault() {
// -
function imageRestoreDefault() {
//
for (let i = 0; i < flightointGraphicData.length; i++) {
let flightointGraphic = flightointGraphicData[i];
for (let i = 0; i < image_flightointGraphicData.length; i++) {
let flightointGraphic = image_flightointGraphicData[i];
flightointGraphic.show = false;
}
// 线
for (let i = 0; i < bottomImagePolylineGraphicData.length; i++) {
let bottomImagePolylineGraphic = bottomImagePolylineGraphicData[i];
for (let i = 0; i < image_bottomImagePolylineGraphicData.length; i++) {
let bottomImagePolylineGraphic = image_bottomImagePolylineGraphicData[i];
let defaultPosition = bottomImagePolylineGraphic.options.defaultPosition;
let surfaceHeight = bottomImagePolylineGraphic.options.surfaceHeight;
bottomImagePolylineGraphic.setStyle({
@ -474,32 +724,37 @@
];
}
//
for (let i = 0; i < imageGraphicData.length; i++) {
let imageGraphic = imageGraphicData[i];
for (let i = 0; i < image_imageGraphicData.length; i++) {
let imageGraphic = image_imageGraphicData[i];
let defaultImage = imageGraphic.options.defaultImage;
imageGraphic.setStyle({
image: defaultImage,
scale: 1,
label: {
show: false,
},
});
}
}
//
// -
function setNowShowImageByRight() {
setTimeout(() => {
//
restoreDefault();
imageRestoreDefault();
//
for (let i = 0; i < flightointGraphicData.length; i++) {
if (flightointGraphicData[i].options.id.includes(props.nowShowImageData.id)) {
let flightointGraphic = flightointGraphicData[i];
for (let i = 0; i < image_flightointGraphicData.length; i++) {
if (image_flightointGraphicData[i].options.id.includes(props.nowShowImageData.id)) {
let flightointGraphic = image_flightointGraphicData[i];
flightointGraphic.show = true;
}
}
// 线
for (let i = 0; i < bottomImagePolylineGraphicData.length; i++) {
if (bottomImagePolylineGraphicData[i].options.id.includes(props.nowShowImageData.id)) {
let bottomImagePolylineGraphic = bottomImagePolylineGraphicData[i];
for (let i = 0; i < image_bottomImagePolylineGraphicData.length; i++) {
if (
image_bottomImagePolylineGraphicData[i].options.id.includes(props.nowShowImageData.id)
) {
let bottomImagePolylineGraphic = image_bottomImagePolylineGraphicData[i];
let defaultPosition = bottomImagePolylineGraphic.options.defaultPosition;
let surfaceHeight = bottomImagePolylineGraphic.options.surfaceHeight;
bottomImagePolylineGraphic.setStyle({
@ -516,18 +771,23 @@
}
}
//
for (let i = 0; i < imageGraphicData.length; i++) {
if (imageGraphicData[i].options.id.includes(props.nowShowImageData.id)) {
let imageGraphic = imageGraphicData[i];
for (let i = 0; i < image_imageGraphicData.length; i++) {
if (image_imageGraphicData[i].options.id.includes(props.nowShowImageData.id)) {
let imageGraphic = image_imageGraphicData[i];
let chooseImage = imageGraphic.options.chooseImage;
imageGraphic.setStyle({
image: chooseImage,
label: {
show: true,
},
});
}
}
}, 500);
}
//
//
const handlerLocation = (lngLat) => {
const position = Cesium.Cartesian3.fromDegrees(lngLat[0], lngLat[1]);

@ -0,0 +1,650 @@
<template>
<div class="markInfo">
<!-- 关闭按钮 -->
<div class="closeButton">
<CloseOutlined @click="closePathMarkInfo" style="font-size: 20px; color: white" />
</div>
<div class="markInfo_biaozhu_1">
<a-row>
<a-col :span="24">
<div class="markTitle">标注信息</div>
</a-col>
<!-- 标题名线 -->
<a-col :span="24">
<div class="markTitle">
<div class="markTitleButton_right">
<AntDesignOutlined
v-if="nowMarkData.resource.type == '0'"
:style="{ color: nowMarkData.resource.content.properties.color }"
/>
<ExpandAltOutlined
v-if="nowMarkData.resource.type == '1'"
:style="{ color: nowMarkData.resource.content.properties.color }"
/>
<BorderOutlined
v-if="nowMarkData.resource.type == '2'"
:style="{ color: nowMarkData.resource.content.properties.color }"
/>
<LogoutOutlined
v-if="nowMarkData.resource.type == '3'"
:style="{ color: nowMarkData.resource.content.properties.color }"
/>
</div>
<a-input v-model:value="nowMarkData.name" style="width: 60%" size="small"></a-input>
<div class="markTitleButton" @click="handlerLocation">
<AimOutlined />
</div>
<div class="markTitleButton" @click="deleteMark">
<DeleteOutlined />
</div>
</div>
</a-col>
<!-- 颜色线 -->
<a-col :span="6">
<div class="markTitle">颜色</div>
</a-col>
<a-col :span="18">
<div class="markContent">
<div
class="popoverClass"
v-for="color in ['#2D8CF0', '#19BE6B', '#FF9900', '#E23C39', '#B620E0']"
:key="color"
:style="{ background: color }"
@click="nowMarkData.resource.content.properties.color = color"
>
<CheckOutlined
v-if="nowMarkData?.resource?.content?.properties?.color == color"
style="color: white"
/>
</div>
</div>
</a-col>
<!-- 形态线 -->
<a-col :span="6" v-if="nowMarkData.resource.type == '1'">
<div class="markTitle">形态</div>
</a-col>
<a-col :span="18" v-if="nowMarkData.resource.type == '1'">
<div class="markContent" style="gap: 5%">
<a-tooltip placement="top">
<template #title> 线宽度 </template>
<a-input
v-model:value="nowMarkData.resource.content.properties.line_width"
style="width: 30%"
>
<template #prefix><AlignLeftOutlined /></template>
</a-input>
</a-tooltip>
<a-tooltip placement="top">
<template #title> 线头部样式 </template>
<a-select
v-model:value="nowMarkData.resource.content.properties.line_start_cap"
style="width: 30%"
option-label-prop="children"
>
<a-select-option :value="0">
<div class="svg-container" v-html="line_start_cap_0"></div>
</a-select-option>
<a-select-option :value="1">
<div class="svg-container" v-html="line_start_cap_1"></div>
</a-select-option>
<a-select-option :value="2">
<div class="svg-container" v-html="line_start_cap_2"></div>
</a-select-option>
<a-select-option :value="3">
<div class="svg-container" v-html="line_start_cap_3"></div>
</a-select-option>
</a-select>
</a-tooltip>
<a-tooltip placement="top">
<template #title> 线尾部样式 </template>
<a-select
v-model:value="nowMarkData.resource.content.properties.line_end_cap"
style="width: 30%"
option-label-prop="children"
>
<a-select-option :value="0">
<div class="svg-container" v-html="line_end_cap_0"></div>
</a-select-option>
<a-select-option :value="1">
<div class="svg-container" v-html="line_end_cap_1"></div>
</a-select-option>
<a-select-option :value="2">
<div class="svg-container" v-html="line_end_cap_2"></div>
</a-select-option>
<a-select-option :value="3">
<div class="svg-container" v-html="line_end_cap_3"></div>
</a-select-option>
</a-select>
</a-tooltip>
</div>
</a-col>
<!-- 图标 -->
<a-col :span="6" v-if="nowMarkData.resource.type == '0'">
<div class="markTitle">图标</div>
</a-col>
<a-col :span="18" v-if="nowMarkData.resource.type == '0'">
<div class="markContent"></div>
</a-col>
<!-- 字体线 -->
<a-col :span="6">
<div class="markTitle">字体</div>
</a-col>
<a-col :span="18">
<div class="markContent">
<a-radio-group
v-model:value="nowMarkData.resource.content.properties.font_size"
button-style="solid"
size="small"
>
<a-radio-button :value="16"></a-radio-button>
<a-radio-button :value="24"></a-radio-button>
<a-radio-button :value="32"></a-radio-button>
</a-radio-group>
</div>
</a-col>
</a-row>
</div>
<div style="border-bottom: 1px solid #ffffff55; margin-left: 15px; margin-right: 15px"></div>
<div class="markInfo_biaozhu_2">
<a-row>
<a-col :span="24">
<div class="markTitle">
测量数据
<a-tooltip placement="top">
<template #title> 只能测量出当前视窗范围内的数据 </template>
<InfoCircleOutlined style="margin-left: 10px" />
</a-tooltip>
</div>
</a-col>
<!-- 经纬模式 -->
<a-col :span="6" v-if="[0, 3].includes(nowMarkData.resource.type)">
<div class="markTitle">经纬模式</div>
</a-col>
<a-col :span="18" v-if="[0, 3].includes(nowMarkData.resource.type)">
<div class="markContent">
<a-radio-group v-model:value="modalType">
<a-radio :value="0"><span style="color: white">十进制</span></a-radio>
<a-radio :value="1"><span style="color: white">度分秒</span></a-radio>
</a-radio-group>
</div>
</a-col>
<!-- 经度 -->
<a-col :span="6" v-if="[0].includes(nowMarkData.resource.type)">
<div class="markTitle">经度</div>
</a-col>
<a-col :span="18" v-if="[0].includes(nowMarkData.resource.type)">
<div class="markContent">
<!-- 十进制 -->
<a-input
v-if="modalType == 0"
v-model:value="nowMarkData.resource.content.geometry.coordinates[0]"
>
<template #addonAfter>
<span style="color: white">°</span>
</template>
</a-input>
<!-- 度分秒 -->
<a-input
v-if="modalType == 1"
v-model:value="decimalToDMS_0.degrees"
style="max-width: 32px"
@change="
decimalToDMS_0.degrees = parseFloat(
decimalToDMS_0.degrees.toString().replace(/[^-0-9]/g, ''),
)
"
/>
<span v-if="modalType == 1" style="margin: 2px; color: white">°</span>
<a-input
v-if="modalType == 1"
v-model:value="decimalToDMS_0.minutes"
style="max-width: 30px"
@change="
decimalToDMS_0.minutes = parseFloat(
decimalToDMS_0.minutes.toString().replace(/[^-0-9]/g, ''),
)
"
/>
<span v-if="modalType == 1" style="margin: 2px; color: white"></span>
<a-input
v-if="modalType == 1"
v-model:value="decimalToDMS_0.seconds"
style="width: 120px"
@change="
decimalToDMS_0.seconds = parseFloat(
decimalToDMS_0.seconds.toString().replace(/[^-0-9]/g, ''),
)
"
/>
<span v-if="modalType == 1" style="margin: 2px; color: white"></span>
</div>
</a-col>
<!-- 纬度 -->
<a-col :span="6" v-if="[0].includes(nowMarkData.resource.type)">
<div class="markTitle">纬度</div>
</a-col>
<a-col :span="18" v-if="[0].includes(nowMarkData.resource.type)">
<div class="markContent">
<!-- 十进制 -->
<a-input
v-if="modalType == 0"
v-model:value="nowMarkData.resource.content.geometry.coordinates[1]"
>
<template #addonAfter>
<span style="color: white">°</span>
</template>
</a-input>
<!-- 度分秒 -->
<a-input
v-if="modalType == 1"
v-model:value="decimalToDMS_1.degrees"
style="max-width: 32px"
@change="
decimalToDMS_1.degrees = parseFloat(
decimalToDMS_1.degrees.toString().replace(/[^-0-9]/g, ''),
)
"
/>
<span v-if="modalType == 1" style="margin: 2px; color: white">°</span>
<a-input
v-if="modalType == 1"
v-model:value="decimalToDMS_1.minutes"
style="max-width: 30px"
@change="
decimalToDMS_1.minutes = parseFloat(
decimalToDMS_1.minutes.toString().replace(/[^-0-9]/g, ''),
)
"
/>
<span v-if="modalType == 1" style="margin: 2px; color: white"></span>
<a-input
v-if="modalType == 1"
v-model:value="decimalToDMS_1.seconds"
style="width: 120px"
@change="
decimalToDMS_1.seconds = parseFloat(
decimalToDMS_1.seconds.toString().replace(/[^-0-9]/g, ''),
)
"
/>
<span v-if="modalType == 1" style="margin: 2px; color: white"></span>
</div>
</a-col>
<!-- 高度 -->
<a-col :span="6" v-if="[0].includes(nowMarkData.resource.type)">
<div class="markTitle">高度</div>
</a-col>
<a-col :span="18" v-if="[0].includes(nowMarkData.resource.type)">
<div class="markContent">
<a-input v-model:value="nowMarkData.resource.content.geometry.coordinates[2]">
<template #addonAfter> <span style="color: white">m</span> </template>
</a-input>
</div>
</a-col>
<!-- 圆心经度 -->
<a-col :span="6" v-if="[3].includes(nowMarkData.resource.type)">
<div class="markTitle">圆心经度</div>
</a-col>
<a-col :span="18" v-if="[3].includes(nowMarkData.resource.type)">
<div class="markContent">
<a-input v-model:value="nowMarkData.resource.content.geometry.coordinates[0]">
<template #addonAfter> <span style="color: white">°</span> </template>
</a-input>
</div>
</a-col>
<!-- 圆心纬度 -->
<a-col :span="6" v-if="[3].includes(nowMarkData.resource.type)">
<div class="markTitle">圆心纬度</div>
</a-col>
<a-col :span="18" v-if="[3].includes(nowMarkData.resource.type)">
<div class="markContent">
<a-input v-model:value="nowMarkData.resource.content.geometry.coordinates[1]">
<template #addonAfter> <span style="color: white">°</span> </template>
</a-input>
</div>
</a-col>
<!-- 水平半径 -->
<a-col :span="6" v-if="[3].includes(nowMarkData.resource.type)">
<div class="markTitle">水平半径</div>
</a-col>
<a-col :span="18" v-if="[3].includes(nowMarkData.resource.type)">
<div class="markContent">
<a-input v-model:value="nowMarkData.resource.content.geometry.radius">
<template #addonAfter> <span style="color: white">m</span> </template>
</a-input>
</div>
</a-col>
<!-- 水平面积形状 -->
<a-col :span="6" v-if="[2, 3].includes(nowMarkData.resource.type)">
<div class="markTitle">水平面积</div>
</a-col>
<a-col :span="18" v-if="[2, 3].includes(nowMarkData.resource.type)">
<div class="markContent">
<span style="color: white; gap: 10px" v-if="[2].includes(nowMarkData.resource.type)">
</span>
<span style="color: white; gap: 10px" v-if="[3].includes(nowMarkData.resource.type)">
{{
(
Math.PI *
nowMarkData.resource.content.geometry.radius *
nowMarkData.resource.content.geometry.radius
).toFixed(2)
}}
</span>
</div>
</a-col>
<!-- 水平周长形状 -->
<a-col :span="6" v-if="[2, 3].includes(nowMarkData.resource.type)">
<div class="markTitle">水平周长</div>
</a-col>
<a-col :span="18" v-if="[2, 3].includes(nowMarkData.resource.type)">
<div class="markContent">
<span style="color: white; gap: 10px" v-if="[2].includes(nowMarkData.resource.type)">
m
</span>
<span style="color: white; gap: 10px" v-if="[3].includes(nowMarkData.resource.type)">
{{ (2 * Math.PI * nowMarkData.resource.content.geometry.radius).toFixed(1) }}
m
</span>
</div>
</a-col>
<!-- 水平距离线 -->
<a-col :span="6" v-if="[1].includes(nowMarkData.resource.type)">
<div class="markTitle">水平距离</div>
</a-col>
<a-col :span="18" v-if="[1].includes(nowMarkData.resource.type)">
<div class="markContent">
<span style="color: white; gap: 10px">
<!-- {{ getLineStringDistance(nowMarkData.resource)[0] }}m -->
</span>
</div>
</a-col>
<!-- 直线距离线 -->
<a-col :span="6" v-if="[1].includes(nowMarkData.resource.type)">
<div class="markTitle">直线距离</div>
</a-col>
<a-col :span="18" v-if="[1].includes(nowMarkData.resource.type)">
<div class="markContent">
<span style="color: white; gap: 10px"> m </span>
</div>
</a-col>
<!-- 高度差线 -->
<a-col :span="6" v-if="[1, 2].includes(nowMarkData.resource.type)">
<div class="markTitle">高度差</div>
</a-col>
<a-col :span="18" v-if="[1, 2].includes(nowMarkData.resource.type)">
<div class="markContent">
<span style="color: white; gap: 10px" v-if="[1].includes(nowMarkData.resource.type)">
m
</span>
<span style="color: white; gap: 10px" v-if="[2].includes(nowMarkData.resource.type)">
m
</span>
</div>
</a-col>
<!-- 简介线 -->
<a-col :span="6">
<div class="markTitle">简介</div>
</a-col>
<a-col :span="18">
<div class="markContent">
<a-textarea
v-model:value="nowMarkData.resource.remark"
:rows="4"
:maxlength="10"
placeholder="请输入"
allow-clear
/>
</div>
</a-col>
<!-- 绘制者线 -->
<a-col :span="6">
<div class="markTitle">绘制者</div>
</a-col>
<a-col :span="18">
<div class="markContent">
<span style="color: white">{{ nowMarkData.resource.user_name }}</span>
</div>
</a-col>
</a-row>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, watch, watchEffect, computed, onMounted } from 'vue';
import * as mars3d from 'mars3d';
import * as Cesium from 'mars3d-cesium';
import {
line_start_cap_0,
line_start_cap_1,
line_start_cap_2,
line_start_cap_3,
line_end_cap_0,
line_end_cap_1,
line_end_cap_2,
line_end_cap_3,
} from './svg';
import {
CloseOutlined,
DeleteOutlined,
CheckOutlined,
AimOutlined,
AlignLeftOutlined,
InfoCircleOutlined,
AntDesignOutlined,
ExpandAltOutlined,
BorderOutlined,
LogoutOutlined,
} from '@ant-design/icons-vue';
import { cloneDeep } from 'lodash-es';
let map: mars3d.Map;
const props = defineProps(['allMarkDataList', 'nowShowMarkData']);
const emits = defineEmits([
'setNowShowMarkData',
'closePathMarkInfo',
'handlerLocation',
'deleteMark',
]);
const nowMarkData: any = ref(props.nowShowMarkData);
//
const modalType = ref<number>(0);
// -
const decimalToDMS_0 = ref({
degrees: 0,
minutes: 0,
seconds: 0,
});
// -
const decimalToDMS_1 = ref({
degrees: 0,
minutes: 0,
seconds: 0,
});
watch(
() => modalType.value,
(newValue) => {
if (newValue == 0) {
// - -
let { degrees, minutes, seconds } = decimalToDMS_0.value;
let decimal = Math.abs(degrees) + minutes / 60 + seconds / 3600;
nowMarkData.value.resource.content.geometry.coordinates[0] = decimal;
// - -
degrees = decimalToDMS_1.value.degrees;
minutes = decimalToDMS_1.value.minutes;
seconds = decimalToDMS_1.value.seconds;
decimal = Math.abs(degrees) + minutes / 60 + seconds / 3600;
nowMarkData.value.resource.content.geometry.coordinates[1] = decimal;
}
if (newValue == 1) {
// - -
const decimal1 = nowMarkData.value.resource.content.geometry.coordinates[0];
const degrees1 = Math.floor(decimal1);
const minutesFull1 = (decimal1 - degrees1) * 60;
const minutes1 = Math.floor(minutesFull1);
const seconds1 = parseFloat((minutesFull1 - minutes1) * 60);
decimalToDMS_0.value = {
degrees: degrees1,
minutes: minutes1,
seconds: seconds1,
};
// - -
const decimal2 = nowMarkData.value.resource.content.geometry.coordinates[1];
const degrees2 = Math.floor(decimal2);
const minutesFull2 = (decimal2 - degrees2) * 60;
const minutes2 = Math.floor(minutesFull2);
const seconds2 = parseFloat((minutesFull2 - minutes2) * 60);
decimalToDMS_1.value = {
degrees: degrees2,
minutes: minutes2,
seconds: seconds2,
};
}
},
);
//
function closePathMarkInfo() {
emits('closePathMarkInfo');
}
//
function handlerLocation() {
let coordinates = props.nowShowMarkData.resource.content.geometry.coordinates;
switch (props.nowShowMarkData.resource.type) {
case 0:
emits('handlerLocation', {
lng: coordinates[0],
lat: coordinates[1],
});
break;
case 1:
emits('handlerLocation', {
lng: coordinates[0][0],
lat: coordinates[0][1],
});
break;
case 2:
emits('handlerLocation', {
lng: coordinates[0][0][0],
lat: coordinates[0][0][1],
});
break;
case 3:
emits('handlerLocation', {
lng: coordinates[0],
lat: coordinates[1],
});
break;
}
}
//
function deleteMark() {
emits('deleteMark', props.nowShowMarkData);
}
watch(
() => props.nowShowMarkData,
() => {
nowMarkData.value = props.nowShowMarkData;
},
{
deep: true,
immediate: true,
},
);
onMounted(() => {});
</script>
<style lang="less" scoped>
.markInfo {
//
-webkit-user-select: none; /* Safari */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* IE/Edge */
user-select: none;
position: relative;
width: 100%;
height: 100%;
background: #232323;
.markInfo_biaozhu_1 {
padding: 15px;
}
.markInfo_biaozhu_2 {
padding: 15px;
overflow-y: auto;
height: 650px;
}
}
//
.closeButton {
position: absolute;
top: 30px;
right: 20px;
z-index: 200;
}
.markTitle {
display: flex;
align-items: center;
justify-content: flex-start;
color: #ffffff;
font-size: 14px;
min-height: 45px;
height: auto;
width: 100%;
flex-wrap: wrap;
.markTitleButton_right {
height: 20px;
width: 20px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 12px;
font-size: 18px;
}
.markTitleButton {
height: 20px;
width: 20px;
display: flex;
align-items: center;
justify-content: center;
margin-left: 12px;
font-size: 18px;
}
}
.markContent {
display: flex;
align-items: center;
justify-content: flex-start;
min-height: 45px;
height: auto;
width: 100%;
flex-wrap: wrap;
}
.popoverClass {
width: 18px;
height: 18px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 3px;
margin-right: 5px;
}
.svg-container {
display: block;
}
::v-deep .markContent .ant-input {
padding: 0px !important;
}
::v-deep .markContent .ant-select-selection-item {
height: 20px !important;
}
</style>

@ -0,0 +1,234 @@
export const line_start_cap_0 = `<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
fill="none"
version="1.1"
width="36"
height="12"
viewBox="0 0 48 16"
>
<g>
<g>
<path
d="M44,9L4,9L4,7L44,7L44,9Z"
fill-rule="evenodd"
fill="#000000"
fill-opacity="1"
/>
</g>
</g>
</svg>`;
export const line_start_cap_1 = `<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
fill="none"
version="1.1"
width="36"
height="12"
viewBox="0 0 48 16"
>
<g>
<g>
<path
d="M14.0459,2.2L4,8L14.0459,13.8L14.0459,9L44,9L44,7L14.0459,7L14.0459,2.2Z"
fill-rule="evenodd"
fill="#000000"
fill-opacity="1"
/>
</g>
</g>
</svg>`;
export const line_start_cap_2 = `<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
fill="none"
version="1.1"
width="36"
height="12"
viewBox="0 0 48 16"
>
<g>
<g>
<g>
<path
d="M44,9L4,9L4,7L44,7L44,9Z"
fill-rule="evenodd"
fill="#000000"
fill-opacity="1"
/>
</g>
<g>
<rect
x="4"
y="4"
width="2"
height="8"
rx="0"
fill="#000000"
fill-opacity="1"
/>
</g>
</g>
</g>
</svg>`;
export const line_start_cap_3 = `<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
fill="none"
version="1.1"
width="36"
height="12"
viewBox="0 0 48 16"
>
<g>
<g>
<g>
<path
d="M44,9L5.5,9L5.5,7L44,7L44,9Z"
fill-rule="evenodd"
fill="#000000"
fill-opacity="1"
/>
</g>
<g>
<ellipse cx="7" cy="8" rx="3" ry="3" fill="#000000" fill-opacity="1" />
</g>
</g>
</g>
</svg>`;
export const line_end_cap_0 = `<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
fill="none"
version="1.1"
width="36"
height="12"
viewBox="0 0 48 16"
>
<g>
<g>
<path
d="M44,9L4,9L4,7L44,7L44,9Z"
fill-rule="evenodd"
fill="#000000"
fill-opacity="1"
/>
</g>
</g>
</svg>`;
export const line_end_cap_1 = `<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
fill="none"
version="1.1"
width="36"
height="12"
viewBox="0 0 48 16"
>
<g>
<g>
<path
d="M33.9541,13.8L44,8L33.9541,2.2L33.9541,7L4,7L4,9L33.9541,9L33.9541,13.8Z"
fill-rule="evenodd"
fill="#000000"
fill-opacity="1"
/>
</g>
</g>
</svg>`;
export const line_end_cap_2 = `<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
fill="none"
version="1.1"
width="36"
height="12"
viewBox="0 0 48 16"
>
<g>
<g>
<g>
<path
d="M44,9L4,9L4,7L44,7L44,9Z"
fill-rule="evenodd"
fill="#000000"
fill-opacity="1"
/>
</g>
<g>
<rect
x="42"
y="4"
width="2"
height="8"
rx="0"
fill="#000000"
fill-opacity="1"
/>
</g>
</g>
</g>
</svg>`;
export const line_end_cap_3 = `<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
fill="none"
version="1.1"
width="36"
height="12"
viewBox="0 0 48 16"
>
<g>
<g>
<g>
<path
d="M43.5,9L4,9L4,7L43.5,7L43.5,9Z"
fill-rule="evenodd"
fill="#000000"
fill-opacity="1"
/>
</g>
<g>
<ellipse cx="41" cy="8" rx="3" ry="3" fill="#000000" fill-opacity="1" />
</g>
</g>
</g>
</svg>`;
export const circle = `<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="48"
height="48"
viewBox="0 0 512 512"
>
<path d="M256 8C119 8 8 119 8 256s111 248 248 248s248-111 248-248S393 8 256 8z" fill="#000000">
</path>
</svg>`;
export const rect = `<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="48"
height="48"
viewBox="0 0 512 512">
<path d="M2 4h20v16H2z" fill="#000000">
</path>
</svg>`;
export const triangle = `<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="48"
height="48"
viewBox="0 0 512 512">
<path d="M464 464H48a16 16 0 0 1-14.07-23.62l208-384a16 16 0 0 1 28.14 0l208 384A16 16 0 0 1 464 464z" fill="#000000">
</path>
</svg>`;
Loading…
Cancel
Save