企微迁移智慧监护(手环)

This commit is contained in:
aixianling
2022-05-17 09:12:29 +08:00
parent 9a3aab86d0
commit f5a1cd7424
10 changed files with 5 additions and 4 deletions

View File

@@ -0,0 +1,461 @@
<template>
<section class="gsLocation">
<ai-map class="fill" :map.sync="amap" :lib.sync="mapLib"/>
<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>
<img :src="`${$cdn}guardianship/tx.png`" @tap="handleShowDetail(selected)"/>
<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 AiSearchPopup from "../../components/AiSearchPopup";
import {mapState} from "vuex";
import UPopup from "../../uview/components/u-popup/u-popup";
import MakeCalls from "./component/makeCalls";
import OpenMap from "./component/openMap";
import AiMap from "../../components/AiMap";
export default {
name: "gsLocation",
components: {AiMap, OpenMap, MakeCalls, UPopup, AiSearchPopup},
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) {
return `${this.$cdn}guardianship/${icon}.png`
},
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>