451 lines
15 KiB
Vue
451 lines
15 KiB
Vue
<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 required label="任务号" prop="taskNo">
|
||
<el-input v-model="formData.taskNo" :disabled="true" />
|
||
</el-form-item>
|
||
<el-form-item label="取货类型" prop="taskDetailList[0].takeType" required>
|
||
<el-select
|
||
v-model="formData.taskDetailList[0].takeType"
|
||
placeholder="请选择取货类型"
|
||
required
|
||
@change="takeTypeChange"
|
||
>
|
||
<el-option label="库位" :value="1" />
|
||
<el-option label="线库" :value="2" />
|
||
<el-option label="区域" :value="3" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item required label="取货位置" prop="taskDetailList[0].takeId">
|
||
<div style="width: 100%; display: flex; align-items: center">
|
||
<el-select
|
||
style="width: 100%"
|
||
:disabled="!formData.taskDetailList[0].takeType"
|
||
v-model="formData.taskDetailList[0].takeId"
|
||
filterable
|
||
remote
|
||
reserve-keyword
|
||
placeholder="请输入取货位置"
|
||
:remote-method="
|
||
(query) => {
|
||
takeRemoteMethod(query, formData.taskDetailList[0])
|
||
}
|
||
"
|
||
:loading="loading"
|
||
>
|
||
<el-option
|
||
v-for="item in formData.taskDetailList[0].takeList"
|
||
:key="item.id"
|
||
:label="item.locationNo"
|
||
:value="item.id"
|
||
/>
|
||
<template #loading>
|
||
<svg class="circular" viewBox="0 0 50 50">
|
||
<circle class="path" cx="25" cy="25" r="20" fill="none" />
|
||
</svg>
|
||
</template>
|
||
</el-select>
|
||
<el-icon class="ml-2" size="20" color="#00329F" @click="chooseLocation('take')"
|
||
><Location
|
||
/></el-icon>
|
||
</div>
|
||
</el-form-item>
|
||
<el-form-item label="放货类型" prop="taskDetailList[0].releaseType" required>
|
||
<el-select
|
||
v-model="formData.taskDetailList[0].releaseType"
|
||
placeholder="请选择放货类型"
|
||
@change="releaseTypeChange"
|
||
>
|
||
<el-option label="库位" :value="1" />
|
||
<el-option label="线库" :value="2" />
|
||
<el-option label="区域" :value="3" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item required label="放货位置" prop="taskDetailList[0].releaseId">
|
||
<div style="width: 100%; display: flex; align-items: center">
|
||
<el-select
|
||
:disabled="!formData.taskDetailList[0].releaseType"
|
||
v-model="formData.taskDetailList[0].releaseId"
|
||
filterable
|
||
remote
|
||
reserve-keyword
|
||
placeholder="请输入放货位置"
|
||
:remote-method="
|
||
(query) => {
|
||
releaseRemoteMethod(query, formData.taskDetailList[0])
|
||
}
|
||
"
|
||
:loading="loading"
|
||
>
|
||
<el-option
|
||
v-for="item in formData.taskDetailList[0].releaseList"
|
||
:key="item.id"
|
||
:label="item.locationNo"
|
||
:value="item.id"
|
||
/>
|
||
<template #loading>
|
||
<svg class="circular" viewBox="0 0 50 50">
|
||
<circle class="path" cx="25" cy="25" r="20" fill="none" />
|
||
</svg>
|
||
</template>
|
||
</el-select>
|
||
<el-icon class="ml-2" size="20" color="#00329F" @click="chooseLocation('release')"
|
||
><Location
|
||
/></el-icon>
|
||
</div>
|
||
</el-form-item>
|
||
<el-form-item label="指定车辆" prop="robotNo">
|
||
<el-select v-model="formData.robotNo" placeholder="请选择车辆">
|
||
<el-option
|
||
v-for="car in robotList"
|
||
:key="car.id"
|
||
:label="car.robotNo"
|
||
:value="car.robotNo"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="优先级" prop="priority">
|
||
<el-input-number
|
||
placeholder="优先级范围为1-100"
|
||
v-model="formData.priority"
|
||
:min="1"
|
||
:max="100"
|
||
class="!w-220px"
|
||
/>
|
||
</el-form-item>
|
||
<el-form-item label="物料信息" prop="skuInfo">
|
||
<el-input
|
||
v-model="formData.skuInfo"
|
||
placeholder="请输入物料信息"
|
||
maxlength="30"
|
||
show-word-limit
|
||
/>
|
||
</el-form-item>
|
||
<el-form-item label="其他信息" prop="otherMsg">
|
||
<el-input
|
||
v-model="formData.otherMsg"
|
||
rows="3"
|
||
type="textarea"
|
||
placeholder="请输入其他信息"
|
||
maxlength="100"
|
||
show-word-limit
|
||
/>
|
||
</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>
|
||
<!-- 选择库位的弹窗 -->
|
||
<locationSelectionDialog
|
||
:positionMapId="positionMapId"
|
||
ref="locationSelectionDialogRef"
|
||
@locationSelectionDialogSuccess="locationSelectionDialogSuccess"
|
||
/>
|
||
</template>
|
||
<script lang="ts" setup>
|
||
const { t } = useI18n() // 国际化
|
||
const message = useMessage() // 消息弹窗
|
||
import * as MapTaskAPi from '@/api/map/mapTask'
|
||
import locationSelectionDialog from '../../components/locationSelectionDialog.vue'
|
||
|
||
const props = defineProps({
|
||
positionMapId: {
|
||
type: String,
|
||
default: () => ''
|
||
}
|
||
})
|
||
|
||
const dialogVisible = ref(false) // 弹窗的是否展示
|
||
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
|
||
|
||
const formData = ref({
|
||
montageTask: 0, //是否拼接任务(0:不拼接、1:拼接)
|
||
montageNumber: 1, // 拼接任务数量
|
||
taskDetailList: [
|
||
{
|
||
taskType: 1, //任务类型(1:取放货、2:停车、 3:充电、4:移动、5:仅取货、6:仅放货、7:扫描码、8:检测托盘类型)
|
||
releaseType: 1, //放货类型 1:库位、2:线库、 3:区域
|
||
takeType: 1, //取货类型(1:库位、2:线库、 3:区域)
|
||
releaseId: undefined, //放货位置的id
|
||
releaseList: [], //放货的名称的列表
|
||
takeId: undefined, //取货位置的id
|
||
takeList: [], //取货位置的名称列表
|
||
robotNo: undefined, //车辆编号
|
||
needLock: 0, //停车后锁定(0:否、1:是)
|
||
electricity: undefined //所选车辆电量(充电模式)
|
||
}
|
||
], //任务列表
|
||
skuInfo: undefined, //物料信息
|
||
skuBatch: undefined, // 物料批次号
|
||
skuNumber: undefined, // 物料数量
|
||
priority: 50, // 优先级
|
||
otherMsg: undefined, // 其他信息
|
||
doCycle: 0, //循环(0:不循环、1:循环)
|
||
doMoveAll: 0, //是否搬空所选线库/区域(0:不搬空、1:搬空)
|
||
cycleNumber: 0, // 其他信息
|
||
remainingCycleNumber: 1, //剩余循环次数,默认1
|
||
taskNo: undefined, // 任务号
|
||
taskStatus: 0, //任务状态(0:未开始、1:执行中、2:已完成、3:已取消)
|
||
taskStage: 0, //任务阶段(0:待执行、1:前往取货、2:取货中、3:运输中、4:放货中、5:结束)
|
||
startTime: 0, //开始时间
|
||
endTime: 0 //结束时间
|
||
})
|
||
const formRules = reactive({
|
||
taskNo: [{ required: true, message: '任务号不能为空', trigger: 'change' }],
|
||
'taskDetailList[0].takeType': [
|
||
{ required: true, message: '取货类型不能为空', trigger: 'change' }
|
||
],
|
||
'taskDetailList[0].takeId': [{ required: true, message: '取货位置不能为空', trigger: 'change' }],
|
||
'taskDetailList[0].releaseType': [
|
||
{ required: true, message: '放货类型不能为空', trigger: 'change' }
|
||
],
|
||
'taskDetailList[0].releaseId': [
|
||
{ required: true, message: '放货位置不能为空', trigger: 'change' }
|
||
]
|
||
})
|
||
const formRef = ref() // 表单 Ref
|
||
|
||
/** 打开弹窗 */
|
||
const open = async () => {
|
||
dialogVisible.value = true
|
||
resetForm()
|
||
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
|
||
// 提交请求
|
||
formLoading.value = true
|
||
try {
|
||
await MapTaskAPi.createTask(formData.value)
|
||
message.success(t('common.createSuccess'))
|
||
dialogVisible.value = false
|
||
push({ name: 'taskManagementTaskList' })
|
||
} 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, // 放货类型(1:库位、2:线库、 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 releaseTypeChange = () => {
|
||
formData.value.taskDetailList[0].releaseId = undefined
|
||
}
|
||
|
||
//取货
|
||
const takeTypeChange = () => {
|
||
formData.value.taskDetailList[0].takeId = undefined
|
||
}
|
||
|
||
//选择库位
|
||
const locationSelectionDialogRef = ref()
|
||
const chooseLocationType = ref('') //放货还是取货
|
||
const locationTypeNumber = ref(1) //1库位 2线库 3区域
|
||
|
||
const chooseLocation = (type) => {
|
||
chooseLocationType.value = type
|
||
if (type == 'take') {
|
||
//取货
|
||
locationTypeNumber.value = formData.value.taskDetailList[0].takeType
|
||
} else {
|
||
//放货
|
||
locationTypeNumber.value = formData.value.taskDetailList[0].releaseType
|
||
}
|
||
locationSelectionDialogRef.value.open(locationTypeNumber.value, type)
|
||
}
|
||
//成功选择库位
|
||
const locationSelectionDialogSuccess = (item) => {
|
||
if (chooseLocationType.value == 'take') {
|
||
//取货
|
||
if (locationTypeNumber.value == 1) {
|
||
// 1库位
|
||
takeRemoteMethod(item.locationNo, formData.value.taskDetailList[0])
|
||
formData.value.taskDetailList[0].takeId = item.id
|
||
} else if (locationTypeNumber.value == 2) {
|
||
// 2线库
|
||
takeRemoteMethod(item.laneName, formData.value.taskDetailList[0])
|
||
formData.value.taskDetailList[0].takeId = item.laneId
|
||
} else {
|
||
// 3区域
|
||
takeRemoteMethod(item.areaName, formData.value.taskDetailList[0])
|
||
formData.value.taskDetailList[0].takeId = item.areaId
|
||
}
|
||
} else if (chooseLocationType.value == 'release') {
|
||
//放货
|
||
if (locationTypeNumber.value == 1) {
|
||
// 1库位
|
||
releaseRemoteMethod(item.locationNo, formData.value.taskDetailList[0])
|
||
formData.value.taskDetailList[0].releaseId = item.id
|
||
} else if (locationTypeNumber.value == 2) {
|
||
// 2线库
|
||
releaseRemoteMethod(item.laneName, formData.value.taskDetailList[0])
|
||
formData.value.taskDetailList[0].releaseId = item.laneId
|
||
} else {
|
||
// 3区域
|
||
releaseRemoteMethod(item.areaName, formData.value.taskDetailList[0])
|
||
formData.value.taskDetailList[0].releaseId = item.areaId
|
||
}
|
||
}
|
||
}
|
||
|
||
/** 重置表单 */
|
||
const resetForm = () => {
|
||
formData.value = {
|
||
montageTask: 0, //是否拼接任务(0:不拼接、1:拼接)
|
||
montageNumber: 0, // 拼接任务数量
|
||
taskDetailList: [
|
||
{
|
||
taskType: 1, //任务类型(1:取放货、2:停车、 3:充电、4:移动、5:仅取货、6:仅放货、7:扫描码、8:检测托盘类型)
|
||
releaseType: 1, //放货类型 1:库位、2:线库、 3:区域
|
||
takeType: 1, //取货类型(1:库位、2:线库、 3:区域)
|
||
releaseId: undefined, //放货位置的id
|
||
releaseList: [], //放货的名称的列表
|
||
takeId: undefined, //取货位置的id
|
||
takeList: [], //取货位置的名称列表
|
||
robotNo: undefined, //车辆编号
|
||
needLock: 0, //停车后锁定(0:否、1:是)
|
||
electricity: undefined //所选车辆电量(充电模式)
|
||
}
|
||
], //任务列表
|
||
skuInfo: undefined, //物料信息
|
||
skuBatch: undefined, // 物料批次号
|
||
skuNumber: undefined, // 物料数量
|
||
priority: 50, // 优先级
|
||
otherMsg: undefined, // 其他信息
|
||
doCycle: 0, //循环(0:不循环、1:循环)
|
||
doMoveAll: 0, //是否搬空所选线库/区域(0:不搬空、1:搬空)
|
||
cycleNumber: 0, // 其他信息
|
||
remainingCycleNumber: 1, //剩余循环次数,默认1
|
||
taskNo: undefined, // 任务号
|
||
taskStatus: 0, //任务状态(0:未开始、1:执行中、2:已完成、3:已取消)
|
||
taskStage: 0, //任务阶段(0:待执行、1:前往取货、2:取货中、3:运输中、4:放货中、5:结束)
|
||
startTime: 0, //开始时间
|
||
endTime: 0 //结束时间
|
||
}
|
||
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>
|