Files
2023-01-04 16:11:46 +08:00

548 lines
15 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>
<template v-if="snapTree.length > 0">
<div
v-for="v in snapTree.slice(
(leftBoxPageNum - 1) * 5,
leftBoxPageNum * 5
)"
>
<div class="a">{{ v.name }}</div>
<div class="b">{{ v.count }}</div>
</div>
</template>
<div v-else>
<div class="a">暂无</div>
<div class="b">暂无</div>
</div>
<RegionPagine
v-if="snapTree.length"
v-model:page="leftBoxPageNum"
:total="snapTree.length"
></RegionPagine>
</div>
<div class="rightBox">
<div class="head">
<div class="a">领域</div>
<div class="b">需求数量</div>
</div>
<div
v-if="Object.keys(industryTree).length > 0"
v-for="(v, k) in industryTree"
>
<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";
import * as echarts from "echarts";
import {
countDemandByProvince,
countDemandByCity,
countDemandByArea,
} from "@/api/website/home/index";
import RegionPagine from "./RegionPagine.vue";
// import { demand } from "@/api/website/home/index";
const { proxy } = getCurrentInstance();
const loading = shallowRef(true);
let treeData = {};
const snapTree = shallowRef([]);
const industryTree = shallowRef({});
const leftBoxPageNum = ref(1);
const searchRegionData = async (code, level) => {
if (level == "province") {
const provcode = code.substring(0, 2) + "0000";
let data = {};
if (
snapTree.value.length &&
snapTree.value[0].code.substring(0, 2) == code.substring(0, 2) &&
snapTree.value[0].code.substring(2, 4) != code.substring(2, 4)
) {
data = snapTree.value;
} else {
const resp = await countDemandByCity(provcode);
snapTree.value = resp.count;
industryTree.value = resp.industry ?? {};
data = resp.count;
}
return data.find((item) => item.code == code) || false;
} else if (level == "city") {
const ctcode = code.substring(0, 4) + "00";
let data = {};
if (
snapTree.value.length &&
snapTree.value[0].code.substring(0, 4) == code.substring(0, 4) &&
snapTree.value[0].code.substring(4, 6) != code.substring(4, 6)
) {
data = snapTree.value;
} else {
const resp = await countDemandByArea(ctcode);
snapTree.value = resp.count;
industryTree.value = resp.industry ?? {};
data = resp.count;
}
return data.find((item) => item.code == code) || false;
} else {
if (Object.keys(treeData).length) {
industryTree.value = treeData.industry ?? {};
snapTree.value = treeData.count ?? [];
return treeData.count.find((item) => item.code == code) || false;
} else {
const { count, industry } = await countDemandByProvince();
industryTree.value = industry ?? {};
return count.find((item) => item.code == code) || false;
}
}
};
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(() => {
// 数据接口
countDemandByProvince().then((resp) => {
treeData = resp;
snapTree.value = resp.count;
industryTree.value = resp.industry ?? {};
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);
}
});
}, 4000);
});
function goBack() {
state.isShowGoBack = false;
loading.value = true;
state.district.search("中国", async (status, result) => {
if (status == "complete") {
await getData(result.districtList[0], "", 100000);
snapTree.value = treeData.count;
}
});
}
async 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里的数据
await searchRegionData(params.data.cityCode, params.data.level);
// 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函数在前面已经定义过了
}
});
}
async 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 = await searchRegionData(cityCode, level);
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 = await searchRegionData(cityCode, level);
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: "#333333",
},
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: false,
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%;
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: #333333;
}
}
.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;
border: 1px solid #dcdcdc;
color: #666666;
& > div {
display: flex;
}
.head {
border-bottom: 1px solid #dcdcdc;
color: #333333;
}
.a {
flex: 1;
border-right: 1px solid #dcdcdc;
text-align: center;
line-height: 42px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.b {
text-align: center;
line-height: 42px;
width: 90px;
}
}
.rightBox {
overflow: hidden;
}
// :deep(.pagine) {
// .prev,
// .next {
// color: #4f93ed !important;
// }
// }
</style>