This commit is contained in:
yyy 2025-01-16 18:19:02 +08:00
parent 50815e06f5
commit 47d7f40706
13 changed files with 706 additions and 24 deletions

View File

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

View File

@ -62,7 +62,7 @@
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "rvest.vs-code-prettier-eslint"
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.defaultFormatter": "rvest.vs-code-prettier-eslint"
@ -141,5 +141,6 @@
"package.json": "pnpm-lock.yaml,yarn.lock,LICENSE,README*,CHANGELOG*,CNAME,.gitattributes,.eslintrc-auto-import.json,.gitignore,prettier.config.js,stylelint.config.js,commitlint.config.js,.stylelintignore,.prettierignore,.gitpod.yml,.eslintrc.js,.eslintignore"
},
"terminal.integrated.scrollback": 10000,
"nuxt.isNuxtApp": false
"nuxt.isNuxtApp": false,
"liveServer.settings.port": 5502
}

36
src/api/map/mapTask.ts Normal file
View File

@ -0,0 +1,36 @@
import request from '@/config/axios'
//获取取货位置
export const getLocationByName = (data) => {
return request.post({ url: '/system/ware/house-location/getLocationByName', data })
}
//获得任务号
export const getTaskNo = async (id: number) => {
return await request.get({ url: `/system/robot/task/getTaskNo?id=` + id })
}
// 查询能正常使用的车辆
export const getCanUseRobot = () => {
return request.post({ url: '/system/robot/information/getCanUseRobot' })
}
// 创建机器人任务主表
export const createTask = (data) => {
return request.post({ url: '/system/robot/task/create', data })
}
// 删除机器人任务主表
export const deleteTask = (id: number) => {
return request.delete({ url: '/system/robot/task/delete?id=' + id })
}
// 更新机器人任务主表
export const updateTask = (data) => {
return request.put({ url: '/system/robot/task/update', data })
}
//获得机器人任务主表分页
export const getTaskPageList = async (params) => {
return await request.get({ url: `/system/robot/task/page`, params })
}

View File

@ -11,7 +11,7 @@ const prefixCls = getPrefixCls('content-wrap')
defineProps({
title: propTypes.string.def(''),
message: propTypes.string.def(''),
bodyStyle: propTypes.object.def({ padding: '10px' })
bodyStyle: propTypes.object.def({ padding: '16px' })
})
</script>

View File

@ -0,0 +1,76 @@
@charset "UTF-8";
/* 改变主题色变量 */
/* 改变 icon 字体路径变量,必需 */
@use '~element-ui/packages/theme-chalk/src/index';
.el-table td,
.el-table th {
color: #333;
}
.el-drawer__header {
padding: 16px 16px 8px 16px;
margin: 0;
line-height: 24px;
font-size: 18px;
color: #303133;
box-sizing: border-box;
border-bottom: 1px solid #e8e8e8;
}
div[class^='el-drawer']:focus,
span:focus {
outline: none;
}
.el-drawer__body {
box-sizing: border-box;
padding: 16px;
width: 100%;
overflow-y: auto;
}
.el-dialog {
margin-top: 50vh !important;
transform: translateY(-50%);
overflow: hidden;
}
.el-dialog__wrapper {
overflow: hidden;
max-height: 100vh;
}
.el-dialog__header {
padding: 16px 16px 8px 16px;
box-sizing: border-box;
border-bottom: 1px solid #e8e8e8;
}
.el-dialog__body {
padding: 16px;
max-height: 80vh;
box-sizing: border-box;
overflow-y: auto;
}
.el-dialog__footer {
padding: 16px;
box-sizing: border-box;
border-top: 1px solid #e8e8e8;
}
.el-dialog__close {
font-weight: 600;
}
.el-select {
width: 100%;
}
.el-divider:not(.el-divider--horizontal) {
margin: 0 8px;
}
.el-divider.el-divider--horizontal {
margin: 16px 0;
}

View File

@ -0,0 +1 @@
@use '~element-ui/packages/theme-chalk/src/index';.el-table td,.el-table th{color:#333}.el-drawer__header{padding:16px 16px 8px 16px;margin:0;line-height:24px;font-size:18px;color:#303133;box-sizing:border-box;border-bottom:1px solid #e8e8e8}div[class^='el-drawer']:focus,span:focus{outline:none}.el-drawer__body{box-sizing:border-box;padding:16px;width:100%;overflow-y:auto}.el-dialog{margin-top:50vh !important;transform:translateY(-50%);overflow:hidden}.el-dialog__wrapper{overflow:hidden;max-height:100vh}.el-dialog__header{padding:16px 16px 8px 16px;box-sizing:border-box;border-bottom:1px solid #e8e8e8}.el-dialog__body{padding:16px;max-height:80vh;box-sizing:border-box;overflow-y:auto}.el-dialog__footer{padding:16px;box-sizing:border-box;border-top:1px solid #e8e8e8}.el-dialog__close{font-weight:600}.el-select{width:100%}.el-divider:not(.el-divider--horizontal){margin:0 8px}.el-divider.el-divider--horizontal{margin:16px 0}

View File

@ -239,5 +239,9 @@ export enum DICT_TYPE {
IOT_PRODUCT_FUNCTION_TYPE = 'iot_product_function_type', // IOT 产品功能类型
IOT_DATA_TYPE = 'iot_data_type', // IOT 数据类型
IOT_UNIT_TYPE = 'iot_unit_type', // IOT 单位类型
IOT_RW_TYPE = 'iot_rw_type' // IOT 读写类型
IOT_RW_TYPE = 'iot_rw_type', // IOT 读写类型
// ========== wcs 地图 ==========
ROBOT_TASK_STATUS = 'robot_task_status', //机器人的任务状态
ROBOT_QUEST_PHASES = 'robot_quest_phases' //机器人的任务阶段
}

View File

@ -0,0 +1,140 @@
<template>
<Dialog v-model="dialogVisible" title="新建任务" width="600" class="task-dialog">
<el-form :model="formData" label-width="auto" ref="formRef" :rules="formRules">
<el-form-item label="取货类型" prop="name1" required>
<el-select v-model="formData.name1" placeholder="请选择取货类型" required>
<el-option label="库位" :value="1" />
<el-option label="线库" :value="2" />
<el-option label="区域" :value="3" />
</el-select>
</el-form-item>
<el-form-item label="取货位置" prop="name2" required>
<el-input v-model="formData.name2" placeholder="请输入取货位置" />
</el-form-item>
<el-form-item label="放货类型" prop="name3" required>
<el-select v-model="formData.name3" placeholder="请选择放货类型">
<el-option label="库位" :value="1" />
<el-option label="线库" :value="2" />
<el-option label="区域" :value="3" />
</el-select>
</el-form-item>
<el-form-item label="放货位置" prop="name4" required>
<el-input v-model="formData.name4" placeholder="请输入放货位置" />
</el-form-item>
<el-form-item label="物料信息" prop="name5">
<el-input v-model="formData.name5" placeholder="请输入物料信息" />
</el-form-item>
<el-form-item label="指定车辆" prop="name6">
<el-select v-model="formData.name6" placeholder="请选择指定车辆">
<el-option label="AGV01" :value="1" />
<el-option label="AGV02" :value="2" />
<el-option label="AGV03" :value="3" />
</el-select>
</el-form-item>
<el-form-item label="优先级" prop="name7">
<el-input v-model="formData.name7" placeholder="请输入优先级" />
</el-form-item>
<el-form-item label="其他信息" prop="name8">
<el-input v-model="formData.name8" rows="3" type="textarea" placeholder="请输入其他信息" />
</el-form-item>
<div class="task-tips">
<el-text class="mx-1">若需要发起拼接任务请点击前往</el-text>
<el-link type="primary" @click="taskManagement()">任务管理</el-link>
</div>
</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() //
const dialogVisible = ref(false) //
const formLoading = ref(false) // 12
const formData = ref({
name1: '',
name2: '',
name3: '',
name4: '',
name5: '',
name6: '',
name7: '',
name8: ''
})
const formRules = reactive({
name1: [{ required: true, message: '取货类型不能为空', trigger: 'blur' }],
name2: [{ required: true, message: '取货位置不能为空', trigger: 'blur' }],
name3: [{ required: true, message: '放货类型不能为空', trigger: 'blur' }],
name4: [{ required: true, message: '放货位置不能为空', trigger: 'blur' }]
})
const formRef = ref() // Ref
/** 打开弹窗 */
const open = async () => {
dialogVisible.value = true
resetForm()
}
defineExpose({ open }) // open
/** 提交表单 */
const emit = defineEmits(['success']) // success
const submitForm = async () => {
//
if (!formRef) return
const valid = await formRef.value.validate()
if (!valid) return
//
formLoading.value = true
try {
dialogVisible.value = false
//
emit('success')
} finally {
formLoading.value = false
}
}
//
const { push } = useRouter()
const taskManagement = () => {
push({ name: 'taskManagementCreateTask' })
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
name1: '',
name2: '',
name3: '',
name4: '',
name5: '',
name6: '',
name7: '',
name8: ''
}
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;
}
</style>

View File

@ -99,8 +99,8 @@ onMounted(() => {
display: flex;
align-items: center;
justify-content: center;
width: 100px;
height: 50px;
width: 90px;
height: 40px;
margin: 10px;
text-align: center;
border-radius: 4px;

View File

@ -1,36 +1,42 @@
<template>
<div class="">
<ContentWrap>
<div class="">
<!-- <div @click="downAgv">导出zip</div> -->
<!-- 首页 -->
<indexPage ref="indexPageRef" v-if="pageName === 'indexPage'"/>
<!-- 编辑地图 -->
<editMap ref="editMapRef" v-if="pageName === 'editMap'"/>
</div>
</ContentWrap>
</div>
<ContentWrap>
<el-button type="primary" @click="createTask">新建任务</el-button>
</ContentWrap>
<ContentWrap>
<!-- <div @click="downAgv">导出zip</div> -->
<!-- 首页 -->
<indexPage ref="indexPageRef" v-if="pageName === 'indexPage'" />
<!-- 编辑地图 -->
<editMap ref="editMapRef" v-if="pageName === 'editMap'" />
</ContentWrap>
<!-- 新建任务的弹窗 -->
<createTaskDialog ref="createTaskDialogRef" />
</template>
<script setup>
import editMap from './components/editMap.vue'
import indexPage from './components/indexPage.vue'
import createTaskDialog from './components/createTaskDialog.vue'
import { ref, defineComponent, reactive, nextTick, onMounted } from 'vue'
import * as MapApi from '@/api/map/map'
import download from '@/utils/download'
const editMapRef = ref(null)
const indexPageRef = ref(null)
const pageName = ref('indexPage')
defineOptions({ name: 'MapPageRealTimeMap' })
// {
// floor: 1,
// area: 'A'
// }
const downAgv = async () => {
const data = await MapApi.agvDownload()
download.zip(data, `agv-${new Date().getTime()}.zip`)
}
//
const createTaskDialogRef = ref()
const createTask = () => {
createTaskDialogRef.value.open()
}
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,204 @@
<template>
<div class="page">
<ContentWrap>
<div class="top-header">
<span class="title">发起任务</span>
<div>
<el-button :icon="RefreshRight">重置</el-button>
<el-button type="primary" :icon="Position">确认</el-button>
</div>
</div>
</ContentWrap>
<el-form :model="formData" label-width="145">
<el-card shadow="never">
<template #header>
<div class="card-header">
<span class="line"></span>
<span>任务基本信息</span>
</div>
</template>
<div>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item required label="任务号" prop="taskNo">
<el-input v-model="formData.taskNo" :disabled="true" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item required label="是否拼接任务" prop="montageTask">
<el-select v-model="formData.montageTask" placeholder="请选择">
<el-option label="不拼接" :value="0" />
<el-option label="拼接" :value="1" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item required label="任务拼接数量" prop="montageNumber">
<el-input-number v-model="formData.montageNumber" :min="0" :max="10" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item required label="搬空所选线库/区域" prop="doMoveAll">
<el-switch v-model="formData.doMoveAll" :active-value="1" :inactive-value="0" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item required label="任务循环" prop="doCycle">
<el-switch v-model="formData.doCycle" :active-value="1" :inactive-value="0" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item required label="循环次数" prop="cycleNumber">
<el-input-number v-model="formData.cycleNumber" :min="0" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="物料信息" prop="skuInfo">
<el-input v-model="formData.skuInfo" placeholder="请输入物料信息" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="优先级" prop="priority">
<el-input v-model="formData.priority" placeholder="请输入优先级" />
</el-form-item>
</el-col>
</el-row>
</div>
</el-card>
<el-card shadow="never" class="mt-4">
<template #header>
<div class="card-header">
<span class="line"></span>
<span>任务基本信息</span>
</div>
</template>
<div>
<!-- 仅放货 -->
<!-- 仅取货 -->
<!-- 充电 -->
<!-- 停车 -->
<!-- 移动 -->
<!-- 检测托盘类型 -->
</div>
</el-card>
</el-form>
</div>
</template>
<script setup lang="ts">
import { reactive } from 'vue'
import { RefreshRight, Position } from '@element-plus/icons-vue'
import * as MapTaskAPi from '@/api/map/mapTask'
defineOptions({ name: 'taskManagementCreateTask' })
const formData = reactive({
montageTask: 0, //01
montageNumber: 0, //
taskDetailList: [
{
releaseType: 1, // 12线 3
takeType: 1, //12线 3
releaseId: undefined, ///线/
takeId: undefined, ///线/
robotNo: undefined, //AGV
needLock: 0, //(0:1:)
electricity: undefined //()
}
], //
skuInfo: undefined, //
skuBatch: undefined, //
skuNumber: undefined, //
priority: undefined, //
otherMsg: undefined, //
doCycle: 0, //(0:1)
doMoveAll: 0, //线/(0:1)
cycleNumber: 0, //
remainingCycleNumber: 1, //1
taskNo: undefined, //
taskStatus: 0, //(0:123)
taskStage: 0, //(0:12345)
startTime: 0, //
endTime: 0 //
})
//
const getTaskNo = async () => {
formData.taskNo = await MapTaskAPi.getTaskNo(1)
}
//
const getLocationList = async () => {
let data = await MapTaskAPi.getLocationByName({
type: 1, // 12线 3
locationNo: 1
})
console.log(data)
}
//
const getCanUseRobotList = async () => {
let data = await MapTaskAPi.getCanUseRobot()
console.log(data)
}
/** 初始化 **/
onMounted(() => {
getTaskNo()
getLocationList()
getCanUseRobotList()
})
</script>
<style lang="scss" scoped>
.card-header {
display: flex;
align-items: center;
.line {
display: block;
width: 4px;
height: 14px;
background: #0147eb;
margin-right: 8px;
}
}
.page {
.top-header {
display: flex;
align-items: center;
justify-content: space-between;
.title {
font-family:
PingFangSC,
PingFang SC;
font-weight: 500;
font-size: 16px;
color: #0d162a;
line-height: 25px;
text-align: center;
font-style: normal;
}
}
.list {
.item {
border: 1px solid #efefef;
margin: 20px 0;
padding: 24px;
}
}
}
</style>

View File

@ -0,0 +1,214 @@
<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="68px"
>
<el-form-item label="任务号" prop="taskNo">
<el-input
v-model="queryParams.taskNo"
placeholder="请输入任务ID"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="车辆编号" prop="carNum">
<el-select v-model="queryParams.carNum" class="!w-240px">
<el-option :value="1" label="1" />
<el-option :value="2" label="2" />
<el-option :value="3" label="3" />
</el-select>
</el-form-item>
<el-form-item label="任务状态" prop="taskStatus">
<!-- <el-select v-model="queryParams.taskStatus" class="!w-240px">
<el-option :value="0" label="未开始" />
<el-option :value="1" label="执行中" />
<el-option :value="2" label="已完成" />
<el-option :value="3" label="已取消" />
</el-select> -->
<el-select
v-model="queryParams.taskStatus"
class="!w-240px"
clearable
placeholder="请选择任务状态"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.ROBOT_TASK_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="任务阶段" prop="taskStage">
<!-- <el-select v-model="queryParams.taskStage" class="!w-240px">
<el-option :value="0" label="待执行" />
<el-option :value="1" label="前往取货" />
<el-option :value="2" label="取货中" />
<el-option :value="3" label="运输中" />
<el-option :value="4" label="放货中" />
<el-option :value="5" label="结束" />
</el-select> -->
<el-select
v-model="queryParams.taskStage"
class="!w-240px"
clearable
placeholder="请选择任务阶段"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.ROBOT_QUEST_PHASES)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</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-button type="primary" @click="openForm('create')" v-hasPermi="['crm:clue:create']">
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<!-- 列表 -->
<ContentWrap>
<el-table :data="list" border style="width: 100%" stripe>
<el-table-column type="expand" width="50">
<template #default="props">
<div class="family-table">
<el-table :data="props.row.family" border :span-method="objectSpanMethod">
<el-table-column label="指令" prop="name1" />
<el-table-column label="车辆编号" prop="name2" />
<el-table-column label="取货点" prop="name3" />
<el-table-column label="放货点" prop="name4" />
<el-table-column label="动作" prop="name5" />
<el-table-column label="状态" prop="name6" />
<el-table-column label="操作" />
</el-table>
</div>
</template>
</el-table-column>
<el-table-column label="任务号" prop="taskNo" align="center" />
<el-table-column label="车辆编号" prop="name2" align="center" />
<el-table-column
label="开始时间"
prop="startTime"
:formatter="dateFormatter"
align="center"
/>
<el-table-column label="结束时间" prop="endTime" :formatter="dateFormatter" align="center" />
<el-table-column label="任务状态" prop="taskStatus" align="center">
<template #default="scope">
<dict-tag :type="DICT_TYPE.ROBOT_TASK_STATUS" :value="scope.row.taskStatus" />
</template>
</el-table-column>
<el-table-column label="任务状态" prop="taskStage" align="center">
<template #default="scope">
<dict-tag :type="DICT_TYPE.ROBOT_QUEST_PHASES" :value="scope.row.taskStage" />
</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 { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import { TabsPaneContext } from 'element-plus'
import * as MapTaskAPi from '@/api/map/mapTask'
defineOptions({ name: 'taskManagementTaskList' })
const message = useMessage() //
const { t } = useI18n() //
const { push } = useRouter()
const loading = ref(true) //
const total = ref(0) //
const list = ref([]) //
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
taskNo: null,
carNum: null,
taskStatus: null,
taskStage: null
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
const activeName = ref('1') // tab
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
const data = await MapTaskAPi.getTaskPageList(queryParams)
list.value = data.list
total.value = data.total
} finally {
loading.value = false
}
}
const objectSpanMethod = ({ row, column, rowIndex, columnIndex }) => {
if (columnIndex === 6) {
if (rowIndex % 2 === 0) {
return {
rowspan: 2,
colspan: 1
}
} else {
return {
rowspan: 0,
colspan: 0
}
}
}
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
getList()
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields()
handleQuery()
}
/** 添加/修改操作 */
const formRef = ref()
const openForm = (id) => {}
/** 初始化 **/
onMounted(() => {
getList()
})
</script>
<style lang="scss" scoped>
.family-table {
margin: 10px 20px 10px 50px;
}
</style>