Files
dvcp_v2_webapp/packages/2.0.5/AppGridMap/components/list.vue
aixianling a8dff862d2 初始化
2021-12-14 18:36:19 +08:00

710 lines
19 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="map">
<div id="mapContainer"></div>
<div class="drawer" ref="drawer">
<div class="drawer-content">
<header>
<h3>网格管理</h3>
<!-- <div class="online">
<p>
<span>人员总数</span>
<span>{{ member.allMemberNumber }}</span>
</p>
<p>
<span>在线人员</span>
<span style="color: #19d286">{{ member.onlineNumber }}</span>
</p>
</div>
<div class="circle">
<el-progress
type="circle"
:width="46"
:stroke-width="4"
:percentage="percentage()"
color="#19D286"
></el-progress>
</div> -->
</header>
<!-- <ul class="nav">
<li
v-for="(e, index) in navList"
:key="index"
@click="navClick(index)"
:class="{ active: activeIndex == index }"
>
{{ e.title }}
</li>
</ul> -->
<div v-show="activeIndex == 0" class="tree">
<div class="map-search">
<el-select
size="mini"
style="width: 80px"
@change="getMemberList()"
v-model="searchObj.onlineStatus"
placeholder="全部"
clearable
>
<el-option
v-for="(item, i) in dict.getDict('onlineStatus')"
:key="i"
:label="item.dictName"
:value="item.dictValue"
></el-option>
</el-select>
<el-input
style="width: 164px"
@change="getMemberList()"
placeholder="请输入网格员姓名"
v-model="searchObj.girdMemberName"
size="mini"
@keyup.enter.native="getMemberList()"
suffix-icon="el-icon-search"
>
</el-input>
</div>
<header class="header">
<span>人员列表</span>
</header>
<ul class="member-list" v-if="member.memberList.length > 0">
<li
v-for="(e, index) in member.memberList"
:key="index"
@click="clickMember(e)"
:class="{ active: activeId == e.id }"
>
<span
class="iconfont iconzxjyzdls"
:style="{
color: e.onlineStatus == 1 ? '#19D286' : 'rgb(178, 178, 201)',
}"
></span>
<span>{{ e.name }}</span>
</li>
</ul>
<div v-if="member.memberList.length == 0" class="empty">暂无数据</div>
</div>
<div v-show="activeIndex == 1" class="tree">
<div class="input">
<el-input
placeholder="请输入网格名称"
v-model="filterText"
size="mini"
suffix-icon="el-icon-search"
>
</el-input>
</div>
<header class="header">
<span>网格列表</span>
</header>
<div class="tree-div">
<el-tree
:data="treeObj.treeList"
:props="treeObj.defaultProps"
@node-click="handleNodeClick"
node-key="id"
ref="tree"
:filter-node-method="filterNode"
default-expand-all
highlight-current
>
</el-tree>
</div>
</div>
</div>
</div>
<div class="drawer-btn" @click="control()" ref="drawerBtn">
<span
class="iconfont iconArrow_Left"
ref="icon"
@click="changeIcon()"
></span>
</div>
</div>
</template>
<script>
import AMapLoader from "@amap/amap-jsapi-loader";
import { mapState } from 'vuex'
export default {
name: "AppGridMap",
label: "网格地图",
props: {
instance: Function,
dict: Object,
permissions: Function,
},
data() {
return {
map: '',
overlays: [],
drawer: false,
navList: [
// { id: 0, title: "网格员" },
{ id: 1, title: "网格" },
],
activeIndex: 1,
filterText: "",
treeObj: {
treeList: [],
defaultProps: {
children: "girdList",
label: "girdName",
},
defaultExpandedKeys: [],
},
polygon: "",
path: [],
searchObj: {
onlineStatus: "",
girdMemberName: "",
},
member: {
memberList: [],
},
infoWindowHtml: "",
marker: {},
activeId: null,
};
},
computed: {
...mapState(['user']),
},
created() {
this.areaId = this.user.info.areaId
},
mounted() {
// this.getMemberList();
this.getTreeList()
},
watch: {
filterText(val) {
this.$refs.tree.filter(val);
},
},
methods: {
filterNode(value, data) {
if (!value) return true;
return data.girdName.indexOf(value) !== -1;
},
getTreeList() {
this.instance.post(`/app/appgirdinfo/listAll`, null, null).then((res) => {
if (res.code == 0) {
this.treeObj.treeList = res.data;
}
});
},
handleNodeClick(val) {
let path = [];
if (val.points) {
val.points.map((e, index) => {
path[index] = [e.lng, e.lat];
});
}
this.initMap(path);
},
initMap(path, marker, initMakers) {
AMapLoader.load({
key: "b553334ba34f7ac3cd09df9bc8b539dc", // 申请好的Web端开发者Key首次调用 load 时必填
version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
plugins: ["AMap.ToolBar", "AMap.Scale", "AMap.InfoWindow"], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
AMapUI: {
// 是否加载 AMapUI缺省不加载
version: "1.1", // AMapUI 缺省 1.1
plugins: [], // 需要加载的 AMapUI ui插件
},
})
.then((AMap) => {
this.map = new AMap.Map("mapContainer", {
resizeEnable: true,
zoom: 13,
});
this.map.setZoomAndCenter(14, [117.147097, 36.72081], false, 600);
if (path) {
this.polygon = new AMap.Polyline({
path: path,
strokeColor: "#FF33FF",
strokeWeight: 6,
strokeStyle: "solid",
strokeOpacity: 1,
fillColor: "#1791fc",
zIndex: 50,
lineJoin: "round",
lineCap: "round",
});
this.map.add(this.polygon);
this.map.setFitView();
}
if (marker) {
console.log(marker);
let infoWindow = new AMap.InfoWindow({
position: new AMap.LngLat(marker.lng, marker.lat),
offset: new AMap.Pixel(0, -30),
content: this.infoWindowHtml,
});
let markerDot = new AMap.Marker({
map: this.map,
position: new AMap.LngLat(marker.lng, marker.lat),
});
markerDot.on("click", () => {
infoWindow.open(this.map);
});
infoWindow.open(this.map);
this.getLngLat(marker);
this.map.setZoomAndCenter(13, [marker.lng, marker.lat], false, 600);
}
if (initMakers) {
let markerList = [];
initMakers.map((e) => {
markerList.push(
new AMap.Marker({
position: new AMap.LngLat(e.lng, e.lat),
label: {
content: `<p class='title_info'>${e.name}</p>`,
direction: "center",
offset: new AMap.Pixel(0, -30),
},
})
);
});
this.map.add(markerList);
}
this.map.addControl(new AMap.Scale());
this.map.addControl(new AMap.ToolBar());
this.eventOn();
})
.catch((e) => {
console.log(e);
});
},
//地图事件绑定
eventOn() {
this.map.on("mousemove", this.showInfoMove, this);
},
showInfoMove(e) {},
hasClass(ele, cls) {
return ele.className.match(new RegExp("(\\s|^)" + cls + "(\\s|$)"));
},
addClass(ele, cls) {
if (!this.hasClass(ele, cls)) ele.className += " " + cls;
},
removeClass(ele, cls) {
if (this.hasClass(ele, cls)) {
const reg = new RegExp("(\\s|^)" + cls + "(\\s|$)");
ele.className = ele.className.replace(reg, " ");
}
},
changClass(ele, className) {
if (!this.hasClass(ele, className)) {
this.addClass(ele, className);
} else {
this.removeClass(ele, className);
}
},
changeIcon() {
this.changClass(this.$refs.icon, "iconArrow_Right");
},
control() {
this.changClass(this.$refs.drawer, "hide");
this.changClass(this.$refs.drawerBtn, "btn-hide");
},
navClick(index) {
this.activeIndex = index;
this.initMap();
if (index == 1) {
this.filterText = "";
this.getTreeList();
} else {
this.searchObj = {
onlineStatus: "",
girdMemberName: "",
};
this.getMemberList();
}
},
percentage() {
if (this.member.onlineNumber == 0) {
return 0;
} else {
return (
100 *
(this.member.onlineNumber / this.member.allMemberNumber)
).toFixed(2);
}
},
getMemberList() {
this.instance
.post(
`/app/appgirdmemberinfo/queryGirdMemberByMap`,
{ ...this.searchObj },
null
)
.then((res) => {
if (res.code == 0) {
let markers = [];
this.member = res.data;
this.member.memberList.map((e) => {
if (e.onlineStatus == "1") {
markers.push({ lng: e.lng, lat: e.lat, name: e.name });
}
});
this.initMap(null, null, markers);
}
});
},
clickMember(marker) {
if (marker.onlineStatus == 1) {
this.activeId = marker.id;
this.marker = marker;
this.infoWindowContent(marker);
}
},
infoWindowContent(marker) {
this.instance
.post(`/app/location/xyToAddress`, null, {
params: {
x: marker.lat,
y: marker.lng,
},
})
.then((res) => {
if (res.code == 0) {
this.infoWindowHtml = `<div class="info">
<p>
<span class="name">${marker.name}</span>
<span class="lat">${marker.lng},${marker.lat}</span>
</p>
<p>
<span class="lat">${res.data}</span>
</p>
<p class="address">
<span class="iconfont iconarea" id="addressSpan">当日轨迹</span>
</p>
</div>`;
this.initMap(false, marker);
}
});
},
getLngLat(marker) {
let span = document.getElementById("addressSpan");
span.addEventListener("click", this.queryTrajectory);
},
queryTrajectory() {
this.instance
.post(`/app/appgirdmembertrajectory/queryTrajectory`, null, {
params: {
userId: this.marker.userId,
},
})
.then((res) => {
if (res.code == 0) {
let path = [];
if (res.data) {
res.data.map((e, index) => {
path[index] = [e.lng, e.lat];
});
}
this.initMap(path, this.marker);
}
});
},
},
};
</script>
<style lang="scss" scoped>
.map {
height: 100%;
width: 100%;
position: relative;
#mapContainer {
width: 100%;
height: 100%;
}
.drawer-btn {
position: absolute;
left: 280px;
bottom: 0;
top: 0;
margin: auto;
width: 20px;
height: 24px;
border-top: 40px solid transparent;
border-bottom: 40px solid transparent;
border-left: 16px solid #333c53;
border-right: 0px solid transparent;
transition: all 0.5s ease-in-out;
cursor: pointer;
.iconfont {
position: absolute;
font-size: 26px;
color: rgb(255, 255, 255);
left: -21px;
top: -14px;
transition: all 0.5s ease-in-out;
}
}
.btn-hide {
left: 0;
}
.drawer {
width: 280px;
height: 100%;
background: #333c53;
position: absolute;
z-index: 1000;
top: 0;
left: 0;
visibility: visible;
opacity: 1;
transition: all 0.5s ease-in-out;
.drawer-content {
width: 100%;
height: 100%;
padding: 0 16px;
box-sizing: border-box;
header {
height: 76px;
display: flex;
align-items: center;
box-sizing: border-box;
h3 {
color: #fff;
font-size: 18px;
}
.online {
color: #fff;
font-size: 12px;
padding-left: 16px;
}
.circle {
width: 40px;
height: 40px;
padding-left: 16px;
display: flex;
align-items: center;
::v-deep .el-progress__text {
color: #19d286;
}
}
}
.nav {
width: 100%;
height: 28px;
display: flex;
padding: 0;
margin: 0;
li {
width: 50%;
height: 28px;
line-height: 28px;
text-align: center;
font-size: 12px;
background: #1d2336;
border-radius: 0px 3px 3px 0px;
color: #8899bb;
cursor: pointer;
}
.active {
background: #3e4a69;
color: #fff;
border-radius: 3px 0px 0px 3px;
}
}
.tree {
height: calc(100% - 28px - 76px);
overflow: auto;
border-radius: 4px;
overflow: hidden;
.map-search {
display: flex;
padding: 8px 0;
justify-content: space-between;
::v-deep .el-input__inner {
color: #fff;
}
}
.member-list {
width: 100%;
height: calc(100% - 44px - 28px);
overflow: auto;
padding: 0;
margin: 0;
li {
width: 100%;
height: 32px;
display: flex;
padding: 0 8px;
align-items: center;
color: #fff;
margin: 0;
cursor: pointer;
span {
padding-right: 8px;
}
}
.active {
background: #1d2336;
}
&::-webkit-scrollbar {
/*滚动条整体样式*/
width: 10px; /*高宽分别对应横竖滚动条的尺寸*/
height: 1px;
}
&::-webkit-scrollbar-thumb {
/*滚动条里面小方块*/
border-radius: 10px;
box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
background: #1a1e2c;
}
&::-webkit-scrollbar-track {
/*滚动条里面轨道*/
box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
border-radius: 10px;
background: #ededed;
background: #282f45;
}
}
.empty {
padding: 20px 0;
color: #7a88bb;
text-align: center;
}
.header {
width: 100%;
height: 28px;
padding: 0 16px;
box-sizing: border-box;
display: flex;
align-items: center;
color: #fff;
justify-content: space-between;
font-size: 14px;
background: #3e4a69;
}
.input {
width: 100%;
padding: 8px 0;
::v-deep .el-input__inner {
color: #fff;
}
}
::v-deep .el-input__inner {
background-color: #282f45;
border: 1px solid #282f45;
}
.tree-div {
width: 100%;
height: calc(100% - 44px - 28px);
overflow: auto;
&::-webkit-scrollbar {
/*滚动条整体样式*/
width: 10px; /*高宽分别对应横竖滚动条的尺寸*/
height: 1px;
}
&::-webkit-scrollbar-thumb {
/*滚动条里面小方块*/
border-radius: 10px;
box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
background: #1a1e2c;
}
&::-webkit-scrollbar-track {
/*滚动条里面轨道*/
box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
border-radius: 10px;
background: #ededed;
background: #282f45;
}
}
footer {
width: 100%;
height: 32px;
background-color: #fff;
display: flex;
align-items: center;
span {
width: 33.33%;
text-align: center;
cursor: pointer;
}
}
::v-deep .el-tree {
width: 100%;
.el-tree__empty-block {
background: #333c53;
}
.el-tree-node__label {
color: #fff;
}
.el-tree-node__content {
background: #333c53;
}
.is-current > .el-tree-node__content {
.el-tree-node__label {
color: #5088ff;
}
}
}
}
}
}
.hide {
left: -280px;
opacity: 0;
visibility: hidden;
}
.btn {
position: absolute;
top: 100px;
}
}
</style>
<style lang="scss">
.map {
.info {
width: 280px;
height: 98px;
background: #fff;
padding: 8px 0 0 12px;
box-sizing: border-box;
p {
margin: 0;
padding: 0;
}
p {
line-height: 20px;
.name {
color: #333;
font-size: 16px;
font-weight: bold;
}
.lat {
font-size: 12px;
color: #999;
}
}
.address {
color: #999;
line-height: 40px;
font-size: 12px;
cursor: pointer;
}
}
.title_info {
width: 68px;
font-size: 14px;
font-weight: bold;
height: 20px;
text-align: center;
line-height: 20px;
border-radius: 4px;
padding: 0;
margin: 0;
}
.amap-marker-label {
border: 1px solid rgb(141, 139, 139);
background-color: #fff;
}
}
</style>