修改实时地图小手

增加整体看板
This commit is contained in:
xhf 2025-02-25 14:42:44 +08:00
parent 4b54062344
commit 9690a8a347
4 changed files with 1563 additions and 119 deletions

View File

@ -4,7 +4,7 @@ NODE_ENV=development
VITE_DEV=true
# 请求路径
VITE_BASE_URL='http://192.168.0.172:48080'
VITE_BASE_URL='http://192.168.0.74:48080'
# VITE_BASE_URL='http://192.168.0.189:48080'
# 文件上传类型server - 后端上传, client - 前端直连上传,仅支持 S3 服务

View File

@ -33,7 +33,9 @@
<el-col :span="4">
<div class="top-item">
<div class="top-item-title"> 已取消 </div>
<div class="top-item-num" style="color: #a6a6a6"> {{ data.cancelledNum || 0 }} </div>
<div class="top-item-num" style="color: #a6a6a6">
{{ data.cancelledNum || 0 }}
</div>
</div>
</el-col>
<el-col :span="4">
@ -77,7 +79,9 @@
<el-col :span="4">
<div class="top-item">
<div class="top-item-title"> 离线 </div>
<div class="top-item-num" style="color: #a6a6a6"> {{ data.statistics.offline || 0 }} </div>
<div class="top-item-num" style="color: #a6a6a6">
{{ data.statistics.offline || 0 }}
</div>
</div>
</el-col>
<el-col :span="4">
@ -92,15 +96,18 @@
</el-col>
</el-row>
</div>
<!-- 底部列表和地图 -->
<!-- 下部分 -->
<div class="bottom-box">
<el-row :gutter="10">
<!-- 左边 -->
<el-col :span="6">
<div class="bottom-box-item" v-if="data">
<div class="bottom-box-item-table">
<div class="bottom-box-item-title">
<div class="bottom-box-item-title-left"> 执行中 </div>
<div class="bottom-box-item-title-right" @click="toManyTask('执行中')"> 查看更多 </div>
<div class="bottom-box-item-title-right" @click="toManyTask('执行中')">
查看更多
</div>
</div>
<div>
<el-table :data="data.underway" style="width: 100%">
@ -116,7 +123,9 @@
<div class="bottom-box-item-table">
<div class="bottom-box-item-title">
<div class="bottom-box-item-title-left"> 待执行 </div>
<div class="bottom-box-item-title-right" @click="toManyTask('未开始')"> 查看更多 </div>
<div class="bottom-box-item-title-right" @click="toManyTask('未开始')">
查看更多
</div>
</div>
<div>
<el-table :data="data.pendingExecution" style="width: 100%">
@ -128,13 +137,83 @@
</div>
</div>
</el-col>
<el-col :span="12"> 2 </el-col>
<!-- 实时地图 -->
<el-col :span="12">
<div style="margin-bottom: 10px">
<el-cascader
v-model="mapValue"
:options="list"
@change="handleChangeMap"
style="width: 160px"
/>
</div>
<div style="width: 100%; padding-bottom: 120px" class="map-box-allBoard">
<indexPage ref="indexPageRef" />
</div>
<div
style="position: fixed; bottom: 20px"
:style="{ width: widthVal + 'px', left: leftVal + 'px' }"
v-if="data&&data.deviceStatusInfoVOS"
>
<div
ref="scrollContainer"
class="scroll-container"
@mousedown="startDrag"
@mousemove="onDrag"
@mouseup="endDrag"
@mouseleave="endDrag"
>
<div class="content">
<div v-for="(n, i) in data.deviceStatusInfoVOS" :key="i" class="item" :class="{ noBoarder: i === data.deviceStatusInfoVOS.length - 1 }">
<div class="scroll-container-item-left">
<div class="scroll-container-item-left-title">{{ filterTypeFun(n.deviceType, typeList) }}</div>
<div class="scroll-container-item-left-img">
<img
:src="n.defaultImage"
alt=""
object-fit="contain"
style="width: 100%; height: 100%"
/>
</div>
</div>
<div class="scroll-container-item-right">
<div class="scroll-container-item-right-item">
<div class="scroll-container-item-right-item-title">
数量
</div>
<div class="scroll-container-item-right-item-num">
{{ n.totalNum || 0 }}
</div>
</div>
<div class="scroll-container-item-right-item" style="margin-top: 3px;">
<div class="scroll-container-item-right-item-title">
正常数量
</div>
<div class="scroll-container-item-right-item-num">
{{ n.normalNum || 0 }}
</div>
</div>
<div class="scroll-container-item-right-item" style="margin-top: 3px;">
<div class="scroll-container-item-right-item-title">
异常数量
</div>
<div class="scroll-container-item-right-item-num" style="color: #c60606">
{{ n.abnormalNum || 0 }}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</el-col>
<!-- 右边 -->
<el-col :span="6">
<div class="bottom-box-item" v-if="data">
<div class="bottom-box-item-table">
<div class="bottom-box-item-title">
<div class="bottom-box-item-title-left"> 异常信息 </div>
<div class="bottom-box-item-title-right"> 查看更多 </div>
<div class="bottom-box-item-title-right" @click="toManyWarnMsg"> 查看更多 </div>
</div>
<div>
<el-table :data="data.robotWarnMsgDOS" style="width: 100%">
@ -142,8 +221,10 @@
<el-table-column prop="warnMsg" label="异常信息">
<template #default="scope">
<div class="warn-msg">
<div class="warn-msg-color" :style="{ backgroundColor: computedBackgroundColor(scope.row.warnLevel) }">
<div
class="warn-msg-color"
:style="{ backgroundColor: computedBackgroundColor(scope.row.warnLevel) }"
>
</div>
<div class="warn-msg-text">
{{ scope.row.warnMsg || '' }}
@ -152,7 +233,6 @@
</template>
</el-table-column>
<el-table-column prop="createTime" label="发生时间" :formatter="dateFormatter" />
</el-table>
</div>
</div>
@ -161,7 +241,7 @@
<div class="bottom-box-item-table">
<div class="bottom-box-item-title">
<div class="bottom-box-item-title-left"> 车辆信息 </div>
<div class="bottom-box-item-title-right"> 查看更多 </div>
<div class="bottom-box-item-title-right" @click="goCarBord"> 查看更多 </div>
</div>
<div>
<el-table :data="data.robotElectricityLevelVOS" style="width: 100%">
@ -176,16 +256,42 @@
<div v-if="scope.row.batSoc === null"></div>
<div class="battery-box-all">
<div class="battery-box" v-if="scope.row.batSoc !== null">
<img src="@/assets/imgs/allBoard/dianlianggreen.png" alt="" class="battery-box-img" v-if="scope.row.batSoc >=40"/>
<img src="@/assets/imgs/allBoard/dianliangyellow.png" alt="" class="battery-box-img" v-if="(scope.row.batSoc < 40) && (scope.row.batSoc >=20)"/>
<img src="@/assets/imgs/allBoard/dianliangred.png" alt="" class="battery-box-img" v-if="scope.row.batSoc < 20"/>
<img
src="@/assets/imgs/allBoard/dianlianggreen.png"
alt=""
class="battery-box-img"
v-if="scope.row.batSoc >= 40"
/>
<img
src="@/assets/imgs/allBoard/dianliangyellow.png"
alt=""
class="battery-box-img"
v-if="scope.row.batSoc < 40 && scope.row.batSoc >= 20"
/>
<img
src="@/assets/imgs/allBoard/dianliangred.png"
alt=""
class="battery-box-img"
v-if="scope.row.batSoc < 20"
/>
<div class="battery-box-inner">
<div class="battery-box-inner-inner " :class="scope.row.batSoc >=40 ? 'green-bg' : scope.row.batSoc < 40 && scope.row.batSoc >=20 ? 'yellow-bg' : 'red-bg'" :style="{width: scope.row.batSoc+'%'}">
<div
class="battery-box-inner-inner"
:class="
scope.row.batSoc >= 40
? 'green-bg'
: scope.row.batSoc < 40 && scope.row.batSoc >= 20
? 'yellow-bg'
: 'red-bg'
"
:style="{ width: scope.row.batSoc + '%' }"
>
</div>
</div>
</div>
<span class="battery-box-text" v-if="scope.row.batSoc !== null">{{scope.row.batSoc || 0}}%</span>
<span class="battery-box-text" v-if="scope.row.batSoc !== null"
>{{ scope.row.batSoc || 0 }}%</span
>
</div>
</template>
</el-table-column>
@ -202,8 +308,12 @@
import { ref, reactive, onMounted, onBeforeUnmount } from 'vue'
import { dateFormatter } from '@/utils/formatTime'
import * as ChartsApi from '@/api/boardCharts'
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { DICT_TYPE, getIntDictOptions,getDictOptions } from '@/utils/dict'
import indexPage from './indexPage.vue'
import * as MapApi from '@/api/map/map'
const router = useRouter() //
const indexPageRef = ref(null)
const typeList = ref([])
defineOptions({ name: 'BoardAllBoard' })
const data = ref(null)
//
@ -212,7 +322,15 @@ const getAllData = async () => {
console.log(datas)
data.value = datas
}
const widthVal = ref(0)
const leftVal = ref(0)
const getWidth = (val) => {
widthVal.value = val
console.log(widthVal.value)
}
const getLeftPx = (val) => {
leftVal.value = val
}
//
const computedBackgroundColor = (warnLevel) => {
switch (warnLevel) {
@ -229,6 +347,7 @@ const computedBackgroundColor = (warnLevel) => {
}
}
//
const toManyTask = (type) => {
// console.log(getIntDictOptions(DICT_TYPE.ROBOT_TASK_STATUS))
// return
@ -240,8 +359,185 @@ const toManyTask = (type) => {
})
}
//
const toManyWarnMsg = () => {
router.push({
path: '/carError'
})
}
//
const goCarBord = () => {
router.push({
path: '/board/carBoard',
})
}
const list = ref([]) //
const mapValue = ref([]) //
const mapInfo = ref(null) //
//
const getList = async () => {
let data = await MapApi.getPositionMapGetMap()
let mapList = []
for (let key in data) {
mapList.push({
floor: key,
label: key + '层',
value: key,
children: data[key]
})
}
if (mapList.length) {
mapList.forEach((item) => {
if (item.children.length) {
item.children.forEach((child) => {
child.label = child.area
child.value = child.id
})
}
})
}
list.value = mapList
console.log(list.value, data)
if (mapValue.value.length) {
handleChangeMap(mapValue.value)
} else {
mapValue.value = [list.value[0].value, list.value[0].children[0].value]
mapInfo.value = list.value[0].children[0]
? JSON.parse(JSON.stringify(list.value[0].children[0]))
: {
mapId: '',
floor: '',
area: ''
}
indexPageRef.value.getMapData(mapInfo.value)
}
}
//
const handleChangeMap = async (e) => {
mapInfo.value = findChildrenByValues(list.value, e)
? findChildrenByValues(list.value, e)
: {
mapId: '',
floor: '',
area: ''
}
console.log(mapInfo.value)
indexPageRef.value.getMapData(mapInfo.value)
}
//
const findChildrenByValues = (tree, values) => {
if (!tree || tree.length === 0) {
return null
}
function traverse(node) {
if (node.children) {
for (let child of node.children) {
if (values.includes(child.value)) {
return child
}
let result = traverse(child)
if (result) {
return result
}
}
}
return null
}
for (let root of tree) {
if (values.includes(root.value)) {
if (root.children) {
for (let child of root.children) {
if (values.includes(child.value)) {
return child
}
let result = traverse(child)
if (result) {
return result
}
}
}
}
let result = traverse(root)
if (result) {
return result
}
}
return null
}
const scrollContainer = ref(null)
let isDragging = false
let startX = 0
let scrollLeft = 0
const startDrag = (e) => {
isDragging = true
const rect = scrollContainer.value.getBoundingClientRect()
startX = e.clientX - rect.left
scrollLeft = scrollContainer.value.scrollLeft
scrollContainer.value.style.cursor = 'grabbing'
}
const onDrag = (e) => {
if (!isDragging) return
const rect = scrollContainer.value.getBoundingClientRect()
const mouseX = e.clientX - rect.left
const dragDistance = (mouseX - startX) * 2.5 //
scrollContainer.value.scrollLeft = scrollLeft - dragDistance
}
const endDrag = () => {
isDragging = false
scrollContainer.value.style.cursor = 'grab'
}
const getElementWidthByClass = (className) => {
const element = document.querySelector(`.${className}`)
if (element) {
// return window.getComputedStyle(element).width
const widthWithUnit = window.getComputedStyle(element).width
return widthWithUnit.slice(0, -2)
}
return null
}
const getLeft = () => {
let indexpageContainer = document.getElementsByClassName('map-box-allBoard')[0]
// console.log('', indexpageContainer.getBoundingClientRect().left)
leftVal.value = indexpageContainer.getBoundingClientRect().left
}
const getWidthPx = () => {
let width = getElementWidthByClass('map-box-allBoard')
// console.log("pppppppppppppp",width)
widthVal.value = width
}
const getLeftWidth = () => {
nextTick(() => {
getWidthPx()
getLeft()
})
}
//type
const filterTypeFun = (type, list) => {
if (list.length) {
let obj = list.find(item => {
return item.value == type
})
return obj == undefined ? type : obj.label
} else {
return type
}
}
onMounted(() => {
typeList.value = getDictOptions(DICT_TYPE.DEVICE_TYPE)
getAllData()
getList()
getLeftWidth()
window.addEventListener('resize', getLeftWidth)
})
onBeforeUnmount(() => {
window.removeEventListener('resize', getLeftWidth)
})
</script>
@ -311,7 +607,6 @@ onMounted(() => {
width: 22px;
height: 11px;
position: relative;
}
.battery-box-img {
width: 100%;
@ -328,22 +623,23 @@ onMounted(() => {
}
.battery-box-inner-inner {
height: 100%;
}
.green-bg {
background: #52C41A;
background: #52c41a;
}
.yellow-bg {
background: #F1CD0B;
background: #f1cd0b;
}
.red-bg {
background: #C60606;
background: #c60606;
}
.battery-box-text {
font-family: PingFangSC, PingFang SC;
font-family:
PingFangSC,
PingFang SC;
font-weight: 400;
font-size: 12px;
color: #0D162A;
color: #0d162a;
margin-left: 3px;
}
.battery-box-all {
@ -353,7 +649,6 @@ margin-left: 3px;
}
.warn-msg {
display: flex;
}
.warn-msg-color {
width: 8px;
@ -365,11 +660,97 @@ margin-left: 3px;
}
.warn-msg-text {
flex: 1;
font-family:
PingFangSC,
PingFang SC;
font-weight: 400;
font-size: 12px;
color: #0d162a;
margin-top: -3px;
}
/* 容器样式 */
.scroll-container {
width: 100%;
height: 104px;
overflow: hidden;
position: relative;
cursor: grab;
user-select: none;
background: #fff;
margin-top: 10px;
}
/* 隐藏滚动条 */
.scroll-container::-webkit-scrollbar {
display: none;
}
/* 内容布局 */
.content {
display: inline-flex;
height: 100%;
padding: 20px 0;
white-space: nowrap;
}
/* 单个项目样式 */
.item {
display: inline-flex;
align-items: center;
padding: 17px 30px;
background: #fff;
transition: transform 0.2s;
border-right: 2px solid #e9e9e9;
}
/* .item:hover {
transform: translateY(-3px);
} */
/* 拖拽时状态 */
.scroll-container:active {
cursor: grabbing;
}
.scroll-container-item-left-title {
font-family:
PingFangSC,
PingFang SC;
font-weight: 500;
font-size: 14px;
color: #0d162a;
margin-bottom: 14px;
flex-shrink: 0;
}
.scroll-container-item-left-img {
width: 40px;
height: 40px;
vertical-align: top;
flex-shrink: 0;
}
.scroll-container-item-right {
flex-shrink: 0;
margin-left: 16px;
}
.noBoarder{
border-right: none;
}
.scroll-container-item-right-item{
display: flex;
flex-shrink: 0;
}
.scroll-container-item-right-item-title{
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 12px;
color: #0D162A;
margin-top: -3px;
flex-shrink: 0;
}
.scroll-container-item-right-item-num{
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 12px;
color: #0D162A;
flex-shrink: 0;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -10,7 +10,7 @@
}"
>
<div
class="indexpage-container"
:class="isDrag ? 'indexpage-container-active' : 'indexpage-container'"
v-if="imgUrl"
v-drag="isDrag"
:style="{ scale: 1, transformOrigin: '0 0' }"
@ -31,11 +31,11 @@
:x2="(Number(item.endPointX) + Number(item.endWidth) / 2) * radio"
:y2="(Number(item.endPointY) + Number(item.endHigh) / 2) * radio"
stroke="#00329F"
stroke-width="5"
:stroke-width="5*radio"
/>
</template>
<template v-else>
<path :d="getCurvePath(item)" :stroke="'#00329F'" stroke-width="5" fill="none" />
<path :d="getCurvePath(item)" :stroke="'#00329F'" :stroke-width="5*radio" fill="none" />
</template>
</svg>
</div>
@ -239,7 +239,7 @@
placement="top"
v-if="item.type == 1"
>
<div style="width: 10px; height: 10px; border-radius: 50%; background: #1890ff">
<div :style="{ width: 10 * radio + 'px', height: 10 * radio + 'px', background: '#1890ff'}">
</div>
</el-tooltip>
</div>
@ -899,6 +899,14 @@ onUnmounted(() => {
width: 100%;
position: relative;
}
.indexpage-container-active{
width: 100%;
position: relative;
cursor: grab;
}
.indexpage-container-active:active {
cursor: grabbing;
}
.indexpage-container .affix-container-top {
width: 100%;
height: 80px;