Compare commits

..

No commits in common. "25f38fb41fe7923492a9eb54a8bf0275ca5be5f0" and "33572177c07df83d084c82cdf6afe3fe0dd4d1e1" have entirely different histories.

2 changed files with 26 additions and 84 deletions

View File

@ -589,13 +589,6 @@ export default {
loading: 'Loading...',
updateRecommendation: 'Update Recommendation',
addRecommendation: 'Add Recommendation',
},
vabtabs: {
refresh: 'Refresh',
closeOthers: 'Close Others',
closeLeft: 'Close Left',
closeRight: 'Close Right',
closeAll: 'Close All',
},
}
},
}

View File

@ -281,8 +281,6 @@
</div>
</div>
</div>
<div ref="bottomAnchor"></div>
</div>
<!-- 输入区域 -->
@ -384,12 +382,11 @@ import { ref, reactive, nextTick, watch, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import VueOfficePdf from '@vue-office/pdf'
import VabChart from '@/plugins/VabChart/index.vue'
import { ChevronDownIcon, ChevronUpIcon } from '@heroicons/vue/24/solid'
import { sendChatMessage, type ChatMessageResponse, type ChatMessageSendRequest, stopMessagesStream, getFilePathList, type TraceFile, type TraceData } from '@/api/chat'
import { useI18n } from 'vue-i18n'
import { throttle } from 'lodash'
const expanded = ref(false)
const { t, locale } = useI18n()
// Props
interface Props {
@ -444,12 +441,11 @@ interface Message {
isOpenRemark?: boolean //
}
//
const bottomAnchor = ref<HTMLElement | null>(null)
const messages = ref<Message[]>([])
const inputMessage = ref('')
const messagesContainer = ref<HTMLElement | null>(null)
const messagesContainer = ref<HTMLElement>()
const isLoading = ref(false)
const currentTaskId = ref('')
const showStopButton = ref(false)
@ -567,7 +563,7 @@ const createNewChat = async () => {
//
await nextTick()
throttledScrollToBottom()
await scrollToBottom()
}
//
@ -636,10 +632,6 @@ watch(messages, (newMessages) => {
}
}, { deep: true })
//
let isUserScrolling = false
//
onMounted(async () => {
loadChatHistory()
@ -647,15 +639,6 @@ onMounted(async () => {
if (chatHistory.value.length === 0) {
await createNewChat()
}
//
messagesContainer.value?.addEventListener('scroll', () => {
const el = messagesContainer.value
if (!el) return
const threshold = 100
isUserScrolling = el.scrollHeight - el.scrollTop - el.clientHeight > threshold
})
})
// ECharts
@ -700,15 +683,10 @@ const formatAnswer = async (text: string) => {
//
const wrappedHtml = html.replace(
/<table>/g,
`<details class="table-wrapper" open>
<summary>
Expand / Collapse table
</summary>
<div class="table-container"><table class="excel-table" border="1" width="auto" cellspacing="0" cellpadding="0">`
'<div class="table-container"><table class="excel-table" border="1" width="auto" cellspacing="0" cellpadding="0">'
).replace(
/<\/table>/g,
'</table></div></details>'
/<\/table>/g,
'</table></div>'
).replace(
/<th>/g,
'<th style="border: 1px solid #cbd5e1; padding: 12px; background: #f1f5f9;">'
@ -722,9 +700,9 @@ const formatAnswer = async (text: string) => {
'strong', 'em', 'code', 'pre', 'a', 'br', 'p',
'ul', 'ol', 'li', 'h1', 'h2', 'h3', 'span',
'blockquote', 'hr', 'table', 'thead', 'tbody',
'tr', 'th', 'td', 'div', 'details', 'summary'
'tr', 'th', 'td', 'div'
],
ALLOWED_ATTR: ['href', 'target', 'class', 'style', 'data-chart-id', 'border', 'cellspacing', 'cellpadding', 'open']
ALLOWED_ATTR: ['href', 'target', 'class', 'style', 'data-chart-id', 'border', 'cellspacing', 'cellpadding']
}) as string
console.log('Markdown输入:', processedText)
@ -823,6 +801,9 @@ const sendMessage = async () => {
currentTaskId.value = data.taskId
}
// messages.value = [...messages.value]
// botMessage.text += data.answer
// await scrollToBottom()
throttledScrollToBottom()
}
} catch (e) {
@ -843,6 +824,7 @@ const sendMessage = async () => {
const formatted = await formatAnswer(parseThink(botMessage.text).answer)
botMessage.formattedText = formatted.html
botMessage.echarts = formatted.echarts
// messages.value = [...messages.value]
if (data.conversationId) {
newConversationId = data.conversationId
@ -870,6 +852,7 @@ const sendMessage = async () => {
botMessage.sources = data
botMessage.conversationId = newConversationId
botMessage.messageId = newMessageId
// messages.value = [...messages.value]
}
} catch (error) {
console.log('获取文件来源失败:', error)
@ -902,35 +885,20 @@ const sendMessage = async () => {
if (messages.value[messages.value.length - 1]?.isLoading) {
messages.value[messages.value.length - 1].isLoading = false
}
scrollToBottomForce()
await scrollToBottom()
}
}
const scrollToBottomForce = async () => {
const scrollToBottom = async () => {
await nextTick()
if (messagesContainer.value) {
messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight
}
}
//
const scrollToBottom = async () => {
await nextTick()
setTimeout(() => {
requestAnimationFrame(() => {
if (messagesContainer.value && !isUserScrolling) {
bottomAnchor.value.scrollIntoView({
behavior: 'smooth',
block: 'start'
})
}
})
},60)
}
const throttledScrollToBottom = throttle(() => {
scrollToBottom()
}, 300,{ leading: true, trailing: true })
scrollToBottom()
}, 150)
//
const parseThink = (text: string) => {
@ -1259,7 +1227,7 @@ const regenerateResponse = async (userQuery: string) => {
formattedText: ''
})
messages.value.push(botMessage)
throttledScrollToBottom()
await scrollToBottom()
// ID
const currentSession = chatHistory.value[currentChatIndex.value]
@ -1319,7 +1287,8 @@ const regenerateResponse = async (userQuery: string) => {
currentTaskId.value = data.taskId
}
throttledScrollToBottom()
// messages.value = [...messages.value]
await scrollToBottom()
}
} catch (e) {
console.error('解析错误:', e)
@ -1339,6 +1308,7 @@ const regenerateResponse = async (userQuery: string) => {
const formatted = await formatAnswer(parseThink(botMessage.text).answer)
botMessage.formattedText = formatted.html
botMessage.echarts = formatted.echarts
// messages.value = [...messages.value]
if (data.conversationId) {
newConversationId = data.conversationId
@ -1366,6 +1336,7 @@ const regenerateResponse = async (userQuery: string) => {
botMessage.sources = data
botMessage.conversationId = newConversationId
botMessage.messageId = newMessageId
// messages.value = [...messages.value]
}
} catch (error) {
console.log('获取文件来源失败:', error)
@ -1398,7 +1369,7 @@ const regenerateResponse = async (userQuery: string) => {
if (messages.value[messages.value.length - 1]?.isLoading) {
messages.value[messages.value.length - 1].isLoading = false
}
scrollToBottomForce()
await scrollToBottom()
}
}
@ -1428,7 +1399,7 @@ const handleRecommendQuestionClick = (question: string) => {
<style scoped>
.chat-container {
height: 100%;
height: 90%;
display: flex;
background: #ffffff;
position: relative;
@ -2159,20 +2130,6 @@ const handleRecommendQuestionClick = (question: string) => {
}
::v-deep .table-wrapper summary {
cursor: pointer;
display: list-item;
align-items: center;
gap: 8px;
font-weight: 600;
padding: 6px 8px;
background: #f8fafc;
/* border: 1px solid #e2e8f0; */
/* border-radius: 6px; */
font-size: 14px;
}
/* .excel-table th,
.excel-table td {
white-space: nowrap;
@ -2748,14 +2705,6 @@ const handleRecommendQuestionClick = (question: string) => {
position: relative;
}
::v-deep .icon-chevron {
width: 20px;
height: 20px;
transition: transform 0.3s ease;
color: #333; /* 让箭头颜色和文字颜色一致 */
}
.chart-wrapper {
margin-bottom: 1.5rem;
background: #ffffff;