<template>
|
<view class="pages-scene">
|
<view class="map-content" v-if="opSceneType =='' ">
|
<image v-if="opType != 'extend'" class="img" src="/images/image_25.png" alt=" 图片" mode="aspectFit" />
|
<image v-else class="img" :src="extendBase64Img" alt=" 图片" mode="aspectFit" />
|
<view v-if="opType != 'extend'" class="space">没有找到符合条件的地图</view>
|
<!-- <view class="loading-view">{{mapserverIsOk?"构图程序准备就绪":"等待构图程序就绪..."}}
|
<view v-if="!mapserverIsOk" class="auto-circle"></view>:disabled="!mapserverIsOk"
|
</view> -->
|
<view class="text-button-group">
|
<a-button type="primary" class="button" @click="clickStartConstructScene">
|
{{opType == 'extend'?"开始扩展":'开始构建'}}
|
</a-button>
|
<a-button v-if="opType != 'extend'" type="primary" class="button"
|
:disabled="loading && localSceneList.length == 0" @click="clickDownloadScene" disabled>
|
下载场景
|
</a-button>
|
</view>
|
|
</view>
|
<view class="content" v-show="opSceneType =='scan'">
|
<view class="fabric" :message="ctxDataStr" :change:message="ctx.receiveMsg" id="canvasMap"></view>
|
<view class="position" @click="clickVehiclePosition">
|
<text class="ico my-location-rounded"></text>
|
</view>
|
</view>
|
<view class="bottom">
|
<view class="bottom-content" v-if="opSceneType =='add_name' ">
|
<view class="tip">请输入场景名称</view>
|
<view class="name-input">
|
<input ref="refInputName" :focus="true" placeholder="请输入场景名称" :value="sceneName"
|
@input="onInputName" />
|
<uni-icons class="clear" color="#ccc" type="clear" size="20" v-if="showClearName"
|
@click="clickClearName"></uni-icons>
|
</view>
|
<view class="text-button-group">
|
<a-button type="primary" class="button" :disabled="loading || sceneName.trim() == ''"
|
@click="clickNameOK">确认</a-button>
|
<a-button type="ghost" class="button" :disabled="loading" @click="clickNameCancel">取消</a-button>
|
|
</view>
|
</view>
|
<view class="bottom-content" v-else-if="opSceneType =='scan'">
|
<view class="tip">场景构建中</view>
|
<view>
|
<!-- 请操作搬运车扫描地图覆盖的区域 -->
|
{{mapServerPhase=== 1 ?"场景构建服务:未启动":mapServerPhase===2 ?"场景构建服务:启动中":mapServerPhase===3 ?"场景构建中":mapServerPhase}}
|
</view>
|
|
<view class="text-button-group">
|
<a-button type="primary" class="button" :disabled="loading" @click="clickScanFinish">扫描完成</a-button>
|
</view>
|
</view>
|
<view class="bottom-content" v-else-if="opSceneType =='finish'">
|
<view class="tip"> “{{sceneName}}”{{opType == "extend"?"场景扩展结束"+"":"场景构建结束"}}</view>
|
<!-- <view> 已成功构建“{{sceneName}}”</view> -->
|
<view class="loading-view">
|
构图状态:{{mapServerPhase===5?"保存成功":mapServerPhase===4?"保存中":mapServerPhase===6?"保存失败":mapServerPhase}}
|
<view v-if="mapServerPhase === 4" class="auto-circle"></view>
|
</view>
|
<view class="text-button-group">
|
<a-button type="primary" class="button" v-if="mapServerPhase === 6"
|
@click="clickRecreate">{{opType == "extend"?"重现扩展":"重现构建"}}</a-button>
|
<a-button type="primary" class="button" v-else :disabled=" mapServerPhase !==5 || loading"
|
@click="clickFinish">{{opType == "extend"?"扩展完成":"构建完成"}}</a-button>
|
</view>
|
</view>
|
</view>
|
</view>
|
</template>
|
<script src="./js/ctx.js" module="ctx" lang="renderjs"></script>
|
|
<script>
|
import {
|
showToast,
|
showModal,
|
session,
|
showError,
|
showInfo
|
} from "@/comm/utils.js"
|
import {
|
Button
|
} from 'antd-mobile-vue-next'
|
|
import {
|
createScene,
|
addMap,
|
stopMap,
|
delScene,
|
//getAgvState,
|
getMapLaserData,
|
saveDBData,
|
// checkMapServerIsStart,
|
// startOrStopMapServer,
|
// checkMapServerIsOk,
|
// checkSaveMapIsOk,
|
getMapServerPhase,
|
getMapUrl
|
|
} from "@/api/vehicle.js"
|
export default {
|
name: "PagesScene",
|
components: {
|
'a-button': Button
|
},
|
data() {
|
return {
|
opType: "",
|
loading: false,
|
ip: "",
|
opSceneType: "",
|
windowWidth: 375,
|
sceneName: "",
|
showClearName: false,
|
mapId: "",
|
ctxDataStr: "[]",
|
localSceneList: [],
|
positioningAgv: true,
|
robotPos: {},
|
mapServerPhase: 1,
|
extendBase64Img: "",
|
saveMapIsOk: false,
|
destroyFlag: false,
|
|
}
|
},
|
computed: {
|
|
},
|
watch: {
|
|
},
|
onLoad(option) {
|
console.log("scene load")
|
const _this = this
|
this.ip = option.ip || ""
|
uni.getSystemInfo({
|
success(e) {
|
_this.windowWidth = e.windowWidth
|
},
|
|
})
|
this.sceneName = option.sceneId || ""
|
this.opType = option.opType || ""
|
this.opSceneType = ""
|
this.loadData()
|
|
},
|
onUnload() {
|
console.log("scene unload")
|
},
|
onBackPress() {
|
|
if (this.opSceneType == "scan") {
|
|
showModal("已构建场景将会被删除", "是否中断场景构建?").then((res) => {
|
if (res) {
|
this.opSceneType = ""
|
if (this.opType != "") {
|
|
uni.navigateBack({
|
delta: 1, //返回层数,2则上上页
|
})
|
}
|
|
}
|
})
|
return true
|
|
} else if (this.opSceneType == "finish") {
|
if (this.destroyFlag) {
|
|
const eventChannel = this.getOpenerEventChannel();
|
eventChannel.emit('create_finish', this.sceneName);
|
return false
|
} else {
|
this.ctxDataStr = JSON.stringify([{
|
method: "destroy",
|
}])
|
return true
|
}
|
|
} else {
|
if (this.destroyFlag)
|
return false
|
else {
|
this.ctxDataStr = JSON.stringify([{
|
method: "destroy",
|
}])
|
return true
|
}
|
}
|
|
},
|
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() {
|
try {
|
|
if (this.opType == "") {
|
this.localSceneList = await this.loadLocalScene()
|
} else {
|
if (this.opType == "create") {
|
this.opSceneType = "add_name"
|
}
|
if (this.opType == "extend") {
|
this.mapServerPhase = 1
|
await addMap(this.ip, this.sceneName, "extend")
|
this.checkMapServerPhase()
|
this.opSceneType = 'scan'
|
}
|
// if (this.opType == "extend") {
|
// // const infoMap = await this.loadMapInfo(this.sceneName)
|
// // if (infoMap.filedata) {
|
// // var base64Image = infoMap.filedata
|
// // if (base64Image.indexOf("data:image/png;base64,") < 0) {
|
// // base64Image = "data:image/png;base64," + infoMap.filedata
|
// // }
|
// // this.extendBase64Img = base64Image
|
// // }
|
|
// }
|
|
}
|
|
this.refreshMapLaserData()
|
|
|
} catch (ex) {
|
|
showError(ex)
|
}
|
},
|
async loadMapInfo(id) {
|
try {
|
const info = await getMapUrl(this.ip, id)
|
return info
|
} catch (ex) {
|
|
return {}
|
}
|
},
|
async checkMapServerPhase() {
|
try {
|
|
const res = await getMapServerPhase(this.ip)
|
this.mapServerPhase = res || 1
|
if (this.mapServerPhase === 3) {
|
return
|
}
|
if (this.mapServerPhase === 5 || this.mapServerPhase === 6) {
|
this.saveMapIsOk = true
|
return
|
}
|
setTimeout(this.checkMapServerPhase, 1000);
|
} catch (ex) {
|
showToast(ex)
|
setTimeout(this.checkMapServerPhase, 1000);
|
}
|
},
|
|
receiveRenderData(param) {
|
console.log('接收到视图层的数据:', param);
|
|
if (param.method === "destroy_complete") {
|
if (param.param) {
|
this.destroyFlag = true
|
uni.navigateBack({
|
delta: 1
|
})
|
}
|
} else if (param.method == "set_backgroud_progress") {
|
if (param.type == "start") {
|
this.setData({
|
bgProgressPercent: 50,
|
bgLoading: true
|
})
|
} else if (param.type == "progress") {
|
this.setData({
|
bgProgressPercent: 50 + (param.percent || 0) / 2
|
})
|
} else if (param.type == "end") {
|
this.setData({
|
bgProgressPercent: 100,
|
bgLoading: true
|
})
|
setTimeout(() => {
|
this.setData({
|
bgLoading: false
|
})
|
}, 500)
|
|
} else if (param.type == "error") {
|
console.log("set_backgroud_progress error")
|
this.setData({
|
bgProgressPercent: 0,
|
bgLoading: false
|
})
|
const now = new Date()
|
const date = `${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}`
|
showToast("加载底图失败")
|
const log = {
|
date,
|
method: `POST`,
|
url: "app/log/load_img",
|
param: param.msg,
|
statusCode: 100,
|
data: "加载底图失败"
|
}
|
const listLog = session.getValue("request_log") || []
|
listLog.unshift(log)
|
session.setValue("request_log", listLog)
|
|
}
|
|
} else if (param.method == "cancel_positioning_agv") {
|
//this.positioningAgv = false
|
} else if (param.method == "show_log") {
|
const listLog = session.getValue("request_log") || []
|
listLog.unshift(param.data)
|
session.setValue("request_log", listLog)
|
}
|
},
|
|
async loadLocalScene() {
|
try {
|
const list = session.getValue("scene_db") || []
|
return list
|
} catch (ex) {
|
showError(ex)
|
return []
|
}
|
},
|
async clickStartConstructScene() {
|
try {
|
this.mapId = ""
|
if (this.opType == "extend") {
|
this.mapServerPhase = 1
|
await addMap(this.ip, this.sceneName, "extend")
|
this.checkMapServerPhase()
|
this.opSceneType = 'scan'
|
} else {
|
this.opSceneType = "add_name"
|
}
|
} catch (ex) {
|
showError(ex)
|
}
|
},
|
async clickDownloadScene() {
|
try {
|
this.loading = true
|
uni.showLoading({
|
title: "下载场景中"
|
})
|
const data = this.localSceneList[0].data
|
await saveDBData(this.ip, data)
|
showToast("下载场景成功")
|
this.opSceneType = ""
|
const eventChannel = this.getOpenerEventChannel();
|
eventChannel.emit('create_finish', this.sceneName);
|
uni.navigateBack({
|
delta: 1, //返回层数,2则上上页
|
})
|
} catch (ex) {
|
showError(ex)
|
} finally {
|
this.loading = false
|
uni.hideLoading()
|
}
|
|
|
},
|
|
clickNameCancel() {
|
uni.navigateBack({
|
delta: 1, //返回层数,2则上上页
|
})
|
},
|
async clickNameOK() {
|
try {
|
this.loading = true
|
uni.showLoading({
|
title: "开始构建场景"
|
})
|
const name = this.sceneName.trim()
|
if (!name) {
|
showToast("站点名称还未输入")
|
return
|
}
|
|
this.sceneName = name
|
await createScene(this.ip, name, 1)
|
await addMap(this.ip, name)
|
this.checkMapServerPhase()
|
uni.showLoading({
|
title: "开始扫描地图"
|
})
|
this.mapId = ""
|
this.opSceneType = 'scan'
|
|
|
} catch (ex) {
|
showError(ex)
|
this.opSceneType = 'add_name'
|
} finally {
|
this.loading = false
|
uni.hideLoading()
|
}
|
|
},
|
clickClearName() {
|
this.sceneName = ""
|
this.showClearName = false
|
},
|
onInputName(event) {
|
this.sceneName = event.detail.value;
|
if (this.sceneName)
|
this.showClearName = true
|
else
|
this.showClearName = false
|
},
|
async clickScanFinish() {
|
try {
|
this.loading = true
|
uni.showLoading({
|
title: "地图扫描结束"
|
})
|
this.opSceneType = "finish"
|
uni.setNavigationBarTitle({
|
title: this.sceneName
|
})
|
this.saveMapIsOk = false
|
await stopMap(this.ip, this.sceneName)
|
this.mapServerPhase = 4
|
this.checkMapServerPhase();
|
// if (this.opType == "extend") {
|
// this.opSceneType = ""
|
// const eventChannel = this.getOpenerEventChannel();
|
// eventChannel.emit('create_finish', this.sceneName);
|
// uni.navigateBack({
|
// delta: 1, //返回层数,2则上上页
|
// })
|
// }
|
|
} catch (ex) {
|
console.log(ex)
|
showModal("请检查车辆连接,并重新开始构建场景", "场景构建失败", false, "确定").then((res) => {
|
this.opSceneType = ''
|
|
})
|
} finally {
|
this.loading = false
|
uni.hideLoading()
|
}
|
|
},
|
async clickFinish() {
|
try {
|
|
this.loading = true
|
uni.showLoading({
|
title: "结束场景构建"
|
})
|
this.opSceneType = ""
|
const eventChannel = this.getOpenerEventChannel();
|
eventChannel.emit('create_finish', this.sceneName);
|
uni.navigateBack({
|
delta: 1, //返回层数,2则上上页
|
})
|
} catch (ex) {
|
console.log(ex)
|
} finally {
|
this.loading = false
|
uni.hideLoading()
|
}
|
},
|
async clickRecreate() {
|
try {
|
if (this.opType == "extend") {
|
this.mapServerPhase = 1
|
await addMap(this.ip, this.sceneName, "extend")
|
this.checkMapServerPhase()
|
this.opSceneType = 'scan'
|
} else {
|
this.mapServerPhase = 1
|
await delScene(this.ip, this.sceneName)
|
await createScene(this.ip, this.sceneName, 1)
|
await addMap(this.ip, this.sceneName)
|
this.checkMapServerPhase()
|
this.opSceneType = 'scan'
|
}
|
} catch (ex) {
|
console.log(ex)
|
}
|
},
|
|
|
async loadMapLaserData() {
|
try {
|
const info = await getMapLaserData(this.ip, this.mapId)
|
return info
|
} catch (ex) {
|
showToast(ex)
|
return {}
|
}
|
},
|
async refreshMapLaserData() {
|
try {
|
if (this.opSceneType === "scan") {
|
|
const data = await this.loadMapLaserData()
|
|
const listCtrData = []
|
let newMap = false
|
if (data.base_map?.image_base64) {
|
this.robotPos = {}
|
newMap = true
|
const mapData = data.base_map.image_base64 //this.mapId ?"terdy":
|
this.mapId = data.base_map.map_id
|
|
listCtrData.push({
|
method: "background",
|
param: {
|
proportion: 1,
|
img_proportion: 1,
|
max_x: data.base_map.width || 100,
|
max_y: data.base_map.height || 100,
|
min_x: 0,
|
min_y: 0,
|
img_x: data.base_map.width || 100,
|
img_y: data.base_map.height || 100,
|
filedata: mapData
|
}
|
})
|
|
|
}
|
|
listCtrData.push({
|
method: "point_cloud",
|
param: data.point_cloud
|
})
|
if (data.robot_pose) {
|
listCtrData.push({
|
method: "agv_laser",
|
param: data.robot_pose
|
})
|
if (newMap) {
|
listCtrData.push({
|
method: "move_pt_center",
|
param: {
|
x: data.robot_pose.x,
|
y: data.robot_pose.y,
|
}
|
})
|
} else {
|
if (this.positioningAgv) {
|
listCtrData.push({
|
method: "move_pt_visible",
|
param: {
|
x: data.robot_pose.x,
|
y: data.robot_pose.y,
|
width: 50,
|
height: 50,
|
}
|
})
|
}
|
}
|
}
|
// console.log("ctxDataStr",listCtrData.length)
|
this.ctxDataStr = JSON.stringify(listCtrData)
|
if (data.robot_pose) {
|
this.robotPos = {
|
x: data.robot_pose.x,
|
y: data.robot_pose.y
|
}
|
}
|
}
|
|
setTimeout(this.refreshMapLaserData, 1000);
|
} catch (ex) {
|
showToast(ex)
|
setTimeout(this.refreshMapLaserData, 1000);
|
}
|
},
|
async clickVehiclePosition() {
|
this.positioningAgv = true
|
|
if (this.robotPos.x) {
|
this.ctxDataStr = JSON.stringify([{
|
method: "move_pt_center",
|
param: {
|
x: this.robotPos.x,
|
y: this.robotPos.y
|
}
|
}])
|
}
|
|
|
},
|
|
|
}
|
}
|
</script>
|
|
<style lang="scss">
|
.pages-scene {
|
display: flex;
|
width: 750rpx;
|
height: 100vh;
|
position: relative;
|
|
.content {
|
overflow: auto;
|
position: absolute;
|
left: 0;
|
right: 0;
|
bottom: 0;
|
top: 0;
|
|
.fabric {
|
width: 100%;
|
height: 100%;
|
background-color: #fff;
|
}
|
|
.position {
|
position: absolute;
|
right: 50rpx;
|
bottom: 500rpx;
|
|
.ico {
|
font-size: 65rpx;
|
color: #1890FF;
|
}
|
}
|
|
}
|
|
.map-content {
|
width: 100%;
|
display: flex;
|
flex: 1;
|
flex-direction: column;
|
margin: auto;
|
align-items: center;
|
justify-content: center;
|
|
|
|
.text-button-group {
|
display: flex;
|
width: 100%;
|
justify-content: center;
|
align-items: center;
|
flex-direction: column;
|
font-size: 30rpx !important;
|
|
.button {
|
margin-top: 20rpx;
|
width: 375rpx;
|
}
|
}
|
|
}
|
|
.loading-view {
|
display: flex;
|
flex-direction: row;
|
|
.auto-circle {
|
margin-left: 20rpx;
|
width: 50rpx;
|
height: 50rpx;
|
border-radius: 50%;
|
border: 10rpx solid #1890FF;
|
border-top-color: transparent;
|
animation: drawCircle 1s infinite linear;
|
}
|
|
@keyframes drawCircle {
|
0% {
|
transform: rotate(0deg);
|
}
|
|
100% {
|
transform: rotate(360deg);
|
}
|
}
|
|
}
|
|
|
.bottom {
|
position: fixed;
|
left: 50rpx;
|
right: 50rpx;
|
bottom: 20rpx;
|
display: flex;
|
|
.bottom-content {
|
display: flex;
|
flex-direction: column;
|
width: 100%;
|
// justify-content: center;
|
// align-items: center;
|
padding: 0 10rpx;
|
padding-bottom: 10rpx;
|
background-color: #fff;
|
border-radius: 10rpx;
|
//background-color: #eee;
|
|
.title {
|
font-size: 40rpx;
|
margin-bottom: 10rpx;
|
}
|
|
.tip {
|
color: #888;
|
margin: 10rpx;
|
text-align: left;
|
}
|
|
|
.disabled {
|
color: #ccc !important;
|
}
|
|
.name-input {
|
width: calc(100% - 20rpx);
|
margin-bottom: 10rpx;
|
background-color: #fff;
|
padding: 10rpx;
|
border-radius: 8rpx;
|
display: flex;
|
flex-direction: row;
|
color: #1890FF;
|
|
input {
|
flex: 1;
|
}
|
}
|
}
|
|
|
.text-button-group {
|
display: flex;
|
width: 100%;
|
justify-content: center;
|
align-items: center;
|
flex-direction: column;
|
font-size: 30rpx !important;
|
|
.button {
|
margin: auto;
|
margin-top: 20rpx;
|
width: calc(100% - 10rpx);
|
}
|
|
.am-button {
|
border-radius: 30px;
|
}
|
|
.am-button-ghost {
|
border: 1px solid #1677ff !important;
|
|
}
|
}
|
|
|
}
|
|
|
}
|
</style>
|