1
This commit is contained in:
@@ -7,14 +7,8 @@
|
|||||||
<div class="digital-avatar" :class="{ speaking: isAISpeaking, thinking: isAIThinking }">
|
<div class="digital-avatar" :class="{ speaking: isAISpeaking, thinking: isAIThinking }">
|
||||||
<div class="avatar-face">
|
<div class="avatar-face">
|
||||||
<div class="avatar-eyes">
|
<div class="avatar-eyes">
|
||||||
<div class="eye left-eye" :class="{ blink: isBlinking }"
|
<div class="eye left-eye" :class="{ blink: isBlinking }"></div>
|
||||||
:style="{ transform: `translate(${eyeOffsetX}px, ${eyeOffsetY}px)` }">
|
<div class="eye right-eye" :class="{ blink: isBlinking }"></div>
|
||||||
<div class="pupil"></div>
|
|
||||||
</div>
|
|
||||||
<div class="eye right-eye" :class="{ blink: isBlinking }"
|
|
||||||
:style="{ transform: `translate(${eyeOffsetX}px, ${eyeOffsetY}px)` }">
|
|
||||||
<div class="pupil"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="avatar-mouth" :class="{ talking: isAISpeaking }"></div>
|
<div class="avatar-mouth" :class="{ talking: isAISpeaking }"></div>
|
||||||
</div>
|
</div>
|
||||||
@@ -211,13 +205,6 @@ export default {
|
|||||||
isBlinking: false, // 是否在眨眼
|
isBlinking: false, // 是否在眨眼
|
||||||
blinkTimer: null, // 眨眼定时器
|
blinkTimer: null, // 眨眼定时器
|
||||||
speakingTimer: null, // 说话动画定时器
|
speakingTimer: null, // 说话动画定时器
|
||||||
|
|
||||||
// 眼睛跟踪鼠标
|
|
||||||
mouseX: 0, // 鼠标X坐标
|
|
||||||
mouseY: 0, // 鼠标Y坐标
|
|
||||||
eyeOffsetX: 0, // 眼睛X偏移
|
|
||||||
eyeOffsetY: 0, // 眼睛Y偏移
|
|
||||||
isMouseTracking: true, // 是否启用鼠标跟踪
|
|
||||||
requestMonitorInterval: null,
|
requestMonitorInterval: null,
|
||||||
maxRequestDuration: 60000, // 最大请求持续时间60秒
|
maxRequestDuration: 60000, // 最大请求持续时间60秒
|
||||||
|
|
||||||
@@ -296,9 +283,6 @@ export default {
|
|||||||
// 启动数字人自动眨眼
|
// 启动数字人自动眨眼
|
||||||
this.startAutoBlinking()
|
this.startAutoBlinking()
|
||||||
|
|
||||||
// 启动鼠标跟踪
|
|
||||||
this.enableMouseTracking()
|
|
||||||
|
|
||||||
// 确保DOM完全渲染后再初始化聊天
|
// 确保DOM完全渲染后再初始化聊天
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
@@ -338,10 +322,9 @@ export default {
|
|||||||
this.contentUpdateTimer = null
|
this.contentUpdateTimer = null
|
||||||
}
|
}
|
||||||
|
|
||||||
// 清理数字人相关定时器和事件监听器
|
// 清理数字人相关定时器
|
||||||
this.stopAutoBlinking()
|
this.stopAutoBlinking()
|
||||||
this.stopAIAnimation()
|
this.stopAIAnimation()
|
||||||
this.disableMouseTracking()
|
|
||||||
|
|
||||||
// 取消正在进行的请求
|
// 取消正在进行的请求
|
||||||
if (this.currentCancel) {
|
if (this.currentCancel) {
|
||||||
@@ -1159,8 +1142,6 @@ export default {
|
|||||||
startAIThinking() {
|
startAIThinking() {
|
||||||
this.isAIThinking = true
|
this.isAIThinking = true
|
||||||
this.isAISpeaking = false
|
this.isAISpeaking = false
|
||||||
// 思考时启用鼠标跟踪
|
|
||||||
this.enableMouseTracking()
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// 开始AI说话动画
|
// 开始AI说话动画
|
||||||
@@ -1168,9 +1149,6 @@ export default {
|
|||||||
this.isAIThinking = false
|
this.isAIThinking = false
|
||||||
this.isAISpeaking = true
|
this.isAISpeaking = true
|
||||||
|
|
||||||
// 说话时禁用鼠标跟踪,眼睛面向前方
|
|
||||||
this.disableMouseTracking()
|
|
||||||
|
|
||||||
// 清除之前的说话定时器
|
// 清除之前的说话定时器
|
||||||
if (this.speakingTimer) {
|
if (this.speakingTimer) {
|
||||||
clearTimeout(this.speakingTimer)
|
clearTimeout(this.speakingTimer)
|
||||||
@@ -1182,9 +1160,6 @@ export default {
|
|||||||
this.isAIThinking = false
|
this.isAIThinking = false
|
||||||
this.isAISpeaking = false
|
this.isAISpeaking = false
|
||||||
|
|
||||||
// 停止动画后恢复鼠标跟踪
|
|
||||||
this.enableMouseTracking()
|
|
||||||
|
|
||||||
if (this.speakingTimer) {
|
if (this.speakingTimer) {
|
||||||
clearTimeout(this.speakingTimer)
|
clearTimeout(this.speakingTimer)
|
||||||
this.speakingTimer = null
|
this.speakingTimer = null
|
||||||
@@ -1222,69 +1197,6 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 鼠标移动事件处理
|
|
||||||
handleMouseMove(event) {
|
|
||||||
if (!this.isMouseTracking || this.isDestroyed) return
|
|
||||||
|
|
||||||
this.mouseX = event.clientX
|
|
||||||
this.mouseY = event.clientY
|
|
||||||
this.updateEyePosition()
|
|
||||||
},
|
|
||||||
|
|
||||||
// 更新眼睛位置
|
|
||||||
updateEyePosition() {
|
|
||||||
if (!this.isMouseTracking) return
|
|
||||||
|
|
||||||
// 获取数字人头像的位置
|
|
||||||
const avatarElement = this.$el.querySelector('.digital-avatar')
|
|
||||||
if (!avatarElement) return
|
|
||||||
|
|
||||||
const rect = avatarElement.getBoundingClientRect()
|
|
||||||
const avatarCenterX = rect.left + rect.width / 2
|
|
||||||
const avatarCenterY = rect.top + rect.height / 2
|
|
||||||
|
|
||||||
// 计算鼠标相对于头像中心的位置
|
|
||||||
const deltaX = this.mouseX - avatarCenterX
|
|
||||||
const deltaY = this.mouseY - avatarCenterY
|
|
||||||
|
|
||||||
// 计算距离和角度
|
|
||||||
const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY)
|
|
||||||
const maxDistance = 100 // 最大跟踪距离
|
|
||||||
const maxOffset = 1.5 // 眼睛最大偏移量
|
|
||||||
|
|
||||||
// 限制跟踪范围
|
|
||||||
const trackingFactor = Math.min(distance / maxDistance, 1)
|
|
||||||
|
|
||||||
// 计算眼睛偏移
|
|
||||||
this.eyeOffsetX = (deltaX / distance) * maxOffset * trackingFactor
|
|
||||||
this.eyeOffsetY = (deltaY / distance) * maxOffset * trackingFactor
|
|
||||||
|
|
||||||
// 如果距离太近,眼睛回到中心
|
|
||||||
if (distance < 50) {
|
|
||||||
this.eyeOffsetX = 0
|
|
||||||
this.eyeOffsetY = 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// 眼睛回到中心位置(说话时使用)
|
|
||||||
resetEyePosition() {
|
|
||||||
this.eyeOffsetX = 0
|
|
||||||
this.eyeOffsetY = 0
|
|
||||||
},
|
|
||||||
|
|
||||||
// 启用鼠标跟踪
|
|
||||||
enableMouseTracking() {
|
|
||||||
this.isMouseTracking = true
|
|
||||||
document.addEventListener('mousemove', this.handleMouseMove)
|
|
||||||
},
|
|
||||||
|
|
||||||
// 禁用鼠标跟踪
|
|
||||||
disableMouseTracking() {
|
|
||||||
this.isMouseTracking = false
|
|
||||||
document.removeEventListener('mousemove', this.handleMouseMove)
|
|
||||||
this.resetEyePosition()
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理点赞
|
* 处理点赞
|
||||||
*/
|
*/
|
||||||
@@ -1808,35 +1720,16 @@ export default {
|
|||||||
|
|
||||||
/* 眼睛 */
|
/* 眼睛 */
|
||||||
.eye {
|
.eye {
|
||||||
width: 8px;
|
|
||||||
height: 8px;
|
|
||||||
background: #fff;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
border-radius: 50%;
|
|
||||||
transition: all 0.15s ease;
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eye.blink {
|
|
||||||
height: 2px;
|
|
||||||
background: #666;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eye.blink .pupil {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 瞳孔 */
|
|
||||||
.pupil {
|
|
||||||
width: 4px;
|
width: 4px;
|
||||||
height: 4px;
|
height: 4px;
|
||||||
background: #333;
|
background: #333;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
transition: transform 0.1s ease;
|
transition: all 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eye.blink {
|
||||||
|
height: 1px;
|
||||||
|
background: #666;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 嘴巴 */
|
/* 嘴巴 */
|
||||||
|
Reference in New Issue
Block a user