Files
lingji-work-fe/src/components/xt-chat/chat-view/index.vue
2025-08-27 18:07:36 +08:00

174 lines
4.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script lang="tsx">
import { message as antdMessage, Tooltip } from 'ant-design-vue';
import { BubbleList } from '@/components/xt-chat/xt-bubble';
import SenderInput from './components/sender-input/index.vue';
import RightView from './components/right-view/index.vue';
import { useRoute } from 'vue-router';
import { useChatStore } from '@/stores/modules/chat';
import { getConversationList } from '@/api/all/chat';
import querySSE from '@/utils/querySSE';
import useChatHandler from './useChatHandler';
import { QUESTION_ROLE, LOADING_ROLE, REMOTE_ROLE } from './constants';
export default {
props: {
inputInfo: {
type: Object as () => CHAT.TInputInfo,
default: null,
},
},
setup(props, { emit, expose }) {
const chatStore = useChatStore();
const route = useRoute();
const rightViewRef = ref(null);
const bubbleListRef = ref<any>(null);
const sseController = ref<any>(null);
const conversationId = computed(() => {
return route.params.conversationId;
});
const handleSubmit = (message: string) => {
if (generateLoading.value) {
antdMessage.warning('停止生成后可发送');
return;
}
conversationList.value.push({
role: QUESTION_ROLE,
content: message,
});
initSse({ message });
};
const handleCancel = () => {
// 中止当前正在输出的回答
console.log('handleCancel', currentTaskId.value);
if (generateLoading.value) {
bubbleListRef.value?.abortTypingByKey(currentTaskId.value);
sseController.value?.abort?.();
}
if (showRightView.value) {
rightViewRef.value?.abortTyping?.();
}
generateLoading.value = false;
antdMessage.info('取消生成');
};
const initSse = (inputInfo: CHAT.TInputInfo): void => {
if (sseController.value) {
sseController.value.abort?.();
sseController.value = null;
}
try {
const { message } = inputInfo;
generateLoading.value = true;
sseController.value = querySSE({
method: 'POST',
handleMessage,
body: JSON.stringify({
content: message,
session_id: conversationId.value,
agent_id: chatStore.agentInfo.agent_id,
}),
});
} catch (error) {
console.error('Failed to initialize SSE:', error);
antdMessage.error('初始化连接失败');
generateLoading.value = false;
}
};
const {
roles,
showRightView,
rightViewInfo,
currentTaskId,
handleMessage,
conversationList,
generateLoading,
senderRef,
} = useChatHandler({
initSse,
});
watch(
() => props.inputInfo,
(newVal) => {
if (newVal) {
const { message } = newVal;
conversationList.value.push({
role: QUESTION_ROLE,
content: message,
});
initSse(newVal);
}
},
{ deep: true },
);
onMounted(async () => {
if (conversationId.value) {
const { data, code } = await getConversationList({
session_id: conversationId.value,
agent_id: chatStore.agentInfo.agent_id,
});
if (code === 200) {
conversationList.value = data.list?.flat(1) ?? []
}
}
});
return () => (
<div class="chat-view-wrap w-full h-full flex">
<section class="flex-1 flex flex-col pt-20px justify-center relative px-16px">
<div class="flex-1 overflow-hidden pb-20px">
<BubbleList
ref={bubbleListRef}
roles={roles}
items={[
...conversationList.value,
generateLoading.value ? { loading: true, role: LOADING_ROLE } : null,
].filter(Boolean)}
/>
</div>
<div class="w-full flex flex-col justify-center items-center">
<SenderInput
ref={senderRef}
class="w-600px"
placeholder="继续追问..."
loading={generateLoading.value}
onSubmit={handleSubmit}
onCancel={handleCancel}
/>
<p class="cts !color-#939499 text-12px !lh-20px my-4px">内容由AI生成仅供参考</p>
</div>
</section>
{/* 右侧展示区域 */}
{showRightView.value && (
<RightView
ref={rightViewRef}
rightViewInfo={rightViewInfo.value}
showRightView={showRightView.value}
onClose={() => (showRightView.value = false)}
/>
)}
</div>
);
},
};
</script>
<style lang="scss" scoped>
@import './style.scss';
</style>