feat: 长文本组件的调试

This commit is contained in:
2026-03-26 00:10:53 +08:00
parent 00c58d47b9
commit e72531cfb7
4 changed files with 100 additions and 33 deletions

View File

@@ -33,6 +33,16 @@
"navigationBarTextStyle": "black" "navigationBarTextStyle": "black"
} }
} }
,
{
"path": "pages/long-answer/index",
"style": {
"navigationStyle": "custom",
"backgroundColor": "#FFFFFF",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}
}
], ],
"subPackages": [ "subPackages": [
{ {

View File

@@ -19,31 +19,31 @@
<template #content v-if="item.toolCall || item.componentName"> <template #content v-if="item.toolCall || item.componentName">
<AnswerComponent v-if=" <AnswerComponent v-if="
item.componentName === CompName.longTextCard item.componentName === CompName.longTextCard
" :answer-text="item.msg" /> " :answer-text="item.msg" :title="item.title" />
<QuickBookingComponent v-if=" <QuickBookingComponent v-if="
item.toolCall.componentName === CompName.quickBookingCard item.toolCall && item.toolCall.componentName === CompName.quickBookingCard
" /> " />
<DiscoveryCardComponent v-else-if=" <DiscoveryCardComponent v-else-if="
item.toolCall.componentName === CompName.discoveryCard item.toolCall && item.toolCall.componentName === CompName.discoveryCard
" /> " />
<CreateServiceOrder v-else-if=" <CreateServiceOrder v-else-if="
item.toolCall.componentName === CompName.callServiceCard item.toolCall && item.toolCall.componentName === CompName.callServiceCard
" :toolCall="item.toolCall" /> " :toolCall="item.toolCall" />
<OpenMapComponent v-else-if=" <OpenMapComponent v-else-if="
item.toolCall.componentName === CompName.openMapCard item.toolCall && item.toolCall.componentName === CompName.openMapCard
" /> " />
<Feedback v-else-if=" <Feedback v-else-if="
item.toolCall.componentName === CompName.feedbackCard item.toolCall && item.toolCall.componentName === CompName.feedbackCard
" :toolCall="item.toolCall" /> " :toolCall="item.toolCall" />
<DetailCardCompontent v-else-if=" <DetailCardCompontent v-else-if="
item.toolCall.componentName === CompName.pictureAndCommodityCard item.toolCall && item.toolCall.componentName === CompName.pictureAndCommodityCard
" :toolCall="item.toolCall" /> " :toolCall="item.toolCall" />
<AddCarCrad v-else-if=" <AddCarCrad v-else-if="
item.toolCall.componentName === CompName.enterLicensePlateCard item.toolCall && item.toolCall.componentName === CompName.enterLicensePlateCard
" :toolCall="item.toolCall" /> " :toolCall="item.toolCall" />
<SurveyQuestionnaire v-else-if=" <SurveyQuestionnaire v-else-if="
item.toolCall.componentName === CompName.callSurveyQuestionnaire item.toolCall && item.toolCall.componentName === CompName.callSurveyQuestionnaire
" :toolCall="item.toolCall" /> " :toolCall="item.toolCall" />
</template> </template>
@@ -473,25 +473,32 @@ const handleWebSocketMessage = (data) => {
return; return;
} }
// 确保消息内容是字符串类型
if (data.content && typeof data.content !== "string") {
try {
data.content = JSON.stringify(data.content);
} catch (e) {
data.content = String(data.content);
}
}
// 优先使用 messageId 进行匹配
const msgId = data.messageId || data.id || data.msgId || data.replyMessageId;
let aiMsgIndex = -1; let aiMsgIndex = -1;
if (msgId && pendingMap.has(msgId)) { if (currentSessionMessageId && pendingMap.has(currentSessionMessageId)) {
aiMsgIndex = pendingMap.get(msgId);
} else if (!msgId && currentSessionMessageId && pendingMap.has(currentSessionMessageId)) {
// 服务端未返回 messageId 的场景:优先使用当前会话的 messageId 映射
aiMsgIndex = pendingMap.get(currentSessionMessageId); aiMsgIndex = pendingMap.get(currentSessionMessageId);
if (aiMsgIndex >= 0 && aiMsgIndex < chatMsgList.value.length) {
const item = chatMsgList.value[aiMsgIndex];
if (item && item.msgType === MessageRole.AI &&
item.replyMessageId.length > 0 && data.replyMessageId &&
item.replyMessageId !== data.replyMessageId) {
// 已经存在对应的AI消息项继续使用
const aiMsg = {
msgId: `msg_${chatMsgList.value.length}`,
msgType: MessageRole.AI,
msg: "",
isLoading: false,
messageId: currentSessionMessageId,
replyMessageId: '',
componentName: "",
title: "",
finish: false,
};
chatMsgList.value.push(aiMsg);
aiMsgIndex = chatMsgList.value.length - 1;
}
}
} else { } else {
// 向后搜索最近的 AI 消息 // 向后搜索最近的 AI 消息(回退逻辑)
for (let i = chatMsgList.value.length - 1; i >= 0; i--) { for (let i = chatMsgList.value.length - 1; i >= 0; i--) {
if (chatMsgList.value[i] && chatMsgList.value[i].msgType === MessageRole.AI) { if (chatMsgList.value[i] && chatMsgList.value[i].msgType === MessageRole.AI) {
aiMsgIndex = i; aiMsgIndex = i;
@@ -504,6 +511,20 @@ const handleWebSocketMessage = (data) => {
} }
} }
// replyMessageId
if(data.replyMessageId) {
chatMsgList.value[aiMsgIndex].replyMessageId = data.replyMessageId;
}
// 确保消息内容是字符串类型
if (data.content && typeof data.content !== "string") {
try {
data.content = JSON.stringify(data.content);
} catch (e) {
data.content = String(data.content);
}
}
// 直接拼接内容到对应 AI 消息 // 直接拼接内容到对应 AI 消息
if (data.content) { if (data.content) {
if (chatMsgList.value[aiMsgIndex].isLoading) { if (chatMsgList.value[aiMsgIndex].isLoading) {
@@ -522,15 +543,18 @@ const handleWebSocketMessage = (data) => {
chatMsgList.value[aiMsgIndex].finish = true; chatMsgList.value[aiMsgIndex].finish = true;
const msg = chatMsgList.value[aiMsgIndex].msg; const msg = chatMsgList.value[aiMsgIndex].msg;
if (!msg || chatMsgList.value[aiMsgIndex].isLoading) { if (!msg || chatMsgList.value[aiMsgIndex].isLoading) {
chatMsgList.value[aiMsgIndex].msg = "未获取到内容,请重试"; // 如果服务器返回了 componentName 或 toolCall应保留空消息以供组件渲染否则显示错误占位
chatMsgList.value[aiMsgIndex].isLoading = false; if (data.toolCall || data.componentName) {
if (data.toolCall) {
chatMsgList.value[aiMsgIndex].msg = ""; chatMsgList.value[aiMsgIndex].msg = "";
} else {
chatMsgList.value[aiMsgIndex].msg = "未获取到内容,请重试";
} }
chatMsgList.value[aiMsgIndex].isLoading = false;
} }
// 处理组件调用 // 处理组件调用
if (data.componentName) { if (data.componentName) {
chatMsgList.value[aiMsgIndex].title = data.content;
chatMsgList.value[aiMsgIndex].componentName = data.componentName; chatMsgList.value[aiMsgIndex].componentName = data.componentName;
} }
@@ -558,6 +582,8 @@ const handleWebSocketMessage = (data) => {
isSessionActive.value = false; isSessionActive.value = false;
// 清理当前会话的 messageId避免保留陈旧 id // 清理当前会话的 messageId避免保留陈旧 id
resetMessageState(); resetMessageState();
nextTick(() => scrollToBottom());
} }
}; };
@@ -763,7 +789,9 @@ const sendChat = async (message, isInstruct = false) => {
msg: "加载中", msg: "加载中",
isLoading: true, isLoading: true,
messageId: currentSessionMessageId, messageId: currentSessionMessageId,
replyMessageId: '',
componentName: "", componentName: "",
title: "",
finish: false, finish: false,
}; };
chatMsgList.value.push(aiMsg); chatMsgList.value.push(aiMsg);

View File

@@ -5,15 +5,15 @@
<view class="flex flex-col p-16 border-box"> <view class="flex flex-col p-16 border-box">
<view class="flex flex-row flex-items-center justify-center"> <view class="flex flex-row flex-items-center justify-center">
<uni-icons class="icon-active" type="fire-filled" size="18" color="opacity" /> <uni-icons class="icon-active" type="fire-filled" size="18" color="opacity" />
<text class="font-size-16 font-500 text-color-900 ml-6">游玩划重点</text> <text class="font-size-16 font-500 text-color-900 ml-6">{{ title }}</text>
</view> </view>
<!-- 文字内容最多显示3行 --> <!-- 文字内容最多显示3行 -->
<view class="answer-content font-size-12 font-color-600 mt-8"> <view class="answer-content font-size-12 font-color-600 mt-8">
{{ answerText }} <ChatMarkdown :text="answerText" />
</view> </view>
<!-- 超过3行时显示...提示 --> <!-- 超过3行时显示...提示 -->
<view class="fles flex-row mt-8" v-if="isOverflow"> <view class="fles flex-row mt-8" v-if="isOverflow" @click="lookDetailAction">
<text class="font-size-12 font-400 theme-color-500 mr-4">查看完整攻略</text> <text class="font-size-12 font-400 theme-color-500 mr-4">查看详情</text>
<uni-icons class="icon-active" type="right" size="14" color="opacity"></uni-icons> <uni-icons class="icon-active" type="right" size="14" color="opacity"></uni-icons>
</view> </view>
</view> </view>
@@ -22,12 +22,17 @@
</template> </template>
<script setup> <script setup>
import { ref } from 'vue' import { ref, defineProps } from 'vue'
import ChatMarkdown from "../../chat/ChatMarkdown/index.vue";
const isOverflow = ref(true) const isOverflow = ref(true)
// 直接根据文字长度判断超过约100个字符认为会溢出约3行 // 直接根据文字长度判断超过约100个字符认为会溢出约3行
const props = defineProps({ const props = defineProps({
title: {
type: String,
default: "",
},
answerText: { answerText: {
type: String, type: String,
default: "", default: "",
@@ -37,6 +42,12 @@ const props = defineProps({
// 简单判断12号字体3行约100个字符 // 简单判断12号字体3行约100个字符
isOverflow.value = props.answerText.length > 100 isOverflow.value = props.answerText.length > 100
const lookDetailAction = () => {
uni.navigateTo({
url: `/pages/long-answer/index?message=${props.answerText}`,
});
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@@ -0,0 +1,18 @@
<template>
<ChatMarkdown :text="answerText" />
</template>
<script setup>
import ChatMarkdown from "../index/components/chat/ChatMarkdown/index.vue";
const props = defineProps({
answerText: {
type: String,
default: "",
}
});
onLoad(({ message = "" }) => {
props.answerText = message;
});
</script>