批量复制改为弧度和距离复制

图例增加曲线隐藏
This commit is contained in:
yyy 2025-06-25 16:55:11 +08:00
parent 24dde0807c
commit b1fbcb09f2
4 changed files with 105 additions and 91 deletions

View File

@ -8,25 +8,27 @@
@close="dialogClose"
>
<el-form :model="batchCopyingForm" label-width="120" ref="BatchCopyingFormRef" :rules="rules">
<el-form-item label="X轴偏移量(实际点位)" prop="x" required>
<el-form-item label="方向(弧度)" prop="radian" required>
<el-input-number
v-model="batchCopyingForm.x"
placeholder="请输入"
v-model="batchCopyingForm.radian"
placeholder="请输入弧度"
controls-position="right"
style="width: 100%"
precision="2"
:min="-Math.PI"
:max="Math.PI"
:step="0.01"
precision="4"
/>
<el-text type="info" size="small">X轴往左为负值往右为正值</el-text>
</el-form-item>
<el-form-item label="Y轴偏移量(实际点位)" prop="y" required>
<el-form-item label="偏移距离(米)" prop="distance" required>
<el-input-number
v-model="batchCopyingForm.y"
placeholder="请输入"
v-model="batchCopyingForm.distance"
placeholder="请输入距离"
controls-position="right"
style="width: 100%"
:min="0"
precision="2"
/>
<el-text type="info" size="small">Y轴往上为负值往下为正值</el-text>
</el-form-item>
</el-form>
<template #footer>
@ -39,7 +41,7 @@
</template>
<script setup>
import { reactive, ref } from 'vue'
import { reactive, ref, watch } from 'vue'
import * as MapApi from '@/api/map/map'
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
@ -52,6 +54,8 @@ const props = defineProps({
})
//
const batchCopyingForm = ref({
radian: 0,
distance: 0,
x: 0,
y: 0
})
@ -59,44 +63,30 @@ const boundaryValue = ref()
const BatchCopyingFormRef = ref()
const dialogFormVisible = ref(false) //
const validateXValue = (rule, value, callback) => {
const { resolution, width } = props.imgBgObj
const roundToThree = (num) => Math.round(Number(num) * 1000) / 1000
let maxLeft = -(Number(boundaryValue.value.left) / Number(resolution))
let maxRight = (Number(width) - Number(boundaryValue.value.right)) / Number(resolution)
if (value < maxLeft || value > maxRight) {
callback(new Error(`不能超出地图宽度,可偏移范围为${maxLeft}${maxRight}`))
} else {
callback()
}
}
const validateYValue = (rule, value, callback) => {
const { resolution, height } = props.imgBgObj
let maxTop = -(Number(boundaryValue.value.top) / Number(resolution))
let maxBottom = (Number(height) - Number(boundaryValue.value.bottom)) / Number(resolution)
if (value < maxTop || value > maxBottom) {
callback(new Error(`不能超出地图宽度,可偏移范围为${maxTop}${maxBottom}`))
} else {
callback()
}
}
watch(
() => [batchCopyingForm.value.radian, batchCopyingForm.value.distance],
([newRadian, newDistance]) => {
// xy
// Ysin
const x = newDistance * Math.cos(newRadian)
const y = -1 * newDistance * Math.sin(newRadian)
batchCopyingForm.value.x = roundToThree(x)
batchCopyingForm.value.y = roundToThree(y)
},
{ immediate: true }
)
const rules = reactive({
x: [
{ required: true, message: '请输入X轴偏移量', trigger: 'blur' },
{ validator: validateXValue, trigger: 'blur' }
],
y: [
{ required: true, message: '请输入Y轴偏移量', trigger: 'blur' },
{ validator: validateYValue, trigger: 'blur' }
]
radian: [{ required: true, message: '请输入方向弧度', trigger: 'blur' }],
distance: [{ required: true, message: '请输入偏移距离', trigger: 'blur' }]
})
const open = (boundaryObj) => {
boundaryValue.value = boundaryObj
batchCopyingForm.value.x = 0
batchCopyingForm.value.y = 0
batchCopyingForm.value.radian = 0
batchCopyingForm.value.distance = 0
dialogFormVisible.value = true
}
@ -115,6 +105,7 @@ const submitLineLibraryForm = async () => {
const y = roundToThree(
safeNumber(batchCopyingForm.value.y) / safeNumber(props.imgBgObj.resolution)
)
emit('submitBatchCopyingFormSuccess', {
x: x,
y: y
@ -124,7 +115,6 @@ const submitLineLibraryForm = async () => {
}
const safeNumber = (value) => Number(value || 0)
const roundToThree = (num) => Math.round(Number(num) * 1000) / 1000
defineExpose({ open }) // open
</script>

View File

@ -134,7 +134,7 @@
</div>
</el-form-item>
<el-form-item label="库位类型" required prop="locationTypeId">
<el-form-item label="库位类型" required prop="locationTypeId" v-if="form.type === 2">
<el-select
class="!w-300px"
v-model="form.locationTypeId"
@ -474,6 +474,7 @@ const typeChange = (type) => {
form.value.dataJson = null
form.value.dataObj = {}
form.value.dataList = []
form.value.locationTypeId = null
if (type === 1) {
form.value.layersNumber = null
form.value.direction = null

View File

@ -22,19 +22,28 @@ const emit = defineEmits(['layerSelectionSuccess'])
const list = ref([
{
category: 'node',
type: 2,
name: '库位点',
isShow: true
},
{
category: 'node',
type: 1,
name: '路径点',
isShow: true
},
{
category: 'node',
type: 3,
name: '设备点',
isShow: true
},
{
category: 'curve',
type: 4,
name: '曲线',
isShow: true
}
])
@ -44,9 +53,13 @@ const changeUnfold = () => {
isUnfold.value = !isUnfold.value
}
const changeSelectList = (item) => {
if (item.category === 'node') {
const types = list.value.filter((item) => !item.isShow).map((item) => item.type)
emit('layerSelectionSuccess', types)
} else {
emit('isCurveDisplayChange')
}
item.isShow = !item.isShow
const types = list.value.filter((item) => !item.isShow).map((item) => item.type)
emit('layerSelectionSuccess', types)
}
const open = (item) => {}
@ -59,8 +72,8 @@ defineExpose({ open }) // 提供 open 方法,用于打开弹窗
z-index: 999;
background-color: #fff;
position: absolute;
bottom: 22px;
left: 18px;
bottom: 0px;
left: 0px;
width: 144px;
cursor: pointer;

View File

@ -715,49 +715,51 @@
</template>
<template v-else>
<path
id="curvePath"
:d="getCurvePath(curve)"
:stroke="curve.isSelected ? '#f48924' : '#2d72d9'"
:stroke-width="state.routeWidthForm.routeWidth"
fill="none"
@click="handleChooseRoute(curve, index)"
/>
<text
style="user-select: none"
:x="computedCurveTextX(curve)"
:y="computedCurveTextY(curve)"
font-size="11"
text-anchor="middle"
fill="black"
v-if="curve.isSelected"
@click="handleChooseRoute(curve, index)"
>
{{ calculateRouteLength(curve, 'curve') }}
</text>
<template v-if="state.isCurveDisplay">
<path
id="curvePath"
:d="getCurvePath(curve)"
:stroke="curve.isSelected ? '#f48924' : '#2d72d9'"
:stroke-width="state.routeWidthForm.routeWidth"
fill="none"
@click="handleChooseRoute(curve, index)"
/>
<text
style="user-select: none"
:x="computedCurveTextX(curve)"
:y="computedCurveTextY(curve)"
font-size="11"
text-anchor="middle"
fill="black"
v-if="curve.isSelected"
@click="handleChooseRoute(curve, index)"
>
{{ calculateRouteLength(curve, 'curve') }}
</text>
<!-- 第一条控制线 -->
<line
v-if="state.currentDragTarget.index == index"
:x1="Number(curve.startPointX)"
:y1="Number(curve.startPointY)"
:x2="curve.beginControlX"
:y2="curve.beginControlY"
:stroke="curve.isSelected ? '#f48924' : '#2d72d9'"
stroke-dasharray="4"
stroke-width="2"
/>
<!-- 第二条控制线 -->
<line
v-if="state.currentDragTarget.index == index"
:x1="Number(curve.endPointX)"
:y1="Number(curve.endPointY)"
:x2="curve.endControlX"
:y2="curve.endControlY"
:stroke="curve.isSelected ? '#f48924' : '#2d72d9'"
stroke-dasharray="4"
stroke-width="2"
/>
<!-- 第一条控制线 -->
<line
v-if="state.currentDragTarget.index == index"
:x1="Number(curve.startPointX)"
:y1="Number(curve.startPointY)"
:x2="curve.beginControlX"
:y2="curve.beginControlY"
:stroke="curve.isSelected ? '#f48924' : '#2d72d9'"
stroke-dasharray="4"
stroke-width="2"
/>
<!-- 第二条控制线 -->
<line
v-if="state.currentDragTarget.index == index"
:x1="Number(curve.endPointX)"
:y1="Number(curve.endPointY)"
:x2="curve.endControlX"
:y2="curve.endControlY"
:stroke="curve.isSelected ? '#f48924' : '#2d72d9'"
stroke-dasharray="4"
stroke-width="2"
/>
</template>
<!-- 控制点circle已移至SVG末尾 -->
</template>
</template>
@ -898,6 +900,7 @@
v-if="state.isShowLayer"
ref="layerSelectionToolDialogRef"
@layer-selection-success="layerSelectionSuccess"
@is-curve-display-change="isCurveDisplayChange"
/>
<!-- 设备弹窗选择 -->
<equipmentToolDialog
@ -1712,7 +1715,8 @@ const state = reactive({
routeDirection: 2, //12
vLine: [],
hLine: [],
svgRouteZIndex: 9
svgRouteZIndex: 9,
isCurveDisplay: true
})
const getRefLineParams = (params) => {
@ -3847,6 +3851,11 @@ const layerSelectionSuccess = (typeList) => {
}
})
}
//线
const isCurveDisplayChange = () => {
state.isCurveDisplay = !state.isCurveDisplay
}
//
const disposeEventPoints = (event) => {
const rect = mapBackgroundRef.value.getBoundingClientRect()
@ -4196,7 +4205,7 @@ const findClosestPoint = (x, y) => {
padding: 0 0 0 4px;
.top-tool-list {
max-width: calc(100vw - 260px);
max-width: calc(100% - 200px);
overflow-x: auto;
display: flex;
align-items: center;
@ -4352,6 +4361,7 @@ const findClosestPoint = (x, y) => {
}
.search-select {
padding-right: 20px;
.search-icon {
widows: 20px;
height: 20px;