Merge branch 'main' of http://123.132.248.154:10000/gitY/LanLingXiangMu
commit
96d1b934e2
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"i18n-ally.localesPaths": [
|
||||||
|
"src/locales",
|
||||||
|
"src/locales/lang",
|
||||||
|
"public/resource/tinymce/langs"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
<template>
|
||||||
|
<Converge />
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import Converge from '@/views/sys/exception/Converge.vue';
|
||||||
|
</script>
|
||||||
|
|
@ -273,7 +273,7 @@ watchEffect(() => {
|
||||||
const MapboxComponent = ref();
|
const MapboxComponent = ref();
|
||||||
const countyId = ref();
|
const countyId = ref();
|
||||||
const defaultColor = ref('#FFFFFF');
|
const defaultColor = ref('#FFFFFF');
|
||||||
const layerCenterShow = ref(false);
|
const layerCenterShow = ref(true);
|
||||||
function getLayerSettings() {
|
function getLayerSettings() {
|
||||||
let title = '';
|
let title = '';
|
||||||
switch (subject.value) {
|
switch (subject.value) {
|
||||||
|
|
@ -325,7 +325,8 @@ watchEffect(() => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
getConfig({
|
getConfig({
|
||||||
code: title,
|
// code: title,
|
||||||
|
code:"Subject_WFYD",
|
||||||
}).then((res) => {
|
}).then((res) => {
|
||||||
let obj = JSON.parse(res.codeValue);
|
let obj = JSON.parse(res.codeValue);
|
||||||
layerSettings.value = obj[0];
|
layerSettings.value = obj[0];
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,318 @@
|
||||||
|
<template>
|
||||||
|
<a-spin size="large" tip="图层加载中..." :spinning="spinning" wrapperClassName="solid-spin">
|
||||||
|
<div class="statistical" id="bg-pan" ref="container">
|
||||||
|
<Map
|
||||||
|
style="
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
height: calc(100vh - 80px);
|
||||||
|
width: 100%;
|
||||||
|
z-index: 0;
|
||||||
|
"
|
||||||
|
ref="MapboxComponent"
|
||||||
|
@handlerGetDetails="handlerGetDetails"
|
||||||
|
@changeLoading="changeLoading"
|
||||||
|
/>
|
||||||
|
<div class="legend">
|
||||||
|
<div class="legend-item" v-for="(item, index) in legends" :key="index">
|
||||||
|
<div class="legend-dot" :style="{ background: item.color }"></div>
|
||||||
|
<div class="legend-label">{{ item.label }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layer-center-container"
|
||||||
|
:style="style">
|
||||||
|
<div class="drag-area"
|
||||||
|
@mousedown="startDrag"></div>
|
||||||
|
<LayerCenter
|
||||||
|
@changeLayer="changeLayer"
|
||||||
|
@changeLabel="changeLabel"
|
||||||
|
ref="LayerCenterComponent"
|
||||||
|
></LayerCenter>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a-modal
|
||||||
|
title="详情"
|
||||||
|
width="100%"
|
||||||
|
wrap-class-name="full-modal"
|
||||||
|
v-model:open="showInfoOpen"
|
||||||
|
:footer="null"
|
||||||
|
:destroyOnClose="true">
|
||||||
|
<IdleWatersInsertModal v-if="showInfoType == 5" :showInfoData="showInfoData" :showInfoFlyToPoint="showInfoFlyToPoint" :isRead="true"/>
|
||||||
|
<IdleLandInsertModal v-if="showInfoType == 3" :showInfoData="showInfoData" :showInfoFlyToPoint="showInfoFlyToPoint" :isRead="true"/>
|
||||||
|
<IdleHouseInsertModal v-if="showInfoType == 2" :showInfoData="showInfoData" :showInfoFlyToPoint="showInfoFlyToPoint" :isRead="true"/>
|
||||||
|
<IdleFarmingInsertModal v-if="showInfoType == 1" :showInfoData="showInfoData" :showInfoFlyToPoint="showInfoFlyToPoint" :isRead="true"/>
|
||||||
|
<IdleNongjiInsertModal v-if="showInfoType == 4" :showInfoData="showInfoData" :showInfoFlyToPoint="showInfoFlyToPoint" :isRead="true"/>
|
||||||
|
</a-modal>
|
||||||
|
</div>
|
||||||
|
</a-spin>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, onMounted } from 'vue'
|
||||||
|
import Map from './Converge/index.vue';
|
||||||
|
import useDrag from './drag';
|
||||||
|
import LayerCenter from './mapComponent/layers/index.vue';
|
||||||
|
import { getDetail } from '@/api/tiankongdi/index'
|
||||||
|
import IdleWatersInsertModal from '@/views/demo/IdleWaters/InsertModal.vue'
|
||||||
|
import IdleLandInsertModal from '@/views/demo/IdleLand/InsertModal.vue'
|
||||||
|
import IdleHouseInsertModal from '@/views/demo/IdleHouse/InsertModal.vue'
|
||||||
|
import IdleFarmingInsertModal from '@/views/demo/IdleFarming/InsertModal.vue'
|
||||||
|
import IdleNongjiInsertModal from '@/views/demo/IdleNongji/InsertModal.vue'
|
||||||
|
|
||||||
|
const { style, startDrag } = useDrag();
|
||||||
|
|
||||||
|
const MapboxComponent = ref();
|
||||||
|
const showInfoData = ref()
|
||||||
|
const showInfoType = ref()
|
||||||
|
const showInfoFlyToPoint = ref()
|
||||||
|
const showInfoOpen = ref(false)
|
||||||
|
const spinning = ref(false)
|
||||||
|
const legends = ref([
|
||||||
|
{ label:'房屋', color: '#F70303' },
|
||||||
|
{ label:'土地资源', color: '#0AF703' },
|
||||||
|
{ label:'水域', color: '#0382F7' },
|
||||||
|
{ label:'农业生产设施', color: '#F4E004' },
|
||||||
|
])
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
spinning.value = true
|
||||||
|
})
|
||||||
|
const changeLoading = (type: boolean) => {
|
||||||
|
spinning.value = type
|
||||||
|
}
|
||||||
|
function changeLayer(layerList) {
|
||||||
|
MapboxComponent.value.handlerChangeLayer(layerList);
|
||||||
|
}
|
||||||
|
const changeLabel = (type) => {
|
||||||
|
MapboxComponent.value.changeTiandituLabelOpen(type);
|
||||||
|
}
|
||||||
|
const handlerGetDetails = (item, flyPoint) => {
|
||||||
|
console.log('item',item)
|
||||||
|
showInfoType.value = item.Type
|
||||||
|
getDetail( {id:item.Id} , item.Type).then(res => {
|
||||||
|
console.log('res',res)
|
||||||
|
showInfoData.value = res
|
||||||
|
showInfoOpen.value = true
|
||||||
|
showInfoFlyToPoint.value = flyPoint
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.full-modal {
|
||||||
|
.ant-modal {
|
||||||
|
min-width: 100vw;
|
||||||
|
top: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
.ant-modal-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.ant-modal-body {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.statistical{
|
||||||
|
|
||||||
|
:deep(.ant-modal-header){
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
:deep(.ant-modal-wrap){
|
||||||
|
overflow: hidden;
|
||||||
|
pointer-events:none;
|
||||||
|
}
|
||||||
|
:deep(.dragModal){
|
||||||
|
margin: 0 !important;
|
||||||
|
.hidden-show-icon{
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
background-size: 100% 100%;
|
||||||
|
margin-left: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.statistical {
|
||||||
|
// position: relative;
|
||||||
|
// 页面不能被选中
|
||||||
|
-webkit-user-select: none; /* Safari */
|
||||||
|
-moz-user-select: none; /* Firefox */
|
||||||
|
-ms-user-select: none; /* IE/Edge */
|
||||||
|
user-select: none;
|
||||||
|
width:100%;
|
||||||
|
height:calc(-80px + 100vh);
|
||||||
|
position:relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bg-pan {
|
||||||
|
|
||||||
|
}
|
||||||
|
#alertOverlay::before,
|
||||||
|
#alertOverlay::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
width: 50px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#alertOverlay div::before,
|
||||||
|
#alertOverlay div::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#alertOverlay::before {
|
||||||
|
background: linear-gradient(to right, rgba(0, 0, 0, 0.8), transparent);
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
#alertOverlay::after {
|
||||||
|
background: linear-gradient(to left, rgba(0, 0, 0, 0.8), transparent);
|
||||||
|
top: 0%;
|
||||||
|
left: 100%;
|
||||||
|
transform: rotate(0deg) translate(calc(-1 * 50px), 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
#alertOverlay div::before {
|
||||||
|
background: linear-gradient(to top, rgba(0, 0, 0, 0.8), transparent);
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
#alertOverlay div::after {
|
||||||
|
background: linear-gradient(to top, rgba(0, 0, 0, 0.8), transparent);
|
||||||
|
top: 100%;
|
||||||
|
left: 0;
|
||||||
|
transform: rotate(0deg) translate(0px, calc(-1 * 50px));
|
||||||
|
}
|
||||||
|
|
||||||
|
#alertOverlay {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
opacity: 1;
|
||||||
|
transition: opacity 0.5s;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-active {
|
||||||
|
animation: blink 0s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes blink {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.legend {
|
||||||
|
width: 220px;
|
||||||
|
padding: 10px;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 20px;
|
||||||
|
right: 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
column-gap: 30px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background-image: url('/statistical/left_statistical.png');
|
||||||
|
background-size: 100% 100%;
|
||||||
|
.legend-item {
|
||||||
|
width: 120px;
|
||||||
|
padding: 5px 0px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666666;
|
||||||
|
display: flex;
|
||||||
|
flex: 48% 48%;
|
||||||
|
color: #7ebbff;
|
||||||
|
.legend-dot {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
}
|
||||||
|
.legend-label {
|
||||||
|
margin-left: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.flh-item{
|
||||||
|
width: 120px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**图层控制 视频监控**/
|
||||||
|
.layer-center-container {
|
||||||
|
width:285px;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
.drag-area{
|
||||||
|
width:245px;
|
||||||
|
height:40px;
|
||||||
|
position:absolute;
|
||||||
|
top:0px;
|
||||||
|
left:0px;
|
||||||
|
z-index:99999;
|
||||||
|
cursor:move;
|
||||||
|
}
|
||||||
|
.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>
|
||||||
|
<style>
|
||||||
|
.solid-spin.ant-spin-nested-loading > .ant-spin-blur::after {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
.solid-spin.ant-spin-nested-loading .ant-spin{
|
||||||
|
max-height: none;
|
||||||
|
}
|
||||||
|
</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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,389 @@
|
||||||
|
<template>
|
||||||
|
<div class="search-container">
|
||||||
|
<div class="search-input">
|
||||||
|
<a-input
|
||||||
|
placeholder="请输入资源编号或地址"
|
||||||
|
v-model:value="keyword"
|
||||||
|
allow-clear
|
||||||
|
@blur="onInputBlue"
|
||||||
|
></a-input>
|
||||||
|
</div>
|
||||||
|
<div class="search-button" @click="searchArea">
|
||||||
|
<img src="/statistical/search-btn.png" alt="" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="search-result-container" v-if="showSearchResult">
|
||||||
|
<div class="result-item" v-for="(item, index) in searchResult" @click="toPosition(item)">
|
||||||
|
<div class="search-icon">
|
||||||
|
<img src="/statistical/search-icon.png" alt="" />
|
||||||
|
</div>
|
||||||
|
<div class="level-0">{{ item.type?item.serialNumber: item.id }}</div>
|
||||||
|
<div class="level-1"></div>
|
||||||
|
<div class="level-2">{{ item.type? getTypeName(item.type): `${item.county} ${item.street}` }}</div>
|
||||||
|
</div>
|
||||||
|
<a-empty v-if="searchResult.length == 0" />
|
||||||
|
</div>
|
||||||
|
<!-- <div class="filter-container">
|
||||||
|
<div class="filter-name">{{ currentFilter }}</div>
|
||||||
|
<div class="filter-icon" @click="handlerChangeFilterOptions">
|
||||||
|
<CaretDownOutlined />
|
||||||
|
</div>
|
||||||
|
<div class="filter-item-container" v-if="showFilterOptions">
|
||||||
|
<div
|
||||||
|
class="filter-item"
|
||||||
|
v-for="(item, index) in filters"
|
||||||
|
:key="index"
|
||||||
|
@click="handlerCheckedFilter(item.name)"
|
||||||
|
>{{ item.name }}</div
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div> -->
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, onMounted, defineExpose, defineEmits, watch } from 'vue';
|
||||||
|
import { CaretDownOutlined, CaretUpOutlined } from '@ant-design/icons-vue';
|
||||||
|
import axios from 'axios';
|
||||||
|
// import { getLoadDroneCaseInfoDetail, getPolygonCenter } from '@/api/tiankongdi/index';
|
||||||
|
// import { homePageLoadCaseInfoTuBanList } from '@/api/demo/system';
|
||||||
|
// import { getLoadCaseInfoMineralsTuBanList } from '@/api/minerals/index';
|
||||||
|
import { WktToGeojson } from '@/components/MapboxMaps/src/WktGeojsonTransform';
|
||||||
|
import { transformGCJ2WGS } from '@/utils/EpsgTransform';
|
||||||
|
import { getPageList, getPolygonCenter } from '@/api/tiankongdi/index'
|
||||||
|
|
||||||
|
const emits = defineEmits(['toPosition', 'handlerFilter', 'flyToLocation']);
|
||||||
|
const props = defineProps(['layer', 'layerSettings']);
|
||||||
|
watch(
|
||||||
|
() => props.layerSettings,
|
||||||
|
() => {
|
||||||
|
subjectName.value = props.layerSettings.subjectname;
|
||||||
|
subjectTable.value = props.layerSettings.tablename;
|
||||||
|
Object.keys(props.layerSettings.legend[0]).forEach((item) => {
|
||||||
|
if (item != '默认') {
|
||||||
|
filters.value.push({ name: item });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const subjectName = ref();
|
||||||
|
const subjectTable = ref();
|
||||||
|
async function toPosition(item) {
|
||||||
|
if (item.location) {
|
||||||
|
let newCoord = transformGCJ2WGS(item.location[1], item.location[0]);
|
||||||
|
if (newCoord) {
|
||||||
|
emits('toPosition', [newCoord.lon, newCoord.lat]);
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let filter = '"Id"=\'' + item.id + "'";
|
||||||
|
let point = await getPolygonCenter({ tablename: 'view_shp_idle', filter: filter });
|
||||||
|
console.log('point',point)
|
||||||
|
if (point.length > 0) {
|
||||||
|
try {
|
||||||
|
let geojson = WktToGeojson(point[0].centroid_point);
|
||||||
|
emits('toPosition', geojson.coordinates);
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const searchResult = ref<any>([]);
|
||||||
|
|
||||||
|
const filters: any = ref([
|
||||||
|
{
|
||||||
|
name: '全部',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
const showSearchResult = ref(false);
|
||||||
|
const showFilterOptions = ref(false);
|
||||||
|
const address = ref()
|
||||||
|
|
||||||
|
onMounted(() => {});
|
||||||
|
|
||||||
|
function onInputFocus() {
|
||||||
|
showSearchResult.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onInputBlue() {
|
||||||
|
showSearchResult.value = false;
|
||||||
|
}
|
||||||
|
async function searchAddress(){
|
||||||
|
axios({
|
||||||
|
method: 'get',
|
||||||
|
url: `https://restapi.amap.com/v3/geocode/geo?key=ed310f0b1f6cfd93edfba42f1a09d4d9&address=`+address.value,
|
||||||
|
}).then((res) => {
|
||||||
|
if(res.data){
|
||||||
|
let location = res.data.geocodes[0].location.split(',')
|
||||||
|
emits('flyToLocation', location);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const keyword = ref('');
|
||||||
|
|
||||||
|
async function searchArea() {
|
||||||
|
if (keyword.value.match(/^[0-9A-Z]+(-[0-9A-Z]+)*$/)) {
|
||||||
|
searchResult.value = [];
|
||||||
|
const params = { page: 1, limit: 10, key: keyword.value};
|
||||||
|
const types = [1,2,3,5]
|
||||||
|
Promise.all(types.map(type => getPageList(params, type)))
|
||||||
|
.then(results => {
|
||||||
|
console.log('所有请求成功', results);
|
||||||
|
for(let index = 0; index < results.length; index ++){
|
||||||
|
let type = 0
|
||||||
|
switch(index){
|
||||||
|
case 0:
|
||||||
|
type = 1;
|
||||||
|
break
|
||||||
|
case 1:
|
||||||
|
type = 2;
|
||||||
|
break
|
||||||
|
case 2:
|
||||||
|
type = 3;
|
||||||
|
break
|
||||||
|
case 3:
|
||||||
|
type = 5;
|
||||||
|
break
|
||||||
|
}
|
||||||
|
results[index].items.forEach(item => {
|
||||||
|
searchResult.value.push({...item,type:type})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
console.log('searchResult',searchResult.value)
|
||||||
|
showSearchResult.value = true;
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('至少有一个请求失败', error);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// 地名搜索
|
||||||
|
axios
|
||||||
|
.get(
|
||||||
|
'https://restapi.amap.com/v5/place/text?&key=ee7f561fae9249aeb971bcc661083438&keywords=' +
|
||||||
|
keyword.value +
|
||||||
|
'®ion=371300&citylimit=true&page_num=1&page_size=10',
|
||||||
|
)
|
||||||
|
.then((res) => {
|
||||||
|
if (res.data.info == 'OK') {
|
||||||
|
searchResult.value = [];
|
||||||
|
res.data?.pois?.forEach((item, index) => {
|
||||||
|
let obj = {
|
||||||
|
id: item.name,
|
||||||
|
county: item.cityname,
|
||||||
|
street: item.adname,
|
||||||
|
location: item.location?.split(','),
|
||||||
|
};
|
||||||
|
searchResult.value.push(obj);
|
||||||
|
});
|
||||||
|
showSearchResult.value = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => keyword.value,
|
||||||
|
(newVal) => {
|
||||||
|
if (!newVal) {
|
||||||
|
showSearchResult.value = false;
|
||||||
|
searchResult.value = [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const getTypeName = (type) => {
|
||||||
|
switch(type){
|
||||||
|
case 3:
|
||||||
|
return '土地资源'
|
||||||
|
case 2:
|
||||||
|
return '房屋'
|
||||||
|
case 1:
|
||||||
|
return '农业生产设施'
|
||||||
|
case 5:
|
||||||
|
return '水域'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 抛出函数
|
||||||
|
defineExpose({});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style type="less" scoped>
|
||||||
|
.addressbox{
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
background-image: url('/statistical/search-bg.png');
|
||||||
|
background-size: 100% 100%;
|
||||||
|
border-top-right-radius: 8px;
|
||||||
|
position: relative;
|
||||||
|
.search-input {
|
||||||
|
flex: auto;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.search-button {
|
||||||
|
width: 62px;
|
||||||
|
height: 36px;
|
||||||
|
border-top-right-radius: 8px;
|
||||||
|
background: #0a62c6;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 36px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
background-image: url('/statistical/search-bg.png');
|
||||||
|
background-size: 100% 100%;
|
||||||
|
border-top-right-radius: 8px;
|
||||||
|
position: relative;
|
||||||
|
.search-input {
|
||||||
|
flex: auto;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.search-button {
|
||||||
|
width: 62px;
|
||||||
|
height: 36px;
|
||||||
|
border-top-right-radius: 8px;
|
||||||
|
background: #0a62c6;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 36px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.search-result-container {
|
||||||
|
width: 100%;
|
||||||
|
position: absolute;
|
||||||
|
top: 36px;
|
||||||
|
left: 0px;
|
||||||
|
background: rgba(11, 39, 68, 0.8);
|
||||||
|
border: 1px solid #0a62c6;
|
||||||
|
border-top: 0px;
|
||||||
|
padding: 8px 0px;
|
||||||
|
.result-item {
|
||||||
|
width: 100%;
|
||||||
|
height: 38px;
|
||||||
|
color: #e1ecf8;
|
||||||
|
display: flex;
|
||||||
|
line-height: 38px;
|
||||||
|
padding: 0px 12px;
|
||||||
|
font-size: 14px;
|
||||||
|
.search-icon {
|
||||||
|
width: 28px;
|
||||||
|
height: 36px;
|
||||||
|
}
|
||||||
|
.level-0 {
|
||||||
|
max-width: 160px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.level-1 {
|
||||||
|
margin: 0px 6px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.level-2 {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
background: #0f3863;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-container {
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
right: -120px;
|
||||||
|
width: 100px;
|
||||||
|
border-radius: 6px;
|
||||||
|
height: 36px;
|
||||||
|
background: #0a62c6;
|
||||||
|
line-height: 36px;
|
||||||
|
color: #fff;
|
||||||
|
display: flex;
|
||||||
|
cursor: pointer;
|
||||||
|
.filter-name {
|
||||||
|
width: 70px;
|
||||||
|
text-align: center;
|
||||||
|
padding: 0px 2px;
|
||||||
|
font-size: 14px;
|
||||||
|
position: relative;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
width: 2px;
|
||||||
|
height: 22px;
|
||||||
|
position: absolute;
|
||||||
|
top: 7px;
|
||||||
|
right: 0px;
|
||||||
|
background: #0751a5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.filter-icon {
|
||||||
|
width: 30px;
|
||||||
|
line-height: 38px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.filter-item-container {
|
||||||
|
width: 100%;
|
||||||
|
position: absolute;
|
||||||
|
background: rgba(11, 39, 68, 0.8);
|
||||||
|
border: 1px solid #0a62c6;
|
||||||
|
top: 36px;
|
||||||
|
left: 0px;
|
||||||
|
.filter-item {
|
||||||
|
height: 36px;
|
||||||
|
text-align: center;
|
||||||
|
&:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
background: #0f3863;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .mapboxgl-ctrl-logo {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .ant-input {
|
||||||
|
background: none;
|
||||||
|
border: 0px;
|
||||||
|
color: #5e90e1;
|
||||||
|
line-height: 30px;
|
||||||
|
text-indent: 8px;
|
||||||
|
outline: none;
|
||||||
|
&::placeholder {
|
||||||
|
color: #5e90e1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .ant-input-affix-wrapper {
|
||||||
|
background: none;
|
||||||
|
border: 0px;
|
||||||
|
color: #5e90e1;
|
||||||
|
line-height: 30px;
|
||||||
|
text-indent: 8px;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .anticon svg {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .ant-input::placeholder {
|
||||||
|
color: #5e90e1;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .ant-empty-description {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
export const MAPBOX_TOKEN = "pk.eyJ1IjoibGllYmFvIiwiYSI6ImNsMXg1OHdtcTE3eDEza3FmODBmeXhldmIifQ.CYYMuikQnGHMtTNq60B_xA";
|
||||||
|
|
||||||
|
export const TINADITU_TOKEN = "b6585bc41ee16251dbe6b1af64f375d9";
|
||||||
|
|
||||||
|
export const MAP_VIEWER = {
|
||||||
|
"兰山区":{
|
||||||
|
center:{lng: 118.35182370979693, lat: 35.183090621691385},
|
||||||
|
zoom:10.048587811931847
|
||||||
|
},
|
||||||
|
"河东区":{
|
||||||
|
center:{lng: 118.59697279346507, lat: 35.18490235060048},
|
||||||
|
zoom:10,
|
||||||
|
},
|
||||||
|
"罗庄区":{
|
||||||
|
center:{lng: 118.32214269732968, lat: 34.88793861991461},
|
||||||
|
zoom:10.348587811931848,
|
||||||
|
},
|
||||||
|
"高新区":{
|
||||||
|
center:{lng: 118.22321338283429, lat: 35.02848900013085},
|
||||||
|
zoom:11.197175623863698,
|
||||||
|
},
|
||||||
|
"沂河新区":{
|
||||||
|
center:{lng: 118.56406202558459, lat: 35.02402208121399},
|
||||||
|
zoom:9.848587811931848,
|
||||||
|
},
|
||||||
|
"费县":{
|
||||||
|
center:{lng: 118.07423584053117, lat: 35.25200708547465},
|
||||||
|
zoom:9.700000000000005,
|
||||||
|
},
|
||||||
|
"平邑县":{
|
||||||
|
center:{lng: 117.7943998613617, lat: 35.397797381650626},
|
||||||
|
zoom:9.5,
|
||||||
|
},
|
||||||
|
"蒙阴县":{
|
||||||
|
center:{lng: 118.16071230795704, lat: 35.706258658571166},
|
||||||
|
zoom:9.500000000000002,
|
||||||
|
},
|
||||||
|
"沂水县":{
|
||||||
|
center:{lng: 118.7262955596875, lat: 35.875369642007094},
|
||||||
|
zoom:9.500000000000002,
|
||||||
|
},
|
||||||
|
"沂南县":{
|
||||||
|
center:{lng: 118.45908849919756, lat: 35.49273684421736},
|
||||||
|
zoom:9.748587811931854,
|
||||||
|
},
|
||||||
|
"兰陵县":{
|
||||||
|
center:{lng: 118.10841982910361, lat: 34.81986176408728},
|
||||||
|
zoom:9.597175623863698,
|
||||||
|
},
|
||||||
|
"郯城县":{
|
||||||
|
center:{lng: 118.32120708234048, lat: 34.635986538650336},
|
||||||
|
zoom:9.7,
|
||||||
|
},
|
||||||
|
"临沭县":{
|
||||||
|
center:{lng: 118.74187031029359, lat: 34.850952753798644},
|
||||||
|
zoom:9.848587811931848,
|
||||||
|
},
|
||||||
|
"莒南县":{
|
||||||
|
center:{lng: 118.96807389575793, lat: 35.186365164136504},
|
||||||
|
zoom:9.848587811931848,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,498 @@
|
||||||
|
<template>
|
||||||
|
<div :id="mapContainerName" class="map-container">
|
||||||
|
<div class="search-container-box">
|
||||||
|
<SearchComponent
|
||||||
|
@flyToLocation="flyToLocation"
|
||||||
|
@toPosition="toPosition"
|
||||||
|
@handlerFilter="handlerFilter"
|
||||||
|
:layerSettings="layerSettings"
|
||||||
|
></SearchComponent>
|
||||||
|
</div>
|
||||||
|
<div class="home-button" @click="handlerInitialize"></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, onMounted, defineExpose, defineEmits, defineProps, watch } from 'vue';
|
||||||
|
import { generateUUID } from '@/components/MapboxMaps/src/tool';
|
||||||
|
import { WktToGeojson } from '@/components/MapboxMaps/src/WktGeojsonTransform';
|
||||||
|
import mapboxgl, { Map, Popup } from 'mapbox-gl';
|
||||||
|
import { MAPBOX_TOKEN, TINADITU_TOKEN, MAP_VIEWER } from './config.js';
|
||||||
|
import axios from 'axios';
|
||||||
|
import SearchComponent from './SearchComponent.vue';
|
||||||
|
import { getAppEnvConfig } from '@/utils/env';
|
||||||
|
const { VITE_GLOB_API_URL,VITE_GLOB_LAN_API_URL } = getAppEnvConfig();
|
||||||
|
const VITE_GLOB_API_URL_VAR = ref<String>(VITE_GLOB_API_URL);
|
||||||
|
const mapContainerName = ref<String>();
|
||||||
|
mapContainerName.value = 'mapContainer-' + generateUUID();
|
||||||
|
const { VITE_GLOB_YINGXIANG_SERVER, VITE_GLOB_YAOGANYINGXIANG_SERVER } = getAppEnvConfig();
|
||||||
|
import { getUserOrgs } from '@/api/tiankongdi';
|
||||||
|
|
||||||
|
const networkType = ref("WAN");
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
import { TableOutlined, GlobalOutlined, HomeOutlined } from '@ant-design/icons-vue';
|
||||||
|
|
||||||
|
// 图层控制 历史影像
|
||||||
|
import { message, Modal } from 'ant-design-vue';
|
||||||
|
import U from 'mapbox-gl-utils';
|
||||||
|
import { MP } from './src/MP.js';
|
||||||
|
import { GeojsonToWkt } from './src/WktGeojsonTransform.js';
|
||||||
|
import { layers } from '@/views/sys/exception/util'
|
||||||
|
|
||||||
|
const emits = defineEmits([
|
||||||
|
'onload',
|
||||||
|
'handlerGetDetails',
|
||||||
|
'showMonitor',
|
||||||
|
'handlerQueryIntersectTif',
|
||||||
|
'changeLoading'
|
||||||
|
]);
|
||||||
|
|
||||||
|
let isZoomVisible: any = false;
|
||||||
|
let map: Map;
|
||||||
|
let mp: any = null;
|
||||||
|
const props = defineProps({
|
||||||
|
layer: Object,
|
||||||
|
defaultColor: String,
|
||||||
|
});
|
||||||
|
const layerSettings = ref<any>({});
|
||||||
|
const layerDefaultColor = ref<String>();
|
||||||
|
watch(
|
||||||
|
() => props.layer,
|
||||||
|
(val) => {
|
||||||
|
layerSettings.value = val;
|
||||||
|
layerDefaultColor.value = props.defaultColor;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const initMap = () => {
|
||||||
|
return new mapboxgl.Map({
|
||||||
|
container: mapContainerName.value,
|
||||||
|
language: 'zh-cmn',
|
||||||
|
projection: 'globe', // wgs84参考系
|
||||||
|
style: {
|
||||||
|
glyphs: 'mapbox://fonts/mapbox/{fontstack}/{range}.pbf',
|
||||||
|
version: 8,
|
||||||
|
sources: {
|
||||||
|
'raster-tiles': {
|
||||||
|
type: 'raster',
|
||||||
|
tiles: [
|
||||||
|
`http://t0.tianditu.gov.cn/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=${TINADITU_TOKEN}`,
|
||||||
|
],
|
||||||
|
tileSize: 256,
|
||||||
|
minzoom: 1,
|
||||||
|
maxzoom: 17,
|
||||||
|
},
|
||||||
|
'raster-tiles-font': {
|
||||||
|
type: 'raster',
|
||||||
|
tiles: [
|
||||||
|
`https://t0.tianditu.gov.cn/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=${TINADITU_TOKEN}`,
|
||||||
|
],
|
||||||
|
tileSize: 256,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
layers: [
|
||||||
|
{
|
||||||
|
id: 'tdt-vec-tiles',
|
||||||
|
type: 'raster',
|
||||||
|
source: 'raster-tiles-font',
|
||||||
|
maxZoom: 32,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'tdt-img-tiles',
|
||||||
|
type: 'raster',
|
||||||
|
source: 'raster-tiles',
|
||||||
|
maxZoom: 32,
|
||||||
|
}
|
||||||
|
// {
|
||||||
|
// id: 'tdt-wms-tiles',
|
||||||
|
// type: 'raster',
|
||||||
|
// source: 'raster-tiles-geo',
|
||||||
|
// },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
maxZoom: 22,
|
||||||
|
minZoom: 8,
|
||||||
|
zoom: 8,
|
||||||
|
pitch: 0,
|
||||||
|
center: [118.30207505530701, 35.30123435040745],
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function loadMapInfo(){
|
||||||
|
|
||||||
|
map = initMap();
|
||||||
|
|
||||||
|
map.on('load', () => {
|
||||||
|
//挂载mapbox-gl-utils
|
||||||
|
U.init(map);
|
||||||
|
mp = new MP(map);
|
||||||
|
// 设置2D地图
|
||||||
|
map.easeTo({ pitch: 0, bearing: 0, duration: 1000 });
|
||||||
|
map.dragRotate.disable(); // 禁用拖动旋转
|
||||||
|
map.pitchWithRotate = false; // 禁用旋转时俯仰变化
|
||||||
|
handlerDealStreet()
|
||||||
|
handlerDealCountry();
|
||||||
|
handlerCheckUserOrgs()
|
||||||
|
getMaskData()
|
||||||
|
const sources = map.getStyle().sources;
|
||||||
|
let loadedSources = 0;
|
||||||
|
Object.keys(sources).forEach(sourceId => {
|
||||||
|
map.on('sourcedata', (e) => {
|
||||||
|
if (e.sourceId === sourceId && e.isSourceLoaded) {
|
||||||
|
loadedSources++;
|
||||||
|
if (loadedSources === Object.keys(sources).length) {
|
||||||
|
console.log('所有图层关联的数据源已加载完成');
|
||||||
|
emits('changeLoading',false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
onMounted(() => {
|
||||||
|
mapboxgl.accessToken = MAPBOX_TOKEN;
|
||||||
|
|
||||||
|
// 获取网络环境后加载地图
|
||||||
|
|
||||||
|
loadMapInfo();
|
||||||
|
|
||||||
|
})
|
||||||
|
// 回到初始视角
|
||||||
|
const handlerInitialize = () => {
|
||||||
|
map.flyTo({
|
||||||
|
center: [118.30207505530701, 35.30123435040745], // 设置中心点坐标
|
||||||
|
zoom: 8, // 设置缩放等级
|
||||||
|
pitch: 0,
|
||||||
|
bearing: 0,
|
||||||
|
duration: 1000,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function toPosition(item) {
|
||||||
|
handlerLocation(item, 17.2);
|
||||||
|
}
|
||||||
|
function handlerFilter(item) {
|
||||||
|
}
|
||||||
|
async function handlerCheckUserOrgs() {
|
||||||
|
handlerLoadPolygon();
|
||||||
|
}
|
||||||
|
function getMaskData() {
|
||||||
|
map.addLayer({
|
||||||
|
id: "linyishizhezhao",
|
||||||
|
type: "raster",
|
||||||
|
source: {
|
||||||
|
type: "raster",
|
||||||
|
tiles: [
|
||||||
|
"http://175.27.168.120:8080/geoserver/gwc/service/wms?service=WMS&version=1.1.0&request=GetMap&layers=linyishi%3Alinyishizhezhao&styles=&bbox={bbox-epsg-3857}&width=256&height=256&srs=EPSG:3857&format=image/png&TRANSPARENT=TRUE",
|
||||||
|
],
|
||||||
|
tileSize: 256,
|
||||||
|
},
|
||||||
|
layout: {
|
||||||
|
visibility: "visible",
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const handlerGetDetails = (e) => {
|
||||||
|
emits('handlerGetDetails', e.features[0].properties, [e.lngLat.lng, e.lngLat.lat]);
|
||||||
|
}
|
||||||
|
const handlerNongjiGetDetails = (e) => {
|
||||||
|
emits('handlerGetDetails', e.features[0].properties, e.features[0].geometry.coordinates);
|
||||||
|
}
|
||||||
|
function handlerLoadPolygon(code = '', filter = '', type = '', level = '') {
|
||||||
|
let field_filter = '&field="SerialNumber","Type","Id",';
|
||||||
|
map.addSource('tianditu-label', {
|
||||||
|
type: 'raster',
|
||||||
|
tiles: [
|
||||||
|
`https://t0.tianditu.gov.cn/DataServer?T=cia_w&x={x}&y={y}&l={z}&tk=${TINADITU_TOKEN}`
|
||||||
|
],
|
||||||
|
tileSize: 256
|
||||||
|
});
|
||||||
|
map.addLayer({
|
||||||
|
id: 'tianditu-label-layer',
|
||||||
|
type: 'raster',
|
||||||
|
source: 'tianditu-label',
|
||||||
|
layout: {
|
||||||
|
visibility: 'none',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
map.loadImage('/homepage/nong.png', (error, image) => {
|
||||||
|
if (error) throw error;
|
||||||
|
if (!map.hasImage('nongji-marker')) {
|
||||||
|
map.addImage('nongji-marker', image);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
layers.forEach(layerItem => {
|
||||||
|
const sourceId = `${layerItem.id}Source`
|
||||||
|
map.addSource(sourceId, {
|
||||||
|
type: 'vector',
|
||||||
|
tiles: [
|
||||||
|
VITE_GLOB_API_URL_VAR.value +
|
||||||
|
'/api/IdleLand/QueryVectorTileByTable?z={z}&x={x}&y={y}&table=' +
|
||||||
|
layerItem.tableName +
|
||||||
|
field_filter
|
||||||
|
],
|
||||||
|
minzoom: 1,
|
||||||
|
maxzoom: 20,
|
||||||
|
});
|
||||||
|
if(layerItem.id == 'nongji'){
|
||||||
|
const layerId = `${layerItem.id}SourceLayer`
|
||||||
|
map.addLayer({
|
||||||
|
id: layerId,
|
||||||
|
type: 'symbol',
|
||||||
|
source: sourceId,
|
||||||
|
'source-layer': layerItem.tableName,
|
||||||
|
layout: {
|
||||||
|
'icon-image': 'nongji-marker',
|
||||||
|
'icon-size': 0.8,
|
||||||
|
'icon-allow-overlap': true,
|
||||||
|
'icon-anchor': 'bottom',
|
||||||
|
visibility: 'none'
|
||||||
|
},
|
||||||
|
});
|
||||||
|
map.on('click', layerId, handlerNongjiGetDetails);
|
||||||
|
}else{
|
||||||
|
const lineLayerId = `${layerItem.id}SourceLineLayer`
|
||||||
|
const fillLayerId = `${layerItem.id}SourceFillLayer`
|
||||||
|
map.addLayer({
|
||||||
|
id: lineLayerId,
|
||||||
|
type: 'line',
|
||||||
|
source: sourceId,
|
||||||
|
'source-layer': layerItem.tableName,
|
||||||
|
layout: {
|
||||||
|
'line-join': 'round',
|
||||||
|
'line-cap': 'round',
|
||||||
|
visibility: 'none',
|
||||||
|
},
|
||||||
|
paint: {
|
||||||
|
'line-color': layerItem.color,
|
||||||
|
'line-width': 5,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
map.addLayer({
|
||||||
|
id: fillLayerId,
|
||||||
|
type: 'fill',
|
||||||
|
source: sourceId,
|
||||||
|
'source-layer': layerItem.tableName,
|
||||||
|
layout: {
|
||||||
|
visibility: 'none',
|
||||||
|
},
|
||||||
|
paint: {
|
||||||
|
'fill-color': layerItem.color,
|
||||||
|
'fill-opacity': 0.5,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
map.on('click', fillLayerId, handlerGetDetails);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 获取乡镇数据
|
||||||
|
const handlerDealStreet = (countyName: String = '临沂市'): void => {
|
||||||
|
map.addSource("zhenjie", {
|
||||||
|
"type": "vector",
|
||||||
|
"scheme": "tms",
|
||||||
|
tiles: [
|
||||||
|
"http://175.27.168.120:8080/geoserver/gwc/service/tms/1.0.0/linyishi%3Azhenjie@EPSG%3A900913@pbf/{z}/{x}/{y}.pbf",
|
||||||
|
],
|
||||||
|
tileSize: 512
|
||||||
|
})
|
||||||
|
map.addLayer({
|
||||||
|
id: "zhenjie",
|
||||||
|
type: "line",
|
||||||
|
source: "zhenjie",
|
||||||
|
'source-layer': 'zhenjie',
|
||||||
|
layout: {
|
||||||
|
visibility: "visible",
|
||||||
|
},
|
||||||
|
paint: {
|
||||||
|
'line-color': '#42befb', // 设置线的颜色
|
||||||
|
'line-width': 1, // 设置线的宽度
|
||||||
|
},
|
||||||
|
minzoom: 10,
|
||||||
|
maxzoom: 24,
|
||||||
|
})
|
||||||
|
map.addSource("zhenjiepoint", {
|
||||||
|
"type": "vector",
|
||||||
|
"scheme": "tms",
|
||||||
|
tiles: [
|
||||||
|
"http://175.27.168.120:8080/geoserver/gwc/service/tms/1.0.0/linyishi%3Azhenjiepoint@EPSG%3A900913@pbf/{z}/{x}/{y}.pbf",
|
||||||
|
],
|
||||||
|
tileSize: 512,
|
||||||
|
})
|
||||||
|
map.addLayer({
|
||||||
|
id: "zhenjiepoint",
|
||||||
|
type: "symbol",
|
||||||
|
source: "zhenjiepoint",
|
||||||
|
'source-layer': 'zhenjiepoint',
|
||||||
|
layout: {
|
||||||
|
visibility: "visible",
|
||||||
|
"text-field": "{xzqmc}",
|
||||||
|
},
|
||||||
|
paint: {
|
||||||
|
'text-color': '#041B36',
|
||||||
|
'text-halo-color': '#fff',
|
||||||
|
'text-halo-width': 2,
|
||||||
|
},
|
||||||
|
minzoom: 10,
|
||||||
|
maxzoom: 24,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// 获取县区边界数据
|
||||||
|
const handlerDealCountry = (countyName: String = '临沂市'): void => {
|
||||||
|
map.addSource("wmsSource", {
|
||||||
|
"type": "vector",
|
||||||
|
"scheme": "tms",
|
||||||
|
tiles: [
|
||||||
|
"http://175.27.168.120:8080/geoserver/gwc/service/tms/1.0.0/linyishi%3Axianjie@EPSG%3A900913@pbf/{z}/{x}/{y}.pbf"
|
||||||
|
],
|
||||||
|
tileSize: 512
|
||||||
|
})
|
||||||
|
map.addLayer({
|
||||||
|
id: "xianjie",
|
||||||
|
type: "line",
|
||||||
|
source: "wmsSource",
|
||||||
|
'source-layer': 'xianjie',
|
||||||
|
layout: {
|
||||||
|
visibility: "visible",
|
||||||
|
},
|
||||||
|
paint: {
|
||||||
|
"line-color": "#6f7ff4",
|
||||||
|
"line-width": 4,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
map.addSource("xianjiepoint", {
|
||||||
|
"type": "vector",
|
||||||
|
"scheme": "tms",
|
||||||
|
tiles: [
|
||||||
|
"http://175.27.168.120:8080/geoserver/gwc/service/tms/1.0.0/linyishi%3Alinyishixianjie_point@EPSG%3A900913@pbf/{z}/{x}/{y}.pbf",
|
||||||
|
],
|
||||||
|
tileSize: 512,
|
||||||
|
})
|
||||||
|
map.addLayer({
|
||||||
|
id: "xianjiepoint",
|
||||||
|
type: "symbol",
|
||||||
|
source: "xianjiepoint",
|
||||||
|
'source-layer': 'linyishixianjie_point',
|
||||||
|
layout: {
|
||||||
|
visibility: "visible",
|
||||||
|
"text-field": "{xzqmc}",
|
||||||
|
"text-size": 18
|
||||||
|
},
|
||||||
|
paint: {
|
||||||
|
'text-color': '#041B36',
|
||||||
|
'text-halo-color': '#fff',
|
||||||
|
'text-halo-width': 2,
|
||||||
|
},
|
||||||
|
minzoom: 8,
|
||||||
|
maxzoom: 10,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// 地图定位
|
||||||
|
function handlerLocation(lngLat, zoom) {
|
||||||
|
map.flyTo({
|
||||||
|
center: lngLat,
|
||||||
|
zoom: zoom,
|
||||||
|
bearing: 0,
|
||||||
|
speed: 1, // 飞行速度
|
||||||
|
curve: 2, // 飞行曲线
|
||||||
|
essential: true,
|
||||||
|
easing(t) {
|
||||||
|
// 飞行动画函数
|
||||||
|
return t;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function flyToLocation(e){
|
||||||
|
map.flyTo({
|
||||||
|
center: e,
|
||||||
|
zoom: 12,
|
||||||
|
bearing: 0,
|
||||||
|
speed: 1, // 飞行速度
|
||||||
|
curve: 2, // 飞行曲线
|
||||||
|
essential: true,
|
||||||
|
easing(t) {
|
||||||
|
// 飞行动画函数
|
||||||
|
return t;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const handlerChangeLayer = (list) => {
|
||||||
|
const layerIds = layers.map(item => item.id);
|
||||||
|
layerIds.forEach(id => {
|
||||||
|
const visibility = list.includes(id) ? 'visible' : 'none';
|
||||||
|
if(id == 'nongji'){
|
||||||
|
const layerId = `${id}SourceLayer`
|
||||||
|
map.setLayoutProperty(layerId, 'visibility', visibility);
|
||||||
|
}else{
|
||||||
|
const lineLayerId = `${id}SourceLineLayer`
|
||||||
|
const fillLayerId = `${id}SourceFillLayer`
|
||||||
|
map.setLayoutProperty(lineLayerId, 'visibility', visibility);
|
||||||
|
map.setLayoutProperty(fillLayerId, 'visibility', visibility);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const changeTiandituLabelOpen = (type) => {
|
||||||
|
map.setLayoutProperty('tianditu-label-layer', 'visibility', type ? 'visible' : 'none');
|
||||||
|
}
|
||||||
|
// 抛出函数
|
||||||
|
defineExpose({
|
||||||
|
handlerChangeLayer,
|
||||||
|
changeTiandituLabelOpen
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style type="less" scoped>
|
||||||
|
.map-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.search-container-box {
|
||||||
|
position: absolute;
|
||||||
|
width: 330px;
|
||||||
|
height: 40px;
|
||||||
|
top: 72px;
|
||||||
|
left: 73px;
|
||||||
|
z-index: 9999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-type-switch-container {
|
||||||
|
width: 208px;
|
||||||
|
height: 40px;
|
||||||
|
position: absolute;
|
||||||
|
top: 72px;
|
||||||
|
right: 23px;
|
||||||
|
z-index: 9999;
|
||||||
|
font-size: 22px;
|
||||||
|
color: #fff;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 40px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.map-type-switch-container .switch-button {
|
||||||
|
line-height: 40px;
|
||||||
|
width: 150px;
|
||||||
|
height: 40px;
|
||||||
|
float: left;
|
||||||
|
background: url(/map/change-view-btn.png);
|
||||||
|
background-size: 100% 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-type-switch-container .switch-button span {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.home-button {
|
||||||
|
width:40px;
|
||||||
|
height:40px;
|
||||||
|
background: url(/map/home-btn.png);
|
||||||
|
background-size: 100% 100%;
|
||||||
|
float: right;
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
z-index: 10;
|
||||||
|
top: 72px;
|
||||||
|
right: 23px;
|
||||||
|
}
|
||||||
|
::v-deep .mapboxgl-ctrl-logo {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -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.eyJ1IjoiemhhbmcxMjM4ODk5OSIsImEiOiJja3N5Ync1cXcyMTR2Mm9xempmbGE4MnBtIn0.R-j78CRvbs6JZG-MDSoh8Q',
|
||||||
|
// 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 }
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,148 @@
|
||||||
|
<script lang="tsx">
|
||||||
|
import type { PropType } from 'vue';
|
||||||
|
import { Result, Button } from 'ant-design-vue';
|
||||||
|
import { defineComponent, ref, computed, unref } from 'vue';
|
||||||
|
import { ExceptionEnum } from '@/enums/exceptionEnum';
|
||||||
|
import notDataSvg from '@/assets/svg/no-data.svg';
|
||||||
|
import netWorkSvg from '@/assets/svg/net-error.svg';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
import { useDesign } from '@/hooks/web/useDesign';
|
||||||
|
import { useI18n } from '@/hooks/web/useI18n';
|
||||||
|
import { useGo, useRedo } from '@/hooks/web/usePage';
|
||||||
|
import { PageEnum } from '@/enums/pageEnum';
|
||||||
|
|
||||||
|
interface MapValue {
|
||||||
|
title: string;
|
||||||
|
subTitle: string;
|
||||||
|
btnText?: string;
|
||||||
|
icon?: string;
|
||||||
|
handler?: any;
|
||||||
|
status?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'ErrorPage',
|
||||||
|
props: {
|
||||||
|
// 状态码
|
||||||
|
status: {
|
||||||
|
type: Number as PropType<number>,
|
||||||
|
default: ExceptionEnum.PAGE_NOT_FOUND,
|
||||||
|
},
|
||||||
|
|
||||||
|
title: {
|
||||||
|
type: String as PropType<string>,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
|
||||||
|
subTitle: {
|
||||||
|
type: String as PropType<string>,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
|
||||||
|
full: {
|
||||||
|
type: Boolean as PropType<boolean>,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
setup(props) {
|
||||||
|
const statusMapRef = ref(new Map<string | number, MapValue>());
|
||||||
|
|
||||||
|
const { query } = useRoute();
|
||||||
|
const go = useGo();
|
||||||
|
const redo = useRedo();
|
||||||
|
const { t } = useI18n();
|
||||||
|
const { prefixCls } = useDesign('app-exception-page');
|
||||||
|
|
||||||
|
const getStatus = computed(() => {
|
||||||
|
const { status: routeStatus } = query;
|
||||||
|
const { status } = props;
|
||||||
|
return Number(routeStatus) || status;
|
||||||
|
});
|
||||||
|
|
||||||
|
const getMapValue = computed((): MapValue => {
|
||||||
|
return unref(statusMapRef).get(unref(getStatus)) as MapValue;
|
||||||
|
});
|
||||||
|
|
||||||
|
const backLoginI18n = t('sys.exception.backLogin');
|
||||||
|
const backHomeI18n = t('sys.exception.backHome');
|
||||||
|
|
||||||
|
unref(statusMapRef).set(ExceptionEnum.PAGE_NOT_ACCESS, {
|
||||||
|
title: '403',
|
||||||
|
status: `${ExceptionEnum.PAGE_NOT_ACCESS}`,
|
||||||
|
subTitle: t('sys.exception.subTitle403'),
|
||||||
|
btnText: props.full ? backLoginI18n : backHomeI18n,
|
||||||
|
handler: () => (props.full ? go(PageEnum.BASE_LOGIN) : go()),
|
||||||
|
});
|
||||||
|
|
||||||
|
unref(statusMapRef).set(ExceptionEnum.PAGE_NOT_FOUND, {
|
||||||
|
title: '404',
|
||||||
|
status: `${ExceptionEnum.PAGE_NOT_FOUND}`,
|
||||||
|
subTitle: t('sys.exception.subTitle404'),
|
||||||
|
btnText: props.full ? backLoginI18n : backHomeI18n,
|
||||||
|
handler: () => (props.full ? go(PageEnum.BASE_LOGIN) : go()),
|
||||||
|
});
|
||||||
|
|
||||||
|
unref(statusMapRef).set(ExceptionEnum.ERROR, {
|
||||||
|
title: '500',
|
||||||
|
status: `${ExceptionEnum.ERROR}`,
|
||||||
|
subTitle: t('sys.exception.subTitle500'),
|
||||||
|
btnText: backHomeI18n,
|
||||||
|
handler: () => go(),
|
||||||
|
});
|
||||||
|
|
||||||
|
unref(statusMapRef).set(ExceptionEnum.PAGE_NOT_DATA, {
|
||||||
|
title: t('sys.exception.noDataTitle'),
|
||||||
|
subTitle: '',
|
||||||
|
btnText: t('common.redo'),
|
||||||
|
handler: () => redo(),
|
||||||
|
icon: notDataSvg,
|
||||||
|
});
|
||||||
|
|
||||||
|
unref(statusMapRef).set(ExceptionEnum.NET_WORK_ERROR, {
|
||||||
|
title: t('sys.exception.networkErrorTitle'),
|
||||||
|
subTitle: t('sys.exception.networkErrorSubTitle'),
|
||||||
|
btnText: t('common.redo'),
|
||||||
|
handler: () => redo(),
|
||||||
|
icon: netWorkSvg,
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
const { title, subTitle, btnText, icon, handler, status } = unref(getMapValue) || {};
|
||||||
|
return (
|
||||||
|
<Result
|
||||||
|
class={prefixCls}
|
||||||
|
status={status as any}
|
||||||
|
title={props.title || title}
|
||||||
|
sub-title={props.subTitle || subTitle}
|
||||||
|
>
|
||||||
|
{{
|
||||||
|
extra: () =>
|
||||||
|
btnText && (
|
||||||
|
<Button type="primary" onClick={handler}>
|
||||||
|
{() => btnText}
|
||||||
|
</Button>
|
||||||
|
),
|
||||||
|
icon: () => (icon ? <img src={icon} /> : null),
|
||||||
|
}}
|
||||||
|
</Result>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style lang="less">
|
||||||
|
@prefix-cls: ~'@{namespace}-app-exception-page';
|
||||||
|
|
||||||
|
.@{prefix-cls} {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.ant-result-icon {
|
||||||
|
img {
|
||||||
|
max-width: 400px;
|
||||||
|
max-height: 300px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -1,4 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
|
<div class="component-container">
|
||||||
|
|
||||||
|
<!-- 分类过滤 -->
|
||||||
|
<div class="search-select">
|
||||||
|
临时用地
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 搜索框 -->
|
||||||
<div class="search-container">
|
<div class="search-container">
|
||||||
<div class="search-input">
|
<div class="search-input">
|
||||||
<a-input
|
<a-input
|
||||||
|
|
@ -22,6 +30,8 @@
|
||||||
</div>
|
</div>
|
||||||
<a-empty v-if="searchResult.length == 0" />
|
<a-empty v-if="searchResult.length == 0" />
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 图斑过滤 -->
|
||||||
<div class="filter-container">
|
<div class="filter-container">
|
||||||
<div class="filter-name">{{ currentFilter }}</div>
|
<div class="filter-name">{{ currentFilter }}</div>
|
||||||
<div class="filter-icon" @click="handlerChangeFilterOptions">
|
<div class="filter-icon" @click="handlerChangeFilterOptions">
|
||||||
|
|
@ -38,6 +48,8 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, onMounted, defineExpose, defineEmits, watch } from 'vue';
|
import { ref, onMounted, defineExpose, defineEmits, watch } from 'vue';
|
||||||
|
|
@ -217,6 +229,74 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style type="less" scoped>
|
<style type="less" scoped>
|
||||||
|
|
||||||
|
.component-container{
|
||||||
|
width:100%;
|
||||||
|
height:100%;
|
||||||
|
display: flex;
|
||||||
|
column-gap: 12px;
|
||||||
|
.search-select{
|
||||||
|
width:320px;
|
||||||
|
line-height:36px;
|
||||||
|
font-weight: bold;
|
||||||
|
height:100%;
|
||||||
|
background-image: url('/statistical/search-bg.png');
|
||||||
|
background-size: 100% 100%;
|
||||||
|
text-align: center;
|
||||||
|
color:#fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-container {
|
||||||
|
width: 100px;
|
||||||
|
border-radius: 6px;
|
||||||
|
height: 36px;
|
||||||
|
background: #0a62c6;
|
||||||
|
line-height: 36px;
|
||||||
|
color: #fff;
|
||||||
|
display: flex;
|
||||||
|
cursor: pointer;
|
||||||
|
.filter-name {
|
||||||
|
width: 70px;
|
||||||
|
text-align: center;
|
||||||
|
padding: 0px 2px;
|
||||||
|
font-size: 14px;
|
||||||
|
position: relative;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
width: 2px;
|
||||||
|
height: 22px;
|
||||||
|
position: absolute;
|
||||||
|
top: 7px;
|
||||||
|
right: 0px;
|
||||||
|
background: #0751a5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.filter-icon {
|
||||||
|
width: 30px;
|
||||||
|
line-height: 38px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.filter-item-container {
|
||||||
|
width: 100%;
|
||||||
|
position: absolute;
|
||||||
|
background: rgba(11, 39, 68, 0.8);
|
||||||
|
border: 1px solid #0a62c6;
|
||||||
|
top: 36px;
|
||||||
|
left: 0px;
|
||||||
|
.filter-item {
|
||||||
|
height: 36px;
|
||||||
|
text-align: center;
|
||||||
|
&:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
background: #0f3863;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
.search-container {
|
.search-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
@ -225,8 +305,10 @@
|
||||||
background-size: 100% 100%;
|
background-size: 100% 100%;
|
||||||
border-top-right-radius: 8px;
|
border-top-right-radius: 8px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
column-gap: 15px;
|
||||||
|
|
||||||
.search-input {
|
.search-input {
|
||||||
flex: auto;
|
flex:auto;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
.search-button {
|
.search-button {
|
||||||
|
|
@ -283,59 +365,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.filter-container {
|
|
||||||
position: absolute;
|
|
||||||
top: 0px;
|
|
||||||
right: -120px;
|
|
||||||
width: 100px;
|
|
||||||
border-radius: 6px;
|
|
||||||
height: 36px;
|
|
||||||
background: #0a62c6;
|
|
||||||
line-height: 36px;
|
|
||||||
color: #fff;
|
|
||||||
display: flex;
|
|
||||||
cursor: pointer;
|
|
||||||
.filter-name {
|
|
||||||
width: 70px;
|
|
||||||
text-align: center;
|
|
||||||
padding: 0px 2px;
|
|
||||||
font-size: 14px;
|
|
||||||
position: relative;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
&::after {
|
|
||||||
content: '';
|
|
||||||
width: 2px;
|
|
||||||
height: 22px;
|
|
||||||
position: absolute;
|
|
||||||
top: 7px;
|
|
||||||
right: 0px;
|
|
||||||
background: #0751a5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.filter-icon {
|
|
||||||
width: 30px;
|
|
||||||
line-height: 38px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
.filter-item-container {
|
|
||||||
width: 100%;
|
|
||||||
position: absolute;
|
|
||||||
background: rgba(11, 39, 68, 0.8);
|
|
||||||
border: 1px solid #0a62c6;
|
|
||||||
top: 36px;
|
|
||||||
left: 0px;
|
|
||||||
.filter-item {
|
|
||||||
height: 36px;
|
|
||||||
text-align: center;
|
|
||||||
&:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
background: #0f3863;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
::v-deep .mapboxgl-ctrl-logo {
|
::v-deep .mapboxgl-ctrl-logo {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
import { ref, onBeforeUnmount } from 'vue';
|
||||||
|
|
||||||
|
export default function useDrag() {
|
||||||
|
const isDragging = ref(false); // 是否正在拖动
|
||||||
|
const offsetX = ref(0); // 鼠标按下时的 X 坐标偏移
|
||||||
|
const offsetY = ref(0); // 鼠标按下时的 Y 坐标偏移
|
||||||
|
const style = ref({
|
||||||
|
position: 'absolute', // 设置为绝对定位
|
||||||
|
top: '200px', // 初始位置
|
||||||
|
left: '70px', // 初始位置
|
||||||
|
});
|
||||||
|
|
||||||
|
// 鼠标按下时,记录偏移量并开始拖动
|
||||||
|
const startDrag = (event: MouseEvent) => {
|
||||||
|
isDragging.value = true;
|
||||||
|
offsetX.value = event.clientX - (event.target as HTMLElement).getBoundingClientRect().left;
|
||||||
|
offsetY.value = event.clientY - (event.target as HTMLElement).getBoundingClientRect().top;
|
||||||
|
|
||||||
|
// 添加鼠标移动和鼠标松开事件监听
|
||||||
|
document.addEventListener('mousemove', onDrag);
|
||||||
|
document.addEventListener('mouseup', stopDrag);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 鼠标移动时,更新元素的位置
|
||||||
|
const onDrag = (event: MouseEvent) => {
|
||||||
|
if (isDragging.value) {
|
||||||
|
|
||||||
|
if(event.clientX - offsetX.value + 280 > window.innerWidth){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if(event.clientY - offsetY.value + 20 > window.innerHeight){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
style.value.left = (event.clientX - offsetX.value - 200) > 0 ? `${event.clientX - offsetX.value - 200}px` : '0px'
|
||||||
|
style.value.top = (event.clientY - offsetY.value - 100) > 0 ? `${event.clientY - offsetY.value - 100}px` : '0px';
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 鼠标松开时,停止拖动
|
||||||
|
const stopDrag = () => {
|
||||||
|
isDragging.value = false;
|
||||||
|
document.removeEventListener('mousemove', onDrag);
|
||||||
|
document.removeEventListener('mouseup', stopDrag);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 在组件卸载时移除事件监听
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
document.removeEventListener('mousemove', onDrag);
|
||||||
|
document.removeEventListener('mouseup', stopDrag);
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
style,
|
||||||
|
startDrag,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
export { default as Exception } from './Exception.vue';
|
||||||
|
|
@ -69,7 +69,9 @@
|
||||||
defaultColor: String,
|
defaultColor: String,
|
||||||
});
|
});
|
||||||
const layerSettings = ref<any>({});
|
const layerSettings = ref<any>({});
|
||||||
|
|
||||||
const layerDefaultColor = ref<String>();
|
const layerDefaultColor = ref<String>();
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.layer,
|
() => props.layer,
|
||||||
(val) => {
|
(val) => {
|
||||||
|
|
@ -126,9 +128,9 @@
|
||||||
},
|
},
|
||||||
maxZoom: 22,
|
maxZoom: 22,
|
||||||
minZoom: 8,
|
minZoom: 8,
|
||||||
zoom: 8,
|
zoom: 9.6,
|
||||||
pitch: 0,
|
pitch: 0,
|
||||||
center: [118.30207505530701, 35.30123435040745],
|
center: [117.97256,34.85481],
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -240,6 +242,7 @@
|
||||||
let isLevel = orgs.find((item, index) => {
|
let isLevel = orgs.find((item, index) => {
|
||||||
return item.name == '临沂市' || item.parentId == 0 || item.parentName == '根节点';
|
return item.name == '临沂市' || item.parentId == 0 || item.parentName == '根节点';
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isLevel) {
|
if (isLevel) {
|
||||||
isRootLevel.value = true;
|
isRootLevel.value = true;
|
||||||
handlerLoadPolygon('', '', '', '1');
|
handlerLoadPolygon('', '', '', '1');
|
||||||
|
|
@ -554,7 +557,7 @@
|
||||||
"type": "vector",
|
"type": "vector",
|
||||||
"scheme": "tms",
|
"scheme": "tms",
|
||||||
tiles: [
|
tiles: [
|
||||||
"http://175.27.168.120:8080/geoserver/gwc/service/tms/1.0.0/linyishi%3Axianjie@EPSG%3A900913@pbf/{z}/{x}/{y}.pbf"
|
"http://175.27.168.120:8080/geoserver/gwc/service/tms/1.0.0/lanling%3Axianjie@EPSG%3A900913@pbf/{z}/{x}/{y}.pbf"
|
||||||
],
|
],
|
||||||
tileSize: 512
|
tileSize: 512
|
||||||
})
|
})
|
||||||
|
|
@ -585,7 +588,7 @@
|
||||||
source: "xianjiepoint",
|
source: "xianjiepoint",
|
||||||
'source-layer': 'linyishixianjie_point',
|
'source-layer': 'linyishixianjie_point',
|
||||||
layout: {
|
layout: {
|
||||||
visibility: "visible",
|
visibility: "none",
|
||||||
"text-field": "{xzqmc}",
|
"text-field": "{xzqmc}",
|
||||||
"text-size": 18
|
"text-size": 18
|
||||||
},
|
},
|
||||||
|
|
@ -669,7 +672,7 @@
|
||||||
source: {
|
source: {
|
||||||
type: "raster",
|
type: "raster",
|
||||||
tiles: [
|
tiles: [
|
||||||
"http://175.27.168.120:8080/geoserver/gwc/service/wms?service=WMS&version=1.1.0&request=GetMap&layers=linyishi%3Alinyishizhezhao&styles=&bbox={bbox-epsg-3857}&width=256&height=256&srs=EPSG:3857&format=image/png&TRANSPARENT=TRUE",
|
"http://175.27.168.120:8080/geoserver/gwc/service/wms?service=WMS&version=1.1.0&request=GetMap&layers=lanling%3Alanlingxian_zhezhao&styles=&bbox={bbox-epsg-3857}&width=256&height=256&srs=EPSG:3857&format=image/png&TRANSPARENT=TRUE",
|
||||||
],
|
],
|
||||||
tileSize: 256,
|
tileSize: 256,
|
||||||
},
|
},
|
||||||
|
|
@ -720,7 +723,7 @@
|
||||||
"type": "vector",
|
"type": "vector",
|
||||||
"scheme": "tms",
|
"scheme": "tms",
|
||||||
tiles: [
|
tiles: [
|
||||||
"http://175.27.168.120:8080/geoserver/gwc/service/tms/1.0.0/linyishi%3Azhenjie@EPSG%3A900913@pbf/{z}/{x}/{y}.pbf",
|
"http://175.27.168.120:8080/geoserver/gwc/service/tms/1.0.0/lanling%3Azhenjie@EPSG%3A900913@pbf/{z}/{x}/{y}.pbf",
|
||||||
],
|
],
|
||||||
tileSize: 512
|
tileSize: 512
|
||||||
})
|
})
|
||||||
|
|
@ -743,7 +746,7 @@
|
||||||
"type": "vector",
|
"type": "vector",
|
||||||
"scheme": "tms",
|
"scheme": "tms",
|
||||||
tiles: [
|
tiles: [
|
||||||
"http://175.27.168.120:8080/geoserver/gwc/service/tms/1.0.0/linyishi%3Azhenjiepoint@EPSG%3A900913@pbf/{z}/{x}/{y}.pbf",
|
"http://175.27.168.120:8080/geoserver/gwc/service/tms/1.0.0/lanling%3Alanlignxian_zhenjie_point@EPSG%3A900913@pbf/{z}/{x}/{y}.pbf",
|
||||||
],
|
],
|
||||||
tileSize: 512,
|
tileSize: 512,
|
||||||
})
|
})
|
||||||
|
|
@ -751,7 +754,7 @@
|
||||||
id: "zhenjiepoint",
|
id: "zhenjiepoint",
|
||||||
type: "symbol",
|
type: "symbol",
|
||||||
source: "zhenjiepoint",
|
source: "zhenjiepoint",
|
||||||
'source-layer': 'zhenjiepoint',
|
'source-layer': 'lanlignxian_zhenjie_point',
|
||||||
layout: {
|
layout: {
|
||||||
visibility: "visible",
|
visibility: "visible",
|
||||||
"text-field": "{xzqmc}",
|
"text-field": "{xzqmc}",
|
||||||
|
|
@ -868,8 +871,8 @@
|
||||||
// 回到初始视角
|
// 回到初始视角
|
||||||
const handlerInitialize = () => {
|
const handlerInitialize = () => {
|
||||||
map.flyTo({
|
map.flyTo({
|
||||||
center: [118.30207505530701, 35.30123435040745], // 设置中心点坐标
|
center: [117.97256,34.85481], // 设置中心点坐标
|
||||||
zoom: 8, // 设置缩放等级
|
zoom: 9.5, // 设置缩放等级
|
||||||
pitch: 0,
|
pitch: 0,
|
||||||
bearing: 0,
|
bearing: 0,
|
||||||
duration: 1000,
|
duration: 1000,
|
||||||
|
|
@ -1030,6 +1033,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (item.id == 'Data') {
|
} else if (item.id == 'Data') {
|
||||||
|
|
||||||
if (map.getLayer('historyLayerLine')) {
|
if (map.getLayer('historyLayerLine')) {
|
||||||
if (item.checked) {
|
if (item.checked) {
|
||||||
map.setLayoutProperty('historyLayerLine', 'visibility', 'visible');
|
map.setLayoutProperty('historyLayerLine', 'visibility', 'visible');
|
||||||
|
|
@ -1155,7 +1159,7 @@
|
||||||
}
|
}
|
||||||
.search-container-box {
|
.search-container-box {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 330px;
|
width: 600px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
top: 72px;
|
top: 72px;
|
||||||
left: 73px;
|
left: 73px;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,163 @@
|
||||||
|
<template>
|
||||||
|
<div :class="`layer-list-container ${openLayer? '': 'layer-list-container-close'}`" >
|
||||||
|
<div class="title">
|
||||||
|
图层资源
|
||||||
|
<div class="hidden-button" @click="openLayer = !openLayer">
|
||||||
|
<img v-if="openLayer" src="/public/map/top.png" alt="">
|
||||||
|
<img v-else src="/public/map/bottom.png" alt="">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layers-container">
|
||||||
|
<p class="cate-name">数据图层</p>
|
||||||
|
<div class="case-list">
|
||||||
|
<div class="case-item" v-for="(item,index) 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 class="case-item">
|
||||||
|
<img src="/statistical/prove-icon.png" alt="" />
|
||||||
|
<a-checkbox v-model:checked="tiandituLabelOpen" @change="labelChange" >
|
||||||
|
<span style="color:#fff;">地图注记</span>
|
||||||
|
</a-checkbox>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import {
|
||||||
|
defineEmits,
|
||||||
|
ref,
|
||||||
|
} from 'vue'
|
||||||
|
import { layers } from '@/views/sys/exception/util'
|
||||||
|
const emits = defineEmits(['changeLayer','changeLabel'])
|
||||||
|
const openLayer = ref(true)
|
||||||
|
const tiandituLabelOpen = ref(false)
|
||||||
|
const dataLayerList = ref(layers)
|
||||||
|
|
||||||
|
const layerChange = (item,type)=>{
|
||||||
|
let showLayer = dataLayerList.value.filter(itemLayer => itemLayer.checked).map(itemLayer => itemLayer.id)
|
||||||
|
emits("changeLayer",showLayer);
|
||||||
|
}
|
||||||
|
const labelChange = () => {
|
||||||
|
emits("changeLabel",tiandituLabelOpen.value);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style type="less" scoped>
|
||||||
|
.layer-list-container-close{
|
||||||
|
height: 41px !important;
|
||||||
|
}
|
||||||
|
.layer-list-container {
|
||||||
|
width: 285px;
|
||||||
|
height: 600px;
|
||||||
|
background: #041b36;
|
||||||
|
position: relative;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
transition: 0.5s;
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
height: 26px;
|
||||||
|
width: 26px;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0px;
|
||||||
|
left: 0px;
|
||||||
|
background: url('/map/layer-center-left.png');
|
||||||
|
background-size: 100% 100%;
|
||||||
|
}
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
height: 26px;
|
||||||
|
width: 26px;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0px;
|
||||||
|
right: 0px;
|
||||||
|
background: url('/map/layer-center-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;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.hidden-button{
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
right: 0px;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
.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;
|
||||||
|
height:40px;
|
||||||
|
overflow:hidden;
|
||||||
|
img {
|
||||||
|
width: 15px;
|
||||||
|
margin-right:12px;
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
color: #7ebbff;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
::v-deep .ant-empty-image{
|
||||||
|
height:50px;
|
||||||
|
position:relative;
|
||||||
|
}
|
||||||
|
::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;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .ant-checkbox-wrapper{
|
||||||
|
width: calc( 100% - 40px);
|
||||||
|
height: 20px;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
@ -0,0 +1,243 @@
|
||||||
|
<template>
|
||||||
|
<div class="county">
|
||||||
|
<div class="county_div">
|
||||||
|
<img class="county_div_leftButton" :src="scrollImgLeft" @click="scrollToElement('left')" />
|
||||||
|
|
||||||
|
<div ref="countyList" id="scrollContainer" class="county_div_list">
|
||||||
|
<div v-for="item in list" :key="item.id" :id="item.id" @click="clickCounty(item)">
|
||||||
|
<span v-if="!item.isClick" class="county_div_list_span_nochoose">{{ item.name }}</span>
|
||||||
|
<img
|
||||||
|
class="county_div_list_nochoose"
|
||||||
|
v-if="!item.isClick"
|
||||||
|
src="/statistical/left_county_nochoose.png"
|
||||||
|
/>
|
||||||
|
<span v-if="item.isClick" class="county_div_list_span_choose">{{ item.name }}</span>
|
||||||
|
<img
|
||||||
|
class="county_div_list_choose"
|
||||||
|
v-if="item.isClick"
|
||||||
|
src="/statistical/left_county_choose.png"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<img class="county_div_rightButton" :src="scrollImgRight" @click="scrollToElement('right')" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<img
|
||||||
|
src="/statistical/left_decorative_bottom.png"
|
||||||
|
:style="{
|
||||||
|
width: '840px',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, onMounted, onUnmounted, computed, defineEmits, watch, defineExpose } from 'vue';
|
||||||
|
import { getChildrenTree } from '@/api/demo/system';
|
||||||
|
import { message } from 'ant-design-vue';
|
||||||
|
import { getUserOrgs } from '@/api/tiankongdi';
|
||||||
|
|
||||||
|
// emit
|
||||||
|
const emit = defineEmits(['countyClick']);
|
||||||
|
const props = defineProps(['bi']);
|
||||||
|
|
||||||
|
// 按键控制滚动条
|
||||||
|
let countyWidth: number = 110;
|
||||||
|
const countyList = ref<HTMLElement | null>(null);
|
||||||
|
const scrollImgLeft = ref('/statistical/left_direction_left1.png');
|
||||||
|
const scrollImgRight = ref('/statistical/left_direction_right1.png');
|
||||||
|
|
||||||
|
const scrollToElement = async (type) => {
|
||||||
|
if (countyList.value) {
|
||||||
|
if (type == 'left') {
|
||||||
|
countyList.value.scrollLeft = countyList.value.scrollLeft - countyWidth;
|
||||||
|
}
|
||||||
|
if (type == 'right') {
|
||||||
|
countyList.value.scrollLeft = countyList.value.scrollLeft + countyWidth;
|
||||||
|
}
|
||||||
|
// if (countyList.value.scrollLeft < countyWidth) {
|
||||||
|
// scrollImgLeft.value = '/statistical/left_direction_left1.png';
|
||||||
|
// } else {
|
||||||
|
// scrollImgLeft.value = '/statistical/left_direction_left2.png';
|
||||||
|
// }
|
||||||
|
// if (countyList.value.scrollLeft > (list.value.length - 7 - 1) * countyWidth) {
|
||||||
|
// scrollImgRight.value = '/statistical/left_direction_right1.png';
|
||||||
|
// } else {
|
||||||
|
// scrollImgRight.value = '/statistical/left_direction_right2.png';
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取用户可以访问的机构信息
|
||||||
|
async function handlerGetOrgs() {
|
||||||
|
let orgs = await getUserOrgs({});
|
||||||
|
let isLevel = orgs.find((item, index) => {
|
||||||
|
return item.name == '临沂市' || item.parentId == 0 || item.parentName == '根节点';
|
||||||
|
});
|
||||||
|
if (isLevel) {
|
||||||
|
// 市级
|
||||||
|
getOptions();
|
||||||
|
} else {
|
||||||
|
// 县区级
|
||||||
|
let levesl = orgs.filter((item, index) => {
|
||||||
|
return item.parentName == '临沂市' || item.parentId == 371300;
|
||||||
|
});
|
||||||
|
list.value = levesl;
|
||||||
|
}
|
||||||
|
// clickCounty(list.value[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
function selectCounty() {}
|
||||||
|
// 选择区县
|
||||||
|
function clickCounty(record) {
|
||||||
|
list.value.forEach((item) => {
|
||||||
|
if (item.cascadeId == record.cascadeId) {
|
||||||
|
item.isClick = true;
|
||||||
|
} else {
|
||||||
|
item.isClick = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
emit('countyClick', record);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始数据
|
||||||
|
const list = ref();
|
||||||
|
async function getOptions() {
|
||||||
|
const data = await getChildrenTree({
|
||||||
|
parentId: 371300,
|
||||||
|
});
|
||||||
|
data.forEach((item) => {
|
||||||
|
item.isClick = false;
|
||||||
|
});
|
||||||
|
list.value = data;
|
||||||
|
|
||||||
|
list.value.sort((a, b) => a.id - b.id);
|
||||||
|
|
||||||
|
let linyishi = {
|
||||||
|
id: '',
|
||||||
|
name: '临沂市',
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log('listValue', list.value);
|
||||||
|
list.value.unshift(linyishi);
|
||||||
|
clickCounty(linyishi);
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
handlerGetOrgs();
|
||||||
|
|
||||||
|
let scrollContainer = document.getElementById('scrollContainer');
|
||||||
|
|
||||||
|
scrollContainer?.addEventListener('wheel', (evt) => {
|
||||||
|
evt.preventDefault();
|
||||||
|
scrollContainer?.scrollBy({
|
||||||
|
left: evt.deltaY * 5,
|
||||||
|
behavior: 'smooth',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
selectCounty,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.county {
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&_div {
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
width: 840px;
|
||||||
|
bottom: 10px;
|
||||||
|
|
||||||
|
&_leftButton {
|
||||||
|
position: relative;
|
||||||
|
top: 42px;
|
||||||
|
left: -4px;
|
||||||
|
height: 31px;
|
||||||
|
width: 31px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&_list {
|
||||||
|
display: flex;
|
||||||
|
max-width: 770px;
|
||||||
|
margin: 0px auto;
|
||||||
|
overflow-x: auto;
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
div {
|
||||||
|
width: 110px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&_span_nochoose {
|
||||||
|
position: relative;
|
||||||
|
top: 30px;
|
||||||
|
width: 110px;
|
||||||
|
z-index: 999;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-family: Alibaba PuHuiTi;
|
||||||
|
font-size: 15px;
|
||||||
|
color: rgba(255, 255, 255, 0);
|
||||||
|
background: linear-gradient(0deg, #6f81d4 0.146484375%, #ffffff 86.7919921875%);
|
||||||
|
opacity: 0.6;
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
background-clip: text;
|
||||||
|
color: transparent;
|
||||||
|
color: #fff;
|
||||||
|
text-shadow:
|
||||||
|
-1px -1px 0 #000,
|
||||||
|
1px -1px 0 #000,
|
||||||
|
-1px 1px 0 #000,
|
||||||
|
1px 1px 0 #000;
|
||||||
|
font-weight: 10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
&_nochoose {
|
||||||
|
position: relative;
|
||||||
|
top: -7px;
|
||||||
|
width: 87px;
|
||||||
|
margin-left: 11.5px;
|
||||||
|
margin-right: 11.5px;
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
&_span_choose {
|
||||||
|
position: relative;
|
||||||
|
top: 30px;
|
||||||
|
width: 110px;
|
||||||
|
z-index: 999;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-family: Alibaba PuHuiTi;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #014ce2;
|
||||||
|
}
|
||||||
|
|
||||||
|
&_choose {
|
||||||
|
position: relative;
|
||||||
|
width: 110px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&_rightButton {
|
||||||
|
position: relative;
|
||||||
|
top: 42px;
|
||||||
|
left: 4px;
|
||||||
|
height: 31px;
|
||||||
|
width: 31px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
<template>
|
||||||
|
<div class="layerbutton">
|
||||||
|
<div
|
||||||
|
class="layerbutton_div"
|
||||||
|
:style="{
|
||||||
|
marginBottom: '15px',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
id="left_layerButton_1"
|
||||||
|
:src="button_1 ? '/statistical/layer-btn1-active.png' : '/statistical/layer-btn1.png'"
|
||||||
|
@click="handlerLayerChange(1)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="layerbutton_div">
|
||||||
|
<img
|
||||||
|
id="left_layerButton_2"
|
||||||
|
:src="button_2 ? '/statistical/layer-btn2-active.png' : '/statistical/layer-btn2.png'"
|
||||||
|
@click="handlerLayerChange(2)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="layerbutton_div">
|
||||||
|
<img
|
||||||
|
id="left_layerButton_2"
|
||||||
|
:src="button_3 ? '/statistical/layer-btn3-active.png' : '/statistical/layer-btn3.png'"
|
||||||
|
@click="handlerLayerChange(3)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, defineEmits, defineProps } from 'vue';
|
||||||
|
// emit
|
||||||
|
const emit = defineEmits(['handlerLayerChange']);
|
||||||
|
const button_1 = ref(false);
|
||||||
|
const button_2 = ref(true);
|
||||||
|
const button_3 = ref(false);
|
||||||
|
// 控制图层
|
||||||
|
function handlerLayerChange(type: number) {
|
||||||
|
switch (type) {
|
||||||
|
case 1:
|
||||||
|
button_1.value = true;
|
||||||
|
button_2.value = false;
|
||||||
|
button_3.value = false;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
button_1.value = false;
|
||||||
|
button_2.value = true;
|
||||||
|
button_3.value = false;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
button_1.value = false;
|
||||||
|
button_2.value = false;
|
||||||
|
button_3.value = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
emit('handlerLayerChange', type);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.layerbutton {
|
||||||
|
position: absolute;
|
||||||
|
top: 130px;
|
||||||
|
left: 60px;
|
||||||
|
.layerbutton_div {
|
||||||
|
margin-bottom: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
img {
|
||||||
|
width: 60px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
<template>
|
||||||
|
<div class="statistical">
|
||||||
|
<img src="/statistical/left_statistical.png" />
|
||||||
|
<div class="statistical_div">
|
||||||
|
<a-row>
|
||||||
|
<a-col :span="10" @click="handlerChangePolygonType('违法')">
|
||||||
|
<span class="statistical_div_dot" style="background: #F70303" />
|
||||||
|
<span class="statistical_div_span"> 违法 </span>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="10" @click="handlerChangePolygonType('补办手续')">
|
||||||
|
<span class="statistical_div_dot" style="background: #AD04F4" />
|
||||||
|
<span class="statistical_div_span"> 补办手续 </span>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
<a-row>
|
||||||
|
<a-col :span="10" @click="handlerChangePolygonType('合法')">
|
||||||
|
<span class="statistical_div_dot" style="background: #0AF703" />
|
||||||
|
<span class="statistical_div_span"> 合法 </span>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="10" @click="handlerChangePolygonType('拆除复耕')">
|
||||||
|
<span class="statistical_div_dot" style="background: #F4E004" />
|
||||||
|
<span class="statistical_div_span"> 拆除复耕 </span>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
<a-row>
|
||||||
|
<a-col :span="10" @click="handlerChangePolygonType('其他')">
|
||||||
|
<span class="statistical_div_dot" style="background: #0382F7" />
|
||||||
|
<span class="statistical_div_span"> 其他 </span>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { defineEmits, defineProps } from 'vue';
|
||||||
|
const emits = defineEmits(['handlerChangePolygonType']);
|
||||||
|
const props = defineProps(['bi']);
|
||||||
|
|
||||||
|
function handlerChangePolygonType(type: String): void {
|
||||||
|
emits('handlerChangePolygonType', type);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.statistical {
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
img {
|
||||||
|
position: relative;
|
||||||
|
height: 100px;
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&_div {
|
||||||
|
position: relative;
|
||||||
|
top: -75px;
|
||||||
|
left: 30px;
|
||||||
|
|
||||||
|
&_dot {
|
||||||
|
display: inline-block;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
position: relative;
|
||||||
|
left: -2px;
|
||||||
|
top: -2px;
|
||||||
|
margin-right: 5px;
|
||||||
|
margin-bottom: 17px;
|
||||||
|
// border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&_span {
|
||||||
|
position: relative;
|
||||||
|
top: -20px;
|
||||||
|
font-family: Microsoft YaHei;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #7ebbff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</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>
|
||||||
|
|
@ -0,0 +1,138 @@
|
||||||
|
<template>
|
||||||
|
<div class="county-container">
|
||||||
|
<div class="slider-container" @mousedown="startDrag" @mouseup="endDrag" @mousemove="onDrag"
|
||||||
|
@touchstart="startDrag" @touchend="endDrag" @touchmove="onDrag">
|
||||||
|
<div class="slider-content" :style="{ transform: `translateX(${translateX}px)` }">
|
||||||
|
<!-- 滑动内容项 -->
|
||||||
|
<div class="slider-item" v-for="(item, index) in list" :key="index" :style="{background:url('/statistical/left_county_nochoose.png')}">
|
||||||
|
<div calss="county-name">{{ item.name }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, onMounted, onUnmounted, computed, defineEmits, watch, defineExpose } from 'vue';
|
||||||
|
import { getChildrenTree } from '@/api/demo/system';
|
||||||
|
import { getUserOrgs } from '@/api/tiankongdi';
|
||||||
|
|
||||||
|
// emit
|
||||||
|
const emit = defineEmits(['countyClick']);
|
||||||
|
|
||||||
|
// 初始数据
|
||||||
|
const list = ref();
|
||||||
|
|
||||||
|
// 获取用户可以访问的机构信息
|
||||||
|
async function handlerGetOrgs() {
|
||||||
|
let orgs = await getUserOrgs({});
|
||||||
|
let isLevel = orgs.find((item, index) => {
|
||||||
|
return item.name == '临沂市' || item.parentId == 0 || item.parentName == '根节点';
|
||||||
|
});
|
||||||
|
if (isLevel) {
|
||||||
|
// 市级
|
||||||
|
getOptions();
|
||||||
|
} else {
|
||||||
|
// 县区级
|
||||||
|
let levesl = orgs.filter((item, index) => {
|
||||||
|
return item.parentName == '临沂市' || item.parentId == 371300;
|
||||||
|
});
|
||||||
|
list.value = levesl;
|
||||||
|
}
|
||||||
|
// clickCounty(list.value[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getOptions() {
|
||||||
|
const data = await getChildrenTree({
|
||||||
|
parentId: 371300,
|
||||||
|
});
|
||||||
|
data.forEach((item) => {
|
||||||
|
item.isClick = false;
|
||||||
|
});
|
||||||
|
list.value = data;
|
||||||
|
let linyishi = {
|
||||||
|
id: '',
|
||||||
|
name: '临沂市',
|
||||||
|
};
|
||||||
|
console.log("countyList",list.value);
|
||||||
|
list.value.unshift(linyishi);
|
||||||
|
clickCounty(linyishi);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
function selectCounty() {}
|
||||||
|
|
||||||
|
// 选择区县
|
||||||
|
function clickCounty(record) {
|
||||||
|
list.value.forEach((item) => {
|
||||||
|
if (item.cascadeId == record.cascadeId) {
|
||||||
|
item.isClick = true;
|
||||||
|
} else {
|
||||||
|
item.isClick = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
emit('countyClick', record);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
handlerGetOrgs();
|
||||||
|
});
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
selectCounty,
|
||||||
|
});
|
||||||
|
const isDragging = ref(false);
|
||||||
|
const startX = ref(0);
|
||||||
|
const translateX = ref(0);
|
||||||
|
const currentTranslateX = ref(0);
|
||||||
|
const items = ref(['Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5'])
|
||||||
|
function startDrag(event) {
|
||||||
|
isDragging.value = true;
|
||||||
|
startX.value = event.type.includes('mouse') ? event.clientX : event.touches[0].clientX;
|
||||||
|
currentTranslateX.value = translateX.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function endDrag() {
|
||||||
|
isDragging.value = false;
|
||||||
|
currentTranslateX.value = translateX.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onDrag(event) {
|
||||||
|
if (!isDragging.value) return;
|
||||||
|
const currentX = event.type.includes('mouse') ? event.clientX : event.touches[0].clientX;
|
||||||
|
const deltaX = currentX - startX.value;
|
||||||
|
translateX.value = currentTranslateX.value + deltaX;
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style type="less" scoped>
|
||||||
|
.county-container{
|
||||||
|
position:absolute;
|
||||||
|
bottom:50px;
|
||||||
|
left:300px;
|
||||||
|
z-index:999999;
|
||||||
|
width:840px;
|
||||||
|
height:80px;
|
||||||
|
background:rgba(0,0,0,0.4);
|
||||||
|
.slider-container {
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
cursor: grab;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider-content {
|
||||||
|
display: flex;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider-item {
|
||||||
|
min-width: 100px;
|
||||||
|
margin: 0px 0px;
|
||||||
|
background-color: #ddd;
|
||||||
|
padding: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,324 @@
|
||||||
|
<template>
|
||||||
|
<div class="screen-header-container">
|
||||||
|
<div class="screen-title">
|
||||||
|
<img src="/statistical/logo.png" alt="" /> {{ t('sys.subject.header_title') }}
|
||||||
|
</div>
|
||||||
|
<span class="screen-currentTime">
|
||||||
|
<span class="time">{{ currentTime }}</span>
|
||||||
|
|
||||||
|
<span class="weather">{{ Weather }}</span>
|
||||||
|
</span>
|
||||||
|
<div class="left-category-container">
|
||||||
|
<div
|
||||||
|
class="category-item"
|
||||||
|
v-for="(item, index) in left_categorys"
|
||||||
|
:key="index"
|
||||||
|
:style="{
|
||||||
|
left: `${-(index * 26)}px`,
|
||||||
|
'background-image': item.hovered
|
||||||
|
? `url(/statistical/category-left-active.png)`
|
||||||
|
: `url(/statistical/category-left.png)`,
|
||||||
|
}"
|
||||||
|
@click="getHome(item)"
|
||||||
|
@mouseover="item.hovered = true"
|
||||||
|
@mouseout="item.hovered = false"
|
||||||
|
>
|
||||||
|
{{ item.title }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="right_category-container">
|
||||||
|
<div
|
||||||
|
class="category-item"
|
||||||
|
v-for="(item, index) in right_categorys"
|
||||||
|
:key="index"
|
||||||
|
:style="{
|
||||||
|
left: `${-(index * 26 - 55)}px`,
|
||||||
|
'background-image': item.hovered
|
||||||
|
? `url(/statistical/category-right-active.png)`
|
||||||
|
: `url(/statistical/category-right.png)`,
|
||||||
|
}"
|
||||||
|
@click="getHome(item)"
|
||||||
|
@mouseover="item.hovered = true"
|
||||||
|
@mouseout="item.hovered = false"
|
||||||
|
>
|
||||||
|
{{ item.title }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="user-info" style="z-index: 9999">
|
||||||
|
<span style="color: #325e95">{{ fireUserLoginName }}</span>
|
||||||
|
|
||||||
|
<span style="color: #ddd" @click="logout">退出</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="right_category-container">
|
||||||
|
<div
|
||||||
|
v-for="(item, index) in right_categorys"
|
||||||
|
:key="item.id"
|
||||||
|
class="category-item"
|
||||||
|
:style="{
|
||||||
|
left: `${-(index * 26)}px`,
|
||||||
|
'background-image': item.hovered
|
||||||
|
? `url(/statistical/category-right-active.png)`
|
||||||
|
: `url(/statistical/category-right.png)`,
|
||||||
|
}"
|
||||||
|
@click="getHome(item)"
|
||||||
|
@mouseover="item.hovered = true"
|
||||||
|
@mouseout="item.hovered = false"
|
||||||
|
>
|
||||||
|
{{ item.title }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="user-info" style="z-index: 9999">
|
||||||
|
<span style="color: #325e95">{{ fireUserLoginName }}</span>
|
||||||
|
|
||||||
|
<span style="color: #ddd" @click="logout">退出</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, defineEmits, onMounted, onUnmounted, watchEffect, h } from 'vue';
|
||||||
|
import axios from 'axios';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import { useI18n } from '@/hooks/web/useI18n';
|
||||||
|
const { t } = useI18n();
|
||||||
|
import { message } from 'ant-design-vue';
|
||||||
|
import { getSpecialData } from '@/api/demo/system';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
import { PageEnum } from '@/enums/pageEnum';
|
||||||
|
import { useUserStore } from '@/store/modules/user';
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const router = useRouter();
|
||||||
|
import { useMessage } from '@/hooks/web/useMessage';
|
||||||
|
import { useMultipleTabStore } from '@/store/modules/multipleTab';
|
||||||
|
const { createConfirm } = useMessage();
|
||||||
|
|
||||||
|
// 上方菜单
|
||||||
|
const left_categorys = ref([]);
|
||||||
|
const right_categorys = ref([]);
|
||||||
|
async function getMenu() {
|
||||||
|
const res: any = await getSpecialData();
|
||||||
|
console.log('res123', res);
|
||||||
|
|
||||||
|
// 综合监管
|
||||||
|
let category: any = {
|
||||||
|
title: '综合监管',
|
||||||
|
isDevelop: false,
|
||||||
|
hovered: false,
|
||||||
|
};
|
||||||
|
left_categorys.value?.push(category);
|
||||||
|
res?.forEach((item, index) => {
|
||||||
|
if (index < 2) {
|
||||||
|
// 违法用地、非法采矿
|
||||||
|
item.hovered = false;
|
||||||
|
left_categorys.value?.push(item);
|
||||||
|
} else if (index >= 2 && index < 5) {
|
||||||
|
// 重点问题、耕地非粮化、巡察审计
|
||||||
|
item.hovered = false;
|
||||||
|
right_categorys.value?.push(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 登陆用户
|
||||||
|
const fireUserLoginName = ref(localStorage.getItem('fireUserLoginName'));
|
||||||
|
function getFireUserLoginName() {
|
||||||
|
fireUserLoginName.value = localStorage.getItem('fireUserLoginName')
|
||||||
|
? localStorage.getItem('fireUserLoginName')
|
||||||
|
: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const tabStore = useMultipleTabStore();
|
||||||
|
|
||||||
|
function logout() {
|
||||||
|
createConfirm({
|
||||||
|
iconType: 'warning',
|
||||||
|
title: () => h('span', t('sys.navigation.logoutTip')),
|
||||||
|
content: () => h('span', t('sys.navigation.logoutMessage')),
|
||||||
|
onOk: async () => {
|
||||||
|
tabStore.resetState();
|
||||||
|
await router.replace(PageEnum.SUBJECT_HOME);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
async function getHome(item) {
|
||||||
|
console.log(window.innerWidth);
|
||||||
|
if (!item.isDevelop) {
|
||||||
|
message.warn(item.title + '系统暂未开放!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (item.isExternal) {
|
||||||
|
if (item.linkOrApi) {
|
||||||
|
window.location.href = item.linkOrApi;
|
||||||
|
} else {
|
||||||
|
message.warn('系统外部链接未配置!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!item.linkOrApi) {
|
||||||
|
item.linkOrApi = PageEnum.WELCOME_HOME;
|
||||||
|
}
|
||||||
|
userStore.setSubject(item.id, item.title, item.logoTitle, item.linkOrApi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 时间和天气
|
||||||
|
const currentTime = ref(dayjs().locale('zh-cn').format('YYYY年M月D日 dddd HH:mm:ss'));
|
||||||
|
const Weather = ref('');
|
||||||
|
async function getWeather() {
|
||||||
|
try {
|
||||||
|
// 百度国内天气查询API
|
||||||
|
const response = await axios.get('https://api.map.baidu.com/weather/v1/', {
|
||||||
|
params: {
|
||||||
|
district_id: 371300,
|
||||||
|
data_type: 'all',
|
||||||
|
ak: 'qbMvuMbWe1fJnOBNLJFsjoeHC3wfWkoB',
|
||||||
|
},
|
||||||
|
timeout: 15000,
|
||||||
|
});
|
||||||
|
Weather.value = response?.result?.now?.text;
|
||||||
|
} catch (error) {
|
||||||
|
// 备用
|
||||||
|
// http://www.tianqiapi.com/index/doc?version=v63
|
||||||
|
// 若次数试用用尽,注册账号后,切换appid和appsecret即可
|
||||||
|
axios({
|
||||||
|
method: 'get',
|
||||||
|
url: `http://v0.yiketianqi.com/api?unescape=1&version=v63&appid=88136471&appsecret=Hw4GLOcA&city=临沂`,
|
||||||
|
}).then((res) => {
|
||||||
|
Weather.value = res.data.wea;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateTime() {
|
||||||
|
currentTime.value = dayjs().locale('zh-cn').format('YYYY年M月D日 dddd HH:mm');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听每一秒更新时间
|
||||||
|
watchEffect(() => {
|
||||||
|
const intervalId = setInterval(updateTime, 1000);
|
||||||
|
// 清除定时器
|
||||||
|
onUnmounted(() => clearInterval(intervalId));
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
updateTime();
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getWeather();
|
||||||
|
getMenu();
|
||||||
|
getFireUserLoginName();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.screen-header-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100px;
|
||||||
|
// background-image: url('/statistical/header.png');
|
||||||
|
// background-size: 100% 96px;
|
||||||
|
background:
|
||||||
|
// linear-gradient(to bottom, rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0.2) 80%, rgba(0, 0, 0, 0) 100%)
|
||||||
|
// no-repeat top left / 100% 90px,
|
||||||
|
url('/statistical/mask.png') no-repeat top left / 100% 100px,
|
||||||
|
url('/statistical/header.png') no-repeat top left / 100% 96px;
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
z-index: 3;
|
||||||
|
height: 94px;
|
||||||
|
.screen-title {
|
||||||
|
width: 682px;
|
||||||
|
// height: 96px;
|
||||||
|
line-height: 90px;
|
||||||
|
font-family: Alibaba PuHuiTi;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 45px;
|
||||||
|
color: #8be5ee;
|
||||||
|
background: linear-gradient(0deg, #c6f3ff 0%, #f3feff 100%);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
margin: 0px auto;
|
||||||
|
text-align: center;
|
||||||
|
img {
|
||||||
|
position: relative;
|
||||||
|
top: -5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.screen-currentTime {
|
||||||
|
position: relative;
|
||||||
|
left: 50px;
|
||||||
|
top: -60px;
|
||||||
|
|
||||||
|
width: 344px;
|
||||||
|
height: 14px;
|
||||||
|
font-family: DengXian;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #8bd8ff;
|
||||||
|
line-height: 3px;
|
||||||
|
font-style: italic;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.time,
|
||||||
|
.weather {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.separator {
|
||||||
|
margin: 0 50px;
|
||||||
|
}
|
||||||
|
.left-category-container {
|
||||||
|
position: absolute;
|
||||||
|
top: 50px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(calc(-50% - 570px), 0);
|
||||||
|
.category-item {
|
||||||
|
float: left;
|
||||||
|
width: 138px;
|
||||||
|
height: 32px;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 32px;
|
||||||
|
text-align: center;
|
||||||
|
background-image: url('/statistical/category-left.png');
|
||||||
|
background-size: 138px 32px;
|
||||||
|
color: #fff;
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.right_category-container {
|
||||||
|
position: absolute;
|
||||||
|
top: 50px;
|
||||||
|
right: 50%;
|
||||||
|
transform: translate(calc(50% + 570px), 0);
|
||||||
|
.category-item {
|
||||||
|
float: left;
|
||||||
|
width: 138px;
|
||||||
|
height: 32px;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 32px;
|
||||||
|
text-align: center;
|
||||||
|
background-image: url('/statistical/category-right.png');
|
||||||
|
background-size: 138px 32px;
|
||||||
|
color: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-info {
|
||||||
|
width: 120px;
|
||||||
|
color: #e1e1e1;
|
||||||
|
position: absolute;
|
||||||
|
top: 48px;
|
||||||
|
right: 50px;
|
||||||
|
font-size: 14px;
|
||||||
|
z-index: 9;
|
||||||
|
&:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
color: #8be5ee;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
export const layers = [
|
||||||
|
{
|
||||||
|
id: 'house',
|
||||||
|
name:"房屋",
|
||||||
|
checked:false,
|
||||||
|
tableName: 'view_shp_idle_house',
|
||||||
|
color: '#F70303',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'land',
|
||||||
|
name:"土地资源",
|
||||||
|
checked:false,
|
||||||
|
tableName: 'view_shp_idle_land',
|
||||||
|
color: '#0AF703',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'waters',
|
||||||
|
name:"水域",
|
||||||
|
checked:false,
|
||||||
|
tableName: 'view_shp_idle_waters',
|
||||||
|
color: '#0382F7',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'farming',
|
||||||
|
name:"农业生产设施",
|
||||||
|
checked:false,
|
||||||
|
tableName: 'view_shp_idle_farming',
|
||||||
|
color: '#F4E004',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'nongji',
|
||||||
|
name:"农机组织",
|
||||||
|
checked:false,
|
||||||
|
tableName: 'view_shp_idle_nongji',
|
||||||
|
color: '#F70303',
|
||||||
|
},
|
||||||
|
]
|
||||||
Loading…
Reference in New Issue