dianlixunjian
徐景良 10 months ago
parent 7e31b6f37b
commit 475c57c440

File diff suppressed because one or more lines are too long

Binary file not shown.

@ -32,6 +32,11 @@
<script src="/monitor/jquery-1.12.4.min.js"></script>
<script src="/monitor/jsencrypt.min.js"></script>
<script src="/monitor/jsWebControl-1.0.0.min.js"></script>
<!-- easy plaer -->
<script src="./EasyPlayer-element.min.js"></script>
</head>
<body>
<div id="app">

@ -73,6 +73,7 @@
}
},
"dependencies": {
"@easydarwin/easyplayer": "^5.1.1",
"@ant-design/icons-vue": "^7.0.1",
"@icon-park/svg": "^1.4.2",
"@iconify/iconify": "^3.1.1",

@ -15,9 +15,12 @@ export function splitPolygonByLine(line, outerPolygon) {
}
console.log("************** 分割开始 start **************")
console.log("第1步传入的分割线数据",line);
console.log("第2步传入的分割面数据",outerPolygon)
// 处理被分割的面数据坐标小数点保留多少位
let truncatedSplitter = turf.truncate(turf.lineString(outerPolygon.geometry.coordinates[0]), dealOptions);
console.log("第3步分割面转换为线数据",truncatedSplitter);
@ -117,6 +120,8 @@ function getRandomPointInPolygon(polygon) {
// 单个面数据分割
export async function splitPolygonByFill(drawPolygon, outerPolygon) {
console.log("outerPolygon",outerPolygon);
return new Promise((resolve,reject)=>{
try{
@ -124,9 +129,18 @@ export async function splitPolygonByFill(drawPolygon, outerPolygon) {
console.log("第2步传入的被切割面数据",outerPolygon)
var polygon1 = turf.polygon(drawPolygon.geometry.coordinates);
var polygon2 = turf.polygon(outerPolygon.geometry.coordinates);
// 判断被分割的面类型
var polygon2 = null;
if(outerPolygon.geometry.type == "MultiPolygon"){
polygon2 = turf.multiPolygon(outerPolygon.geometry.coordinates);
}else if(outerPolygon.geometry.type == "Polygon"){
polygon2 = turf.polygon(outerPolygon.geometry.coordinates);
}
// var intersection = turf.intersect(polygon1, polygon2);
let intersection = turf.intersect(turf.featureCollection([polygon1, polygon2]));
console.log("第4步获取绘制图斑和分割图斑的交集",JSON.stringify(polygon2),JSON.stringify(polygon1),intersection);
@ -134,9 +148,7 @@ export async function splitPolygonByFill(drawPolygon, outerPolygon) {
console.log("第3步获取绘制图斑和分割图斑的差集",difference);
let splitAfterFeatures = [intersection,difference];
setTimeout(function(){
console.log("splitAfterFeatures9876",splitAfterFeatures);
},3000)
resolve(splitAfterFeatures)
}catch(e){
console.log(e);

@ -1,8 +1,17 @@
<template>
<div class="statistical" id="bg-pan">
<Map @onload="handlerOnMapLoad" @handlerGetDetails="handlerGetDetails" style="position: absolute; top: 0px; left: 0px;height: calc( 100vh - 80px);width:100%;z-index:0;" ref="MapboxComponent"></Map>
<Map
@onload="handlerOnMapLoad"
@handlerGetDetails="handlerGetDetails"
style="position: absolute; top: 0px; left: 0px;height: calc( 100vh - 80px);width:100%;z-index:0;"
ref="MapboxComponent"
@showMonitor="showMonitor"
@handlerQueryIntersectTif="handlerQueryIntersectTif"
></Map>
<div style="position: absolute; left:60px; bottom: 20px; z-index:1;">
<div :class="`button-item ${buttonSelect == 1? 'button-select': ''}`" style="margin-bottom: 10px" @click="changeLayer(1)"></div>
<div :class="`button-item ${buttonSelect == 2? 'button-select': ''}`" style="margin-bottom: 10px" @click="changeLayer(2)"></div>
@ -30,7 +39,25 @@
<ShowInfoModal v-if="showInfoOpen" :showInfoData="showInfoData" />
</div>
</a-modal>
<!-- 图层控制 视频监控-->
<div class="layer-center-container">
<LayerCenter
@drawPolygon="drawPolygon"
@cancleDrawPolygon="cancleDrawPolygon"
@changeTifLayer="changeTifLayer"
ref="LayerCenterComponent"></LayerCenter>
</div>
<div class="TC-videoi-container" v-if="showTCLPlayer" v-drag>
<div class="close-button" @click="showTCLPlayer = false;">
<CloseOutlined></CloseOutlined>
</div>
<Monitor v-if="showTCLPlayer" :play-url="playUrl"></Monitor>
</div>
</div>
</template>
@ -128,7 +155,44 @@
break;
}
}
/*图层控制 视频监控*/
import LayerCenter from './mapComponent/layers/index.vue';
//
import Monitor from './mapComponent/monitor/index.vue';
import {CloseOutlined} from "@ant-design/icons-vue"
const showTCLPlayer = ref(false);
const playUrl = ref("");
function showMonitor(info){
playUrl.value = info.playUrl
showTCLPlayer.value = true;
}
//
function drawPolygon(state){
// Map
MapboxComponent.value.handlerDrawPolygon();
}
function cancleDrawPolygon(){
MapboxComponent.value.handlerDeletePolygon();
}
const LayerCenterComponent = ref();
function handlerQueryIntersectTif(wktStr){
LayerCenterComponent.value.handlerQueryIntersectTif(wktStr);
}
function changeTifLayer(layer){
console.log("layer",layer);
MapboxComponent.value.handlerChangeTifLayer(layer);
}
</script>
<style lang="less" scoped>
@ -263,6 +327,53 @@
}
}
/**图层控制 视频监控**/
.layer-center-container{
width:208px;
position:absolute;
bottom:0px;
left:20px;
z-index:99999;
}
.TC-videoi-container{
position: absolute;
bottom:48px;
right:38px;
width:418px;
height:300px;
.close-button{
width:28px;
height:28px;
background:rgba(0, 0, 0, 0.6);
text-align: center;
line-height:28px;
position:absolute;
top:4px;
right:4px;
z-index:999999;
color:#fff;
cursor:pointer;
}
}
.selection-button{
position:absolute;
cursor:pointer;
top:20px;
left:220px;
width:140px;
height:40px;
margin-left:20px;
background-image: url(/map/change-view-btn.png);
background-size:100% 100%;
color:#efefef;
text-align: center;
line-height:46px;
font-size:14px;
}
</style>

@ -0,0 +1,16 @@
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [118.429056,35.387537]
},
"properties": {
"name":"沂南县砖埠镇东岳庄村北可见光",
"playUrl":"http://221.2.83.254:7012/live/37130100181328000001.m3u8"
}
}
]
}

@ -42,10 +42,17 @@ mapContainerName.value = "mapContainer-"+generateUUID();
//
import { TableOutlined, GlobalOutlined,HomeOutlined} from '@ant-design/icons-vue';
const emits = defineEmits(["onload","handlerGetDetails"])
//
import { message, Modal } from 'ant-design-vue';
import U from 'mapbox-gl-utils';
import {MP} from "./src/MP";
import { GeojsonToWkt } from './src/WktGeojsonTransform';
const emits = defineEmits(["onload","handlerGetDetails","showMonitor","handlerQueryIntersectTif"])
let map:Map;
let mp: any = null;
// init map
@ -841,7 +848,9 @@ onMounted(()=>{
mapboxgl.accessToken = MAPBOX_TOKEN;
map = initMap();
//mapbox-gl-utils
U.init(map);
mp = new MP(map);
map.on("load",()=>{
//
@ -865,6 +874,9 @@ onMounted(()=>{
getMaskData();
handlerDealStreet();
handlerDealCountry();
//
addMonitorLayer();
})
})
@ -874,8 +886,170 @@ defineExpose({
handlerChangeCounty, //
handlerChangeLayerVisible, //
handlerLoadPolygon,
handlerDrawPolygon, //
handlerDeletePolygon, //
handlerChangeTifLayer, //
});
/* 图层控制 视频监控*/
import MonitoringData from './MonitoringData.json';
function addMonitorLayer() {
//
map.loadImage('/monitor/monitor.png', function (error, image) {
if (error) throw error;
if (!map.hasImage('monitorIcon')) {
map.addImage('monitorIcon', image);
}
});
//
map.addSource('JianKongSource', {
type: 'geojson',
data: MonitoringData,
});
//
map.addLayer({
id: 'JianKong',
type: 'symbol',
source: 'JianKongSource',
layout: {
'icon-image': 'monitorIcon',
'icon-size': 0.8,
'text-field': ['get', 'name'],
'text-size': 12,
'text-font': ['Open Sans Semibold', 'Arial Unicode MS Bold'],
'text-offset': [0, 1.6],
'text-anchor': 'top',
'text-allow-overlap': false,
visibility: 'none',
},
paint: {
'text-color': '#041B36',
'text-halo-color': '#fff',
'text-halo-width': 2,
},
});
map.on('click', 'JianKong', (e) => {
//
emits('showMonitor', e.features[0].properties);
});
}
function handlerDeletePolygon(){
mp.deleteDraw();
}
function handlerDrawPolygon (){
mp.draw('Polygon');
mp.on('Polygon', function (e) {
Modal.confirm({
title: '是否查询历史影像?',
onCancel() {
// mp.deleteDraw();
},
async onOk() {
let geojson = {
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates":[]
}
}
let coordinates = [];
e?.forEach((item, index) => {
coordinates?.push([item.lng, item.lat]);
});
coordinates.push(coordinates[0]);
geojson.geometry.coordinates[0] = coordinates
let wktStr = GeojsonToWkt(geojson.geometry)
emits("handlerQueryIntersectTif",wktStr)
},
});
// emit('mapDraw', 'Polygon', e);
});
};
const tifLayers = ref([])
function handlerChangeTifLayer(item){
if(item.type == 'historyLayer' || item.type == 'speciaLayer'){
if (item.checked) { //
if(map.getLayer(item.id)){
map.setLayoutProperty(item.id, 'visibility', 'visible');
}else{
map.addSource("source"+item.id,{
type: "raster",
tiles: [
item.url,
],
tileSize: 256,
})
map.addLayer({
id: item.id,
type: "raster",
source: "source"+item.id,
layout: {
visibility: "visible",
},
paint: {},
})
tifLayers.value.push(item.id);
map.moveLayer(item.id,"historyLayerFill");
map.moveLayer(item.id,"historyLayerLine");
}
} else {
map.setLayoutProperty(item.id, 'visibility', 'none');
}
}else if(item.type == "dataLayer"){
if(item.id == "Monitor"){
if(map.getLayer("JianKong")){
if (item.checked) {
map.setLayoutProperty("JianKong", 'visibility', 'visible');
} else {
map.setLayoutProperty("JianKong", 'visibility', 'none');
}
}
}else if(item.id == "Data"){
if(map.getLayer("historyLayerLine")){
if (item.checked) {
map.setLayoutProperty("historyLayerLine", 'visibility', 'visible');
map.setLayoutProperty("historyLayerFill", 'visibility', 'visible');
} else {
map.setLayoutProperty("historyLayerLine", 'visibility', 'none');
map.setLayoutProperty("historyLayerFill", 'visibility', 'none');
}
}
}
}else if(item.type == "baseLayer"){
switch(item.id){
case 1:
handlerChangeLayerVisible('tdt-img-tiles',false)
handlerChangeLayerVisible('tdt-vec-tiles',true)
handlerChangeLayerVisible('countyPanelLayer',false)
break;
case 2:
handlerChangeLayerVisible('tdt-img-tiles',true)
handlerChangeLayerVisible('tdt-vec-tiles',false)
handlerChangeLayerVisible('countyPanelLayer',false)
break;
case 3:
handlerChangeLayerVisible('tdt-img-tiles',false)
handlerChangeLayerVisible('tdt-vec-tiles',false)
handlerChangeLayerVisible('countyPanelLayer',true)
break;
}
}
}
</script>
<style type="less" scoped>
.map-container{

@ -0,0 +1,554 @@
import U from 'mapbox-gl-utils';
import * as turf from '@turf/turf';
type EventType = 'Point' | 'LineString' | 'Polygon';
interface GenerateGeoJSONDataInterface {
lng: number;
lat: number;
}
interface FeatureCollection {
type: string;
features: Array<any>;
}
const CIRCLE_STYLE = {
'circle-color': '#6495ED',
'circle-radius': 8,
'circle-stroke-width': 2,
'circle-stroke-color': '#ffffff',
};
const LINE_STYLE = {
'line-color': '#6495ED',
'line-width': 3,
};
const LINE_IS_DRAW_STYLE = {
'line-dasharray': [2, 2],
'line-color': '#00FA9A',
'line-width': 3,
};
const POLYGON_STYLE = {
'fill-color': '#FAFAD2',
'fill-opacity': 0.1,
};
function typeOf(obj: any): any {
const toString: any = Object.prototype.toString;
const map: any = {
'[object Boolean]': 'boolean',
'[object Number]': 'number',
'[object String]': 'string',
'[object Function]': 'function',
'[object Array]': 'array',
'[object Date]': 'date',
'[object RegExp]': 'regExp',
'[object Undefined]': 'undefined',
'[object Null]': 'null',
'[object Object]': 'object',
};
return map[toString.call(obj)];
}
function deepClone(data: any): any {
// 获取传入拷贝函数的数据类型
const type = typeOf(data);
// 定义一个返回any类型的数据
let reData: any;
// 递归遍历一个array类型数据
if (type === 'array') {
reData = [];
for (let i = 0; i < data.length; i++) {
reData.push(deepClone(data[i]));
}
} else if (type === 'object') {
//递归遍历一个object类型数据
reData = {};
for (const i in data) {
reData[i] = deepClone(data[i]);
}
} else {
// 返回基本数据类型
return data;
}
// 将any类型的数据return出去作为deepClone的结果
return reData;
}
class BaseMP {
map: any;
listeners: {};
constructor(map: any) {
this.map = map;
// 初始化mapbox工具类
U.init(this.map);
this.listeners = {};
}
//监听
on(event: EventType, callback: void) {
console.log('on', event);
this.listeners[event] = callback;
}
off(event: EventType) {
console.log('off', event);
if (this.listeners[event]) {
delete this.listeners[event];
}
}
emit(event: EventType, data: any) {
if (this.listeners[event]) {
this.listeners[event](data);
}
}
//防抖函数
debounce = (func: Function, delay: number) => {
let timer: any = null;
return (...args: any) => {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, args);
}, delay);
};
};
//切换鼠标样式
_changeMouseCursor = (cursor: string = 'pointer') => {
this.map.getCanvas().style.cursor = cursor;
};
//生成geoJson
_generateGeoJSON(data: GenerateGeoJSONDataInterface[], geometryType: EventType) {
/**
* // 生成点类型的GeoJSON
* var data = [{lng: -122.4194, lat: 37.7749}, {lng: -122.408, lat: 37.791}, {lng: -122.431, lat: 37.769}];
* var geoJSON = generateGeoJSON(data, "Point");
*
* // 生成线类型的GeoJSON
* var data = [{lng: -122.4194, lat: 37.7749}, {lng: -122.408, lat: 37.791}, {lng: -122.431, lat: 37.769}];
* var geoJSON = generateGeoJSON(data, "LineString");
*
* // 生成面类型的GeoJSON
* var data = [{lng: -122.4194, lat: 37.7749}, {lng: -122.408, lat: 37.791}, {lng: -122.431, lat: 37.769}];
* var geoJSON = generateGeoJSON(data, "Polygon");
* **/
const featureCollection: FeatureCollection = {
type: 'FeatureCollection',
features: [],
};
switch (geometryType) {
case 'Point':
for (let i = 0; i < data.length; i++) {
const feature = {
type: 'Feature',
geometry: {
type: geometryType,
coordinates: [data[i].lng, data[i].lat],
},
properties: {},
};
featureCollection.features.push(feature);
}
break;
case 'LineString':
const lineFeature = {
type: 'Feature',
geometry: {
type: geometryType,
coordinates: [],
},
properties: {},
};
for (let i = 0; i < data.length; i++) {
lineFeature['geometry']['coordinates'].push([data[i].lng, data[i].lat]);
}
featureCollection.features.push(lineFeature);
break;
case 'Polygon':
const polygonFeature = {
type: 'Feature',
geometry: {
type: geometryType,
coordinates: [[]],
},
properties: {},
};
for (let i = 0; i < data.length; i++) {
polygonFeature['geometry']['coordinates'][0].push([data[i].lng, data[i].lat]);
}
featureCollection.features.push(polygonFeature);
break;
}
return featureCollection;
}
}
export class MP extends BaseMP {
drawModelChoose: { LineString: string; Point: string; Polygon: string; DEFAULT: string };
drawModel: string;
drawLocal: never[];
drawCurrentId: {
point: string; //点
line: string; //线
lastLine: string; //鼠标位置的点
polygon: string;
};
currentMouseLocation: null;
correctionMouseLocation: any;
clickCount: number;
clickTimeout: any;
constructor(map) {
super(map);
this.drawModelChoose = {
LineString: 'LineString',
Point: 'Point',
Polygon: 'Polygon',
DEFAULT: 'default',
};
this.drawModel = this.drawModelChoose.DEFAULT;
this.drawLocal = [];
this.drawCurrentId = {
point: 'current-draw-point', //点
line: 'current-draw-line', //线
lastLine: 'current-draw-last-line', //鼠标位置的点
polygon: 'current-draw-polygon',
};
this.currentMouseLocation = null; //当前鼠标位置
this.correctionMouseLocation = null; //校正后的鼠标位置
this.clickCount = 0; // 定义一个计数器
this.clickTimeout = null; // 定义一个超时变量
}
//添加或更新source
_addOrUpdateSource = (gS, id) => {
if (this.map.getSource(id)) {
this.map.getSource(id).setData(gS);
} else {
this.map.U.addGeoJSON(id, gS);
}
};
// 添加layer有则不操作
_addLayer = (layerId, sourceId, type, style) => {
// 如果图层不存在,添加图层。如果存在,不做操作
if (!this.map.getLayer(sourceId)) {
switch (type) {
case this.drawModelChoose.Point:
//addCircleLayer
this.map.U.addCircleLayer(layerId, sourceId, style);
break;
case this.drawModelChoose.LineString:
//addLineLayer
this.map.U.addLineLayer(layerId, sourceId, style);
break;
case this.drawModelChoose.Polygon:
//addPolygonLayer
this.map.U.addFillLayer(layerId, sourceId, style);
break;
default:
console.log('layer类型错误');
}
}
};
_currentDrawSource = () => {
// currentGSP 点 currentGSL 线 currentGSPL 面
const currentGSP = this._generateGeoJSON(this.drawLocal, 'Point');
this._addOrUpdateSource(currentGSP, this.drawCurrentId.point);
if (
this.drawModel === this.drawModelChoose.LineString ||
this.drawModel === this.drawModelChoose.Polygon
) {
const currentGSL = this._generateGeoJSON(this.drawLocal, 'LineString');
this._addOrUpdateSource(currentGSL, this.drawCurrentId.line);
}
if (this.drawModel === this.drawModelChoose.Polygon) {
const lastGSPL = this._generateGeoJSON(this.drawLocal, 'Polygon');
this._addOrUpdateSource(lastGSPL, this.drawCurrentId.polygon);
}
};
//绘制当前的layer
_currentDrawLayer = () => {
// 如果是点,直接绘制点
this._addLayer(this.drawCurrentId.point, this.drawCurrentId.point, 'Point', CIRCLE_STYLE);
// 如果是线,在点的基础上,加上线
// 如果是面,在线的基础上,加上面
if (
this.drawModel === this.drawModelChoose.LineString ||
this.drawModel === this.drawModelChoose.Polygon
) {
this._addLayer(this.drawCurrentId.line, this.drawCurrentId.line, 'LineString', LINE_STYLE);
}
if (this.drawModel === this.drawModelChoose.Polygon) {
this._addLayer(
this.drawCurrentId.polygon,
this.drawCurrentId.polygon,
'Polygon',
POLYGON_STYLE,
);
}
};
//最后动态的一笔
_currentDrawLastLine = () => {
if (
this.drawModel === this.drawModelChoose.LineString ||
this.drawModel === this.drawModelChoose.Polygon
) {
if (!this.drawLocal.length) {
this.map.U.removeLayer(this.drawCurrentId.lastLine);
this.map.U.removeSource(this.drawCurrentId.lastLine);
return false;
}
const startPoint = this.drawLocal[this.drawLocal.length - 1];
const endPoint = this.getDrawEndPoint();
// 添加动态线
const lastGSL = this._generateGeoJSON([startPoint, endPoint], 'LineString');
this.crossesLine(this.drawLocal, [startPoint, endPoint]);
this._addOrUpdateSource(lastGSL, this.drawCurrentId.lastLine);
this._addLayer(
this.drawCurrentId.lastLine,
this.drawCurrentId.lastLine,
'LineString',
LINE_IS_DRAW_STYLE,
);
}
if (this.drawModel === this.drawModelChoose.Polygon) {
this._currentDrawLastPolygon();
}
};
//获取矫正的最后点
getDrawEndPoint = () => {
let endPoint = null;
if (this.nearlyClientDistant()) {
endPoint = this.correctionMouseLocation;
} else {
endPoint = this.currentMouseLocation;
}
return endPoint;
};
//最后动态的一笔,跟随面生成
_currentDrawLastPolygon = () => {
// 添加动态面
const endPoint = this.getDrawEndPoint();
const drawLocalCopy = deepClone(this.drawLocal);
drawLocalCopy.push(endPoint);
drawLocalCopy.push(drawLocalCopy[0]);
const lastGSPL = this._generateGeoJSON(drawLocalCopy, 'Polygon');
this._addOrUpdateSource(lastGSPL, this.drawCurrentId.polygon);
this._addLayer(
this.drawCurrentId.polygon,
this.drawCurrentId.polygon,
'Polygon',
POLYGON_STYLE,
);
};
//鼠标点击
clickHandler = (e) => {
const _this = this;
this.clickCount++; // 每次单击事件计数器加1
if (this.clickCount === 1) {
// 如果是第一次单击
this.clickTimeout = setTimeout(function () {
// 启动超时变量
// 单击事件
_this.clickCount = 0; // 计数器清零
if (_this.nearlyClientDistant()) {
_this.drawLocal.push(_this.correctionMouseLocation);
// 如果是第一个点,那么就结束绘制
// todo 画面第一点后结束
if (
_this.drawModel === _this.drawModelChoose.Polygon &&
_this.correctionMouseLocation === _this.drawLocal[0]
) {
_this._currentDrawSource();
_this._currentDrawLayer();
_this.emit(_this.drawModel, _this.drawLocal);
_this.finishDraw();
return false;
} else {
_this.drawLocal.pop();
}
} else {
_this.drawLocal.push(e.lngLat);
}
_this._currentDrawSource();
_this._currentDrawLayer();
if (_this.drawModel === _this.drawModelChoose.Point) {
_this.drawIsFinish();
}
}, 200); // 设置超时时间为300毫秒
} else {
// 如果不是第一次单击
clearTimeout(this.clickTimeout); // 清除超时变量
this.clickCount = 0; // 计数器清零
// 在这里编写双击事件的操作
// 鼠标双击事件
if (this.drawModel === this.drawModelChoose.LineString) {
_this.drawLocal.push(e.lngLat);
_this._currentDrawSource();
_this._currentDrawLayer();
this.drawIsFinish();
}
if (this.drawModel === this.drawModelChoose.Polygon) {
_this.drawLocal.push(e.lngLat);
_this._currentDrawSource();
_this._currentDrawLayer();
this.drawIsFinish();
}
}
};
//右键点击
contextmenuHandler = (e) => {
if (this.drawLocal.length < 1) {
return false;
}
this.drawLocal.pop();
this._currentDrawSource();
this._currentDrawLayer();
this._currentDrawLastLine();
};
// 鼠标移动
mousemoveHandler = this.debounce((e) => {
this.currentMouseLocation = e.lngLat;
this._currentDrawLastLine();
}, 5);
// 判断是否吸附距离12像素
nearlyClientDistant = () => {
// 判断屏幕距离,鼠标吸附
let _this = this;
let mousePoint = [this.currentMouseLocation.lng, this.currentMouseLocation.lat];
let closestFeature = null;
let closestDistance = Infinity;
let threshold = 10; // 阈值,单位为像素
// 遍历所有特征,找到距离最近的特征
let clientPosition = _this.map.project(mousePoint);
this.drawLocal.forEach(function (feature) {
_this.map.project([feature.lng, feature.lat]);
let featurePosition = _this.map.project([feature.lng, feature.lat]);
// 计算两个点在屏幕上的像素距离
let distance = Math.sqrt(
Math.pow(clientPosition.x - featurePosition.x, 2) +
Math.pow(clientPosition.y - featurePosition.y, 2),
);
if (distance < closestDistance && distance < threshold) {
closestFeature = feature;
closestDistance = distance;
}
});
// 如果距离小于阈值,则将标注吸附到特征上
if (closestFeature) {
this._changeMouseCursor('pointer');
this.correctionMouseLocation = closestFeature;
return true;
} else {
// console.log('范围外')
this._changeMouseCursor('crosshair');
return false;
}
};
// 判断是否相交 true 相交 false 不相交
crossesLine = (line1, line2) => {
let _this = this;
if (this.drawLocal.length >= 3) {
let _line1 = line1.map((e) => {
return [e.lng, e.lat];
});
_line1.pop();
let _line2 = line2.map((e) => {
return [e.lng, e.lat];
});
//判断是否有交叉
let intersect = turf.lineIntersect(turf.lineString(_line1), turf.lineString(_line2));
if (intersect.features.length > 0) {
let coordinates = intersect.features[0].geometry.coordinates;
//判断是否交叉在点上
const isExist = _line1.some(
(item) => item[0] === coordinates[0] && item[1] === coordinates[1],
);
if (isExist) {
// console.log('no cross,穿过了交点')
_this.map.U.setProperty(this.drawCurrentId.lastLine, 'line-color', '#00FA9A');
_this.map.on('click', this.clickHandler);
} else {
// console.log('cross')
_this.map.U.setProperty(this.drawCurrentId.lastLine, 'line-color', '#DC143C');
_this._changeMouseCursor('no-drop');
_this.map.off('click', this.clickHandler);
}
} else {
// console.log('no cross,不沾边')
_this.map.U.setProperty(this.drawCurrentId.lastLine, 'line-color', '#00FA9A');
_this.map.on('click', this.clickHandler);
}
} else {
return false;
}
};
drawStart = () => {
//每次绘制都要初始化数据
this.drawLocal = [];
this.deleteDraw();
//禁用鼠标双击放大事件
this.map.doubleClickZoom.disable();
this._changeMouseCursor('crosshair');
this.map.on('click', this.clickHandler);
this.map.on('contextmenu', this.contextmenuHandler);
this.map.on('mousemove', this.mousemoveHandler);
};
draw = (shape) => {
if(this.drawModelChoose[shape]) {
this.drawModel = this.drawModelChoose[shape];
this.drawStart();
} else {
console.log(`暂无${shape}类型`);
}
};
drawIsFinish = () => {
let _this = this;
this.emit(this.drawModel, this.drawLocal);
this.finishDraw();
//恢复双击放大功能
setTimeout(() => {
_this.map.doubleClickZoom.enable();
}, 10);
};
// 结束绘制线和面
finishDraw = () => {
this.map.U.removeSource(this.drawCurrentId.lastLine);
this.map.U.removeLayer(this.drawCurrentId.lastLine);
this.drawModel = this.drawModelChoose.DEFAULT;
this.unDraw();
};
unDraw = () => {
// console.log('推出绘制模式');
this.map.off('click', this.clickHandler);
this.map.off('contextmenu', this.contextmenuHandler);
this.map.off('mousemove', this.mousemoveHandler);
this._changeMouseCursor('pointer');
this.drawLocal = [];
};
//删除绘制的内容
deleteDraw = () => {
this.map.U.removeSource([
this.drawCurrentId.line,
this.drawCurrentId.point,
this.drawCurrentId.lastLine,
this.drawCurrentId.polygon,
]);
this.map.U.removeLayer([
this.drawCurrentId.line,
this.drawCurrentId.point,
this.drawCurrentId.lastLine,
this.drawCurrentId.polygon,
]);
this.unDraw();
};
}

@ -0,0 +1,18 @@
import WKT from "terraformer-wkt-parser"
import { wktToGeoJSON,geojsonToWKT } from "@terraformer/wkt"
const WktToGeojson = (wktData)=> {
// return WKT.parse(wktData)
return wktToGeoJSON(wktData);
}
const GeojsonToWkt = (geojsonData)=> {
// return WKT.convert(geojsonData)
console.log("geojsonData",geojsonData)
return geojsonToWKT(geojsonData)
}
export {WktToGeojson,GeojsonToWkt}

@ -0,0 +1,80 @@
export enum MapboxConfig {
ACCESS_TOKEN = 'pk.eyJ1IjoieHVqaW5nbGlhbmciLCJhIjoiY2w3bzFzZnZqMjdieTN1cG92N2I1d2huOSJ9.aQqMz4S-cTziUYizIH_gNg',
// ACCESS_TOKEN = "1234",
TDT_TOKEN = 'b6585bc41ee16251dbe6b1af64f375d9',
// add more config options here
}
export const MapboxDefaultStyle = {
glyphs: 'mapbox://fonts/mapbox/{fontstack}/{range}.pbf',
version: 8,
sources: {
'dianzi': {
type: 'raster',
tiles: [
`https://t0.tianditu.gov.cn/DataServer?T=cva_w&x={x}&y={y}&l={z}&tk=${MapboxConfig.TDT_TOKEN}`,
],
tileSize: 256,
minzoom:18,
maxzoom:24,
},
'dianzi-biaozhu': {
type: 'raster',
tiles: [
`https://t0.tianditu.gov.cn/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=${MapboxConfig.TDT_TOKEN}`,
],
tileSize: 256,
},
'raster-tiles': {
type: 'raster',
tiles: [
`https://t0.tianditu.gov.cn/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=${MapboxConfig.TDT_TOKEN}`,
],
tileSize: 256,
minzoom:0,
maxzoom:18,
},
},
layers: [
{
id: 'dianzi-biaozhu',
type: 'raster',
source: 'dianzi-biaozhu',
layout: {
visibility: 'visible',
},
},{
id: 'tdt-img-tiles',
type: 'raster',
source: 'raster-tiles',
minzoom: 0,
maxzoom: 18,
},{
id: 'dianzi',
type: 'raster',
source: 'dianzi',
layout: {
visibility: 'visible',
},
minzoom: 18,
maxzoom: 24,
}
],
};
export const MapControlConfig = {
DrawPoint: {
handler: 'handlerDrawPoint',
icon: '/point.png',
title: '绘制点',
},
DrawLineString: {
handler: 'handlerDrawLineString',
icon: '/line.png',
title: '绘制线',
},
DrawPolygon: {
handler: 'handlerDrawPolygon',
icon: '/polygon.png',
title: '绘制面',
},
};

@ -0,0 +1,22 @@
.mapboxgl-ctrl-logo {
display: none !important;
}
.map-container {
position: relative;
}
.map-box,
.map-container {
width: 100%;
height: 100%;
}
.map-control {
position: absolute;
right: 10px;
top: 10px;
display: flex;
}
.map-control img {
width: 40px;
height: 40px;
cursor: pointer;
}

@ -0,0 +1,27 @@
.mapboxgl-ctrl-logo {
display: none !important;
}
.map-container{
position: relative;
}
.map-box,
.map-container {
width: 100%;
height: 100%;
}
.map-control {
position: absolute;
right: 10px;
top: 10px;
display: flex;
img {
width: 40px;
height: 40px;
cursor: pointer;
}
img:hover {
scale: 1.2;
}
}

@ -0,0 +1,62 @@
import { ControlOutlined } from '@ant-design/icons-vue';
import * as turf from '@turf/turf'
// js生成UUID
const generateUUID = ()=>{
var d = new Date().getTime(); //Timestamp
var d2 = (performance && performance.now && (performance.now()*1000)) || 0;
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16;
if(d > 0) {
r = (d + r)%16 | 0;
d = Math.floor(d/16);
} else {
r = (d2 + r)%16 | 0;
d2 = Math.floor(d2/16);
}
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
});
}
// js 针对后端post接口参数拼接到url的情况 将json参数转换为 ?key1=value1&key2=value2
const ObjectToUrl = (obj)=>{
let params = "?";
for(let item in obj){
params+=item+"="+obj[item]+"&"
}
return params;
}
// turf获取几何图形的中心
const getGeometryCenter = (geometry)=>{
let coordinates = [];
switch(geometry.geometry.type.toUpperCase()){
case "POINT":
break;
case "MULTIPOINT":
break;
case "LINESTRING":
break;
case "MULTILINESTRING":
break;
case "POLYGON":
coordinates = geometry.geometry.coordinates
break;
case "MULTIPOLYGON":
coordinates = geometry.geometry.coordinates[0]
break;
}
// let polygon = turf.polygon(coordinates);
// let center = turf.centerOfMass(polygon);
return [coordinates[0][0][0],coordinates[0][0][1]];
// return [117.732878836452,35.1320944773393]
}
export { generateUUID,ObjectToUrl,getGeometryCenter }

@ -33,7 +33,7 @@
<!-- case list -->
<CaseList v-show="false" @handlerLayerButtonClick="handlerLayerButtonClick" @toPosition="toPosition"></CaseList>
<!-- uav -->
<UAV v-show="false" @toPosition="toPosition" @handlerUpdateUavLayerData="handlerUpdateUavLayerData" @handlerLayerButtonClick="handlerLayerButtonClick"></UAV>
<!-- <UAV v-show="false" @toPosition="toPosition" @handlerUpdateUavLayerData="handlerUpdateUavLayerData" @handlerLayerButtonClick="handlerLayerButtonClick"></UAV> -->
</div>
<!-- monitor -->
<!-- <Monitor :currentMonitor="monitorInfo" @register="registerModal" /> -->
@ -43,8 +43,17 @@
<div class="close-button" @click="showTCLPlayer = false;">
<CloseOutlined></CloseOutlined>
</div>
<TCVideo v-if="showTCLPlayer"></TCVideo>
<TCVideo v-if="showTCLPlayer" :play-url="'12334344'"></TCVideo>
</div>
<!-- layer center -->
</div>
<div class="layer-center-container">
<LayerCenter></LayerCenter>
</div>
<a-modal
@ -62,8 +71,11 @@
</div>
</a-modal>
</template>
<script lang="ts" setup>
import ShowInfoModal from '@/views/demo/tiankongdi/curbspotcity/MapList/ShowInfoModal/index.vue';
import SearchComponent from './VideoSupervision/search/index.vue'
import Map from './VideoSupervision/map/map.vue';
@ -82,6 +94,10 @@ import {PlayCircleOutlined,EnvironmentOutlined,CloseOutlined} from "@ant-design/
import { useMessage } from '@/hooks/web/useMessage';
import { useMultipleTabStore } from '@/store/modules/multipleTab';
import { getLoadDroneCaseInfoDetail, getCaseInfoById } from '@/api/tiankongdi/index';
import LayerCenter from './VideoSupervision/layers/index.vue';
const { t } = useI18n();
const router = useRouter();
const { createConfirm } = useMessage();
@ -367,4 +383,12 @@ onMounted(() => {
cursor:pointer;
}
}
.layer-center-container{
width:208px;
position:absolute;
bottom:20px;
left:20px;
z-index:99999;
}
</style>

@ -0,0 +1,223 @@
<template>
<div class="layer-list-container" >
<div class="title">
图层
</div>
<p class="cate-name">数据图层</p>
<div class="case-list">
<div class="case-item" v-for="item in dataLayerList" :key="index" >
<img src="/statistical/prove-icon.png" alt="" />
<a-checkbox v-model:checked="item.checked" @change="layerChange(item)" >
<span style="color:#fff;">{{item.name}}</span>
</a-checkbox>
</div>
</div>
<p class="cate-name">历史影像</p>
<div class="case-list">
<div class="case-item" v-for="item in historyLayerList" :key="index" >
<img src="/statistical/prove-icon.png" alt="" />
<a-checkbox v-model:checked="item.checked" @change="layerChange(item)" >
<span style="color:#fff;">{{item.name}}</span>
</a-checkbox>
</div>
<a-empty v-if="historyLayerList.length <= 0" />
</div>
<p class="cate-name">专题图层</p>
<div class="case-list">
<div class="case-item" v-for="item in speciaLayerList" :key="index" >
<img src="/statistical/prove-icon.png" alt="" />
<a-checkbox v-model:checked="item.checked" @change="layerChange(item)" >
<span style="color:#fff;">{{item.name}}</span>
</a-checkbox>
</div>
<a-empty v-if="speciaLayerList.length <= 0" />
</div>
<p class="cate-name">地图底图</p>
<div class="case-list">
<a-radio-group v-model:value="baseLayer">
<div class="case-item" v-for="item in baseLayerList" :key="index" >
<img src="/statistical/prove-icon.png" alt="" />
<a-radio :value="item.value">
<span style="color:#fff;">{{item.name}}</span>
</a-radio>
</div>
</a-radio-group>
</div>
</div>
</template>
<script lang="ts" setup>
import {
defineEmits,
ref,
defineExpose,
} from 'vue'
import {getIntersectTif } from '@/api/tiankongdi';
import { useMessage } from '@/hooks/web/useMessage';
const { createConfirm, createMessage } = useMessage();
const dataLayerList = ref([
{
name:"数据图层",
checked:true,
},
{
name:"视频监控",
checked:false,
value:"JianKong"
}
])
const historyLayerList = ref([
{
name:"费县影像图层",
checked:false,
}
])
const speciaLayerList = ref([
{
name:"地类图层",
checked:false,
},
{
name:"三调图层",
checked:false,
}
])
const baseLayerList = ref([
{
name:"导航地图",
checked:false,
value:"daohang",
},{
name:"卫星地图",
checked:false,
value:"weixing",
},{
name:"白板地图",
checked:false,
value:"baiban",
},
])
const baseLayer = ref("weixing")
const emits = defineEmits(['changeTifLayer'])
const handlerQueryIntersectTif = (wkt:string)=>{
let query = {
TargetShape:wkt,
page:1,
limit:10,
key:null
}
getIntersectTif(query).then(res=>{
if(res.items.length>0){
res.items?.forEach((item,index)=>{
res.items[index].checked = false;
})
layerList.value = res.items;
}else{
createMessage.error("当前范围内暂无查询数据!");
}
})
}
const layerChange = (item)=>{
emits("changeTifLayer",item);
}
//
defineExpose({
// handlerQueryIntersectTif
});
</script>
<style type="less" scoped>
.layer-list-container {
width: 208px;
min-height: 340px;
background: #041b36;
position: relative;
margin-bottom: 20px;
&::before {
content: '';
height: 70%;
width: 20px;
position: absolute;
bottom: 5px;
left: 5px;
background: url('/videosupervision/main-left.png');
background-size: 100% 100%;
}
&::after {
content: '';
height: 70%;
width: 20px;
position: absolute;
bottom: 5px;
right: 5px;
background: url('/videosupervision/main-right.png');
background-size: 100% 100%;
}
.title {
width: 100%;
height: 40px;
background-image: url('/videosupervision/title.png');
background-size: 100% 100%;
line-height: 40px;
text-indent: 18px;
font-size: 18px;
font-weight: bold;
color: #fff;
}
.switch-button {
float: right;
margin-right: 20px;
}
}
.case-list {
padding: 10px 24px;
overflow: auto;
.case-item {
cursor:pointer;
border-bottom: 1px dashed #1d60b4;
color:#fff;
padding: 5px 0;
img {
width: 15px;
margin-right:12px;
}
span {
color: #7ebbff;
margin-left: 10px;
}
}
}
::v-deep .ant-empty{
margin-top:110px;
}
::v-deep .ant-empty-description{
color:#fff;
}
.cate-name{
color:#fff;
padding:12px;
font-size:14px;
margin-bottom:0px;
}
</style>

@ -0,0 +1,16 @@
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [118.429056,35.387537]
},
"properties": {
"name":"沂南县砖埠镇东岳庄村北可见光",
"playUrl":"http://221.2.83.254:7012/live/37130100181328000001.m3u8"
}
}
]
}

@ -20,6 +20,8 @@
</div>
</template>
<script lang="ts" setup>
import MonitoringData from './MonitoringData.json';
import { TableOutlined, GlobalOutlined,HomeOutlined} from '@ant-design/icons-vue';
import { ref, onMounted, defineExpose, defineEmits } from 'vue';
import { generateUUID } from '@/components/MapboxMaps/src/tool';
@ -812,18 +814,11 @@ import { TableOutlined, GlobalOutlined,HomeOutlined} from '@ant-design/icons-vue
}
});
// //
// map.loadImage('/images/map/warning-car.png', function (error, image) {
// if (error) throw error;
// if (!map.hasImage('warningCarIcon')) {
// map.addImage('warningCarIcon', image);
// }
// });
//
map.addSource('JianKongSource', {
type: 'geojson',
data: geojson,
data: MonitoringData,
});
//
@ -1189,7 +1184,6 @@ function handlerChangeTifLayer(item){
//
const handlerDeletePolygon = ()=>{
mp.deleteDraw();
tifLayers.value?.forEach((item,index)=>{
if(map.getLayer(item)){
map.removeLayer(item);

@ -5,47 +5,114 @@
视频监控
</div>
<div v-show="isShowPlayer">
<div class="close-video-button">
<CloseOutlined />
</div>
<video
class="video-container"
class="TCPlayer-video-contaiiner"
id="TCPlaeyrContainer"
width="235px"
height="178px"
autoplay
preload="auto"
playsinline
muted
webkit-playsinline
></video>
</div>
<!-- <video id="flv-player" class="video-js vjs-default-skin" controls preload="auto" width="400" height="250" style="position:relative;left:10px;">
</video> -->
<!-- <EasyPlayer
style="width:900px;height:500px;"
:videoUrl="'http://221.2.83.254:7012/live/37130100181328000001.flv'"
:aspect="'16:9'"
live
:fluent="true"
:autoplay="true"
stretch
></EasyPlayer> -->
<!-- <easy-player
video-url="http://221.2.83.254:7012/live/37130100181328000001.m3u8"
:live="true"
:autoplay="true"
style="width:400px;height:250px;"
></easy-player> -->
</div>
</template>
<script lang="ts" setup>
import {ref,onMounted,onBeforeUnmount} from 'vue';
// import EasyPlayer from '@easydarwin/easyplayer'
const isShowPlayer = ref(false);
let player = null;
function handlerPlayVideo(item){
isShowPlayer.value = true;
if (player) {
player.src("http://221.2.83.254:7012/live/37130100181328000001.flv");
player.src("http://221.2.83.254:7012/live/37130100181328000001.m3u8");
} else {
player = TCPlayer("TCPlaeyrContainer", {});
player.src("http://221.2.83.254:7012/live/37130100181328000001.flv");
player.src("http://221.2.83.254:7012/live/37130100181328000001.m3u8");
}
// player = videojs('flv-player', {
// techOrder: ['flvjs', 'html5'], // 使 flv.js
// autoplay: true,
// controls: true,
// muted: true,
// preload: 'auto',
// sources: [
// {
// // src: 'http://221.2.83.254:7012/live/37130100181328000001.flv', // FLV
// src:"http://60.213.14.14:8080/live/1.flv",
// type: 'video/x-flv',
// },
// ],
// });
// flv.js
// if (flvjs.isSupported()) {
// alert(123);
// const flvPlayer = flvjs.createPlayer({
// type: 'flv',
// url: 'http://221.2.83.254:7012/live/37130100181328000001.flv', // FLV
// },{
// enableStashBuffer: false, //
// isLive: true, //
// stashInitialSize: ,
// });
// flvPlayer.attachMediaElement(document.getElementById('flv-player'));
// flvPlayer.load();
// flvPlayer.play();
// } else {
// console.error('FLV.js is not supported in this browser.');
// }
}
onMounted(()=>{
// document.getElementById("TCPlaeyrContainer").addEventListener('error', () => {
// console.error('Video playback error occurred.1111111111');
// player.reload()
// // if (retryCount < maxRetries) {
// // retryCount++;
// // console.log(`Retrying to load video... Attempt ${retryCount}`);
// // reloadVideo();
// // } else {
// // console.error('Max retries reached. Could not recover video playback.');
// // alert('');
// // }
// });
setTimeout(function(){
handlerPlayVideo(123);
},1000)
@ -54,7 +121,7 @@ onMounted(()=>{
onBeforeUnmount(()=>{
player.dispose();
player = null
player = null;
})
</script>
@ -66,26 +133,7 @@ onBeforeUnmount(()=>{
height: 300px;
background:#041B36;
position: relative;
&::before{
content:"";
height:70%;
width:50px;
position:absolute;
bottom:10px;
left:10px;
background:url("/videosupervision/main-left.png");
background-size:100% 100%;
}
&::after{
content:"";
height:70%;
width:50px;
position:absolute;
bottom:10px;
right:10px;
background:url("/videosupervision/main-right.png");
background-size:100% 100%;
}
.title{
width:100%;
height:40px;
@ -143,7 +191,7 @@ onBeforeUnmount(()=>{
}
}
.video-container{
.TCPlayer-video-contaiiner{
width: calc( 100% - 30px);
height: calc( 100% - 70px);
position:absolute;

@ -1,34 +1,27 @@
<template>
<div class="case-list-container" v-show="tifList.length > 0">
<div class="title">
查询结果
</div>
<div class="case-list">
<div class="case-item" v-for="item in tifList" :key="index" >
<img src="/statistical/prove-icon.png" alt="" />
<a-checkbox v-model:checked="item.checked" @change="layerChange(item)" >
<span>{{item.tifName}}</span>
</a-checkbox>
</div>
<a-empty v-if="tifList.length <= 0" />
<div class="case-list-container" v-show="tifList.length > 0">
<div class="title">
查询结果
</div>
<div class="case-list">
<div class="case-item" v-for="item in tifList" :key="index" >
<img src="/statistical/prove-icon.png" alt="" />
<a-checkbox v-model:checked="item.checked" @change="layerChange(item)" >
<span>{{item.tifName}}</span>
</a-checkbox>
</div>
<a-empty v-if="tifList.length <= 0" />
</div>
</div>
</template>
<script lang="ts" setup>
import {
onMounted,
onUnmounted,
defineProps,
defineEmits,
reactive,
ref,
defineExpose,
watch,
inject,
} from 'vue'
import {getIntersectTif } from '@/api/tiankongdi';
import { useMessage } from '@/hooks/web/useMessage';
const { createConfirm, createMessage } = useMessage();

@ -0,0 +1,290 @@
<template>
<div class="layer-list-container" >
<div class="title">
图层资源
</div>
<div class="layers-container">
<p class="cate-name">数据图层</p>
<div class="case-list">
<div class="case-item" v-for="item in dataLayerList" :key="index" >
<img src="/statistical/prove-icon.png" alt="" />
<a-checkbox v-model:checked="item.checked" @change="layerChange(item,'dataLayer')" >
<span style="color:#fff;">{{item.name}}</span>
</a-checkbox>
</div>
</div>
<p class="cate-name">
历史影像
<div style="float:right;position:relative;top:-4px;">
<a-button style="flaot:right;" @click="drawPolygon" v-if="!drawState" size="small" type="primary"></a-button>
<a-button style="flaot:right;" @click="cancleDrawPolygon" v-else size="small" type="primary">取消查询</a-button>
</div>
</p>
<div class="case-list">
<div class="case-item" v-for="item in historyLayerList" :key="index" >
<img src="/statistical/prove-icon.png" alt="" />
<a-checkbox v-model:checked="item.checked" @change="layerChange(item,'historyLayer')" >
<span style="color:#fff;">{{item.name}}</span>
</a-checkbox>
</div>
<a-empty size="small" :description="'暂无历史影像数据'" v-if="historyLayerList.length <= 0" />
</div>
<p class="cate-name">专题图层</p>
<div class="case-list">
<div class="case-item" v-for="item in speciaLayerList" :key="index" >
<img src="/statistical/prove-icon.png" alt="" />
<a-checkbox v-model:checked="item.checked" @change="layerChange(item,'speciaLayer')" >
<span style="color:#fff;">{{item.name}}</span>
</a-checkbox>
</div>
<a-empty size="small" :description="'暂无专题图层数据'" v-if="speciaLayerList.length <= 0" />
</div>
<p class="cate-name">地图底图</p>
<div class="case-list">
<a-radio-group v-model:value="baseLayer">
<div class="case-item" v-for="item in baseLayerList" :key="index" >
<img src="/statistical/prove-icon.png" alt="" />
<a-radio :value="item.value" @change="layerChange(item,'baseLayer')">
<span style="color:#fff;">{{item.name}}</span>
</a-radio>
</div>
</a-radio-group>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import {
defineEmits,
ref,
defineExpose,
} from 'vue'
import {getIntersectTif } from '@/api/tiankongdi';
import { useMessage } from '@/hooks/web/useMessage';
const { createConfirm, createMessage } = useMessage();
const generateUUID = ()=>{
var d = new Date().getTime(); //Timestamp
var d2 = (performance && performance.now && (performance.now()*1000)) || 0;
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16;
if(d > 0) {
r = (d + r)%16 | 0;
d = Math.floor(d/16);
} else {
r = (d2 + r)%16 | 0;
d2 = Math.floor(d2/16);
}
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
});
}
const dataLayerList = ref([
{
id:"Data",
name:"数据图层",
checked:true,
},
{
id:"Monitor",
name:"视频监控",
checked:false,
}
])
const historyLayerList = ref([
// {
// id:generateUUID(),
// name:"",
// url:"http://60.213.14.14:8060/geoserver/feixian/wms?service=WMS&version=1.1.0&request=GetMap&layers=feixian:yingxiang&styles=&bbox={bbox-epsg-3857}&width=256&height=256&srs=EPSG:3857&format=image/png&TRANSPARENT=TRUE",
// checked:false,
// }
])
const speciaLayerList = ref([
// {
// id:generateUUID(),
// name:"",
// url:"http://60.213.14.14:8060/geoserver/feixian/wms?service=WMS&version=1.1.0&request=GetMap&layers=feixian:yingxiang&styles=&bbox={bbox-epsg-3857}&width=256&height=256&srs=EPSG:3857&format=image/png&TRANSPARENT=TRUE",
// checked:false,
// },
// {
// id:generateUUID(),
// name:"",
// url:"http://60.213.14.14:8060/geoserver/feixian/wms?service=WMS&version=1.1.0&request=GetMap&layers=feixian:yingxiang&styles=&bbox={bbox-epsg-3857}&width=256&height=256&srs=EPSG:3857&format=image/png&TRANSPARENT=TRUE",
// checked:false,
// }
])
const baseLayer = ref("2")
const baseLayerList = ref([
{
id:1,
name:"导航地图",
checked:false,
value:"1"
},{
id:2,
name:"卫星地图",
checked:false,
value:"2"
},{
id:3,
name:"白板地图",
checked:false,
value:"3",
},
])
const emits = defineEmits(['changeTifLayer',"drawPolygon","cancleDrawPolygon"])
const handlerQueryIntersectTif = (wkt:string)=>{
let query = {
TargetShape:wkt,
page:1,
limit:10,
key:null
}
getIntersectTif(query).then(res=>{
if(res.items.length>0){
res.items?.forEach((item,index)=>{
res.items[index].checked = false;
res.items[index].id = generateUUID();
res.items[index].url = res.items[index].accessUrl;
})
historyLayerList.value = res.items;
}else{
createMessage.error("当前范围内暂无查询数据!");
}
})
}
const layerChange = (item,type)=>{
item.type = type;
emits("changeTifLayer",item);
}
const drawState = ref(false);
const cancleDrawPolygon = ()=>{
drawState.value = false;
emits("cancleDrawPolygon")
}
const drawPolygon = (state)=>{
drawState.value = true;
emits("drawPolygon",state)
}
//
defineExpose({
handlerQueryIntersectTif
});
</script>
<style type="less" scoped>
.layer-list-container {
width: 208px;
height: 600px;
background: #041b36;
position: relative;
margin-bottom: 20px;
&::before {
content: '';
height: 70%;
width: 20px;
position: absolute;
bottom: 5px;
left: 5px;
background: url('/videosupervision/main-left.png');
background-size: 100% 100%;
}
&::after {
content: '';
height: 70%;
width: 20px;
position: absolute;
bottom: 5px;
right: 5px;
background: url('/videosupervision/main-right.png');
background-size: 100% 100%;
}
.layers-container{
width:100%;
height: calc( 100% - 60px);
overflow-y:auto;
}
.title {
width: 100%;
height: 40px;
background-image: url('/videosupervision/title.png');
background-size: 100% 100%;
line-height: 40px;
text-indent: 18px;
font-size: 18px;
font-weight: bold;
color: #fff;
}
.switch-button {
float: right;
margin-right: 20px;
}
}
.case-list {
padding: 10px 24px;
overflow: auto;
.case-item {
cursor:pointer;
border-bottom: 1px dashed #1d60b4;
color:#fff;
padding: 5px 0;
img {
width: 15px;
margin-right:12px;
}
span {
color: #7ebbff;
margin-left: 10px;
}
}
}
::v-deep .ant-empty-image{
height:50px;
position:relative;
left:-26px;
}
::v-deep .ant-empty-description{
color:#fff;
}
.cate-name{
color:#fff;
padding:12px;
font-size:14px;
margin-bottom:0px;
background:rgba(0, 0, 0, 0.2)
}
::v-deeep .ant-empty-image img{
width:50px;
height:50px;
}
</style>

@ -0,0 +1,156 @@
<template>
<div class="uav-container">
<div class="title">
视频监控
</div>
<div v-show="isShowPlayer">
<video
class="TCPlayer-video-contaiiner"
id="TCPlaeyrContainer"
width="235px"
height="178px"
autoplay
preload="auto"
playsinline
muted
webkit-playsinline
></video>
</div>
</div>
</template>
<script lang="ts" setup>
import {ref,onMounted,defineProps,onBeforeUnmount} from 'vue';
const props = defineProps(["playUrl"])
let player = null;
const isShowPlayer = ref(false);
function handlerPlayVideo(item){
isShowPlayer.value = true;
if (player) {
player.src(props.playUrl);
} else {
player = TCPlayer("TCPlaeyrContainer", {});
player.src(props.playUrl);
}
}
//
onMounted(()=>{
setTimeout(function(){
handlerPlayVideo(123);
},1000)
})
//
onBeforeUnmount(()=>{
player.dispose();
player = null;
})
</script>
<style type="less" scoped>
.uav-container{
width: 418px;
height: 300px;
background:#041B36;
position: relative;
.title{
width:100%;
height:40px;
background-image:url("/videosupervision/title.png");
background-size:100% 100%;
line-height:40px;
text-indent:18px;
font-size:18px;
font-weight:bold;
color:#fff;
}
.switch-button{
float:right;
margin-right:20px;
}
.uav-list-container{
width:100%;
height: calc( 100% - 60px);
overflow:auto;
padding:20px 20px;
position:relative;
z-index:999;
.uav-empty{
width:100%;
height:100%;
text-align:center;
color:#999;
img{
width:120px;
margin:40px 0px 18px 0px;
}
}
.uav-item{
width:100%;
height:40px;
padding:0px 15px;
line-height:40px;
color:#f1f1f1;
display:flex;
background:rgba(0,0,0,0.2);
&:hover{
background:rgba(0,0,0,0.4);
}
div{
flex:1;
}
.position{
max-width:30px;
cursor:pointer;
}
.play{
max-width:30px;
cursor:pointer;
}
}
}
.TCPlayer-video-contaiiner{
width: calc( 100% - 30px);
height: calc( 100% - 70px);
position:absolute;
margin:15px;
top:40px;
right:0px;
z-index:1000;
background:#041B36;
.video-contain {
width: 100%;
height: 100%;
}
}
.close-video-button{
position:absolute;
top:40px;
right:10px;
background:rgba(0,0,0,0.3);
z-index:100100;
color:#fff;
padding:10px;
cursor:pointer;
&:hover{
color:#408eff;
}
}
}
</style>
Loading…
Cancel
Save