diff --git a/src/pages/index/components/chat/ChatMainList/index.vue b/src/pages/index/components/chat/ChatMainList/index.vue
index f995910..6183ef3 100644
--- a/src/pages/index/components/chat/ChatMainList/index.vue
+++ b/src/pages/index/components/chat/ChatMainList/index.vue
@@ -477,31 +477,62 @@ const handleWebSocketMessage = (data) => {
}
let aiMsgIndex = -1;
- if (currentSessionMessageId && pendingMap.has(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;
- }
+ // Prefer matching by replyMessageId if provided
+ if (data.replyMessageId) {
+ // 1) Try to find an existing AI message that already has the same replyMessageId
+ for (let i = chatMsgList.value.length - 1; i >= 0; i--) {
+ const it = chatMsgList.value[i];
+ if (it && it.msgType === MessageRole.AI && it.replyMessageId === data.replyMessageId) {
+ aiMsgIndex = i;
+ break;
+ }
+ }
+
+ // 2) If not found, check pendingMap for currentSessionMessageId
+ if (aiMsgIndex === -1 && currentSessionMessageId && pendingMap.has(currentSessionMessageId)) {
+ const idx = pendingMap.get(currentSessionMessageId);
+ if (idx >= 0 && idx < chatMsgList.value.length) {
+ const item = chatMsgList.value[idx];
+ // If the pending item already has a different non-empty replyMessageId, create a new AI entry
+ if (item && item.msgType === MessageRole.AI && item.replyMessageId && item.replyMessageId !== data.replyMessageId) {
+ const aiMsg = {
+ msgId: `msg_${chatMsgList.value.length}`,
+ msgType: MessageRole.AI,
+ msg: "",
+ isLoading: false,
+ messageId: currentSessionMessageId,
+ replyMessageId: data.replyMessageId || '',
+ componentName: "",
+ title: "",
+ finish: false,
+ };
+ chatMsgList.value.push(aiMsg);
+ aiMsgIndex = chatMsgList.value.length - 1;
+ } else {
+ // Reuse the pending item
+ aiMsgIndex = idx;
+ }
+ }
+ }
+
+ // 3) If still not found, create a new AI message for this replyMessageId
+ if (aiMsgIndex === -1) {
+ const aiMsg = {
+ msgId: `msg_${chatMsgList.value.length}`,
+ msgType: MessageRole.AI,
+ msg: "",
+ isLoading: false,
+ messageId: currentSessionMessageId,
+ replyMessageId: data.replyMessageId || '',
+ componentName: "",
+ title: "",
+ finish: false,
+ };
+ chatMsgList.value.push(aiMsg);
+ aiMsgIndex = chatMsgList.value.length - 1;
}
} else {
- // 向后搜索最近的 AI 消息(回退逻辑)
+ // No replyMessageId: fall back to most recent AI message
for (let i = chatMsgList.value.length - 1; i >= 0; i--) {
if (chatMsgList.value[i] && chatMsgList.value[i].msgType === MessageRole.AI) {
aiMsgIndex = i;
@@ -572,7 +603,7 @@ const handleWebSocketMessage = (data) => {
}
// 清理 pendingMap / timeout
- const ownedMessageId = chatMsgList.value[aiMsgIndex].messageId || msgId;
+ const ownedMessageId = chatMsgList.value[aiMsgIndex].messageId || null;
if (ownedMessageId) {
if (pendingTimeouts.has(ownedMessageId)) {
clearTimeout(pendingTimeouts.get(ownedMessageId));
diff --git a/src/pages/index/components/module/AnswerComponent/index.vue b/src/pages/index/components/module/AnswerComponent/index.vue
index 18f1be4..2eca5e2 100644
--- a/src/pages/index/components/module/AnswerComponent/index.vue
+++ b/src/pages/index/components/module/AnswerComponent/index.vue
@@ -3,7 +3,7 @@
-
+
游玩划重点
@@ -12,7 +12,7 @@
-
+
查看详情
@@ -43,10 +43,28 @@ const props = defineProps({
// 用于强制重新渲染的key
const textKey = ref(0);
-// 处理文本内容(纯计算,不应有副作用)
+// 处理文本内容:按行截断以保证预览最多显示三行(更贴近视觉行数)
+// 点击“查看详情”会跳转到完整页面(不受预览截断影响)。
+const PREVIEW_LINES = 3;
+const PREVIEW_CHAR_LIMIT = 100; // 作为备用,当没有换行但过长时也会截断
const processedText = computed(() => {
- if (!props.text) return "";
- return String(props.text);
+ const txt = props.text ? String(props.text) : "";
+ if (!txt) return "";
+
+ // 按行分割(保留空行)
+ const lines = txt.split(/\r?\n/);
+
+ // 如果行数超过限制,截取前 PREVIEW_LINES 行并添加省略号
+ if (lines.length > PREVIEW_LINES) {
+ return lines.slice(0, PREVIEW_LINES).join("\n") + "...";
+ }
+
+ // 若虽然行数不超过,但总长度仍然很长,做字符级截断作为兜底
+ if (txt.length > PREVIEW_CHAR_LIMIT) {
+ return txt.slice(0, PREVIEW_CHAR_LIMIT) + "...";
+ }
+
+ return txt;
});
// 监听 text 变化:更新 textKey 并同步 isOverflow(合并为单一响应函数,避免冗余)
@@ -54,7 +72,8 @@ watch(
() => props.text,
(newText, oldText) => {
const textStr = newText ? String(newText) : "";
- isOverflow.value = textStr.length > 100;
+ const lines = textStr.split(/\r?\n/);
+ isOverflow.value = lines.length > PREVIEW_LINES || textStr.length > PREVIEW_CHAR_LIMIT;
if (newText !== oldText) {
textKey.value++;
}
diff --git a/src/uni_modules/zero-markdown-view/components/zero-markdown-view/zero-markdown-view.vue b/src/uni_modules/zero-markdown-view/components/zero-markdown-view/zero-markdown-view.vue
index 82db93b..2409d7f 100644
--- a/src/uni_modules/zero-markdown-view/components/zero-markdown-view/zero-markdown-view.vue
+++ b/src/uni_modules/zero-markdown-view/components/zero-markdown-view/zero-markdown-view.vue
@@ -111,38 +111,40 @@ export default {
`,
// 一级标题
h1: `
- margin:4px 0;
- font-size: 20px;
- text-align: center;
- font-weight: bold;
- color: ${themeColor};
+ margin:8px 0;
+ font-size: 20px;
+ line-height: 1.6;
+ text-align: center;
+ font-weight: bold;
+ color: ${themeColor};
font-family: ${fontFamily};
- padding:3px 10px 1px;
- border-bottom: 2px solid ${themeColor};
- border-top-right-radius:3px;
- border-top-left-radius:3px;
-
- `,
+ padding:6px 10px 4px;
+ border-bottom: 2px solid ${themeColor};
+ border-top-right-radius:3px;
+ border-top-left-radius:3px;
+ `,
// 二级标题
h2: `
- margin:4px 0;
- font-size: 18px;
- text-align:center;
- color:${themeColor};
+ margin:6px 0;
+ font-size: 18px;
+ line-height: 1.55;
+ text-align:center;
+ color:${themeColor};
font-family: ${fontFamily};
- font-weight:bolder;
- padding-left:10px;
- // border:1px solid ${themeColor};
- `,
+ font-weight:bolder;
+ padding-left:10px;
+ // border:1px solid ${themeColor};
+ `,
// 三级标题
h3: `
- margin:4px 0;
- font-size: 16px;
- color: ${themeColor};
+ margin:6px 0;
+ font-size: 16px;
+ line-height: 1.5;
+ color: ${themeColor};
font-family: ${fontFamily};
- padding-left:10px;
- border-left:3px solid ${themeColor};
- `,
+ padding-left:10px;
+ border-left:3px solid ${themeColor};
+ `,
// 引用
blockquote: `
margin:4px 0;
@@ -151,7 +153,7 @@ export default {
color: #777777;
border-left: 4px solid #dddddd;
padding: 0 10px;
- `,
+ `,
// 列表
ul: `
font-size: 14px;
@@ -231,25 +233,28 @@ export default {
`,
// 一级标题
h1: `
- margin:4px 0;
- font-size: 20px;
- color: ${themeColor};
- font-family: ${fontFamily};
- `,
+ margin:8px 0;
+ font-size: 20px;
+ line-height: 1.6;
+ color: ${themeColor};
+ font-family: ${fontFamily};
+ `,
// 二级标题
h2: `
- margin:4px 0;
- font-size: 18px;
- color: ${themeColor};
- font-family: ${fontFamily};
- `,
+ margin:6px 0;
+ font-size: 18px;
+ line-height: 1.55;
+ color: ${themeColor};
+ font-family: ${fontFamily};
+ `,
// 三级标题
h3: `
- margin:4x 0;
- font-size: 16px;
- color: ${themeColor};
- font-family: ${fontFamily};
- `,
+ margin:6px 0;
+ font-size: 16px;
+ line-height: 1.5;
+ color: ${themeColor};
+ font-family: ${fontFamily};
+ `,
// 四级标题
h4: `
margin:4px 0;