|
|
<template>
|
|
|
<div class="container">
|
|
|
<div class="containertwo">
|
|
|
<!-- 地图区域 -->
|
|
|
<div class="mapareaone">
|
|
|
<!-- 展开/隐藏控制按钮(放在盒子右侧外部) -->
|
|
|
<div class="collapse-control" @click="toggleCollapse">
|
|
|
<img v-show="!isCollapsed" src="@/assets/images/icon-sq@2x.png" alt="隐藏" class="control-icon">
|
|
|
<img v-show="isCollapsed" src="@/assets/images/icon-zk@2x.png" alt="展开" class="control-icon">
|
|
|
</div>
|
|
|
|
|
|
<!-- 左侧项目列表区域 -->
|
|
|
<div class="leftdiv" v-show="!isCollapsed">
|
|
|
<!-- 项目列表内容 -->
|
|
|
<div class="mainarea" style="background-color: #FFFFFF;">
|
|
|
<ProjectList />
|
|
|
</div>
|
|
|
</div>
|
|
|
<!-- 右侧搜索 -->
|
|
|
<div class="rightdiv">
|
|
|
<el-input v-model="searchBox" placeholder="请输入项目名称" class="search-input" @input="handleSearchInput"
|
|
|
@clear="handleClear" clearable>
|
|
|
<el-button slot="append" icon="el-icon-search" @click="toSearch"></el-button>
|
|
|
</el-input>
|
|
|
</div>
|
|
|
<!-- 搜索结果列表 -->
|
|
|
<div class="search-results" v-if="searchList && searchList.length > 0">
|
|
|
<div class="search-item" v-for="(item, index) in searchList" :key="index" @click="centerMap(item)">
|
|
|
<div class="item-name">{{ item.name }}</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<!-- 右侧地图区域 -->
|
|
|
<div class="map-container">
|
|
|
<div id="mars2dContainerSSS" class="mars2d-container"></div>
|
|
|
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<!-- 悬浮窗 -->
|
|
|
<div class="app-container" v-show="dialogVisible" v-click-outside="closeDialog">
|
|
|
<div class="close-btn" @click="closeDialog">
|
|
|
<i class="el-icon-close"></i>
|
|
|
</div>
|
|
|
<div class="dialog-content">
|
|
|
<div class="dialog-title">{{ selectedProject.name }}</div>
|
|
|
<div class="dialog-info">
|
|
|
<p><span class="label">状态:</span>
|
|
|
<span class="value" :style="{ color: xzflColors[xzflMap[selectedProject.xzfl]] }">
|
|
|
{{ xzflMap[selectedProject.xzfl] }}
|
|
|
</span>
|
|
|
</p>
|
|
|
<p><span class="label">项目单位:</span> <span class="value">{{ selectedProject.xmfrdwxz }}</span></p>
|
|
|
<p><span class="label">总投资额:</span> <span class="value">{{ selectedProject.ztze }}</span></p>
|
|
|
<p><span class="label">联系人:</span> <span class="value">{{ selectedProject.projectLeader }}</span></p>
|
|
|
<p><span class="label">联系电话:</span><span class="value"> {{ selectedProject.phone }}</span></p>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
import 'mars2d/mars2d.css';
|
|
|
import * as mars2d from 'mars2d';
|
|
|
import ProjectList from '@/views/components/analysis/projectList.vue'
|
|
|
import { getBasicInformationPage } from "@/api/ManageApi/index";
|
|
|
import { debounce } from 'lodash';
|
|
|
|
|
|
import suzhouData from '@/assets/json/suzhou.json'
|
|
|
|
|
|
|
|
|
// 自定义指令
|
|
|
// 点击外部关闭弹窗
|
|
|
const clickOutside = {
|
|
|
bind(el, binding, vnode) {
|
|
|
el.clickOutsideEvent = function (event) {
|
|
|
if (!(el === event.target || el.contains(event.target))) {
|
|
|
vnode.context[binding.expression](event);
|
|
|
}
|
|
|
};
|
|
|
document.body.addEventListener('click', el.clickOutsideEvent);
|
|
|
},
|
|
|
unbind(el) {
|
|
|
document.body.removeEventListener('click', el.clickOutsideEvent);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
export default {
|
|
|
components: {
|
|
|
ProjectList,
|
|
|
},
|
|
|
directives: {
|
|
|
'click-outside': clickOutside
|
|
|
},
|
|
|
data() {
|
|
|
const basePathUrl = window.basePathUrl || "";
|
|
|
return {
|
|
|
markerIcon: require('@/assets/images/detailsicon/icon-定位@2x.png'),
|
|
|
projectMarker: null,
|
|
|
isCollapsed: false,
|
|
|
searchBox: '',
|
|
|
searchList: [],
|
|
|
dialogVisible: false,
|
|
|
selectedProject: {
|
|
|
name: '',
|
|
|
xzfl: '',
|
|
|
projectLeader: '',
|
|
|
phone: '',
|
|
|
ztze: '',
|
|
|
xmfrdwxz: ''
|
|
|
},
|
|
|
showLocationIcon: false,
|
|
|
iconPosition: {
|
|
|
position: 'absolute',
|
|
|
top: '0px',
|
|
|
left: '0px'
|
|
|
},
|
|
|
hasSearched: false,
|
|
|
// 状态颜色映射
|
|
|
xzflColors: {
|
|
|
'在建': '#6EDABE',
|
|
|
'拟建': '#FFBF6B',
|
|
|
'已建': '#2B62F1'
|
|
|
},
|
|
|
xzflMap: {
|
|
|
1: '已建',
|
|
|
2: '在建',
|
|
|
3: '拟建'
|
|
|
},
|
|
|
// 地图相关配置
|
|
|
configUrl: basePathUrl + "config/config.json",
|
|
|
mapOptions: {
|
|
|
copyright: false,
|
|
|
basemaps: [
|
|
|
{
|
|
|
id: 2021,
|
|
|
chinaCRS: "GCJ02",
|
|
|
pid: 10,
|
|
|
name: "高德电子",
|
|
|
icon: "img/basemaps/gaode_vec.png",
|
|
|
type: "gaode",
|
|
|
layer: "vec",
|
|
|
show: true
|
|
|
}
|
|
|
],
|
|
|
center: { lat: 31.3356, lng: 120.7157 },
|
|
|
zoom: 11,
|
|
|
minZoom: 10,
|
|
|
maxZoom: 20,
|
|
|
// zoomControl: true,
|
|
|
chinaCRS: 'GCJ02'
|
|
|
},
|
|
|
map: null
|
|
|
};
|
|
|
},
|
|
|
created() {
|
|
|
this.debouncedSearch = debounce(this.toSearch, 300);
|
|
|
},
|
|
|
mounted() {
|
|
|
this.initMap();
|
|
|
},
|
|
|
beforeDestroy() {
|
|
|
if (this.map) {
|
|
|
this.map.destroy();
|
|
|
}
|
|
|
},
|
|
|
methods: {
|
|
|
// 初始化地图
|
|
|
initMap() {
|
|
|
this.map = new mars2d.Map('mars2dContainerSSS', this.mapOptions);
|
|
|
this.map.on('load', this.onMapLoad);
|
|
|
},
|
|
|
|
|
|
onMapLoad() {
|
|
|
this.addSuzhouIndustrialParkLayer();
|
|
|
},
|
|
|
// 园区
|
|
|
async addSuzhouIndustrialParkLayer() {
|
|
|
try {
|
|
|
const geoJsonData = suzhouData; // 直接使用导入的数据
|
|
|
const graphicLayer = new mars2d.layer.GraphicLayer({
|
|
|
name: "苏州园区高亮区域",
|
|
|
zIndex: 10
|
|
|
});
|
|
|
this.map.addLayer(graphicLayer);
|
|
|
const polygon = mars2d.Util.geoJsonToGraphics(geoJsonData, {
|
|
|
style: {
|
|
|
fill: true,
|
|
|
fillColor: "#2B62F1",
|
|
|
fillOpacity: 0.3,
|
|
|
stroke: true,
|
|
|
color: "#2B62F1",
|
|
|
opacity: 0.8,
|
|
|
weight: 3
|
|
|
},
|
|
|
tooltip: "苏州工业园区"
|
|
|
});
|
|
|
graphicLayer.addGraphic(polygon);
|
|
|
} catch (error) {
|
|
|
console.error('加载苏州园区数据失败:', error);
|
|
|
}
|
|
|
},
|
|
|
toggleCollapse() {
|
|
|
this.isCollapsed = !this.isCollapsed;
|
|
|
},
|
|
|
handleSearchInput() {
|
|
|
if (this.searchBox.trim() === '') {
|
|
|
this.searchList = [];
|
|
|
this.hasSearched = false;
|
|
|
this.showLocationIcon = false;
|
|
|
this.showLocationIcon = false;
|
|
|
return;
|
|
|
}
|
|
|
this.debouncedSearch();
|
|
|
},
|
|
|
toSearch() {
|
|
|
if (!this.searchBox.trim()) {
|
|
|
this.searchList = [];
|
|
|
this.hasSearched = true;
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
const params = {
|
|
|
name: this.searchBox,
|
|
|
current: 1,
|
|
|
size: 10
|
|
|
};
|
|
|
|
|
|
getBasicInformationPage(params)
|
|
|
.then(response => {
|
|
|
this.hasSearched = true;
|
|
|
if (response && response.code === 200 && response.data) {
|
|
|
this.searchList = response.data.records;
|
|
|
if (this.searchList.length === 0) {
|
|
|
this.$message.warning('查无此项目');
|
|
|
}
|
|
|
} else {
|
|
|
this.searchList = [];
|
|
|
this.$message.warning('查无此项目');
|
|
|
}
|
|
|
})
|
|
|
.catch(error => {
|
|
|
console.error('搜索失败:', error);
|
|
|
this.hasSearched = true;
|
|
|
this.searchList = [];
|
|
|
this.$message.error('搜索失败,请重试');
|
|
|
});
|
|
|
},
|
|
|
centerMap(item) {
|
|
|
if (!item.longitude || !item.latitude) {
|
|
|
this.$message.warning('该项目未落图!');
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
this.searchBox = item.name;
|
|
|
this.searchList = [];
|
|
|
this.selectedProject = {
|
|
|
name: item.name,
|
|
|
projectLeader: item.projectLeader || '暂无',
|
|
|
phone: item.phone || '暂无',
|
|
|
ztze: item.ztze || '暂无',
|
|
|
xmfrdwxz: item.xmfrdwxz || '暂无',
|
|
|
xzfl: item.xzfl || '暂无'
|
|
|
};
|
|
|
|
|
|
// 解析坐标并定位
|
|
|
if (item.jsdd && item.jsdd.includes(',')) {
|
|
|
const [lng, lat] = item.jsdd.split(',').map(Number);
|
|
|
this.map.flyTo([lat, lng], 17);
|
|
|
}
|
|
|
|
|
|
// 坐标定位
|
|
|
this.map.flyTo([item.latitude, item.longitude], 17);
|
|
|
|
|
|
// 标记
|
|
|
this.addProjectMarker(item);
|
|
|
},
|
|
|
handleClear() {
|
|
|
this.showLocationIcon = false;
|
|
|
this.searchList = [];
|
|
|
this.hasSearched = false;
|
|
|
this.searchBox = '';
|
|
|
this.dialogVisible = false;
|
|
|
// 移除标记
|
|
|
if (this.projectMarker) {
|
|
|
this.map.removeLayer(this.projectMarker);
|
|
|
this.projectMarker = null;
|
|
|
}
|
|
|
this.map.setView(this.mapOptions.center, this.mapOptions.zoom);
|
|
|
},
|
|
|
addProjectMarker(item) {
|
|
|
if (this.projectMarker) {
|
|
|
this.map.removeLayer(this.projectMarker);
|
|
|
}
|
|
|
|
|
|
this.projectMarker = new mars2d.graphic.Marker({
|
|
|
latlng: [item.latitude, item.longitude],
|
|
|
style: {
|
|
|
image: this.markerIcon,
|
|
|
width: 32,
|
|
|
height: 44,
|
|
|
anchor: [16, 44]
|
|
|
},
|
|
|
interactive: true,
|
|
|
cursor: 'pointer'
|
|
|
});
|
|
|
|
|
|
// 点击图标
|
|
|
this.projectMarker.on(mars2d.EventType.click, (event) => {
|
|
|
this.selectedProject = { ...item };
|
|
|
this.dialogVisible = true;
|
|
|
});
|
|
|
|
|
|
this.map.addLayer(this.projectMarker);
|
|
|
},
|
|
|
showDialog() {
|
|
|
this.dialogVisible = true;
|
|
|
},
|
|
|
closeDialog() {
|
|
|
this.dialogVisible = false;
|
|
|
},
|
|
|
}
|
|
|
}
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
.collapse-control {
|
|
|
position: absolute;
|
|
|
left: -1.5rem;
|
|
|
top: 12.5rem;
|
|
|
width: auto;
|
|
|
height: 2rem;
|
|
|
border-radius: 0 4px 4px 0;
|
|
|
cursor: pointer;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
z-index: 1001;
|
|
|
transition: all 0.3s ease;
|
|
|
}
|
|
|
|
|
|
.control-icon {
|
|
|
width: 3.5rem;
|
|
|
height: 3.5rem;
|
|
|
}
|
|
|
|
|
|
.leftdiv {
|
|
|
width: 38%;
|
|
|
height: 100%;
|
|
|
position: absolute;
|
|
|
left: 0rem;
|
|
|
top: 0rem;
|
|
|
background: #FFFFFF;
|
|
|
border-radius: 0.5rem;
|
|
|
transition: all 0.3s ease;
|
|
|
z-index: 1000;
|
|
|
overflow: hidden;
|
|
|
overflow-y: auto;
|
|
|
}
|
|
|
|
|
|
.mainarea {
|
|
|
height: 100%;
|
|
|
overflow: auto;
|
|
|
}
|
|
|
|
|
|
.icondiv {
|
|
|
width: 8rem;
|
|
|
height: 8rem;
|
|
|
position: relative;
|
|
|
}
|
|
|
|
|
|
.icondiv img {
|
|
|
width: 1.7rem;
|
|
|
height: 2rem;
|
|
|
transition: all 0.2s ease;
|
|
|
}
|
|
|
|
|
|
.icondiv img:hover {
|
|
|
transform: scale(1.1);
|
|
|
}
|
|
|
|
|
|
.rightdiv {
|
|
|
width: 30%;
|
|
|
position: absolute;
|
|
|
right: 1rem;
|
|
|
top: 1rem;
|
|
|
z-index: 900;
|
|
|
}
|
|
|
|
|
|
.search-results {
|
|
|
position: absolute;
|
|
|
right: 1rem;
|
|
|
top: 3.5rem;
|
|
|
width: 30%;
|
|
|
background-color: #FFFFFF;
|
|
|
border: 1px solid #E5E5E5;
|
|
|
border-radius: 0.5rem;
|
|
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
|
|
z-index: 900;
|
|
|
max-height: 15rem;
|
|
|
overflow-y: auto;
|
|
|
}
|
|
|
|
|
|
.search-item {
|
|
|
padding: 0.5rem;
|
|
|
cursor: pointer;
|
|
|
transition: background-color 0.3s ease;
|
|
|
}
|
|
|
|
|
|
.search-item:hover {
|
|
|
background-color: #F2F4F7;
|
|
|
}
|
|
|
|
|
|
.item-name {
|
|
|
margin-bottom: 0.3rem;
|
|
|
}
|
|
|
|
|
|
.item-address {
|
|
|
font-size: 0.88rem;
|
|
|
color: #606266;
|
|
|
}
|
|
|
|
|
|
/* 悬浮div */
|
|
|
.app-container {
|
|
|
position: absolute;
|
|
|
top: 20%;
|
|
|
left: 53%;
|
|
|
height: 15rem;
|
|
|
width: 18rem;
|
|
|
background-color: #fff;
|
|
|
border-radius: 4px;
|
|
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
|
|
z-index: 2000;
|
|
|
padding: 15px;
|
|
|
}
|
|
|
|
|
|
.close-btn {
|
|
|
position: absolute;
|
|
|
top: 5px;
|
|
|
right: 5px;
|
|
|
cursor: pointer;
|
|
|
font-size: 16px;
|
|
|
color: #909399;
|
|
|
}
|
|
|
|
|
|
.close-btn:hover {
|
|
|
color: #409EFF;
|
|
|
}
|
|
|
|
|
|
.dialog-content {
|
|
|
height: 100%;
|
|
|
}
|
|
|
|
|
|
.dialog-title {
|
|
|
font-size: 16px;
|
|
|
font-family: aliregular;
|
|
|
margin-bottom: 15px;
|
|
|
padding-bottom: 10px;
|
|
|
border-bottom: 1px solid #EBEEF5;
|
|
|
color: #2B62F1;
|
|
|
white-space: nowrap;
|
|
|
overflow: hidden;
|
|
|
text-overflow: ellipsis;
|
|
|
}
|
|
|
|
|
|
.dialog-info {
|
|
|
font-size: 14px;
|
|
|
color: #606266;
|
|
|
}
|
|
|
|
|
|
.dialog-info p {
|
|
|
margin-bottom: 10px;
|
|
|
}
|
|
|
|
|
|
.label {
|
|
|
color: #9E9E9E;
|
|
|
font-family: aliregular;
|
|
|
width: 3rem;
|
|
|
}
|
|
|
|
|
|
.value {
|
|
|
color: #3D424C;
|
|
|
font-family: aliregular;
|
|
|
}
|
|
|
|
|
|
/* 所有容器 */
|
|
|
.container {
|
|
|
position: relative;
|
|
|
height: 100%;
|
|
|
}
|
|
|
|
|
|
.mapareaone {
|
|
|
height: 100%;
|
|
|
grid-column: span 2;
|
|
|
width: 100%;
|
|
|
position: relative;
|
|
|
}
|
|
|
|
|
|
.containertwo {
|
|
|
height: 100%;
|
|
|
position: relative;
|
|
|
}
|
|
|
|
|
|
.map-container {
|
|
|
width: 100%;
|
|
|
height: 25rem;
|
|
|
position: relative;
|
|
|
}
|
|
|
|
|
|
.mars2d-container {
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
border-radius: 0.5rem;
|
|
|
}
|
|
|
</style> |