2021-11-15 10:29:05 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<section class="gsLocation">
|
2022-05-18 09:40:21 +08:00
|
|
|
|
<AiMap class="fill" :map.sync="amap" :lib.sync="mapLib"/>
|
2021-11-15 10:29:05 +08:00
|
|
|
|
<div class="searchZone">
|
|
|
|
|
|
<u-search v-model="search" placeholder="请输入姓名" shape="square" bg-color="#fff"
|
|
|
|
|
|
:show-action="false" @search="getList()"/>
|
|
|
|
|
|
<div class="searchResult" v-if="searchResult">
|
|
|
|
|
|
<div class="item" v-for="row in list" :key="row.id" @tap="handleSelect(row)">
|
|
|
|
|
|
<img :src="cdn(row.onlineStatus==1?'zxtx':'lxtx')"/>
|
|
|
|
|
|
<div flex class="column fill">
|
|
|
|
|
|
<b v-html="searchName(row.name)"/>
|
|
|
|
|
|
<div v-text="row.gpsDesc"/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<u-popup v-model="popup" mode="bottom" :mask="false">
|
|
|
|
|
|
<div class="headerIcon" flex @touchstart="handleTouchStart" @touchmove="handleTouchmoveClose"/>
|
|
|
|
|
|
<div class="selectedInfo">
|
|
|
|
|
|
<div class="header" flex>
|
2022-05-18 14:18:39 +08:00
|
|
|
|
<img :src="`${$cdn}AppGuardianship/tx.png`" @tap="handleShowDetail(selected)"/>
|
2021-11-15 10:29:05 +08:00
|
|
|
|
<b v-text="selected.name" @tap="handleShowDetail(selected)"/>
|
|
|
|
|
|
<div v-if="selected.abnormalStatus==1" class="abnormal" @tap="handleShowDetail(selected)">异常</div>
|
|
|
|
|
|
<u-icon name="arrow-right" color="#ddd" class="fill" @tap="handleShowDetail(selected)"/>
|
|
|
|
|
|
<make-calls :list="phoneList"/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div flex class="spb wrap">
|
|
|
|
|
|
<div class="detail" v-for="(op,i) in quotas" :key="i" flex>
|
|
|
|
|
|
<img :src="op.icon"/>
|
|
|
|
|
|
<div class="fill" v-text="op.label"/>
|
|
|
|
|
|
<div :class="{abnormal:op.abnormal}" v-text="op.value"/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="navigation">
|
|
|
|
|
|
<div class="content" flex>
|
|
|
|
|
|
<div flex class="spb wrap">
|
|
|
|
|
|
<div class="fill" v-text="selected.gpsDesc"/>
|
|
|
|
|
|
<span>最后更新:{{ selected.lastUpdateTime }}</span>
|
|
|
|
|
|
<div class="battery" flex>
|
|
|
|
|
|
<img :src="batteryIcon"/>
|
|
|
|
|
|
<div v-text="`剩余${selected.electricQuantity}%`"/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<open-map :data="selected"/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</u-popup>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</section>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
|
import {mapState} from "vuex";
|
|
|
|
|
|
import MakeCalls from "./component/makeCalls";
|
|
|
|
|
|
import OpenMap from "./component/openMap";
|
|
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
|
name: "gsLocation",
|
2022-05-17 10:19:56 +08:00
|
|
|
|
components: {OpenMap, MakeCalls},
|
2021-11-15 10:29:05 +08:00
|
|
|
|
computed: {
|
|
|
|
|
|
...mapState(['user']),
|
|
|
|
|
|
markers() {
|
|
|
|
|
|
return this.list.filter(e => e.lng).map(e => {
|
|
|
|
|
|
let abnormal = 'offline'
|
|
|
|
|
|
if (e.onlineStatus == 1) {
|
|
|
|
|
|
switch (e.abnormalStatus) {
|
|
|
|
|
|
case '1':
|
|
|
|
|
|
abnormal = 'warning';
|
|
|
|
|
|
break;
|
|
|
|
|
|
case '2':
|
|
|
|
|
|
abnormal = 'abnormal';
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
abnormal = ''
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return new this.mapLib.Marker({
|
|
|
|
|
|
position: new this.mapLib.LngLat(e.lng, e.lat),
|
|
|
|
|
|
anchor: 'bottom-center',
|
|
|
|
|
|
content: `<div class="marker ${abnormal}">${e.name}</div>`,
|
|
|
|
|
|
extData: e,
|
|
|
|
|
|
topWhenClick: true
|
|
|
|
|
|
}).on('click', () => {
|
|
|
|
|
|
this.handleSelect(e)
|
|
|
|
|
|
})
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
|
|
|
|
|
quotas() {
|
|
|
|
|
|
let quota = [
|
|
|
|
|
|
{key: "0", icon: "1"},
|
|
|
|
|
|
{key: "1", icon: "2"},
|
|
|
|
|
|
{key: "2", icon: "3"},
|
|
|
|
|
|
{key: "3", icon: "4"},
|
|
|
|
|
|
]
|
|
|
|
|
|
return quota.map(e => {
|
|
|
|
|
|
let item = this.detail.find(d => d.item == e.key)
|
|
|
|
|
|
let label = this.$dict.getLabel('intelligentGuardianshipItem', e.key)
|
|
|
|
|
|
return {
|
|
|
|
|
|
label, icon: this.cdn(e.icon),
|
|
|
|
|
|
value: item?.itemValue || "-",
|
|
|
|
|
|
abnormal: item?.abnormalStatus == 1
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
|
|
|
|
|
batteryIcon() {
|
|
|
|
|
|
return this.cdn(this.selected.electricQuantity == 100 ? 'dcm' : 'dcq')
|
|
|
|
|
|
},
|
|
|
|
|
|
phoneList() {
|
|
|
|
|
|
let {name: guardianName, phone: guardianPhone} = this.selected
|
|
|
|
|
|
return [{guardianName, guardianPhone}, ...(this.selected.guardians || [])]
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
data() {
|
|
|
|
|
|
return {
|
|
|
|
|
|
mapLib: null,
|
|
|
|
|
|
amap: null,
|
|
|
|
|
|
search: "",
|
|
|
|
|
|
selected: {},
|
|
|
|
|
|
list: [],
|
|
|
|
|
|
popup: false,//被监护人信息弹窗
|
|
|
|
|
|
detail: [],
|
|
|
|
|
|
moveDistance: 0,
|
|
|
|
|
|
searchResult: false //搜索下拉弹窗
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
watch: {
|
|
|
|
|
|
amap(v) {
|
|
|
|
|
|
v && this.getList().then(() => {
|
|
|
|
|
|
this.amap?.add(this.markers)
|
|
|
|
|
|
this.getMapArea()
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
methods: {
|
|
|
|
|
|
cdn(icon) {
|
2022-05-18 14:42:54 +08:00
|
|
|
|
return `${this.$cdn}AppGuardianship/${icon}.png`
|
2021-11-15 10:29:05 +08:00
|
|
|
|
},
|
|
|
|
|
|
getMapArea() {
|
|
|
|
|
|
if (this.mapLib) {
|
|
|
|
|
|
new this.mapLib.DistrictSearch({
|
|
|
|
|
|
subdistrict: 0, //获取边界不需要返回下级行政区
|
|
|
|
|
|
extensions: 'all', //返回行政区边界坐标组等具体信息
|
|
|
|
|
|
level: 'district' //查询行政级别为 市
|
|
|
|
|
|
}).search(this.user.areaId.substring(0, 6), (status, result) => {
|
|
|
|
|
|
let bounds = result?.districtList?.[0]?.boundaries;
|
|
|
|
|
|
let polygons = []
|
|
|
|
|
|
bounds?.forEach(path => polygons.push(new this.mapLib.Polygon({
|
|
|
|
|
|
strokeWeight: 1,
|
|
|
|
|
|
path,
|
|
|
|
|
|
strokeStyle: 'dashed',
|
|
|
|
|
|
fillOpacity: 0.1,
|
|
|
|
|
|
fillColor: '#80d8ff',
|
|
|
|
|
|
strokeColor: '#0091ea'
|
|
|
|
|
|
})))
|
|
|
|
|
|
this.amap.add(polygons)
|
|
|
|
|
|
this.amap.setFitView();//视口自适应
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
getList() {
|
|
|
|
|
|
this.searchResult = !!this.search
|
|
|
|
|
|
return this.$http.post("/app/appintelligentguardianshipdevice/list", null, {
|
|
|
|
|
|
params: {name: this.search, size: 999, areaId: this.user.areaId}
|
|
|
|
|
|
}).then(res => {
|
|
|
|
|
|
if (res?.data) {
|
|
|
|
|
|
this.list = res.data.records
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
|
|
|
|
|
getDetail(deviceId) {
|
|
|
|
|
|
this.$http.post("/app/appintelligentguardianshipdevice/queryMonitorList", null, {
|
|
|
|
|
|
params: {type: 1, deviceId}
|
|
|
|
|
|
}).then(res => {
|
|
|
|
|
|
if (res?.data) {
|
|
|
|
|
|
this.detail = res.data.records
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
this.$http.post("/app/appintelligentguardianshipdevice/queryDetailById", null, {
|
|
|
|
|
|
params: {id: deviceId}
|
|
|
|
|
|
}).then(res => {
|
|
|
|
|
|
if (res?.data) {
|
|
|
|
|
|
this.selected = {...this.selected, ...res.data}
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
|
|
|
|
|
searchName(name) {
|
|
|
|
|
|
return name?.replace(this.search, `<span>${this.search}</span>`)
|
|
|
|
|
|
},
|
|
|
|
|
|
handleSelect(e) {
|
|
|
|
|
|
this.amap.setCenter(new this.mapLib.LngLat(e.lng, e.lat))
|
|
|
|
|
|
this.selected = e
|
|
|
|
|
|
this.popup = true
|
|
|
|
|
|
this.searchResult = false
|
|
|
|
|
|
this.getDetail(e.id)
|
|
|
|
|
|
},
|
|
|
|
|
|
handleShowDetail(user) {
|
|
|
|
|
|
uni.navigateTo({url: `./userDetail?id=${user.id}`})
|
|
|
|
|
|
},
|
|
|
|
|
|
handleTouchmoveClose(e) {
|
|
|
|
|
|
if (e.touches?.[0]?.clientY > this.moveDistance + 10) {
|
|
|
|
|
|
this.popup = false
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
handleTouchStart(e) {
|
|
|
|
|
|
this.moveDistance = e.touches?.[0]?.clientY
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
|
.gsLocation {
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
|
|
|
|
|
|
a {
|
|
|
|
|
|
color: inherit;
|
|
|
|
|
|
text-decoration: none;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
height: 112px;
|
|
|
|
|
|
border-top: 1px solid #d8dde6;
|
|
|
|
|
|
|
|
|
|
|
|
&:first-of-type {
|
|
|
|
|
|
border-top: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.headerIcon {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 60px;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
|
|
|
|
|
|
&:before {
|
|
|
|
|
|
content: " ";
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
width: 64px;
|
|
|
|
|
|
height: 10px;
|
|
|
|
|
|
background: #CCCCCC;
|
|
|
|
|
|
border-radius: 5px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
::v-deep .makeCalls {
|
|
|
|
|
|
.option:last-of-type {
|
|
|
|
|
|
margin-bottom: 120px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
::v-deep .selectedInfo {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
border-radius: 20px 20px 0 0;
|
|
|
|
|
|
padding: 0 32px;
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
|
|
|
|
|
|
.header {
|
|
|
|
|
|
margin-bottom: 40px;
|
|
|
|
|
|
font-size: 40px;
|
|
|
|
|
|
|
|
|
|
|
|
& > img {
|
|
|
|
|
|
width: 82px;
|
|
|
|
|
|
height: 82px;
|
|
|
|
|
|
margin-right: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.abnormal {
|
|
|
|
|
|
color: #FF4466;
|
|
|
|
|
|
font-size: 24px;
|
|
|
|
|
|
padding: 12px;
|
|
|
|
|
|
background: rgba(#EC4461, .1);
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
margin: 0 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
span {
|
|
|
|
|
|
margin-left: 0;
|
|
|
|
|
|
color: #999;
|
|
|
|
|
|
font-size: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.detail {
|
|
|
|
|
|
width: 318px;
|
|
|
|
|
|
height: 84px;
|
|
|
|
|
|
background: #F4F5F6;
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
padding: 0 24px;
|
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
margin-bottom: 36px;
|
|
|
|
|
|
|
|
|
|
|
|
img {
|
|
|
|
|
|
margin-right: 16px;
|
|
|
|
|
|
width: 56px;
|
|
|
|
|
|
height: 56px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.abnormal {
|
|
|
|
|
|
color: #FF4466;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.navigation {
|
|
|
|
|
|
padding-bottom: 100px;
|
|
|
|
|
|
|
|
|
|
|
|
.content {
|
|
|
|
|
|
padding: 32px 40px;
|
|
|
|
|
|
font-size: 26px;
|
|
|
|
|
|
|
|
|
|
|
|
& > .spb {
|
|
|
|
|
|
margin-right: 40px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.fill {
|
|
|
|
|
|
min-width: 100%;
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
span {
|
|
|
|
|
|
margin-left: 0;
|
|
|
|
|
|
color: #999;
|
|
|
|
|
|
font-size: 22px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.battery > img {
|
|
|
|
|
|
margin-right: 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&:before {
|
|
|
|
|
|
content: " ";
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 8px;
|
|
|
|
|
|
background: #F4F5F6;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
::v-deep .searchZone {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: 0;
|
|
|
|
|
|
z-index: 2;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
background: transparent;
|
|
|
|
|
|
padding: 24px 16px;
|
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
|
|
|
|
|
|
.u-search {
|
|
|
|
|
|
box-shadow: 0 4px 8px 0 rgba(192, 185, 185, 0.5);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.searchResult {
|
|
|
|
|
|
margin-top: 16px;
|
|
|
|
|
|
padding: 0 28px;
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
|
|
|
|
|
|
.item {
|
|
|
|
|
|
font-size: 24px;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
line-height: 36px;
|
|
|
|
|
|
padding: 24px 0;
|
|
|
|
|
|
border-bottom: 3px solid #DEDFE1;
|
|
|
|
|
|
|
|
|
|
|
|
&:last-of-type {
|
|
|
|
|
|
border-bottom: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
img {
|
|
|
|
|
|
width: 36px;
|
|
|
|
|
|
height: 36px;
|
|
|
|
|
|
margin-right: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
& > .fill {
|
|
|
|
|
|
align-items: unset;
|
|
|
|
|
|
|
|
|
|
|
|
b > span {
|
|
|
|
|
|
color: #1365DD;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
& > div {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
::v-deep .marker {
|
|
|
|
|
|
color: #fff;
|
|
|
|
|
|
font-size: 30px;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
padding: 0 32px;
|
|
|
|
|
|
height: 56px;
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
background: #5088FF;
|
|
|
|
|
|
border-color: #5088FF;
|
|
|
|
|
|
border-radius: 52px;
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
&:after {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
content: " ";
|
|
|
|
|
|
bottom: -12px;
|
|
|
|
|
|
left: 50%;
|
|
|
|
|
|
transform: translateX(-50%);
|
|
|
|
|
|
border: 12px solid transparent;
|
|
|
|
|
|
border-bottom: none;
|
|
|
|
|
|
height: 0;
|
|
|
|
|
|
width: 0;
|
|
|
|
|
|
border-top-color: inherit;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&.offline {
|
|
|
|
|
|
background: #C4CAD4;
|
|
|
|
|
|
border-color: #C4CAD4;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&.warning {
|
|
|
|
|
|
background: #FFAA44;
|
|
|
|
|
|
border-color: #FFAA44;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&.abnormal {
|
|
|
|
|
|
background: #F46159;
|
|
|
|
|
|
border-color: #F46159;
|
|
|
|
|
|
|
|
|
|
|
|
&:before {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
z-index: -1;
|
|
|
|
|
|
bottom: -40px;
|
|
|
|
|
|
width: 80px;
|
|
|
|
|
|
height: 80px;
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
background-color: #F46159;
|
|
|
|
|
|
transform: translate(-50%, -50%);
|
|
|
|
|
|
animation: mapWarn 1s ease-out 0s infinite;
|
|
|
|
|
|
content: " ";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.AiMap {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|