feat: 发布任务页面子任务类型支持拖拽排序

This commit is contained in:
Your Name 2026-01-16 11:03:36 +08:00
parent f4c07ab334
commit 8ed4183e6f

View File

@ -68,10 +68,21 @@
<div class="task-types-list">
<div
v-for="(item, index) in formData.taskTypes"
:key="index"
:key="item.id || index"
class="task-type-item"
:class="{ 'dragging': dragIndex === index, 'drag-over': dragOverIndex === index }"
draggable="true"
@dragstart="handleDragStart($event, index)"
@dragend="handleDragEnd"
@dragover.prevent="handleDragOver($event, index)"
@dragleave="handleDragLeave"
@drop="handleDrop($event, index)"
>
<div class="task-type-row">
<!-- 拖拽手柄 -->
<div class="drag-handle" title="拖拽调整顺序">
<Icon name="menu" size="sm" />
</div>
<div class="task-type-select task-type-cascader">
<a-cascader
v-model:value="item.taskTypePath"
@ -629,6 +640,10 @@ interface CascaderOption {
// 设计师列表缓存 { taskType_{id}: designers[] }
const designersCache = reactive<Record<string, any[]>>({})
// 拖拽排序相关
const dragIndex = ref<number | null>(null)
const dragOverIndex = ref<number | null>(null)
// 表单数据
const formData = reactive({
title: '',
@ -920,6 +935,55 @@ const removeTaskType = (index: number) => {
}
}
// 拖拽开始
const handleDragStart = (e: DragEvent, index: number) => {
dragIndex.value = index
if (e.dataTransfer) {
e.dataTransfer.effectAllowed = 'move'
e.dataTransfer.setData('text/plain', String(index))
}
}
// 拖拽结束
const handleDragEnd = () => {
dragIndex.value = null
dragOverIndex.value = null
}
// 拖拽经过
const handleDragOver = (e: DragEvent, index: number) => {
e.preventDefault()
if (dragIndex.value !== null && dragIndex.value !== index) {
dragOverIndex.value = index
}
}
// 拖拽离开
const handleDragLeave = () => {
dragOverIndex.value = null
}
// 放置
const handleDrop = (e: DragEvent, targetIndex: number) => {
e.preventDefault()
if (dragIndex.value === null || dragIndex.value === targetIndex) {
handleDragEnd()
return
}
// 交换位置
const sourceIndex = dragIndex.value
const items = [...formData.taskTypes]
const [removed] = items.splice(sourceIndex, 1)
items.splice(targetIndex, 0, removed)
formData.taskTypes = items
// 重新计算积分
calculateScore()
handleDragEnd()
}
// 处理SPU输入(只允许大写字母、数字和横杠)
const handleSpuInput = (e: Event) => {
const input = e.target as HTMLInputElement
@ -2169,10 +2233,57 @@ onUnmounted(() => {
.task-types-list {
.task-type-item {
margin-bottom: $space-md;
padding: 12px;
background: rgba(255, 255, 255, 0.02);
border: 1px solid transparent;
border-radius: 8px;
transition: all 0.2s ease;
cursor: grab;
&:last-child {
margin-bottom: $space-lg;
}
&:hover {
background: rgba(49, 240, 139, 0.05);
border-color: rgba(49, 240, 139, 0.2);
}
&.dragging {
opacity: 0.5;
cursor: grabbing;
border-color: $brand-primary;
background: rgba(49, 240, 139, 0.1);
}
&.drag-over {
border-color: $brand-primary;
border-style: dashed;
background: rgba(49, 240, 139, 0.15);
transform: scale(1.02);
}
}
.drag-handle {
display: flex;
align-items: center;
justify-content: center;
width: 32px;
height: 40px;
color: #666;
cursor: grab;
border-radius: 4px;
transition: all 0.2s ease;
flex-shrink: 0;
&:hover {
color: $brand-primary;
background: rgba(49, 240, 139, 0.1);
}
&:active {
cursor: grabbing;
}
}
.task-type-row {