From 3911af7b51db03515d4cf39922d28d0397ed5172 Mon Sep 17 00:00:00 2001 From: kuaifan Date: Wed, 21 Jan 2026 07:17:41 +0000 Subject: [PATCH] =?UTF-8?q?fix(ai):=20=E4=BF=AE=E5=A4=8D=E6=8F=8F=E8=BF=B0?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=92=8C=E8=B4=9F=E8=B4=A3=E4=BA=BA=E9=87=8D?= =?UTF-8?q?=E5=A4=8D=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 描述建议:AI 返回 Markdown,前端用 MarkdownConver 转 HTML 2. 负责人推荐:排除已分配的任务成员 3. 解析负责人推荐时去重,防止 AI 返回重复用户 Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude Co-Authored-By: Happy --- app/Module/AiTaskSuggestion.php | 44 ++++++++++++++----- .../manage/components/DialogMarkdown.vue | 4 +- 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/app/Module/AiTaskSuggestion.php b/app/Module/AiTaskSuggestion.php index a9b0c86d3..c15ecf310 100644 --- a/app/Module/AiTaskSuggestion.php +++ b/app/Module/AiTaskSuggestion.php @@ -103,8 +103,18 @@ class AiTaskSuggestion */ public static function generateAssignee(ProjectTask $task): ?array { - // 获取项目成员 + // 获取当前任务已有的成员(负责人和协助人) + $existingUserIds = ProjectTaskUser::where('task_id', $task->id) + ->pluck('userid') + ->toArray(); + + // 获取项目成员,排除已有任务成员 $members = self::getProjectMembersInfo($task->project_id); + $members = array_filter($members, function ($member) use ($existingUserIds) { + return !in_array($member['userid'], $existingUserIds); + }); + $members = array_values($members); // 重新索引 + if (empty($members)) { return null; } @@ -192,17 +202,20 @@ class AiTaskSuggestion 请按以下格式生成任务描述(使用 Markdown): -> **背景**:[描述任务的背景和上下文] -> **目标**:[明确任务要达成的目标] -> **验收标准**: -> - [验收标准1] -> - [验收标准2] -> - [验收标准3] +**背景**:[描述任务的背景和上下文] + +**目标**:[明确任务要达成的目标] + +**验收标准**: +- [验收标准1] +- [验收标准2] +- [验收标准3] 要求: 1. 内容要专业、简洁 2. 验收标准要具体、可衡量 3. 与用户输入语言保持一致 +4. 只返回 Markdown 内容,不要返回其他文字 PROMPT; } @@ -379,6 +392,8 @@ PROMPT; $lines = explode("\n", trim($text)); $recommendations = []; + $addedUserIds = []; // 记录已添加的用户ID,防止重复 + foreach ($lines as $line) { $line = trim($line); $line = preg_replace('/^\d+[\.\)、]\s*/', '', $line); @@ -387,12 +402,18 @@ PROMPT; $userid = intval($matches[1]); $reason = trim($matches[2]); + // 跳过已添加的用户 + if (in_array($userid, $addedUserIds)) { + continue; + } + if (isset($memberMap[$userid])) { $recommendations[] = [ 'userid' => $userid, 'nickname' => $memberMap[$userid]['nickname'], 'reason' => $reason, ]; + $addedUserIds[] = $userid; } } } @@ -496,7 +517,7 @@ PROMPT; } } - return implode("\n---\n\n", $parts); + return implode("\n\n---\n\n", $parts); } /** @@ -512,7 +533,7 @@ PROMPT; {$content} -[✓ 采纳描述]({$applyUrl}) [✗ 忽略]({$dismissUrl}) +[✅ 采纳描述]({$applyUrl}) [❌ 忽略]({$dismissUrl}) MD; } @@ -534,7 +555,7 @@ MD; ### 建议拆分子任务 {$list} -[✓ 创建子任务]({$applyUrl}) [✗ 忽略]({$dismissUrl}) +[✅ 创建子任务]({$applyUrl}) [❌ 忽略]({$dismissUrl}) MD; } @@ -672,7 +693,8 @@ MD; $dialogId, 'text', ['text' => $newContent, 'type' => 'md'], - self::AI_ASSISTANT_USERID + self::AI_ASSISTANT_USERID, + true, // push_self ); } } diff --git a/resources/assets/js/pages/manage/components/DialogMarkdown.vue b/resources/assets/js/pages/manage/components/DialogMarkdown.vue index 5479b91b4..e6f1b4009 100644 --- a/resources/assets/js/pages/manage/components/DialogMarkdown.vue +++ b/resources/assets/js/pages/manage/components/DialogMarkdown.vue @@ -191,10 +191,10 @@ export default { applyAiSuggestionByType(type, taskId, result, params) { switch (type) { case 'description': - // 更新任务描述 + // 更新任务描述(Markdown 转 HTML) this.$store.dispatch('taskUpdate', { task_id: taskId, - content: result.content, + content: MarkdownConver(result.content), }).then(() => { $A.messageSuccess(this.$L('应用成功')); }).catch(({msg}) => {