-
Load...
+
+

+ {{ $t('threeModel.loading') }}
+
@@ -190,30 +196,49 @@ defineExpose({open})
border: 1px solid #D9D9D9;
overflow: hidden;
}
+ > .icon{
+ position: absolute;
+ bottom: 2.4rem;
+ right: 2.4rem;
+ }
> .load{
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
- background: rgba(0, 0, 0, .2);
+ background: #e6e6e6;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
color: #fff;
+ > .text{
+ font-weight: 500;
+ font-size: 1.8rem;
+ line-height: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: #747474;
+ > img{
+ margin-right: 1rem;
+ }
+ }
> i{
font-size: 3rem;
}
> .loadBox{
- width: 15rem;
+ width: 26rem;
height: 1rem;
- border-radius: 1rem;
+ border-radius: 3.3rem;
background: #fff;
overflow: hidden;
+ margin-top: 1.2rem;
> .schedule{
height: 100%;
- background: greenyellow;
+ border-radius: 3.3rem;
+ background: #848484;
}
}
}
diff --git a/src/components/Canvas/FlowCanvas/components/tools/upload-file.vue b/src/components/Canvas/FlowCanvas/components/tools/upload-file.vue
index 27a6907..740e719 100644
--- a/src/components/Canvas/FlowCanvas/components/tools/upload-file.vue
+++ b/src/components/Canvas/FlowCanvas/components/tools/upload-file.vue
@@ -80,7 +80,7 @@
text-align: center;
line-height: 18px;
background-color: #fff;
- font-size: 6px;
+ font-size: 9px;
color: #000;
border: 1px solid #d9d9d9;
cursor: pointer;
diff --git a/src/lang/en.ts b/src/lang/en.ts
index c6a61b2..1750c74 100644
--- a/src/lang/en.ts
+++ b/src/lang/en.ts
@@ -187,5 +187,9 @@ export default {
},
assistant: {
inputPlaceholder: 'Ask anything',
+ },
+ //3d面板
+ threeModel: {
+ loading: 'Loading',
}
}
diff --git a/src/lang/zh-cn.ts b/src/lang/zh-cn.ts
index b98be7b..db123b9 100644
--- a/src/lang/zh-cn.ts
+++ b/src/lang/zh-cn.ts
@@ -182,5 +182,9 @@ export default {
},
assistant: {
inputPlaceholder: '请输入'
+ },
+ //3d面板
+ threeModel: {
+ loading: '加载中',
}
}
diff --git a/src/views/home/agent/components/Agent.vue b/src/views/home/agent/components/Agent.vue
index c075d81..f654e30 100644
--- a/src/views/home/agent/components/Agent.vue
+++ b/src/views/home/agent/components/Agent.vue
@@ -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
@@ -143,6 +146,7 @@
id: messageList.value.length + 1,
text: '',
isUser: false,
+ sessionId: 'projectStore.state.id',
loading: true,
thinking: false,
thinkingText: '',
@@ -206,11 +210,13 @@
// 流式响应处理
let contentBody = ''
let buffer = ''
+ const webAddressList = []
const reader = response.body?.getReader()
if (!reader) throw new Error('无法获取流读取器')
const decoder = new TextDecoder()
-
+ let previousEventName = '' // 记录上一个事件名称
+ let hasReportStarted = false // 标记 report 是否已经开始
try {
let flag = true
while (flag) {
@@ -232,16 +238,41 @@
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 += `
123`
+ hasReportStarted = true
}
- console.log('event', event)
- if (event.includes('error')) {
+
+ if (
+ previousEventName === 'report' &&
+ eventName !== 'report' &&
+ reportsContent.value
+ ) {
+ isGeneratingReport.value = false
+ localStorage.setItem(
+ 'reportsContent_' + projectStore.state.id,
+ reportsContent.value
+ )
+ }
+
+ previousEventName = eventName
+
+ // console.log('eventName:', eventName, 'event:', event)
+
+ // 根据事件名称精确判断,而不是用 includes
+ if (eventName === 'error') {
aiMessage.text = '出现错误,请重试'
aiMessage.streaming = false
aiMessage.loading = false
@@ -249,27 +280,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 +311,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.report
+ } 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 +369,9 @@
console.warn('⚠️ JSON 格式错误,跳过:', jsonText)
}
}
+
+ // 更新上一个事件名称
+ previousEventName = eventName
}
}
} catch (error) {
@@ -378,7 +431,7 @@
}
// 处理对话列表,将连续的 assistant 消息合并为一条
- const processDialogue = (dialogue, startIndex, existingImgList) => {
+ const processDialogue = (dialogue, startIndex, existingImgList, sessionId) => {
if (!dialogue || dialogue.length === 0) return []
const result = []
@@ -393,26 +446,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 +479,8 @@
...item,
text: item.content,
isUser: item.role === 'user',
- id: result.length + 1
+ id: result.length + 1,
+ sessionId: sessionId
})
i++
}
@@ -430,6 +488,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 =
+ `
123` +
+ (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 +550,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
})
diff --git a/src/views/home/agent/components/Item.vue b/src/views/home/agent/components/Item.vue
index e604da0..fa08495 100644
--- a/src/views/home/agent/components/Item.vue
+++ b/src/views/home/agent/components/Item.vue
@@ -16,7 +16,7 @@
class="img-item"
/>