diff --git a/src/components/editor/TiptapEditor.vue b/src/components/editor/TiptapEditor.vue index 0604af1..e19da1e 100644 --- a/src/components/editor/TiptapEditor.vue +++ b/src/components/editor/TiptapEditor.vue @@ -457,71 +457,106 @@ function onRecorderEvent(file) { // 将Tiptap内容转换为消息格式 function tiptapToMessage() { - if (!editor.value) return { items: [], mentions: [], mentionUids: [], quoteId: '', msgType: 1 } - + if (!editor.value) return [] + const json = editor.value.getJSON() - const resp = { - items: [], - mentions: [], - mentionUids: [], - quoteId: '', - msgType: 1 - } - - // 处理引用 - const quoteNode = json.content?.find((node) => node.type === 'quote') - if (quoteNode) { - resp.quoteId = quoteNode.attrs.id - } - - // 处理内容 - let textContent = '' - let hasImage = false - - const processNode = (node) => { - if (node.type === 'text') { - textContent += node.text - } else if (node.type === 'mention') { - textContent += ` @${node.attrs.label} ` - resp.mentions.push({ - name: `@${node.attrs.label}`, - atid: parseInt(node.attrs.id) - }) - } else if (node.type === 'emoji') { - textContent += node.attrs.alt - } else if (node.type === 'image') { - hasImage = true - resp.items.push({ - type: 3, - content: node.attrs.src - }) - } else if (node.content) { - node.content.forEach(processNode) + const messages = [] + let quoteId = null + let currentTextBuffer = '' + let currentMentions = [] + let currentMentionUids = new Set() + + const flushTextBuffer = () => { + const content = currentTextBuffer.trim() + if (content) { + const data = { + items: [{ type: 1, content: content }], + mentions: [...currentMentions], + mentionUids: Array.from(currentMentionUids) + } + if (quoteId) { + data.quoteId = quoteId + quoteId = null + } + messages.push({ type: 'text', data }) } + currentTextBuffer = '' + currentMentions = [] + currentMentionUids.clear() } - - if (json.content) { - json.content.forEach(processNode) - } - - // 如果有文本内容,添加到items - if (textContent.trim()) { - resp.items.unshift({ - type: 1, - content: textContent.trim() + + const processInlines = nodes => { + nodes.forEach(node => { + if (node.type === 'text') { + currentTextBuffer += node.text + } else if (node.type === 'mention') { + currentTextBuffer += `@${node.attrs.label} ` + const uid = parseInt(node.attrs.id) + if (!currentMentionUids.has(uid)) { + currentMentionUids.add(uid) + currentMentions.push({ name: `@${node.attrs.label}`, atid: uid }) + } + } else if (node.type === 'emoji') { + currentTextBuffer += node.attrs.alt + } else if (node.type === 'hardBreak') { + currentTextBuffer += '\n' + } else if (node.type === 'image') { + // 处理段落内的图片 + flushTextBuffer() + const data = { + ...getImageInfo(node.attrs.src), + url: node.attrs.src + } + if (quoteId) { + data.quoteId = quoteId + quoteId = null + } + messages.push({ type: 'image', data }) + } }) } - - // 设置消息类型 - if (resp.items.length > 1) { - resp.msgType = 12 // 混合消息 - } else if (resp.items.length === 1) { - resp.msgType = resp.items[0].type + + if (json.content) { + const quoteIndex = json.content.findIndex(node => node.type === 'quote') + if (quoteIndex > -1) { + quoteId = json.content[quoteIndex].attrs.id + json.content.splice(quoteIndex, 1) + } + + json.content.forEach(node => { + if (node.type === 'paragraph') { + if (node.content) { + processInlines(node.content) + } + currentTextBuffer += '\n' // Add newline after each paragraph + } else if (node.type === 'image') { + flushTextBuffer() + const data = { + ...getImageInfo(node.attrs.src), + url: node.attrs.src + } + if (quoteId) { + data.quoteId = quoteId + quoteId = null + } + messages.push({ type: 'image', data }) + } + }) } - - resp.mentionUids = resp.mentions.map((item) => item.atid) - - return resp + + flushTextBuffer() + + if (messages.length > 0) { + const lastMessage = messages[messages.length - 1] + if (lastMessage.type === 'text') { + lastMessage.data.items[0].content = lastMessage.data.items[0].content.trim() + if (!lastMessage.data.items[0].content) { + messages.pop() + } + } + } + + return messages } // 将Tiptap内容转换为纯文本 @@ -550,52 +585,36 @@ function isEditorEmpty() { * 根据编辑器内容类型发送不同类型的消息 */ function onSendMessage() { - if (!editor.value) return - - if (isEditorEmpty()) return - - const data = tiptapToMessage() - - if (data.items.length === 0 || (data.items[0].type === 1 && !data.items[0].content.trim())) { - return // 没有内容不发送 + if (!editor.value || isEditorEmpty()) return + + const messages = tiptapToMessage() + + if (messages.length === 0) { + return } - switch (data.msgType) { - case 1: // 文字消息 - if (data.items[0].content.length > 1024) { - return window['$message'].info('发送内容超长,请分条发送') + let canClear = true + messages.forEach(msg => { + if (msg.type === 'text') { + if (msg.data.items[0].content.length > 1024) { + window['$message'].info('发送内容超长,请分条发送') + canClear = false + return } + emit('editor-event', emitCall('text_event', msg.data)) + } else if (msg.type === 'image') { + const data = { + height: 0, + width: 0, + size: 10000, + url: msg.data.url, + } + emit('editor-event', emitCall('image_event', data)) + } + }) - // 发送文本消息 - emit( - 'editor-event', - emitCall('text_event', data, (ok) => { - ok && editor.value?.commands.clearContent(true) // 成功发送后清空编辑器 - }) - ) - break - case 3: // 图片消息 - // 发送图片消息 - emit( - 'editor-event', - emitCall( - 'image_event', - { ...getImageInfo(data.items[0].content), url: data.items[0].content, size: 10000 }, - (ok) => { - ok && editor.value?.commands.clearContent(true) // 成功发送后清空编辑器 - } - ) - ) - break - case 12: // 图文混合消息 - // 发送混合消息 - emit( - 'editor-event', - emitCall('mixed_event', data, (ok) => { - ok && editor.value?.commands.clearContent(true) // 成功发送后清空编辑器 - }) - ) - break + if (canClear) { + editor.value?.commands.clearContent(true) } } @@ -728,45 +747,7 @@ const navs = reactive([ uploadFileRef.value.click() // 触发文件上传 } }, - // 以下功能已被注释掉,但保留代码 - // { - // title: '代码', - // icon: markRaw(SourceCode), - // show: true, - // click: () => { - // isShowEditorCode.value = true - // } - // }, - // { - // title: '语音消息', - // icon: markRaw(IconVoice), - // show: true, - // click: () => { - // isShowEditorRecorder.value = true - // } - // }, - // { - // title: '地理位置', - // icon: markRaw(Local), - // show: true, - // click: () => {} - // }, - // { - // title: '群投票', - // icon: markRaw(Ranking), - // show: computed(() => props.vote), - // click: () => { - // isShowEditorVote.value = true - // } - // }, - // { - // title: '历史记录', - // icon: markRaw(History), - // show: true, - // click: () => { - // emit('editor-event', emitCall('history_event')) - // } - // } + ]) // 监听聊天索引变化,切换聊天时加载对应草稿