This commit is contained in:
lzp
2026-03-16 16:51:13 +08:00
20 changed files with 280 additions and 101 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 349 B

BIN
src/assets/images/link.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 426 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

View File

@@ -132,7 +132,6 @@
imageUrl: attrs.node?.data?.originalImage, imageUrl: attrs.node?.data?.originalImage,
...data, ...data,
} }
console.log(subordNode)
const taskList = await currentComponent.value.api(apiData).then((rv)=>{ const taskList = await currentComponent.value.api(apiData).then((rv)=>{
return rv return rv
}) || [] }) || []
@@ -143,6 +142,7 @@
positionY: (index + subordNodes.length) * (50 + 250), positionY: (index + subordNodes.length) * (50 + 250),
data: { data: {
superiorID: attrs.node.id, superiorID: attrs.node.id,
superiorNodeType: attrs.node?.data?.type,
createIndexPosition: index, createIndexPosition: index,
tier: currentComponent.value.tier, tier: currentComponent.value.tier,
isActive: index == 0 && subordNodes.length == 0, isActive: index == 0 && subordNodes.length == 0,

View File

@@ -7,7 +7,7 @@
:class="{'active': config.isActive}" :class="{'active': config.isActive}"
@click="setSelectTaskId(item.taskId)" @click="setSelectTaskId(item.taskId)"
> >
<div class="header" v-if="item.status == 'RETURNED'" v-show="showHeader && item.taskId === data.selectTaskId" @mousedown.stop> <div class="header" v-if="item.status == 'RETURNED'" v-show="showHeader && config.isActive" @mousedown.stop>
<span class="icon"> <span class="icon">
<svg-icon name="chat-compose" size="20" size-unit="px" /> <svg-icon name="chat-compose" size="20" size-unit="px" />
</span> </span>
@@ -61,7 +61,9 @@
import { downloadImage } from '../../../tools/tools' import { downloadImage } from '../../../tools/tools'
import { reactive, ref, onBeforeUnmount, useAttrs, inject, watch, computed, onMounted } from 'vue' import { reactive, ref, onBeforeUnmount, useAttrs, inject, watch, computed, onMounted } from 'vue'
import HighlightAdmin from '@/components/highlightAdmin.vue' import HighlightAdmin from '@/components/highlightAdmin.vue'
import { NODE_DATATYPE } from '../../tools/index.d'
const openImagePreview = inject('openImagePreview') as (url: string) => void const openImagePreview = inject('openImagePreview') as (url: string) => void
const openThreeModelPreview = inject('openThreeModelPreview') as (url: string) => void
const props = defineProps({ const props = defineProps({
node: { node: {
type: Object, type: Object,
@@ -83,8 +85,8 @@
'send-to-back', 'send-to-back',
'update-data' 'update-data'
]) ])
const attrs = useAttrs() // const attrs = useAttrs()
const showHeader = ref(!!attrs.node?.data?.isHeader) const showHeader = ref(!!props.node?.data?.isHeader)
const showMenu = ref(false) const showMenu = ref(false)
const clickTaskId = ref('') const clickTaskId = ref('')
const generateManager = inject('generateManager') as any const generateManager = inject('generateManager') as any
@@ -97,6 +99,7 @@
const data = reactive({ const data = reactive({
selectTaskId: props.data?.selectTaskId || '', selectTaskId: props.data?.selectTaskId || '',
imageProcessTasks: props.data?.imageProcessTasks, imageProcessTasks: props.data?.imageProcessTasks,
superiorNodeType: props?.node?.data?.superiorNodeType,
isActive: props.data?.isActive || false, isActive: props.data?.isActive || false,
}) })
const setSelectTaskId = (taskId: string) => { const setSelectTaskId = (taskId: string) => {
@@ -171,7 +174,11 @@
} }
]) ])
const onPreview = (url: string) => { const onPreview = (url: string) => {
openImagePreview(url) if(data.superiorNodeType == NODE_DATATYPE.TO_3D_MODEL){
openThreeModelPreview(url)
}else{
openImagePreview(url)
}
} }
const onDownload = (url: string) => { const onDownload = (url: string) => {
downloadImage(url, 'image.png') downloadImage(url, 'image.png')

View File

@@ -62,6 +62,7 @@ const {} = toRefs(data);
</div> </div>
</div> </div>
</div> </div>
<div class="download">{{ $t('threeModel.download') }}</div>
</div> </div>
</template> </template>
<style lang="less" scoped> <style lang="less" scoped>
@@ -76,6 +77,20 @@ const {} = toRefs(data);
line-height: 2.7rem; line-height: 2.7rem;
color: #000; color: #000;
} }
> .download{
margin-left: 4.2rem;
margin-top: 24.8rem;
line-height: 3rem;
width: 20rem;
border-radius: 1.5rem;
color: #fff;
background-color: #ff7a51;
font-weight: 600;
font-style: Semibold;
font-size: 1.2rem;
text-align: center;
cursor: pointer;
}
> .detail{ > .detail{
> .name{ > .name{
> .title{ > .title{

View File

@@ -1,18 +1,25 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue"; import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
import threeGlb from '@/assets/images/three/sample.glb'
import model from './model.vue' import model from './model.vue'
import detail from './detail.vue' import detail from './detail.vue'
//const props = defineProps({ const props = defineProps({
//}) currentUrl: {
type: String,
default: ''
}
})
//const emit = defineEmits([ //const emit = defineEmits([
//]) //])
let data = reactive({ let data = reactive({
}) })
const modelRef = ref(null) const modelRef = ref(null)
onMounted(()=>{ onMounted(()=>{
modelRef.value.open() console.log(props.currentUrl)
modelRef.value.open(threeGlb)
}) })
onUnmounted(()=>{ onUnmounted(()=>{
}) })

View File

@@ -5,7 +5,6 @@ import { useI18n } from 'vue-i18n'
import gsap from 'gsap'; import gsap from 'gsap';
import * as THREE from 'three'; import * as THREE from 'three';
import { initThree,clearModel,addModel,getModelInfo,calculateCameraPosition } from './threeTool' import { initThree,clearModel,addModel,getModelInfo,calculateCameraPosition } from './threeTool'
import threeGlb from '@/assets/images/three/sample.glb'
//const props = defineProps({ //const props = defineProps({
//}) //})
@@ -134,7 +133,7 @@ const setModel = async (url:any)=>{
await addModel(url,controls,camera,pointLight,group,load) await addModel(url,controls,camera,pointLight,group,load)
// addMaterial() // addMaterial()
} }
const open = async ()=>{ const open = async (url)=>{
load.value.state = true load.value.state = true
await nextTick(()=>{ await nextTick(()=>{
init() init()
@@ -152,7 +151,7 @@ const open = async ()=>{
// composer.render(); // composer.render();
}; };
animate(); animate();
await setModel(threeGlb) await setModel(url)
load.value.state = false load.value.state = false
} }

View File

@@ -56,7 +56,9 @@
/> />
<image-preview ref="imagePreviewRef" /> <image-preview ref="imagePreviewRef" />
<baseModal ref="threeModelRef"> <baseModal ref="threeModelRef">
<threeModel /> <template v-slot="{ currentUrl }">
<threeModel :currentUrl="currentUrl" />
</template>
</baseModal> </baseModal>
</template> </template>
@@ -215,7 +217,12 @@
const openImagePreview = (url: string) => { const openImagePreview = (url: string) => {
imagePreviewRef.value.open(url) imagePreviewRef.value.open(url)
} }
/** 打开3D预览 */
const openThreeModelPreview = (url: string) => {
threeModelRef.value.open(url)
}
provide('openImagePreview', openImagePreview) provide('openImagePreview', openImagePreview)
provide('openThreeModelPreview', openThreeModelPreview)
onMounted(async () => { onMounted(async () => {
// window['vueFlow'] = vueFlow // window['vueFlow'] = vueFlow

View File

@@ -7,6 +7,7 @@ interface NodeData {
tier?: string// 节点层级 tier?: string// 节点层级
isHeader?: boolean// 是否显示头 isHeader?: boolean// 是否显示头
superiorID?: string// 上级节点ID superiorID?: string// 上级节点ID
superiorNodeType?: string// 上级节点类型
disableDelete?: boolean// 是否禁用删除 disableDelete?: boolean// 是否禁用删除
disableCopy?: boolean// 是否禁用复制 disableCopy?: boolean// 是否禁用复制
originalImage?: string// 要进行生成的图片 originalImage?: string// 要进行生成的图片

View File

@@ -13,7 +13,7 @@
</div> </div>
</template> </template>
<div class="modal-box"> <div class="modal-box">
<slot></slot> <slot v-if="currentUrl" :currentUrl="currentUrl"></slot>
</div> </div>
</el-dialog> </el-dialog>
</template> </template>
@@ -27,11 +27,14 @@
} }
}) })
const showDialog = ref(false) const showDialog = ref(false)
let currentUrl = ref('')
const open = (url_: any) => { const open = (url_: any) => {
currentUrl.value = url_
showDialog.value = true showDialog.value = true
} }
const close = () => { const close = () => {
showDialog.value = false showDialog.value = false
currentUrl.value = ''
} }
defineExpose({ defineExpose({

View File

@@ -151,7 +151,8 @@ export default {
copySuccess: 'Text copied to clipboard', copySuccess: 'Text copied to clipboard',
copyFaild: 'Copy failed. Your browser may be restricting clipboard access. Please try copying manually.', copyFaild: 'Copy failed. Your browser may be restricting clipboard access. Please try copying manually.',
Download: 'Download', Download: 'Download',
deleteSuccess: 'Successfully deleted' deleteSuccess: 'Successfully deleted',
thinking: 'Thinking...',
}, },
// Version Tree // Version Tree
@@ -191,5 +192,6 @@ export default {
//3d面板 //3d面板
threeModel: { threeModel: {
loading: 'Loading', loading: 'Loading',
download: 'Download',
} }
} }

View File

@@ -146,7 +146,8 @@ export default {
copyFaild: copyFaild:
'复制失败。您的浏览器可能限制了剪贴板访问,请允许浏览器访问剪贴板或尝试手动复制。', '复制失败。您的浏览器可能限制了剪贴板访问,请允许浏览器访问剪贴板或尝试手动复制。',
Download: '下载', Download: '下载',
deleteSuccess:'删除成功' deleteSuccess: '删除成功',
thinking:'已思考'
}, },
// Version Tree // Version Tree
@@ -186,5 +187,6 @@ export default {
//3d面板 //3d面板
threeModel: { threeModel: {
loading: '加载中', loading: '加载中',
download: '下载'
} }
} }

View File

@@ -146,7 +146,7 @@
id: messageList.value.length + 1, id: messageList.value.length + 1,
text: '', text: '',
isUser: false, isUser: false,
sessionId: 'projectStore.state.id', sessionId: projectStore.state.id,
loading: true, loading: true,
thinking: false, thinking: false,
thinkingText: '', thinkingText: '',
@@ -210,7 +210,6 @@
// 流式响应处理 // 流式响应处理
let contentBody = '' let contentBody = ''
let buffer = '' let buffer = ''
const webAddressList = []
const reader = response.body?.getReader() const reader = response.body?.getReader()
if (!reader) throw new Error('无法获取流读取器') if (!reader) throw new Error('无法获取流读取器')
@@ -248,10 +247,8 @@
?.trim() || '' ?.trim() || ''
if (!hasReportStarted && eventName === 'report') { if (!hasReportStarted && eventName === 'report') {
console.log('开始生成报告--------')
isGeneratingReport.value = true isGeneratingReport.value = true
contentBody += `<slot slot-name="card" title="123">123</slot>` contentBody += `<slot slot-name="card" title="123" content="123">123</slot>`
hasReportStarted = true hasReportStarted = true
} }
@@ -261,7 +258,7 @@
reportsContent.value reportsContent.value
) { ) {
isGeneratingReport.value = false isGeneratingReport.value = false
localStorage.setItem( sessionStorage.setItem(
'reportsContent_' + projectStore.state.id, 'reportsContent_' + projectStore.state.id,
reportsContent.value reportsContent.value
) )
@@ -286,7 +283,7 @@
let isNodeIdEvent = eventName === 'nodeId' let isNodeIdEvent = eventName === 'nodeId'
let hasSketch = eventName === 'sketch' let hasSketch = eventName === 'sketchIDAndUrl'
const dataLines = event const dataLines = event
.split(/\n/) .split(/\n/)
@@ -295,12 +292,18 @@
.filter((content) => content.startsWith('{') || content.startsWith('[')) .filter((content) => content.startsWith('{') || content.startsWith('['))
// console.log('dataLInes', dataLines) // console.log('dataLInes', dataLines)
if (isNodeIdEvent) { if (isNodeIdEvent) {
params.versionID = dataLines[0] const versionID = event.split(/\n/)
projectStore.setProject({ nodeId: dataLines[0] }) .filter((line) => line.startsWith('data:'))
} .map((line) => line.replace(/^data:\s*/, ''))[0]
if (eventName === 'webAddress') {
console.log('webAddress-----', eventName, dataLines) debugger
params.versionID = versionID
projectStore.setProject({ nodeId: versionID })
} }
// if (eventName === 'webAddress') {
// console.log('webAddress111111111111111', eventName, dataLines)
// debugger
// }
if (eventName === 'tool') { if (eventName === 'tool') {
MyEvent.emit('loading-sketch') MyEvent.emit('loading-sketch')
@@ -313,7 +316,8 @@
const jsonData = JSON.parse(jsonText) const jsonData = JSON.parse(jsonText)
// console.log('jsonData', jsonData) // console.log('jsonData', jsonData)
if (jsonData.webAddress) { if (jsonData.webAddress) {
console.log('webAddress-----', jsonData) aiMessage.webAddress = JSON.parse(jsonData.webAddress)
contentBody += `<slot slot-name="url">123</slot>`
} }
if (jsonData.title) { if (jsonData.title) {
emits('setTitle', jsonData.title) emits('setTitle', jsonData.title)
@@ -323,6 +327,7 @@
sketchList.value.push({ sketchList.value.push({
[Object.keys(jsonData)[0]]: jsonData[Object.keys(jsonData)[0]] [Object.keys(jsonData)[0]]: jsonData[Object.keys(jsonData)[0]]
}) })
MyEvent.emit('OpenSketch')
} }
if (eventName === 'report') { if (eventName === 'report') {
reportsContent.value += jsonData.report reportsContent.value += jsonData.report
@@ -439,7 +444,6 @@
while (i < dialogue.length) { while (i < dialogue.length) {
const item = dialogue[i] const item = dialogue[i]
if (item.role === 'user') { if (item.role === 'user') {
// user 角色直接添加 // user 角色直接添加
result.push({ result.push({
@@ -496,7 +500,7 @@
for (let i = 0; i < session.dialogue.length; i++) { for (let i = 0; i < session.dialogue.length; i++) {
if (session.dialogue[i].report) { if (session.dialogue[i].report) {
session.dialogue[i].content = session.dialogue[i].content =
`<slot slot-name="card" title="123">123</slot>` + `<slot slot-name="card" title="123" content="123">123</slot>` +
(session.dialogue[i].content || '') (session.dialogue[i].content || '')
break break
} }
@@ -511,12 +515,12 @@
} }
}) })
if (reportStr && session.id) { if (reportStr && session.id) {
localStorage.setItem(`reportsContent_${session.id}`, reportStr) sessionStorage.setItem(`reportsContent_${session.id}`, reportStr)
} }
// 3. 收集 sketchIDAndUrl 到 imgList // 3. 收集 sketchIDAndUrl 到 imgList
if (session.sketchIDAndUrl) { if (session.sketchIDAndUrl) {
imgList.push(...session.sketchIDAndUrl) imgList.push(session.sketchIDAndUrl)
} }
// 4. 处理 dialogue // 4. 处理 dialogue

View File

@@ -22,7 +22,7 @@
class="thinking-header flex align-center" class="thinking-header flex align-center"
@click="toggleThinkingCollapsed" @click="toggleThinkingCollapsed"
> >
<span>思考中</span> <span>{{ t('agent.thinking') }}</span>
<!-- <SvgIcon :name="content.thinkingCollapsed ? 'arrowDown' : 'arrowUp'" size="16" color="#666" /> --> <!-- <SvgIcon :name="content.thinkingCollapsed ? 'arrowDown' : 'arrowUp'" size="16" color="#666" /> -->
</div> </div>
<div class="thinking-content" v-show="!content.thinkingCollapsed"> <div class="thinking-content" v-show="!content.thinkingCollapsed">
@@ -40,10 +40,20 @@
<template v-slot:s-card="{ children: children, ...attrs }"> <template v-slot:s-card="{ children: children, ...attrs }">
<Card :title="attrs.title" @click.native="handleClickReport" /> <Card :title="attrs.title" @click.native="handleClickReport" />
</template> </template>
<template v-slot:s-url="{ children: children }">
<Url :list="content.webAddress" @click.native="handleClickUrls" />
</template>
</VueMarkdown> </VueMarkdown>
<div
class="web-address flex align-center"
v-show="content.webAddress?.length > 0"
>
<img src="@/assets/images/search.png" class="search-icon" />
<span>{{ content.webAddress?.length }} web pages have been retrieved.</span>
</div>
</div> </div>
<div <div
v-show="!content.thinking" v-show="!content.streaming"
class="operate flex" class="operate flex"
:class="{ 'is-user': content.isUser }" :class="{ 'is-user': content.isUser }"
> >
@@ -96,13 +106,13 @@
isLast: Boolean isLast: Boolean
}>() }>()
watch( // watch(
() => props.content, // () => props.content,
(newVal) => { // (newVal) => {
console.log('newVal-----', newVal) // console.log('newVal-----', newVal)
}, // },
{ immediate: true } // { immediate: true }
) // )
const emit = defineEmits(['regenerate']) const emit = defineEmits(['regenerate'])
@@ -215,6 +225,7 @@
// 点击显示报告 // 点击显示报告
} }
const handleClickUrls = (data) => { const handleClickUrls = (data) => {
MyEvent.emit('openUrls', props.content.webAddress)
// 点击显示来源 // 点击显示来源
} }
</script> </script>
@@ -260,6 +271,24 @@
width: fit-content; width: fit-content;
max-width: 82%; max-width: 82%;
} }
.web-address {
width: fit-content;
min-width: 22.5rem;
line-height: 2.6rem;
padding: 0 1rem;
border-radius: 1.5rem;
color: #000000a6;
border: 0.1rem solid #0000001a;
font-family: 'Regular';
font-weight: 400;
font-size: 1.2rem;
margin-top: 1rem;
column-gap: 0.8rem;
.search-icon {
width: 1.4rem;
height: 1.4rem;
}
}
} }
.operate { .operate {
margin-top: 1.3rem; margin-top: 1.3rem;

View File

@@ -50,29 +50,42 @@
<img src="@/assets/images/sketch-loading.gif" alt="loading" /> <img src="@/assets/images/sketch-loading.gif" alt="loading" />
</div> </div>
</template> </template>
<template v-else-if="type === 'url'">
<div class="url-list flex">
<div class="url-item" v-for="item in urlList" :key="item">
<div class="url-title" @click="handleClickUrl(item)">
{{ item }}
<img src="@/assets/images/link-outer.png" class="link-outer" />
</div>
<div class="url-link">{{ item }}</div>
</div>
</div>
</template>
<div v-else class="reportBorder"> <div v-else class="reportBorder">
<div class="report"> <div class="report">
<div v-if="false" class="report-content-null"> <!-- <div v-if="false" class="report-content-null">
<img :src="reportNull" alt="" /> <img :src="reportNull" alt="" />
</div> </div> -->
<div v-else class="report-content"> <template v-if="reportType === 'report'">
<div class="downBtnBox"> <div class="report-content">
<div class="downBtn" @click="handleDownloadMd"> <div class="downBtnBox">
<div class="icon"> <div class="downBtn" @click="handleDownloadMd">
<SvgIcon name="reportDown" size="16"></SvgIcon> <div class="icon">
<SvgIcon name="reportDown" size="16"></SvgIcon>
</div>
<span>{{ $t('agent.Download') }}</span>
</div> </div>
<span>{{ $t('agent.Download') }}</span> </div>
<div class="content">
<VueMarkdown
:custom-attrs="customAttrs"
:markdown="markdownContent"
:rehype-plugins="[rehypeRaw]"
>
</VueMarkdown>
</div> </div>
</div> </div>
<div class="content"> </template>
<VueMarkdown
:custom-attrs="customAttrs"
:markdown="markdownContent"
:rehype-plugins="[rehypeRaw]"
>
</VueMarkdown>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -101,7 +114,7 @@
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
type: 'sketch' | 'report' type: 'sketch' | 'report' | 'url'
sketchList: Array<string> sketchList: Array<string>
}>(), }>(),
{ {
@@ -125,17 +138,26 @@
const sessionId = ref('') const sessionId = ref('')
const markdownContent = ref('') const markdownContent = ref('')
const setSessionId = (id: string) => { const urlList = ref([])
const reportType = ref<'report' | 'urls'>('report')
const setSessionId = (id: string) => {
reportType.value = 'report'
sessionId.value = id sessionId.value = id
} }
const setUrls = (list: string[]) => {
reportType.value = 'urls'
urlList.value = list
// urlList.value = [
// 'https://furnitureindustrynews.substack.com/p/what-2026-really-looks-like-for-furniture',
// 'https://furnitureindustrynews.substack.com/p/what-2026-really-looks-like-for-furniture',
// 'https://furnitureindustrynews.substack.com/p/what-2026-really-looks-like-for-furniture'
// ]
}
watch( watch(
() => sessionId.value, () => sessionId.value,
(newVal) => { (newVal) => {
if (newVal) { if (newVal) {
markdownContent.value = localStorage.getItem(`reportsContent_${newVal}`) markdownContent.value = sessionStorage.getItem(`reportsContent_${newVal}`)
console.log('markdownContent-----', markdownContent.value);
} }
} }
) )
@@ -143,9 +165,7 @@ const setSessionId = (id: string) => {
// 图片加载完成时触发 // 图片加载完成时触发
const handleImageLoad = (index: number) => { const handleImageLoad = (index: number) => {
loadedStatus[index] = true loadedStatus[index] = true
if (index === props.sketchList.length - 1) { showLoading.value = false
showLoading.value = false
}
} }
// 获取当前显示的图片源 // 获取当前显示的图片源
@@ -206,15 +226,20 @@ const setSessionId = (id: string) => {
const handleLoadingSketch = () => { const handleLoadingSketch = () => {
showLoading.value = true showLoading.value = true
} }
watch(
() => props.sketchList, const handleClickUrl = (item: string) => {
(val) => { window.open(item, '_blank')
if (val.length > 0) { }
showLoading.value = false
} // watch(
}, // () => props.sketchList,
{ deep: true } // (val) => {
) // if (val.length > 0) {
// showLoading.value = false
// }
// },
// { deep: true }
// )
onMounted(() => { onMounted(() => {
MyEvent.add('loading-sketch', handleLoadingSketch) MyEvent.add('loading-sketch', handleLoadingSketch)
}) })
@@ -223,7 +248,8 @@ const setSessionId = (id: string) => {
}) })
defineExpose({ defineExpose({
setSessionId setSessionId,
setUrls
}) })
</script> </script>
@@ -280,6 +306,38 @@ const setSessionId = (id: string) => {
} }
} }
} }
.url-list {
flex: 1;
flex-wrap: wrap;
column-gap: 4rem;
row-gap: 3rem;
.url-item {
width: 24rem;
height: 28.7rem;
word-break: break-all;
background: url('@/assets/images/web-card.png') no-repeat;
background-size: 100% 100%;
padding: 5rem 1.5rem;
.url-title {
cursor: pointer;
font-family: 'Medium';
font-size: 1.6rem;
color: #232323;
padding-bottom: 0.6rem;
.link-outer {
width: 1.2rem;
height: 1.2rem;
}
}
.url-link {
font-family: 'Medium';
font-style: italic;
font-size: 1.2rem;
color: #7c7c7c;
user-select: text;
}
}
}
.reportBorder { .reportBorder {
position: relative; position: relative;
display: flex; display: flex;
@@ -289,6 +347,7 @@ const setSessionId = (id: string) => {
flex: 1; flex: 1;
overflow: hidden; overflow: hidden;
height: 100%; height: 100%;
&::before { &::before {
content: ''; content: '';
position: absolute; position: absolute;
@@ -348,6 +407,7 @@ const setSessionId = (id: string) => {
white-space: pre-wrap; white-space: pre-wrap;
overflow-y: auto; overflow-y: auto;
margin: 2rem; margin: 2rem;
padding: 0 8.8rem 8.8rem;
} }
} }
} }

View File

@@ -1,49 +1,79 @@
<template> <template>
<div class="report-card"> <div class="report-card" :class="{ 'is-url': isUrl }">
<div class="report-card-header"> <div class="report-card-header">
<span>{{ title }}</span> <span v-if="!isUrl">{{ title }}</span>
<div v-else class="web-sources flex align-center">
<span>Web Sources</span>
<img src="@/assets/images/link.png" class="link-icon" />
</div>
</div> </div>
<div class="report-card-content"> <div class="report-card-content">
<span>{{ title }}</span> <span v-if="!isUrl">markdown.md</span>
<span v-else>Destination URL</span>
</div> </div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
const props = defineProps<{ // const props = defineProps<{
title: string // title: string
}>() // isUrl?: boolean
// }>()
const props = withDefaults(
defineProps<{
title?: string
content?: string
isUrl?: boolean
}>(),
{
isUrl: false,
title: '',
content: ''
}
)
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.report-card { .report-card {
cursor: pointer; cursor: pointer;
width:100%; width: 100%;
margin: 2.4rem 0; margin: 2.4rem 0;
min-height: 11.2rem; min-height: 11.2rem;
background: url('@/assets/images/report-card.png') no-repeat; background: url('@/assets/images/report-card.png') no-repeat;
background-size: 100% 100%; background-size: 100% 100%;
padding: 2.9rem; padding: 2.9rem;
overflow: hidden; overflow: hidden;
&.is-url {
background: url('@/assets/images/link-card.png') no-repeat;
background-size: 100% 100%;
}
// &:first-of-type{ // &:first-of-type{
// margin-top: 0; // margin-top: 0;
// } // }
&-header { &-header {
font-family: 'Medium'; font-family: 'Medium';
font-size: 1.6rem; font-size: 1.6rem;
margin-bottom: 1.3rem; margin-bottom: 1.3rem;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
display: -webkit-box; display: -webkit-box;
-webkit-line-clamp: 3; -webkit-line-clamp: 3;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
line-clamp: 3; line-clamp: 3;
.web-sources {
column-gap: 0.8rem;
.link-icon {
width: 1.6rem;
height: 1.6rem;
}
}
}
&-content {
font-family: 'Regular';
font-weight: 300;
font-size: 1.6rem;
color: #7c7c7c;
} }
&-content{
font-family: 'Regular';
font-weight: 300;
font-size: 1.6rem;
color: #7c7c7c;
}
} }
</style> </style>

View File

@@ -1,5 +1,5 @@
<template> <template>
<ReportCard :report="{title: 'WebSources', content: 'Destination URL'}"/> <ReportCard is-url :report="{title: 'WebSources', content: 'Destination URL'}"/>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">

View File

@@ -103,11 +103,16 @@
const proJectId = computed(() => route.params.id) const proJectId = computed(() => route.params.id)
const handleOpenReport = (data) => { const handleOpenReport = (data, isUrls = false) => {
previewRef.value.setSessionId(data) previewRef.value.setSessionId(data)
previewType.value = 'report' previewType.value = 'report'
} }
const handleOpenUrls = (data) => {
previewRef.value.setUrls(data)
previewType.value = 'url'
}
watch( watch(
() => proJectId.value, () => proJectId.value,
(newVal, oldVal) => { (newVal, oldVal) => {
@@ -120,6 +125,10 @@ const handleOpenReport = (data) => {
onMounted(() => { onMounted(() => {
MyEvent.add('openReport', handleOpenReport) MyEvent.add('openReport', handleOpenReport)
MyEvent.add('openUrls', handleOpenUrls)
MyEvent.add('OpenSketch', ()=>{
previewType.value = 'sketch'
})
projectStore.clearProject() projectStore.clearProject()
if (proJectId.value) { if (proJectId.value) {
handleGetProjectInfoAndHistory() handleGetProjectInfoAndHistory()
@@ -127,6 +136,10 @@ const handleOpenReport = (data) => {
}) })
onUnmounted(() => { onUnmounted(() => {
MyEvent.remove('openReport', handleOpenReport) MyEvent.remove('openReport', handleOpenReport)
MyEvent.remove('openUrls', handleOpenUrls)
MyEvent.remove('OpenSketch', ()=>{
previewType.value = 'sketch'
})
}) })
</script> </script>