feat: 报告初步显示

This commit is contained in:
2026-03-13 17:23:56 +08:00
parent 570701b927
commit 430d3fb7f1
5 changed files with 256 additions and 77 deletions

View File

@@ -33,7 +33,10 @@
const agentStore = useAgentStore()
const projectStore = useProjectStore()
const emits = defineEmits(['update:sketchList'])
const reportsContent = ref('')
const isGeneratingReport = ref(false)
const emits = defineEmits(['update:sketchList', 'setTitle'])
const props = withDefaults(
defineProps<{
title: string
@@ -206,6 +209,7 @@
// 流式响应处理
let contentBody = ''
let buffer = ''
const webAddressList = []
const reader = response.body?.getReader()
if (!reader) throw new Error('无法获取流读取器')
@@ -230,18 +234,43 @@
let events = buffer.split(/\n\n/)
buffer = events.pop() // 保留不完整块
let previousEventName = '' // 记录上一个事件名称
let hasReportStarted = false // 标记 report 是否已经开始
for (let event of events) {
if (!event.trim()) continue
// debugger
// 过滤掉 id: 等字段,只取 data:
let isNodeIdEvent = false
if (event.includes('nodeId')) {
isNodeIdEvent = true
// continue
// 解析事件名称(从 event:xxx 行)
const eventName =
event
.split(/\n/)
.find((line) => line.startsWith('event:'))
?.replace(/^event:\s*/, '')
?.trim() || ''
if (!hasReportStarted && eventName === 'report') {
console.log('开始生成报告--------')
isGeneratingReport.value = true
contentBody += `<slot slot-name="card" title="123">123</slot>`
hasReportStarted = true
}
console.log('event', event)
if (event.includes('error')) {
if (
previousEventName === 'report' &&
eventName !== 'report' &&
reportsContent.value
) {
isGeneratingReport.value = false
localStorage.setItem('reportsContent', reportsContent.value)
}
previousEventName = eventName
// console.log('eventName:', eventName, 'event:', event)
// 根据事件名称精确判断,而不是用 includes
if (eventName === 'error') {
aiMessage.text = '出现错误,请重试'
aiMessage.streaming = false
aiMessage.loading = false
@@ -249,27 +278,29 @@
flag = false
break
}
// TODO: 暂时不处理webAddress
if (event.includes('todo')) {
if (eventName === 'todo') {
break
}
let hasSketch = false
if (event.includes('sketchIDAndUrl')) {
hasSketch = true
}
let isNodeIdEvent = eventName === 'nodeId'
let hasSketch = eventName === 'sketch'
const dataLines = event
.split(/\n/)
.filter((line) => line.startsWith('data:'))
.map((line) => line.replace(/^data:\s*/, '').trim())
.map((line) => line.replace(/^data:\s*/, ''))
.filter((content) => content.startsWith('{') || content.startsWith('['))
console.log('dataLInes', dataLines)
// console.log('dataLInes', dataLines)
if (isNodeIdEvent) {
params.versionID = dataLines[0]
projectStore.setProject({ nodeId: dataLines[0] })
}
if (eventName === 'webAddress') {
console.log('webAddress-----', eventName, dataLines)
}
if (event.includes('tool')) {
if (eventName === 'tool') {
MyEvent.emit('loading-sketch')
}
@@ -278,21 +309,38 @@
try {
const jsonData = JSON.parse(jsonText)
console.log('jsonData', jsonData)
// console.log('jsonData', jsonData)
if (jsonData.webAddress) {
console.log('webAddress-----', jsonData)
}
if (jsonData.title) {
emits('setTitle', jsonData.title)
}
if (hasSketch) {
sketchList.value.push({
[Object.keys(jsonData)[0]]: jsonData[Object.keys(jsonData)[0]]
})
}
if (
jsonData.content &&
jsonData.content.length > 0 &&
jsonData.type !== 'end'
) {
contentBody += jsonData.content
aiMessage.text = contentBody
aiMessage.loading = false
if (eventName === 'report') {
reportsContent.value += jsonData.content
} else {
if (jsonData.reasoning) {
aiMessage.thinking = true
aiMessage.loading = false
aiMessage.thinkingText += jsonData.reasoning
} else {
aiMessage.thinking = false
if (
jsonData.content &&
jsonData.content.length > 0 &&
jsonData.type !== 'end'
) {
contentBody += jsonData.content
aiMessage.text = contentBody
aiMessage.loading = false
}
}
}
if (jsonData.type === 'end') {
aiMessage.streaming = false
@@ -319,6 +367,9 @@
console.warn('⚠️ JSON 格式错误,跳过:', jsonText)
}
}
// 更新上一个事件名称
previousEventName = eventName
}
}
} catch (error) {
@@ -378,7 +429,7 @@
}
// 处理对话列表,将连续的 assistant 消息合并为一条
const processDialogue = (dialogue, startIndex, existingImgList) => {
const processDialogue = (dialogue, startIndex, existingImgList, sessionId) => {
if (!dialogue || dialogue.length === 0) return []
const result = []
@@ -393,26 +444,30 @@
...item,
text: item.content,
isUser: true,
id: result.length + 1
id: result.length + 1,
sessionId: sessionId
})
i++
} else if (item.role === 'assistant') {
// assistant 角色,拼接直到下一个 user
let combinedContent = item.content || ''
let combinedThinkingText = item.reasoning || ''
// 继续往后找连续的 assistant 消息
let j = i + 1
while (j < dialogue.length && dialogue[j].role === 'assistant') {
combinedContent += dialogue[j].content || ''
combinedThinkingText += dialogue[j].reasoning || ''
j++
}
result.push({
...item,
content: combinedContent,
thinkingText: combinedThinkingText,
text: combinedContent,
isUser: false,
id: result.length + 1
id: result.length + 1,
sessionId: sessionId
})
i = j
@@ -422,7 +477,8 @@
...item,
text: item.content,
isUser: item.role === 'user',
id: result.length + 1
id: result.length + 1,
sessionId: sessionId
})
i++
}
@@ -430,6 +486,44 @@
return result
}
const processSession = (session, imgList, ancestorsList, idCounterRef) => {
if (!session) return
// 1. 在 dialogue 第一个 report 有值的项的 content 中插入报告卡片
if (session.dialogue) {
for (let i = 0; i < session.dialogue.length; i++) {
if (session.dialogue[i].report) {
session.dialogue[i].content =
`<slot slot-name="card" title="123">123</slot>` +
(session.dialogue[i].content || '')
break
}
}
}
// 2. 收集 report 内容并保存到 localStorage
let reportStr = ''
session.dialogue?.forEach((item) => {
if (item.report) {
reportStr += item.report
}
})
if (reportStr && session.id) {
localStorage.setItem(`reportsContent_${session.id}`, reportStr)
}
// 3. 收集 sketchIDAndUrl 到 imgList
if (session.sketchIDAndUrl) {
imgList.push(...session.sketchIDAndUrl)
}
// 4. 处理 dialogue
const list = processDialogue(session.dialogue, 0, imgList, session.id)
list.forEach((el) => {
el.id = idCounterRef.value++
})
ancestorsList.push(...list)
}
const setChatInfo = (info) => {
const initialData = agentStore.getInitialProjectData
@@ -454,37 +548,25 @@
messageList.value = []
return
}
const { ancestors, current } = data
let imgList = []
const ancestorsList = []
let ancestorsIdCounter = 1
if (ancestors) {
ancestors.forEach((item) => {
if (item.sketchIDAndUrl) {
imgList = imgList.concat(item.sketchIDAndUrl)
}
const list = processDialogue(item.dialogue, 0, imgList)
// 重新设置 id
list.forEach((el) => {
el.id = ancestorsIdCounter++
})
ancestorsList.push(...list)
})
}
const currentList = processDialogue(current?.dialogue, 0, imgList)
if (current.sketchIDAndUrl) {
imgList = imgList.concat(current.sketchIDAndUrl)
}
// 处理单个会话ancestor 或 current
currentList.forEach((el, index) => {
el.id = index + 1 + ancestorsList.length
const imgList = []
const ancestorsList = []
const idCounterRef = { value: 1 }
// 处理所有 ancestors
ancestors?.forEach((item) => {
processSession(item, imgList, ancestorsList, idCounterRef)
})
// 处理 current
processSession(current, imgList, ancestorsList, idCounterRef)
// 延迟设置新数据,确保 UI 有时间响应清空操作
nextTick(() => {
messageList.value = [...ancestorsList, ...currentList]
messageList.value = [...ancestorsList]
params.versionID = current?.id
sketchList.value = imgList
})