任务发起增加移动到点位 任务列表任务阶段增加状态

This commit is contained in:
yyy 2025-04-10 16:32:59 +08:00
parent 9c43785df0
commit a4d9cb8e7d
5 changed files with 656 additions and 143 deletions

View File

@ -4,9 +4,9 @@ NODE_ENV=development
VITE_DEV=true
# 请求路径
# VITE_BASE_URL='http://192.168.0.74:48080'
VITE_BASE_URL='http://192.168.0.74:48080'
# VITE_BASE_URL='http://192.168.0.153:48080'
VITE_BASE_URL='http://192.168.0.45:48080'
# VITE_BASE_URL='http://192.168.0.45:48080'
# 文件上传类型server - 后端上传, client - 前端直连上传,仅支持 S3 服务
VITE_UPLOAD_TYPE=server

View File

@ -47,7 +47,7 @@
<div style="text-align: right">
<el-button
size="small"
style="width: 64px; height: 30px; background: #00329f"
style="width: 4rem; height: 1.875rem; background: #00329f"
color="#00329F"
@click="moveFormSubmit()"
>确认</el-button
@ -67,7 +67,7 @@
<div style="text-align: right">
<el-button
size="small"
style="width: 64px; height: 30px; background: #00329f"
style="width: 4rem; height: 1.875rem; background: #00329f"
color="#00329F"
@click="rotationFormSubmit"
>确认</el-button
@ -80,7 +80,7 @@
placement="bottom"
trigger="click"
v-else-if="item.switchType === 'lineLibrary'"
:popper-style="{ padding: '0px' }"
:popper-style="{ padding: '0rem' }"
>
<template #reference>
<div
@ -120,7 +120,7 @@
placement="bottom"
trigger="click"
v-else-if="item.switchType === 'region'"
:popper-style="{ padding: '0px' }"
:popper-style="{ padding: '0rem' }"
>
<template #reference>
<div
@ -196,21 +196,21 @@
</el-select>
</el-form-item>
<el-form-item label="标记属性" v-if="state.markForm.markProperty">
<el-input v-model="state.markForm.markProperty" style="width: 240px" disabled />
<el-input v-model="state.markForm.markProperty" style="width: 15rem" disabled />
</el-form-item>
<el-form-item label="原节点" v-if="state.markForm.originalNode">
<el-input v-model="state.markForm.originalNode" style="width: 240px" disabled />
<el-input v-model="state.markForm.originalNode" style="width: 15rem" disabled />
</el-form-item>
<div style="text-align: right">
<el-button
size="small"
style="width: 64px; height: 30px; background: #efefef"
style="width: 4rem; height: 1.875rem; background: #efefef"
@click="markFormCancel()"
>取消</el-button
>
<el-button
size="small"
style="width: 64px; height: 30px; background: #00329f"
style="width: 4rem; height: 1.875rem; background: #00329f"
color="#00329F"
@click="markFormSubmit()"
>确认</el-button
@ -480,7 +480,7 @@
color: item.fontColor,
fontSize: item.fontSize + 'px',
fontFamily: item.fontFamily,
border: state.currentItemIndex === index ? '1px dashed #000' : 'none'
border: state.currentItemIndex === index ? '.0625rem dashed #000' : 'none'
}"
>
{{ item.text }}
@ -610,7 +610,7 @@
top: `${box.y}px`,
width: `${box.width}px`,
height: `${box.height}px`,
border: '2px dashed #007bff',
border: '.125rem dashed #007bff',
backgroundColor: 'rgba(0, 123, 255, 0.1)',
zIndex: 999
}"
@ -624,7 +624,7 @@
top: `${state.drawSelectionAreaBox.y}px`,
width: `${state.drawSelectionAreaBox.width}px`,
height: `${state.drawSelectionAreaBox.height}px`,
border: '2px dashed #007bff',
border: '.125rem dashed #007bff',
backgroundColor: 'rgba(0, 123, 255, 0.1)',
zIndex: 9999
}"
@ -787,8 +787,8 @@ const nodeStyle = (item, index) => {
verticalAlign: 'top',
width: item.locationWidePx + 'px',
height: item.locationDeepPx + 'px',
border: state.currentItemIndex === index ? '1px dashed #000' : 'none',
borderRadius: '3px'
border: state.currentItemIndex === index ? '.0625rem dashed #000' : 'none',
borderRadius: '.1875rem'
}
}
//sortNum
@ -887,11 +887,11 @@ const binLocationStyle = (item, index) => {
height: item.locationDeepPx + 'px',
border:
state.currentItemIndex === index
? '1px dashed #000'
? '.0625rem dashed #000'
: state.noLocationNumberList.includes(index)
? '1px dashed red'
? '.0625rem dashed red'
: (laneId && item.laneId === laneId) || (areaId && item.areaId === areaId)
? '1px dashed #ff6a00'
? '.0625rem dashed #ff6a00'
: 'none'
}
}
@ -2581,7 +2581,7 @@ const rangingLineStyle = computed(() => {
left: `${point1.x}px`,
top: `${point1.y}px`,
width: `${length}px`,
height: '2px',
height: '.125rem',
backgroundColor: 'red',
transform: `rotate(${angle}deg)`,
transformOrigin: '0 0'
@ -2612,9 +2612,9 @@ const rangingTextStyle = computed(() => {
top: `${midY}px`,
transform: `translate(-50%, -50%) rotate(${textRotation}deg)`,
backgroundColor: 'rgba(255, 255, 255, 0.8)',
padding: '2px',
borderRadius: '4px',
fontSize: '12px',
padding: '.125rem',
borderRadius: '.25rem',
fontSize: '.75rem',
color: 'black',
whiteSpace: 'nowrap', //
pointerEvents: 'none' //
@ -2628,8 +2628,8 @@ const getRangingPointStyle = (point) => ({
position: 'absolute',
left: `${point.x - 4}px`,
top: `${point.y - 4}px`,
width: '8px',
height: '8px',
width: '.5rem',
height: '.5rem',
backgroundColor: 'blue',
borderRadius: '50%'
})
@ -3231,7 +3231,7 @@ onUnmounted(() => {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 200px;
max-width: 12.5rem;
}
.edit-map-page {
@ -3240,14 +3240,14 @@ onUnmounted(() => {
width: 100%;
overflow: auto;
// height: 85vh;
height: calc(100vh - 140px);
height: calc(100vh - 8.75rem);
.map-bg {
background-size: contain;
background-repeat: no-repeat;
position: absolute;
// top: 18px;
// left: 18px;
// top: 1.125rem;
// left: 1.125rem;
top: 0;
left: 0;
@ -3260,15 +3260,15 @@ onUnmounted(() => {
}
.top-tool {
margin-bottom: 2px;
margin-bottom: 0.125rem;
.top-tool-list {
display: flex;
align-items: center;
text-align: center;
background-color: #fff;
padding: 0 12px;
height: 70px;
box-shadow: rgba(0, 0, 0, 0.06) 0px 2px 3px;
padding: 0 0.75rem;
height: 4.375rem;
box-shadow: rgba(0, 0, 0, 0.06) 0rem 0.125rem 0.1875rem;
.top-tool-item {
display: flex;
@ -3276,8 +3276,8 @@ onUnmounted(() => {
.tool-item {
cursor: pointer;
width: 50px;
height: 70px;
width: 3.125rem;
height: 4.375rem;
display: flex;
flex-direction: column;
align-items: center;
@ -3289,19 +3289,19 @@ onUnmounted(() => {
PingFangSC,
PingFang SC;
font-weight: 400;
font-size: 14px;
font-size: 0.875rem;
color: #0d162a;
line-height: 20px;
line-height: 1.25rem;
text-align: center;
font-style: normal;
margin-top: 4px;
margin-top: 0.25rem;
}
}
.line {
margin: 0 12px;
width: 1px;
height: 47px;
border: 1px solid #cccccc;
margin: 0 0.75rem;
width: 0.0625rem;
height: 2.9375rem;
border: 0.0625rem solid #cccccc;
}
}
}
@ -3309,23 +3309,23 @@ onUnmounted(() => {
.right-tool-list {
position: absolute;
right: 0;
top: 114px;
top: 7.125rem;
background-color: #fff;
z-index: 999;
text-align: center;
box-shadow: rgba(0, 0, 0, 0.05) 0px 0px 0px 1px;
box-shadow: rgba(0, 0, 0, 0.05) 0rem 0rem 0rem 0.0625rem;
.tool-item {
cursor: pointer;
padding: 10px;
padding: 0.625rem;
.name {
font-family:
PingFangSC,
PingFang SC;
font-weight: 400;
font-size: 14px;
font-size: 0.875rem;
color: #0d162a;
line-height: 20px;
line-height: 1.25rem;
text-align: center;
font-style: normal;
}
@ -3335,36 +3335,36 @@ onUnmounted(() => {
.input-box-class {
position: absolute;
border: 1px solid #00329f;
padding: 4px;
border: 0.0625rem solid #00329f;
padding: 0.25rem;
outline: none;
}
.selection-area-btn {
width: 80px;
margin-left: 4px;
width: 5rem;
margin-left: 0.25rem;
}
.grid-show {
// background: linear-gradient(-90deg, rgba(0, 0, 0, 0.1) 1px, transparent 1px),
// linear-gradient(rgba(0, 0, 0, 0.1) 1px, transparent 1px);
// background: linear-gradient(-90deg, rgba(0, 0, 0, 0.1) .0625rem, transparent .0625rem),
// linear-gradient(rgba(0, 0, 0, 0.1) .0625rem, transparent .0625rem);
// background-size:
// 20px 20px,
// 20px 20px;
// 1.25rem 1.25rem,
// 1.25rem 1.25rem;
background-image: repeating-linear-gradient(
to right,
rgba(0, 0, 0, 0.1),
rgba(0, 0, 0, 0.1) 1px,
transparent 1px,
transparent 50px
rgba(0, 0, 0, 0.1) 0.0625rem,
transparent 0.0625rem,
transparent 3.125rem
),
repeating-linear-gradient(
to bottom,
rgba(0, 0, 0, 0.1),
rgba(0, 0, 0, 0.1) 1px,
transparent 1px,
transparent 50px
rgba(0, 0, 0, 0.1) 0.0625rem,
transparent 0.0625rem,
transparent 3.125rem
);
}
@ -3387,7 +3387,7 @@ onUnmounted(() => {
.tool-active {
background: #ebf1ff;
border-bottom: 2px solid #1677ff;
border-bottom: 0.125rem solid #1677ff;
}
.right-tool-active {
@ -3401,41 +3401,41 @@ onUnmounted(() => {
flex-direction: column;
align-items: center;
width: 100%;
padding: 11px 0;
padding: 0.6875rem 0;
font-family:
PingFangSC,
PingFang SC;
font-weight: 400;
font-size: 14px;
font-size: 0.875rem;
color: #0d162a;
line-height: 20px;
line-height: 1.25rem;
text-align: left;
font-style: normal;
border-bottom: 1px solid #e9e9e9;
border-bottom: 0.0625rem solid #e9e9e9;
}
}
.sort-num {
position: absolute;
font-size: 12px;
font-size: 0.75rem;
user-select: none;
color: #000;
}
.sort-num-location {
position: absolute;
font-size: 12px;
font-size: 0.75rem;
user-select: none;
color: #000;
}
.actual-location {
position: fixed;
bottom: 10px;
right: 16px;
bottom: 0.625rem;
right: 1rem;
background-color: #f48924;
color: #fff;
padding: 6px;
border-radius: 2px;
font-size: 14px;
padding: 0.375rem;
border-radius: 0.125rem;
font-size: 0.875rem;
user-select: none;
}
</style>

View File

@ -1,68 +1,474 @@
<template>
<div>
<label for="width">宽度:</label>
<input v-model="width" type="number" id="width" />
<label for="height">高度:</label>
<input v-model="height" type="number" id="height" />
<div ref="scaleRef"></div>
<div class="fence-container">
<div class="svg-container" ref="svgContainer">
<svg
ref="fenceSvg"
@click="handleSvgClick"
@mousedown="startPan"
@mousemove="handleMouseMove"
@mouseup="endPan"
@mouseleave="endPan"
@wheel="handleWheel"
:viewBox="viewBox"
preserveAspectRatio="none"
>
<!-- 网格背景 -->
<pattern id="grid" width="20" height="20" patternUnits="userSpaceOnUse">
<path d="M 20 0 L 0 0 0 20" fill="none" stroke="#eee" stroke-width="0.5" />
</pattern>
<rect width="100%" height="100%" fill="url(#grid)" />
<!-- 围栏多边形 -->
<polygon
v-if="fencePoints.length > 2"
:points="fencePointsString"
fill="rgba(231, 76, 60, 0.2)"
stroke="#e74c3c"
stroke-width="2"
/>
<!-- 绘制中的线段 -->
<polyline
v-if="isDrawing && currentPoints.length > 0"
:points="currentPointsString"
fill="none"
stroke="#3498db"
stroke-width="2"
/>
<!-- 顶点标记 -->
<circle
v-for="(point, index) in allPoints"
:key="index"
:cx="point.x"
:cy="point.y"
r="3"
fill="#3498db"
@mousedown.stop="startDrag(index, $event)"
/>
<!-- 测试点 -->
<circle
v-if="testPoint"
:cx="testPoint.x"
:cy="testPoint.y"
r="5"
:fill="isInside ? '#2ecc71' : '#e74c3c'"
/>
<!-- 坐标显示 -->
<text x="10" y="20" font-size="12" fill="#333" v-if="cursorPosition">
X: {{ cursorPosition.x.toFixed(1) }}, Y: {{ cursorPosition.y.toFixed(1) }}
</text>
</svg>
</div>
<div class="controls">
<div class="control-group">
<h3>绘制控制</h3>
<button @click="startDrawing">开始绘制</button>
<button @click="stopDrawing">结束绘制</button>
<button @click="clearDrawing">清空</button>
<button @click="checkRandomPoint">检测随机点</button>
</div>
<div class="control-group">
<h3>视图控制</h3>
<button @click="zoomIn">放大</button>
<button @click="zoomOut">缩小</button>
<button @click="resetView">重置视图</button>
</div>
<div class="control-group">
<h3>数据管理</h3>
<button @click="saveFence">保存围栏</button>
<button @click="loadFence">加载围栏</button>
</div>
</div>
</div>
</template>
<script setup>
import { onMounted, ref, watch } from 'vue'
import * as d3 from 'd3'
import { ref, computed, onMounted, onUnmounted } from 'vue'
const width = ref(500)
const height = ref(300)
const scaleRef = ref(null)
const svgContainer = ref(null)
const fenceSvg = ref(null)
const isDrawing = ref(false)
const fencePoints = ref([])
const currentPoints = ref([])
const testPoint = ref(null)
const isInside = ref(false)
const draggingIndex = ref(null)
const initialPos = ref(null)
const viewBox = ref('0 0 1000 600')
const svgSize = ref({ width: 1000, height: 600 })
const isPanning = ref(false)
const panStart = ref({ x: 0, y: 0 })
const cursorPosition = ref(null)
const drawScalesWithContent = () => {
const margin = { top: 20, right: 20, bottom: 20, left: 40 }
const innerWidth = width.value - margin.left - margin.right
const innerHeight = height.value - margin.top - margin.bottom
//
const fencePointsString = computed(() => {
return fencePoints.value.map((p) => `${p.x},${p.y}`).join(' ')
})
const svg = d3
.select(scaleRef.value)
.html('')
.append('svg')
.attr('width', width.value)
.attr('height', height.value)
.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`)
const currentPointsString = computed(() => {
return currentPoints.value.map((p) => `${p.x},${p.y}`).join(' ')
})
//
const xScale = d3.scaleLinear().domain([0, 100]).range([0, innerWidth])
const allPoints = computed(() => {
return isDrawing.value ? [...fencePoints.value, ...currentPoints.value] : fencePoints.value
})
const xAxis = d3.axisTop(xScale)
//
onMounted(() => {
updateSvgSize()
window.addEventListener('resize', updateSvgSize)
})
svg.append('g').call(xAxis)
onUnmounted(() => {
window.removeEventListener('resize', updateSvgSize)
})
//
const yScale = d3.scaleLinear().domain([0, 100]).range([innerHeight, 0])
function updateSvgSize() {
const container = svgContainer.value
svgSize.value = {
width: container.clientWidth,
height: container.clientHeight
}
fenceSvg.value.setAttribute('viewBox', viewBox.value)
}
const yAxis = d3.axisLeft(yScale)
//
const startDrawing = () => {
fencePoints.value = []
currentPoints.value = []
isDrawing.value = true
testPoint.value = null
}
svg.append('g').call(yAxis)
const stopDrawing = () => {
if (currentPoints.value.length > 0) {
fencePoints.value = [...fencePoints.value, ...currentPoints.value]
currentPoints.value = []
}
//
const numCircles = 10
for (let i = 0; i < numCircles; i++) {
const x = Math.random() * innerWidth
const y = Math.random() * innerHeight
const radius = Math.random() * 10 + 5
svg.append('circle').attr('cx', x).attr('cy', y).attr('r', radius).attr('fill', 'blue')
if (fencePoints.value.length > 2) {
//
if (
fencePoints.value[0].x !== fencePoints.value[fencePoints.value.length - 1].x ||
fencePoints.value[0].y !== fencePoints.value[fencePoints.value.length - 1].y
) {
fencePoints.value.push({ ...fencePoints.value[0] })
}
}
isDrawing.value = false
}
const clearDrawing = () => {
fencePoints.value = []
currentPoints.value = []
isDrawing.value = false
testPoint.value = null
}
const handleSvgClick = (e) => {
if (!isDrawing.value || isPanning.value) return
const svg = fenceSvg.value
const pt = svg.createSVGPoint()
pt.x = e.clientX
pt.y = e.clientY
const cursorPt = pt.matrixTransform(svg.getScreenCTM().inverse())
currentPoints.value.push({
x: cursorPt.x,
y: cursorPt.y
})
}
//
const checkRandomPoint = () => {
if (fencePoints.value.length < 3) {
alert('请先绘制电子围栏')
return
}
const [vbX, vbY, vbWidth, vbHeight] = viewBox.value.split(' ').map(Number)
testPoint.value = {
x: vbX + Math.random() * vbWidth,
y: vbY + Math.random() * vbHeight
}
isInside.value = pointInPolygon(testPoint.value, fencePoints.value)
}
function pointInPolygon(point, polygon) {
const x = point.x
const y = point.y
let inside = false
for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
const xi = polygon[i].x
const yi = polygon[i].y
const xj = polygon[j].x
const yj = polygon[j].y
const intersect = yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi
if (intersect) inside = !inside
}
return inside
}
//
const startDrag = (index, e) => {
e.preventDefault()
draggingIndex.value = index
const svg = fenceSvg.value
const pt = svg.createSVGPoint()
pt.x = e.clientX
pt.y = e.clientY
const cursorPt = pt.matrixTransform(svg.getScreenCTM().inverse())
initialPos.value = {
x: cursorPt.x,
y: cursorPt.y,
index
}
document.addEventListener('mousemove', handleDrag)
document.addEventListener('mouseup', stopDrag)
}
const handleDrag = (e) => {
if (draggingIndex.value === null) return
const svg = fenceSvg.value
const pt = svg.createSVGPoint()
pt.x = e.clientX
pt.y = e.clientY
const cursorPt = pt.matrixTransform(svg.getScreenCTM().inverse())
const points =
isDrawing.value && draggingIndex.value >= fencePoints.value.length
? currentPoints.value
: fencePoints.value
const actualIndex =
isDrawing.value && draggingIndex.value >= fencePoints.value.length
? draggingIndex.value - fencePoints.value.length
: draggingIndex.value
points[actualIndex] = {
x: cursorPt.x,
y: cursorPt.y
}
//
if (
!isDrawing.value &&
fencePoints.value.length > 0 &&
draggingIndex.value === fencePoints.value.length - 1
) {
fencePoints.value[0] = { ...fencePoints.value[fencePoints.value.length - 1] }
}
}
onMounted(() => {
drawScalesWithContent()
})
const stopDrag = () => {
draggingIndex.value = null
initialPos.value = null
document.removeEventListener('mousemove', handleDrag)
document.removeEventListener('mouseup', stopDrag)
}
watch([width, height], () => {
drawScalesWithContent()
})
//
const handleWheel = (e) => {
e.preventDefault()
const delta = e.deltaY > 0 ? 0.9 : 1.1
zoomAt(e.clientX, e.clientY, delta)
}
function zoomAt(clientX, clientY, factor) {
const container = svgContainer.value
const rect = container.getBoundingClientRect()
const x = ((clientX - rect.left) / rect.width) * svgSize.value.width
const y = ((clientY - rect.top) / rect.height) * svgSize.value.height
const [vbX, vbY, vbWidth, vbHeight] = viewBox.value.split(' ').map(Number)
const newWidth = vbWidth * factor
const newHeight = vbHeight * factor
const newX = vbX + (x - vbX) * (1 - factor)
const newY = vbY + (y - vbY) * (1 - factor)
//
if (newWidth > svgSize.value.width * 10 || newWidth < svgSize.value.width / 10) return
viewBox.value = `${newX} ${newY} ${newWidth} ${newHeight}`
fenceSvg.value.setAttribute('viewBox', viewBox.value)
}
const zoomIn = () => {
const container = svgContainer.value
const rect = container.getBoundingClientRect()
zoomAt(rect.left + rect.width / 2, rect.top + rect.height / 2, 1.2)
}
const zoomOut = () => {
const container = svgContainer.value
const rect = container.getBoundingClientRect()
zoomAt(rect.left + rect.width / 2, rect.top + rect.height / 2, 0.8)
}
const resetView = () => {
viewBox.value = `0 0 ${svgSize.value.width} ${svgSize.value.height}`
fenceSvg.value.setAttribute('viewBox', viewBox.value)
}
const startPan = (e) => {
if (draggingIndex.value !== null) return
isPanning.value = true
panStart.value = {
x: e.clientX,
y: e.clientY
}
fenceSvg.value.style.cursor = 'grabbing'
}
const handlePan = (e) => {
if (!isPanning.value) return
const [vbX, vbY, vbWidth, vbHeight] = viewBox.value.split(' ').map(Number)
const dx = ((e.clientX - panStart.value.x) / svgSize.value.width) * vbWidth
const dy = ((e.clientY - panStart.value.y) / svgSize.value.height) * vbHeight
viewBox.value = `${vbX - dx} ${vbY - dy} ${vbWidth} ${vbHeight}`
fenceSvg.value.setAttribute('viewBox', viewBox.value)
panStart.value = {
x: e.clientX,
y: e.clientY
}
}
const endPan = () => {
isPanning.value = false
fenceSvg.value.style.cursor = 'crosshair'
}
//
const handleMouseMove = (e) => {
const svg = fenceSvg.value
const pt = svg.createSVGPoint()
pt.x = e.clientX
pt.y = e.clientY
const cursorPt = pt.matrixTransform(svg.getScreenCTM().inverse())
cursorPosition.value = {
x: cursorPt.x,
y: cursorPt.y
}
}
//
const saveFence = () => {
if (fencePoints.value.length < 3) {
alert('请先绘制有效的电子围栏')
return
}
const data = {
points: fencePoints.value,
viewBox: viewBox.value,
svgSize: svgSize.value
}
localStorage.setItem('fenceData', JSON.stringify(data))
alert('围栏已保存')
}
const loadFence = () => {
const data = localStorage.getItem('fenceData')
if (data) {
try {
const parsed = JSON.parse(data)
fencePoints.value = parsed.points
viewBox.value = parsed.viewBox || `0 0 ${svgSize.value.width} ${svgSize.value.height}`
svgSize.value = parsed.svgSize || { width: 1000, height: 600 }
fenceSvg.value.setAttribute('viewBox', viewBox.value)
alert('围栏已加载')
} catch (e) {
alert('加载围栏数据失败')
}
} else {
alert('没有找到保存的围栏数据')
}
}
</script>
<style scoped>
/* 可根据需要添加样式 */
.fence-container {
display: flex;
flex-direction: column;
height: 100vh;
}
.svg-container {
flex: 1;
position: relative;
border: 1px solid #ccc;
background: #f9f9f9;
overflow: hidden;
}
svg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
cursor: crosshair;
}
svg.panning {
cursor: grabbing;
}
.controls {
padding: 10px;
background: #f5f5f5;
display: flex;
gap: 20px;
}
.control-group {
display: flex;
flex-direction: column;
gap: 5px;
}
.control-group h3 {
margin: 0 0 5px 0;
font-size: 14px;
color: #333;
}
button {
padding: 8px 12px;
background: #3498db;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
}
button:hover {
background: #2980b9;
}
circle {
cursor: move;
}
</style>

View File

@ -604,6 +604,62 @@
</el-col>
</el-row>
</div>
<!-- 移动到点位 -->
<div v-if="detailItem.taskType === 9">
<el-row :gutter="24">
<el-col :span="12">
<el-form-item
required
label="车辆编号"
:prop="`taskDetailList[${index}].robotNo`"
:rules="{ required: true, message: '车辆不能为空', trigger: 'change' }"
>
<el-select
v-model="detailItem.robotNo"
placeholder="请选择车辆"
@change="chooseCarErrorMsg"
>
<el-option
v-for="car in robotList"
:key="car.id"
:label="car.robotList"
:value="car.robotNo"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
required
label="终点点位"
:prop="`taskDetailList[${index}].releaseId`"
:rules="{ required: true, message: '终点点位不能为空', trigger: 'change' }"
>
<el-select
:disabled="!detailItem.takeType"
v-model="detailItem.releaseId"
filterable
remote
reserve-keyword
placeholder="请输入终点点位"
:remote-method="
(query) => {
endPointMethod(query, detailItem)
}
"
:loading="loading"
>
<el-option
v-for="item in detailItem.endPointList"
:key="item.id"
:label="item.locationNo"
:value="item.id"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
</div>
<!-- 扫描码 -->
<!-- <div v-if="detailItem.taskType === 7">
<el-row :gutter="24">
@ -755,7 +811,8 @@ const formData = ref({
{ label: '充电', value: 3 },
{ label: '移动', value: 4 },
{ label: '仅取货', value: 5 },
{ label: '仅放货', value: 6 }
{ label: '仅放货', value: 6 },
{ label: '移动到点位', value: 9 }
]
}
], //
@ -783,7 +840,7 @@ const resetFormData = () => {
taskDetailList: [
{
taskType: 1, //12 345678
releaseType: 1, // 12线 3
releaseType: 1, // 12线 3 4
takeType: 1, //12线 3
releaseId: undefined, //id
releaseList: [], //
@ -798,7 +855,8 @@ const resetFormData = () => {
{ label: '充电', value: 3 },
{ label: '移动', value: 4 },
{ label: '仅取货', value: 5 },
{ label: '仅放货', value: 6 }
{ label: '仅放货', value: 6 },
{ label: '移动到点位', value: 9 }
]
}
], //
@ -850,6 +908,14 @@ const takeRemoteMethod = async (query, item) => {
item.takeList = []
}
}
//
const endPointMethod = async (query, item) => {
if (query) {
item.endPointList = await getLocationList(4, query)
} else {
item.endPointList = []
}
}
//
const robotList = ref([])
@ -898,14 +964,16 @@ const taskTypeChange = (item, index) => {
if (formData.value.doCycle === 1) {
nextItem.taskTypeList = [
{ label: '取放货', value: 1 },
{ label: '移动', value: 4 }
{ label: '移动', value: 4 },
{ label: '移动到点位', value: 9 }
]
} else {
if (item.taskType === 1) {
nextItem.taskTypeList = [
{ label: '取放货', value: 1 },
{ label: '移动', value: 4 },
{ label: '仅取货', value: 5 }
{ label: '仅取货', value: 5 },
{ label: '移动到点位', value: 9 }
]
} else if (item.taskType === 2) {
formData.value.taskDetailList = formData.value.taskDetailList.slice(0, index + 1)
@ -917,18 +985,21 @@ const taskTypeChange = (item, index) => {
nextItem.taskTypeList = [
{ label: '取放货', value: 1 },
{ label: '移动', value: 4 },
{ label: '仅取货', value: 5 }
{ label: '仅取货', value: 5 },
{ label: '移动到点位', value: 9 }
]
} else if (item.taskType === 5) {
nextItem.taskTypeList = [
{ label: '移动', value: 4 },
{ label: '仅放货', value: 6 }
{ label: '仅放货', value: 6 },
{ label: '移动到点位', value: 9 }
]
} else if (item.taskType === 6) {
nextItem.taskTypeList = [
{ label: '取放货', value: 1 },
{ label: '移动', value: 4 },
{ label: '仅取货', value: 5 }
{ label: '仅取货', value: 5 },
{ label: '移动到点位', value: 9 }
]
}
}
@ -951,7 +1022,8 @@ const montageNumberChange = (currentValue: number, oldValue: number) => {
if (formData.value.doCycle === 1) {
taskTypeList = [
{ label: '取放货', value: 1 },
{ label: '移动', value: 4 }
{ label: '移动', value: 4 },
{ label: '移动到点位', value: 9 }
]
} else {
if (oldItem) {
@ -959,24 +1031,28 @@ const montageNumberChange = (currentValue: number, oldValue: number) => {
taskTypeList = [
{ label: '取放货', value: 1 },
{ label: '移动', value: 4 },
{ label: '仅取货', value: 5 }
{ label: '仅取货', value: 5 },
{ label: '移动到点位', value: 9 }
]
} else if (oldItem.taskType === 4) {
taskTypeList = [
{ label: '取放货', value: 1 },
{ label: '移动', value: 4 },
{ label: '仅取货', value: 5 }
{ label: '仅取货', value: 5 },
{ label: '移动到点位', value: 9 }
]
} else if (oldItem.taskType === 5) {
taskTypeList = [
{ label: '移动', value: 4 },
{ label: '仅放货', value: 6 }
{ label: '仅放货', value: 6 },
{ label: '移动到点位', value: 9 }
]
} else if (oldItem.taskType === 6) {
taskTypeList = [
{ label: '取放货', value: 1 },
{ label: '移动', value: 4 },
{ label: '仅取货', value: 5 }
{ label: '仅取货', value: 5 },
{ label: '移动到点位', value: 9 }
]
}
} else {
@ -986,7 +1062,8 @@ const montageNumberChange = (currentValue: number, oldValue: number) => {
{ label: '充电', value: 3 },
{ label: '移动', value: 4 },
{ label: '仅取货', value: 5 },
{ label: '仅放货', value: 6 }
{ label: '仅放货', value: 6 },
{ label: '移动到点位', value: 9 }
]
}
}
@ -1029,7 +1106,8 @@ const doMoveAllChange = (e) => {
formData.value.taskDetailList.forEach((item, index) => {
item.taskTypeList = [
{ label: '取放货', value: 1 },
{ label: '移动', value: 4 }
{ label: '移动', value: 4 },
{ label: '移动到点位', value: 9 }
]
})
} else {
@ -1042,7 +1120,8 @@ const doMoveAllChange = (e) => {
{ label: '充电', value: 3 },
{ label: '移动', value: 4 },
{ label: '仅取货', value: 5 },
{ label: '仅放货', value: 6 }
{ label: '仅放货', value: 6 },
{ label: '移动到点位', value: 9 }
]
} else {
item.taskTypeList = []
@ -1092,7 +1171,8 @@ const doCycleChange = () => {
{ label: '充电', value: 3 },
{ label: '移动', value: 4 },
{ label: '仅取货', value: 5 },
{ label: '仅放货', value: 6 }
{ label: '仅放货', value: 6 },
{ label: '移动到点位', value: 9 }
]
} else {
item.taskTypeList = []
@ -1116,7 +1196,8 @@ const doCycleChange = () => {
} else {
item.taskTypeList = [
{ label: '取放货', value: 1 },
{ label: '移动', value: 4 }
{ label: '移动', value: 4 },
{ label: '移动到点位', value: 9 }
]
}
})
@ -1166,6 +1247,7 @@ const submitForm = async () => {
formData.value.taskDetailList.forEach((item) => {
delete item.releaseList
delete item.takeList
delete item.endPointList
})
await MapTaskAPi.createTask(formData.value)
message.success(t('common.createSuccess'))

View File

@ -51,12 +51,17 @@
placeholder="请选择任务阶段"
@change="handleQuery()"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.ROBOT_QUEST_PHASES)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
<el-option label="待执行" :value="0" />
<el-option label="前往取货" :value="1" />
<el-option label="取货中" :value="2" />
<el-option label="前往放货" :value="3" />
<el-option label="放货中" :value="4" />
<el-option label="完成" :value="5" />
<el-option label="移动中" :value="6" />
<el-option label="正在充电" :value="7" />
<el-option label="取消" :value="8" />
<el-option label="人工完成" :value="9" />
<el-option label="异常" :value="10" />
</el-select>
</el-form-item>
<el-form-item>
@ -117,13 +122,13 @@
</div>
<div class="task-stage" v-else-if="scope.row.taskStage == 3">
<div class="icon-dot"> </div>
<el-text class="mx-1">运输中</el-text>
<el-text class="mx-1">前往放货</el-text>
</div>
<div class="task-stage" v-else-if="scope.row.taskStage == 4">
<div class="icon-dot"> </div>
<el-text class="mx-1">放货中</el-text>
</div>
<div class="task-stage" v-else>
<div class="task-stage" v-else-if="scope.row.taskStage == 5">
<div
class="icon-dot"
style="background-color: #4dc606; border: 0.0625rem solid #4dc606"
@ -131,6 +136,26 @@
</div>
<el-text class="mx-1">已完成</el-text>
</div>
<div class="task-stage" v-else-if="scope.row.taskStage == 6">
<div class="icon-dot"> </div>
<el-text class="mx-1">移动中</el-text>
</div>
<div class="task-stage" v-else-if="scope.row.taskStage == 7">
<div class="icon-dot"> </div>
<el-text class="mx-1">正在充电</el-text>
</div>
<div class="task-stage" v-else-if="scope.row.taskStage == 8">
<div class="icon-dot"> </div>
<el-text class="mx-1">取消</el-text>
</div>
<div class="task-stage" v-else-if="scope.row.taskStage == 9">
<div class="icon-dot"> </div>
<el-text class="mx-1">人工完成</el-text>
</div>
<div class="task-stage" v-else-if="scope.row.taskStage == 10">
<div class="icon-dot"> </div>
<el-text class="mx-1">异常</el-text>
</div>
</template>
</el-table-column>
<el-table-column align="center" label="操作" width="270">