feat: 整加八大类追问聊天窗体
This commit is contained in:
parent
d66b64de07
commit
63954dddf4
|
|
@ -209,6 +209,11 @@
|
||||||
window.addEventListener('homepage-mounted', handleHomePageMounted)
|
window.addEventListener('homepage-mounted', handleHomePageMounted)
|
||||||
window.addEventListener('homepage-unmounted', handleHomePageUnmounted)
|
window.addEventListener('homepage-unmounted', handleHomePageUnmounted)
|
||||||
|
|
||||||
|
// 监听来自homePage的拖拽状态更新
|
||||||
|
window.addEventListener('update-drag-mode', ((e: CustomEvent) => {
|
||||||
|
isDragEnabled.value = e.detail.enabled
|
||||||
|
}) as EventListener)
|
||||||
|
|
||||||
// 初始化时检查是否已经在 homePage
|
// 初始化时检查是否已经在 homePage
|
||||||
if ((window as any).__isHomePage__) {
|
if ((window as any).__isHomePage__) {
|
||||||
isHomePageActive.value = true
|
isHomePageActive.value = true
|
||||||
|
|
@ -236,6 +241,9 @@
|
||||||
window.removeEventListener('scroll', handleScroll)
|
window.removeEventListener('scroll', handleScroll)
|
||||||
window.removeEventListener('homepage-mounted', handleHomePageMounted)
|
window.removeEventListener('homepage-mounted', handleHomePageMounted)
|
||||||
window.removeEventListener('homepage-unmounted', handleHomePageUnmounted)
|
window.removeEventListener('homepage-unmounted', handleHomePageUnmounted)
|
||||||
|
window.removeEventListener('update-drag-mode', ((e: CustomEvent) => {
|
||||||
|
isDragEnabled.value = e.detail.enabled
|
||||||
|
}) as EventListener)
|
||||||
|
|
||||||
// 取消订阅
|
// 取消订阅
|
||||||
if ($unsub) {
|
if ($unsub) {
|
||||||
|
|
@ -427,7 +435,7 @@
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
z-index: 1000;
|
z-index: 1003;
|
||||||
pointer-events: none; // 允许点击穿透到下方内容
|
pointer-events: none; // 允许点击穿透到下方内容
|
||||||
|
|
||||||
// 子元素恢复 pointer-events
|
// 子元素恢复 pointer-events
|
||||||
|
|
@ -720,7 +728,7 @@
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 12px;
|
top: 12px;
|
||||||
left: 12px;
|
left: 12px;
|
||||||
z-index: 1001;
|
z-index: 1004;
|
||||||
background: linear-gradient(135deg, rgba(0, 212, 255, 0.15) 0%, rgba(24, 144, 255, 0.15) 100%);
|
background: linear-gradient(135deg, rgba(0, 212, 255, 0.15) 0%, rgba(24, 144, 255, 0.15) 100%);
|
||||||
border: 1px solid rgba(0, 212, 255, 0.3);
|
border: 1px solid rgba(0, 212, 255, 0.3);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -699,98 +699,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- AI助手对话 - 已注释 -->
|
<!-- AI助手对话卡片头部 -->
|
||||||
<!-- <div v-else-if="config.id === 'inputCard'" class="module-card__chat-info">
|
|
||||||
<div ref="chatHistoryRef" class="chat-history">
|
|
||||||
<div v-if="chatMessages.length === 0 && taskList.length === 0" class="chat-empty">
|
|
||||||
<p>开始与AI助手对话吧!</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
v-for="(message, index) in chatMessages"
|
|
||||||
:key="index"
|
|
||||||
class="chat-message"
|
|
||||||
:class="{ 'chat-message--user': message.type === 'user', 'chat-message--ai': message.type === 'ai' }"
|
|
||||||
>
|
|
||||||
<div class="chat-message__avatar">
|
|
||||||
<Users v-if="message.type === 'user'" :size="16" />
|
|
||||||
<Activity v-else :size="16" />
|
|
||||||
</div>
|
|
||||||
<div class="chat-message__content">
|
|
||||||
<div class="chat-message__text">{{ message.content }}</div>
|
|
||||||
<div class="chat-message__time">{{ message.timestamp }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="taskList && taskList.length > 0 && chatMessages.length > 0" class="task-list-container">
|
|
||||||
<div class="task-list-header" @click.stop="toggleTaskList">
|
|
||||||
<Activity :size="16" class="task-list-icon" />
|
|
||||||
<h4 class="task-list-title">数据加载进度</h4>
|
|
||||||
<span class="task-list-badge">{{ completedTaskCount }}/{{ taskList.length }}</span>
|
|
||||||
<button class="task-list-toggle" :title="isTaskListExpanded ? '收起' : '展开'" @click.stop="toggleTaskList">
|
|
||||||
<ChevronUp v-if="isTaskListExpanded" :size="16" />
|
|
||||||
<ChevronDown v-else :size="16" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<transition name="task-list-expand">
|
|
||||||
<div v-show="isTaskListExpanded" class="task-list">
|
|
||||||
<div
|
|
||||||
v-for="task in taskList"
|
|
||||||
:key="task.id"
|
|
||||||
class="task-item"
|
|
||||||
:class="`task-item--${task.status}`"
|
|
||||||
>
|
|
||||||
<div class="task-icon">
|
|
||||||
<div v-if="task.status === 'loading'" class="task-spinner">
|
|
||||||
<Loader2 :size="14" class="animate-spin" />
|
|
||||||
</div>
|
|
||||||
<svg v-else-if="task.status === 'completed'" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round">
|
|
||||||
<polyline points="20 6 9 17 4 12"/>
|
|
||||||
</svg>
|
|
||||||
<svg v-else-if="task.status === 'error'" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
||||||
<circle cx="12" cy="12" r="10"/>
|
|
||||||
<line x1="15" y1="9" x2="9" y2="15"/>
|
|
||||||
<line x1="9" y1="9" x2="15" y2="15"/>
|
|
||||||
</svg>
|
|
||||||
<svg v-else xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
||||||
<circle cx="12" cy="12" r="10"/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<span class="task-title">{{ task.title }}</span>
|
|
||||||
<span class="task-status-text">
|
|
||||||
{{ getTaskStatusText(task.status) }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</transition>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="chat-input-area">
|
|
||||||
<div class="chat-input-container">
|
|
||||||
<el-input
|
|
||||||
v-model="currentMessage"
|
|
||||||
placeholder="请输入您的问题..."
|
|
||||||
type="textarea"
|
|
||||||
:rows="2"
|
|
||||||
resize="none"
|
|
||||||
class="chat-input"
|
|
||||||
@keydown.enter.prevent="handleSendMessage"
|
|
||||||
:disabled="isAiThinking"
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
class="chat-send-btn"
|
|
||||||
@mousedown.stop
|
|
||||||
@click.stop="handleSendMessage"
|
|
||||||
:disabled="!currentMessage.trim() || isAiThinking"
|
|
||||||
:title="isAiThinking ? 'AI正在思考中...' : '发送消息'"
|
|
||||||
>
|
|
||||||
<Activity v-if="isAiThinking" :size="16" class="animate-spin" />
|
|
||||||
<span v-else>发送</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div> -->
|
|
||||||
|
|
||||||
<!-- 输入框卡片 -->
|
<!-- 输入框卡片 -->
|
||||||
<div v-else-if="config.id === 'inputCard'" class="module-card__input-card">
|
<div v-else-if="config.id === 'inputCard'" class="module-card__input-card">
|
||||||
|
|
@ -1017,7 +926,8 @@ import {
|
||||||
MapPin,
|
MapPin,
|
||||||
AlertCircle,
|
AlertCircle,
|
||||||
Phone,
|
Phone,
|
||||||
GraduationCap
|
GraduationCap,
|
||||||
|
MessageSquare
|
||||||
} from 'lucide-vue-next';
|
} from 'lucide-vue-next';
|
||||||
import VabQrCode from '@/plugins/VabQrCode';
|
import VabQrCode from '@/plugins/VabQrCode';
|
||||||
// 规章制度的 PDF 预览弹窗迁移到 HomePage 页面,组件不再直接引用
|
// 规章制度的 PDF 预览弹窗迁移到 HomePage 页面,组件不再直接引用
|
||||||
|
|
@ -1095,6 +1005,11 @@ interface Emits {
|
||||||
(e: 'show-card-selector'): void;
|
(e: 'show-card-selector'): void;
|
||||||
// 新增:让父组件移除选中的卡片
|
// 新增:让父组件移除选中的卡片
|
||||||
(e: 'remove-selected-card', cardId: string): void;
|
(e: 'remove-selected-card', cardId: string): void;
|
||||||
|
// 新增:AI响应相关事件
|
||||||
|
(e: 'ai-user-message', message: string): void;
|
||||||
|
(e: 'ai-stream-start'): void;
|
||||||
|
(e: 'ai-stream-update', content: string): void;
|
||||||
|
(e: 'ai-stream-finish', finalContent?: string): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
|
@ -1366,7 +1281,7 @@ const editingPhoneNumber = ref('');
|
||||||
|
|
||||||
// 运用信息卡片状态
|
// 运用信息卡片状态
|
||||||
const isPrecautionQrMode = ref(false); // 是否显示二维码模式
|
const isPrecautionQrMode = ref(false); // 是否显示二维码模式
|
||||||
const precautionEditText = ref('配属长沙南所CRH2C-2344 ,担当 D1814次交路,CRH2C-2344 列 00 车主控,途中 2344列 00 车报司机室感烟探头火灾报警(401),司机反馈有焦糊味,司机操作降弓停车,拔取主控。将重联端两头车连接切换器打至分割位、空气管开闭器打至开位,切除 2344 列全列空气制动,断开2344 列00 车总配电柜 CN1 至 CN7 连接器'); // 编辑文本内容
|
const precautionEditText = ref('配属广州南所CRH2C-2344 ,担当 D1814次交路,CRH2C-2344 列 00 车主控,途中 2344列 00 车报司机室感烟探头火灾报警(401),司机反馈有焦糊味,司机操作降弓停车,拔取主控。将重联端两头车连接切换器打至分割位、空气管开闭器打至开位,切除 2344 列全列空气制动,断开2344 列00 车总配电柜 CN1 至 CN7 连接器'); // 编辑文本内容
|
||||||
|
|
||||||
// 对话消息接口
|
// 对话消息接口
|
||||||
interface ChatMessage {
|
interface ChatMessage {
|
||||||
|
|
@ -1378,17 +1293,47 @@ interface ChatMessage {
|
||||||
// 对话消息列表
|
// 对话消息列表
|
||||||
const chatMessages = ref<ChatMessage[]>([]);
|
const chatMessages = ref<ChatMessage[]>([]);
|
||||||
|
|
||||||
|
// 流式响应状态
|
||||||
|
const isStreamingResponse = ref(false);
|
||||||
|
|
||||||
|
// 当前流式响应消息
|
||||||
|
const currentStreamMessage = ref('');
|
||||||
|
|
||||||
|
// 聊天历史引用
|
||||||
|
const chatHistoryRef = ref<HTMLElement>();
|
||||||
|
|
||||||
|
// 任务列表展开状态
|
||||||
|
const isTaskListExpanded = ref(true);
|
||||||
|
|
||||||
|
// 计算完成的任务数量
|
||||||
|
const completedTaskCount = computed(() => {
|
||||||
|
return props.taskList?.filter(task => task.status === 'completed').length || 0;
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 切换任务列表展开/收起状态 - 已注释
|
* 切换任务列表展开/收起状态
|
||||||
*/
|
*/
|
||||||
// const toggleTaskList = (event?: Event) => {
|
const toggleTaskList = (event?: Event) => {
|
||||||
// if (event) {
|
if (event) {
|
||||||
// event.stopPropagation();
|
event.stopPropagation();
|
||||||
// event.preventDefault();
|
event.preventDefault();
|
||||||
// }
|
}
|
||||||
// isTaskListExpanded.value = !isTaskListExpanded.value;
|
isTaskListExpanded.value = !isTaskListExpanded.value;
|
||||||
// console.log('任务列表状态切换:', isTaskListExpanded.value ? '展开' : '收起');
|
console.log('任务列表状态切换:', isTaskListExpanded.value ? '展开' : '收起');
|
||||||
// };
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取任务状态文本
|
||||||
|
*/
|
||||||
|
const getTaskStatusText = (status: string): string => {
|
||||||
|
const statusMap: Record<string, string> = {
|
||||||
|
pending: '等待中',
|
||||||
|
loading: '加载中',
|
||||||
|
completed: '已完成',
|
||||||
|
error: '失败'
|
||||||
|
};
|
||||||
|
return statusMap[status] || status;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据图标名称获取对应的图标组件
|
* 根据图标名称获取对应的图标组件
|
||||||
|
|
@ -1407,7 +1352,8 @@ const iconComponent = computed(() => {
|
||||||
Loader2,
|
Loader2,
|
||||||
ChevronDown,
|
ChevronDown,
|
||||||
ChevronUp,
|
ChevronUp,
|
||||||
QrCode
|
QrCode,
|
||||||
|
MessageSquare
|
||||||
};
|
};
|
||||||
return iconMap[props.config.icon as keyof typeof iconMap] || FileText;
|
return iconMap[props.config.icon as keyof typeof iconMap] || FileText;
|
||||||
});
|
});
|
||||||
|
|
@ -1525,25 +1471,89 @@ const handleDoubleClick = (event: MouseEvent) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 格式化时间戳 - 已注释
|
* 格式化时间戳
|
||||||
*/
|
*/
|
||||||
// const formatTimestamp = (date: Date): string => {
|
const formatTimestamp = (date: Date): string => {
|
||||||
// return date.toLocaleTimeString('zh-CN', {
|
return date.toLocaleTimeString('zh-CN', {
|
||||||
// hour: '2-digit',
|
hour: '2-digit',
|
||||||
// minute: '2-digit'
|
minute: '2-digit'
|
||||||
// });
|
});
|
||||||
// };
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 滚动到对话历史底部 - 已注释
|
* 格式化消息内容,支持HTML和换行
|
||||||
*/
|
*/
|
||||||
// const scrollToBottom = () => {
|
const formatMessageContent = (content: string): string => {
|
||||||
// nextTick(() => {
|
if (!content) {
|
||||||
// if (chatHistoryRef.value) {
|
console.log('formatMessageContent: 内容为空', content);
|
||||||
// chatHistoryRef.value.scrollTop = chatHistoryRef.value.scrollHeight;
|
return '';
|
||||||
// }
|
}
|
||||||
// });
|
|
||||||
// };
|
console.log('formatMessageContent: 格式化消息内容:', {
|
||||||
|
originalContent: content,
|
||||||
|
contentLength: content.length,
|
||||||
|
contentType: typeof content
|
||||||
|
});
|
||||||
|
|
||||||
|
// 将换行符转换为HTML换行
|
||||||
|
const formattedContent = content.replace(/\n/g, '<br>');
|
||||||
|
console.log('formatMessageContent: 格式化后的内容:', {
|
||||||
|
formattedContent,
|
||||||
|
formattedLength: formattedContent.length
|
||||||
|
});
|
||||||
|
|
||||||
|
return formattedContent;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加流式响应消息
|
||||||
|
*/
|
||||||
|
const addStreamMessage = (content: string, isComplete: boolean = false) => {
|
||||||
|
if (isComplete) {
|
||||||
|
// 流式响应完成,添加完整消息
|
||||||
|
const aiMessage: ChatMessage = {
|
||||||
|
type: 'ai',
|
||||||
|
content: content,
|
||||||
|
timestamp: formatTimestamp(new Date())
|
||||||
|
};
|
||||||
|
chatMessages.value.push(aiMessage);
|
||||||
|
isStreamingResponse.value = false;
|
||||||
|
currentStreamMessage.value = '';
|
||||||
|
|
||||||
|
// 滚动到底部
|
||||||
|
nextTick(() => {
|
||||||
|
scrollToBottom();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// 流式响应进行中
|
||||||
|
isStreamingResponse.value = true;
|
||||||
|
currentStreamMessage.value = content;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清空聊天消息
|
||||||
|
*/
|
||||||
|
const clearChatMessages = () => {
|
||||||
|
chatMessages.value = [];
|
||||||
|
isStreamingResponse.value = false;
|
||||||
|
currentStreamMessage.value = '';
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 滚动到对话历史底部
|
||||||
|
*/
|
||||||
|
const scrollToBottom = () => {
|
||||||
|
nextTick(() => {
|
||||||
|
if (chatHistoryRef.value) {
|
||||||
|
chatHistoryRef.value.scrollTop = chatHistoryRef.value.scrollHeight;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 模拟AI回复 - 已注释
|
* 模拟AI回复 - 已注释
|
||||||
|
|
@ -1942,6 +1952,22 @@ const handleInputCardSubmit = async () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// 先添加用户消息到聊天记录
|
||||||
|
const userMessage: ChatMessage = {
|
||||||
|
type: 'user',
|
||||||
|
content: inputText,
|
||||||
|
timestamp: formatTimestamp(new Date())
|
||||||
|
};
|
||||||
|
chatMessages.value.push(userMessage);
|
||||||
|
|
||||||
|
// 发送用户消息事件到父组件(用于抽屉显示)
|
||||||
|
emit('ai-user-message', inputText);
|
||||||
|
|
||||||
|
// 滚动到底部
|
||||||
|
nextTick(() => {
|
||||||
|
scrollToBottom();
|
||||||
|
});
|
||||||
|
|
||||||
// 调用 sendMessageToAgentInputCard 方法
|
// 调用 sendMessageToAgentInputCard 方法
|
||||||
const { sendMessageToAgentInputCard } = await import('@/api/chat');
|
const { sendMessageToAgentInputCard } = await import('@/api/chat');
|
||||||
|
|
||||||
|
|
@ -1957,15 +1983,200 @@ const handleInputCardSubmit = async () => {
|
||||||
|
|
||||||
console.log('发送输入卡片消息:', requestData);
|
console.log('发送输入卡片消息:', requestData);
|
||||||
|
|
||||||
// 发送请求
|
// 发送流式请求
|
||||||
const response = await sendMessageToAgentInputCard(requestData);
|
const response = await sendMessageToAgentInputCard(requestData);
|
||||||
console.log('输入卡片响应:', response);
|
|
||||||
|
|
||||||
ElMessage.success('消息发送成功');
|
console.log('API响应对象:', {
|
||||||
|
response,
|
||||||
|
responseType: typeof response,
|
||||||
|
hasBody: !!response?.body,
|
||||||
|
headers: response?.headers,
|
||||||
|
status: response?.status,
|
||||||
|
ok: response?.ok
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response || !response.body) {
|
||||||
|
console.error('响应无效:', response);
|
||||||
|
throw new Error('No response body');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查响应类型
|
||||||
|
const contentType = response.headers?.get('content-type');
|
||||||
|
console.log('响应内容类型:', contentType);
|
||||||
|
|
||||||
|
// 开始流式响应显示
|
||||||
|
isStreamingResponse.value = true;
|
||||||
|
currentStreamMessage.value = '';
|
||||||
|
|
||||||
|
// 发送流式响应开始事件到父组件
|
||||||
|
emit('ai-stream-start');
|
||||||
|
|
||||||
|
console.log('流式响应状态设置:', {
|
||||||
|
isStreamingResponse: isStreamingResponse.value,
|
||||||
|
currentStreamMessage: currentStreamMessage.value,
|
||||||
|
chatMessagesLength: chatMessages.value.length
|
||||||
|
});
|
||||||
|
|
||||||
|
// 处理流式响应
|
||||||
|
const reader = response.body.getReader();
|
||||||
|
const decoder = new TextDecoder();
|
||||||
|
let buffer = '';
|
||||||
|
let streamedAnswer = '';
|
||||||
|
let conversationId = '';
|
||||||
|
let messageId = '';
|
||||||
|
let taskId = '';
|
||||||
|
|
||||||
|
console.log('开始处理流式响应...', {
|
||||||
|
readerType: typeof reader,
|
||||||
|
decoderType: typeof decoder
|
||||||
|
});
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const { done, value } = await reader.read();
|
||||||
|
// console.log('读取流式数据块:', { done, valueLength: value?.length, valueType: typeof value });
|
||||||
|
|
||||||
|
if (done) {
|
||||||
|
// console.log('流式数据读取完成');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const decodedChunk = decoder.decode(value, { stream: true });
|
||||||
|
// console.log('解码后的数据块:', decodedChunk);
|
||||||
|
|
||||||
|
buffer += decodedChunk;
|
||||||
|
// console.log('当前缓冲区内容:', buffer);
|
||||||
|
|
||||||
|
const chunks = buffer.split(/\n\n/);
|
||||||
|
buffer = chunks.pop() || '';
|
||||||
|
// console.log('分割后的数据块数量:', chunks.length, '剩余缓冲区:', buffer);
|
||||||
|
|
||||||
|
for (const chunk of chunks) {
|
||||||
|
const eventData = chunk.trim();
|
||||||
|
// console.log('处理事件数据:', eventData);
|
||||||
|
|
||||||
|
if (!eventData) {
|
||||||
|
//console.log('跳过空事件数据');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const jsonData = eventData.replace(/^data:\s*/, '');
|
||||||
|
// console.log('提取的JSON数据:', jsonData);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(jsonData);
|
||||||
|
// console.log('解析成功的流式数据:', data);
|
||||||
|
|
||||||
|
if (data.answer) {
|
||||||
|
streamedAnswer += data.answer;
|
||||||
|
// console.log('data.answerr', data.answer);
|
||||||
|
// console.log('累积答案更新:', {
|
||||||
|
// newAnswer: data.answer,
|
||||||
|
// totalAnswer: streamedAnswer,
|
||||||
|
// answerLength: streamedAnswer.length
|
||||||
|
// });
|
||||||
|
|
||||||
|
// 实时更新流式响应显示
|
||||||
|
currentStreamMessage.value = streamedAnswer;
|
||||||
|
|
||||||
|
// 发送流式响应更新事件到父组件
|
||||||
|
emit('ai-stream-update', streamedAnswer);
|
||||||
|
|
||||||
|
// console.log('更新流式消息显示:', {
|
||||||
|
// currentStreamMessage: currentStreamMessage.value,
|
||||||
|
// isStreamingResponse: isStreamingResponse.value,
|
||||||
|
// streamedAnswerLength: streamedAnswer.length,
|
||||||
|
// chatMessagesLength: chatMessages.value.length
|
||||||
|
// });
|
||||||
|
|
||||||
|
// 强制触发Vue响应式更新
|
||||||
|
nextTick(() => {
|
||||||
|
console.log('nextTick执行,准备滚动到底部');
|
||||||
|
scrollToBottom();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新会话ID和消息ID
|
||||||
|
// if (data.conversationId) {
|
||||||
|
// conversationId = data.conversationId;
|
||||||
|
// console.log('更新conversationId:', conversationId);
|
||||||
|
// }
|
||||||
|
// if (data.messageId) {
|
||||||
|
// messageId = data.messageId;
|
||||||
|
// console.log('更新messageId:', messageId);
|
||||||
|
// }
|
||||||
|
// if (data.taskId) {
|
||||||
|
// taskId = data.taskId;
|
||||||
|
// console.log('更新taskId:', taskId);
|
||||||
|
// }
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
console.error('解析流式数据错误:', e, '原始数据:', jsonData, '事件数据:', eventData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理剩余数据
|
||||||
|
console.log('处理剩余缓冲区数据:', buffer);
|
||||||
|
if (buffer) {
|
||||||
|
const eventData = buffer.trim();
|
||||||
|
// console.log('剩余事件数据:', eventData);
|
||||||
|
if (eventData) {
|
||||||
|
try {
|
||||||
|
const jsonData = eventData.replace(/^data:\s*/, '');
|
||||||
|
// console.log('剩余JSON数据:', jsonData);
|
||||||
|
const data = JSON.parse(jsonData);
|
||||||
|
// console.log('剩余解析成功的数据:', data);
|
||||||
|
|
||||||
|
if (data.answer) {
|
||||||
|
streamedAnswer += data.answer;
|
||||||
|
// console.log('剩余答案累积:', streamedAnswer);
|
||||||
|
// 实时更新流式响应显示
|
||||||
|
currentStreamMessage.value = streamedAnswer;
|
||||||
|
|
||||||
|
// 发送流式响应更新事件到父组件
|
||||||
|
emit('ai-stream-update', streamedAnswer);
|
||||||
|
}
|
||||||
|
if (data.conversationId) {
|
||||||
|
conversationId = data.conversationId;
|
||||||
|
}
|
||||||
|
if (data.messageId) {
|
||||||
|
messageId = data.messageId;
|
||||||
|
}
|
||||||
|
if (data.taskId) {
|
||||||
|
taskId = data.taskId;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('最终解析错误:', e, '剩余数据:', eventData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('流式响应完成:', {
|
||||||
|
answer: streamedAnswer,
|
||||||
|
conversationId,
|
||||||
|
messageId,
|
||||||
|
taskId
|
||||||
|
});
|
||||||
|
|
||||||
|
// 流式响应完成,使用 addStreamMessage 函数完成显示
|
||||||
|
if (streamedAnswer) {
|
||||||
|
addStreamMessage(streamedAnswer, true);
|
||||||
|
} else {
|
||||||
|
// 如果没有内容,也要停止流式响应状态
|
||||||
|
isStreamingResponse.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送流式响应完成事件到父组件
|
||||||
|
emit('ai-stream-finish', streamedAnswer);
|
||||||
|
|
||||||
|
ElMessage.success('消息发送成功,响应已接收');
|
||||||
|
|
||||||
// 清空输入框
|
// 清空输入框
|
||||||
inputCardText.value = '';
|
inputCardText.value = '';
|
||||||
|
|
||||||
|
// 可以在这里触发事件或回调来处理接收到的答案
|
||||||
|
// 例如:emit('message-received', { answer: streamedAnswer, conversationId, messageId });
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('发送输入卡片消息失败:', error);
|
console.error('发送输入卡片消息失败:', error);
|
||||||
ElMessage.error('消息发送失败,请重试');
|
ElMessage.error('消息发送失败,请重试');
|
||||||
|
|
@ -2294,6 +2505,13 @@ watch(
|
||||||
// { immediate: true } // 立即执行一次
|
// { immediate: true } // 立即执行一次
|
||||||
// );
|
// );
|
||||||
|
|
||||||
|
// 暴露方法给父组件使用
|
||||||
|
defineExpose({
|
||||||
|
addStreamMessage,
|
||||||
|
clearChatMessages,
|
||||||
|
scrollToBottom
|
||||||
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|
@ -3332,16 +3550,7 @@ watch(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// AI对话卡片样式 - 已注释
|
|
||||||
// &__chat-info {
|
|
||||||
// display: flex;
|
|
||||||
// flex-direction: column;
|
|
||||||
// height: 100%; // 占据父容器的全部高度
|
|
||||||
// min-height: 200px; // 设置最小高度,确保有足够空间
|
|
||||||
// overflow: hidden;
|
|
||||||
// position: relative; // 添加相对定位,为绝对定位的输入框提供参考
|
|
||||||
// flex: 1; // 确保在父容器中占据剩余空间
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 输入框卡片样式
|
// 输入框卡片样式
|
||||||
&__input-card {
|
&__input-card {
|
||||||
|
|
@ -3691,6 +3900,11 @@ watch(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 对话历史区域 - 已注释
|
// 对话历史区域 - 已注释
|
||||||
// .chat-history {
|
// .chat-history {
|
||||||
// flex: 1;
|
// flex: 1;
|
||||||
|
|
@ -4768,7 +4982,7 @@ watch(
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
transform: rotate(2deg) scale(1.02) translate3d(0, 0, 0);
|
transform: rotate(2deg) scale(1.02) translate3d(0, 0, 0);
|
||||||
box-shadow: 0 12px 40px rgba(0, 212, 255, 0.3);
|
box-shadow: 0 12px 40px rgba(0, 212, 255, 0.3);
|
||||||
z-index: 1000;
|
z-index: 1002;
|
||||||
transition: none !important; /* 禁用所有过渡效果以提升性能 */
|
transition: none !important; /* 禁用所有过渡效果以提升性能 */
|
||||||
pointer-events: none; /* 防止拖拽时触发其他事件 */
|
pointer-events: none; /* 防止拖拽时触发其他事件 */
|
||||||
|
|
||||||
|
|
@ -6484,4 +6698,27 @@ watch(
|
||||||
color: rgba(0, 212, 255, 1);
|
color: rgba(0, 212, 255, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 动画关键帧
|
||||||
|
@keyframes messageSlideIn {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(10px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes streamingDot {
|
||||||
|
0%, 80%, 100% {
|
||||||
|
transform: scale(0.8);
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
40% {
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
@ -66,7 +66,8 @@ export const MODULE_CONFIGS: ModuleConfig[] = [
|
||||||
icon: 'Activity',
|
icon: 'Activity',
|
||||||
color: '#00D4FF',
|
color: '#00D4FF',
|
||||||
description: '用于输入消息或指令的交互界面'
|
description: '用于输入消息或指令的交互界面'
|
||||||
}
|
},
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
// 主题色彩配置
|
// 主题色彩配置
|
||||||
|
|
|
||||||
|
|
@ -322,7 +322,7 @@ export const generateCaseData = (): TypicalCase[] => {
|
||||||
{
|
{
|
||||||
id: '1',
|
id: '1',
|
||||||
fileName: '附件:CRH2C型动车组总配热损故障典型案例.pdf',
|
fileName: '附件:CRH2C型动车组总配热损故障典型案例.pdf',
|
||||||
fileUrl: 'http://10.183.199.18/ocr-src-doc-preview/附件:CRH2C型动车组总配热损故障典型案例.pdf',
|
fileUrl: 'http://192.168.8.253/ocr-src-doc-preview/附件:CRH2C型动车组总配热损故障典型案例.pdf',
|
||||||
caseSummary: 'CRH2C型动车组在运行中因总配电柜CN3连接器热损及母板熏黑变色,导致152线回路短路接地,引发00车司机室感烟探头火灾报警(代码401),司机反馈有焦糊味并操作降弓停车。',
|
caseSummary: 'CRH2C型动车组在运行中因总配电柜CN3连接器热损及母板熏黑变色,导致152线回路短路接地,引发00车司机室感烟探头火灾报警(代码401),司机反馈有焦糊味并操作降弓停车。',
|
||||||
caseAnalysis: '',
|
caseAnalysis: '',
|
||||||
emergencyPoints: '',
|
emergencyPoints: '',
|
||||||
|
|
@ -331,7 +331,7 @@ export const generateCaseData = (): TypicalCase[] => {
|
||||||
{
|
{
|
||||||
id: '2',
|
id: '2',
|
||||||
fileName: '附件:CRH2C型动车组总配热损故障典型案例.pdf',
|
fileName: '附件:CRH2C型动车组总配热损故障典型案例.pdf',
|
||||||
fileUrl: 'http://10.183.199.18/ocr-src-doc-preview/附件:CRH2C型动车组总配热损故障典型案例.pdf',
|
fileUrl: 'http://192.168.8.253/ocr-src-doc-preview/附件:CRH2C型动车组总配热损故障典型案例.pdf',
|
||||||
caseSummary: '总配电柜热损故障中,152线接地短路导致00车总配母板与148线回路导通,造成全列【显示灯电源】断路器跳断,虽受电弓实际升起但MON屏显示异常,同时触发司机室感烟探头报警。',
|
caseSummary: '总配电柜热损故障中,152线接地短路导致00车总配母板与148线回路导通,造成全列【显示灯电源】断路器跳断,虽受电弓实际升起但MON屏显示异常,同时触发司机室感烟探头报警。',
|
||||||
caseAnalysis: '',
|
caseAnalysis: '',
|
||||||
emergencyPoints: '',
|
emergencyPoints: '',
|
||||||
|
|
@ -340,7 +340,7 @@ export const generateCaseData = (): TypicalCase[] => {
|
||||||
{
|
{
|
||||||
id: '3',
|
id: '3',
|
||||||
fileName: '附件:CRH2C型动车组总配热损故障典型案例.pdf',
|
fileName: '附件:CRH2C型动车组总配热损故障典型案例.pdf',
|
||||||
fileUrl: 'http://10.183.199.18/ocr-src-doc-preview/附件:CRH2C型动车组总配热损故障典型案例.pdf',
|
fileUrl: 'http://192.168.8.253/ocr-src-doc-preview/附件:CRH2C型动车组总配热损故障典型案例.pdf',
|
||||||
caseSummary: '故障分析表明,总配电柜内EBFBR继电器线圈对地短路引发大电流热损,热损产生的烟雾触发感烟探头报警(代码401),并伴随VCB状态显示异常和受电弓显示故障。',
|
caseSummary: '故障分析表明,总配电柜内EBFBR继电器线圈对地短路引发大电流热损,热损产生的烟雾触发感烟探头报警(代码401),并伴随VCB状态显示异常和受电弓显示故障。',
|
||||||
caseAnalysis: '',
|
caseAnalysis: '',
|
||||||
emergencyPoints: '',
|
emergencyPoints: '',
|
||||||
|
|
@ -399,14 +399,14 @@ export const generateRuleData = (): RuleRegulation[] => {
|
||||||
title: 'CRH380A动车组运行中触发火灾报警及设备故障案例',
|
title: 'CRH380A动车组运行中触发火灾报警及设备故障案例',
|
||||||
content: '2025年5月25日南昌局CRH380A动车组运行中,00车司机室总配电盘触发集成柜烟感探头火灾报警,伴随ATP、CIR黑屏及断路器跳断故障。',
|
content: '2025年5月25日南昌局CRH380A动车组运行中,00车司机室总配电盘触发集成柜烟感探头火灾报警,伴随ATP、CIR黑屏及断路器跳断故障。',
|
||||||
fileName: 'TB 9085.pdf',
|
fileName: 'TB 9085.pdf',
|
||||||
fileUrl: 'http://10.183.199.18/ocr-src-doc-preview/TB 9085.pdf'
|
fileUrl: 'http://192.168.8.253/ocr-src-doc-preview/TB 9085.pdf'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '2',
|
id: '2',
|
||||||
title: '故障原因分析:过电压吸收器击穿短路引发连锁反应',
|
title: '故障原因分析:过电压吸收器击穿短路引发连锁反应',
|
||||||
content: '故障原因为总配电柜内CIR主机供电接触器的过电压吸收器击穿短路,导致过流引发电路板热损、绝缘失效,间接触发烟感探头报警。',
|
content: '故障原因为总配电柜内CIR主机供电接触器的过电压吸收器击穿短路,导致过流引发电路板热损、绝缘失效,间接触发烟感探头报警。',
|
||||||
fileName: 'TB 9085.pdf',
|
fileName: 'TB 9085.pdf',
|
||||||
fileUrl: 'http://10.183.199.18/ocr-src-doc-preview/TB 9085.pdf'
|
fileUrl: 'http://192.168.8.253/ocr-src-doc-preview/TB 9085.pdf'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -440,7 +440,7 @@ export const generateRouteData = (): RouteInfo[] => {
|
||||||
currentRoute: '广州南所-成都东',
|
currentRoute: '广州南所-成都东',
|
||||||
followingTrainNumber: '0D1821\n(00主',
|
followingTrainNumber: '0D1821\n(00主',
|
||||||
followingRoute: '成都东-天府动车所',
|
followingRoute: '成都东-天府动车所',
|
||||||
workScheduleUrl: 'http://10.183.199.18/ocr-src-doc-preview/D1820.pdf',
|
workScheduleUrl: 'http://192.168.8.253/ocr-src-doc-preview/D1820.pdf',
|
||||||
safetyReminders: [
|
safetyReminders: [
|
||||||
{
|
{
|
||||||
id: '1',
|
id: '1',
|
||||||
|
|
@ -599,7 +599,7 @@ export const generateFaultInfoData = (): FaultInfo => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
number: 3,
|
number: 3,
|
||||||
content: '3)若检查为旅客吸烟、吸入灰尘、水雾等导致假火情,在烟火报警控制器上进行复位。'
|
content: '若检查为旅客吸烟、吸入灰尘、水雾等导致假火情,在烟火报警控制器上进行复位。'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -615,11 +615,11 @@ export const generatePersonnelData = (): PersonnelInfo[] => {
|
||||||
name: '向亮',
|
name: '向亮',
|
||||||
phone: '013922466474',
|
phone: '013922466474',
|
||||||
position: '技师',
|
position: '技师',
|
||||||
department: '长沙动车乘务车间',
|
department: '广州南动车乘务车间',
|
||||||
trainTypeQualifications: 'CRH2A、CRH380A、CR400AF、CR400BF',
|
trainTypeQualifications: 'CRH2A、CRH380A、CR400AF、CR400BF',
|
||||||
trainingRecords: [
|
trainingRecords: [
|
||||||
{
|
{
|
||||||
title: '长沙西所通知[2025]45号--关于开展全员学习CRH3C-3028动车组网络、牵引及制动系统自主化改造内容的通知',
|
title: '广州南所通知[2025]45号--关于开展全员学习CRH3C-3028动车组网络、牵引及制动系统自主化改造内容的通知',
|
||||||
date: '2025-01-15',
|
date: '2025-01-15',
|
||||||
status: 'completed',
|
status: 'completed',
|
||||||
statusText: '已完成'
|
statusText: '已完成'
|
||||||
|
|
@ -649,7 +649,7 @@ export const generatePersonnelData = (): PersonnelInfo[] => {
|
||||||
name: '施文龙',
|
name: '施文龙',
|
||||||
phone: '013128646100',
|
phone: '013128646100',
|
||||||
position: '技师',
|
position: '技师',
|
||||||
department: '长沙动车乘务车间',
|
department: '广州南动车乘务车间',
|
||||||
trainTypeQualifications: 'CRH2A、CRH380A、CR400AF、CR400BF',
|
trainTypeQualifications: 'CRH2A、CRH380A、CR400AF、CR400BF',
|
||||||
trainingRecords: [
|
trainingRecords: [
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -245,7 +245,8 @@ export type ModuleType =
|
||||||
| 'typicalCase'
|
| 'typicalCase'
|
||||||
| 'ruleRegulation'
|
| 'ruleRegulation'
|
||||||
| 'precautions'
|
| 'precautions'
|
||||||
| 'inputCard';
|
| 'inputCard'
|
||||||
|
| 'chatResponse';
|
||||||
|
|
||||||
// 模块配置接口
|
// 模块配置接口
|
||||||
export interface ModuleConfig {
|
export interface ModuleConfig {
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -163,6 +163,10 @@
|
||||||
@open-case-pdf="handleOpenCasePdf"
|
@open-case-pdf="handleOpenCasePdf"
|
||||||
@show-card-selector="showCardSelector"
|
@show-card-selector="showCardSelector"
|
||||||
@remove-selected-card="removeSelectedCard"
|
@remove-selected-card="removeSelectedCard"
|
||||||
|
@ai-user-message="handleAIUserMessage"
|
||||||
|
@ai-stream-start="handleAIStreamStart"
|
||||||
|
@ai-stream-update="handleAIStreamUpdate"
|
||||||
|
@ai-stream-finish="handleAIStreamFinish"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
@ -237,6 +241,15 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- AI响应抽屉 -->
|
||||||
|
<AIResponseDrawer
|
||||||
|
ref="aiDrawerRef"
|
||||||
|
v-model="showAIDrawer"
|
||||||
|
@close="handleAIDrawerClose"
|
||||||
|
@minimize="handleAIDrawerMinimize"
|
||||||
|
@maximize="handleAIDrawerMaximize"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -246,6 +259,7 @@ import { useRoute } from 'vue-router';
|
||||||
import { MODULE_CONFIGS } from '@/constants/modules';
|
import { MODULE_CONFIGS } from '@/constants/modules';
|
||||||
import ModuleCard from '@/components/dashboard/ModuleCard.vue';
|
import ModuleCard from '@/components/dashboard/ModuleCard.vue';
|
||||||
import DetailModal from '@/components/dashboard/DetailModal.vue';
|
import DetailModal from '@/components/dashboard/DetailModal.vue';
|
||||||
|
import AIResponseDrawer from '@/components/AIResponseDrawer.vue';
|
||||||
import type { ModuleConfig, ModuleType, SearchResult, StatusStats, Position, Size, RuleRegulation, TypicalCase } from '@/types/dashboard';
|
import type { ModuleConfig, ModuleType, SearchResult, StatusStats, Position, Size, RuleRegulation, TypicalCase } from '@/types/dashboard';
|
||||||
import { webSocketService } from '@/utils/websocket';
|
import { webSocketService } from '@/utils/websocket';
|
||||||
import { baseURL } from '@/config';
|
import { baseURL } from '@/config';
|
||||||
|
|
@ -305,6 +319,10 @@ const questionTextarea = ref<HTMLTextAreaElement>(); // 输入框引用
|
||||||
const atSuggestionsStyle = ref({}); // @推荐框的样式定位
|
const atSuggestionsStyle = ref({}); // @推荐框的样式定位
|
||||||
const selectedCards = ref([]); // 选中的卡片列表,用于显示tag标签
|
const selectedCards = ref([]); // 选中的卡片列表,用于显示tag标签
|
||||||
|
|
||||||
|
// AI响应抽屉相关
|
||||||
|
const showAIDrawer = ref(false); // 控制AI响应抽屉显示
|
||||||
|
const aiDrawerRef = ref<InstanceType<typeof AIResponseDrawer>>(); // AI抽屉组件引用
|
||||||
|
|
||||||
// 监听弹窗状态变化
|
// 监听弹窗状态变化
|
||||||
watch(showCardSelectorDialog, (newVal, oldVal) => {
|
watch(showCardSelectorDialog, (newVal, oldVal) => {
|
||||||
// 弹窗状态变化处理
|
// 弹窗状态变化处理
|
||||||
|
|
@ -1545,6 +1563,71 @@ const showNotification = (message: string, type: 'success' | 'error' | 'info' =
|
||||||
}, 3000);
|
}, 3000);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理AI用户消息事件
|
||||||
|
*/
|
||||||
|
const handleAIUserMessage = (message: string) => {
|
||||||
|
console.log('收到用户消息:', message);
|
||||||
|
// 显示AI抽屉
|
||||||
|
showAIDrawer.value = true;
|
||||||
|
// 添加用户消息到抽屉
|
||||||
|
nextTick(() => {
|
||||||
|
aiDrawerRef.value?.addUserMessage(message);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理AI流式响应开始事件
|
||||||
|
*/
|
||||||
|
const handleAIStreamStart = () => {
|
||||||
|
console.log('AI流式响应开始');
|
||||||
|
// 确保抽屉是打开的
|
||||||
|
showAIDrawer.value = true;
|
||||||
|
// 开始流式响应
|
||||||
|
nextTick(() => {
|
||||||
|
aiDrawerRef.value?.startStreaming();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理AI流式响应更新事件
|
||||||
|
*/
|
||||||
|
const handleAIStreamUpdate = (content: string) => {
|
||||||
|
console.log('AI流式响应更新:', content.length, '字符');
|
||||||
|
// 更新流式内容
|
||||||
|
aiDrawerRef.value?.updateStreamContent(content);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理AI流式响应完成事件
|
||||||
|
*/
|
||||||
|
const handleAIStreamFinish = (finalContent?: string) => {
|
||||||
|
console.log('AI流式响应完成,最终内容长度:', finalContent?.length || 0);
|
||||||
|
// 完成流式响应
|
||||||
|
aiDrawerRef.value?.finishStreaming(finalContent);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理AI抽屉关闭事件
|
||||||
|
*/
|
||||||
|
const handleAIDrawerClose = () => {
|
||||||
|
showAIDrawer.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理AI抽屉缩略事件
|
||||||
|
*/
|
||||||
|
const handleAIDrawerMinimize = () => {
|
||||||
|
console.log('AI抽屉已缩略');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理AI抽屉展开事件
|
||||||
|
*/
|
||||||
|
const handleAIDrawerMaximize = () => {
|
||||||
|
console.log('AI抽屉已展开');
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import com.bjtds.brichat.entity.chat.AgentInputCardReq;
|
||||||
import com.bjtds.brichat.entity.chat.ChatMessage;
|
import com.bjtds.brichat.entity.chat.ChatMessage;
|
||||||
import com.bjtds.brichat.entity.chat.ChatTypeVo;
|
import com.bjtds.brichat.entity.chat.ChatTypeVo;
|
||||||
import com.bjtds.brichat.entity.dataset.TUserDataset;
|
import com.bjtds.brichat.entity.dataset.TUserDataset;
|
||||||
|
import com.bjtds.brichat.entity.sys.ApiKey;
|
||||||
import com.bjtds.brichat.mapper.opengauss.TUserDatasetMapper;
|
import com.bjtds.brichat.mapper.opengauss.TUserDatasetMapper;
|
||||||
import com.bjtds.brichat.service.KnowledgeBaseService;
|
import com.bjtds.brichat.service.KnowledgeBaseService;
|
||||||
import com.bjtds.brichat.service.TApiKeyService;
|
import com.bjtds.brichat.service.TApiKeyService;
|
||||||
|
|
@ -131,14 +132,16 @@ public class ChatServiceImpl implements ChatService {
|
||||||
datasetIds.add(datasetId);
|
datasetIds.add(datasetId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UUID appId = UUID.fromString("f940e32f-e302-49b8-b030-591539c26779");
|
|
||||||
|
ApiKey workFlowInfo = apiKeyService.queryByName("agentInput");
|
||||||
|
UUID appId = UUID.fromString(workFlowInfo.getRemark());
|
||||||
final boolean b = knowledgeBaseService.addDatasetsToWorkflow(appId, datasetIds);
|
final boolean b = knowledgeBaseService.addDatasetsToWorkflow(appId, datasetIds);
|
||||||
|
|
||||||
//启动对话流
|
//启动对话流
|
||||||
ChatMessageSendRequest sendRequest = new ChatMessageSendRequest();
|
ChatMessageSendRequest sendRequest = new ChatMessageSendRequest();
|
||||||
sendRequest.setUserId(agentInputCardReq.getUserId());
|
sendRequest.setUserId(agentInputCardReq.getUserId());
|
||||||
sendRequest.setContent(agentInputCardReq.getContent());
|
sendRequest.setContent(agentInputCardReq.getContent());
|
||||||
sendRequest.setApiKey("app-jCKfKpPW8f9C7ZXLElAq1DSS");
|
sendRequest.setApiKey(workFlowInfo.getValue());
|
||||||
Map<String, Object> inputMap = new HashMap<>();
|
Map<String, Object> inputMap = new HashMap<>();
|
||||||
inputMap.put("sys_message_id", sysMessage);
|
inputMap.put("sys_message_id", sysMessage);
|
||||||
inputMap.put("context", agentInputCardReq.getContext());
|
inputMap.put("context", agentInputCardReq.getContext());
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue