refactor(draggable): 优化拖拽组件绑定逻辑

- 添加 cloneBindingItem 方法用于创建唯一绑定键
- 使用 _bindingKey 替代 name 作为拖拽项标识符
- 修改 removeFromB 方法参数从 id 改为 index 提升删除效率
- 重构数据映射逻辑统一添加 _bindingKey 字段
- 移除重复的已绑定项过滤逻辑简化代码结构
This commit is contained in:
lixiaolong 2026-08-12 15:28:38 +08:00
parent 40a787e723
commit 9d57865e6a
3 changed files with 34 additions and 43 deletions

View File

@ -122,7 +122,8 @@
<div class="task-title">待选择点位</div>
<draggable :animation="340" :forceFallback="true" :list="taskLeftList" class="draggable-group"
ghostClass="dragClass" :group="{ name: 'people', pull: 'clone', put: false}" itemKey="name">
ghostClass="dragClass" :group="{ name: 'people', pull: 'clone', put: false}"
:clone="cloneBindingItem" itemKey="_bindingKey">
<template #item="{ element, index }">
<div class="list-group-item">
<el-icon>
@ -138,11 +139,11 @@
<div style="height: 55vh">
<div class="task-title">点位排序</div>
<draggable :animation="340" :forceFallback="true" :list="taskRightList" class="draggable-group"
ghostClass="dragClass" :group="{ name: 'people', pull: false, put: true }" itemKey="name">
ghostClass="dragClass" :group="{ name: 'people', pull: false, put: true }" itemKey="_bindingKey">
<template #item="{ element, index }">
<div class="list-group-item">
{{ index + 1 }} 、{{ element.waypointName }}
<el-icon color="red" @click="removeFromB(element.id)" style="margin-left: 10px;"><Delete /></el-icon>
<el-icon color="red" @click="removeFromB(index)" style="margin-left: 10px;"><Delete /></el-icon>
</div>
</template>
</draggable>
@ -328,6 +329,9 @@ function resetBindPointQuery() {
}
const taskId = ref(null);
let bindingSequence = 0
const createBindingKey = () => `waypoint-${Date.now()}-${bindingSequence++}`
const cloneBindingItem = (item) => ({ ...item, _bindingKey: createBindingKey() })
const handleBindPoint = async (row) => {
dialogVisible.value = true;
taskId.value = row.id;
@ -342,20 +346,14 @@ const handleBindPoint = async (row) => {
const getPointListData = async () => {
const res = await getPointList(pointQueryParams)
if (res.code === 200) {
let ids = []
if (taskRightList.value) {
ids = taskRightList.value.map(item => item.id)
}
taskLeftList.value = res.rows.filter(item => {
return !ids.includes(item.id)
})
taskLeftList.value = res.rows.map(item => ({ ...item, _bindingKey: createBindingKey() }))
}
}
const getBindPointByTaskId = async (taskId) => {
const res = await getWaypointByTaskId(taskId)
if (res.code === 200) {
taskRightList.value = res.data;
taskRightList.value = res.data.map(item => ({ ...item, _bindingKey: createBindingKey() }));
}
}
@ -379,9 +377,8 @@ const cancelPoint = () => {
dialogVisible.value = false;
};
const removeFromB = (id) => {
const index = taskRightList.value.findIndex(item => item.id === id)
if (index !== -1) taskRightList.value.splice(index, 1)
const removeFromB = (index) => {
taskRightList.value.splice(index, 1)
}
onMounted(() => {

View File

@ -108,7 +108,8 @@
<div class="task-title">待选择用例</div>
<draggable :animation="340" :forceFallback="true" :list="taskLeftList" class="draggable-group"
ghostClass="dragClass" :group="{ name: 'people', pull: 'clone', put: false}" itemKey="name">
ghostClass="dragClass" :group="{ name: 'people', pull: 'clone', put: false}"
:clone="cloneBindingItem" itemKey="_bindingKey">
<template #item="{ element, index }">
<div class="list-group-item">
<el-icon>
@ -124,11 +125,11 @@
<div style="height: 55vh">
<div class="task-title">用例排序</div>
<draggable :animation="340" :forceFallback="true" :list="taskRightList" class="draggable-group"
ghostClass="dragClass" :group="{ name: 'people', pull: false, put: true }" itemKey="name">
ghostClass="dragClass" :group="{ name: 'people', pull: false, put: true }" itemKey="_bindingKey">
<template #item="{ element, index }">
<div class="list-group-item">
{{ index + 1 }} 、{{ element.caseName }}
<el-icon color="red" @click="removeFromB(element.id)" style="margin-left: 10px;"><Delete /></el-icon>
<el-icon color="red" @click="removeFromB(index)" style="margin-left: 10px;"><Delete /></el-icon>
</div>
</template>
</draggable>
@ -302,6 +303,9 @@ function resetBindCaseQuery() {
}
const taskId = ref(null);
let bindingSequence = 0
const createBindingKey = () => `case-${Date.now()}-${bindingSequence++}`
const cloneBindingItem = (item) => ({ ...item, _bindingKey: createBindingKey() })
const handleBindCase = async (row) => {
dialogVisible.value = true;
taskId.value = row.id;
@ -315,20 +319,14 @@ const handleBindCase = async (row) => {
const getTestCaseListData = async () => {
const res = await getTestCaseList(caseQueryParams)
if (res.code === 200) {
let ids = []
if (taskRightList.value) {
ids = taskRightList.value.map(item => item.id)
}
taskLeftList.value = res.rows.filter(item => {
return !ids.includes(item.id)
})
taskLeftList.value = res.rows.map(item => ({ ...item, _bindingKey: createBindingKey() }))
}
}
const getbindCaseByTaskId = async (taskId) => {
const res = await getTestCaseByTaskId(taskId)
if (res.code === 200) {
taskRightList.value = res.data;
taskRightList.value = res.data.map(item => ({ ...item, _bindingKey: createBindingKey() }));
}
}
@ -352,9 +350,8 @@ const cancelCase = () => {
dialogVisible.value = false;
};
const removeFromB = (id) => {
const index = taskRightList.value.findIndex(item => item.id === id)
if (index !== -1) taskRightList.value.splice(index, 1)
const removeFromB = (index) => {
taskRightList.value.splice(index, 1)
}
onMounted(() => {

View File

@ -235,7 +235,8 @@
class="draggable-group"
ghostClass="dragClass"
:group="{ name: 'people', pull: 'clone', put: false}"
itemKey="name"
:clone="cloneBindingItem"
itemKey="_bindingKey"
>
<template #item="{ element, index }">
<div class="list-group-item">
@ -258,12 +259,12 @@
class="draggable-group"
ghostClass="dragClass"
:group="{ name: 'people', pull: false, put: true }"
itemKey="name"
itemKey="_bindingKey"
>
<template #item="{ element, index }">
<div class="list-group-item">
{{ index + 1 }} 、{{ element.name }}
<el-icon color="red" @click="removeFromB(element.id)" style="margin-left: 10px;"><Delete /></el-icon>
<el-icon color="red" @click="removeFromB(index)" style="margin-left: 10px;"><Delete /></el-icon>
</div>
</template>
</draggable>
@ -395,6 +396,9 @@ const { queryParams, form, rules, paramsFormList } = toRefs(data);
const taskLeftList = ref([]);
const taskRightList = ref([]);
let bindingSequence = 0;
const createBindingKey = () => `item-${Date.now()}-${bindingSequence++}`;
const cloneBindingItem = (item) => ({ ...item, _bindingKey: createBindingKey() });
/** 查询任务流程编排列表 */
function getList() {
@ -537,17 +541,10 @@ const getLiftTaskList = () => {
return {
name: item.detectName,
id: item.id,
_bindingKey: createBindingKey(),
};
}) || [];
if (taskRightList.value.length === 0) {
taskLeftList.value = tempLeftData;
return;
}
taskLeftList.value = tempLeftData.filter((item) => {
return !taskRightList.value.some((item2) => {
return item.id === item2.id;
});
});
taskLeftList.value = tempLeftData;
});
};
//获取右侧编排数据
@ -558,6 +555,7 @@ const getRightTaskList = () => {
return {
name: item.itemName,
id: item.itemId,
_bindingKey: createBindingKey(),
};
}) || [];
getLiftTaskList();
@ -617,9 +615,8 @@ function handleGetSystemGroup(row) {
});
}
const removeFromB = (id) => {
const index = taskRightList.value.findIndex(item => item.id === id)
if (index !== -1) taskRightList.value.splice(index, 1)
const removeFromB = (index) => {
taskRightList.value.splice(index, 1)
}
onMounted(() => {