refactor(TiptapEditor): 重构消息转换逻辑以支持多消息分段处理

重构 tiptapToMessage 函数,将单条消息处理改为支持多条消息分段处理
优化消息内容处理流程,添加文本缓冲区和图片单独处理逻辑
简化消息发送逻辑,移除 msgType 判断改为直接处理不同类型消息
清理已注释的导航功能代码
This commit is contained in:
Phoenix 2025-07-02 13:34:23 +08:00
parent dd170cb50d
commit 8be8afc675

View File

@ -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 messages = []
let quoteId = null
let currentTextBuffer = ''
let currentMentions = []
let currentMentionUids = new Set()
//
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 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)
flushTextBuffer()
return resp
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 (!editor.value || isEditorEmpty()) return
if (isEditorEmpty()) return
const messages = tiptapToMessage()
const data = tiptapToMessage()
if (data.items.length === 0 || (data.items[0].type === 1 && !data.items[0].content.trim())) {
return //
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'))
// }
// }
])
// 稿