Merge branch 'xhf' of http://git.znkjfw.com/ak/zn-admin-vue3-wcs into xhf
2
.env.dev
@ -6,7 +6,7 @@ VITE_DEV=true
|
|||||||
# 请求路径
|
# 请求路径
|
||||||
# VITE_BASE_URL='http://192.168.0.66:48080'
|
# VITE_BASE_URL='http://192.168.0.66:48080'
|
||||||
# VITE_BASE_URL='http://192.168.0.189:48080'
|
# VITE_BASE_URL='http://192.168.0.189:48080'
|
||||||
VITE_BASE_URL='http://192.168.0.74:48080'
|
VITE_BASE_URL='http://192.168.0.66:48080'
|
||||||
|
|
||||||
# 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持S3服务
|
# 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持S3服务
|
||||||
VITE_UPLOAD_TYPE=server
|
VITE_UPLOAD_TYPE=server
|
||||||
|
BIN
src/assets/imgs/indexPage/chache-4@2x(1).png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
src/assets/imgs/indexPage/chache-4@2x.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
src/assets/imgs/indexPage/chache-4备份 2@2x.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
src/assets/imgs/indexPage/chache-4备份 3@2x.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
src/assets/imgs/indexPage/chache-4备份 4@2x.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
src/assets/imgs/indexPage/chache-4备份 5@2x.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
src/assets/imgs/indexPage/chache-4备份 6@2x.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
src/assets/imgs/indexPage/chache-4备份 7@2x.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
src/assets/imgs/indexPage/chache-4备份 8@2x.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
src/assets/imgs/indexPage/chache-4备份 9@2x.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
src/assets/imgs/indexPage/chache-4备份@2x.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
src/assets/imgs/indexPage/chongdianzhuang_ceshi@2x.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
src/assets/imgs/indexPage/shusongxian-youhuo@2x.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
src/assets/imgs/indexPage/shusongxian@2x.png
Normal file
After Width: | Height: | Size: 727 B |
BIN
src/assets/imgs/indexPage/tuopan备份 18@2x.png
Normal file
After Width: | Height: | Size: 767 B |
BIN
src/assets/imgs/indexPage/tuopan备份 62@2x.png
Normal file
After Width: | Height: | Size: 428 B |
BIN
src/assets/imgs/indexPage/直线 4备份@2x.png
Normal file
After Width: | Height: | Size: 101 B |
BIN
src/assets/imgs/indexPage/直线备份@2x.png
Normal file
After Width: | Height: | Size: 98 B |
BIN
src/assets/imgs/indexPage/编组 10@2x.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
src/assets/imgs/indexPage/编组 11@2x.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
src/assets/imgs/indexPage/编组 12@2x.png
Normal file
After Width: | Height: | Size: 860 B |
BIN
src/assets/imgs/indexPage/编组 13@2x.png
Normal file
After Width: | Height: | Size: 551 B |
BIN
src/assets/imgs/indexPage/编组 15@2x(1).png
Normal file
After Width: | Height: | Size: 8.6 KiB |
BIN
src/assets/imgs/indexPage/编组 15@2x.png
Normal file
After Width: | Height: | Size: 8.0 KiB |
BIN
src/assets/imgs/indexPage/编组 15备份 2@2x.png
Normal file
After Width: | Height: | Size: 8.8 KiB |
BIN
src/assets/imgs/indexPage/编组 15备份 3@2x.png
Normal file
After Width: | Height: | Size: 8.8 KiB |
BIN
src/assets/imgs/indexPage/编组 15备份 4@2x.png
Normal file
After Width: | Height: | Size: 8.7 KiB |
BIN
src/assets/imgs/indexPage/编组 15备份@2x.png
Normal file
After Width: | Height: | Size: 8.8 KiB |
BIN
src/assets/imgs/indexPage/编组 16@2x.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
src/assets/imgs/indexPage/编组 17@2x.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
src/assets/imgs/indexPage/编组 18@2x.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
src/assets/imgs/indexPage/编组 19@2x.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
src/assets/imgs/indexPage/编组 24@2x.png
Normal file
After Width: | Height: | Size: 443 B |
BIN
src/assets/imgs/indexPage/编组 2@2x.png
Normal file
After Width: | Height: | Size: 7.9 KiB |
BIN
src/assets/imgs/indexPage/编组 3@2x.png
Normal file
After Width: | Height: | Size: 7.7 KiB |
BIN
src/assets/imgs/indexPage/编组 4@2x.png
Normal file
After Width: | Height: | Size: 7.8 KiB |
BIN
src/assets/imgs/indexPage/编组 4备份 26@2x.png
Normal file
After Width: | Height: | Size: 732 B |
BIN
src/assets/imgs/indexPage/编组 4备份 27@2x.png
Normal file
After Width: | Height: | Size: 732 B |
BIN
src/assets/imgs/indexPage/编组 4备份 37@2x.png
Normal file
After Width: | Height: | Size: 751 B |
BIN
src/assets/imgs/indexPage/编组 4备份 38@2x.png
Normal file
After Width: | Height: | Size: 751 B |
BIN
src/assets/imgs/indexPage/编组 6@2x.png
Normal file
After Width: | Height: | Size: 7.8 KiB |
BIN
src/assets/imgs/indexPage/编组 7@2x.png
Normal file
After Width: | Height: | Size: 7.8 KiB |
BIN
src/assets/imgs/indexPage/编组 8@2x.png
Normal file
After Width: | Height: | Size: 481 B |
BIN
src/assets/imgs/indexPage/编组 9@2x.png
Normal file
After Width: | Height: | Size: 859 B |
BIN
src/assets/imgs/indexPage/编组@2x.png
Normal file
After Width: | Height: | Size: 7.7 KiB |
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<Dialog v-model="dialogVisible" :title="title" width="545px" class="task-dialog">
|
<Dialog v-model="dialogVisible" :title="title" width="545px" style="padding: 0;">
|
||||||
<el-form :model="formData" label-width="auto" ref="formRef" :rules="formRules">
|
<el-form :model="formData" label-width="auto" ref="formRef" :rules="formRules">
|
||||||
<el-form-item label="车辆类型" prop="robotModelId" required>
|
<el-form-item label="车辆类型" prop="robotModelId" required>
|
||||||
<el-select v-model="formData.robotModelId" placeholder="请选择车辆类型" required :disabled="formData.id">
|
<el-select v-model="formData.robotModelId" placeholder="请选择车辆类型" required :disabled="formData.id">
|
||||||
@ -49,8 +49,10 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
<template #footer >
|
<template #footer >
|
||||||
|
<div style="padding: 0 10px 10px 0;">
|
||||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||||
<el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
|
<el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</template>
|
</template>
|
||||||
@ -226,18 +228,15 @@ const resetForm = () => {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss" scoped>
|
||||||
.task-dialog {
|
::v-deep .el-dialog {
|
||||||
|
padding: 0 !important;
|
||||||
// .el-dialog__header {
|
|
||||||
// border-bottom: none;
|
|
||||||
// }
|
|
||||||
|
|
||||||
.el-dialog__footer {
|
|
||||||
border-top: none !important;
|
|
||||||
}
|
}
|
||||||
|
::v-deep .el-dialog__header {
|
||||||
|
border-bottom: 1px solid #e8e8e8 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.task-tips {
|
.task-tips {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -79,17 +79,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="new-top-box-right">
|
<div class="new-top-box-right">
|
||||||
<!-- <el-input
|
|
||||||
v-model="queryParams.robotNo"
|
|
||||||
style="width: 240px"
|
|
||||||
placeholder="请输入关键字"
|
|
||||||
clearable
|
|
||||||
>
|
|
||||||
<template #append>
|
|
||||||
<el-button><Icon icon="ep:search" @click="getCarList" /></el-button
|
|
||||||
></template>
|
|
||||||
</el-input>
|
|
||||||
<el-button type="primary" @click="openForm('create')">新增车辆</el-button> -->
|
|
||||||
<div class="new-top-box-right-input-box">
|
<div class="new-top-box-right-input-box">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
@ -236,8 +225,8 @@
|
|||||||
<div class="item-inner-right-msg-item-name">车辆状态</div>
|
<div class="item-inner-right-msg-item-name">车辆状态</div>
|
||||||
<div class="item-inner-right-msg-item-value">
|
<div class="item-inner-right-msg-item-value">
|
||||||
<span v-if="item.robotEssenceStatus == 2" style="color: #c60606">异常</span>
|
<span v-if="item.robotEssenceStatus == 2" style="color: #c60606">异常</span>
|
||||||
<span v-if="item.robotEssenceStatus == 1" style="color: #f1cd0b">锁定</span>
|
<span v-if="item.robotEssenceStatus == 0" style="color: #f1cd0b">锁定</span>
|
||||||
<span v-if="item.robotEssenceStatus == 0" style="color: #4dc606">空闲</span>
|
<span v-if="item.robotEssenceStatus == 1" style="color: #4dc606">空闲</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="item-inner-right-msg-item m-b-10">
|
<div class="item-inner-right-msg-item m-b-10">
|
||||||
@ -321,6 +310,7 @@ const message = useMessage() // 消息弹窗
|
|||||||
// 引入swiper核心和所需模块
|
// 引入swiper核心和所需模块
|
||||||
// import { Autoplay, Pagination, Navigation, Scrollbar } from 'swiper'
|
// import { Autoplay, Pagination, Navigation, Scrollbar } from 'swiper'
|
||||||
import createEditDialog from './createEditDialog.vue'
|
import createEditDialog from './createEditDialog.vue'
|
||||||
|
const route = useRoute() // 路由
|
||||||
// import 'swiper/css'
|
// import 'swiper/css'
|
||||||
const router = useRouter() // 路由对象
|
const router = useRouter() // 路由对象
|
||||||
const createEditDialogRef = ref(null)
|
const createEditDialogRef = ref(null)
|
||||||
@ -472,6 +462,9 @@ const goToMap = (item) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
if(route.query.robotNo){
|
||||||
|
queryParams.robotNo = route.query.robotNo
|
||||||
|
}
|
||||||
getCarList()
|
getCarList()
|
||||||
getRobotInformationStatistics()
|
getRobotInformationStatistics()
|
||||||
})
|
})
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<Dialog v-model="dialogVisible" :title="title" width="545" class="task-dialog">
|
<Dialog v-model="dialogVisible" :title="title" width="545" style="padding: 0;">
|
||||||
<el-form :model="formData" label-width="auto" ref="formRef" :rules="formRules">
|
<el-form :model="formData" label-width="auto" ref="formRef" :rules="formRules">
|
||||||
<el-form-item label="设备类型" prop="robotModelId" >
|
<el-form-item label="设备类型" prop="robotModelId" >
|
||||||
<el-select v-model="formData.deviceType" clearable placeholder="请选择设备类型">
|
<el-select v-model="formData.deviceType" clearable placeholder="请选择设备类型">
|
||||||
@ -34,8 +34,10 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
|
<div style="padding: 0 10px 10px 0;">
|
||||||
<el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
|
<el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
|
||||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</template>
|
</template>
|
||||||
@ -174,15 +176,12 @@ const resetForm = () => {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style scoped>
|
||||||
.task-dialog {
|
::v-deep .el-dialog {
|
||||||
.el-dialog__header {
|
padding: 0 !important;
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-dialog__footer {
|
|
||||||
border-top: none !important;
|
|
||||||
}
|
}
|
||||||
|
::v-deep .el-dialog__header {
|
||||||
|
border-bottom: 1px solid #e8e8e8 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-tips {
|
.task-tips {
|
||||||
|
186
src/views/mapPage/realTimeMap/components/carDialog.vue
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
<template>
|
||||||
|
<Dialog v-model="dialogVisible" title="车辆信息" width="545" style="padding: 0">
|
||||||
|
<div class="dialog-box">
|
||||||
|
<div class="dialog-box-left" :style="{ background: formData.url?'#ffffff':'#EEEEEE' }">
|
||||||
|
<el-image style="width: 100%; height: 100%" :src="formData.url" fit="contain" />
|
||||||
|
</div>
|
||||||
|
<div class="dialog-box-right">
|
||||||
|
<div class="dialog-box-right-top">
|
||||||
|
<div class="dialog-box-right-top-btn"> 急停 </div>
|
||||||
|
</div>
|
||||||
|
<div class="dialog-box-right-item">
|
||||||
|
<div class="dialog-box-right-item-left"> 编号 </div>
|
||||||
|
<div class="dialog-box-right-item-right">
|
||||||
|
{{ formData.robotNo || '' }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="dialog-box-right-item">
|
||||||
|
<div class="dialog-box-right-item-left"> 电量 </div>
|
||||||
|
<div class="dialog-box-right-item-right">
|
||||||
|
{{ formData.electricity || '' }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="dialog-box-right-item">
|
||||||
|
<div class="dialog-box-right-item-left"> 车辆状态 </div>
|
||||||
|
<div class="dialog-box-right-item-right">
|
||||||
|
<span v-if="formData.robotEssenceStatus == 2" style="color: #c60606">异常</span>
|
||||||
|
<span v-if="formData.robotEssenceStatus == 0" style="color: #f1cd0b">锁定</span>
|
||||||
|
<span v-if="formData.robotEssenceStatus == 1" style="color: #4dc606">空闲</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="dialog-box-right-item">
|
||||||
|
<div class="dialog-box-right-item-left"> 任务状态 </div>
|
||||||
|
<div class="dialog-box-right-item-right">
|
||||||
|
<span v-if="formData.robotTaskStatus == 1" style="color: #f1cd0b">工作中</span>
|
||||||
|
<span v-if="formData.robotTaskStatus == 0" style="color: #4dc606">待命中</span>
|
||||||
|
<span v-if="formData.robotTaskStatus == 2" style="color: #e07300">充电中</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="dialog-box-right-item">
|
||||||
|
<div class="dialog-box-right-item-left"> 楼层 </div>
|
||||||
|
<div class="dialog-box-right-item-right">
|
||||||
|
{{ formData.floor || '' }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="dialog-box-right-item">
|
||||||
|
<div class="dialog-box-right-item-left"> 区域 </div>
|
||||||
|
<div class="dialog-box-right-item-right">
|
||||||
|
{{ formData.area || '' }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="dialog-box-right-item">
|
||||||
|
<div class="dialog-box-right-item-left"> 信息 </div>
|
||||||
|
<div class="dialog-box-right-item-right">
|
||||||
|
{{ formData.msg || '' }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="dialog-box-right-item">
|
||||||
|
<div class="dialog-box-right-item-left" style="color: #1677FF;cursor: pointer;" @click="goCarBord"> 更多操作 </div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Dialog>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
const { t } = useI18n() // 国际化
|
||||||
|
const message = useMessage() // 消息弹窗
|
||||||
|
import * as CarApi from '@/api/car/index'
|
||||||
|
const dialogVisible = ref(false) // 弹窗的是否展示
|
||||||
|
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
|
||||||
|
const id = ref('')
|
||||||
|
const formData = ref({})
|
||||||
|
const formRules = reactive({})
|
||||||
|
const selectIndex = ref(0)
|
||||||
|
const formRef = ref() // 表单 Ref
|
||||||
|
const storeData = ref([])
|
||||||
|
/** 打开弹窗 */
|
||||||
|
const open = async (data) => {
|
||||||
|
console.log(data)
|
||||||
|
|
||||||
|
resetForm()
|
||||||
|
if (data.data.id) {
|
||||||
|
let paramsData = await CarApi.getRobotInformation({ id: data.data.id })
|
||||||
|
console.log(paramsData)
|
||||||
|
formData.value = paramsData
|
||||||
|
}
|
||||||
|
dialogVisible.value = true
|
||||||
|
}
|
||||||
|
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
|
||||||
|
|
||||||
|
//前往任务管理页面
|
||||||
|
const { push } = useRouter()
|
||||||
|
|
||||||
|
/** 重置表单 */
|
||||||
|
const resetForm = () => {
|
||||||
|
// formData.value = {
|
||||||
|
// locationNo: undefined, //库位编号
|
||||||
|
// areaName: undefined, //区域名称
|
||||||
|
// locationUseStatus: undefined, //库位状态 (0:空闲、1:占用)
|
||||||
|
// locationEnable: undefined, //是否禁用(0:禁用、1:启用)
|
||||||
|
// skuInfo: undefined //物料信息
|
||||||
|
// }
|
||||||
|
// formRef.value?.resetFields()
|
||||||
|
}
|
||||||
|
const goCarBord = () => {
|
||||||
|
push({
|
||||||
|
path: '/board/carBoard',
|
||||||
|
query: {
|
||||||
|
robotNo: formData.value.robotNo
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
::v-deep .el-dialog {
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
::v-deep .el-dialog__header {
|
||||||
|
border-bottom: 1px solid #e8e8e8 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-dialog__footer {
|
||||||
|
border-top: none !important;
|
||||||
|
}
|
||||||
|
.dialog-box {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
padding: 15px;
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
.dialog-box-left {
|
||||||
|
width: 252px;
|
||||||
|
height: 324px;
|
||||||
|
background: #eeeeee;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.dialog-box-right {
|
||||||
|
margin-left: 24px;
|
||||||
|
flex: 1;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.dialog-box-right-top {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
.dialog-box-right-top-btn {
|
||||||
|
width: 104px;
|
||||||
|
height: 36px;
|
||||||
|
background: #c60606;
|
||||||
|
font-family:
|
||||||
|
PingFangSC,
|
||||||
|
PingFang SC;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #ffffff;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 36px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.dialog-box-right-item {
|
||||||
|
display: flex;
|
||||||
|
margin-top: 24px;
|
||||||
|
}
|
||||||
|
.dialog-box-right-item-left {
|
||||||
|
font-family:
|
||||||
|
PingFangSC,
|
||||||
|
PingFang SC;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #0d162a;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.dialog-box-right-item-right {
|
||||||
|
font-family:
|
||||||
|
PingFangSC,
|
||||||
|
PingFang SC;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 18px;
|
||||||
|
color: #0d162a;
|
||||||
|
margin-left: 10px;
|
||||||
|
flex: 1;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
word-break:break-all;
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="affix-container" :style="{ height: heightVal + 'px' }">
|
<div class="affix-container" :style="{ height: (heightVal*radio ) + 'px'}">
|
||||||
<el-affix target=".affix-container" :offset="80">
|
<!-- <el-affix target=".affix-container" :offset="80">
|
||||||
<span @click="resetPosition ">回到原点</span>
|
<span @click="resetPosition ">回到原点</span>
|
||||||
<div class="affix-container-top">
|
<div class="affix-container-top">
|
||||||
<el-scrollbar>
|
<el-scrollbar>
|
||||||
@ -28,13 +28,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
</div>
|
</div>
|
||||||
</el-affix>
|
</el-affix> -->
|
||||||
<div class="indexpage-container" v-if="imgUrl" v-drag="true" :style="{scale:1,transformOrigin:'0 0'}" ref="draggableElement">
|
<div class="indexpage-container" v-if="imgUrl" v-drag="true" :style="{scale:1,transformOrigin:'0 0'}" ref="draggableElement">
|
||||||
<div class="indexpage-container-box">
|
<div class="indexpage-container-box">
|
||||||
<img :src="imgUrl" alt="" class="indexpage-container-box-img" />
|
<img :src="imgUrl" alt="" class="indexpage-container-box-img" />
|
||||||
|
|
||||||
<div class="indexpage-container-box-point">
|
<div class="indexpage-container-box-point">
|
||||||
<div
|
<!-- 连线 -->
|
||||||
|
<!-- <div
|
||||||
class="line-box"
|
class="line-box"
|
||||||
v-for="(item, index) in lineList"
|
v-for="(item, index) in lineList"
|
||||||
:key="index"
|
:key="index"
|
||||||
@ -48,6 +49,19 @@
|
|||||||
transformOrigin: 'left top'
|
transformOrigin: 'left top'
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
|
</div> -->
|
||||||
|
<!-- 小车 -->
|
||||||
|
<div class="indexpage-car-item"
|
||||||
|
v-for="(item, index) in testCarList"
|
||||||
|
@dblclick="carDbClick(item,index)"
|
||||||
|
:key="index"
|
||||||
|
:style="{
|
||||||
|
left: item.realX * radio + 'px',
|
||||||
|
top: item.realY * radio + 'px',
|
||||||
|
width: 40 * radio + 'px',
|
||||||
|
height: 22 * radio + 'px',
|
||||||
|
}">
|
||||||
|
<img src="@/assets/imgs/indexPage/chache-4备份 7@2x.png" alt="" style="width: 100%; height: 100%" />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="indexpage-container-box-point-item"
|
class="indexpage-container-box-point-item"
|
||||||
@ -107,14 +121,6 @@
|
|||||||
{{ item.showData.areaName || '' }}
|
{{ item.showData.areaName || '' }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- <div class="indexpage-container-box-point-item-inner-popover-item" style="margin-bottom: 8px;">
|
|
||||||
<div class="indexpage-container-box-point-item-inner-popover-name">
|
|
||||||
状态:
|
|
||||||
</div>
|
|
||||||
<div class="indexpage-container-box-point-item-inner-popover-value">
|
|
||||||
{{ item.showData.locationUseStatus == 0 ? '空闲' : '占用' }}
|
|
||||||
</div>
|
|
||||||
</div> -->
|
|
||||||
</div>
|
</div>
|
||||||
</el-popover>
|
</el-popover>
|
||||||
</div>
|
</div>
|
||||||
@ -130,6 +136,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<storeDialog ref="storeDialogRef" @success="getList" />
|
<storeDialog ref="storeDialogRef" @success="getList" />
|
||||||
|
<carDialog ref="carDialogRef" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@ -139,14 +146,33 @@ import WebSocketClient from '../webSocket.js'
|
|||||||
import storeDialog from './storeDialog.vue'
|
import storeDialog from './storeDialog.vue'
|
||||||
import { color } from 'echarts'
|
import { color } from 'echarts'
|
||||||
import { resetDragPosition } from '@/utils/drag'
|
import { resetDragPosition } from '@/utils/drag'
|
||||||
|
import carDialog from './carDialog.vue'
|
||||||
const imgUrl = ref('')
|
const imgUrl = ref('')
|
||||||
|
const carDialogRef = ref(null)
|
||||||
const socketClient = ref(null)
|
const socketClient = ref(null)
|
||||||
|
|
||||||
const emit = defineEmits(['transmitMapId'])
|
const emit = defineEmits(['transmitMapId'])
|
||||||
const storeDialogRef = ref(null)
|
const storeDialogRef = ref(null)
|
||||||
const list = ref([])
|
const list = ref([])
|
||||||
const nowObject = ref(null)
|
const nowObject = ref(null)
|
||||||
|
const testCarList = ref([])
|
||||||
|
const carPointListFun = () => {
|
||||||
|
let testJson = {"type":"map_push","content":"{\"d0:65:78:c4:af:cc\":\"{\\\"id\\\":1,\\\"macAddress\\\":\\\"d0:65:78:c4:af:cc\\\",\\\"robotModelNumber\\\":\\\"A-1\\\",\\\"pose2d\\\":{\\\"y\\\":\\\"1\\\",\\\"x\\\":\\\"2\\\",\\\"yaw\\\":\\\"30\\\",\\\"floor\\\":\\\"1\\\",\\\"area\\\":\\\"A区\\\",\\\"bat_soc\\\":\\\"40\\\"}}\"}"}
|
||||||
|
let data = JSON.parse(testJson.content)
|
||||||
|
// console.log("============",data)
|
||||||
|
let dataList = []
|
||||||
|
for (let key in data) {
|
||||||
|
dataList.push({
|
||||||
|
macAddress: key,
|
||||||
|
data: JSON.parse(data[key])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
console.log("=====",dataList)
|
||||||
|
testCarList.value = dataList
|
||||||
|
|
||||||
|
// let data2 = JSON.parse(data['d0:65:78:c4:af:cc'])
|
||||||
|
// console.log(data2)
|
||||||
|
}
|
||||||
//获取地图区域
|
//获取地图区域
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
let data = await MapApi.getPositionMapGetMap()
|
let data = await MapApi.getPositionMapGetMap()
|
||||||
@ -154,9 +180,22 @@ const getList = async () => {
|
|||||||
for (let key in data) {
|
for (let key in data) {
|
||||||
mapList.push({
|
mapList.push({
|
||||||
floor: key,
|
floor: key,
|
||||||
|
label: key + '层',
|
||||||
|
value: key,
|
||||||
children: data[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
|
list.value = mapList
|
||||||
console.log(list.value, data)
|
console.log(list.value, data)
|
||||||
//默认取第一个
|
//默认取第一个
|
||||||
@ -280,6 +319,7 @@ const disconnect = () => {
|
|||||||
}
|
}
|
||||||
//获取扫描图
|
//获取扫描图
|
||||||
const getMapData = async (item) => {
|
const getMapData = async (item) => {
|
||||||
|
console.log("============",item)
|
||||||
nowObject.value = JSON.parse(JSON.stringify(item))
|
nowObject.value = JSON.parse(JSON.stringify(item))
|
||||||
let websoketUrl = `${replaceHttpWithWs(import.meta.env.VITE_BASE_URL)}/infra/ws?type=map&floor=${nowObject.value.floor}&area=${nowObject.value.area}`
|
let websoketUrl = `${replaceHttpWithWs(import.meta.env.VITE_BASE_URL)}/infra/ws?type=map&floor=${nowObject.value.floor}&area=${nowObject.value.area}`
|
||||||
console.log(websoketUrl)
|
console.log(websoketUrl)
|
||||||
@ -298,20 +338,48 @@ const getMapData = async (item) => {
|
|||||||
computedRatio()
|
computedRatio()
|
||||||
}
|
}
|
||||||
const heightVal = ref(0)
|
const heightVal = ref(0)
|
||||||
|
const widthVal = ref(0)
|
||||||
const radio = ref(1)
|
const radio = ref(1)
|
||||||
const computedRatio = () => {
|
const computedRatio = () => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
if (imgUrl.value) {
|
if (imgUrl.value) {
|
||||||
|
|
||||||
|
//这段代码之后会删掉 yaml会给原始宽高
|
||||||
|
getImageSize(imgUrl.value)
|
||||||
|
.then(({ width, height }) => {
|
||||||
|
// console.log("原始地图的宽高",JSON.parse(nowObject.value.yamlJson))
|
||||||
|
if(testCarList.value.length){
|
||||||
|
testCarList.value.forEach((item) => {
|
||||||
|
item.originWidth = width
|
||||||
|
item.originHeight = height
|
||||||
|
item.origin = JSON.parse(nowObject.value.yamlJson).origin
|
||||||
|
item.realX = convertToFrontendCoordinates(item.origin, width, height, [item.data.pose2d.x, item.data.pose2d.y]).left
|
||||||
|
item.realY = convertToFrontendCoordinates(item.origin, width, height, [item.data.pose2d.x, item.data.pose2d.y]).top
|
||||||
|
})
|
||||||
|
console.log("当前数据",testCarList.value)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error(error.message);
|
||||||
|
});
|
||||||
|
|
||||||
let width = getElementWidthByClass('indexpage-container')
|
let width = getElementWidthByClass('indexpage-container')
|
||||||
getImageWidth(imgUrl.value,'width').then((res) => {
|
getImageWidth(imgUrl.value,'width').then((res) => {
|
||||||
// console.log(res)
|
// console.log(res)
|
||||||
let ratioVal = width / res
|
let ratioVal = width / res
|
||||||
radio.value = ratioVal
|
radio.value = ratioVal
|
||||||
|
widthVal.value = res
|
||||||
if (pointList.value.length) {
|
if (pointList.value.length) {
|
||||||
pointList.value.forEach((item) => {
|
pointList.value.forEach((item) => {
|
||||||
item.radio = radio.value
|
item.radio = radio.value
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
if(testCarList.value.length){
|
||||||
|
testCarList.value.forEach((item) => {
|
||||||
|
item.radio = radio.value
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
getImageWidth(imgUrl.value,'height').then((res) => {
|
getImageWidth(imgUrl.value,'height').then((res) => {
|
||||||
console.log("高",res)
|
console.log("高",res)
|
||||||
@ -322,6 +390,44 @@ const computedRatio = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getImageSize = (url) =>{
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const img = new Image();
|
||||||
|
img.src = url;
|
||||||
|
// 图片加载成功时触发
|
||||||
|
img.onload = () => {
|
||||||
|
const width = img.width;
|
||||||
|
const height = img.height;
|
||||||
|
resolve({ width, height });
|
||||||
|
};
|
||||||
|
// 图片加载失败时触发
|
||||||
|
img.onerror = () => {
|
||||||
|
reject(new Error(`Failed to load image from URL 获取图片尺寸失败: ${url}`));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const convertToFrontendCoordinates = (origin, width, height, target) => {
|
||||||
|
// 提取原点的 x 和 y 坐标
|
||||||
|
const [originX, originY] = origin;
|
||||||
|
// 提取目标点的 x 和 y 坐标
|
||||||
|
const [targetX, targetY] = target;
|
||||||
|
|
||||||
|
// 计算目标点相对于原点在 x 方向上的偏移量
|
||||||
|
const offsetX = targetX - originX;
|
||||||
|
// 计算目标点相对于原点在 y 方向上的偏移量
|
||||||
|
const offsetY = targetY - originY;
|
||||||
|
|
||||||
|
// 计算前端页面中的 left 坐标
|
||||||
|
const left = offsetX;
|
||||||
|
// 计算前端页面中的 top 坐标,需要考虑坐标系的转换
|
||||||
|
const top = height - offsetY;
|
||||||
|
|
||||||
|
return {
|
||||||
|
top,
|
||||||
|
left,
|
||||||
|
origin
|
||||||
|
};
|
||||||
|
}
|
||||||
const getImageWidth = (imageUrl,name) => {
|
const getImageWidth = (imageUrl,name) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const img = new Image()
|
const img = new Image()
|
||||||
@ -344,9 +450,15 @@ const getElementWidthByClass = (className) => {
|
|||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
//小车双击
|
||||||
|
const carDbClick = (item,index) => {
|
||||||
|
console.log(item)
|
||||||
|
carDialogRef.value.open(JSON.parse(JSON.stringify(item)))
|
||||||
|
}
|
||||||
|
defineExpose({ getMapData }) // 提供 open 方法,用于打开弹窗
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList()
|
carPointListFun()
|
||||||
|
// getList()
|
||||||
window.addEventListener('resize', computedRatio)
|
window.addEventListener('resize', computedRatio)
|
||||||
})
|
})
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
@ -359,6 +471,7 @@ onBeforeUnmount(() => {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
background: rgba(0,0,0,0.8);
|
||||||
}
|
}
|
||||||
.indexpage-container {
|
.indexpage-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -430,4 +543,8 @@ onBeforeUnmount(() => {
|
|||||||
.line-box {
|
.line-box {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
|
.indexpage-car-item {
|
||||||
|
position: absolute;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,14 +1,25 @@
|
|||||||
<template>
|
<template>
|
||||||
<ContentWrap>
|
<ContentWrap>
|
||||||
<el-button type="success" @click="createTask">新建任务</el-button>
|
<div style="display: flex; align-items: center">
|
||||||
<el-button type="primary" @click="editMap">地图编辑</el-button>
|
<el-cascader
|
||||||
<el-button type="danger" @click="emergencyStop">一键急停</el-button>
|
v-model="mapValue"
|
||||||
|
:options="list"
|
||||||
|
@change="handleChangeMap"
|
||||||
|
style="width: 160px"
|
||||||
|
/>
|
||||||
|
<div style="width: 1px; height: 25px; background: #e5e5e5; margin: 0 16px"></div>
|
||||||
|
<el-button @click="createTask" :icon="'CirclePlus'" style="color: #536387"
|
||||||
|
>新建任务</el-button
|
||||||
|
>
|
||||||
|
<el-button @click="editMap" :icon="'EditPen'" style="color: #536387">地图编辑</el-button>
|
||||||
|
<el-button type="danger" @click="emergencyStop" :icon="'Remove'">一键急停</el-button>
|
||||||
|
</div>
|
||||||
</ContentWrap>
|
</ContentWrap>
|
||||||
|
|
||||||
<div class="main-content">
|
<div class="main-content">
|
||||||
<!-- <div @click="downAgv">导出zip</div> -->
|
<!-- <div @click="downAgv">导出zip</div> -->
|
||||||
<!-- 首页 -->
|
<!-- 首页 -->
|
||||||
<indexPage ref="indexPageRef" @transmitMapInfo="transmitMapInfo" />
|
<indexPage ref="indexPageRef" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 新建任务的弹窗 -->
|
<!-- 新建任务的弹窗 -->
|
||||||
@ -22,16 +33,102 @@ import { ref, defineComponent, reactive, nextTick, onMounted } from 'vue'
|
|||||||
import * as MapApi from '@/api/map/map'
|
import * as MapApi from '@/api/map/map'
|
||||||
import download from '@/utils/download'
|
import download from '@/utils/download'
|
||||||
|
|
||||||
|
|
||||||
defineOptions({ name: 'MapPageRealTimeMap' })
|
defineOptions({ name: 'MapPageRealTimeMap' })
|
||||||
|
const mapValue = ref([])
|
||||||
|
const list = ref([])
|
||||||
const indexPageRef = ref(null)
|
const indexPageRef = ref(null)
|
||||||
|
|
||||||
const downAgv = async () => {
|
const downAgv = async () => {
|
||||||
const data = await MapApi.agvDownload()
|
const data = await MapApi.agvDownload()
|
||||||
download.zip(data, `agv-${new Date().getTime()}.zip`)
|
download.zip(data, `agv-${new Date().getTime()}.zip`)
|
||||||
}
|
}
|
||||||
|
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 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)
|
||||||
|
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 createTaskDialogRef = ref()
|
const createTaskDialogRef = ref()
|
||||||
const createTask = () => {
|
const createTask = () => {
|
||||||
@ -60,9 +157,13 @@ const mapInfo = ref({
|
|||||||
floor: '',
|
floor: '',
|
||||||
area: ''
|
area: ''
|
||||||
})
|
})
|
||||||
const transmitMapInfo = (map) => {
|
// const transmitMapInfo = (map) => {
|
||||||
mapInfo.value = map
|
// mapInfo.value = map
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getList()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -17,29 +17,29 @@
|
|||||||
<div class="">
|
<div class="">
|
||||||
<el-row :gutter="16">
|
<el-row :gutter="16">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-card style="width: 100%;">
|
<el-card style="width: 100%">
|
||||||
<div class="charts-title">
|
<div class="charts-title"> 任务总览 </div>
|
||||||
任务总览
|
<div ref="chartDom" style="width: 100%; height: 400px"></div>
|
||||||
</div>
|
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-card style="width: 100%">
|
<el-card style="width: 100%">
|
||||||
<div class="charts-title">
|
<div class="charts-title"> 任务完成率 </div>
|
||||||
任务总览
|
<div ref="chartDomFinish" style="width: 100%; height: 400px"></div>
|
||||||
</div>
|
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row :gutter="16" style="margin-top: 12px">
|
<el-row :gutter="16" style="margin-top: 12px">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-card style="width: 100%;">
|
<el-card style="width: 100%">
|
||||||
111
|
<div class="charts-title"> AGV工作利用率统计 </div>
|
||||||
|
<div ref="chartDomAgv" style="width: 100%; height: 400px"></div>
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-card style="width: 100%;">
|
<el-card style="width: 100%">
|
||||||
111
|
<div class="charts-title"> 任务异常数 </div>
|
||||||
|
<div ref="chartDomError" style="width: 100%; height: 400px"></div>
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@ -47,7 +47,389 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, onMounted, onBeforeUnmount } from 'vue'
|
import { ref, onMounted, onUnmounted, nextTick, reactive } from 'vue'
|
||||||
|
import * as echarts from 'echarts'
|
||||||
|
import { lte } from 'lodash-es'
|
||||||
|
|
||||||
|
// 创建一个响应式引用来保存DOM元素
|
||||||
|
const chartDom = ref(null)
|
||||||
|
const chartDomFinish = ref(null)
|
||||||
|
const chartDomError = ref(null)
|
||||||
|
const chartDomAgv = ref(null)
|
||||||
|
|
||||||
|
// 初始化ECharts实例并设置配置项(这里以折线图为例,但可灵活替换)
|
||||||
|
onMounted(async () => {
|
||||||
|
await nextTick() // 确保DOM已经渲染完成
|
||||||
|
initEcharts()
|
||||||
|
})
|
||||||
|
|
||||||
|
const initEcharts = () => {
|
||||||
|
initOne()
|
||||||
|
initTwo()
|
||||||
|
initFour()
|
||||||
|
}
|
||||||
|
|
||||||
|
const chartInstance = ref(null)
|
||||||
|
const initOne = () => {
|
||||||
|
chartInstance.value = echarts.init(chartDom.value)
|
||||||
|
let ydata = [
|
||||||
|
{
|
||||||
|
name: '执行中',
|
||||||
|
value: 18
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '已完成',
|
||||||
|
value: 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '已取消',
|
||||||
|
value: 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '未开始',
|
||||||
|
value: 14
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '异常',
|
||||||
|
value: 10
|
||||||
|
}
|
||||||
|
]
|
||||||
|
let color = ['#0147EB', '#01BCEB', '#C800FF', '#F1CD0B', '#EB0000']
|
||||||
|
let xdata = ['执行中', '已完成', '已取消', '未开始', '异常']
|
||||||
|
const option = {
|
||||||
|
backgroundColor: 'rgba(255,255,255,1)',
|
||||||
|
color: color,
|
||||||
|
// tooltip: {
|
||||||
|
// trigger: 'item',
|
||||||
|
// // formatter: '{a} <br/>{b} : {c} ({d}%)'
|
||||||
|
// },
|
||||||
|
legend: {
|
||||||
|
orient: 'vartical',
|
||||||
|
x: 'left',
|
||||||
|
top: 'center',
|
||||||
|
left: '60%',
|
||||||
|
bottom: '0%',
|
||||||
|
data: xdata,
|
||||||
|
itemWidth: 10,
|
||||||
|
itemHeight: 10,
|
||||||
|
itemGap: 16,
|
||||||
|
formatter: function (name) {
|
||||||
|
let str = ''
|
||||||
|
ydata.forEach((item) => {
|
||||||
|
if (item.name == name) {
|
||||||
|
str = `{c|${item.name}} {a|${item.value}}`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return str
|
||||||
|
},
|
||||||
|
textStyle: {
|
||||||
|
rich: {
|
||||||
|
a: {
|
||||||
|
color: '#0D162A',
|
||||||
|
fontSize: 18
|
||||||
|
},
|
||||||
|
c: {
|
||||||
|
color: '#536387',
|
||||||
|
fontSize: 12
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
type: 'pie',
|
||||||
|
clockwise: false, //饼图的扇区是否是顺时针排布
|
||||||
|
minAngle: 2, //最小的扇区角度(0 ~ 360)
|
||||||
|
radius: ['50%', '65%'],
|
||||||
|
center: ['30%', '50%'],
|
||||||
|
avoidLabelOverlap: false,
|
||||||
|
itemStyle: {
|
||||||
|
//图形样式
|
||||||
|
normal: {
|
||||||
|
borderColor: '#ffffff',
|
||||||
|
borderWidth: 6
|
||||||
|
}
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
// '{text|{b}}\n{c} ({d}%)'
|
||||||
|
normal: {
|
||||||
|
show: true,
|
||||||
|
position: 'center',
|
||||||
|
formatter: '{c|234,12} \n {a|任务总数}',
|
||||||
|
rich: {
|
||||||
|
c: {
|
||||||
|
color: '#0D162A',
|
||||||
|
fontSize: 15,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
height: 30
|
||||||
|
},
|
||||||
|
|
||||||
|
a: {
|
||||||
|
align: 'center',
|
||||||
|
color: '#727272',
|
||||||
|
fontSize: 12
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
labelLine: {
|
||||||
|
length: 15,
|
||||||
|
length2: 0,
|
||||||
|
maxSurfaceAngle: 80
|
||||||
|
},
|
||||||
|
data: ydata
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
chartInstance.value.setOption(option)
|
||||||
|
}
|
||||||
|
|
||||||
|
const chartInstanceTwo = ref(null)
|
||||||
|
const initTwo = () => {
|
||||||
|
chartInstanceTwo.value = echarts.init(chartDomFinish.value)
|
||||||
|
let option = {
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
grid: {
|
||||||
|
top: '9%',
|
||||||
|
bottom: '19%',
|
||||||
|
left: '6%',
|
||||||
|
right: '4%'
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
label: {
|
||||||
|
show: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
boundaryGap: true, //默认,坐标轴留白策略
|
||||||
|
axisLine: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: false,
|
||||||
|
alignWithLabel: true
|
||||||
|
},
|
||||||
|
data: [
|
||||||
|
'武汉',
|
||||||
|
'襄阳',
|
||||||
|
'黄冈',
|
||||||
|
'荆门',
|
||||||
|
'十堰',
|
||||||
|
'随州',
|
||||||
|
'鄂州',
|
||||||
|
'恩施',
|
||||||
|
'宜昌',
|
||||||
|
'孝感',
|
||||||
|
'咸宁',
|
||||||
|
'仙桃',
|
||||||
|
'潜江',
|
||||||
|
'天门',
|
||||||
|
'黄石',
|
||||||
|
'荆州',
|
||||||
|
'神农架'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
axisLine: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: {
|
||||||
|
type: 'solid',
|
||||||
|
color: '#E2E7F5'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
splitArea: {
|
||||||
|
show: true,
|
||||||
|
areaStyle: {
|
||||||
|
color: 'rgb(245,250,254)'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
type: 'line',
|
||||||
|
symbol: 'circle',
|
||||||
|
symbolSize: 1,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#0147EB'
|
||||||
|
},
|
||||||
|
|
||||||
|
label: {
|
||||||
|
show: false,
|
||||||
|
distance: 1,
|
||||||
|
emphasis: {
|
||||||
|
show: true,
|
||||||
|
offset: [25, -2],
|
||||||
|
backgroundColor: 'rgba(0,0,0,0.7)',
|
||||||
|
color: '#FFF',
|
||||||
|
padding: [8, 20, 8, 6],
|
||||||
|
//width:60,
|
||||||
|
height: 36,
|
||||||
|
formatter: function (params) {
|
||||||
|
var name = params.name
|
||||||
|
var value = params.data
|
||||||
|
var str = name + '\n数据量:' + value
|
||||||
|
return str
|
||||||
|
},
|
||||||
|
rich: {
|
||||||
|
bg: {
|
||||||
|
width: 78,
|
||||||
|
//height:42,
|
||||||
|
color: '#FFF',
|
||||||
|
padding: [20, 0, 20, 10]
|
||||||
|
},
|
||||||
|
br: {
|
||||||
|
width: '100%',
|
||||||
|
height: '100%'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: [
|
||||||
|
2000, 1800, 2800, 900, 1600, 2000, 3000, 2030, 1356, 1900, 4000, 3000, 2000, 3000, 4200,
|
||||||
|
3200, 3800
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
chartInstanceTwo.value.setOption(option)
|
||||||
|
}
|
||||||
|
|
||||||
|
const chartInstanceFour = ref(null)
|
||||||
|
const initFour = () => {
|
||||||
|
chartInstanceFour.value = echarts.init(chartDomError.value)
|
||||||
|
let option = {
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
grid: {
|
||||||
|
top: '9%',
|
||||||
|
bottom: '19%',
|
||||||
|
left: '6%',
|
||||||
|
right: '4%'
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
label: {
|
||||||
|
show: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
boundaryGap: true, //默认,坐标轴留白策略
|
||||||
|
axisLine: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: false,
|
||||||
|
alignWithLabel: true
|
||||||
|
},
|
||||||
|
data: [
|
||||||
|
'武汉',
|
||||||
|
'襄阳',
|
||||||
|
'黄冈',
|
||||||
|
'荆门',
|
||||||
|
'十堰',
|
||||||
|
'随州',
|
||||||
|
'鄂州',
|
||||||
|
'恩施',
|
||||||
|
'宜昌',
|
||||||
|
'孝感',
|
||||||
|
'咸宁',
|
||||||
|
'仙桃',
|
||||||
|
'潜江',
|
||||||
|
'天门',
|
||||||
|
'黄石',
|
||||||
|
'荆州',
|
||||||
|
'神农架'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
axisLine: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: {
|
||||||
|
type: 'solid',
|
||||||
|
color: '#E2E7F5'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
splitArea: {
|
||||||
|
show: true,
|
||||||
|
areaStyle: {
|
||||||
|
color: 'rgb(245,250,254)'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
type: 'line',
|
||||||
|
symbol: 'circle',
|
||||||
|
symbolSize: 1,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#0147EB'
|
||||||
|
},
|
||||||
|
|
||||||
|
label: {
|
||||||
|
show: false,
|
||||||
|
distance: 1,
|
||||||
|
emphasis: {
|
||||||
|
show: true,
|
||||||
|
offset: [25, -2],
|
||||||
|
backgroundColor: 'rgba(0,0,0,0.7)',
|
||||||
|
color: '#FFF',
|
||||||
|
padding: [8, 20, 8, 6],
|
||||||
|
//width:60,
|
||||||
|
height: 36,
|
||||||
|
formatter: function (params) {
|
||||||
|
var name = params.name
|
||||||
|
var value = params.data
|
||||||
|
var str = name + '\n数据量:' + value
|
||||||
|
return str
|
||||||
|
},
|
||||||
|
rich: {
|
||||||
|
bg: {
|
||||||
|
width: 78,
|
||||||
|
//height:42,
|
||||||
|
color: '#FFF',
|
||||||
|
padding: [20, 0, 20, 10]
|
||||||
|
},
|
||||||
|
br: {
|
||||||
|
width: '100%',
|
||||||
|
height: '100%'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: [
|
||||||
|
2000, 1800, 2800, 900, 1600, 2000, 3000, 2030, 1356, 1900, 4000, 3000, 2000, 3000, 4200,
|
||||||
|
3200, 3800
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
chartInstanceFour.value.setOption(option)
|
||||||
|
}
|
||||||
|
// 销毁ECharts实例
|
||||||
|
onUnmounted(() => {
|
||||||
|
if (chartInstance.value != null && chartInstance.value.dispose) {
|
||||||
|
chartInstance.value.dispose()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const type = ref(1)
|
const type = ref(1)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|