From 6cf82905650e0a2c645feaa6b3e90b38f1db4769 Mon Sep 17 00:00:00 2001 From: kuaifan Date: Wed, 24 Dec 2025 05:58:48 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=BC=BA=E6=96=9C=E6=9D=A0?= =?UTF-8?q?=E5=91=BD=E4=BB=A4=E6=94=AF=E6=8C=81=EF=BC=8C=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E6=9C=BA=E5=99=A8=E4=BA=BA=E5=91=BD=E4=BB=A4=E5=92=8C=E8=A1=8C?= =?UTF-8?q?=E9=A6=96=E6=A3=80=E6=B5=8B=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../manage/components/ChatInput/index.vue | 112 +++++++++++++++++- 1 file changed, 108 insertions(+), 4 deletions(-) diff --git a/resources/assets/js/pages/manage/components/ChatInput/index.vue b/resources/assets/js/pages/manage/components/ChatInput/index.vue index bb119e536..f2652a949 100755 --- a/resources/assets/js/pages/manage/components/ChatInput/index.vue +++ b/resources/assets/js/pages/manage/components/ChatInput/index.vue @@ -1250,7 +1250,14 @@ export default { this.quill.deleteText(mentionCharPos, cursorPos - mentionCharPos, Quill.sources.USER); this.quill.setSelection(mentionCharPos, 0, Quill.sources.USER); } - this.openMenu(item.tip); + if (["@", "#", "~", "%"].includes(item.tip)) { + this.openMenu(item.tip); + } else { + const insertText = item.tip.endsWith(' ') ? item.tip : `${item.tip} `; + const insertAt = typeof mentionCharPos === 'number' ? mentionCharPos : (this.quill.getSelection(true)?.index || 0); + this.quill.insertText(insertAt, insertText, Quill.sources.USER); + this.quill.setSelection(insertAt + insertText.length, 0, Quill.sources.USER); + } return; } insertItem(item); @@ -2633,8 +2640,14 @@ export default { case "/": // /快捷菜单 this.mentionMode = "slash-mention"; - resultCallback([{ - label: null, + const allowBotCommands = this.isSlashAtLineStart(); + const isBotDialog = this.dialogData.type === 'user' && this.dialogData.bot; + const isOwnBot = isBotDialog && this.dialogData.bot == this.userId; + const isBotManager = isBotDialog && this.dialogData.email === 'bot-manager@bot.system'; + const showBotCommands = allowBotCommands && (isOwnBot || isBotManager); + const baseLabel = showBotCommands ? [{id: 0, value: this.$L('快捷菜单'), disabled: true}] : null; + const slashLists = [{ + label: baseLabel, list: [ { id: 'mention', @@ -2657,7 +2670,81 @@ export default { tip: '%', }, ] - }]) + }]; + if (showBotCommands) { + const commandList = []; + if (isBotManager) { + commandList.push( + { + id: 'list', + value: this.$L('我的机器人'), + tip: '/list', + }, + { + id: 'newbot', + value: this.$L('新建机器人'), + tip: '/newbot', + } + ); + } + commandList.push( + { + id: 'help', + value: this.$L('帮助指令'), + tip: '/help', + }, + { + id: 'api', + value: this.$L('API接口文档'), + tip: '/api', + }, + { + id: 'info', + value: this.$L('机器人信息'), + tip: '/info', + }, + { + id: 'setname', + value: this.$L('设置名称'), + tip: '/setname', + }, + { + id: 'deletebot', + value: this.$L('删除机器人'), + tip: '/deletebot', + }, + { + id: 'token', + value: this.$L('机器人Token'), + tip: '/token', + }, + { + id: 'revoke', + value: this.$L('更新Token'), + tip: '/revoke', + }, + { + id: 'clearday', + value: this.$L('设置保留消息时间'), + tip: '/clearday', + }, + { + id: 'webhook', + value: this.$L('设置Webhook'), + tip: '/webhook', + }, + { + id: 'dialog', + value: this.$L('对话列表'), + tip: '/dialog', + } + ); + slashLists.push({ + label: [{id: 0, value: this.$L('机器人命令'), disabled: true}], + list: commandList, + }); + } + resultCallback(slashLists) break; default: @@ -2666,6 +2753,23 @@ export default { } }, + isSlashAtLineStart() { + const editor = this.getEditor(); + const mention = editor?.getModule("mention"); + const mentionCharPos = mention?.mentionCharPos; + if (!editor || typeof mentionCharPos !== 'number') { + return false; + } + const textLength = Math.max(0, editor.getLength() - 1); + if (textLength > 100) { + return false; + } + const prefixText = editor.getText(0, mentionCharPos) || ''; + const lastBreak = Math.max(prefixText.lastIndexOf("\n"), prefixText.lastIndexOf("\r")); + const linePrefix = lastBreak >= 0 ? prefixText.slice(lastBreak + 1) : prefixText; + return linePrefix.trim().length === 0; + }, + getMoreUser(key, existIds) { return new Promise(resolve => { const {owner_id, type} = this.dialogData