From 165ad0302465a44b9d98fd00325dfb65aea5cb6e Mon Sep 17 00:00:00 2001 From: kuaifan Date: Wed, 21 Jan 2026 01:54:32 +0000 Subject: [PATCH] feat(ai): add ai-apply/ai-dismiss protocol handlers --- .../manage/components/DialogMarkdown.vue | 69 +++++++++++++++++++ resources/assets/js/store/actions.js | 36 ++++++++++ 2 files changed, 105 insertions(+) diff --git a/resources/assets/js/pages/manage/components/DialogMarkdown.vue b/resources/assets/js/pages/manage/components/DialogMarkdown.vue index 111d62eae..f42aa8453 100644 --- a/resources/assets/js/pages/manage/components/DialogMarkdown.vue +++ b/resources/assets/js/pages/manage/components/DialogMarkdown.vue @@ -146,7 +146,76 @@ export default { $A.modalError(msg); }); break; + + case 'ai-apply': + this.handleAiApply(href); + break; + + case 'ai-dismiss': + this.handleAiDismiss(href); + break; } + }, + + /** + * 处理 AI 建议采纳 + * 格式: dootask://ai-apply/{type}/{task_id}/{msg_id}?{params} + */ + handleAiApply(href) { + const match = href.match(/^dootask:\/\/ai-apply\/(\w+)\/(\d+)\/(\d+)(?:\?(.*))?$/); + if (!match) { + return; + } + const [, type, taskId, msgId, queryString] = match; + const params = new URLSearchParams(queryString || ''); + + const data = {}; + if (type === 'assignee') { + const userid = params.get('userid'); + if (!userid || isNaN(parseInt(userid, 10))) { + return; + } + data.userid = parseInt(userid, 10); + } else if (type === 'similar') { + const related = params.get('related'); + if (!related || isNaN(parseInt(related, 10))) { + return; + } + data.related_task_id = parseInt(related, 10); + } + + this.$store.dispatch('applyAiSuggestion', { + task_id: parseInt(taskId, 10), + msg_id: parseInt(msgId, 10), + type, + data, + }).then(() => { + $A.messageSuccess(this.$L('应用成功')); + }).catch(({msg}) => { + $A.modalError(msg); + }); + }, + + /** + * 处理 AI 建议忽略 + * 格式: dootask://ai-dismiss/{type}/{task_id}/{msg_id} + */ + handleAiDismiss(href) { + const match = href.match(/^dootask:\/\/ai-dismiss\/(\w+)\/(\d+)\/(\d+)$/); + if (!match) { + return; + } + const [, type, taskId, msgId] = match; + + this.$store.dispatch('dismissAiSuggestion', { + task_id: parseInt(taskId, 10), + msg_id: parseInt(msgId, 10), + type, + }).then(() => { + $A.messageSuccess(this.$L('已忽略')); + }).catch(({msg}) => { + $A.modalError(msg); + }); } } } diff --git a/resources/assets/js/store/actions.js b/resources/assets/js/store/actions.js index 263c3e9da..deb37de51 100644 --- a/resources/assets/js/store/actions.js +++ b/resources/assets/js/store/actions.js @@ -5219,6 +5219,42 @@ export default { // 启动 MCP 服务器 commit('mcp/server/status', {running: 'running'}); } + }, + + /** *****************************************************************************************/ + /** *********************************** AI Suggestions **************************************/ + /** *****************************************************************************************/ + + /** + * 采纳 AI 建议 + */ + applyAiSuggestion({}, params) { + return new Promise((resolve, reject) => { + this.dispatch('call', { + url: 'project/task/ai-apply', + data: params, + }).then(result => { + resolve(result); + }).catch(e => { + reject(e); + }); + }); + }, + + /** + * 忽略 AI 建议 + */ + dismissAiSuggestion({}, params) { + return new Promise((resolve, reject) => { + this.dispatch('call', { + url: 'project/task/ai-dismiss', + data: params, + }).then(result => { + resolve(result); + }).catch(e => { + reject(e); + }); + }); } }