【类 型】:factor 飞机控制控件 调整

【原  因】:自适应移动端 大小屏幕就 横竖屏
【过  程】:调到下方 自适应
【影  响】:
This commit is contained in:
tk 2024-07-23 20:40:42 +08:00
parent 074996f51f
commit c23aa3543c
3 changed files with 1017 additions and 143 deletions

View File

@ -0,0 +1,897 @@
<template>
<div>
<!-- 弹出框 -->
<el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="320px" top="30vh">
<!-- 起飞设置弹出框 -->
<template v-if="dialogItem == 'takeoffBox'">
<el-slider class="w-100" v-model="takeoffValue" :show-tooltip="false" show-input :min="1" :max="100">
</el-slider>
<span slot="footer" class="dialog-footer">
<el-button size="medium" @click="dialogVisible = false">关闭</el-button>
<el-button size="medium" type="primary"
@click="publishFun(`{setPlaneState:{bit:6,state:1,count:1,param:[${takeoffValue}]}`); speakText('确认起飞')">确认起飞</el-button>
</span>
</template>
<!-- 摄像头弹出框 -->
<template v-if="dialogItem == 'cameraBox'">
<div class="slider-container">
<div class="m-l-10 m-r-10"></div>
<el-slider @change="releaseCameraSlider('pitch')" @input="setCamera('pitch')" v-model="pitchValue"
:show-tooltip="false" class="w-80"></el-slider>
<div class="m-l-10 m-r-10"></div>
</div>
<div class="slider-container">
<div class="m-l-10 m-r-10"></div>
<el-slider @change="releaseCameraSlider('yaw')" @input="setCamera('yaw')" v-model="yawValue"
:show-tooltip="false" class="w-80"></el-slider>
<div class="m-l-10 m-r-10"></div>
</div>
<div class="slider-container">
<div class="m-l-10 m-r-10"></div>
<el-slider @change="releaseCameraSlider('scale')" @input="setCamera('scale')" v-model="scaleValue"
:show-tooltip="false" class="w-80"></el-slider>
<div class="m-l-10 m-r-10"></div>
</div>
<span slot="footer" class="dialog-footer">
<el-button size="medium" @click="dialogVisible = false">关闭</el-button>
</span>
</template>
</el-dialog>
<!-- 侧边 tab -->
<div class="tab-container">
<el-button size="medium" type="primary" :class="activeIndex === index ? 'butIconGroupBG' : ''"
class="butIconGroup" v-for="(item, index) in controlItems" :key="index"
@click="toggleContent(index, item.voice)">
<i :class="item.icon" class="iconfont f-s-35"></i>
<div class="m-t-5 fb">{{ item.title }}</div>
</el-button>
<!-- 子内容菜单 -->
<div class="content" :class="{ 'active': activeIndex !== null }">
<!-- 订单任务 -->
<div v-if="activeIndex === 0" class="contentBox">
<!-- 标题 -->
<div class="clearB m-b-10 fb f-s-16 contentTit">
<i class="iconfont icon-dingdanguanli f-s-22 m-r-5"></i>
<span>送餐任务</span>
</div>
<!-- 内容 -->
<el-form label-position="left" ref="questForm" :model="questForm" label-width="80px">
<el-form-item label="订单选择" v-if="!executeOrder">
<el-select v-model="questForm.id" :filterable="isMobile" placeholder="请选择,也可输入搜索"
:disabled="executeOrder">
<el-option v-for="item in questList" :key="item.id" :label="item.id" :value="item.id"
:class="isWaring(item) ? 'danger-color' : ''">
<span class="l">{{ item.id }}</span>
<span class="l m-l-5">{{ item.receiver }}</span>
<span class="l m-l-5">{{ item.receive_site_name }}</span>
</el-option>
</el-select>
</el-form-item>
<template v-else>
<el-form-item label="订单ID:">
{{ executeOrder.id }}
</el-form-item>
<el-form-item label="收货站点:">
{{ executeOrder.receive_site_name }}
</el-form-item>
<el-form-item label="联系电话:">
{{ executeOrder.tel }}
</el-form-item>
</template>
<el-form-item label="飞机操作">
<el-button-group>
<el-button size="mini" class="f-s-14" v-if="plane.planeState.state & 1" type="primary"
icon="f-s-14 iconfont icon-chakanzhihangrizhi" @click="checkQuest">
<font class="m-l-5">上传航点</font>
</el-button>
<el-button size="mini" class="f-s-14" v-else-if="plane.planeState.state & 2" key="wirteBut" type="info"
:loading="true" disabled>
<font class="m-l-5">航点写入中···</font>
</el-button>
<el-button size="mini" class="f-s-14"
v-else-if="plane.planeState.state & 4 && !(plane.planeState.state & 16)" type="warning"
icon="f-s-14 iconfont icon-jiesuo"
@click="publishFun('{setPlaneState:{bit:3,state:1,count:2,param:[1,0]}}'); speakText('解锁飞机')">
<font class="m-l-5">解锁飞机</font>
</el-button>
<el-button size="mini" class="f-s-14"
v-else-if="plane.planeState.state & 16 && !(plane.planeState.state & 1) && !(plane.planeState.state & 2)"
type="success" icon="f-s-14 iconfont icon-yangshi_icon_tongyong_departure"
@click="publishFun('{setPlaneState:{bit:5,state:1}'); speakText('准备起飞,执行送餐任务')">
<font class="m-l-5">执行任务</font>
</el-button>
</el-button-group>
</el-form-item>
<el-form-item label="任务操作">
<el-button-group>
<el-button size="mini" class="f-s-14" type="danger" icon="iconfont icon-meiyoudingdan-01" key="celBUt"
@click="reQuest">
<font class="m-l-5">取消任务</font>
</el-button>
<el-button size="mini" class="f-s-14" type="success" icon="iconfont icon-qiandai" key="bingBut"
@click="overQuest">
<font class="m-l-5">已送达</font>
</el-button>
</el-button-group>
</el-form-item>
</el-form>
</div>
<!-- 飞机操作 -->
<template v-if="activeIndex === 1">
<!-- 标题 -->
<div class="clearB m-b-10 fb f-s-16 contentTit">
<i class="iconfont icon-youxishoubing f-s-22 m-r-5"></i>
<span>飞机控制</span>
</div>
<div class="butIconBox">
<el-button size="medium" type="primary" class="butIcon border"
@click="publishFun('{setPlaneState:{bit:3,state:1,count:2,param:[1,0]}}'); speakText('解锁飞机')">
<i class="iconfont icon-jiesuo f-s-24"></i>
<div class="m-t-5">解锁</div>
</el-button>
<el-button size="medium" type="primary" class="butIcon border"
@click="confirmation('飞机加锁,螺旋桨将停转,请谨慎操作!', '加锁操作', '{setPlaneState:{bit:3,state:0,count:2,param:[0,21196]}}'); speakText('加锁,请注意安全')">
<i class=" iconfont icon-suoding f-s-24"></i>
<div class="m-t-5">加锁</div>
</el-button>
<el-button size="medium" type="primary" class="butIcon border"
@click="dialogVisible = true; dialogTitle = '起飞高度(米)设置'; dialogItem = 'takeoffBox'; speakText('设置起飞高度')">
<i class="iconfont icon-yangshi_icon_tongyong_departure f-s-24"></i>
<div class="m-t-5">起飞</div>
</el-button>
<el-button size="medium" type="primary" class="butIcon border"
@click="publishFun('{setPlaneState:{bit:7,state:1}'); speakText('悬停')">
<i class="iconfont icon-fengzheng1 f-s-24"></i>
<div class="m-t-5">悬停</div>
</el-button>
<el-button size="medium" type="primary" class="butIcon border" @click="speakText('继续执行航线')">
<i class="iconfont icon-duandianxufei f-s-24"></i>
<div class="m-t-5">复航</div>
</el-button>
<el-button size="medium" type="primary" class="butIcon border"
@click="publishFun('{setPlaneState:{bit:9,state:1}'); speakText('返航')">
<i class="iconfont icon-yijianfanhang f-s-24"></i>
<div class="m-t-5">返航</div>
</el-button>
<el-button size="medium" type="primary" class="butIcon border"
@click="publishFun('{setPlaneState:{bit:5,state:1}'); speakText('降落')">
<i class="iconfont icon-yangshi_icon_tongyong_arriving f-s-24"></i>
<div class="m-t-5">降落</div>
</el-button>
</div>
</template>
<!-- 附加模组操作 -->
<template v-if="activeIndex === 2">
<!-- 标题 -->
<div class="clearB m-b-10 fb f-s-16 contentTit">
<i class="iconfont icon-mianxingdiaogou f-s-22 m-r-5"></i>
<span>挂载仓控制</span>
</div>
<div class="butIconBox">
<el-button size="medium" type="primary" class="butIcon border"
@click="publishFun('{hookConteroller:4}'); speakText('重置重量传感器')">
<i class="iconfont icon-zhongliang f-s-24"></i>
<div class="m-t-5">归零</div>
</el-button>
<el-button size="medium" type="primary" class="butIcon border"
@click="publishFun('{hookConteroller:0}'); speakText('收钩')">
<i class="iconfont icon-xiangshang f-s-24"></i>
<div class="m-t-5">收钩</div>
</el-button>
<el-button size="medium" type="primary" class="butIcon border"
@click="publishFun('{hookConteroller:3}'); speakText('继续放钩')">
<i class="iconfont icon-qiyong f-s-24"></i>
<div class="m-t-5">继续</div>
</el-button>
<el-button size="medium" type="primary" class="butIcon border"
@click="publishFun('{hookConteroller:2}'); speakText('暂停放钩')">
<i class="iconfont icon-xuanting-zanting f-s-24"></i>
<div class="m-t-5">暂停</div>
</el-button>
</div>
<!-- 标题 -->
<div class="clearB m-b-10 fb f-s-16 contentTit">
<i class="iconfont icon-shipinjiankong f-s-22 m-r-5"></i>
<span>摄像头控制</span>
</div>
<div class="butIconBox">
<el-button size="medium" type="primary" class="butIcon border"
@click="publishFun('{cameraController:{item:0,val:0}}'); speakText('摄像头一键回中')">
<i class="iconfont icon-icon-rotation f-s-24"></i>
<div class="m-t-5">回中</div>
</el-button>
<el-button size="medium" type="primary" class="butIcon border"
@click="publishFun('{cameraController:{item:2,val:0,yaw:0,pitch:-50}}'); speakText('摄像头一键俯瞰')">
<i class="iconfont icon-down f-s-24"></i>
<div class="m-t-5">俯瞰</div>
</el-button>
<el-button size="medium" type="primary" class="butIcon border"
@click="dialogVisible = true; dialogTitle = '摄像头控制'; dialogItem = 'cameraBox'; speakText('手动调整摄像头')">
<i class="iconfont icon-chukong f-s-24"></i>
<div class="m-t-5">手动</div>
</el-button>
<el-button size="medium" type="primary" class="butIcon border"
@click="dialogVisible = true; dialogTitle = '摄像头控制'; dialogItem = 'cameraBox'; speakText('调整镜头焦距')">
<i class="iconfont icon-fangda f-s-24"></i>
<div class="m-t-5">焦距</div>
</el-button>
</div>
<!-- 标题 -->
<div class="clearB m-b-10 fb f-s-16 contentTit">
<i class="iconfont icon-tongzhi f-s-22 m-r-5"></i>
<span>喇叭控制</span>
</div>
<div class="butIconBox">
<el-button size="medium" type="primary" class="butIcon border">
<i class="iconfont icon-icon-test f-s-24"></i>
<div class="m-t-5">喊话</div>
</el-button>
</div>
</template>
<!-- 飞机调试 -->
<template v-if="activeIndex === 3">
<!-- 标题 -->
<div class="clearB m-b-10 fb f-s-16 contentTit">
<i class="iconfont icon-banshou_Line f-s-22 m-r-5"></i>
<span>飞机调试</span>
</div>
<div class="butIconBox">
<el-button size="medium" type="primary" class="butIcon border"
@click="publishFun('{bit:11,state:1}'); speakText('校准磁罗盘')">
<i class="iconfont icon-zhinanzhen f-s-24"></i>
<div class="m-t-5">磁罗盘</div>
</el-button>
<el-button size="medium" type="primary" class="butIcon border" @click="speakText('校准加速度计')">
<i class="iconfont icon-zuobiaozhoupeizhixiang f-s-24"></i>
<div class="m-t-5">加速度计</div>
</el-button>
<el-button size="medium" type="primary" class="butIcon border" @click="speakText('写入参数')">
<i class="iconfont icon-canshupeizhi f-s-24"></i>
<div class="m-t-5">写入参数</div>
</el-button>
</div>
</template>
</div>
</div>
<!-- 底边 tab -->
<div></div>
</div>
</template>
<script>
import { questAss } from '@/utils/api/table'
import mqtt from '@/utils/mqtt'
import { speakText } from '@/utils/index'
export default {
name: 'TabController',
data () {
return {
dialogTitle: '', //
dialogItem: '', //
dialogVisible: false, //
pitchValue: 50, //
yawValue: 50, //
scaleValue: 50, //
takeoffValue: 2, //
controlItems: [//
{ title: '任务', icon: 'icon-songcanfuwu', voice: '设置送餐任务' },
{ title: '控制', icon: 'icon-youxishoubing', voice: '控制飞机' },
{ title: '扩展', icon: 'icon-linghuokuozhan', voice: '控制扩展组件' },
{ title: '调试', icon: 'icon-banshou_Line', voice: '调试飞机' }
],
activeIndex: null, //
tabIsOpen: false, // tab
questForm: { //
id: ''
}
}
},
props: {
plane: {
typeof: 'Object',
deep: true
}
},
computed: {
/**
* @description: 终端平台是否是pc
*/
isMobile () {
return this.$store.state.app.isMobile
},
/**
* @description: 已付款 已接单 未发起退款 订单列表
*/
questList () {
const plane = this.plane
return plane ? this.$store.state.paidOrderList.filter((item) => item.shop_id === plane.shop_id && item.shipment_status === '已接单' && item.refund_status !== '申请中') : []
},
/**
* @description: 已发货 订单列表
*/
ShippedList () {
const plane = this.plane
return plane ? this.$store.state.paidOrderList.filter((item) => item.shop_id === plane.shop_id && item.shipment_status === '已发货') : []
},
/**
* @description: 当前选框 中的订单
*/
currentOrder () {
if (this.questForm && this.questForm.id !== undefined) {
return this.questList.find((item) => item.id === this.questForm.id) || null
}
return null
},
/**
* @description: 正在执行的订单 没有未null 代表飞机空闲
*/
executeOrder () {
const plane = this.plane
if (plane) {
const order = this.ShippedList.find((item) => item.by_plane_id === plane.id)
return order && Object.keys(order).length === 0 ? null : order || null
}
return null
},
/**
* @description: 航线列表
*/
routeList () {
return this.$store.state.routeList
},
/**
* @description: 获取站点列表
*/
siteList () {
return this.$store.state.siteList
}
},
methods: {
questAss,
speakText,
/**
* @description: 摄像头 滑动条松开
* @param {string} item 项目
*/
releaseCameraSlider (item) {
if (item === 'pitch') {
this.pitchValue = 50
this.publishFun('{cameraController:{item:2,val:0,yaw:0,pitch:0}}')
} else if (item === 'yaw') {
this.yawValue = 50
this.publishFun('{cameraController:{item:2,val:0,yaw:0,pitch:0}}')
} else if (item === 'scale') {
this.publishFun('{cameraController:{item:1,val:0}}')
this.scaleValue = 50
}
},
/**
* @description: 摄像头 滑动条滚动 发送设置命令
* @param {*} item 项目
*/
setCamera (item) {
if (item === 'pitch') { // pitch
const pitchV = (this.pitchValue - 50) * 2
this.publishFun(`{cameraController:{item:2,yaw:0,pitch:${pitchV}}`)
} else if (item === 'yaw') { // yaw
const yawV = (this.yawValue - 50) * 2
this.publishFun(`{cameraController:{item:2,yaw:${yawV},pitch:0}`)
} else if (item === 'scale') {
if (this.scaleValue < 50) { //
this.publishFun('{cameraController:{item:1,val:1}}')
} else if (this.scaleValue > 50) {
this.publishFun('{cameraController:{item:1,val:255}}')
}
}
},
/**
* @description: 菜单切换 PS:UI
* @param {*} index 序号
* @param {*} voice 播放声音的文本
*/
toggleContent (index, voice) {
this.activeIndex = this.activeIndex === index ? null : index
if (this.tabIsOpen) {
if (index !== this.activeIndex) {
this.tabIsOpen = false
this.$emit('mapXOffset', -200)
} else {
this.speakText(voice)
}
} else {
this.tabIsOpen = true
this.$emit('mapXOffset', 200)
this.speakText(voice)
}
},
/**
* @description: 发布 mqtt 信息
* @param {*} jsonData {'item':val} // item: questAss setPlaneState getPlaneState resetState chan11 chan22 chan33 chan44 hookConteroller cameraController
*/
publishFun (jsonData) {
if (this.plane) {
mqtt.publishFun(`cmd/${this.plane.macadd}`, jsonData)
} else {
this.$message.warning('与飞机通信未接通,请稍后')
}
},
/**
* @description: 执行任务前 先检测订单是否 合法 例如订单重量会不会超出飞机载重上限
*/
checkQuest () {
let checkOrder //
//
if (this.executeOrder) {
checkOrder = this.executeOrder
} else {
checkOrder = this.currentOrder
}
//
if (this.questForm.id === '' && !checkOrder) {
this.$message.error('未选择订单任务!')
return
}
// 退
if (checkOrder.refund_status === '申请中') {
this.$message.error('此订单已被申请退款或者订单已经被取消!')
return
}
//
if (checkOrder.bind_route === null) {
this.$message.error('此站点,未绑定任务航点')
return
}
/* 如果是正在执行订单 直接调用重新提交 */
if (this.executeOrder) {
this.continueQuest()
return
}
/* 综合检查 这部分针对 新提交订单 */
//
const weightCheck = new Promise((resolve, reject) => {
if (Number(checkOrder.total_weight) >= Number(this.plane.weight_max)) {
this.$confirm('此订单总重超出本飞机的载重上限', '检测订单', {
confirmButtonText: '继续',
cancelButtonText: '放弃',
type: 'warning'
})
.then(() => {
resolve()
})
.catch(action => {
this.$message({
type: 'info',
message: '取消提交订单'
})
reject(new Error('Weight check failed'))
})
} else {
resolve()
}
})
//
const runningCheck = new Promise((resolve, reject) => {
if ((checkOrder.runing ?? '').split(',').some(item => item !== '')) {
this.$confirm('此订单的目标站点,已经有飞机正在执行任务。请注意安全!', '检测订单', {
confirmButtonText: '继续',
cancelButtonText: '放弃',
type: 'warning'
})
.then(() => {
resolve()
})
.catch(action => {
this.$message({
type: 'info',
message: '取消提交订单'
})
reject(new Error('Running check failed'))
})
} else {
resolve()
}
})
//
Promise.all([weightCheck, runningCheck])
.then(() => {
this.runQuest()
})
.catch((error) => {
console.log(error.message)
})
},
/**
* @description: 正在执行的任务 重新上传航线
*/
continueQuest () {
/* 执行写在这里 */
let routeData // 线
try {
/* 航线选择 */
const bindRoute = (this.executeOrder.bind_route ?? '').split(',')
const runing = (this.executeOrder.runing ?? '').split(',')
const matchingIndex = runing
.map((route, index) => route === this.executeOrder.by_plane_id ? index : -1)
.filter(index => index !== -1)// 线
routeData = this.routeList.find(element => element.id === bindRoute[matchingIndex]).route_data
routeData = JSON.parse(routeData)//
// $food_sn$
this.executeOrder.telTail = this.executeOrder.tel.substr(-4)// telTail tel
routeData.questAss.tasks.forEach((x, index) => {
if (x.sound) {
const str = this.voiceRouteParse(this.executeOrder, x.sound)
routeData.questAss.tasks[index].sound = str//
}
})
routeData = JSON.stringify(routeData)//
//
this.publishFun(routeData)
//
this.publishFun('{getPlaneState:1}')
} catch (error) {
this.$message.error('操作失败,航线异常')
}
},
/**
* @description: 选择订单的 执行订单任务 ps:改变订单状态 站点runing状态 上传航线
*/
async runQuest () {
/* 插入日志 */
this.$store.dispatch('fetchLog', { content: `${this.plane.name} 开始执行 订单ID${this.currentOrder.id}、叫餐号:${this.currentOrder.food_sn}号。` })
/* 执行写在这里 */
let routeData // 线
let newRuning // running
try {
/* 站点正在执行任务runing 注册 */
const runing = (this.currentOrder.runing ?? '').split(',')
let foundEmpty = false
let matchingIndex // 使线
runing.some((item, index, arr) => {
if (item === '') {
arr[index] = this.plane.id
foundEmpty = true
matchingIndex = index
return true // 退
}
})
newRuning = runing.join(',')
if (!foundEmpty) {
this.$message({
type: 'warning',
message: '此站点所有航线均被占用,等航线空闲再试!'
})
return // 退
}
/* 航线选择 */
const bindRoute = (this.currentOrder.bind_route ?? '').split(',')
routeData = this.routeList.find(element => element.id === bindRoute[matchingIndex]).route_data
routeData = JSON.parse(routeData)//
// $food_sn$
this.currentOrder.telTail = this.currentOrder.tel.substr(-4)// telTail tel
routeData.questAss.tasks.forEach((x, index) => {
if (x.sound) {
const str = this.voiceRouteParse(this.currentOrder, x.sound)
routeData.questAss.tasks[index].sound = str//
}
})
routeData = JSON.stringify(routeData)//
} catch (error) {
this.$message.error('操作失败,航线异常')
return
}
let res = await this.$store.dispatch('fetchLockSite', { id: this.currentOrder.receive_site_id, shop_id: this.plane.shop_id, runing: newRuning })// 线
if (res.data.status === 1) {
res = await this.questAss(this.currentOrder.id, ['shipment_status', 'by_plane_id'], ['已发货', this.plane.id])//
if (res.data.status === 1) {
this.publishFun(routeData)//
}
}
//
this.publishFun('{getPlaneState:1}')
},
/**
* @description: 匹配声音航点字符串 比如$food_sn$ food_sn匹配成 送餐订单里面的对应字段
* @param {*} questItem 送餐的订单 ps:从数据库里拿的 订单信息对象
* @param {*} voiceRouteStr 声音航点的字符串
*/
voiceRouteParse (questItem, voiceRouteStr) {
//
const regex = /\$(.*?)\$/g
// 使replace()
const replacedStr = voiceRouteStr.replace(regex, (match, p1) => {
// matchp1
return questItem[p1] //
})
//
return replacedStr // "4513301115846"
},
/**
* @description: 确认操作
* @param {*}msg 提示的话语内容
* @param {*}tit 提示框的标题
* @param {*}instruct 需要发送的mqtt指令内容
*/
confirmation (msg, tit, instruct) {
this.$confirm(msg, tit, {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.publishFun(instruct)
}).catch(() => {
this.$message.info('取消操作!')
})
},
/**
* @description: 取消任务
*/
reQuest () {
if (!this.executeOrder) { // ""
this.$message.warning('当前没有执行任务')
return
}
this.$confirm('取消已发货状态,并使飞机复位?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
/* 关联当前订单的站点 搜寻注册的飞机 并预设newRuning 用于注销runing字段航线 */
//
const runingArray = this.executeOrder.runing.split(',')
//
for (let i = 0; i < runingArray.length; i++) {
if (runingArray[i] === this.executeOrder.by_plane_id) {
runingArray[i] = ''
}
}
//
const newRuning = runingArray.join(',')
/* 确认 把订单从发货退回到已接单 站点runing字段飞机航线注销 重置飞机状态 */
this.$store.dispatch('fetchLockSite', { id: this.executeOrder.receive_site_id, shop_id: this.plane.shop_id, runing: newRuning }).then(res => { // 退
if (res.data.status === 1) {
this.questAss(this.executeOrder.id, ['shipment_status', 'by_plane_id'], ['已接单', 'null']).then(res => { // 线
if (res.data.status === 1) {
this.publishFun('{"resetState":1}')//
}
})
}
})
}).catch(() => {
this.$message.info('取消操作!')
})
},
/**
* @description: 已送达任务
*/
overQuest () {
if (!this.executeOrder) { // ""
this.$message.warning('当前没有执行任务')
return
}
this.$confirm('确认订单已送达?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
/* 关联当前订单的站点 搜寻注册的飞机 并预设newRuning 用于注销runing字段航线 */
//
const runingArray = this.executeOrder.runing.split(',')
//
for (let i = 0; i < runingArray.length; i++) {
if (runingArray[i] === this.executeOrder.by_plane_id) {
runingArray[i] = ''
}
}
//
const newRuning = runingArray.join(',')
/* 确认 把订单从发货退回到已接单 站点runing字段飞机航线注销 重置飞机状态 */
this.$store.dispatch('fetchLockSite', { id: this.executeOrder.receive_site_id, shop_id: this.plane.shop_id, runing: newRuning }).then(res => { //
if (res.data.status === 1) {
this.questAss(this.executeOrder.id, 'shipment_status', '已送达').then(res => { // 线
if (res.data.status === 1) {
this.publishFun('{"resetState":1}')//
}
})
}
})
}).catch(() => {
this.$message.info('取消操作!')
})
},
/**
* @description: 在地图上绘制航线
*/
makeRouteForMap () {
let bindRoute
let routeData
let found = false
this.siteList.some(item => {
const runing = (item.runing ?? '').split(',')
const index = runing.indexOf(this.plane.id.toString())
if (index !== -1) {
found = true
//
if (item.bind_route !== null) { //
bindRoute = (item.bind_route ?? '').split(',')
this.$store.dispatch('fetchRouteList').then(res => { //
routeData = res.find(element => element.id === bindRoute[index]).route_data
this.$emit('makeRoute', JSON.parse(routeData))
})
} else {
this.$message.error('此站点,未绑定任务航点')
}
return true // 退
}
return false //
})
if (!found) {
this.$message.error('未找到匹配的站点')
}
},
/**
* @description: 判断 已接订单下拉框 的任务 有疑问的 坐标集 class样式显示成红色
* @param {*} item 对应下拉框的任务
*/
isWaring (item) {
const isOverWaight = Number(item.total_weight) >= Number(this.plane.weight_max)//
const isQuestIng = (item.runing ?? '').split(',').some(i => i !== '') //
return isOverWaight || isQuestIng
}
},
mounted () {
//
if (this.executeOrder) { //
this.makeRouteForMap()//
} else { //
if (this.plane) {
this.publishFun('{"resetState":1}')//
}
}
},
watch: {
executeOrder (val) {
if (val) { // 线
this.makeRouteForMap()
} else { // 线
this.$emit('clearRoute')
this.publishFun('{"resetState":1}')//
}
},
questList (val) {
/* 任务列表更新时 判断还有没有当前选择的id 没有就清空 */
const found = val.some(item => item.id === this.questForm.id)
if (!found) {
this.questForm.id = ''
}
}
},
destroyed () {
}
}
</script>
<style lang="scss" scoped>
@import "@/styles/theme.scss";
.danger-color {
color: $danger-color;
font-weight: bold;
}
.tab-container {
height: 365px;
width: 80px;
display: flex;
flex-direction: column;
align-items: flex-end;
position: fixed;
right: 15px;
top: 50%;
transform: translateY(-50%);
z-index: 1000;
}
.butIconGroup {
color: $maintext-color;
background-color: rgba(255, 255, 255, 0.5);
border-radius: 15px;
padding: 5px;
width: 80px;
height: 80px;
text-align: center;
margin-bottom: 20px;
border: none;
box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.2);
}
.butIconGroupBG {
color: $graylight-color;
background-color: $brand-color;
}
.butIconGroup:last-of-type {
margin-bottom: 0px;
}
.slider-container {
display: flex;
align-items: center;
/* 水平垂直居中 */
}
.content {
color: $maintext-color;
border-radius: 15px;
height: 100%;
position: fixed;
right: -400px;
top: 50%;
transform: translateY(-50%);
width: 350px;
background-color: rgba(255, 255, 255, 0.8);
padding: 20px;
box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.2);
transition: right 0.3s ease;
}
.content.active {
right: 95px;
}
.contentTit i {
vertical-align: middle;
}
.butIcon {
border-radius: 10px;
padding: 5px;
width: 66px;
height: 66px;
text-align: center;
border: none;
float: left;
margin: 0px !important;
margin-bottom: 15px !important;
margin-right: 15px !important;
}
.butIconBox .butIcon:nth-child(4n) {
margin-right: 0 !important;
}
/* 手机端样式 */
@media screen and (max-height: 500px) {
.tab-container {
height: 300px;
width: 50px;
}
.butIconGroup {
margin-bottom: 12px;
}
.el-button {
font-size: 14px !important;
}
.contentTit {
font-size: 14px !important;
margin-bottom: 5px !important;
}
.contentTit i {
font-size: 18px !important;
}
.butIcon {
height: 56px;
margin-bottom: 10px !important;
}
}
</style>

View File

@ -1,5 +1,5 @@
<template>
<div>
<div class="w-100 h-100 mainBox">
<!-- 弹出框 -->
<el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="320px" top="30vh">
<!-- 起飞设置弹出框 -->
@ -37,20 +37,14 @@
</span>
</template>
</el-dialog>
<!-- 侧边 tab -->
<div class="tab-container">
<el-button size="medium" type="primary" :class="activeIndex === index ? 'butIconGroupBG' : ''"
class="butIconGroup" v-for="(item, index) in controlItems" :key="index"
@click="toggleContent(index, item.voice)">
<i :class="item.icon" class="iconfont f-s-35"></i>
<div class="m-t-5 fb">{{ item.title }}</div>
</el-button>
<!-- 子内容菜单 -->
<div class="content" :class="{ 'active': activeIndex !== null }">
<!-- 底边 tab控件组 -->
<div class="flex column mr mac tabContainer p-l-10 p-r-10">
<!-- tab控件组 内容组 -->
<div class="tabContent" :class="{ 'active': activeIndex !== null }">
<!-- 订单任务 -->
<div v-if="activeIndex === 0" class="contentBox">
<div v-if="activeIndex === 0" class="tabContentBox">
<!-- 标题 -->
<div class="clearB m-b-10 fb f-s-16 contentTit">
<div class="clearB m-b-15 fb f-s-16 contentTit">
<i class="iconfont icon-dingdanguanli f-s-22 m-r-5"></i>
<span>送餐任务</span>
</div>
@ -117,140 +111,148 @@
</el-form>
</div>
<!-- 飞机操作 -->
<template v-if="activeIndex === 1">
<div v-else-if="activeIndex === 1" class="tabContentBox">
<!-- 标题 -->
<div class="clearB m-b-10 fb f-s-16 contentTit">
<div class="clearB m-b-15 fb f-s-16 contentTit">
<i class="iconfont icon-youxishoubing f-s-22 m-r-5"></i>
<span>飞机控制</span>
</div>
<div class="butIconBox">
<el-button size="medium" type="primary" class="butIcon border"
<div class="butIconBox gap10 flex">
<el-button size="medium" type="primary" class="butIcon"
@click="publishFun('{setPlaneState:{bit:3,state:1,count:2,param:[1,0]}}'); speakText('解锁飞机')">
<i class="iconfont icon-jiesuo f-s-24"></i>
<div class="m-t-5">解锁</div>
</el-button>
<el-button size="medium" type="primary" class="butIcon border"
<el-button size="medium" type="primary" class="butIcon"
@click="confirmation('飞机加锁,螺旋桨将停转,请谨慎操作!', '加锁操作', '{setPlaneState:{bit:3,state:0,count:2,param:[0,21196]}}'); speakText('加锁,请注意安全')">
<i class=" iconfont icon-suoding f-s-24"></i>
<div class="m-t-5">加锁</div>
</el-button>
<el-button size="medium" type="primary" class="butIcon border"
<el-button size="medium" type="primary" class="butIcon"
@click="dialogVisible = true; dialogTitle = '起飞高度(米)设置'; dialogItem = 'takeoffBox'; speakText('设置起飞高度')">
<i class="iconfont icon-yangshi_icon_tongyong_departure f-s-24"></i>
<div class="m-t-5">起飞</div>
</el-button>
<el-button size="medium" type="primary" class="butIcon border"
<el-button size="medium" type="primary" class="butIcon"
@click="publishFun('{setPlaneState:{bit:7,state:1}'); speakText('悬停')">
<i class="iconfont icon-fengzheng1 f-s-24"></i>
<div class="m-t-5">悬停</div>
</el-button>
<el-button size="medium" type="primary" class="butIcon border" @click="speakText('继续执行航线')">
<el-button size="medium" type="primary" class="butIcon" @click="speakText('继续执行航线')">
<i class="iconfont icon-duandianxufei f-s-24"></i>
<div class="m-t-5">复航</div>
</el-button>
<el-button size="medium" type="primary" class="butIcon border"
<el-button size="medium" type="primary" class="butIcon"
@click="publishFun('{setPlaneState:{bit:9,state:1}'); speakText('返航')">
<i class="iconfont icon-yijianfanhang f-s-24"></i>
<div class="m-t-5">返航</div>
</el-button>
<el-button size="medium" type="primary" class="butIcon border"
<el-button size="medium" type="primary" class="butIcon"
@click="publishFun('{setPlaneState:{bit:5,state:1}'); speakText('降落')">
<i class="iconfont icon-yangshi_icon_tongyong_arriving f-s-24"></i>
<div class="m-t-5">降落</div>
</el-button>
</div>
</template>
</div>
<!-- 附加模组操作 -->
<template v-if="activeIndex === 2">
<div v-else-if="activeIndex === 2" class="tabContentBox">
<!-- 标题 -->
<div class="clearB m-b-10 fb f-s-16 contentTit">
<div class="clearB m-b-15 fb f-s-16 contentTit">
<i class="iconfont icon-mianxingdiaogou f-s-22 m-r-5"></i>
<span>挂载仓控制</span>
</div>
<div class="butIconBox">
<el-button size="medium" type="primary" class="butIcon border"
<div class="butIconBox m-b-15 gap10 flex">
<el-button size="medium" type="primary" class="butIcon"
@click="publishFun('{hookConteroller:4}'); speakText('重置重量传感器')">
<i class="iconfont icon-zhongliang f-s-24"></i>
<div class="m-t-5">归零</div>
</el-button>
<el-button size="medium" type="primary" class="butIcon border"
<el-button size="medium" type="primary" class="butIcon"
@click="publishFun('{hookConteroller:0}'); speakText('收钩')">
<i class="iconfont icon-xiangshang f-s-24"></i>
<div class="m-t-5">收钩</div>
</el-button>
<el-button size="medium" type="primary" class="butIcon border"
<el-button size="medium" type="primary" class="butIcon"
@click="publishFun('{hookConteroller:3}'); speakText('继续放钩')">
<i class="iconfont icon-qiyong f-s-24"></i>
<div class="m-t-5">继续</div>
</el-button>
<el-button size="medium" type="primary" class="butIcon border"
<el-button size="medium" type="primary" class="butIcon"
@click="publishFun('{hookConteroller:2}'); speakText('暂停放钩')">
<i class="iconfont icon-xuanting-zanting f-s-24"></i>
<div class="m-t-5">暂停</div>
</el-button>
</div>
<!-- 标题 -->
<div class="clearB m-b-10 fb f-s-16 contentTit">
<div class="clearB m-b-15 fb f-s-16 contentTit">
<i class="iconfont icon-shipinjiankong f-s-22 m-r-5"></i>
<span>摄像头控制</span>
</div>
<div class="butIconBox">
<el-button size="medium" type="primary" class="butIcon border"
<div class="butIconBox m-b-15 gap10 flex">
<el-button size="medium" type="primary" class="butIcon"
@click="publishFun('{cameraController:{item:0,val:0}}'); speakText('摄像头一键回中')">
<i class="iconfont icon-icon-rotation f-s-24"></i>
<div class="m-t-5">回中</div>
</el-button>
<el-button size="medium" type="primary" class="butIcon border"
<el-button size="medium" type="primary" class="butIcon"
@click="publishFun('{cameraController:{item:2,val:0,yaw:0,pitch:-50}}'); speakText('摄像头一键俯瞰')">
<i class="iconfont icon-down f-s-24"></i>
<div class="m-t-5">俯瞰</div>
</el-button>
<el-button size="medium" type="primary" class="butIcon border"
<el-button size="medium" type="primary" class="butIcon"
@click="dialogVisible = true; dialogTitle = '摄像头控制'; dialogItem = 'cameraBox'; speakText('手动调整摄像头')">
<i class="iconfont icon-chukong f-s-24"></i>
<div class="m-t-5">手动</div>
</el-button>
<el-button size="medium" type="primary" class="butIcon border"
<el-button size="medium" type="primary" class="butIcon"
@click="dialogVisible = true; dialogTitle = '摄像头控制'; dialogItem = 'cameraBox'; speakText('调整镜头焦距')">
<i class="iconfont icon-fangda f-s-24"></i>
<div class="m-t-5">焦距</div>
</el-button>
</div>
<!-- 标题 -->
<div class="clearB m-b-10 fb f-s-16 contentTit">
<div class="clearB m-b-15 fb f-s-16 contentTit">
<i class="iconfont icon-tongzhi f-s-22 m-r-5"></i>
<span>喇叭控制</span>
</div>
<div class="butIconBox">
<el-button size="medium" type="primary" class="butIcon border">
<div class="butIconBox gap10 flex">
<el-button size="medium" type="primary" class="butIcon">
<i class="iconfont icon-icon-test f-s-24"></i>
<div class="m-t-5">喊话</div>
</el-button>
</div>
</template>
</div>
<!-- 飞机调试 -->
<template v-if="activeIndex === 3">
<div v-else-if="activeIndex === 3" class="tabContentBox">
<!-- 标题 -->
<div class="clearB m-b-10 fb f-s-16 contentTit">
<div class="clearB m-b-15 fb f-s-16 contentTit">
<i class="iconfont icon-banshou_Line f-s-22 m-r-5"></i>
<span>飞机调试</span>
</div>
<div class="butIconBox">
<el-button size="medium" type="primary" class="butIcon border"
<div class="butIconBox m-b-15 gap10 flex">
<el-button size="medium" type="primary" class="butIcon"
@click="publishFun('{bit:11,state:1}'); speakText('校准磁罗盘')">
<i class="iconfont icon-zhinanzhen f-s-24"></i>
<div class="m-t-5">磁罗盘</div>
</el-button>
<el-button size="medium" type="primary" class="butIcon border" @click="speakText('校准加速度计')">
<el-button size="medium" type="primary" class="butIcon" @click="speakText('校准加速度计')">
<i class="iconfont icon-zuobiaozhoupeizhixiang f-s-24"></i>
<div class="m-t-5">加速度计</div>
</el-button>
<el-button size="medium" type="primary" class="butIcon border" @click="speakText('写入参数')">
<el-button size="medium" type="primary" class="butIcon" @click="speakText('写入参数')">
<i class="iconfont icon-canshupeizhi f-s-24"></i>
<div class="m-t-5">写入参数</div>
</el-button>
</div>
</template>
</div>
</div>
<!-- tab控件组 按钮组 -->
<div class="flex gap10 m-b-10 taButGroup">
<div class="flex1 h-100 taBut flex column mac mc" :class="activeIndex === index ? 'taButBG' : ''"
v-for="(item, index) in controlItems" :key="index" @click="toggleContent(index, item.voice)">
<i :class="item.icon" class="iconfont f-s-35 no-select"></i>
<div class="m-t-15 fb f-s-18 no-select">{{ item.title }}</div>
</div>
</div>
</div>
</div>
@ -393,13 +395,13 @@ export default {
if (this.tabIsOpen) {
if (index !== this.activeIndex) {
this.tabIsOpen = false
this.$emit('mapXOffset', -200)
this.$emit('mapXOffset', 0, -200)
} else {
this.speakText(voice)
}
} else {
this.tabIsOpen = true
this.$emit('mapXOffset', 200)
this.$emit('mapXOffset', 0, 200)
this.speakText(voice)
}
},
@ -782,114 +784,91 @@ export default {
font-weight: bold;
}
.tab-container {
height: 365px;
width: 80px;
display: flex;
flex-direction: column;
align-items: flex-end;
position: fixed;
right: 15px;
top: 50%;
transform: translateY(-50%);
z-index: 1000;
.mainBox {
position: absolute;
}
.butIconGroup {
color: $maintext-color;
background-color: rgba(255, 255, 255, 0.5);
border-radius: 15px;
padding: 5px;
width: 80px;
height: 80px;
text-align: center;
margin-bottom: 20px;
border: none;
box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.2);
}
.butIconGroupBG {
color: $graylight-color;
background-color: $brand-color;
}
.butIconGroup:last-of-type {
margin-bottom: 0px;
}
.slider-container {
display: flex;
align-items: center;
/* 水平垂直居中 */
}
.content {
color: $maintext-color;
border-radius: 15px;
.tabContainer {
width: 100%;
height: 100%;
position: fixed;
right: -400px;
top: 50%;
transform: translateY(-50%);
width: 350px;
background-color: rgba(255, 255, 255, 0.8);
padding: 20px;
box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.2);
transition: right 0.3s ease;
}
.content.active {
right: 95px;
.tabContent {
z-index: 90;
position: relative;
width: 100%;
border-radius: 10px;
max-width: 470px;
background-color: rgba(255, 255, 255, 0.8);
box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.2);
top: -50px;
opacity: 0;
transition: top 0.5s ease, opacity 1s ease;
}
.tabContent.active {
top: -10px;
opacity: 1;
}
.tabContentBox {
padding: 20px;
}
.contentTit i {
vertical-align: middle;
}
.butIconBox {
flex-wrap: wrap;
/* 允许换行 */
justify-content: flex-start;
/* 主轴对齐方式 */
align-content: space-around;
/* 多行在侧轴上的对齐方式 */
}
.butIcon {
border-radius: 10px;
padding: 5px;
width: 66px;
height: 66px;
text-align: center;
border: none;
float: left;
margin: 0px !important;
margin-bottom: 15px !important;
margin-right: 15px !important;
margin-left: 0px !important;
}
.butIconBox .butIcon:nth-child(4n) {
margin-right: 0 !important;
.taButGroup {
position: relative;
width: 100%;
max-width: 470px;
height: 105px;
cursor: pointer;
z-index: 90;
}
/* 手机端样式 */
@media screen and (max-height: 500px) {
@media (max-width: 480px) {
.taButGroup {
height: calc((100vw - 50px)/4);
}
.tab-container {
height: 300px;
width: 50px;
width: 100vw;
}
}
.butIconGroup {
margin-bottom: 12px;
}
.taBut {
color: $maintext-color;
background-color: rgba(255, 255, 255, 0.5);
border-radius: 10px;
padding: 5px;
text-align: center;
box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.2);
}
.el-button {
font-size: 14px !important;
}
.taButBG {
color: $graylight-color;
background-color: $brand-color;
}
.contentTit {
font-size: 14px !important;
margin-bottom: 5px !important;
}
.contentTit i {
font-size: 18px !important;
}
.butIcon {
height: 56px;
margin-bottom: 10px !important;
}
.gap10 {
gap: 10px;
}
</style>

View File

@ -3,8 +3,7 @@
<map-box ref="mapbox" :key="mapBoxKey" class="ofh">
<template #content>
<!-- <PlaneStatus :plane="plane" /> -->
<As />
<!-- <ControllerTabs :plane="plane" @mapXOffset="mapXOffset" @makeRoute="makeRoute" @clearRoute="clearRoute" /> -->
<ControllerTabs :plane="plane" @mapXOffset="mapXOffset" @makeRoute="makeRoute" @clearRoute="clearRoute" />
</template>
</map-box>
</div>
@ -13,8 +12,7 @@
<script>
import mqtt from '@/utils/mqtt'
import MapBox from '@/components/MapBox'
// import ControllerTabs from '@/components/ControllerTabs'
import As from '@/components/As'
import ControllerTabs from '@/components/ControllerTabs'
// import PlaneStatus from '@/components/PlaneStatus'
export default {
@ -28,8 +26,7 @@ export default {
},
components: {
MapBox,
As
// ControllerTabs,
ControllerTabs
// PlaneStatus
},
computed: {
@ -90,9 +87,10 @@ export default {
/**
* @description: 屏幕横移
* @param {*} val 正数向左移动 负数向右移动
* @param {*} y 正数向上移动 负数向下移动
*/
mapXOffset (val) {
this.$refs.mapbox.mapXOffset(val)
mapXOffset (x, y) {
this.$refs.mapbox.mapXOffset(x, y)
}
},
mounted () {