This commit is contained in:
hrx 2026-04-27 10:27:48 +08:00
parent f31a47f56c
commit 22204bedec

View File

@ -160,8 +160,13 @@
</div> </div>
</div> </div>
<div v-show="aiDialogVisible" class="ai-chat-panel"> <div
<div class="ai-chat-panel__header"> v-show="aiDialogVisible"
ref="aiChatPanel"
class="ai-chat-panel"
:style="aiPanelStyle"
>
<div class="ai-chat-panel__header" @mousedown="startAIPanelDrag">
<div class="ai-chat-panel__title"> <div class="ai-chat-panel__title">
<span class="ai-chat-panel__logo">AI</span> <span class="ai-chat-panel__logo">AI</span>
<span>有问题找开元</span> <span>有问题找开元</span>
@ -260,6 +265,15 @@ export default Vue.extend({
aiInput: '', aiInput: '',
aiLoading: false, aiLoading: false,
aiMessages: [], aiMessages: [],
aiPanelPosition: {
left: null,
top: null
},
aiPanelDragging: false,
aiPanelDragOffset: {
x: 0,
y: 0
},
aiQuickQuestions: [ aiQuickQuestions: [
'推荐适合训练大模型的 GPU 服务器', '推荐适合训练大模型的 GPU 服务器',
'4090 和 A100 怎么选', '4090 和 A100 怎么选',
@ -308,6 +322,9 @@ export default Vue.extend({
} }
}); });
}, },
beforeDestroy() {
this.stopAIPanelDrag()
},
computed: { computed: {
...mapGetters(["sidebar", "avatar", "device"]), ...mapGetters(["sidebar", "avatar", "device"]),
...mapState({ ...mapState({
@ -342,6 +359,18 @@ export default Vue.extend({
} else { } else {
return this.$route.path.includes('/homePage/index'); return this.$route.path.includes('/homePage/index');
} }
},
aiPanelStyle() {
if (this.aiPanelPosition.left === null || this.aiPanelPosition.top === null) {
return {}
}
return {
left: `${this.aiPanelPosition.left}px`,
top: `${this.aiPanelPosition.top}px`,
right: 'auto',
bottom: 'auto'
}
} }
}, },
methods: { methods: {
@ -350,12 +379,14 @@ export default Vue.extend({
handleAIClick() { handleAIClick() {
this.aiDialogVisible = true this.aiDialogVisible = true
this.$nextTick(() => { this.$nextTick(() => {
this.initAIPanelPosition()
this.scrollAIChatToBottom() this.scrollAIChatToBottom()
}) })
}, },
closeAIPanel() { closeAIPanel() {
this.aiDialogVisible = false this.aiDialogVisible = false
this.stopAIPanelDrag()
}, },
resetAIChat() { resetAIChat() {
@ -367,6 +398,73 @@ export default Vue.extend({
this.sendAIMessage(question) this.sendAIMessage(question)
}, },
initAIPanelPosition() {
if (this.aiPanelPosition.left !== null && this.aiPanelPosition.top !== null) {
return
}
const panel = this.$refs.aiChatPanel
if (!panel) return
const panelWidth = panel.offsetWidth || 380
const panelHeight = panel.offsetHeight || 620
this.aiPanelPosition = {
left: Math.max(window.innerWidth - panelWidth - 24, 16),
top: Math.max(window.innerHeight - panelHeight - 24, 16)
}
},
startAIPanelDrag(event) {
if (event.button !== 0) return
if (event.target && event.target.closest('.ai-chat-panel__close')) {
return
}
const panel = this.$refs.aiChatPanel
if (!panel) return
const rect = panel.getBoundingClientRect()
this.aiPanelDragging = true
this.aiPanelDragOffset = {
x: event.clientX - rect.left,
y: event.clientY - rect.top
}
window.addEventListener('mousemove', this.handleAIPanelDrag)
window.addEventListener('mouseup', this.stopAIPanelDrag)
document.body.style.userSelect = 'none'
},
handleAIPanelDrag(event) {
if (!this.aiPanelDragging) return
const panel = this.$refs.aiChatPanel
if (!panel) return
const panelWidth = panel.offsetWidth || 380
const panelHeight = panel.offsetHeight || 620
const minLeft = 0
const minTop = 0
const maxLeft = Math.max(window.innerWidth - panelWidth, 0)
const maxTop = Math.max(window.innerHeight - panelHeight, 0)
const nextLeft = event.clientX - this.aiPanelDragOffset.x
const nextTop = event.clientY - this.aiPanelDragOffset.y
this.aiPanelPosition = {
left: Math.min(Math.max(nextLeft, minLeft), maxLeft),
top: Math.min(Math.max(nextTop, minTop), maxTop)
}
},
stopAIPanelDrag() {
this.aiPanelDragging = false
window.removeEventListener('mousemove', this.handleAIPanelDrag)
window.removeEventListener('mouseup', this.stopAIPanelDrag)
document.body.style.userSelect = ''
},
handleAIKeydown(event) { handleAIKeydown(event) {
if (event.key === 'Enter' && !event.shiftKey) { if (event.key === 'Enter' && !event.shiftKey) {
event.preventDefault() event.preventDefault()
@ -1251,6 +1349,7 @@ export default Vue.extend({
justify-content: space-between; justify-content: space-between;
border-bottom: 1px solid #f0f0f0; border-bottom: 1px solid #f0f0f0;
background: #fff; background: #fff;
cursor: move;
} }
&__title { &__title {