设备
This commit is contained in:
parent
66150c708d
commit
1b188bdf26
@ -4,7 +4,7 @@ NODE_ENV=development
|
||||
VITE_DEV=true
|
||||
|
||||
# 请求路径
|
||||
VITE_BASE_URL='http://192.168.0.66:48080'
|
||||
VITE_BASE_URL='http://192.168.0.74:48080'
|
||||
# VITE_BASE_URL='http://192.168.0.189:48080'
|
||||
|
||||
# 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持 S3 服务
|
||||
|
@ -1,27 +1,6 @@
|
||||
import request from '@/config/axios'
|
||||
|
||||
//agv 下载
|
||||
export const agvDownload = async (params) => {
|
||||
return await request.download({ url: `/system/position-map/agvDownload`, params })
|
||||
}
|
||||
//点位地图列表
|
||||
export const getPositionMapList = async (params) => {
|
||||
return await request.get({ url: `/system/position-map/list`, params })
|
||||
}
|
||||
|
||||
//删除车辆信息
|
||||
export const deleteRobotInformation = async (id: number) => {
|
||||
return await request.delete({ url: `/system/robot/information/delete?id=` + id })
|
||||
}
|
||||
|
||||
//查询所有车辆
|
||||
export const getAllRobot = async (data) => {
|
||||
return await request.post({ url: `/system/robot/information/getAllRobot`, data })
|
||||
}
|
||||
//获得车辆信息 详情
|
||||
export const getRobotInformation = async (params) => {
|
||||
return await request.get({ url: `/system/robot/information/get`, params })
|
||||
}
|
||||
|
||||
//分页查询设备列表 看板信息设备目前用的是这个
|
||||
export const deviceInformationPage = async (params) => {
|
||||
@ -32,25 +11,24 @@ export const robotInformationStatistics = async (data) => {
|
||||
return await request.post({ url: `/system/robot/information/statistics`, data })
|
||||
}
|
||||
|
||||
// 创建车辆信息
|
||||
export const robotInformationCreate = async (data) => {
|
||||
return await request.post({ url: `/system/robot/information/create`, data })
|
||||
// 创建设备信息
|
||||
export const deviceInformationCreate = async (data) => {
|
||||
return await request.post({ url: `/system/device/information/create`, data })
|
||||
}
|
||||
// 编辑车辆信息
|
||||
export const robotInformationUpdate = async (data) => {
|
||||
return await request.put({ url: `/system/robot/information/update`, data })
|
||||
// 编辑设备信息
|
||||
export const deviceInformationUpdate = async (data) => {
|
||||
return await request.put({ url: `/system/device/information/update`, data })
|
||||
}
|
||||
//分页查询车辆列表 看板信息车辆目前用的是这个
|
||||
export const robotGetAllModel = async (params) => {
|
||||
return await request.get({ url: `/system/robot/model/getAllModel`, params })
|
||||
}
|
||||
// 范围选择
|
||||
export const robotPositionGetMap = async (params) => {
|
||||
return await request.get({ url: `/system/position-map/getMap`, params })
|
||||
}
|
||||
// 完整范围选择
|
||||
export const robotPositionGetMapAll = async (params) => {
|
||||
return await request.get({ url: `/system/position-map/getAllMap`, params })
|
||||
// 地图绑定设备
|
||||
export const deviceInformationGet = async (params) => {
|
||||
return await request.get({ url: `/system/device/information/get`, params })
|
||||
}
|
||||
|
||||
|
||||
//删除设备信息
|
||||
export const deleteDeviceInformation = async (id: number) => {
|
||||
return await request.delete({ url: `/system/device/information/delete?id=` + id })
|
||||
}
|
||||
// 获取设备列表
|
||||
export const deviceNumber = async (params) => {
|
||||
return await request.get({ url: `/system/device/information/deviceNumber`, params })
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import UploadImg from './src/UploadImg.vue'
|
||||
import UploadImgs from './src/UploadImgs.vue'
|
||||
import UploadFile from './src/UploadFile.vue'
|
||||
import UploadFileNew from './src/UploadFileNew.vue'
|
||||
|
||||
export { UploadImg, UploadImgs, UploadFile }
|
||||
export { UploadImg, UploadImgs, UploadFile ,UploadFileNew}
|
||||
|
271
src/components/UploadFile/src/UploadFileNew.vue
Normal file
271
src/components/UploadFile/src/UploadFileNew.vue
Normal file
@ -0,0 +1,271 @@
|
||||
<template>
|
||||
<div class="upload-box">
|
||||
<el-upload
|
||||
:id="uuid"
|
||||
:accept="fileType.join(',')"
|
||||
:action="uploadUrl"
|
||||
:before-upload="beforeUpload"
|
||||
:class="['upload', drag ? 'no-border' : '']"
|
||||
:disabled="disabled"
|
||||
:drag="drag"
|
||||
:http-request="httpRequest"
|
||||
:multiple="false"
|
||||
:on-error="uploadError"
|
||||
:on-success="uploadSuccess"
|
||||
:show-file-list="false"
|
||||
>
|
||||
<template v-if="modelValue">
|
||||
<img :src="modelValue" class="upload-image" />
|
||||
<div class="upload-handle" @click.stop>
|
||||
<div v-if="!disabled" class="handle-icon" @click="editImg">
|
||||
<Icon icon="ep:edit" />
|
||||
<span v-if="showBtnText">{{ t('action.edit') }}</span>
|
||||
</div>
|
||||
<div class="handle-icon" @click="imagePreview(modelValue)">
|
||||
<Icon icon="ep:zoom-in" />
|
||||
<span v-if="showBtnText">{{ t('action.detail') }}</span>
|
||||
</div>
|
||||
<div v-if="showDelete && !disabled" class="handle-icon" @click="deleteImg">
|
||||
<Icon icon="ep:delete" />
|
||||
<span v-if="showBtnText">{{ t('action.del') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="upload-empty">
|
||||
<slot name="empty">
|
||||
<Icon icon="ep:plus" />
|
||||
<!-- <span>请上传图片</span> -->
|
||||
</slot>
|
||||
</div>
|
||||
</template>
|
||||
</el-upload>
|
||||
<div class="el-upload__tip">
|
||||
<slot name="tip"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { UploadProps } from 'element-plus'
|
||||
|
||||
import { generateUUID } from '@/utils'
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
import { createImageViewer } from '@/components/ImageViewer'
|
||||
import { useUpload } from '@/components/UploadFile/src/useUpload'
|
||||
|
||||
defineOptions({ name: 'UploadImg' })
|
||||
|
||||
type FileTypes =
|
||||
| 'image/apng'
|
||||
| 'image/bmp'
|
||||
| 'image/gif'
|
||||
| 'image/jpeg'
|
||||
| 'image/pjpeg'
|
||||
| 'image/png'
|
||||
| 'image/svg+xml'
|
||||
| 'image/tiff'
|
||||
| 'image/webp'
|
||||
| 'image/x-icon'
|
||||
|
||||
// 接受父组件参数
|
||||
const props = defineProps({
|
||||
modelValue: propTypes.string.def(''),
|
||||
drag: propTypes.bool.def(true), // 是否支持拖拽上传 ==> 非必传(默认为 true)
|
||||
disabled: propTypes.bool.def(false), // 是否禁用上传组件 ==> 非必传(默认为 false)
|
||||
fileSize: propTypes.number.def(5), // 图片大小限制 ==> 非必传(默认为 5M)
|
||||
fileType: propTypes.array.def(['image/jpeg', 'image/png', 'image/gif']), // 图片类型限制 ==> 非必传(默认为 ["image/jpeg", "image/png", "image/gif"])
|
||||
height: propTypes.string.def('150px'), // 组件高度 ==> 非必传(默认为 150px)
|
||||
width: propTypes.string.def('150px'), // 组件宽度 ==> 非必传(默认为 150px)
|
||||
borderradius: propTypes.string.def('8px'), // 组件边框圆角 ==> 非必传(默认为 8px)
|
||||
showDelete: propTypes.bool.def(true), // 是否显示删除按钮
|
||||
showBtnText: propTypes.bool.def(true) // 是否显示按钮文字
|
||||
})
|
||||
const { t } = useI18n() // 国际化
|
||||
const message = useMessage() // 消息弹窗
|
||||
// 生成组件唯一id
|
||||
const uuid = ref('id-' + generateUUID())
|
||||
// 查看图片
|
||||
const imagePreview = (imgUrl: string) => {
|
||||
createImageViewer({
|
||||
zIndex: 9999999,
|
||||
urlList: [imgUrl]
|
||||
})
|
||||
}
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
const deleteImg = () => {
|
||||
emit('update:modelValue', '')
|
||||
}
|
||||
|
||||
const { uploadUrl, httpRequest } = useUpload()
|
||||
|
||||
const editImg = () => {
|
||||
const dom = document.querySelector(`#${uuid.value} .el-upload__input`)
|
||||
dom && dom.dispatchEvent(new MouseEvent('click'))
|
||||
}
|
||||
|
||||
const beforeUpload: UploadProps['beforeUpload'] = (rawFile) => {
|
||||
const imgSize = rawFile.size / 1024 / 1024 < props.fileSize
|
||||
const imgType = props.fileType
|
||||
if (!imgType.includes(rawFile.type as FileTypes))
|
||||
message.notifyWarning('上传图片不符合所需的格式!')
|
||||
if (!imgSize) message.notifyWarning(`上传图片大小不能超过 ${props.fileSize}M!`)
|
||||
return imgType.includes(rawFile.type as FileTypes) && imgSize
|
||||
}
|
||||
|
||||
// 图片上传成功提示
|
||||
const uploadSuccess: UploadProps['onSuccess'] = (res: any): void => {
|
||||
message.success('上传成功')
|
||||
emit('update:modelValue', res.data)
|
||||
}
|
||||
|
||||
// 图片上传错误提示
|
||||
const uploadError = () => {
|
||||
message.notifyError('图片上传失败,请您重新上传!')
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.is-error {
|
||||
.upload {
|
||||
:deep(.el-upload),
|
||||
:deep(.el-upload-dragger) {
|
||||
border: 1px dashed var(--el-color-danger) !important;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--el-color-primary) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.disabled) {
|
||||
.el-upload,
|
||||
.el-upload-dragger {
|
||||
cursor: not-allowed !important;
|
||||
background: var(--el-disabled-bg-color);
|
||||
border: 1px dashed var(--el-border-color-darker) !important;
|
||||
|
||||
&:hover {
|
||||
border: 1px dashed var(--el-border-color-darker) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.upload-box {
|
||||
.no-border {
|
||||
:deep(.el-upload) {
|
||||
border: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.upload) {
|
||||
.el-upload {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: v-bind(width);
|
||||
height: v-bind(height);
|
||||
overflow: hidden;
|
||||
border: 1px dashed var(--el-border-color-darker);
|
||||
border-radius: v-bind(borderradius);
|
||||
transition: var(--el-transition-duration-fast);
|
||||
|
||||
&:hover {
|
||||
border-color: var(--el-color-primary);
|
||||
|
||||
.upload-handle {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.el-upload-dragger {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
background-color: transparent;
|
||||
border: 1px dashed var(--el-border-color-darker);
|
||||
border-radius: v-bind(borderradius);
|
||||
|
||||
&:hover {
|
||||
border: 1px dashed var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.el-upload-dragger.is-dragover {
|
||||
background-color: var(--el-color-primary-light-9);
|
||||
border: 2px dashed var(--el-color-primary) !important;
|
||||
}
|
||||
|
||||
.upload-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.upload-empty {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 12px;
|
||||
line-height: 30px;
|
||||
color: var(--el-color-info);
|
||||
|
||||
.el-icon {
|
||||
font-size: 28px;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
}
|
||||
|
||||
.upload-handle {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
background: rgb(0 0 0 / 60%);
|
||||
opacity: 0;
|
||||
box-sizing: border-box;
|
||||
transition: var(--el-transition-duration-fast);
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.handle-icon {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 6%;
|
||||
color: aliceblue;
|
||||
|
||||
.el-icon {
|
||||
margin-bottom: 40%;
|
||||
font-size: 130%;
|
||||
line-height: 130%;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 85%;
|
||||
line-height: 85%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-upload__tip {
|
||||
line-height: 18px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -12,28 +12,33 @@
|
||||
<div class="new-top-box-left-item" style="color: #00329f">
|
||||
<div class="new-top-box-left-item-name">工作</div>
|
||||
<div class="new-top-box-left-item-value">{{ carStatistics.inTask || 0 }}</div>
|
||||
<div class="grey-line" style="margin-left: 8px"> </div>
|
||||
|
||||
</div>
|
||||
<div class="new-top-box-left-item" style="color: #e07300">
|
||||
<div class="grey-line"> </div>
|
||||
<div class="new-top-box-left-item" style="color: #e07300;background: #EBF1FF;">
|
||||
<div class="new-top-box-left-item-name">充电</div>
|
||||
<div class="new-top-box-left-item-value">{{ carStatistics.charge || 0 }}</div>
|
||||
<div class="grey-line" style="margin-left: 8px"> </div>
|
||||
|
||||
</div>
|
||||
<div class="grey-line" > </div>
|
||||
<div class="new-top-box-left-item" style="color: #c60606">
|
||||
<div class="new-top-box-left-item-name">异常</div>
|
||||
<div class="new-top-box-left-item-value">{{ carStatistics.fault || 0 }}</div>
|
||||
<div class="grey-line" style="margin-left: 8px"> </div>
|
||||
|
||||
</div>
|
||||
<div class="grey-line" > </div>
|
||||
<div class="new-top-box-left-item" style="color: #f1cd0b">
|
||||
<div class="new-top-box-left-item-name">锁定</div>
|
||||
<div class="new-top-box-left-item-value">{{ carStatistics.doLock || 0 }}</div>
|
||||
<div class="grey-line" style="margin-left: 8px"> </div>
|
||||
|
||||
</div>
|
||||
<div class="grey-line" > </div>
|
||||
<div class="new-top-box-left-item" style="color: #4dc606">
|
||||
<div class="new-top-box-left-item-name">待命</div>
|
||||
<div class="new-top-box-left-item-value">{{ carStatistics.standby || 0 }}</div>
|
||||
<div class="grey-line" style="margin-left: 8px"> </div>
|
||||
|
||||
</div>
|
||||
<div class="grey-line"> </div>
|
||||
<div class="new-top-box-left-item" style="color: #7a7a7a">
|
||||
<div class="new-top-box-left-item-name">离线</div>
|
||||
<div class="new-top-box-left-item-value">{{ carStatistics.offline || 0 }}</div>
|
||||
@ -106,7 +111,7 @@
|
||||
<div class="item-inner-left">
|
||||
|
||||
<div class="item-inner-left-img-box">
|
||||
<el-image style="width: 100%; height: 100%" :src="url" :fit="'fill'" />
|
||||
<el-image style="width: 100%; height: 100%" :src="item.url" :fit="'fill'" />
|
||||
</div>
|
||||
<div class="item-inner-left-bottom">
|
||||
<div class="item-inner-left-bottom-btn" @click="goMap(item)"> 地图定位 </div>
|
||||
@ -478,8 +483,9 @@ onBeforeRouteLeave((to, from, next) => {
|
||||
PingFang SC;
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
margin-left: 10px;
|
||||
padding: 5px 0;
|
||||
|
||||
padding: 5px 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.new-top-box-left-item-name {
|
||||
flex-shrink: 0;
|
||||
|
@ -1,49 +1,35 @@
|
||||
<template>
|
||||
<Dialog v-model="dialogVisible" :title="title" width="800" class="task-dialog">
|
||||
<Dialog v-model="dialogVisible" :title="title" width="545" class="task-dialog">
|
||||
<el-form :model="formData" label-width="auto" ref="formRef" :rules="formRules">
|
||||
<el-form-item label="车辆类型" prop="robotModelId" required>
|
||||
<el-select v-model="formData.robotModelId" placeholder="请选择车辆类型" required>
|
||||
<el-form-item label="设备类型" prop="robotModelId" >
|
||||
<el-select v-model="formData.deviceType" clearable placeholder="请选择设备类型">
|
||||
<el-option
|
||||
:label="item.robotModelNumber"
|
||||
:value="item.id"
|
||||
v-for="item in carModelList"
|
||||
:key="item.id"
|
||||
v-for="dict in getDictOptions(DICT_TYPE.DEVICE_TYPE)"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="Number(dict.value)"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item required label="车辆编号" prop="robotNo">
|
||||
<el-input v-model="formData.robotNo" :disabled="false" placeholder="请输入车辆编号"/>
|
||||
<el-form-item label="设备编号" prop="robotNo">
|
||||
<el-input v-model="formData.deviceNo" :disabled="false" placeholder="请输入设备编号" />
|
||||
</el-form-item>
|
||||
<el-form-item required label="任务模式" v-if="formData.id">
|
||||
<el-select v-model="formData.robotTaskModel" placeholder="请选择车辆类型" required>
|
||||
<el-option
|
||||
:label="'拒收任务'"
|
||||
:value="0"
|
||||
/>
|
||||
<el-option
|
||||
:label="'正常'"
|
||||
:value="1"
|
||||
/>
|
||||
</el-select>
|
||||
|
||||
<el-form-item label="Mac地址" prop="macAddress">
|
||||
<el-input v-model="formData.macAddress" :disabled="false" placeholder="请输入Mac地址" />
|
||||
</el-form-item>
|
||||
<el-form-item required label="自动充电电量" prop="autoCharge">
|
||||
<el-input-number v-model="formData.autoCharge" :disabled="false" :controls="false" :precision="0" :step="1" type="number" :min="0" :max="99" placeholder="请输入自动充电电量">
|
||||
<template #append>%</template>
|
||||
</el-input-number>
|
||||
<span style="margin-left: 20px;">%</span>
|
||||
<el-form-item label="设备图标" prop="macAddress">
|
||||
<UploadImg v-model="formData.mapImageUrl" :limit="1" />
|
||||
</el-form-item>
|
||||
<el-form-item required label="Mac地址" prop="macAddress">
|
||||
<el-input v-model="formData.macAddress" :disabled="false" placeholder="请输入Mac地址"/>
|
||||
<el-form-item label="设备图配置" prop="pictureConfig">
|
||||
<el-radio-group v-model="formData.pictureConfig">
|
||||
<el-radio :label="1">默认图片</el-radio>
|
||||
<el-radio :label="2">上传图片</el-radio>
|
||||
<el-radio :label="3">不显示图片</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item required label="选择范围" placeholder="请选择范围">
|
||||
<el-cascader
|
||||
:options="floorAreaList"
|
||||
:props="props"
|
||||
clearable
|
||||
:collapse-tags="false"
|
||||
v-model="floorAreaJsonData"
|
||||
@change="floorAreaChange"
|
||||
/>
|
||||
<el-form-item label="设备图片" prop="mapImageUrl" v-if="formData.pictureConfig === 2">
|
||||
<UploadImg v-model="formData.url" :limit="1" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
@ -57,77 +43,42 @@
|
||||
const { t } = useI18n() // 国际化
|
||||
const message = useMessage() // 消息弹窗
|
||||
import * as MapTaskAPi from '@/api/map/mapTask'
|
||||
import * as CarApi from '@/api/car/index'
|
||||
import * as DeviceApi from '@/api/device/index'
|
||||
import { DICT_TYPE, getDictOptions } from '@/utils/dict'
|
||||
const dialogVisible = ref(false) // 弹窗的是否展示
|
||||
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
|
||||
const title = ref('新建') // form表单
|
||||
const formData = ref({
|
||||
robotModelId: undefined, //车辆类型id
|
||||
robotNo: undefined, //AGV编号
|
||||
deviceType: undefined, //车辆类型id
|
||||
deviceNo: undefined, //AGV编号
|
||||
macAddress: undefined, //mac地址
|
||||
floorAreaJson: [],
|
||||
autoCharge: undefined
|
||||
mapImageUrl: undefined, //设备在地图上图标
|
||||
pictureConfig: undefined, // 图片设置(1:默认图片、2:上传图片、 3:不显示图片)
|
||||
url: undefined //上传图片附件
|
||||
})
|
||||
const carModelList = ref([])
|
||||
const floorAreaList = ref([])
|
||||
const props = { multiple: true }
|
||||
const floorAreaJsonData = ref([])
|
||||
|
||||
const getCarModelList = async () => {
|
||||
const res = await CarApi.robotGetAllModel()
|
||||
carModelList.value = res
|
||||
}
|
||||
|
||||
const getFloorArea = async () => {
|
||||
const res = await CarApi.robotPositionGetMapAll()
|
||||
let data = []
|
||||
let floor = []
|
||||
data = res
|
||||
for(let key in res){
|
||||
let obj = {
|
||||
value: key,
|
||||
label: key + '层',
|
||||
children: res[key].map(item => {return {label: item.area, value: item.id,...item,children: []}})
|
||||
}
|
||||
floor.push(obj)
|
||||
}
|
||||
console.log(floor)
|
||||
floorAreaList.value = floor
|
||||
}
|
||||
|
||||
const floorAreaChange = (value) => {
|
||||
console.log(value)
|
||||
formData.value.floorAreaJson = []
|
||||
value.forEach(item => {
|
||||
formData.value.floorAreaJson.push(item[1])
|
||||
})
|
||||
console.log(formData.value.floorAreaJson)
|
||||
}
|
||||
|
||||
const formRules = reactive({
|
||||
robotModelId: [{ required: true, message: '车辆类型不能为空', trigger: 'change' }],
|
||||
robotNo: [{ required: true, message: 'AGV编号不能为空', trigger: 'change' }],
|
||||
macAddress: [{ required: true, message: 'Mac地址不能为空', trigger: 'change' }],
|
||||
autoCharge: [{ required: true, message: '自动充电电量不能为空', trigger: 'change' }]
|
||||
deviceType: [{ required: true, message: '设备类型不能为空', trigger: 'blur' }],
|
||||
deviceNo: [{ required: true, message: '设备编号不能为空', trigger: 'blur' }],
|
||||
macAddress: [{ required: true, message: 'Mac地址不能为空', trigger: 'blur' }],
|
||||
mapImageUrl: [{ required: true, message: '设备图标不能为空', trigger: 'blur' }],
|
||||
pictureConfig: [{ required: true, message: '设备图配置不能为空', trigger: 'blur' }],
|
||||
url: [{ required: true, message: '设备图片不能为空', trigger: 'blur' }]
|
||||
})
|
||||
const formRef = ref() // 表单 Ref
|
||||
|
||||
/** 打开弹窗 */
|
||||
const open = async (type, id) => {
|
||||
floorAreaJsonData.value = []
|
||||
getCarModelList()
|
||||
getFloorArea()
|
||||
dialogVisible.value = true
|
||||
resetForm()
|
||||
if (id) {
|
||||
title.value = '编辑'
|
||||
const data = await CarApi.getRobotInformation({id})
|
||||
const data = await DeviceApi.deviceInformationGet({ id })
|
||||
formData.value = data
|
||||
if(data.positionMapList.length){
|
||||
data.positionMapList.forEach(item => {
|
||||
floorAreaJsonData.value.push([item.floor,item.id])
|
||||
})
|
||||
}
|
||||
|
||||
console.log(data)
|
||||
} else {
|
||||
title.value = '新建'
|
||||
@ -144,23 +95,20 @@ const submitForm = async () => {
|
||||
if (!formRef) return
|
||||
const valid = await formRef.value.validate()
|
||||
if (!valid) return
|
||||
if(!formData.value.floorAreaJson.length){
|
||||
message.warning('请选择范围')
|
||||
return
|
||||
}
|
||||
|
||||
// 提交请求
|
||||
formLoading.value = true
|
||||
try {
|
||||
if(formData.value.id){
|
||||
await CarApi.robotInformationUpdate(formData.value)
|
||||
if (formData.value.id) {
|
||||
await DeviceApi.deviceInformationUpdate(formData.value)
|
||||
message.success(t('common.updateSuccess'))
|
||||
dialogVisible.value = false
|
||||
emit('success')
|
||||
} else {
|
||||
await CarApi.robotInformationCreate(formData.value)
|
||||
await DeviceApi.deviceInformationCreate(formData.value)
|
||||
message.success(t('common.createSuccess'))
|
||||
dialogVisible.value = false
|
||||
emit('success')
|
||||
emit('success')
|
||||
}
|
||||
} finally {
|
||||
formLoading.value = false
|
||||
@ -214,13 +162,14 @@ const takeRemoteMethod = async (query, item) => {
|
||||
/** 重置表单 */
|
||||
const resetForm = () => {
|
||||
formData.value = {
|
||||
robotModelId: undefined, //车辆类型id
|
||||
robotNo: undefined, //AGV编号
|
||||
deviceType: undefined, //车辆类型id
|
||||
deviceNo: undefined, //AGV编号
|
||||
macAddress: undefined, //mac地址
|
||||
floorAreaJson: [],
|
||||
autoCharge: undefined
|
||||
mapImageUrl: undefined, //设备在地图上图标
|
||||
pictureConfig: undefined, // 图片设置(1:默认图片、2:上传图片、 3:不显示图片)
|
||||
url: undefined //上传图片附件
|
||||
}
|
||||
floorAreaJsonData.value = []
|
||||
|
||||
formRef.value?.resetFields()
|
||||
}
|
||||
</script>
|
||||
|
@ -6,117 +6,30 @@
|
||||
<div class="new-top-box-left-title"> 设备看板 </div>
|
||||
</el-col>
|
||||
<el-col :span="16">
|
||||
<el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
|
||||
<el-tab-pane :label="'总数' + carStatistics.total || 0" name="first1" />
|
||||
<el-tab-pane :label="'总数' + carStatistics.total || 0" name="first2" />
|
||||
<el-tab-pane :label="'总数' + carStatistics.total || 0" name="first3" />
|
||||
<el-tab-pane :label="'总数' + carStatistics.total || 0" name="first4" />
|
||||
<el-tab-pane :label="'总数' + carStatistics.total || 0" name="first5" />
|
||||
<el-tab-pane :label="'总数' + carStatistics.total || 0" name="first" />
|
||||
<el-tab-pane :label="'总数' + carStatistics.total || 0" name="first" />
|
||||
<el-tab-pane :label="'总数' + carStatistics.total || 0" name="first" />
|
||||
<el-tab-pane :label="'总数' + carStatistics.total || 0" name="first" />
|
||||
<el-tab-pane :label="'总数' + carStatistics.total || 0" name="first" />
|
||||
<el-tab-pane :label="'总数' + carStatistics.total || 0" name="first" />
|
||||
<el-tab-pane :label="'总数' + carStatistics.total || 0" name="first" />
|
||||
<el-tab-pane :label="'总数' + carStatistics.total || 0" name="first" />
|
||||
<el-tab-pane :label="'总数' + carStatistics.total || 0" name="first" />
|
||||
<el-tab-pane :label="'总数' + carStatistics.total || 0" name="first" />
|
||||
<el-tab-pane :label="'总数' + carStatistics.total || 0" name="first" />
|
||||
<el-tab-pane :label="'总数' + carStatistics.total || 0" name="first" />
|
||||
<el-tab-pane :label="'总数' + carStatistics.total || 0" name="first" />
|
||||
<el-tab-pane :label="'总数' + carStatistics.total || 0" name="first" />
|
||||
<el-tab-pane :label="'总数' + carStatistics.total || 0" name="first" />
|
||||
<el-tab-pane :label="'总数' + carStatistics.total || 0" name="first" />
|
||||
<el-tab-pane :label="'总数' + carStatistics.total || 0" name="first" />
|
||||
<el-tab-pane :label="'总数' + carStatistics.total || 0" name="first" />
|
||||
<el-tab-pane :label="'总数' + carStatistics.total || 0" name="first" />
|
||||
<el-tab-pane :label="'总数' + carStatistics.total || 0" name="first" />
|
||||
<el-tab-pane :label="'总数' + carStatistics.total || 0" name="first" />
|
||||
<div style="width: 100%;height: 100%;padding-top: 5px;">
|
||||
<el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
|
||||
<el-tab-pane :label="item.label + ' ' + (item.number?item.number: 0)" :name="item.value" v-for="(item, index) in typeList" :key="index"/>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<!-- <div class="new-top-box-right">
|
||||
<div class="new-top-box-right-input-box">
|
||||
<input
|
||||
type="text"
|
||||
v-model="queryParams.robotNo"
|
||||
placeholder="请输入关键字"
|
||||
class="new-top-box-right-input"
|
||||
placeholder-class="new-top-box-right-input-placeholder"
|
||||
/>
|
||||
<Icon
|
||||
icon="ep:search"
|
||||
size="20px"
|
||||
color="#A4AFCA"
|
||||
style="cursor: pointer"
|
||||
@click="getCarList"
|
||||
class="new-top-box-right-input-icon"
|
||||
/>
|
||||
</div>
|
||||
<el-button>Default</el-button>
|
||||
<div class="new-top-box-right-button" @click="openForm('create')"> 新增设备 </div>
|
||||
</div> -->
|
||||
<div style="display: flex">
|
||||
<el-input
|
||||
style="height: 40px"
|
||||
v-model="queryParams.robotNo"
|
||||
placeholder="Please Input"
|
||||
:suffix-icon="Search"
|
||||
/>
|
||||
|
||||
<el-button style="height: 40px">Default</el-button>
|
||||
style="height: 40px;margin-right: 16px;"
|
||||
v-model="queryParams.deviceNo"
|
||||
placeholder="请输入关键词"
|
||||
>
|
||||
<template #append>
|
||||
<el-button :icon="'search'" @click="getCarList"/>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-button style="height: 40px" @click="openForm('create')">新增设备</el-button>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
<!-- <div class="new-top-box-left-statistics-box">
|
||||
<div class="new-top-box-left-statistics-box-inner" v-if="carStatistics">
|
||||
<div class="new-top-box-left-statistics"> 总数 {{ carStatistics.total || 0 }} </div>
|
||||
<div class="grey-line"> </div>
|
||||
<div class="new-top-box-left-item">
|
||||
<div class="new-top-box-left-item-name">充电桩</div>
|
||||
<div class="new-top-box-left-item-value">{{ carStatistics.inTask || 0 }}</div>
|
||||
<div class="grey-line" style="margin-left: 8px"> </div>
|
||||
</div>
|
||||
<div class="new-top-box-left-item">
|
||||
<div class="new-top-box-left-item-name">输送线</div>
|
||||
<div class="new-top-box-left-item-value">{{ carStatistics.charge || 0 }}</div>
|
||||
<div class="grey-line" style="margin-left: 8px"> </div>
|
||||
</div>
|
||||
<div class="new-top-box-left-item">
|
||||
<div class="new-top-box-left-item-name">码垛机</div>
|
||||
<div class="new-top-box-left-item-value">{{ carStatistics.fault || 0 }}</div>
|
||||
<div class="grey-line" style="margin-left: 8px"> </div>
|
||||
</div>
|
||||
<div class="new-top-box-left-item">
|
||||
<div class="new-top-box-left-item-name">自动门</div>
|
||||
<div class="new-top-box-left-item-value">{{ carStatistics.fault || 0 }}</div>
|
||||
<div class="grey-line" style="margin-left: 8px"> </div>
|
||||
</div>
|
||||
<div class="new-top-box-left-item">
|
||||
<div class="new-top-box-left-item-name">提升机</div>
|
||||
<div class="new-top-box-left-item-value">{{ carStatistics.fault || 0 }}</div>
|
||||
<div class="grey-line" style="margin-left: 8px"> </div>
|
||||
</div>
|
||||
<div class="new-top-box-left-item">
|
||||
<div class="new-top-box-left-item-name">信号灯</div>
|
||||
<div class="new-top-box-left-item-value">{{ carStatistics.fault || 0 }}</div>
|
||||
<div class="grey-line" style="margin-left: 8px"> </div>
|
||||
</div>
|
||||
<div class="new-top-box-left-item">
|
||||
<div class="new-top-box-left-item-name">按钮盒</div>
|
||||
<div class="new-top-box-left-item-value">{{ carStatistics.fault || 0 }}</div>
|
||||
<div class="grey-line" style="margin-left: 8px"> </div>
|
||||
</div>
|
||||
<div class="new-top-box-left-item">
|
||||
<div class="new-top-box-left-item-name">拆垛机</div>
|
||||
<div class="new-top-box-left-item-value">{{ carStatistics.fault || 0 }}</div>
|
||||
<div class="grey-line" style="margin-left: 8px"> </div>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
</ContentWrap>
|
||||
<div class="new-list-box-all">
|
||||
<div class="new-list-box">
|
||||
@ -124,7 +37,7 @@
|
||||
<div class="item-top">
|
||||
<div class="item-inner-left-name">
|
||||
<div class="item-inner-left-name-inner">
|
||||
{{ formatterDeviceType(item.deviceType) }} {{ item.deviceNo }}
|
||||
{{ filterTypeFun(item.deviceType, typeList) }} {{ item.deviceNo }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-inner-right-top">
|
||||
@ -136,9 +49,6 @@
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="openForm('update', item.id)">编辑</el-dropdown-item>
|
||||
<el-dropdown-item @click="clockCar(item)">{{
|
||||
item.status == 0 ? '解锁' : '锁定'
|
||||
}}</el-dropdown-item>
|
||||
<el-dropdown-item @click="deleteCar(item.id)">删除</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
@ -149,7 +59,10 @@
|
||||
<div class="item-inner">
|
||||
<div class="item-inner-left">
|
||||
<div class="item-inner-left-img-box">
|
||||
<el-image style="width: 100%; height: 100%" :src="url" :fit="'fill'" />
|
||||
<el-image style="width: 100%; height: 100%" :src="item.url" :fit="'fill'" v-if="item.pictureConfig!=3"/>
|
||||
<div class="item-inner-left-img-box-no" v-else>
|
||||
<span >不显示图片</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-inner-left-bottom">
|
||||
<div class="item-inner-left-bottom-btn" @click="goMap(item)"> 地图定位 </div>
|
||||
@ -157,15 +70,15 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-inner-right-msg">
|
||||
<!-- <div class="item-inner-right-msg-item m-b-10">
|
||||
<div class="item-inner-right-msg-item-name">电量</div>
|
||||
<div class="item-inner-right-msg-item-value" :style="{color:item.electricity>20?'#4DC606':'#C60606'}" v-if="item.electricity">{{ item.electricity || '' }} %</div>
|
||||
</div> -->
|
||||
<div class="item-inner-right-msg-item m-b-10">
|
||||
<div class="item-inner-right-msg-item-name">编号</div>
|
||||
<div class="item-inner-right-msg-item-value">{{ item.deviceNo || ''}}</div>
|
||||
</div>
|
||||
<div class="item-inner-right-msg-item m-b-10">
|
||||
<div class="item-inner-right-msg-item-name">是否启用</div>
|
||||
<div class="item-inner-right-msg-item-value">
|
||||
<span v-if="item.robotStatus == 0" style="color: #c60606">禁用</span>
|
||||
<span v-if="item.robotStatus == 1" style="color: #4dc606">启用</span>
|
||||
<span v-if="item.deviceEnable == 0" style="color: #c60606">禁用</span>
|
||||
<span v-if="item.deviceEnable == 1" style="color: #4dc606">启用</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-inner-right-msg-item m-b-10">
|
||||
@ -206,19 +119,36 @@ import createEditDialog from './createEditDialog.vue'
|
||||
import 'swiper/css'
|
||||
|
||||
import { formatter } from 'element-plus'
|
||||
import { DICT_TYPE, getDictOptions } from '@/utils/dict'
|
||||
// DEVICE_TYPE
|
||||
const router = useRouter() // 路由对象
|
||||
const createEditDialogRef = ref(null)
|
||||
const list = ref([])
|
||||
const queryParams = reactive({
|
||||
pageNo: 1,
|
||||
pageSize: 100,
|
||||
robotNo: undefined
|
||||
deviceNo: undefined,
|
||||
deviceType: undefined
|
||||
})
|
||||
const spaceBetween = ref(20)
|
||||
const navigation = ref({
|
||||
nextEl: '.swiper-button-next-custome',
|
||||
prevEl: '.swiper-button-prev-custome'
|
||||
})
|
||||
const activeName = ref('-1')
|
||||
const handleClick = (tab, event) => {
|
||||
console.log(tab, event)
|
||||
queryParams.deviceType = tab.props.name !=-1?tab.props.name:undefined
|
||||
getCarList()
|
||||
}
|
||||
const typeList = ref([])
|
||||
|
||||
const getTypeList = () => {
|
||||
typeList.value = getDictOptions(DICT_TYPE.DEVICE_TYPE)&&getDictOptions(DICT_TYPE.DEVICE_TYPE).length?JSON.parse(JSON.stringify(getDictOptions(DICT_TYPE.DEVICE_TYPE))):[]
|
||||
console.log(typeList.value)
|
||||
typeList.value.unshift({ label: '全部', value: '-1' })
|
||||
getRobotInformationStatistics()
|
||||
}
|
||||
// 在modules加入要使用的模块
|
||||
const modules = [Autoplay, Navigation, Scrollbar]
|
||||
// Pagination
|
||||
@ -233,6 +163,17 @@ const onSlideChange = (swiper) => {
|
||||
// swiper是当前轮播的对象,里面可以获取到当前swiper的所有信息,当前索引是activeIndex
|
||||
console.log(swiper.activeIndex)
|
||||
}
|
||||
//根据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
|
||||
}
|
||||
}
|
||||
// (1:充电桩,2:输送线,3:码垛机,4:自动门,5:提升机,6:信号灯,7:按钮盒,8:拆垛机)
|
||||
const formatterDeviceType = (deviceType) => {
|
||||
switch (deviceType) {
|
||||
@ -254,60 +195,18 @@ const formatterDeviceType = (deviceType) => {
|
||||
return '拆垛机'
|
||||
}
|
||||
}
|
||||
const topList = ref([
|
||||
{
|
||||
name: '总数',
|
||||
count: 0,
|
||||
id: -1
|
||||
},
|
||||
{
|
||||
name: '充电桩',
|
||||
count: 0,
|
||||
id: 1
|
||||
},
|
||||
{
|
||||
name: '输送线',
|
||||
count: 0,
|
||||
id: 2
|
||||
},
|
||||
{
|
||||
name: '码垛机',
|
||||
count: 0,
|
||||
id: 3
|
||||
},
|
||||
{
|
||||
name: '自动门',
|
||||
count: 0,
|
||||
id: 4
|
||||
},
|
||||
{
|
||||
name: '提升机',
|
||||
count: 0
|
||||
},
|
||||
{
|
||||
name: '信号灯',
|
||||
count: 0
|
||||
},
|
||||
{
|
||||
name: '按钮盒',
|
||||
count: 0
|
||||
},
|
||||
{
|
||||
name: '拆垛机',
|
||||
count: 0
|
||||
}
|
||||
])
|
||||
|
||||
const timerRef = ref(null)
|
||||
//查询车辆列表
|
||||
const getCarList = async () => {
|
||||
if (timerRef.value) {
|
||||
clearInterval(timerRef.value)
|
||||
timerRef.value = null
|
||||
}
|
||||
timerRef.value = setInterval(() => {
|
||||
getCarList()
|
||||
getRobotInformationStatistics()
|
||||
}, 5000)
|
||||
// if (timerRef.value) {
|
||||
// clearInterval(timerRef.value)
|
||||
// timerRef.value = null
|
||||
// }
|
||||
// timerRef.value = setInterval(() => {
|
||||
// getCarList()
|
||||
// getRobotInformationStatistics()
|
||||
// }, 5000)
|
||||
let res = await DeviceApi.deviceInformationPage(queryParams)
|
||||
// console.log(res.list)
|
||||
list.value = res.list
|
||||
@ -323,27 +222,25 @@ const carStatistics = ref({
|
||||
})
|
||||
//查询车辆统计
|
||||
const getRobotInformationStatistics = async () => {
|
||||
let res = await DeviceApi.robotInformationStatistics({})
|
||||
console.log('车辆统计', res)
|
||||
let res = await DeviceApi.deviceNumber({})
|
||||
console.log('设备统计', res)
|
||||
let total = 0
|
||||
if (res) {
|
||||
carStatistics.value = res
|
||||
carStatistics.value.total =
|
||||
Number(carStatistics.value.standby) +
|
||||
Number(carStatistics.value.inTask) +
|
||||
Number(carStatistics.value.doLock) +
|
||||
Number(carStatistics.value.offline) +
|
||||
Number(carStatistics.value.fault) +
|
||||
Number(carStatistics.value.charge)
|
||||
} else {
|
||||
carStatistics.value = {
|
||||
standby: 0,
|
||||
inTask: 0,
|
||||
doLock: 0,
|
||||
offline: 0,
|
||||
fault: 0,
|
||||
charge: 0,
|
||||
total: 0
|
||||
if(typeList.value.length){
|
||||
typeList.value.forEach(item => {
|
||||
res.forEach(resItem => {
|
||||
if(item.value == resItem.deviceType){
|
||||
item.number = resItem.number
|
||||
total += Number(resItem.number)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
typeList.value[0].number = total
|
||||
} else {
|
||||
typeList.value.forEach(item => {
|
||||
item.number = 0
|
||||
})
|
||||
}
|
||||
}
|
||||
//新建编辑车辆
|
||||
@ -352,13 +249,13 @@ const openForm = (type, id) => {
|
||||
}
|
||||
//删除车辆
|
||||
const deleteCar = (id) => {
|
||||
ElMessageBox.confirm('您确定要删除此车辆吗?', '提示', {
|
||||
ElMessageBox.confirm('您确定要删除此设备吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
.then(() => {
|
||||
DeviceApi.deleteRobotInformation(id).then((res) => {
|
||||
DeviceApi.deleteDeviceInformation(id).then((res) => {
|
||||
getCarList()
|
||||
message.success('删除成功')
|
||||
})
|
||||
@ -405,7 +302,9 @@ const goToMap = (item) => {
|
||||
}
|
||||
onMounted(() => {
|
||||
getCarList()
|
||||
getRobotInformationStatistics()
|
||||
getTypeList()
|
||||
// getRobotInformationStatistics()
|
||||
|
||||
})
|
||||
onBeforeUnmount(() => {
|
||||
if (timerRef.value) {
|
||||
@ -439,7 +338,32 @@ onBeforeRouteLeave((to, from, next) => {
|
||||
margin: 0px;
|
||||
}
|
||||
:deep(.is-active) {
|
||||
background-color: #1677ff;
|
||||
background-color: #EBF1FF;
|
||||
color: #0D162A;
|
||||
}
|
||||
:deep(.el-tabs__item) {
|
||||
padding-left: 8px !important;
|
||||
padding-right: 8px !important;
|
||||
height: auto !important;
|
||||
padding-top: 5px !important;
|
||||
padding-bottom: 5px !important;
|
||||
}
|
||||
:deep(.el-tabs__active-bar) {
|
||||
height: 0;
|
||||
}
|
||||
:deep(.el-tabs__nav-next) {
|
||||
line-height: 34px !important;
|
||||
}
|
||||
:deep(.el-tabs__nav-prev) {
|
||||
line-height: 34px !important;
|
||||
}
|
||||
:deep(.el-input-group__append){
|
||||
background: none !important;
|
||||
}
|
||||
:deep(.el-input__wrapper){
|
||||
border: 1px solid var(--el-input-border-color,var(--el-border-color));
|
||||
border-right: none;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.swiper-container {
|
||||
@ -771,4 +695,13 @@ input::-webkit-input-placeholder {
|
||||
.m-b-10 {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.item-inner-left-img-box-no{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 13px;
|
||||
color: #a4afca;
|
||||
}
|
||||
</style>
|
||||
|
@ -37,7 +37,8 @@
|
||||
|
||||
<!-- 列表 -->
|
||||
<ContentWrap>
|
||||
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
|
||||
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true" row-class-name="table-row-class"
|
||||
:header-cell-style="{ backgroundColor: '#EBF1FF', color: '#0D162A' }">
|
||||
<el-table-column label="序号" align="center" prop="id" />
|
||||
<el-table-column label="告警等级(1-4)" align="center" prop="warnLevel" />
|
||||
<el-table-column label="告警/异常ID" align="center" prop="warnCode" />
|
||||
@ -186,3 +187,8 @@ onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
</script>
|
||||
<style scoped>
|
||||
::v-deep .table-row-class {
|
||||
background-color: #f9f9f9e5;
|
||||
}
|
||||
</style>
|
||||
|
@ -39,10 +39,12 @@
|
||||
<script setup>
|
||||
import { ref, defineComponent, reactive, nextTick, onMounted } from 'vue'
|
||||
import * as MapApi from '@/api/map/map'
|
||||
import WebSocketClient from '../webSocket.js';
|
||||
const imgUrl = ref('')
|
||||
|
||||
const socketClient = ref(null)
|
||||
const list = ref([])
|
||||
//获取地图点位
|
||||
const nowObject = ref(null)
|
||||
//获取地图区域
|
||||
const getList = async () => {
|
||||
let data = await MapApi.getPositionMapGetMap()
|
||||
let mapList = []
|
||||
@ -53,13 +55,38 @@ const getList = async () => {
|
||||
})
|
||||
}
|
||||
list.value = mapList
|
||||
|
||||
console.log(list.value,data)
|
||||
//默认取第一个
|
||||
if (data[1][1]) {
|
||||
getMapData(data[1][1])
|
||||
if (data[1][0]) {
|
||||
getMapData(data[1][0])
|
||||
}
|
||||
}
|
||||
|
||||
const getPositionMapList = async () => {
|
||||
let data = await MapApi.getPositionMap()
|
||||
console.log(data)
|
||||
}
|
||||
const replaceHttpWithWs = (str) => {
|
||||
return str.replace(/^http/, 'ws');
|
||||
}
|
||||
const linkWebSocket = (url) => {
|
||||
socketClient.value = new WebSocketClient(url);
|
||||
if(socketClient.value){
|
||||
// 监听消息
|
||||
socketClient.value.onMessage((message) => {
|
||||
console.log('收到消息:', message);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const sendMessage = () => {
|
||||
socketClient.value.send('Hello, WebSocket!');
|
||||
};
|
||||
|
||||
const disconnect = () => {
|
||||
socketClient.value.disconnect();
|
||||
};
|
||||
//获取扫描图
|
||||
const getMapData = async (item) => {
|
||||
let data = await MapApi.getPositionMapdDwnloadPngBase64({
|
||||
@ -69,10 +96,15 @@ const getMapData = async (item) => {
|
||||
|
||||
let base64Url = 'data:image/png;base64,'
|
||||
imgUrl.value = data
|
||||
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}`
|
||||
console.log(websoketUrl)
|
||||
linkWebSocket(websoketUrl)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getList()
|
||||
|
||||
})
|
||||
</script>
|
||||
|
||||
|
@ -22,6 +22,7 @@ import { ref, defineComponent, reactive, nextTick, onMounted } from 'vue'
|
||||
import * as MapApi from '@/api/map/map'
|
||||
import download from '@/utils/download'
|
||||
|
||||
|
||||
defineOptions({ name: 'MapPageRealTimeMap' })
|
||||
|
||||
const indexPageRef = ref(null)
|
||||
|
115
src/views/mapPage/realTimeMap/webSocket.js
Normal file
115
src/views/mapPage/realTimeMap/webSocket.js
Normal file
@ -0,0 +1,115 @@
|
||||
// websocket.js
|
||||
class WebSocketClient {
|
||||
constructor(url) {
|
||||
this.currentUrl = url;
|
||||
this.socket = null;
|
||||
this.heartbeatInterval = null;
|
||||
this.messageCallback = null;
|
||||
this.reconnectTimer = null;
|
||||
this.reconnectAttempts = 0;
|
||||
this.MAX_RECONNECT_ATTEMPTS = 5;
|
||||
this.RECONNECT_DELAY = 5000; // 5 秒
|
||||
this.HEARTBEAT_INTERVAL = 30000; // 30 秒
|
||||
this.URL_CHECK_INTERVAL = 5000; // 每 5 秒检查一次 URL
|
||||
this.init();
|
||||
this.startUrlCheck();
|
||||
}
|
||||
|
||||
init() {
|
||||
try {
|
||||
console.log('尝试创建 WebSocket 连接:', this.currentUrl);
|
||||
this.socket = new WebSocket(this.currentUrl);
|
||||
|
||||
this.socket.onopen = () => {
|
||||
console.log('WebSocket 连接已建立:', this.currentUrl);
|
||||
this.startHeartbeat();
|
||||
this.reconnectAttempts = 0;
|
||||
};
|
||||
|
||||
this.socket.onmessage = (event) => {
|
||||
if (this.messageCallback) {
|
||||
this.messageCallback(event.data);
|
||||
}
|
||||
};
|
||||
|
||||
this.socket.onclose = () => {
|
||||
console.log('WebSocket 连接已关闭:', this.currentUrl);
|
||||
this.stopHeartbeat();
|
||||
this.reconnect();
|
||||
};
|
||||
|
||||
this.socket.onerror = (error) => {
|
||||
console.error('WebSocket 发生错误:', error);
|
||||
this.socket.close();
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('创建 WebSocket 连接时出错:', error);
|
||||
}
|
||||
}
|
||||
|
||||
startHeartbeat() {
|
||||
this.heartbeatInterval = setInterval(() => {
|
||||
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
|
||||
this.socket.send('ping');
|
||||
}
|
||||
}, this.HEARTBEAT_INTERVAL);
|
||||
}
|
||||
|
||||
stopHeartbeat() {
|
||||
if (this.heartbeatInterval) {
|
||||
clearInterval(this.heartbeatInterval);
|
||||
this.heartbeatInterval = null;
|
||||
}
|
||||
}
|
||||
|
||||
onMessage(callback) {
|
||||
this.messageCallback = callback;
|
||||
}
|
||||
|
||||
send(message) {
|
||||
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
|
||||
this.socket.send(message);
|
||||
} else {
|
||||
console.error('WebSocket 连接未打开,无法发送消息');
|
||||
}
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
if (this.socket) {
|
||||
this.stopHeartbeat();
|
||||
this.socket.close();
|
||||
this.socket = null;
|
||||
}
|
||||
}
|
||||
|
||||
reconnect() {
|
||||
if (this.reconnectAttempts < this.MAX_RECONNECT_ATTEMPTS) {
|
||||
this.reconnectTimer = setTimeout(() => {
|
||||
console.log('尝试重新连接...', this.currentUrl);
|
||||
this.reconnectAttempts++;
|
||||
this.init();
|
||||
}, this.RECONNECT_DELAY);
|
||||
} else {
|
||||
console.error('达到最大重连次数,停止重连');
|
||||
}
|
||||
}
|
||||
|
||||
startUrlCheck() {
|
||||
setInterval(() => {
|
||||
const newUrl = this.getUpdatedUrl();
|
||||
if (newUrl && newUrl!== this.currentUrl) {
|
||||
this.disconnect();
|
||||
this.currentUrl = newUrl;
|
||||
this.init();
|
||||
}
|
||||
}, this.URL_CHECK_INTERVAL);
|
||||
}
|
||||
|
||||
// 这个方法需要根据实际情况重写,用于获取最新的 URL
|
||||
getUpdatedUrl() {
|
||||
// 这里只是示例,返回 null 表示没有更新的 URL
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export default WebSocketClient;
|
@ -142,8 +142,7 @@
|
||||
:step="1"
|
||||
type="number"
|
||||
:min="0"
|
||||
:max="99999"
|
||||
placeholder="充电阈值"
|
||||
placeholder="充电周期"
|
||||
>
|
||||
<template #append>天</template>
|
||||
</el-input-number>
|
||||
@ -172,7 +171,7 @@
|
||||
:step="1"
|
||||
type="number"
|
||||
:min="0"
|
||||
:max="99"
|
||||
|
||||
placeholder="请输入等待时间"
|
||||
>
|
||||
<template #append>秒</template>
|
||||
|
Loading…
Reference in New Issue
Block a user