<template>
|
<view class="pages-main">
|
<uni-nav-bar :fixed="true" status-bar right-text="" left-text="" :leftWidth="0" rightWidth="72px"
|
:title="navigationBarTitle">
|
<view class="uni-navbar-container-inner">
|
<text class="uni-nav-bar-text">{{navigationBarTitle }}</text>
|
</view>
|
<template v-slot:right>
|
<view v-if="currentPage < pageList.length">
|
<a @click="clickScanCode">
|
<uni-icons class="uni-panel-bar-icon" type="scan" size="28"></uni-icons>
|
</a>
|
<a @click="clickMore">
|
<uni-icons class="uni-panel-bar-icon" type="more-filled" size="28"></uni-icons>
|
</a>
|
</view>
|
|
</template>
|
</uni-nav-bar>
|
<swiper v-if="pageList.length > 0" circular indicator-dots class="swiper" :current="currentPage"
|
@change="changeSwiper">
|
<swiper-item v-for="(page,index) in pageList" class="swiper-item">
|
<view class="vehicle-header">
|
<view class="link-view">
|
<view v-if="page.link_status">
|
<!-- <image class="img-battery-charging" src="/images/bx_battery3.svg" alt="SVG 图片" /> -->
|
<image class="img-battery-charging" src="/images/bx_battery2.svg" alt="SVG 图片" />
|
<image class="img-battery-soc" :style="{width:(page.soc*0.4)+'rpx'}"
|
src="/images/bx_battery4.svg" alt="SVG 图片" />
|
|
</view>
|
<view v-else>
|
<image class="img-battery" src="/images/bx_battery1.svg" alt="SVG 图片" />
|
</view>
|
<template v-if="page.link_status">
|
<view class="soc-text">{{page.soc}}%</view>
|
<view class="status-text">{{getAgvStateText(page)}}</view>
|
</template>
|
|
|
<view v-else class="gray-text">已离线</view>
|
</view>
|
</view>
|
<image class="vehicle-img " :class="page.link_status ?'':'gray-image'" mode="aspectFit"
|
src="/images/image 11.png" alt="图片" />
|
<view v-if="page.link_status" class="img-button-group">
|
<view type="primary" class="img-text-button" @click="clickToTask(index,page)">
|
<a-button class="img-button" color='primary' disabled>
|
<text class="ico task-list" />
|
</a-button>
|
<text>任务列表</text>
|
</view>
|
<view type="primary" plain="true" class="img-text-button" @click="clickToMap(index,page)">
|
<a-button class="img-button" color='primary'>
|
<text class="ico map" />
|
</a-button>
|
<text>进入地图</text>
|
|
</view>
|
</view>
|
<view v-else class="unlink-content">
|
<view class="content2" v-if="page.conntecting">
|
<view class="auto-circle"></view>
|
|
<view class="text">连接中...</view>
|
</view>
|
<view class="content2" v-else>
|
<view class="text"> 车辆已离线,请重新连接</view>
|
<a-button type="primary" class="button" @click="clickRelink">重新连接
|
</a-button>
|
</view>
|
|
</view>
|
|
|
</swiper-item>
|
<swiper-item class="swiper-item">
|
|
<image class="title-img gray-image" src="/images/image 15.png" alt="图片" />
|
<view class="button-group">
|
<a-button type="primary" class="button" @click="clickScanCode">扫描添加设备</a-button>
|
<a-button type="ghost" class="button" @click="clickManualAdd">手动添加设备</a-button>
|
</view>
|
</swiper-item>
|
</swiper>
|
<view v-else class="no-page items-center">
|
<view class="content ">
|
<image class="title-img gray-image" src="/images/image 15.png" alt="图片" />
|
<view class="button-group">
|
<a-button type="primary" class="button" @click="clickScanCode">扫描添加设备</a-button>
|
<a-button type="ghost" class="button" @click="clickManualAdd">手动添加设备</a-button>
|
</view>
|
</view>
|
</view>
|
<view>
|
<uni-popup ref="refPopupInput" type="dialog">
|
<uni-popup-dialog mode="input" title="输入车辆IP" :value="inputPopupValue" placeholder="车辆IP"
|
:beforeClose="true" @confirm="dialogInputConfirm" @close="dialogInputClose"></uni-popup-dialog>
|
</uni-popup>
|
<!-- <uni-popup ref="refPopupMessage" type="dialog">
|
<uni-popup-dialog type="info" title="" :content="inputPopupValue"
|
@confirm="dialogMessageConfirm"></uni-popup-dialog>
|
</uni-popup> -->
|
<uni-popup ref="refPopupMenu" background-color="transparent" maskBackgroundColor="rgba(0, 0, 0, 0.2)">
|
<view class="popup-content" @click="closeMenu">
|
<view class="popup-content-menu ">
|
<a-button class="popup-content-menu-item" v-for="(item,index) in menuList" :key="index"
|
@click="menuItemChange(item)" :style="{'color':item.color}">
|
<view class="text">{{item.text}}</view>
|
<text class="ico" :class="item.ico" />
|
</a-button>
|
</view>
|
</view>
|
</uni-popup>
|
</view>
|
</view>
|
</template>
|
|
<script>
|
import {
|
ref
|
} from "vue";
|
import {
|
session,
|
showToast,
|
showModal
|
} from "@/comm/utils.js"
|
import {
|
mtBattery,
|
getAgvState,
|
checkIpLinkSuccess,
|
} from "@/api/vehicle.js"
|
import {
|
Button
|
} from 'antd-mobile-vue-next'
|
import {
|
async
|
} from "rxjs";
|
export default {
|
name: "PagesMain",
|
components: {
|
'a-button': Button
|
},
|
data() {
|
return {
|
navigationBarTitle: "",
|
currentPage: 0,
|
pageList: [],
|
timerBatteryId: 0,
|
inputPopupValue: "",
|
menuList: [{
|
ico: "edit-line",
|
text: "编辑",
|
color: "black"
|
}, {
|
ico: "update",
|
text: "更新",
|
color: "black"
|
}, {
|
ico: "book",
|
text: "教程",
|
color: "black"
|
}, {
|
ico: "share",
|
text: "共享",
|
color: "black"
|
}, {
|
ico: "copy",
|
text: "备份",
|
color: "black"
|
}, {
|
ico: "delete-outline",
|
text: "删除",
|
color: "red"
|
}]
|
|
}
|
},
|
onShow() {
|
console.log("show")
|
if (this.timerBatteryId) {
|
clearInterval(this.timerBatteryId)
|
}
|
setTimeout(() => {
|
this.loadVehicleBattery()
|
}, 2000)
|
this.timerBatteryId = setInterval(() => {
|
this.loadVehicleBattery()
|
}, 60 * 1000)
|
|
},
|
onHide() {
|
if (this.timerBatteryId) {
|
clearInterval(this.timerBatteryId)
|
this.timerBatteryId = 0
|
}
|
},
|
onLoad(option) {
|
const ip = option.connectedIp || ""
|
this.loadData(ip)
|
console.log("hide")
|
},
|
computed: {
|
|
},
|
methods: {
|
setData(obj) {
|
let that = this;
|
let keys = [];
|
let val, data;
|
|
Object.keys(obj).forEach(function(key) {
|
keys = key.split(".");
|
val = obj[key];
|
data = that.$data;
|
keys.forEach(function(key2, index) {
|
if (index + 1 == keys.length) {
|
that.$set(data, key2, val);
|
} else {
|
if (!data[key2]) {
|
that.$set(data, key2, {});
|
}
|
}
|
data = data[key2];
|
});
|
});
|
},
|
async loadData(ip) {
|
|
try {
|
|
let list = session.getValue("vehicles") || []
|
|
list.forEach((page) => {
|
page.soc = 0
|
page.link_status = false
|
})
|
let curIndex = -1
|
if (ip)
|
curIndex = list.findIndex((a) => a.ip == ip)
|
if (curIndex < 0) {
|
|
this.pageList = list
|
if (this.pageList.length > 0)
|
this.navigationBarTitle = this.pageList[0].name
|
else
|
this.navigationBarTitle = "添加设备"
|
for (let i in list) {
|
const page = list[i]
|
const battery = await this.loadMTBattery(page.ip)
|
if (battery > -1) {
|
page.soc = battery
|
page.status = await this.loadAgvState(page.ip)
|
page.link_status = true
|
this.setData({
|
currentPage: i
|
})
|
break
|
}
|
}
|
|
this.pageList = [...list]
|
} else {
|
this.setData({
|
currentPage: curIndex
|
})
|
const page = list[curIndex]
|
const battery = await this.loadMTBattery(page.ip)
|
if (battery > -1) {
|
page.soc = battery
|
page.link_status = true
|
page.status = await this.loadAgvState(page.ip)
|
} else {
|
page.link_status = false
|
}
|
|
this.pageList = [...list]
|
this.navigationBarTitle = page.name
|
}
|
} catch (ex) {
|
|
this.showError(ex)
|
}
|
},
|
|
async loadVehicleBattery() {
|
try {
|
|
const list = this.pageList
|
if (this.currentPage < list.length && this.currentPage > -1) {
|
const page = list[this.currentPage]
|
const battery = await this.loadMTBattery(page.ip)
|
if (battery > -1) {
|
page.soc = battery
|
page.status = await this.loadAgvState(page.ip)
|
page.link_status = true
|
|
} else {
|
page.soc = 0
|
page.link_status = false
|
}
|
}
|
this.pageList = [...list]
|
|
} catch (ex) {
|
this.showError(ex)
|
}
|
|
},
|
async loadMTBattery(ip) {
|
try {
|
let battery = await mtBattery(ip)
|
let str = `${battery}`
|
str = str.trim()
|
str = str.replace("%", "")
|
battery = parseInt(str)
|
return battery
|
} catch (ex) {
|
|
return -1
|
}
|
|
},
|
|
|
async loadAgvState(ip) {
|
try {
|
let info = await getAgvState(ip)
|
return info.status || 0
|
} catch (ex) {
|
|
return 0
|
}
|
|
},
|
getAgvStateText(page) {
|
let text = ""
|
if (page.status == 1) {
|
text = "空闲中"
|
} else if (page.status == 2) {
|
text = "工作中"
|
} else if (page.status == 3) {
|
text = "故障"
|
} else {
|
text = `状态${page.status}`
|
}
|
return text
|
},
|
async checkPageConnected(index) {
|
try {
|
const list = this.pageList
|
const page = list[index]
|
let battery = await this.loadMTBattery(page.ip)
|
if (battery > -1) {
|
page.soc = battery
|
page.link_status = true
|
page.status = await this.loadAgvState(page.ip)
|
} else {
|
page.link_status = false
|
}
|
this.pageList = [...list]
|
} catch (ex) {
|
|
|
}
|
|
},
|
changeSwiper(evt) {
|
|
let index = evt.target.current || evt.detail.current;
|
this.setData({
|
currentPage: index
|
})
|
if (this.pageList.length == this.currentPage)
|
this.navigationBarTitle = "添加设备"
|
else
|
this.navigationBarTitle = this.pageList[this.currentPage].name
|
},
|
async clickRelink() {
|
try {
|
|
const page = this.pageList[this.currentPage]
|
page.conntecting = true
|
let res = await this.checkConnectSuccess(page.ip)
|
if (!res) {
|
page.conntecting = false
|
uni.navigateTo({
|
url: `/pages/index/connect?ip=${ page.ip}&sid=${ page.wifi?.sid || ""}&reconnect=true`
|
})
|
} else {
|
page.conntecting = false
|
const list = this.pageList
|
list.forEach((page2) => {
|
if (page.ip != page2.ip) {
|
page2.soc = 0
|
page2.link_status = false
|
}
|
})
|
page.connectState = 2
|
const battery = await this.loadMTBattery(page.ip)
|
if (battery > -1) {
|
page.soc = battery
|
page.link_status = true
|
page.status = await this.loadAgvState(page.ip)
|
this.setData({
|
pageList: list
|
})
|
}
|
}
|
} catch (ex) {
|
this.showError(ex)
|
}
|
},
|
async checkConnectSuccess(ip) {
|
try {
|
const res = await checkIpLinkSuccess(ip)
|
return true
|
} catch (ex) {
|
return false
|
}
|
|
},
|
|
|
clickScanCode() {
|
const that = this
|
uni.scanCode({
|
scanType: ["qrCode"],
|
success: function(res) {
|
console.log(res)
|
const result = res.result || ""
|
const arCode = result.split(";")
|
if (arCode.length != 3) {
|
showToast("无效的二维码!")
|
return
|
}
|
let ip = arCode[0].trim()
|
if (!ip || !arCode[0].trim()) {
|
showToast("无效的二维码!")
|
return
|
}
|
const curIndex = that.pageList.findIndex((a) => a.ip == ip)
|
if (curIndex < 0) {
|
if (that.pageList.length === 3) {
|
showToast("对多只允许添加3辆车!")
|
return
|
}
|
uni.navigateTo({
|
url: `/pages/index/connect?ip=${ ip}&sid=${ arCode[1]}&password=${ arCode[2]}`
|
})
|
} else {
|
showToast("不允许添加相同IP的设备!")
|
}
|
},
|
})
|
|
},
|
clickManualAdd() {
|
this.inputPopupValue = ""
|
this.$refs.refPopupInput.open()
|
},
|
clickToTask(index, page) {
|
showToast("该功能还在开发中")
|
// uni.navigateTo({
|
// url: `/pages/task/index?ip=${page.ip}`
|
// })
|
},
|
clickMore() {
|
if (this.currentPage < this.pageList.length) {
|
this.$refs.refPopupMenu.open("top")
|
}
|
|
},
|
clickInfo(page) {
|
const that = this
|
uni.navigateTo({
|
url: `/pages/index/detail?param=${JSON.stringify(page)}`,
|
events: {
|
// 为指定事件添加一个监听器,获取被打开页面传送到当前页面的数据
|
delete_vehicle: function(data) {
|
const list = that.pageList
|
const index = that.currentPage
|
list.splice(index, 1)
|
that.setData({
|
currentPage: index,
|
pageList: list
|
})
|
session.setValue("vehicles", list)
|
if (list.length > 0)
|
that.navigationBarTitle = that.pageList[that.currentPage].name
|
else
|
that.navigationBarTitle = "添加设备"
|
},
|
update_vehicle: function(data) {
|
console.log("update_vehicle", data)
|
const list = that.pageList
|
Object.assign(list[that.currentPage], data)
|
that.setData({
|
pageList: list
|
})
|
session.setValue("vehicles", list)
|
that.navigationBarTitle = list[that.currentPage].name
|
},
|
}
|
})
|
},
|
|
clickToMap(index, page) {
|
const _this = this
|
uni.navigateTo({
|
url: `/pages/map/index?ip=${page.ip}`,
|
events: {
|
// 为指定事件添加一个监听器,获取被打开页面传送到当前页面的数据
|
check_connect: function(flag) {
|
page.link_status = flag
|
_this.checkPageConnected(index)
|
},
|
}
|
})
|
},
|
isValidIP(ip) {
|
// IPv4 地址正则表达式
|
const ipRegex =
|
/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
|
|
// 检查是否符合 IPv4 地址格式
|
return ipRegex.test(ip);
|
},
|
dialogInputConfirm(val) {
|
|
let text = val.trim()
|
if (!text) {
|
showToast("请输入车辆IP!")
|
this.$refs.refPopupInput.open()
|
return
|
}
|
if (!this.isValidIP(text)) {
|
showToast("IP无效!")
|
this.$refs.refPopupInput.open()
|
return
|
}
|
|
|
this.$refs.refPopupInput.close()
|
|
const curIndex = this.pageList.findIndex((a) => a.ip == text)
|
if (curIndex < 0) {
|
if (this.pageList.length === 3) {
|
showToast("对多只允许添加3辆车!")
|
return
|
}
|
uni.navigateTo({
|
url: `/pages/index/connect?ip=${text}`
|
})
|
} else {
|
showToast("不允许添加相同IP的设备!")
|
return
|
}
|
|
|
},
|
dialogInputClose() {
|
this.$refs.refPopupInput.close()
|
},
|
menuItemChange(item) {
|
if (item.text == "编辑") {
|
const page = this.pageList[this.currentPage]
|
this.clickInfo(page)
|
|
} else if (item.text == "删除") {
|
const page = this.pageList[this.currentPage]
|
showModal(`确定要删除设备“${ page.name}”吗`, "警告").then((res) => {
|
if (res) {
|
const list = this.pageList
|
const curPage = this.currentPage
|
list.splice(this.currentPage, 1)
|
this.setData({
|
currentPage: curPage,
|
pageList: list
|
})
|
session.setValue("vehicles", list)
|
if (list.length > 0)
|
this.navigationBarTitle = this.pageList[this.currentPage].name
|
else
|
this.navigationBarTitle = "添加设备"
|
|
}
|
})
|
}
|
},
|
showError(ex) {
|
let exStr = JSON.stringify(ex)
|
if (exStr == "{}")
|
exStr = ex
|
let tip = typeof ex.msg == "string" ? ex.msg : exStr
|
showModal(tip, "错误", false)
|
},
|
closeMenu() {
|
this.$refs.refPopupMenu.close()
|
}
|
}
|
}
|
</script>
|
|
<style lang="scss">
|
.pages-main {
|
display: flex;
|
width: 750rpx;
|
height: 100vh;
|
flex-direction: column;
|
font-size: 30rpx;
|
background-color: #fff;
|
|
.justify-center {
|
justify-content: center;
|
}
|
|
.items-center {
|
align-items: center
|
}
|
|
.swiper {
|
flex: 1;
|
width: 100%;
|
|
|
.swiper-item {
|
width: 100%;
|
height: 100vh;
|
display: flex;
|
flex-direction: column;
|
|
.vehicle-header {
|
|
width: 700rpx;
|
margin-left: 20rpx;
|
|
|
.link-view {
|
width: 100%;
|
height: 80rpx;
|
position: relative;
|
|
.img-battery {
|
position: absolute;
|
left: 0;
|
width: 64rpx;
|
height: 64rpx;
|
}
|
|
.img-battery-charging {
|
position: absolute;
|
left: 0;
|
width: 65rpx;
|
height: 64rpx;
|
}
|
|
.img-battery-charging2 {
|
position: absolute;
|
left: 0;
|
width: 90rpx;
|
height: 64rpx;
|
}
|
|
.img-battery-soc {
|
position: absolute;
|
left: 10rpx;
|
top: 21rpx;
|
width: 40rpx;
|
height: 22rpx;
|
background-color: #73D13D;
|
}
|
|
.gray-text {
|
position: absolute;
|
left: 90rpx;
|
height: 72rpx;
|
line-height: 72rpx;
|
color: #ccc;
|
}
|
|
|
.soc-text {
|
border-width: 0px;
|
position: absolute;
|
left: 90rpx;
|
height: 72rpx;
|
line-height: 72rpx;
|
}
|
|
.status-text {
|
border-width: 0px;
|
position: absolute;
|
left: 160rpx;
|
height: 72rpx;
|
line-height: 72rpx;
|
}
|
|
.charge2 {
|
background-color: #fff;
|
}
|
|
}
|
}
|
|
|
.img-button-group {
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
flex-direction: row;
|
|
|
.img-text-button {
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
flex-direction: column;
|
margin: 50rpx;
|
|
.img-button {
|
display: flex;
|
width: 160rpx !important;
|
height: 160rpx !important;
|
align-items: center;
|
justify-content: center;
|
|
.ico {
|
font-size: 72rpx;
|
color: #1890FF;
|
}
|
|
|
}
|
|
text {
|
margin-top: 20rpx;
|
}
|
|
}
|
}
|
|
}
|
}
|
|
.no-page {
|
display: flex;
|
width: 100%;
|
flex: 1;
|
|
.content {
|
width: 750rpx;
|
display: flex;
|
flex-direction: column;
|
|
}
|
|
}
|
|
.title-img {
|
margin-top: 40rpx;
|
display: block;
|
margin-left: calc(50% - 180rpx);
|
width: 360rpx;
|
height: 500rpx;
|
}
|
|
.vehicle-img {
|
margin-top: 20rpx;
|
margin-left: calc(50% - 280rpx);
|
display: block;
|
width: 560rpx;
|
height: 560rpx;
|
|
}
|
|
.gray-image {
|
filter: grayscale(100%);
|
opacity: 0.5;
|
}
|
|
.unlink-content {
|
width: 100%;
|
flex: 1;
|
|
.content {
|
align-items: center;
|
text-align: center;
|
display: flex;
|
flex-direction: column;
|
font-size: 36rpx;
|
font-weight: 400;
|
}
|
|
.content2 {
|
margin: auto;
|
|
.auto-circle {
|
margin: auto;
|
width: 160rpx;
|
height: 160rpx;
|
border-radius: 50%;
|
border: 28rpx solid #1890FF;
|
border-top-color: transparent;
|
animation: drawCircle 1s infinite linear;
|
}
|
|
@keyframes drawCircle {
|
0% {
|
transform: rotate(0deg);
|
}
|
|
100% {
|
transform: rotate(360deg);
|
}
|
}
|
|
.text {
|
text-align: center;
|
margin-top: 20rpx;
|
margin-bottom: 20rpx;
|
}
|
|
}
|
|
}
|
|
.button-group {
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
flex-direction: column;
|
font-size: 30rpx !important;
|
}
|
|
.button {
|
margin: auto;
|
margin-top: 20rpx;
|
width: 320rpx !important;
|
border-radius: 4rpx;
|
}
|
|
.popup-content {
|
display: flex;
|
justify-content: center;
|
flex-direction: column;
|
background-color: transparent;
|
}
|
|
.popup-content-menu {
|
margin-top: 150rpx;
|
margin-left: calc(750rpx - 330rpx);
|
width: 320rpx;
|
align-items: center;
|
justify-content: center;
|
flex-direction: column;
|
background-color: #fff;
|
border-radius: 4rpx;
|
border: 2rpx solid gray;
|
}
|
|
.popup-content-menu-item {
|
display: flex;
|
flex-wrap: nowrap;
|
flex-direction: row !important;
|
align-items: center;
|
padding: 8rpx 16rpx;
|
font-size: 32rpx;
|
|
.text {
|
flex: 1;
|
}
|
|
.img {
|
width: 40rpx;
|
height: 40rpx;
|
margin: 10rpx;
|
}
|
}
|
|
|
|
}
|
</style>
|