|
|
@@ -10,39 +10,48 @@
|
|
|
@cancel="$emit('close')"
|
|
|
>
|
|
|
<div class="di-header">
|
|
|
- <span class="di-header__title">数据解读</span>
|
|
|
+ <span class="di-header__title"><img :src="aiIcon" width="20" height="20" alt="" class="di-header__icon" />数据解读</span>
|
|
|
<span class="di-header__close" @click="$emit('close')">✕</span>
|
|
|
</div>
|
|
|
<div ref="bodyRef" class="di-body">
|
|
|
- <div v-if="showProcess" class="di-process">
|
|
|
- <div v-if="processCollapsed" class="di-process__summary" @click="processCollapsed = false">
|
|
|
- <span class="di-process__summary-icon">▸</span>
|
|
|
- <span>查看处理过程</span>
|
|
|
- </div>
|
|
|
- <template v-else>
|
|
|
- <div v-if="!props.loading" class="di-process__summary" @click="processCollapsed = true">
|
|
|
- <span class="di-process__summary-icon">▾</span>
|
|
|
- <span>收起处理过程</span>
|
|
|
- </div>
|
|
|
- <div v-if="thinking" class="di-process__row di-process__thinking"><a-spin size="small" /><span>AI 正在思考...</span></div>
|
|
|
- <div v-if="todos.length > 0" class="di-process__todos">
|
|
|
- <div v-for="(todo, i) in todos" :key="i" class="di-todo-item" :class="`di-todo-item--${todo.status}`">
|
|
|
- <span class="di-todo-item__icon">
|
|
|
- <span v-if="todo.status === 'completed'" class="di-todo-check">✓</span>
|
|
|
- <span v-else-if="todo.status === 'in_progress'" class="di-todo-spinner"></span>
|
|
|
- <span v-else class="di-todo-dot"></span>
|
|
|
- </span>
|
|
|
- <span class="di-todo-item__text">{{ todo.content }}</span>
|
|
|
+ <div class="di-section">
|
|
|
+ <div class="di-section__title">监测对象</div>
|
|
|
+ <div class="di-section__content di-section__content--target">{{ props.itemName }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="di-section">
|
|
|
+ <div class="di-section__title">分析结论</div>
|
|
|
+ <div class="di-section__content">
|
|
|
+ <div v-if="showProcess" class="di-process">
|
|
|
+ <div v-if="processCollapsed" class="di-process__summary" @click="processCollapsed = false">
|
|
|
+ <span class="di-process__summary-icon">▸</span>
|
|
|
+ <span>查看处理过程</span>
|
|
|
</div>
|
|
|
+ <template v-else>
|
|
|
+ <div v-if="!props.loading" class="di-process__summary" @click="processCollapsed = true">
|
|
|
+ <span class="di-process__summary-icon">▾</span>
|
|
|
+ <span>收起处理过程</span>
|
|
|
+ </div>
|
|
|
+ <div v-if="thinking" class="di-process__row di-process__thinking"><a-spin size="small" /><span>AI 正在思考...</span></div>
|
|
|
+ <div v-if="todos.length > 0" class="di-process__todos">
|
|
|
+ <div v-for="(todo, i) in todos" :key="i" class="di-todo-item" :class="`di-todo-item--${todo.status}`">
|
|
|
+ <span class="di-todo-item__icon">
|
|
|
+ <span v-if="todo.status === 'completed'" class="di-todo-check">✓</span>
|
|
|
+ <span v-else-if="todo.status === 'in_progress'" class="di-todo-spinner"></span>
|
|
|
+ <span v-else class="di-todo-dot"></span>
|
|
|
+ </span>
|
|
|
+ <span class="di-todo-item__text">{{ todo.content }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div v-if="props.latestMessage && loading" class="di-process__row di-process__message">
|
|
|
+ <span class="di-process__dot"></span><span>{{ props.latestMessage }}</span>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
</div>
|
|
|
- <div v-if="props.latestMessage && loading" class="di-process__row di-process__message">
|
|
|
- <span class="di-process__dot"></span><span>{{ props.latestMessage }}</span>
|
|
|
- </div>
|
|
|
- </template>
|
|
|
+ <div v-if="loading && !hasContent" class="di-loading"><a-spin tip="正在分析数据..." /></div>
|
|
|
+ <div v-if="hasContent" class="di-markdown" v-html="renderedText"></div>
|
|
|
+ <div v-else-if="error && !loading" class="di-error">数据解读失败:{{ error }}</div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- <div v-if="loading && !hasContent" class="di-loading"><a-spin tip="正在分析数据..." /></div>
|
|
|
- <div v-if="hasContent" class="di-markdown" v-html="renderedText"></div>
|
|
|
- <div v-else-if="error && !loading" class="di-error">数据解读失败:{{ error }}</div>
|
|
|
</div>
|
|
|
<div v-if="loading && hasContent" class="di-streaming-bar"><a-spin size="small" /><span class="di-streaming-bar__tip">AI 正在生成...</span></div>
|
|
|
</a-modal>
|
|
|
@@ -52,6 +61,7 @@
|
|
|
import { computed, ref, watch, nextTick, onMounted, onBeforeUnmount } from 'vue';
|
|
|
import { marked } from 'marked';
|
|
|
import type { TodoItem, ToolCallRecord } from '../types';
|
|
|
+ import aiIcon from '@/assets/images/ventAI/dataPicker/AI-icon.svg';
|
|
|
|
|
|
const props = defineProps<{
|
|
|
visible: boolean;
|
|
|
@@ -63,6 +73,7 @@
|
|
|
executingTools: string[];
|
|
|
toolCalls: ToolCallRecord[];
|
|
|
latestMessage: string;
|
|
|
+ itemName: string;
|
|
|
}>();
|
|
|
|
|
|
defineEmits<{ close: [] }>();
|
|
|
@@ -147,10 +158,9 @@
|
|
|
}
|
|
|
.ant-modal-content {
|
|
|
color: var(--vent-font-color) !important;
|
|
|
- background-color: var(--vent-modal-bg) !important;
|
|
|
- border: 1px solid var(--vent-modal-border) !important;
|
|
|
- -webkit-box-shadow: 0px 0px 10px var(--vent-modal-box-shadow) inset !important;
|
|
|
- box-shadow: 0px 0px 10px var(--vent-modal-box-shadow) inset !important;
|
|
|
+ background-color: rgba(9, 23, 44, 0.3);
|
|
|
+ border: 1px solid #3df6ff;
|
|
|
+ box-shadow: inset 0 0 12px #2cb6ff;
|
|
|
backdrop-filter: blur(30px);
|
|
|
}
|
|
|
.ant-modal-body {
|
|
|
@@ -169,14 +179,21 @@
|
|
|
display: flex;
|
|
|
justify-content: space-between;
|
|
|
align-items: center;
|
|
|
- padding: 18px 24px;
|
|
|
+ padding: 8px;
|
|
|
border-bottom: 1px solid rgba(30, 144, 255, 0.15);
|
|
|
flex-shrink: 0;
|
|
|
+ background-color: rgba(57, 163, 255, 0.2);
|
|
|
&__title {
|
|
|
font-size: 18px;
|
|
|
font-weight: bold;
|
|
|
color: #fff;
|
|
|
letter-spacing: 2px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+ }
|
|
|
+ &__icon {
|
|
|
+ display: inline-block;
|
|
|
}
|
|
|
&__close {
|
|
|
cursor: pointer;
|
|
|
@@ -193,6 +210,27 @@
|
|
|
max-height: 700px;
|
|
|
overflow-y: auto;
|
|
|
}
|
|
|
+ .di-section {
|
|
|
+ margin-bottom: 16px;
|
|
|
+ &:last-child {
|
|
|
+ margin-bottom: 0;
|
|
|
+ }
|
|
|
+ &__title {
|
|
|
+ color: #c9f0ff;
|
|
|
+ font-size: 15px;
|
|
|
+ font-weight: bold;
|
|
|
+ margin-bottom: 8px;
|
|
|
+ }
|
|
|
+ &__content {
|
|
|
+ border-top: 2px solid #2cb6ff;
|
|
|
+ background: rgba(36, 138, 191, 0.1);
|
|
|
+ padding: 12px;
|
|
|
+ &--target {
|
|
|
+ color: #fff;
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
.di-loading {
|
|
|
display: flex;
|
|
|
justify-content: center;
|