diff --git a/app/Http/Controllers/Api/ProjectController.php b/app/Http/Controllers/Api/ProjectController.php index 2e8dc9445..1d7e11b41 100755 --- a/app/Http/Controllers/Api/ProjectController.php +++ b/app/Http/Controllers/Api/ProjectController.php @@ -3889,6 +3889,14 @@ class ProjectController extends AbstractController case ProjectTaskAiEvent::EVENT_SUBTASKS: // 创建子任务 $subtasks = $result['content'] ?? []; + // 过滤无效的子任务名称 + $subtasks = array_filter(array_map(function ($name) { + $name = trim((string)$name); + return (empty($name) || mb_strlen($name) > 100) ? null : $name; + }, $subtasks)); + if (empty($subtasks)) { + return Base::retError('没有有效的子任务名称'); + } // 检查子任务数量限制 $existingCount = ProjectTask::where('parent_id', $task->id) ->whereNull('deleted_at') @@ -3930,6 +3938,11 @@ class ProjectController extends AbstractController if ($relatedTaskId <= 0) { return Base::retError('请选择关联任务'); } + // 验证关联任务存在且有权限 + $relatedTask = ProjectTask::userTask($relatedTaskId); + if (!$relatedTask) { + return Base::retError('关联任务不存在或无权限'); + } ProjectTaskRelation::firstOrCreate([ 'task_id' => $task->id, 'related_task_id' => $relatedTaskId, @@ -3944,6 +3957,9 @@ class ProjectController extends AbstractController return Base::retError('未知的建议类型'); } + // 标记事件为已采纳 + $event->markApplied(); + // 更新消息状态 if ($msgId > 0 && $task->dialog_id) { AiTaskSuggestion::updateMessageStatus($msgId, $task->dialog_id, $type, 'applied'); @@ -3996,6 +4012,9 @@ class ProjectController extends AbstractController return Base::retError('建议不存在或已处理'); } + // 标记事件为已忽略 + $event->markDismissed(); + // 更新消息状态 if ($msgId > 0 && $task->dialog_id) { AiTaskSuggestion::updateMessageStatus($msgId, $task->dialog_id, $type, 'dismissed'); diff --git a/app/Models/ProjectTaskAiEvent.php b/app/Models/ProjectTaskAiEvent.php index 4c1deb80e..cc646fd77 100644 --- a/app/Models/ProjectTaskAiEvent.php +++ b/app/Models/ProjectTaskAiEvent.php @@ -31,6 +31,8 @@ class ProjectTaskAiEvent extends AbstractModel const STATUS_COMPLETED = 'completed'; const STATUS_FAILED = 'failed'; const STATUS_SKIPPED = 'skipped'; + const STATUS_APPLIED = 'applied'; + const STATUS_DISMISSED = 'dismissed'; const MAX_RETRY = 3; @@ -129,4 +131,24 @@ class ProjectTaskAiEvent extends AbstractModel return $this->status === self::STATUS_FAILED && $this->retry_count < self::MAX_RETRY; } + + /** + * 标记为已采纳 + */ + public function markApplied(): bool + { + return $this->update([ + 'status' => self::STATUS_APPLIED, + ]); + } + + /** + * 标记为已忽略 + */ + public function markDismissed(): bool + { + return $this->update([ + 'status' => self::STATUS_DISMISSED, + ]); + } }