This commit is contained in:
yyy 2025-02-08 17:38:55 +08:00
commit 82eff5bf84
11 changed files with 1115 additions and 3 deletions

View File

@ -4,8 +4,9 @@ NODE_ENV=production
VITE_DEV=true
# 请求路径
VITE_BASE_URL='http://192.168.0.74: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.74:48080'
# 文件上传类型server - 后端上传, client - 前端直连上传仅支持S3服务
VITE_UPLOAD_TYPE=server

View File

@ -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 服务

77
package-lock.json generated
View File

@ -51,9 +51,11 @@
"qs": "^6.12.0",
"sortablejs": "^1.15.3",
"steady-xml": "^0.1.0",
"swiper": "^8.4.7",
"url": "^0.11.3",
"video.js": "^7.21.5",
"vue": "3.5.12",
"vue-awesome-swiper": "^5.0.1",
"vue-dompurify-html": "^4.1.4",
"vue-i18n": "9.10.2",
"vue-router": "4.4.5",
@ -16573,6 +16575,42 @@
"integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==",
"dev": true
},
"node_modules/swiper": {
"version": "8.4.7",
"resolved": "https://registry.npmmirror.com/swiper/-/swiper-8.4.7.tgz",
"integrity": "sha512-VwO/KU3i9IV2Sf+W2NqyzwWob4yX9Qdedq6vBtS0rFqJ6Fa5iLUJwxQkuD4I38w0WDJwmFl8ojkdcRFPHWD+2g==",
"funding": [
{
"type": "patreon",
"url": "https://www.patreon.com/swiperjs"
},
{
"type": "open_collective",
"url": "http://opencollective.com/swiper"
}
],
"hasInstallScript": true,
"dependencies": {
"dom7": "^4.0.4",
"ssr-window": "^4.0.2"
},
"engines": {
"node": ">= 4.7.0"
}
},
"node_modules/swiper/node_modules/dom7": {
"version": "4.0.6",
"resolved": "https://registry.npmmirror.com/dom7/-/dom7-4.0.6.tgz",
"integrity": "sha512-emjdpPLhpNubapLFdjNL9tP06Sr+GZkrIHEXLWvOGsytACUrkbeIdjO5g77m00BrHTznnlcNqgmn7pCN192TBA==",
"dependencies": {
"ssr-window": "^4.0.0"
}
},
"node_modules/swiper/node_modules/ssr-window": {
"version": "4.0.2",
"resolved": "https://registry.npmmirror.com/ssr-window/-/ssr-window-4.0.2.tgz",
"integrity": "sha512-ISv/Ch+ig7SOtw7G2+qkwfVASzazUnvlDTwypdLoPoySv+6MqlOV10VwPSE6EWkGjhW50lUmghPmpYZXMu/+AQ=="
},
"node_modules/synckit": {
"version": "0.8.8",
"resolved": "https://registry.npmmirror.com/synckit/-/synckit-0.8.8.tgz",
@ -17918,6 +17956,15 @@
}
}
},
"node_modules/vue-awesome-swiper": {
"version": "5.0.1",
"resolved": "https://registry.npmmirror.com/vue-awesome-swiper/-/vue-awesome-swiper-5.0.1.tgz",
"integrity": "sha512-mWjFJzUqA4lG+DmsmibvMpoiBnl+IH2SSeiiQ3i5M0t1y9FknTxnGT0DsMb2YdJLgjYMEK3sYOWzqgLnZMH8Lg==",
"peerDependencies": {
"swiper": "^7.0.0 || ^8.0.0",
"vue": "3.x"
}
},
"node_modules/vue-dompurify-html": {
"version": "4.1.4",
"resolved": "https://registry.npmmirror.com/vue-dompurify-html/-/vue-dompurify-html-4.1.4.tgz",
@ -30293,6 +30340,30 @@
}
}
},
"swiper": {
"version": "8.4.7",
"resolved": "https://registry.npmmirror.com/swiper/-/swiper-8.4.7.tgz",
"integrity": "sha512-VwO/KU3i9IV2Sf+W2NqyzwWob4yX9Qdedq6vBtS0rFqJ6Fa5iLUJwxQkuD4I38w0WDJwmFl8ojkdcRFPHWD+2g==",
"requires": {
"dom7": "^4.0.4",
"ssr-window": "^4.0.2"
},
"dependencies": {
"dom7": {
"version": "4.0.6",
"resolved": "https://registry.npmmirror.com/dom7/-/dom7-4.0.6.tgz",
"integrity": "sha512-emjdpPLhpNubapLFdjNL9tP06Sr+GZkrIHEXLWvOGsytACUrkbeIdjO5g77m00BrHTznnlcNqgmn7pCN192TBA==",
"requires": {
"ssr-window": "^4.0.0"
}
},
"ssr-window": {
"version": "4.0.2",
"resolved": "https://registry.npmmirror.com/ssr-window/-/ssr-window-4.0.2.tgz",
"integrity": "sha512-ISv/Ch+ig7SOtw7G2+qkwfVASzazUnvlDTwypdLoPoySv+6MqlOV10VwPSE6EWkGjhW50lUmghPmpYZXMu/+AQ=="
}
}
},
"synckit": {
"version": "0.8.8",
"resolved": "https://registry.npmmirror.com/synckit/-/synckit-0.8.8.tgz",
@ -31306,6 +31377,12 @@
}
}
},
"vue-awesome-swiper": {
"version": "5.0.1",
"resolved": "https://registry.npmmirror.com/vue-awesome-swiper/-/vue-awesome-swiper-5.0.1.tgz",
"integrity": "sha512-mWjFJzUqA4lG+DmsmibvMpoiBnl+IH2SSeiiQ3i5M0t1y9FknTxnGT0DsMb2YdJLgjYMEK3sYOWzqgLnZMH8Lg==",
"requires": {}
},
"vue-dompurify-html": {
"version": "4.1.4",
"resolved": "https://registry.npmmirror.com/vue-dompurify-html/-/vue-dompurify-html-4.1.4.tgz",

View File

@ -67,9 +67,11 @@
"qs": "^6.12.0",
"sortablejs": "^1.15.3",
"steady-xml": "^0.1.0",
"swiper": "^8.4.7",
"url": "^0.11.3",
"video.js": "^7.21.5",
"vue": "3.5.12",
"vue-awesome-swiper": "^5.0.1",
"vue-dompurify-html": "^4.1.4",
"vue-i18n": "9.10.2",
"vue-router": "4.4.5",

56
src/api/car/index.ts Normal file
View File

@ -0,0 +1,56 @@
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 robotInformationPage = async (params) => {
return await request.get({ url: `/system/robot/information/page`, params })
}
//统计车辆待命-任务中-离线
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 robotInformationUpdate = async (data) => {
return await request.put({ url: `/system/robot/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 })
}

11
src/api/carError/index.ts Normal file
View File

@ -0,0 +1,11 @@
import request from '@/config/axios'
//获得机器人告警信息分页
export const getRobotWarnMsgPage = async (params) => {
return await request.get({ url: `/system/robot/warn-msg/page`, params })
}

BIN
src/assets/imgs/chache.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

View File

@ -43,10 +43,13 @@ import Logger from '@/utils/Logger'
import VueDOMPurifyHTML from 'vue-dompurify-html' // 解决v-html 的安全隐患
import VueDragResizeRotate from '@gausszhou/vue3-drag-resize-rotate'
import '@gausszhou/vue3-drag-resize-rotate/lib/bundle.esm.css'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
// 创建实例
const setupAll = async () => {
const app = createApp(App)
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
await setupI18n(app)
setupStore(app)
@ -68,6 +71,7 @@ const setupAll = async () => {
app.use(VueDOMPurifyHTML)
app.use(VueDragResizeRotate)
app.mount('#app')
}
setupAll()

View File

@ -0,0 +1,292 @@
<template>
<Dialog v-model="dialogVisible" :title="title" width="800" 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-option
:label="item.robotModelNumber"
:value="item.id"
v-for="item in carModelList"
:key="item.id"
/>
</el-select>
</el-form-item>
<el-form-item required label="车辆编号" prop="robotNo">
<el-input v-model="formData.robotNo" :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>
<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>
<el-form-item required label="Mac地址" prop="macAddress">
<el-input v-model="formData.macAddress" :disabled="false" placeholder="请输入Mac地址"/>
</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>
</el-form>
<template #footer>
<el-button :disabled="formLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
</template>
</Dialog>
</template>
<script lang="ts" setup>
const { t } = useI18n() //
const message = useMessage() //
import * as MapTaskAPi from '@/api/map/mapTask'
import * as CarApi from '@/api/car/index'
const dialogVisible = ref(false) //
const formLoading = ref(false) // 12
const title = ref('新建') // form
const formData = ref({
robotModelId: undefined, //id
robotNo: undefined, //AGV
macAddress: undefined, //mac
floorAreaJson: [],
autoCharge: 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' }]
})
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})
formData.value = data
if(data.positionMapList.length){
data.positionMapList.forEach(item => {
floorAreaJsonData.value.push([item.floor,item.id])
})
}
console.log(data)
} else {
title.value = '新建'
}
// getCanUseRobotList()
// getTaskNo()
}
defineExpose({ open }) // open
/** 提交表单 */
const emit = defineEmits(['success']) // success
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)
message.success(t('common.updateSuccess'))
dialogVisible.value = false
emit('success')
} else {
await CarApi.robotInformationCreate(formData.value)
message.success(t('common.createSuccess'))
dialogVisible.value = false
emit('success')
}
} finally {
formLoading.value = false
}
}
//
const { push } = useRouter()
const taskManagement = () => {
push({ name: 'taskManagementCreateTask' })
}
//
const robotList = ref([])
const getCanUseRobotList = async () => {
robotList.value = await MapTaskAPi.getCanUseRobot()
}
//
const getTaskNo = async () => {
formData.value.taskNo = await MapTaskAPi.getTaskNo()
}
//
const getLocationList = async (type, locationNo) => {
return await MapTaskAPi.getLocationByName({
type, // 12线 3
locationNo
})
}
//
const loading = ref(false)
const releaseRemoteMethod = async (query, item) => {
if (query) {
loading.value = true
item.releaseList = await getLocationList(item.releaseType, query)
loading.value = false
} else {
item.releaseList = []
}
}
//
const takeRemoteMethod = async (query, item) => {
if (query) {
item.takeList = await getLocationList(item.takeType, query)
} else {
item.takeList = []
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
robotModelId: undefined, //id
robotNo: undefined, //AGV
macAddress: undefined, //mac
floorAreaJson: [],
autoCharge: undefined
}
floorAreaJsonData.value = []
formRef.value?.resetFields()
}
</script>
<style lang="scss">
.task-dialog {
.el-dialog__header {
border-bottom: none;
}
.el-dialog__footer {
border-top: none !important;
}
}
.task-tips {
display: flex;
align-items: center;
justify-content: flex-end;
}
.el-select-dropdown__loading {
display: flex;
justify-content: center;
align-items: center;
height: 100px;
font-size: 20px;
}
.circular {
display: inline;
height: 30px;
width: 30px;
animation: loading-rotate 2s linear infinite;
}
.path {
animation: loading-dash 1.5s ease-in-out infinite;
stroke-dasharray: 90, 150;
stroke-dashoffset: 0;
stroke-width: 2;
stroke: var(--el-color-primary);
stroke-linecap: round;
}
@keyframes loading-rotate {
to {
transform: rotate(360deg);
}
}
@keyframes loading-dash {
0% {
stroke-dasharray: 1, 200;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 90, 150;
stroke-dashoffset: -40px;
}
100% {
stroke-dasharray: 90, 150;
stroke-dashoffset: -120px;
}
}
@keyframes custom-spin-move {
to {
opacity: 1;
}
}
</style>

View File

@ -0,0 +1,481 @@
<template>
<div class="">
<ContentWrap>
<div class="top-box">
<el-button type="primary" @click="openForm('create')">新增车辆</el-button>
<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>
</div>
</ContentWrap>
<ContentWrap v-loading="formLoading">
<div style="width: 100%">
<!-- 大于等于4个数据 -->
<div class="swiper-container" v-if="list.length >= 4">
<swiper
:modules="modules"
:loop="true"
:slides-per-view="list.length > 4 ? 4 : list.length"
:space-between="spaceBetween"
:navigation="navigation"
:pagination="{ clickable: true }"
:scrollbar="{ draggable: true }"
:direction="'horizontal'"
:observer="true"
:observeParents="true"
class="swiperBox"
>
<!-- :autoplay="{ delay: 5000, disableOnInteraction: false }" -->
<swiper-slide v-for="item in list" :key="item">
<div class="swiper-item-box">
<div class="swiper-item-box-top">
<el-button type="primary" size="small" @click="goToMap(item)">地图定位</el-button>
<div class="swiper-item-box-top-name"> {{ item.robotNo || '' }} </div>
<div class="swiper-item-box-top-msg">
<el-dropdown>
<div style="flex-shrink: 0">
<el-icon size="20px"><MoreFilled /></el-icon>
</div>
<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>
</el-dropdown>
</div>
</div>
<div class="swiper-item-img-box">
<img :src="item.url" alt="" class="swiper-item-img" />
</div>
<div class="swiper-item-box-msg">
<div class="swiper-item-box-msg-item">
<div class="swiper-item-box-msg-item-left"> 电量 </div>
<div class="swiper-item-box-msg-item-right" v-if="item.electricity">
{{ item.electricity || '' }} %</div
>
<div class="swiper-item-box-msg-item-right" v-else> 无电量数据</div>
</div>
<div class="swiper-item-box-msg-item">
<div class="swiper-item-box-msg-item-left"> 状态 </div>
<!-- 0暂停且无任务1暂停(有处理中的任务)2任务中3待命 -->
<div class="swiper-item-box-msg-item-right">
{{
item.status == 0
? '暂停且无任务'
: item.status == 1
? '暂停(有处理中的任务)'
: item.status == 2
? '任务中'
: '待命'
}}
</div>
</div>
<div class="swiper-item-box-msg-item">
<div class="swiper-item-box-msg-item-left"> 楼层 </div>
<div class="swiper-item-box-msg-item-right"> 1 </div>
</div>
<div class="swiper-item-box-msg-item">
<div class="swiper-item-box-msg-item-left"> 区域 </div>
<div class="swiper-item-box-msg-item-right"> A </div>
</div>
<div class="swiper-item-box-msg-item">
<div class="swiper-item-box-msg-item-left"> 信息 </div>
<div class="swiper-item-box-msg-item-right"> 车辆正在待命 </div>
</div>
<el-button type="primary" size="small" style="margin-top: 30px"
>日志查看</el-button
>
</div>
</div>
</swiper-slide>
<!-- 如果需要滚动条 -->
<div class="swiper-scrollbar"></div>
</swiper>
<!--右箭头如果放置在swiper外面需要自定义样式swiper-button-prev-->
<div class="swiper-button-prev-custome" @click.stop="prevEl(item, index)">
<el-icon size="40px"><CaretLeft /></el-icon>
</div>
<!--左箭头如果放置在swiper外面需要自定义样式swiper-button-next-->
<div class="swiper-button-next-custome" @click.stop="nextEl">
<el-icon size="40px"><CaretRight /></el-icon
></div>
</div>
<!-- 不足四个数据的时候 -->
<div v-else class="letter-data-box">
<div
class="letter-data-item"
v-for="(item, index) in list"
:key="index"
:style="{ marginRight: index % 4 == 3 ? '0' : '20px' }"
>
<div class="swiper-item-box">
<div class="swiper-item-box-top">
<el-button type="primary" size="small" @click="goToMap(item)">地图定位</el-button>
<div class="swiper-item-box-top-name"> {{ item.robotNo || '' }} </div>
<div class="swiper-item-box-top-msg">
<el-dropdown>
<div style="flex-shrink: 0">
<el-icon size="20px"><MoreFilled /></el-icon>
</div>
<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>
</el-dropdown>
</div>
</div>
<div class="swiper-item-img-box">
<img :src="item.url" alt="" class="swiper-item-img" />
</div>
<div class="swiper-item-box-msg">
<div class="swiper-item-box-msg-item">
<div class="swiper-item-box-msg-item-left"> 电量 </div>
<div class="swiper-item-box-msg-item-right" v-if="item.electricity">
{{ item.electricity || '' }} %</div
>
<div class="swiper-item-box-msg-item-right" v-else> 无电量数据</div>
</div>
<div class="swiper-item-box-msg-item">
<div class="swiper-item-box-msg-item-left"> 状态 </div>
<!-- 0暂停且无任务1暂停(有处理中的任务)2任务中3待命 -->
<div class="swiper-item-box-msg-item-right">
{{
item.status == 0
? '暂停且无任务'
: item.status == 1
? '暂停(有处理中的任务)'
: item.status == 2
? '任务中'
: '待命'
}}
</div>
</div>
<div class="swiper-item-box-msg-item">
<div class="swiper-item-box-msg-item-left"> 楼层 </div>
<div class="swiper-item-box-msg-item-right"> {{ item.floor || '未知' }} </div>
</div>
<div class="swiper-item-box-msg-item">
<div class="swiper-item-box-msg-item-left"> 区域 </div>
<div class="swiper-item-box-msg-item-right"> {{ item.area || '未知' }} </div>
</div>
<div class="swiper-item-box-msg-item">
<div class="swiper-item-box-msg-item-left"> 信息 </div>
<div class="swiper-item-box-msg-item-right"> {{ item.msg || '' }} </div>
</div>
<el-button type="primary" size="small" style="margin-top: 30px">日志查看</el-button>
</div>
</div>
</div>
</div>
<!-- 车辆统计 -->
<div class="car-statistics-box" v-if="carStatistics">
<!-- carStatistics -->
<div class="car-statistics-item" style="color: #67c23a; border: 2px solid #67c23a">
<div class="car-statistics-item-name"> 待命中 </div>
<div class="car-statistics-item-value">
{{ carStatistics.standby || 0 }}
</div>
</div>
<div class="car-statistics-item" style="color: #e6a23c; border: 2px solid #e6a23c">
<div class="car-statistics-item-name"> 任务中 </div>
<div class="car-statistics-item-value">
{{ carStatistics.inTask || 0 }}
</div>
</div>
<div class="car-statistics-item" style="color: #409eff; border: 2px solid #409eff">
<div class="car-statistics-item-name"> 充电中 </div>
<div class="car-statistics-item-value">
{{ carStatistics.charge || 0 }}
</div>
</div>
<div class="car-statistics-item" style="color: #f56c6c; border: 2px solid #f56c6c">
<div class="car-statistics-item-name"> 离线 </div>
<div class="car-statistics-item-value">
{{ carStatistics.offline || 0 }}
</div>
</div>
</div>
</div>
</ContentWrap>
<createEditDialog ref="createEditDialogRef" @success="getCarList" />
</div>
</template>
<script setup>
import { ref, reactive, onMounted ,onBeforeUnmount } from 'vue'
defineOptions({ name: 'BoardCarBoard' })
import * as CarApi from '@/api/car/index'
import { Swiper, SwiperSlide } from 'swiper/vue'
// API
import { onBeforeRouteLeave,onBeforeRouteUpdate } from 'vue-router';
const message = useMessage() //
// swiper
import 'swiper/css/pagination' //
import 'swiper/css/navigation' //
// import 'swiper/css/scrollbar' // 使import
// swiper
import { Autoplay, Pagination, Navigation, Scrollbar } from 'swiper'
import createEditDialog from './createEditDialog.vue'
import 'swiper/css'
const router = useRouter() //
const createEditDialogRef = ref(null)
const list = ref([])
const queryParams = reactive({
pageNo: 1,
pageSize: 100,
robotNo: undefined
})
const spaceBetween = ref(20)
const navigation = ref({
nextEl: '.swiper-button-next-custome',
prevEl: '.swiper-button-prev-custome'
})
// modules使
const modules = [Autoplay, Navigation, Scrollbar]
// Pagination
const prevEl = (item, index) => {
// console.log('' + index + item)
}
const nextEl = () => {
// console.log('')
}
// swiper
const onSlideChange = (swiper) => {
// swiperswiperactiveIndex
console.log(swiper.activeIndex)
}
const timerRef = ref(null)
//
const getCarList = async () => {
if(timerRef.value){
clearInterval(timerRef.value)
timerRef.value = null
}
timerRef.value = setInterval(() => {
getCarList()
getRobotInformationStatistics()
},5000)
let res = await CarApi.robotInformationPage(queryParams)
// console.log(res.list)
list.value = res.list
}
const carStatistics = ref(null)
//
const getRobotInformationStatistics = async () => {
let res = await CarApi.robotInformationStatistics({})
console.log('车辆统计', res)
carStatistics.value = res
}
//
const openForm = (type, id) => {
createEditDialogRef.value.open(type, id ? id : null)
}
//
const deleteCar = (id) => {
ElMessageBox.confirm('您确定要删除此车辆吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {
CarApi.deleteRobotInformation(id).then((res) => {
getCarList()
message.success('删除成功')
})
})
.catch(() => {
// ElMessage({
// type: 'info',
// message: 'Delete canceled',
// })
})
}
const clockCar = (item) => {
let valueStr = item.robotTaskModel == 1 ? '锁定' : '解锁'
let data = JSON.parse(JSON.stringify(item))
data.robotTaskModel = item.robotTaskModel == 1 ? 0 : 1
ElMessageBox.confirm(`您确定要${valueStr}此车辆吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {
CarApi.robotInformationUpdate(data).then((res) => {
getCarList()
message.success(`${valueStr}成功`)
})
})
.catch(() => {
// ElMessage({
// type: 'info',
// message: 'Delete canceled',
// })
})
}
//
const goToMap = (item) => {
// console.log(item)
router.push({
name: 'MapPageRealTimeMap',
query: {
id: item.id
}
})
}
onMounted(() => {
getCarList()
getRobotInformationStatistics()
})
onBeforeUnmount(() => {
if(timerRef.value){
clearInterval(timerRef.value)
timerRef.value = null
}
})
// beforeRouteLeave((to, from, next) => {
// console.log('beforeRouteLeave',to, from, next)
// if(timerRef.value){
// clearInterval(timerRef.value)
// timerRef.value = null
// }
// })
onBeforeRouteLeave((to, from, next) => {
// console.log('beforeRouteLeave',to, from)
if(timerRef.value){
clearInterval(timerRef.value)
timerRef.value = null
}
next()
})
</script>
<style scoped>
.swiper-container {
width: calc(100% - 60px);
padding: 0 30px;
margin: 0 auto;
position: relative;
}
.swiperBox {
width: 100%;
/* background: rgba(0, 0, 0, 0.3); */
}
.swiper-item-box {
width: 100%;
padding-bottom: 30px;
border: 1px solid #f5f5f5;
}
.swiper-item-img-box {
width: 100%;
display: flex;
justify-content: center;
}
.swiper-item-img {
width: 150px;
height: 150px;
}
.swiper-item-box-top {
width: calc(100% - 20px);
display: flex;
align-items: center;
justify-content: space-between;
margin: 20px 0px;
padding: 0 10px;
}
.swiper-item-box-top-name {
font-size: 13px;
font-weight: bold;
}
.swiper-item-box-msg {
width: calc(100% - 20px);
padding: 0 10px;
}
.swiper-item-box-msg-item {
display: flex;
align-items: center;
margin-top: 20px;
}
.swiper-item-box-msg-item-left {
font-size: 13px;
}
.swiper-item-box-msg-item-right {
font-size: 13px;
margin-left: 40px;
}
:focus-visible {
outline: none;
}
.swiper-button-prev-custome {
position: absolute;
left: -30px;
top: 50%;
transform: translateY(-50%);
cursor: pointer;
z-index: 999;
}
.swiper-button-next-custome {
position: absolute;
right: -30px;
top: 50%;
transform: translateY(-50%);
cursor: pointer;
z-index: 999;
}
.letter-data-box {
width: calc(100% - 60px);
padding: 0 30px;
margin: 0 auto;
position: relative;
display: flex;
}
.letter-data-item {
width: calc(25% - 20px);
flex-shrink: 0;
}
.car-statistics-box {
width: 100%;
margin-top: 40px;
display: flex;
justify-content: space-between;
}
.car-statistics-item {
width: calc(15% - 20px);
padding: 0 10px;
height: 60px;
font-size: 14px;
font-weight: bold;
flex-shrink: 0;
display: flex;
align-items: center;
}
.top-box {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
}
</style>

View File

@ -0,0 +1,188 @@
<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="120px"
>
<el-form-item label="ID号" prop="warnCode">
<el-input
v-model="queryParams.warnCode"
placeholder="请输入告警/异常ID"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="时间段" prop="createTime">
<el-date-picker
v-model="queryParams.createTime"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-240px"
/>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<!-- 列表 -->
<ContentWrap>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
<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" />
<el-table-column label="车辆" align="center" prop="robotNo" />
<el-table-column label="告警/异常信息" align="center" prop="warnMsg" />
<el-table-column label="发生时间" align="center" prop="createTime" >
<template #default="scope">
{{ formatDate(scope.row.createTime, 'YYYY-MM-DD HH:mm:ss') }}
</template>
</el-table-column>
<!-- <el-table-column label="操作" align="center">
<template #default="scope">
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['system:user-bank:update']"
>
编辑
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['system:user-bank:delete']"
>
删除
</el-button>
</template>
</el-table-column> -->
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</ContentWrap>
</template>
<script setup lang="ts">
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import * as CarErrorApi from '@/api/carError'
import { formatDate } from '@/utils/formatTime'
defineOptions({ name: 'SystemCarError' })
const message = useMessage() //
const { t } = useI18n() //
const loading = ref(false) //
const list = ref([]) //
const total = ref(0) //
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
createTime: [],
warnCode: undefined,
})
const monthList = ref([
{ label: '1月', value: 1 },
{ label: '2月', value: 2 },
{ label: '3月', value: 3 },
{ label: '4月', value: 4 },
{ label: '5月', value: 5 },
{ label: '6月', value: 6 },
{ label: '7月', value: 7 },
{ label: '8月', value: 8 },
{ label: '9月', value: 9 },
{ label: '10月', value: 10 },
{ label: '11月', value: 11 },
{ label: '12月', value: 12 }
])
const queryFormRef = ref() //
const exportLoading = ref(false) //
const deptList = ref([])
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
const data = await CarErrorApi.getRobotWarnMsgPage(queryParams)
list.value = data.list
total.value = data.total
} finally {
loading.value = false
}
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
getList()
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields()
handleQuery()
}
/** 添加/修改操作 */
const formRef = ref()
const openForm = (type: string, id?: number) => {
formRef.value.open(type, id)
}
/** 关联操作 */
const formBank = ref()
const openBankForm = () => {
formBank.value.open()
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {
//
await message.delConfirm()
//
await UserBankApi.deleteUserBank(id)
message.success(t('common.delSuccess'))
//
await getList()
} catch {}
}
/** 导出按钮操作 */
const handleExport = async () => {
try {
//
await message.exportConfirm()
//
exportLoading.value = true
const data = await UserBankApi.exportUserBank(queryParams)
download.excel(data, '用户银行卡信息.xls')
} catch {
} finally {
exportLoading.value = false
}
}
/** 初始化 **/
onMounted(() => {
getList()
})
</script>