You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

拖拽式事件调度器的拖拽复制逻辑实现求助

拖拽式事件调度器的拖拽复制逻辑实现求助

嘿,我完全懂你现在的困扰——这个拖拽复制的规则确实有点绕,不过你的基础框架已经搭得很扎实了,只需要针对LeadIn事件的特殊需求调整几个回调逻辑就行。咱们一步步来搞定它:

核心需求回顾

先再理一遍你要的规则,确保咱们没跑偏:

  • 从Events列拖拽LeadIn到Screen列:原LeadIn留在Events,复制一份到目标Screen
  • 从Screen列拖拽LeadIn到另一个Screen列:直接移动过去
  • 从Screen列拖拽LeadIn到Events列:移除这个Screen里的LeadIn,Events里保持原有那一个
  • Events列永远只能有一个LeadIn

代码修改方案

咱们主要修改sortable的回调函数,加上拖拽开始的判断,以及调整receive、remove的逻辑,同时强化LeadIn的唯一性校验:

$(document).ready(function () {
    // Call the sort function on page load to alphabetize the Events column
    sortEventsInEventsColumn();

    // 全局变量记录拖拽的源信息
    let dragSourceColumnId;
    let isDraggingLeadIn;

    $(function() {
        $(".sortable-list").sortable({
            connectWith: ".sortable-list",
            placeholder: "event-placeholder",
            start: function(event, ui) {
                // 记录拖拽开始时的源列ID和是否是LeadIn
                dragSourceColumnId = $(this).closest(".column").attr("id");
                isDraggingLeadIn = ui.item.hasClass("lead-in-event");
            },
            receive: function (event, ui) {
                const $targetColumn = $(this).closest(".column");
                const targetColumnId = $targetColumn.attr("id");

                // 处理LeadIn的特殊逻辑
                if (isDraggingLeadIn) {
                    // 场景1:从Events拖到Screen列,需要复制,保留原LeadIn
                    if (dragSourceColumnId === "events" && targetColumnId !== "events") {
                        // 复制原LeadIn放回Events列
                        const originalLeadIn = $("#leadIn").clone(true);
                        $("#events .sortable-list").append(originalLeadIn);
                        // 重新排序Events列,确保LeadIn在顶部
                        sortEventsInEventsColumn();
                    }
                    // 场景2:从Screen拖到Events列,直接移除拖拽的这个LeadIn
                    else if (targetColumnId === "events") {
                        ui.item.remove();
                        // 确保Events列只有一个LeadIn
                        ensureSingleLeadInInEvents();
                        return; // 跳过后续时间计算逻辑
                    }
                }

                // 常规时间计算逻辑(非LeadIn或者Screen之间的LeadIn移动)
                if (targetColumnId !== "events") {
                    recalculateColumnTimes($targetColumn);
                    updateTotalDuration($targetColumn);
                } else {
                    updateEventTimes(ui.item, "", "");
                    sortEventsInEventsColumn();
                }
            },
            update: function (event, ui) {
                const $targetColumn = $(this).closest(".column");
                const targetColumnId = $targetColumn.attr("id");

                if (targetColumnId !== "events") {
                    recalculateColumnTimes($targetColumn);
                    updateTotalDuration($targetColumn);
                } else {
                    updateEventTimes(ui.item, "", "");
                    // 确保Events列只有一个LeadIn
                    ensureSingleLeadInInEvents();
                    sortEventsInEventsColumn();
                }
            },
            remove: function (event, ui) {
                const $sourceColumn = $(this).closest(".column");
                const sourceColumnId = $sourceColumn.attr("id");

                if (sourceColumnId !== "events") {
                    recalculateColumnTimes($sourceColumn);
                    updateTotalDuration($sourceColumn);
                }
            }
        }).disableSelection();
    });

    // 新增函数:确保Events列只有一个LeadIn
    function ensureSingleLeadInInEvents() {
        const $eventsColumn = $("#events");
        const $leadIns = $eventsColumn.find(".lead-in-event");
        if ($leadIns.length > 1) {
            // 保留第一个,移除其他多余的LeadIn
            $leadIns.slice(1).remove();
        }
    }

    // 以下是你原有的函数,保持不变
    function recalculateColumnTimes($column) {
        var $events = $column.find(".event");
        var startTime = $column.data("start-time");
        $events.each(function (index) {
            var $event = $(this);
            var duration = $event.data("duration");
            var endTime = calculateEndTime(startTime, duration);
            updateEventTimes($event, "Start: " + formatTimeAMPM(startTime), "End: " + formatTimeAMPM(endTime));
            startTime = endTime;
        });
    }

    function updateEventTimes($event, startTime, endTime) {
        $event.find(".event-start-time").text(startTime);
        $event.find(".event-end-time").text(endTime);
    }

    function calculateEndTime(startTime, duration) {
        var start = moment(startTime, "HH:mm:ss");
        var dur = moment.duration(duration);
        var end = start.clone().add(dur);
        return end.format("HH:mm:ss");
    }

    function formatTimeAMPM(time) {
        return moment(time, "HH:mm:ss").format("h:mm:ss A");
    }

    function sortEventsInEventsColumn() {
        var $eventsColumn = $("#events");
        var $eventList = $eventsColumn.find(".sortable-list");
        var events = $eventList.children(".event").get();
        events.sort(function (a, b) {
            var titleA = $(a).find(".event-title").text();
            var titleB = $(b).find(".event-title").text();
            if (titleA === "LeadIn") {
                return -1;
            } else if (titleB === "LeadIn") {
                return 1;
            }
            return titleA.localeCompare(titleB);
        });
        $.each(events, function (index, event) {
            $eventList.append(event);
        });
        // 排序后也要确保只有一个LeadIn
        ensureSingleLeadInInEvents();
    }

    function updateTotalDuration($column) {
        var $eventList = $column.find(".sortable-list");
        var totalDuration = moment.duration();
        $eventList.find(".event").each(function () {
            var duration = moment.duration($(this).data("duration"));
            totalDuration.add(duration);
        });
        var formattedTotalDuration = formatDuration(totalDuration);
        $column.find(".column-total-duration").text("Total Duration: " + formattedTotalDuration);
    }

    function formatDuration(duration) {
        var hours = duration.hours();
        var minutes = duration.minutes();
        return hours + "h " + minutes + "m";
    }

});

修改点说明

  1. start回调:新增这个回调来记录拖拽的源列ID和当前元素是否是LeadIn,后续的逻辑都依赖这个判断。
  2. receive回调:针对三种场景分别处理:
    • 从Events到Screen:复制原LeadIn放回Events,保证原元素不被移走。
    • 从Screen到Events:直接删除拖拽的LeadIn,不让它进入Events列。
  3. 新增ensureSingleLeadInInEvents函数:专门用来校验Events列的LeadIn数量,确保永远只有一个,不管是拖拽还是排序后都调用它。
  4. sortEventsInEventsColumn函数:最后加上ensureSingleLeadInInEvents的调用,防止排序时出现多个LeadIn。

这样调整后,你的拖拽规则就完全符合需求啦,你可以测试一下各个场景,应该都能正常工作~

备注:内容来源于stack exchange,提问作者Trick Kramer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.21 14:59:28