Files
2022-10-01 09:12:01 +08:00

773 lines
22 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="box3" v-loading="loading">
<div class="tit">专家分布地图</div>
<div v-if="state.isShowGoBack" class="close-back" @click="goBack">
<img src="./img/back_button.png" />
</div>
<!-- echartsDom 兼容缩放 -->
<div ref="map" class="map echartsDom" id="map"></div>
<div class="leftBox">
<div class="head">
<div class="a">地区</div>
<div class="b">专家数量</div>
</div>
<div v-if="Object.keys(snapTree).length > 0" v-for="v in snapTree">
<div class="a">{{ v.name }}</div>
<div class="b">{{ v.count }}</div>
</div>
<div v-else>
<div class="a">暂无</div>
<div class="b">暂无</div>
</div>
</div>
<div class="rightBox">
<div class="head">
<div class="a">领域</div>
<div class="b">专家数量</div>
</div>
<div
v-if="Object.keys(getIndustry(snapTree)).length > 0"
v-for="(v, k) in getIndustry(snapTree)"
>
<div class="a" :title="k">{{ k }}</div>
<div class="b">{{ v }}</div>
</div>
<div v-else>
<div class="a">暂无</div>
<div class="b">暂无</div>
</div>
</div>
</div>
</template>
<script setup>
import { defineComponent, getCurrentInstance, onMounted, reactive } from "vue";
// return;
// console.log(echarts);
import * as echarts from "echarts";
import * as ama from "echarts-extension-amap";
console.log(ama);
// import { AMap } from "echarts-extension-amap";
// import { echarts } from "echarts";
// import { getExpert } from "@/api/website/home/index";
const { proxy } = getCurrentInstance();
const loading = shallowRef(true);
// console.log(123);
let treeData = {
340000: {
code: "340000",
name: "安徽省",
count: 107,
industry: { "1-1": 2, "1-2": 1, "2-1": 3 },
children: {
340100: {
code: "340100",
name: "合肥市",
count: 106,
industry: { "1-1": 1, "1-2": 1, "2-1": 2 },
children: {
340111: {
code: "340111",
name: "包河区",
count: 105,
industry: { "1-1": 1, "2-1": 1 },
children: null,
},
340121: {
code: "340121",
name: "长丰县",
count: 105,
industry: { "1-2": 1, "2-1": 1 },
children: null,
},
},
},
340200: {
code: "340200",
name: "芜湖市",
count: 105,
industry: { "1-1": 1, "2-1": 1 },
children: {},
},
},
},
500000: {
code: "500000",
name: "重庆",
count: 300,
industry: null,
children: {
500100: {
code: "500100",
name: "市辖区",
count: 300,
industry: null,
children: null,
},
},
},
630000: {
code: "630000",
name: "青海省",
count: 1200,
industry: null,
children: {
630200: {
code: "630200",
name: "海东市",
count: 1200,
industry: null,
children: null,
},
},
},
};
// let treeData = {};
const snapTree = shallowRef({});
function searchRegionData(code) {
// console.log(code, treeData,'searchRegionData')
return deepFindTree(code, treeData);
}
function deepFindTree(code, tree) {
let snap = false;
for (const key in tree) {
if (Object.hasOwnProperty.call(tree, key)) {
if (code == key) {
snap = tree[code];
break;
} else if (tree[key]["children"] != null) {
snap = deepFindTree(code, tree[key]["children"]);
if (snap) {
break;
}
} else {
snap = false;
}
}
}
return snap;
}
function getIndustry(object) {
let snap = {};
for (const key in object) {
if (Object.hasOwnProperty.call(object, key)) {
const element = object[key];
if (element["industry"] != null) {
for (const ek in element["industry"]) {
if (Object.hasOwnProperty.call(element["industry"], ek)) {
const ele = element["industry"][ek];
if (!Object.hasOwnProperty.call(snap, ek)) {
snap[ek] = 0;
}
snap[ek] += ele;
}
}
// for (let index = 0; index < element['industry'].length; index++) {
// const ele = element['industry'][index];
// if(Object.hasOwnProperty.call(snap, ele)) {
// }
// }
}
}
}
return snap;
}
const state = reactive({
loading: false,
isShowGoBack: false,
nameType: "",
// cityName: "中国",
cityName: "china",
areaCode: 10000,
AreaCodeStack: ["中国"],
geoJsonData: "",
echartsMap: null,
map: null,
uimap: null,
district: null,
polygons: [],
cityCode: "100000",
citySelect: null,
districtSelect: null,
opts: {},
areaData: {},
mapData: [],
zip: {}, //打包zip
codeList: [],
isCodeListLoadComplete: false, //codeList是否全部获取完毕
downloadTips: "下载geoJson数据", //下载进度提示
isShowTips: false, //是否显示下载提示
});
onMounted(() => {
// 数据接口
const res = {
code: 200,
message: "ok",
data: {
110000: {
code: "110000",
name: "北京市",
count: 3,
industry: {
"新能源与节能-批发业": 1,
"生物与新医药-医药生物技术-新型疫苗": 1,
电子信息: 1,
"电子信息-软件-基础信息": 1,
"科学研究和技术服务业-专业技术服务业": 1,
"科学研究和技术服务业-科技推广和应用服务业": 1,
"高技术服务-检验检测认证与标准服务": 1,
},
children: {
110100: {
code: "110100",
name: "市辖区",
count: 3,
industry: {
"新能源与节能-批发业": 1,
"生物与新医药-医药生物技术-新型疫苗": 1,
电子信息: 1,
"电子信息-软件-基础信息": 1,
"科学研究和技术服务业-专业技术服务业": 1,
"科学研究和技术服务业-科技推广和应用服务业": 1,
"高技术服务-检验检测认证与标准服务": 1,
},
children: {
110101: {
code: "110101",
name: "东城区",
count: 1,
industry: {
"新能源与节能-批发业": 1,
"生物与新医药-医药生物技术-新型疫苗": 1,
"电子信息-软件-基础信息": 1,
},
children: null,
},
110102: {
code: "110102",
name: "西城区",
count: 1,
industry: {
电子信息: 1,
"科学研究和技术服务业-专业技术服务业": 1,
"高技术服务-检验检测认证与标准服务": 1,
},
children: null,
},
110108: {
code: "110108",
name: "海淀区",
count: 1,
industry: { "科学研究和技术服务业-科技推广和应用服务业": 1 },
children: null,
},
},
},
},
},
120000: {
code: "120000",
name: "天津市",
count: 1,
industry: {
"电子信息-微电子技术-集成电路设计技术": 1,
"电子信息-软件-基础信息": 1,
"航空航天-航天技术": 1,
},
children: {
120100: {
code: "120100",
name: "市辖区",
count: 1,
industry: {
"电子信息-微电子技术-集成电路设计技术": 1,
"电子信息-软件-基础信息": 1,
"航空航天-航天技术": 1,
},
children: {
120101: {
code: "120101",
name: "和平区",
count: 1,
industry: {
"电子信息-微电子技术-集成电路设计技术": 1,
"电子信息-软件-基础信息": 1,
"航空航天-航天技术": 1,
},
children: null,
},
},
},
},
},
310000: {
code: "310000",
name: "上海市",
count: 1,
industry: { "新能源与节能-可再生清洁能源-太阳能": 1 },
children: {
310100: {
code: "310100",
name: "市辖区",
count: 1,
industry: { "新能源与节能-可再生清洁能源-太阳能": 1 },
children: {
310109: {
code: "310109",
name: "虹口区",
count: 1,
industry: { "新能源与节能-可再生清洁能源-太阳能": 1 },
children: null,
},
},
},
},
},
340000: {
code: "340000",
name: "安徽省",
count: 3,
industry: {
"新材料-金属材料-精品钢材制备技术": 1,
"生物与新医药-煤炭开采和洗选业": 2,
"生物与新医药-石油和天然气开采业": 3,
"电子信息-农业": 1,
"电子信息-农业-测试名称": 5,
"电子信息-林业": 1,
"电子信息-畜牧业": 1,
"电子信息-软件-基础信息": 3,
航空航天: 1,
},
children: {
340100: {
code: "340100",
name: "合肥市",
count: 1,
industry: {
"新材料-金属材料-精品钢材制备技术": 1,
"生物与新医药-煤炭开采和洗选业": 1,
"电子信息-农业": 1,
"电子信息-软件-基础信息": 3,
航空航天: 1,
},
children: {
340171: {
code: "340171",
name: "合肥高新技术产业开发区",
count: 1,
industry: {
"新材料-金属材料-精品钢材制备技术": 1,
"生物与新医药-煤炭开采和洗选业": 1,
"电子信息-农业": 1,
"电子信息-软件-基础信息": 3,
航空航天: 1,
},
children: null,
},
},
},
340200: {
code: "340200",
name: "芜湖市",
count: 1,
industry: {
"电子信息-农业-测试名称": 1,
"电子信息-林业": 1,
"电子信息-畜牧业": 1,
},
children: {
340208: {
code: "340208",
name: "三山区",
count: 1,
industry: {
"电子信息-农业-测试名称": 1,
"电子信息-林业": 1,
"电子信息-畜牧业": 1,
},
children: null,
},
},
},
340800: {
code: "340800",
name: "安庆市",
count: 1,
industry: {
"生物与新医药-煤炭开采和洗选业": 1,
"生物与新医药-石油和天然气开采业": 3,
"电子信息-农业-测试名称": 4,
},
children: {
340826: {
code: "340826",
name: "宿松县",
count: 1,
industry: {
"生物与新医药-煤炭开采和洗选业": 1,
"生物与新医药-石油和天然气开采业": 3,
"电子信息-农业-测试名称": 4,
},
children: null,
},
},
},
},
},
},
};
// getExpert().then((res) => {
// if (200 == res.code) {
treeData = res.data;
snapTree.value = res.data;
loading.value = false;
// }
// });
// let echartsDomList = document.querySelectorAll('.echartsDom');
// // 兼容echarts
// echartsDomList.forEach(element => {
// element.style.zoom = window.devicePixelRatio;
// element.style.transform = "scale(" + (1 / window.devicePixelRatio) + ")";
// element.style.transformOrigin = "0%0%";
// element.style.width = window.devicePixelRatio * 100 + '%';
// element.style.height = window.devicePixelRatio * 100 + '%';
// console.log(element.style.zoom, 'element.style.zoom')
// });
let height = document.body.clientHeight;
let width = document.body.clientWidth;
let dom = proxy.$refs["map"];
dom.style.width = width + "px";
dom.style.height = height - 80 + "px";
state.echartsMap = echarts.init(dom);
state.echartsMap.on("click", echartsMapClick);
setTimeout(() => {
state.map = new AMap.Map("container", {
resizeEnable: true,
center: [116.30946, 39.937629],
zoom: 3,
});
state.opts = {
subdistrict: 1, //返回下一级行政区
showbiz: false, //最后一级返回街道信息
};
state.district = new AMap.DistrictSearch(state.opts); //注意:需要使用插件同步下发功能才能这样直接使用
state.district.search("中国", (status, result) => {
if (status == "complete") {
getData(result.districtList[0], "", 100000);
}
});
}, 1000);
});
function goBack() {
state.isShowGoBack = false;
loading.value = true;
state.district.search("中国", (status, result) => {
if (status == "complete") {
getData(result.districtList[0], "", 100000);
snapTree.value = treeData;
}
});
}
function echartsMapClick(params) {
//地图点击事件
if (params.data.cityCode == "710000") {
return;
}
if (params.data.level == "district") {
return;
}
if (params.data.level == "street") return; //此处的params.data为state.mapData里的数据
let snap = searchRegionData(params.data.cityCode);
snapTree.value = {};
if (snap) {
snapTree.value = snap["children"];
}
state.cityCode = params.data.cityCode;
state.cityName = params.data.name;
state.district.setLevel(params.data.level); //行政区级别
state.district.setExtensions("all");
state.isShowGoBack = true;
loading.value = true;
//行政区查询
//按照adcode进行查询可以保证数据返回的唯一性
state.district.search(state.cityCode, (status, result) => {
if (status === "complete") {
if (params.data.level == "district") {
return;
}
state.AreaCodeStack.push(result.districtList[0].adcode);
getData(result.districtList[0], params.data.level, state.cityCode); //这个getData函数在前面已经定义过了
}
});
}
function getData(data, level, adcode) {
//处理获取出来的边界数据
var subList = data.districtList;
if (subList) {
var curlevel = subList[0].level;
if (curlevel === "street") {
//为了配合echarts地图区县名称显示正常这边街道级别数据需要特殊处理
let mapJsonList = state.geoJsonData.features;
let mapJson = {};
for (let i in mapJsonList) {
if (mapJsonList[i].properties.name == state.cityName) {
mapJson["features"] = [].concat(mapJsonList[i]);
}
}
state.mapData = [];
let item = searchRegionData(cityCode);
if (item) {
console.log("1 searchRegionData(cityCode)", item);
}
//这个mapData里包含每个区域的code、名称、对应的等级实现第三步功能时能用上
state.mapData.push({
name: state.cityName,
value: item ? item.count : 0,
level: curlevel,
});
loadMap(state.cityName, mapJson);
state.geoJsonData = mapJson;
return;
}
//街道级以上的数据处理方式
state.mapData = [];
for (var i = 0, l = subList.length; i < l; i++) {
var name = subList[i].name;
var cityCode = subList[i].adcode;
//这个mapData里包含每个区域的code、名称、对应的等级实现第三步功能时能用上
let item = searchRegionData(cityCode);
if (item) {
console.log("2 searchRegionData(cityCode)", item);
}
state.mapData.push({
name: name,
value: item ? item.count : 0,
cityCode: cityCode,
level: curlevel,
});
}
loadMapData(adcode);
}
}
function loadMapData(areaCode) {
AMapUI.loadUI(["geo/DistrictExplorer"], (DistrictExplorer) => {
//创建一个实例
var districtExplorer = (window.districtExplorer = new DistrictExplorer({
eventSupport: true, //打开事件支持
map: state.map,
}));
districtExplorer.loadAreaNode(areaCode, (error, areaNode) => {
if (error) {
console.error(error);
return;
}
let mapJson = {};
//特别注意这里哦如果查看过正常的geojson文件都会发现文件都是以features 字段开头的,所以这里要记得加上
mapJson.features = areaNode.getSubFeatures();
console.log("------------------");
for (var i = 0; i < mapJson.features.length; i++) {
if (
mapJson.features[i].properties.adcode == 810000 ||
mapJson.features[i].properties.adcode == 820000
) {
mapJson.features.splice(i, 1); // 删除下标为i 的元素i开始只删除一个就它自己了
i--; // 删除一个元素后数组长度减一了
}
}
console.log("------------------");
loadMap(state.cityName, mapJson);
});
});
}
function loadMap(mapName, data) {
if (data) {
echarts.registerMap(mapName, data); //把geoJson数据注入echarts
//配置echarts的option
var option = {
visualMap: {
type: "piecewise",
left: "center", //组件离容器左侧的距离,'left', 'center', 'right','20%'
bottom: "30",
orient: "horizontal", //图例排列方向
padding: 5,
pieces: [
{ gte: 0, lte: 99, label: "99", color: "#CAE9FD" },
{ gte: 100, lte: 299, label: "100-299", color: "#7ED2F7" },
{ gte: 300, lte: 499, label: "299-499", color: "#039DDD" },
{ gte: 500, label: "500", color: "#0D4884" },
// {max: 30, label: '安全', color: '#2c9a42'},
// {min: 30, max: 60, label: '警告', color: '#d08a00'},
// {min: 60, label: '危险', color: '#c23c33'},
],
// color: '#fff',
textStyle: {
color: "#fff",
},
visibility: "off",
},
tooltip: {
//提示框信息
trigger: "item",
formatter: "{b}\n{c}人",
},
series: [
{
name: "数据名称",
type: "map",
roam: false,
top: "15%",
bottom: state.isShowGoBack ? "8%" : "-20%",
mapType: mapName,
selectedMode: "single",
showLegendSymbol: false,
visibility: "off",
backgroundColor: "transparent",
itemStyle: {
normal: {
color: "#333333",
areaColor: "#fff",
borderColor: "#666666",
borderWidth: 0.5,
label: {
show: true,
textStyle: {
color: "#333333",
},
},
},
emphasis: {
areaColor: "rgb(38, 219, 11)",
borderColor: "#666666",
areaStyle: {
color: "#333333",
},
label: {
show: true,
textStyle: {
color: "#333333",
},
// formatter: function (value) { //标签的格式化工具。
// return value.name + '' + value.value; // 范围标签显示内容。
// }
},
},
},
data: state.mapData, //这个data里包含每个区域的code、名称、对应的等级实现第三步功能时能用上
},
],
};
state.echartsMap.setOption(option);
loading.value = false;
}
}
</script>
<style lang="scss" scoped>
.box3 {
width: 100%;
height: 100%;
background: linear-gradient(0deg, #010101, #041744);
position: relative;
.tit {
position: absolute;
top: 75px;
width: 100%;
text-align: center;
font-size: 36px;
font-family: Source Han Sans CN;
font-weight: 300;
color: #ffffff;
}
}
.map {
width: 100%;
height: 100%;
background-image: url(./img/lightEffect.png);
background-size: 644px 272px;
background-repeat: no-repeat;
background-position: center top;
}
.close-back {
background: url(img/close_back.png) no-repeat;
transition: all 0.5s;
height: 70px;
width: 85px;
color: #fff;
left: 65px;
position: absolute;
top: 100px;
cursor: pointer;
z-index: 1000;
&:hover {
left: 55px;
}
img {
margin: 28px auto 0;
width: 30px;
display: block;
transition: all 0.5s;
}
}
.leftBox {
left: 6%;
}
.rightBox {
right: 6%;
max-height: 465px !important;
}
.leftBox,
.rightBox {
position: absolute;
top: 25%;
max-width: 250px;
min-width: 200px;
max-height: 256px;
overflow: hidden;
background: rgba(4, 22, 65, 0.5);
border: 1px solid #0054ff;
color: rgba(161, 192, 255, 1);
& > div {
display: flex;
}
.head {
border-bottom: 1px solid #0054ff;
color: #ffffff;
}
.a {
flex: 1;
border-right: 1px solid #0054ff;
text-align: center;
line-height: 42px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.b {
text-align: center;
line-height: 42px;
width: 90px;
}
}
</style>