From c2c27a684b8c932320a8cb184412c9effee1137b Mon Sep 17 00:00:00 2001 From: kuaifan Date: Wed, 14 Jan 2026 11:31:28 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A4=8D=E5=88=B6/=E5=91=A8=E6=9C=9F?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E6=97=B6=E5=A4=8D=E5=88=B6=E5=AD=90=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E5=B9=B6=E9=87=8D=E7=BD=AE=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 复制任务时同时复制子任务,子任务状态重置为未完成 - 周期任务生成时,子任务状态重置为未完成并映射到 start 工作流 - 新增 getProjectFlowItems 方法获取项目工作流状态 - 新增 formatFlowItemName 方法格式化工作流状态名称 - 新增 copySubTasks 方法复制子任务到新父任务 - 新增 moveSubTasks 方法移动子任务,重构 moveTask 复用代码 --- .../Controllers/Api/ProjectController.php | 5 + app/Models/ProjectTask.php | 165 +++++++++++++----- app/Tasks/LoopTask.php | 14 +- 3 files changed, 130 insertions(+), 54 deletions(-) diff --git a/app/Http/Controllers/Api/ProjectController.php b/app/Http/Controllers/Api/ProjectController.php index cee34f93e..a40ea604b 100755 --- a/app/Http/Controllers/Api/ProjectController.php +++ b/app/Http/Controllers/Api/ProjectController.php @@ -3051,6 +3051,11 @@ class ProjectController extends AbstractController $copy->addLog('复制{任务}', [ 'copy_from' => $task->id, ]); + // 复制子任务 + $task->copySubTasks($copy, [ + 'reset_complete' => true, + 'update_project' => true, + ]); return $copy; }); // diff --git a/app/Models/ProjectTask.php b/app/Models/ProjectTask.php index 81f1cf73a..ff90efa91 100644 --- a/app/Models/ProjectTask.php +++ b/app/Models/ProjectTask.php @@ -1228,6 +1228,126 @@ class ProjectTask extends AbstractModel }); } + /** + * 获取项目的工作流状态项(start 和 end) + * @param int $projectId 项目ID + * @return array ['start' => ProjectFlowItem|null, 'end' => ProjectFlowItem|null] + */ + public static function getProjectFlowItems(int $projectId): array + { + $startFlowItem = null; + $endFlowItem = null; + $projectFlow = ProjectFlow::whereProjectId($projectId)->orderByDesc('id')->first(); + if ($projectFlow) { + $flowItems = ProjectFlowItem::whereFlowId($projectFlow->id)->orderBy('sort')->get(); + foreach ($flowItems as $item) { + if ($item->status == 'start' && !$startFlowItem) { + $startFlowItem = $item; + } + if ($item->status == 'end' && !$endFlowItem) { + $endFlowItem = $item; + } + } + } + return ['start' => $startFlowItem, 'end' => $endFlowItem]; + } + + /** + * 生成工作流状态名称 + * @param ProjectFlowItem|null $flowItem + * @return string + */ + public static function formatFlowItemName(?ProjectFlowItem $flowItem): string + { + return $flowItem ? ($flowItem->status . '|' . $flowItem->name . '|' . $flowItem->color) : ''; + } + + /** + * 复制子任务到新的父任务 + * @param ProjectTask $newParentTask 新的父任务 + * @param array $options 选项 + * - reset_complete: 是否重置完成状态并映射到 start 工作流(默认 true) + * - sync_time: 是否同步时间到父任务的时间(默认 false) + * - update_project: 是否更新项目相关字段(project_id、column_id)(默认 false) + * @return array 新创建的子任务数组 + */ + public function copySubTasks(ProjectTask $newParentTask, array $options = []): array + { + $resetComplete = $options['reset_complete'] ?? true; + $syncTime = $options['sync_time'] ?? false; + $updateProject = $options['update_project'] ?? false; + + $newSubTasks = []; + $subTasks = self::whereParentId($this->id)->get(); + if ($subTasks->isEmpty()) { + return $newSubTasks; + } + + // 获取 start 工作流状态 + $flowItems = $resetComplete ? self::getProjectFlowItems($newParentTask->project_id) : ['start' => null]; + $startFlowItem = $flowItems['start']; + + foreach ($subTasks as $subTask) { + $newSubTask = $subTask->copyTask(); + $newSubTask->parent_id = $newParentTask->id; + + // 同步时间 + if ($syncTime) { + $newSubTask->start_at = $newParentTask->start_at; + $newSubTask->end_at = $newParentTask->end_at; + } + + // 更新项目相关字段 + if ($updateProject) { + $newSubTask->project_id = $newParentTask->project_id; + $newSubTask->column_id = $newParentTask->column_id; + } + + // 重置完成状态 + if ($resetComplete) { + $newSubTask->complete_at = null; + $newSubTask->flow_item_id = $startFlowItem?->id ?? 0; + $newSubTask->flow_item_name = self::formatFlowItemName($startFlowItem); + } + + $newSubTask->save(); + $newSubTasks[] = $newSubTask; + } + + return $newSubTasks; + } + + /** + * 移动子任务到新项目/列 + * @param int $projectId 目标项目ID + * @param int $columnId 目标列ID + */ + public function moveSubTasks(int $projectId, int $columnId): void + { + $subTasks = self::whereParentId($this->id)->get(); + if ($subTasks->isEmpty()) { + return; + } + + $flowItems = self::getProjectFlowItems($projectId); + $startFlowItem = $flowItems['start']; + $endFlowItem = $flowItems['end']; + + foreach ($subTasks as $subTask) { + $subTask->project_id = $projectId; + $subTask->column_id = $columnId; + // 根据完成状态映射工作流 + if ($subTask->complete_at) { + $subTask->flow_item_id = $endFlowItem?->id ?? 0; + $subTask->flow_item_name = self::formatFlowItemName($endFlowItem); + } else { + $subTask->flow_item_id = $startFlowItem?->id ?? 0; + $subTask->flow_item_name = self::formatFlowItemName($startFlowItem); + } + $subTask->save(); + } + } + /** * 同步项目成员至聊天室 */ @@ -1961,50 +2081,7 @@ class ProjectTask extends AbstractModel } } // 子任务 - 根据完成状态映射工作流 - $subTasks = ProjectTask::whereParentId($this->id)->get(); - if ($subTasks->isNotEmpty()) { - // 获取新项目的工作流状态 - $newProjectFlow = ProjectFlow::whereProjectId($projectId)->orderByDesc('id')->first(); - $startFlowItem = null; - $endFlowItem = null; - if ($newProjectFlow) { - $flowItems = ProjectFlowItem::whereFlowId($newProjectFlow->id)->orderBy('sort')->get(); - foreach ($flowItems as $item) { - if ($item->status == 'start' && !$startFlowItem) { - $startFlowItem = $item; - } - if ($item->status == 'end' && !$endFlowItem) { - $endFlowItem = $item; - } - } - } - // 更新每个子任务 - foreach ($subTasks as $subTask) { - $subTask->project_id = $projectId; - $subTask->column_id = $columnId; - // 根据完成状态映射工作流 - if ($subTask->complete_at) { - // 已完成 -> end 状态 - if ($endFlowItem) { - $subTask->flow_item_id = $endFlowItem->id; - $subTask->flow_item_name = $endFlowItem->status . '|' . $endFlowItem->name . '|' . $endFlowItem->color; - } else { - $subTask->flow_item_id = 0; - $subTask->flow_item_name = ''; - } - } else { - // 未完成 -> start 状态 - if ($startFlowItem) { - $subTask->flow_item_id = $startFlowItem->id; - $subTask->flow_item_name = $startFlowItem->status . '|' . $startFlowItem->name . '|' . $startFlowItem->color; - } else { - $subTask->flow_item_id = 0; - $subTask->flow_item_name = ''; - } - } - $subTask->save(); - } - } + $this->moveSubTasks($projectId, $columnId); // if ($flowItemId) { // 更新任务流程 diff --git a/app/Tasks/LoopTask.php b/app/Tasks/LoopTask.php index dde40f3e7..1dc0d282e 100644 --- a/app/Tasks/LoopTask.php +++ b/app/Tasks/LoopTask.php @@ -65,16 +65,10 @@ class LoopTask extends AbstractTask $task->end_at = $task->start_at->clone()->addSeconds($diffSecond); } // 处理子任务 - $subTasks = ProjectTask::whereParentId($item->id)->get(); - if (!$subTasks->isEmpty()) { - foreach ($subTasks as $subTask) { - $newSubTask = $subTask->copyTask(); - $newSubTask->parent_id = $task->id; - $newSubTask->start_at = $task->start_at; - $newSubTask->end_at = $task->end_at; - $newSubTask->save(); - } - } + $item->copySubTasks($task, [ + 'reset_complete' => true, + 'sync_time' => true, + ]); // $task->refreshLoop(true); $task->addLog("创建任务来自周期任务ID:{$item->id}", [], $task->userid);