|
|
@ -232,6 +232,7 @@ |
|
|
@touchmove="onBackTopTouchMove" |
|
|
@touchmove="onBackTopTouchMove" |
|
|
@touchend="onBackTopTouchEnd" |
|
|
@touchend="onBackTopTouchEnd" |
|
|
@click="onBackTopClick" |
|
|
@click="onBackTopClick" |
|
|
|
|
|
v-if="messages.length > 0" |
|
|
></image> |
|
|
></image> |
|
|
|
|
|
|
|
|
<!-- 搜索历史侧拉框 --> |
|
|
<!-- 搜索历史侧拉框 --> |
|
|
@ -249,7 +250,7 @@ |
|
|
<view class="delete-all-container"> |
|
|
<view class="delete-all-container"> |
|
|
<image |
|
|
<image |
|
|
class="delete-icon" |
|
|
class="delete-icon" |
|
|
src="/static/icons/Group_48095481.svg" |
|
|
|
|
|
|
|
|
src="/static/icons/Group_48095481.svg" @click="clearAllHistory" |
|
|
></image> |
|
|
></image> |
|
|
<text class="delete-all" @click="clearAllHistory">删除全部</text> |
|
|
<text class="delete-all" @click="clearAllHistory">删除全部</text> |
|
|
</view> |
|
|
</view> |
|
|
@ -595,8 +596,21 @@ const groupedHistory = computed(() => { |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
const clearAllHistory = () => { |
|
|
const clearAllHistory = () => { |
|
|
searchHistory.value = []; |
|
|
|
|
|
// uni.setStorageSync("search_history", []); |
|
|
|
|
|
|
|
|
uni.showModal({ |
|
|
|
|
|
title: '确认删除', |
|
|
|
|
|
content: '确定要删除全部历史记录吗?该操作不可撤销。', |
|
|
|
|
|
confirmText: '删除', |
|
|
|
|
|
cancelText: '取消', |
|
|
|
|
|
success: (res) => { |
|
|
|
|
|
if (res.confirm) { |
|
|
|
|
|
// 当前历史面板依赖 historyList,而非 searchHistory |
|
|
|
|
|
historyList.value = []; |
|
|
|
|
|
// 同步清空本地旧缓存(如果曾使用) |
|
|
|
|
|
// uni.setStorageSync("search_history", []); |
|
|
|
|
|
uni.showToast({ title: '历史已清空', icon: 'none' }); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
}) |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
// 发送消息 |
|
|
// 发送消息 |
|
|
@ -669,7 +683,7 @@ const simulateBotResponse = async (userMessage) => { |
|
|
|
|
|
|
|
|
// 更新机器人的消息内容 |
|
|
// 更新机器人的消息内容 |
|
|
const errorMessage = res.message || "请求失败,请稍后重试"; |
|
|
const errorMessage = res.message || "请求失败,请稍后重试"; |
|
|
let responseText = `我已经收到您的消息: "${userMessage}"。错误信息: "${errorMessage}"`; |
|
|
|
|
|
|
|
|
let responseText = `我已经收到您的消息: "${userMessage}"。"${errorMessage}"`; |
|
|
|
|
|
|
|
|
// 开始打字机效果显示错误信息 |
|
|
// 开始打字机效果显示错误信息 |
|
|
let index = 0; |
|
|
let index = 0; |
|
|
@ -677,26 +691,48 @@ const simulateBotResponse = async (userMessage) => { |
|
|
|
|
|
|
|
|
const typeWriter = () => { |
|
|
const typeWriter = () => { |
|
|
if (index < responseText.length) { |
|
|
if (index < responseText.length) { |
|
|
const ch = responseText.charAt(index); |
|
|
|
|
|
|
|
|
let ch = responseText.charAt(index); |
|
|
|
|
|
let charsToAdd = ch; |
|
|
|
|
|
let newIndex = index + 1; |
|
|
|
|
|
|
|
|
|
|
|
// 检查是否遇到HTML标签开始 |
|
|
|
|
|
if (ch === '<') { |
|
|
|
|
|
// 寻找标签结束位置 |
|
|
|
|
|
let tagEndIndex = responseText.indexOf('>', index); |
|
|
|
|
|
if (tagEndIndex !== -1) { |
|
|
|
|
|
// 完整获取标签内容 |
|
|
|
|
|
charsToAdd = responseText.substring(index, tagEndIndex + 1); |
|
|
|
|
|
newIndex = tagEndIndex + 1; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
const current = messages.value[botIndex]; |
|
|
const current = messages.value[botIndex]; |
|
|
// 通过数组替换触发渲染,避免部分平台对子项属性变更不响应 |
|
|
// 通过数组替换触发渲染,避免部分平台对子项属性变更不响应 |
|
|
messages.value.splice(botIndex, 1, { |
|
|
messages.value.splice(botIndex, 1, { |
|
|
...current, |
|
|
...current, |
|
|
content: current.content + ch, |
|
|
|
|
|
|
|
|
content: current.content + charsToAdd, |
|
|
isTyping: true, |
|
|
isTyping: true, |
|
|
}); |
|
|
}); |
|
|
index++; |
|
|
|
|
|
|
|
|
index = newIndex; |
|
|
scrollToBottom(); |
|
|
scrollToBottom(); |
|
|
|
|
|
|
|
|
// 字符间延迟,模拟打字效果 |
|
|
// 字符间延迟,模拟打字效果 |
|
|
const baseDelay = 5; // 普通字符基础延迟(毫秒) |
|
|
const baseDelay = 5; // 普通字符基础延迟(毫秒) |
|
|
const slowPunct = /[。!?!?;;]/; // 句号、感叹号、分号等较长停顿 |
|
|
const slowPunct = /[。!?!?;;]/; // 句号、感叹号、分号等较长停顿 |
|
|
const midPunct = /[,、,::]/; // 逗号、顿号、冒号等中等停顿 |
|
|
const midPunct = /[,、,::]/; // 逗号、顿号、冒号等中等停顿 |
|
|
const delay = slowPunct.test(ch) |
|
|
|
|
|
? 220 |
|
|
|
|
|
: midPunct.test(ch) |
|
|
|
|
|
? 120 |
|
|
|
|
|
: baseDelay; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 如果是标签,使用更短的延迟或者立即显示 |
|
|
|
|
|
let delay; |
|
|
|
|
|
if (charsToAdd.startsWith('<')) { |
|
|
|
|
|
delay = 1; // 标签快速显示 |
|
|
|
|
|
} else { |
|
|
|
|
|
delay = slowPunct.test(ch) |
|
|
|
|
|
? 220 |
|
|
|
|
|
: midPunct.test(ch) |
|
|
|
|
|
? 120 |
|
|
|
|
|
: baseDelay; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
setTimeout(typeWriter, delay); |
|
|
setTimeout(typeWriter, delay); |
|
|
} else { |
|
|
} else { |
|
|
// 打字完成,更新状态 |
|
|
// 打字完成,更新状态 |
|
|
@ -786,22 +822,33 @@ const simulateBotResponse = async (userMessage) => { |
|
|
|
|
|
|
|
|
const typeWriter = () => { |
|
|
const typeWriter = () => { |
|
|
if (index < responseText.length) { |
|
|
if (index < responseText.length) { |
|
|
const ch = responseText.charAt(index); |
|
|
|
|
|
|
|
|
let ch = responseText.charAt(index); |
|
|
|
|
|
let charsToAdd = ch; |
|
|
|
|
|
let newIndex = index + 1; |
|
|
|
|
|
let delay = baseDelay; |
|
|
|
|
|
|
|
|
|
|
|
// 检查是否遇到HTML标签开始 |
|
|
|
|
|
if (ch === '<') { |
|
|
|
|
|
// 寻找标签结束位置 |
|
|
|
|
|
let tagEndIndex = responseText.indexOf('>', index); |
|
|
|
|
|
if (tagEndIndex !== -1) { |
|
|
|
|
|
// 完整获取标签内容 |
|
|
|
|
|
charsToAdd = responseText.substring(index, tagEndIndex + 1); |
|
|
|
|
|
newIndex = tagEndIndex + 1; |
|
|
|
|
|
delay = 1; // 标签快速显示 |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
const current = messages.value[botIndex]; |
|
|
const current = messages.value[botIndex]; |
|
|
// 通过数组替换触发渲染,避免部分平台对子项属性变更不响应 |
|
|
// 通过数组替换触发渲染,避免部分平台对子项属性变更不响应 |
|
|
messages.value.splice(botIndex, 1, { |
|
|
messages.value.splice(botIndex, 1, { |
|
|
...current, |
|
|
...current, |
|
|
content: current.content + ch, |
|
|
|
|
|
|
|
|
content: current.content + charsToAdd, |
|
|
isTyping: true, |
|
|
isTyping: true, |
|
|
}); |
|
|
}); |
|
|
index++; |
|
|
|
|
|
|
|
|
index = newIndex; |
|
|
scrollToBottom(); |
|
|
scrollToBottom(); |
|
|
|
|
|
|
|
|
const delay = slowPunct.test(ch) |
|
|
|
|
|
? 220 |
|
|
|
|
|
: midPunct.test(ch) |
|
|
|
|
|
? 120 |
|
|
|
|
|
: baseDelay; |
|
|
|
|
|
setTimeout(typeWriter, delay); |
|
|
setTimeout(typeWriter, delay); |
|
|
} else { |
|
|
} else { |
|
|
const current = messages.value[botIndex]; |
|
|
const current = messages.value[botIndex]; |
|
|
@ -1157,7 +1204,7 @@ async function itemClick(item) { |
|
|
|
|
|
|
|
|
.welcome-section { |
|
|
.welcome-section { |
|
|
/* 灰色卡片(recommend-card)之后展示背景图 */ |
|
|
/* 灰色卡片(recommend-card)之后展示背景图 */ |
|
|
margin-top: 10rpx; |
|
|
|
|
|
|
|
|
margin-top: 2rem; |
|
|
display: flex; |
|
|
display: flex; |
|
|
align-items: center; |
|
|
align-items: center; |
|
|
justify-content: center; |
|
|
justify-content: center; |
|
|
@ -1769,9 +1816,21 @@ async function itemClick(item) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
.thinking-content { |
|
|
.thinking-content { |
|
|
|
|
|
transition: transform 1s ease; /* 添加过渡效果 */ |
|
|
|
|
|
transform-origin: top center; /* 设置变换原点 */ |
|
|
padding: 20rpx 30rpx; |
|
|
padding: 20rpx 30rpx; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@keyframes transform { |
|
|
|
|
|
from { |
|
|
|
|
|
transform: scaleY(0); |
|
|
|
|
|
} |
|
|
|
|
|
to { |
|
|
|
|
|
transform: scaleY(1); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
.thinking-item { |
|
|
.thinking-item { |
|
|
display: flex; |
|
|
display: flex; |
|
|
align-items: center; |
|
|
align-items: center; |
|
|
|