This commit is contained in:
严浩
2025-04-16 18:11:40 +08:00
parent 182d87c773
commit b9ae95bfee
3 changed files with 129 additions and 0 deletions

View File

@ -0,0 +1,110 @@
<script setup lang="ts">
import Sortable from 'sortablejs';
interface ComponentItem {
id: number | string;
name: string;
}
interface SelectorState {
组件列表: ComponentItem[];
已选流程ID: (number | string)[];
}
const props = defineProps<{
state: SelectorState;
}>();
const 流程起点列表 = ref<ComponentItem[]>([]);
// const 流程终点列表 = ref<ComponentItem[]>([]);
const 源列表引用 = useTemplateRef<HTMLDivElement | null>('源列表引用');
const 起点列表引用 = useTemplateRef<HTMLDivElement | null>('起点列表引用');
// const 终点列表引用 = useTemplateRef<HTMLDivElement | null>('终点列表引用');
const 组件列表 = computed(() => props.state.组件列表);
onMounted(() => {
if (!源列表引用.value || !起点列表引用.value /* || !终点列表引用.value */) {
consola.error('未能获取到 SortableJS 容器元素');
return;
}
// 初始化源列表
Sortable.create(源列表引用.value, {
group: {
name: 'components',
pull: 'clone', // 允许克隆
put: false, // 不允许拖入
},
sort: false, // 源列表内不允许排序
// 将 data-id 附加到拖拽数据中,供目标列表识别
setData: (dataTransfer, dragEl) => {
if (!dragEl.dataset.id) {
consola.error('拖拽元素未包含 data-id');
return;
}
dataTransfer.setData('text/plain', dragEl.dataset.id);
},
});
// 初始化流程起点列表
Sortable.create(起点列表引用.value, {
group: {
name: 'flowPoints', // 修改为新的组名,用于区分"流程点"和普通组件
pull: true, // 允许拖出
put: ['components'], // 允许接收的组
},
draggable: '.DRAG-ITEM', // 只有带 .DRAG-ITEM 的元素才能被拖动
onAdd: (evt) => {
const itemId = Number.parseInt(evt.item.dataset.id || '0', 10);
consola.info(`从 [${evt.from.dataset.name}] 拖入到 [${evt.to.dataset.name}]itemId: ${itemId}`);
},
});
});
</script>
<template>
<div class="flex gap-5 p-5 bg-[#1a1a1a] text-[#e0e0e0] font-sans min-h-100">
<!-- 组件选择区域 -->
<div class="flex-1 p-4 rounded">
<h3 class="text-center mb-5 text-white font-bold">组件选择</h3>
<div ref="源列表引用" class="flex flex-col gap-2 bg-[#2a2a2a] p-4 rounded" data-name="组件选择区域">
<div class="DRAG-ITEM" v-for="item in 组件列表" :key="item.id" :data-id="item.id">
<AButton class="min-h-50px">
{{ item.name }}
</AButton>
</div>
</div>
</div>
<!-- 构建流程区域 -->
<div class="flex-1 p-4 rounded">
<h3 class="text-center mb-5 text-white font-bold">构建流程</h3>
<div class="flex items-start mb-2.5">
<div class="w-20 text-right mr-2.5 pt-2.5 text-[#ccc]">流程起点</div>
<div ref="起点列表引用" data-name="流程起点区域" class="TARGET-AREA">
<div
v-if="流程起点列表.length === 0"
class="flex justify-center items-center h-full min-h-130px text-[#888] text-center placeholder"
>
请拖入组件构成流程起点
</div>
</div>
</div>
</div>
</div>
</template>
<style scoped>
.placeholder {
/* 默认隐藏的 */
display: none;
}
.TARGET-AREA {
@apply flex-1 min-h-150px rounded p-2.5 border-2 border-dashed border-[#555] bg-[#2a2a2a] mt-1.25 mb-5;
}
/* target-area 的最后一个 .placeholder 元素 */
.TARGET-AREA > .placeholder:last-child {
/* 显示 */
display: block;
}
</style>

View File

@ -0,0 +1,18 @@
<script setup lang="ts">
const state = reactive({
组件列表: [
{ id: 1, name: '组件1' },
{ id: 2, name: '组件2' },
{ id: 3, name: '组件3' },
],
已选流程ID: [],
});
</script>
<template>
<div>
<SortableComponentSelector :state="state" />
</div>
</template>
<style scoped></style>