This commit is contained in:
2025-08-19 12:05:22 +08:00
parent 625178632b
commit 0c3fca167a

View File

@@ -219,6 +219,13 @@ export default {
// 消息显示优化
maxVisibleMessages: 50, // 最大可见消息数量
messageRenderBatch: 20, // 每批渲染的消息数量
// 鼠标跟踪相关
mouseX: 0, // 鼠标X坐标
mouseY: 0, // 鼠标Y坐标
eyeTrackingEnabled: true, // 是否启用眼睛跟踪
avatarRect: null, // 头像位置信息
eyeUpdateTimer: null, // 眼睛更新定时器
}
},
computed: {
@@ -255,6 +262,8 @@ export default {
setTimeout(() => {
if (!this.isDestroyed) {
this.scrollToBottom(false)
// 更新头像位置信息,确保鼠标跟踪正常工作
this.updateAvatarRect()
}
}, 100)
}
@@ -283,6 +292,9 @@ export default {
// 启动数字人自动眨眼
this.startAutoBlinking()
// 启动鼠标跟踪
this.startMouseTracking()
// 确保DOM完全渲染后再初始化聊天
this.$nextTick(() => {
setTimeout(async () => {
@@ -321,11 +333,18 @@ export default {
clearTimeout(this.contentUpdateTimer)
this.contentUpdateTimer = null
}
if (this.eyeUpdateTimer) {
clearTimeout(this.eyeUpdateTimer)
this.eyeUpdateTimer = null
}
// 清理数字人相关定时器
this.stopAutoBlinking()
this.stopAIAnimation()
// 停止鼠标跟踪
this.stopMouseTracking()
// 取消正在进行的请求
if (this.currentCancel) {
this.currentCancel()
@@ -745,6 +764,10 @@ export default {
this.inputMessage = ''
this.sending = true
// 初始化定时器变量
let streamTimeout = null
let noDataTimeout = null
// 添加到请求队列
const requestId = Date.now()
this.requestQueue.push(requestId)
@@ -796,7 +819,7 @@ export default {
})
// 添加额外的超时保护
const streamTimeout = setTimeout(() => {
streamTimeout = setTimeout(() => {
if (cancel) {
cancel('流式响应超时')
}
@@ -811,7 +834,6 @@ export default {
const { reader, decoder } = response
let buffer = ''
let lastUpdateTime = Date.now()
let noDataTimeout = null
while (true) {
// 设置无数据超时检测
@@ -1197,6 +1219,101 @@ export default {
}
},
// 启动鼠标跟踪
startMouseTracking() {
if (!this.eyeTrackingEnabled) return
// 添加鼠标移动监听器
document.addEventListener('mousemove', this.handleMouseMove)
// 获取头像位置信息
this.$nextTick(() => {
this.updateAvatarRect()
})
// 监听窗口大小变化,更新头像位置
window.addEventListener('resize', this.updateAvatarRect)
},
// 停止鼠标跟踪
stopMouseTracking() {
document.removeEventListener('mousemove', this.handleMouseMove)
window.removeEventListener('resize', this.updateAvatarRect)
// 清理眼睛更新定时器
if (this.eyeUpdateTimer) {
clearTimeout(this.eyeUpdateTimer)
this.eyeUpdateTimer = null
}
},
// 处理鼠标移动
handleMouseMove(event) {
if (!this.eyeTrackingEnabled || this.isDestroyed) return
this.mouseX = event.clientX
this.mouseY = event.clientY
// 使用节流避免过于频繁的更新
if (this.eyeUpdateTimer) {
clearTimeout(this.eyeUpdateTimer)
}
this.eyeUpdateTimer = setTimeout(() => {
if (!this.isDestroyed) {
this.updateEyePosition()
}
}, 16) // 约60fps的更新频率
},
// 更新头像位置信息
updateAvatarRect() {
if (this.isDestroyed) return
const avatarElement = this.$el.querySelector('.digital-avatar')
if (avatarElement) {
this.avatarRect = avatarElement.getBoundingClientRect()
}
},
// 更新眼睛位置
updateEyePosition() {
if (!this.avatarRect || this.isDestroyed) return
// 计算头像中心点
const avatarCenterX = this.avatarRect.left + this.avatarRect.width / 2
const avatarCenterY = this.avatarRect.top + this.avatarRect.height / 2
// 计算鼠标相对于头像中心的方向
const deltaX = this.mouseX - avatarCenterX
const deltaY = this.mouseY - avatarCenterY
const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY)
// 避免除零错误
if (distance === 0) return
// 计算单位向量
const unitX = deltaX / distance
const unitY = deltaY / distance
// 根据距离调整眼睛移动幅度
const maxMoveDistance = 1.5 // 最大移动距离(像素)
const sensitivity = Math.min(distance / 100, 1) // 距离越远,眼睛移动越明显
const moveX = unitX * maxMoveDistance * sensitivity
const moveY = unitY * maxMoveDistance * sensitivity
// 应用眼睛位置
const leftEye = this.$el.querySelector('.left-eye')
const rightEye = this.$el.querySelector('.right-eye')
if (leftEye && rightEye) {
// 使用CSS变量来实现更平滑的动画
leftEye.style.transform = `translate(${moveX}px, ${moveY}px)`
rightEye.style.transform = `translate(${moveX}px, ${moveY}px)`
}
},
/**
* 处理点赞
*/
@@ -1724,7 +1841,9 @@ export default {
height: 4px;
background: #333;
border-radius: 50%;
transition: all 0.15s ease;
transition: height 0.15s ease, background 0.15s ease, transform 0.1s ease-out;
position: relative;
transform-origin: center;
}
.eye.blink {