feat: 对话显示sketch

This commit is contained in:
2026-02-25 15:10:03 +08:00
parent 74346516f1
commit 99ee2036a1
3 changed files with 178 additions and 119 deletions

View File

@@ -20,7 +20,7 @@
</template>
<script setup lang="ts">
import { ref, reactive, computed, onUnmounted, onMounted, nextTick } from 'vue'
import { ref, reactive, computed, onUnmounted, onMounted, nextTick,watch } from 'vue'
import List from './List.vue'
import Input from '../../components/Input.vue'
import { fetchAgentReply } from '@/api/agent'
@@ -31,6 +31,8 @@
const userStore = useUserInfoStore()
const agentStore = useAgentStore()
const projectStore = useProjectStore()
const emits = defineEmits(['update:sketchList'])
const props = withDefaults(
defineProps<{
title: string
@@ -41,6 +43,7 @@
)
const messageList = ref([])
const listRef = ref()
const isGenerating = ref(false)
const isPaused = ref(false) // 标记是否为主动暂停
@@ -58,6 +61,13 @@
imageUrlList: []
})
const sketchList = ref([])
watch(sketchList, (newVal) => {
console.log('添加图片链接--------');
emits('update:sketchList', newVal)
}, { deep: true })
// 每次请求时创建新的 AbortController
let abort: AbortController
@@ -81,9 +91,9 @@
if (initialData) {
// 等待页面渲染完成后自动发送初始消息
params.configParams = {
type: initialData.type ,
type: initialData.type,
region: initialData.area,
style: initialData.style ,
style: initialData.style,
temperature: 0.7
}
handleSendMessage({
@@ -97,10 +107,13 @@
}
})
const handleSendMessage = async (message: {
text: string
images: Array<{ url: string; name: string }>
}, skipUserMessage = false) => {
const handleSendMessage = async (
message: {
text: string
images: Array<{ url: string; name: string }>
},
skipUserMessage = false
) => {
console.log('Message sent:', message)
isPaused.value = false
isGenerating.value = true
@@ -197,6 +210,7 @@
console.log('传输结束 end---', contentBody)
aiMessage.streaming = false
aiMessage.loading = false
isGenerating.value = false
flag = false
break
}
@@ -217,12 +231,21 @@
isNodeIdEvent = true
// continue
}
console.log('event', event)
if (event.includes('error')) {
aiMessage.text = '出现错误,请重试'
aiMessage.streaming = false
aiMessage.loading = false
isGenerating.value = false
flag = false
break
}
const dataLines = event
.split(/\n/)
.filter((line) => line.startsWith('data:'))
.map((line) => line.replace(/^data:\s*/, '').trim())
console.log('dataLInes', dataLines)
// console.log('dataLInes', dataLines)
if (isNodeIdEvent) {
params.versionID = dataLines[0]
}
@@ -232,10 +255,14 @@
try {
const jsonData = JSON.parse(jsonText)
console.log('jsonData', jsonData);
// 赋值 project_id 和 version_id
if (jsonData.project_id) params.projectID = jsonData.project_id
if (jsonData.version_id) params.versionID = jsonData.version_id
// if (jsonData.project_id) params.projectID = jsonData.project_id
// if (jsonData.version_id) params.versionID = jsonData.version_id
if (jsonData.image_url) {
sketchList.value.push(jsonData.image_url)
}
if (
jsonData.content &&
jsonData.content.length > 0 &&
@@ -243,6 +270,7 @@
) {
contentBody += jsonData.content
aiMessage.text = contentBody
aiMessage.loading = false
}
if (jsonData.type === 'end') {
aiMessage.streaming = false

View File

@@ -4,13 +4,21 @@
:class="type === 'sketch' ? 'sketch-preview' : 'report-preview'"
>
<template v-if="type === 'sketch'">
<div class="sketch-item" v-for="item in 12">
<div
class="sketch-item"
v-for="(item, index) in sketchList"
:key="'sketch-item-' + index"
>
<Menu class="menu-btn" @click="handleClickMenu" />
<div class="edit-btn flex align-center space-between" @click="handleClickEdit">
<div>Edit</div>
<img src="@/assets/images/arrow-top-right.png" alt="" />
<img src="@/assets/images/arrow-top-right.png" />
</div>
<img :src="LoadingImg" alt="" />
<img
:src="getImageSrc(item, index)"
:alt="'sketch-' + index"
@load="handleImageLoad(index)"
/>
</div>
</template>
<div v-else class="reportBorder">
@@ -28,116 +36,127 @@
</div>
</div>
<div class="content">
# 一级标题
# 一级标题
<br />
# 一级标题
# 一级标题
<br />
# 一级标题
# 一级标题
<br />
# 一级标题
# 一级标题
<br />
# 一级标题
# 一级标题
<br />
# 一级标题
# 一级标题
<br />
# 一级标题
# 一级标题
<br />
# 一级标题
<br />
# 一级标题
# 一级标题
<br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题
# 一级标题
<br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题 <br />
# 一级标题
<br />
# 一级标题
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { ref, reactive } from 'vue'
import Menu from './Menu.vue'
import LoadingImg from '@/assets/images/sketch-loading.gif'
import reportNull from '@/assets/images/reportNull.png'
import LoadingImg from '@/assets/images/sketch-loading.gif'
import reportNull from '@/assets/images/reportNull.png'
// 存储每个图片的加载状态
const loadedStatus = reactive<Record<number, boolean>>({})
const props = withDefaults(
defineProps<{
type: 'sketch' | 'report'
sketchList: Array<string>
}>(),
{
type: 'sketch'
type: 'sketch',
sketchList: []
}
)
// 图片加载完成时触发
const handleImageLoad = (index: number) => {
loadedStatus[index] = true
}
const handleClickEdit = () => {
// 编辑按钮点击逻辑
console.log('Edit button clicked')
}
const handleClickMenu = () => {
// 菜单按钮点击逻辑
console.log('Menu button clicked')
}
// 获取当前显示的图片源
const getImageSrc = (item: string, index: number) => {
return loadedStatus[index] ? item : LoadingImg
}
const handleClickEdit = () => {
// 编辑按钮点击逻辑
console.log('Edit button clicked')
}
const handleClickMenu = () => {
// 菜单按钮点击逻辑
console.log('Menu button clicked')
}
</script>
<style lang="less" scoped>
@@ -172,13 +191,13 @@
font-size: 1.4rem;
padding: 0 0.9rem 0 1.4rem;
cursor: pointer;
img{
img {
width: 1.8rem;
height: 1.8rem;
}
}
}
.reportBorder{
.reportBorder {
position: relative;
display: flex;
align-items: center;
@@ -190,7 +209,11 @@
&::before {
content: '';
position: absolute;
background: linear-gradient(119.03deg, rgba(233, 121, 60, 0.3) 1.61%, rgba(255, 207, 144, 0.3) 101.01%);
background: linear-gradient(
119.03deg,
rgba(233, 121, 60, 0.3) 1.61%,
rgba(255, 207, 144, 0.3) 101.01%
);
border-radius: 2.3rem;
z-index: -1;
width: 100%;
@@ -205,20 +228,20 @@
height: calc(100% - var(--border-width) * 2);
border-radius: 2rem;
display: flex;
.report-content-null{
.report-content-null {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
}
.report-content{
.report-content {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
.downBtnBox{
.downBtnBox {
padding: 2.2rem 5.2rem 0;
.downBtn{
.downBtn {
display: flex;
width: 11.2rem;
justify-content: center;
@@ -228,16 +251,16 @@
background-color: #ff7a51;
color: #fff;
cursor: pointer;
.icon{
margin-right: .02rem;
.icon {
margin-right: 0.02rem;
}
span{
span {
font-weight: 500;
font-size: 1.2rem;
}
}
}
.content{
.content {
word-break: break-word;
white-space: pre-wrap;
overflow-y: auto;

View File

@@ -1,14 +1,12 @@
<template>
<div class="agent-wrapper flex space-between">
<div class="openVersionTree">
<div class="btn" @click="versionTreeData.drawer = true">
Version Tree
</div>
<div class="btn" @click="versionTreeData.drawer = true">Version Tree</div>
</div>
<div class="content-wrapper">
<Agent :title="agentTitle" />
<Agent :title="agentTitle" @update:sketchList="updateSketchList" />
<div class="preview-wrapper">
<Preview :type="previewType" />
<Preview :type="previewType" :sketchList="sketchList" />
</div>
</div>
<VersionTreeIndex v-model:versionTreeData="versionTreeData" />
@@ -22,11 +20,17 @@
import VersionTreeIndex from './components/versionTree/index.vue'
const agentTitle = ref('Retro Sofa Sketch')
const previewType = ref<'sketch' | 'report'>('report')
const previewType = ref<'sketch' | 'report'>('sketch')
const sketchList = ref([])
const updateSketchList = (newVal) => {
console.log('newVal', newVal)
sketchList.value = newVal
}
const versionTreeData = ref({
drawer:false,
list:computed(()=>{
drawer: false,
list: computed(() => {
return []
})
})
@@ -39,13 +43,13 @@
border-top: 0.1rem solid #c9c9c9;
padding: 0rem 2.3rem 6rem 2.8rem;
flex-direction: column;
.openVersionTree{
.openVersionTree {
padding: 2rem 0rem;
width: 100%;
display: flex;
justify-content: flex-end;
height: min-content;
> .btn{
> .btn {
padding: 1.5rem 1.45rem;
font-weight: 500;
font-size: 1.4rem;
@@ -57,14 +61,18 @@
content: '';
position: absolute;
inset: -1px;
background: linear-gradient(119.03deg, rgba(233, 121, 60, 0.8) 1.61%, rgba(255, 207, 144, 0.8) 101.01%);
background: linear-gradient(
119.03deg,
rgba(233, 121, 60, 0.8) 1.61%,
rgba(255, 207, 144, 0.8) 101.01%
);
border-radius: 2.2rem;
z-index: -1;
}
}
}
.content-wrapper{
.content-wrapper {
display: flex;
flex: 1;
justify-content: space-between;