Ожидаемое/нормальное поведение: Для большинства сценариев перетаскивания (изменение порядка в одном списке или перемещение задачи на непервую позицию в другом списке) серверная часть успешно обновляет статус перемещенной задачи и позицию, а также повторно индексирует задачи как в старом, так и в старом списке. и новые столбцы.
Проблема (единственный случай сбоя): Обновление не работает только при перемещении задачи на первую позицию (position=1) в другом списке статусов. Похоже, что в транзакции базы данных возникла проблема, которая привела к следующему:
- Перемещена задача () возвращается к своему исходному списку (
Код: Выделить всё
id: 15) и ему неправильно присвоена позиция: "1".Код: Выделить всё
status: "To Do" - Исходный список () переиндексируется, при этом перемещенная задача поднимается вверх.
Код: Выделить всё
"To Do" - Целевой список () не обновляется вообще.
Код: Выделить всё
"In Progress"
Пример состояния базы данных (сценарий сбоя):
- Перемещенная задача: id: 15, из статуса: «Задать», позиция: «3».
- Целевое перемещение: В статус: «В процессе», позиция: «1».
Список
Идентификатор задачи
Статус
Позиция
ДО
11, 14
В Прогресс
1, 2
20, 19, 15, 21, 22
Сделать
1, 2, 3, 4, 5
AFTER (Не удалось)
11, 14
В процессе
1, 2 (без изменений)
15, 20, 19, 21, 22
Что сделать
1, 1, 2, 3, 4 (перемещено назад, переиндексировано)
Я подозреваю, что проблема заключается в том, как позиция/статус перемещенной задачи обновляется в цикле целевого столбца, или при последующем повторном индексировании исходного столбца.
Лучший способ изолировать это — удалить API, Blade и несущественную логику Livewire и показать упрощенный сценарий, который по-прежнему вызывает основную функцию.
Показ updateTaskOrder и методы reorderTasksInColumn.
Код: Выделить всё
// Only the essential Livewire component methods
class TaskBoard extends Component
{
// ... (omitted: properties, render, other methods)
/**
* Handles task reordering, called by Alpine/SortableJS.
* @param array $sortedTaskIds An array of task IDs in the new order for the target column.
* @param string $newStatus The status (column name) the task was moved to.
* @param int $taskId The ID of the task that was moved.
*/
public function updateTaskOrder(array $sortedTaskIds, string $newStatus, int $taskId): void
{
DB::transaction(function () use ($sortedTaskIds, $newStatus, $taskId) {
$movedTask = Task::find($taskId);
if (!$movedTask) return; // Handle task not found
$oldStatus = $movedTask->status;
$originalPosition = $movedTask->position;
$newPositionForMovedTask = null;
$statusChanged = $oldStatus !== $newStatus;
// 1. Update positions for all tasks in the target column
foreach ($sortedTaskIds as $index => $id) {
$newPosition = $index + 1; // Positions are 1-based
if ((int)$id === $taskId) {
$newPositionForMovedTask = $newPosition;
// Why does this update sometimes fail for newPosition=1?
$movedTask->update(['status' => $newStatus, 'position' => $newPosition]);
} else {
// This update could be the issue, as it assumes $id is a non-moved task
// that is *already* in $newStatus.
Task::where('id', $id)->where('status', $newStatus)->update(['position' => $newPosition]);
}
}
if ($newPositionForMovedTask === null) return; // Moved task not in sorted list
// 2. If status changed, re-order the tasks in the original column
if ($statusChanged) {
// Re-index remaining tasks in the column the task left
$this->reorderTasksInColumn($oldStatus);
}
// ... (omitted: activity logging - non-essential)
});
// ... (omitted: $this->dispatch('$refresh'))
}
/**
* Re-orders tasks in a specific column, closing gaps.
* @param string $status The status/column to re-order.
*/
private function reorderTasksInColumn(string $status): void
{
$tasksToReorder = Task::where('status', $status)
->orderBy('position', 'asc')
->get();
foreach ($tasksToReorder as $index => $task) {
$task->update(['position' => $index + 1]);
}
}
}
Пример исходного состояния базы данных:
- : [20 (поз. 1), 19 (поз. 2), 15 (поз. 3), 21 (поз. 4), 22 (поз. 5)]
Код: Выделить всё
To Do - : [11 (поз. 1), 14 (поз. 2)]
Код: Выделить всё
In Progress
Код: Выделить всё
// Goal: Move Task 15 from 'To Do' to 'In Progress', position 1.
$taskId = 15;
$newStatus = 'In Progress';
// The sorted IDs for the TARGET column, with the moved task (15) at the start:
$sortedTaskIds = [15, 11, 14];
// Instantiate the component (or a service class with this logic)
$taskBoard = new TaskBoard();
$taskBoard->updateTaskOrder($sortedTaskIds, $newStatus, $taskId);
Подробнее здесь: https://stackoverflow.com/questions/798 ... irst-posit
Мобильная версия