Laravel Livewire/Eloquent: обновление позиции завершается сбоем при перемещении задачи в первую позицию (индекс 1) другоPhp

Кемеровские программисты php общаются здесь
Ответить
Anonymous
 Laravel Livewire/Eloquent: обновление позиции завершается сбоем при перемещении задачи в первую позицию (индекс 1) друго

Сообщение Anonymous »

Мое приложение использует Laravel Livewire с Alpine.js/SortableJS для изменения порядка задач между столбцами состояния путем перетаскивания. Задачи имеют статус (строка) и позицию (целое число) в базе данных.
Ожидаемое/нормальное поведение: Для большинства сценариев перетаскивания (изменение порядка в одном списке или перемещение задачи на непервую позицию в другом списке) серверная часть успешно обновляет статус перемещенной задачи и позицию, а также повторно индексирует задачи как в старом, так и в старом списке. и новые столбцы.
Проблема (единственный случай сбоя): Обновление не работает только при перемещении задачи на первую позицию (position=1) в другом списке статусов. Похоже, что в транзакции базы данных возникла проблема, которая привела к следующему:
  • Перемещена задача () возвращается к своему исходному списку (

    Код: Выделить всё

    status: "To Do"
    ) и ему неправильно присвоена позиция: "1".
  • Исходный список () переиндексируется, при этом перемещенная задача поднимается вверх.
  • Целевой список (

    Код: Выделить всё

    "In Progress"
    ) не обновляется вообще.
Такое поведение предполагает логическую ошибку в основном методе обновления, особенно для межстолбцового перемещения в позицию 1.
Пример состояния базы данных (сценарий сбоя):
  • Перемещенная задача: 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 и показать упрощенный сценарий, который по-прежнему вызывает основную функцию.
📄 app/Livewire/TaskBoard.php
Показ 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]);
}
}
}
Имитированный вызов (пример Tinker):
Пример исходного состояния базы данных: Неудачное перетаскивание в позицию 1 «Выполняется» передаст эти данные в метод Livewire:

Код: Выделить всё

// 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);
Что является причиной сбоя обновления позиции и статуса для задачи с идентификатором 15, когда newPosition = 1?


Подробнее здесь: https://stackoverflow.com/questions/798 ... irst-posit
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Php»