feat: 兼容老的长文本
This commit is contained in:
@@ -8,25 +8,29 @@
|
|||||||
<!-- ✅ 滚动区域 -->
|
<!-- ✅ 滚动区域 -->
|
||||||
<scroll-view class="flex-full overflow-hidden chat-scroll" scroll-y :scroll-into-view="scrollIntoViewId" scroll-with-animation @scroll="onScroll" @touchstart="onTouchStart" @touchend="onTouchEnd" @touchcancel="onTouchEnd">
|
<scroll-view class="flex-full overflow-hidden chat-scroll" scroll-y :scroll-into-view="scrollIntoViewId" scroll-with-animation @scroll="onScroll" @touchstart="onTouchStart" @touchend="onTouchEnd" @touchcancel="onTouchEnd">
|
||||||
<view class="flex flex-col pt-12 px-16 pb-24 border-box gap-8">
|
<view class="flex flex-col pt-12 px-16 pb-24 border-box gap-8">
|
||||||
<view v-if="headerSections.title || headerSections.tag" class="long-answer-header">
|
<template v-if="hasStructuredLongTextData">
|
||||||
<view v-if="headerSections.title" class="long-answer-title">
|
<view v-if="headerSections.title || headerSections.tag" class="long-answer-header">
|
||||||
{{ headerSections.title.contentValue }}
|
<view v-if="headerSections.title" class="long-answer-title">
|
||||||
|
{{ headerSections.title.contentValue }}
|
||||||
|
</view>
|
||||||
|
<view v-if="headerSections.tag" class="long-answer-tag" :style="longAnswerTagStyle">
|
||||||
|
{{ headerSections.tag.contentValue }}
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view v-if="headerSections.tag" class="long-answer-tag" :style="longAnswerTagStyle">
|
|
||||||
{{ headerSections.tag.contentValue }}
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<template v-for="section in contentSections" :key="section.contentKey">
|
<template v-for="section in contentSections" :key="section.contentKey">
|
||||||
<ParsedValueView
|
<ParsedValueView
|
||||||
v-if="shouldUseParsedValueView(section)"
|
v-if="shouldUseParsedValueView(section)"
|
||||||
:field-key="section.contentKey"
|
:field-key="section.contentKey"
|
||||||
:value="section.parsedValue !== null ? section.parsedValue : section.contentValue"
|
:value="section.parsedValue !== null ? section.parsedValue : section.contentValue"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ChatMarkdown v-else :text="section.contentValue" />
|
<ChatMarkdown v-else :text="section.contentValue" />
|
||||||
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<ChatMarkdown v-else-if="answerText" :text="answerText" />
|
||||||
|
|
||||||
<!-- ✅ 底部锚点(必须存在) -->
|
<!-- ✅ 底部锚点(必须存在) -->
|
||||||
<view id="bottom-anchor"></view>
|
<view id="bottom-anchor"></view>
|
||||||
</view>
|
</view>
|
||||||
@@ -64,6 +68,10 @@ const longAnswerTagStyle = computed(() => buildTagToneStyle(longAnswerTagColor.v
|
|||||||
let unsubscribe = null;
|
let unsubscribe = null;
|
||||||
|
|
||||||
const HIDDEN_DETAIL_SECTION_KEYS = [];
|
const HIDDEN_DETAIL_SECTION_KEYS = [];
|
||||||
|
const hasStructuredLongTextData = computed(() => {
|
||||||
|
const values = longTextData.value?.values;
|
||||||
|
return !!(values && Object.keys(values).length > 0);
|
||||||
|
});
|
||||||
|
|
||||||
const shouldUseParsedValueView = (section) => {
|
const shouldUseParsedValueView = (section) => {
|
||||||
return (
|
return (
|
||||||
@@ -75,19 +83,14 @@ const shouldUseParsedValueView = (section) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const renderSections = computed(() => {
|
const renderSections = computed(() => {
|
||||||
const data = longTextData.value;
|
if (!hasStructuredLongTextData.value) return [];
|
||||||
if (data && data.values) {
|
|
||||||
return getLongTextSections(data)
|
|
||||||
.filter((section) => section.contentValue)
|
|
||||||
.map((section) => ({
|
|
||||||
...section,
|
|
||||||
fromLongTextData: true,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
return answerText.value
|
return getLongTextSections(longTextData.value)
|
||||||
? [{ contentKey: "content", contentValue: answerText.value }]
|
.filter((section) => section.contentValue)
|
||||||
: [];
|
.map((section) => ({
|
||||||
|
...section,
|
||||||
|
fromLongTextData: true,
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
const headerSections = computed(() => {
|
const headerSections = computed(() => {
|
||||||
|
|||||||
@@ -74,15 +74,16 @@
|
|||||||
"
|
"
|
||||||
>
|
>
|
||||||
<AnswerComponent
|
<AnswerComponent
|
||||||
v-if="isLongTextCard(item.componentName)"
|
v-if="isLongTextCard(item.componentName) && (item.componentName === CompName.longTextCard)"
|
||||||
|
:content="item.componentMsg || ''"
|
||||||
:longTextData="item.longTextData"
|
:longTextData="item.longTextData"
|
||||||
:finish="item.finish"
|
:finish="item.finish"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- <LongTextGuideCardPreview
|
<LongTextGuideCardPreview
|
||||||
v-if="isLongTextCard(item.componentName) && (item.componentName !== CompName.longTextCard)"
|
v-if="isLongTextCard(item.componentName) && (item.componentName !== CompName.longTextCard)"
|
||||||
:componentName="item.componentName"
|
:componentName="item.componentName"
|
||||||
/> -->
|
/>
|
||||||
|
|
||||||
<QuickBookingComponent
|
<QuickBookingComponent
|
||||||
v-if="
|
v-if="
|
||||||
@@ -798,6 +799,7 @@ const handleWebSocketMessage = (data) => {
|
|||||||
messageId: currentSessionMessageId,
|
messageId: currentSessionMessageId,
|
||||||
replyMessageId: data.replyMessageId || "",
|
replyMessageId: data.replyMessageId || "",
|
||||||
componentName: "",
|
componentName: "",
|
||||||
|
componentMsg: "",
|
||||||
longTextData: null,
|
longTextData: null,
|
||||||
finish: false,
|
finish: false,
|
||||||
};
|
};
|
||||||
@@ -820,6 +822,7 @@ const handleWebSocketMessage = (data) => {
|
|||||||
messageId: currentSessionMessageId,
|
messageId: currentSessionMessageId,
|
||||||
replyMessageId: data.replyMessageId || "",
|
replyMessageId: data.replyMessageId || "",
|
||||||
componentName: "",
|
componentName: "",
|
||||||
|
componentMsg: "",
|
||||||
longTextData: null,
|
longTextData: null,
|
||||||
finish: false,
|
finish: false,
|
||||||
};
|
};
|
||||||
@@ -1213,6 +1216,7 @@ const sendChat = async (message, isInstruct = false) => {
|
|||||||
messageId: currentSessionMessageId,
|
messageId: currentSessionMessageId,
|
||||||
replyMessageId: "",
|
replyMessageId: "",
|
||||||
componentName: "",
|
componentName: "",
|
||||||
|
componentMsg: "",
|
||||||
longTextData: null,
|
longTextData: null,
|
||||||
finish: false,
|
finish: false,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<view v-if="longTextData?.values" class="w-full bg-white border-box border-ff overflow-hidden rounded-20 flex flex-col">
|
<view v-if="shouldRenderCard" class="w-full bg-white border-box border-ff overflow-hidden rounded-20 flex flex-col">
|
||||||
<!-- 占位撑开 -->
|
<!-- 占位撑开 -->
|
||||||
<view class="w-vw"></view>
|
<view class="w-vw"></view>
|
||||||
<view class="flex flex-col px-16 pt-16 pb-12 border-box" @click="lookDetailAction">
|
<view class="flex flex-col px-16 pt-16 pb-12 border-box" @click="lookDetailAction">
|
||||||
@@ -60,8 +60,20 @@ const tag = computed(() => getLongTextValue(props.longTextData, LONG_TEXT_KEYS.t
|
|||||||
const title = computed(() => getLongTextValue(props.longTextData, LONG_TEXT_KEYS.title));
|
const title = computed(() => getLongTextValue(props.longTextData, LONG_TEXT_KEYS.title));
|
||||||
const longAnswerTagColor = ref(pickRandomTagToneColor());
|
const longAnswerTagColor = ref(pickRandomTagToneColor());
|
||||||
const longAnswerTagStyle = computed(() => buildTagToneStyle(longAnswerTagColor.value));
|
const longAnswerTagStyle = computed(() => buildTagToneStyle(longAnswerTagColor.value));
|
||||||
|
const hasStructuredLongTextData = computed(() => {
|
||||||
|
const values = props.longTextData?.values;
|
||||||
|
return !!(values && Object.keys(values).length > 0);
|
||||||
|
});
|
||||||
|
const detailLongTextData = computed(() => {
|
||||||
|
return hasStructuredLongTextData.value ? props.longTextData : null;
|
||||||
|
});
|
||||||
const previewContent = computed(() => {
|
const previewContent = computed(() => {
|
||||||
return getLongTextPreviewText(props.longTextData, [LONG_TEXT_KEYS.contentSummary]);
|
const structuredPreview = getLongTextPreviewText(props.longTextData, [LONG_TEXT_KEYS.contentSummary]);
|
||||||
|
if (structuredPreview) return structuredPreview;
|
||||||
|
return hasStructuredLongTextData.value ? "" : props.content || "";
|
||||||
|
});
|
||||||
|
const shouldRenderCard = computed(() => {
|
||||||
|
return hasStructuredLongTextData.value || !!previewContent.value || !props.finish;
|
||||||
});
|
});
|
||||||
|
|
||||||
// 处理文本内容:按行截断以保证预览最多显示两行(更贴近视觉行数)
|
// 处理文本内容:按行截断以保证预览最多显示两行(更贴近视觉行数)
|
||||||
@@ -92,7 +104,7 @@ const isOverflow = computed(() => {
|
|||||||
const contentStr = previewContent.value ? String(previewContent.value) : "";
|
const contentStr = previewContent.value ? String(previewContent.value) : "";
|
||||||
const lines = contentStr.split(/\r?\n/);
|
const lines = contentStr.split(/\r?\n/);
|
||||||
return (
|
return (
|
||||||
hasLongTextExtraSections(props.longTextData) ||
|
(hasStructuredLongTextData.value && hasLongTextExtraSections(props.longTextData)) ||
|
||||||
lines.length > PREVIEW_LINES ||
|
lines.length > PREVIEW_LINES ||
|
||||||
contentStr.length > PREVIEW_CHAR_LIMIT
|
contentStr.length > PREVIEW_CHAR_LIMIT
|
||||||
);
|
);
|
||||||
@@ -128,11 +140,11 @@ const lookDetailAction = () => {
|
|||||||
streamId,
|
streamId,
|
||||||
previewContent.value ? String(previewContent.value) : "",
|
previewContent.value ? String(previewContent.value) : "",
|
||||||
!!props.finish,
|
!!props.finish,
|
||||||
props.longTextData || null,
|
detailLongTextData.value,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
StreamManager.openStream(streamId, message, !!props.finish, props.longTextData || null);
|
StreamManager.openStream(streamId, message, !!props.finish, detailLongTextData.value);
|
||||||
|
|
||||||
cleanupStreamWatchers();
|
cleanupStreamWatchers();
|
||||||
|
|
||||||
@@ -154,7 +166,7 @@ const lookDetailAction = () => {
|
|||||||
streamId,
|
streamId,
|
||||||
previewContent.value ? String(previewContent.value) : "",
|
previewContent.value ? String(previewContent.value) : "",
|
||||||
!!f,
|
!!f,
|
||||||
props.longTextData || null,
|
detailLongTextData.value,
|
||||||
);
|
);
|
||||||
if (f) {
|
if (f) {
|
||||||
cleanupStreamWatchers();
|
cleanupStreamWatchers();
|
||||||
@@ -179,7 +191,7 @@ const lookDetailAction = () => {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
max-height: 52px;
|
max-height: 62px;
|
||||||
}
|
}
|
||||||
.long-answer-tag {
|
.long-answer-tag {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
|
|||||||
Reference in New Issue
Block a user