diff --git a/src/views/portal/case/AICall.vue b/src/views/portal/case/AICall.vue index 465a365c..b4f5592a 100644 --- a/src/views/portal/case/AICall.vue +++ b/src/views/portal/case/AICall.vue @@ -14,11 +14,14 @@ :fullscreen="false" top="10vh" v-show="windowState === 'maximized'" + v-resizeable + v-draggable >
案例专家
案例专家 - - - +
+ + + + + + + +
@@ -99,7 +113,7 @@ import { mapState } from 'vuex' import messages from './components/messages.vue' import sendMessage from './components/sendMessage.vue' - +import openImg from './components/open.png' export default { name: 'CaseExpertDialog', props: { @@ -112,6 +126,281 @@ export default { messages, sendMessage }, + directives: { + draggable: { + bind(el, binding, vnode) { + vnode.context.$nextTick(() => { + const dialogEl = el.querySelector('.el-dialog'); + if (!dialogEl) return; + + const headerEl = dialogEl.querySelector('.dialog-title'); + if (!headerEl) return; + + // 设置初始样式 + dialogEl.style.position = 'fixed'; + dialogEl.style.top = '100px'; + dialogEl.style.left = (window.innerWidth - dialogEl.offsetWidth) / 2 + 'px'; + dialogEl.style.margin = '0'; + + let isDragging = false; + let startX = 0; + let startY = 0; + let startLeft = 0; + let startTop = 0; + + const startDrag = (event) => { + // 只有在标题栏上按下鼠标才开始拖动 + if (event.target.closest('.resize-handle')) { + return; // 如果点击的是resize-handle,则不触发拖动 + } + + isDragging = true; + startX = event.clientX; + startY = event.clientY; + startLeft = parseInt(dialogEl.style.left) || dialogEl.offsetLeft; + startTop = parseInt(dialogEl.style.top) || dialogEl.offsetTop; + + event.preventDefault(); + event.stopPropagation(); + + // 添加全局事件监听 + document.addEventListener('mousemove', handleMouseMove); + document.addEventListener('mouseup', stopDrag); + }; + + const handleMouseMove = (event) => { + if (!isDragging) return; + + const deltaX = event.clientX - startX; + const deltaY = event.clientY - startY; + + dialogEl.style.left = (startLeft + deltaX) + 'px'; + dialogEl.style.top = (startTop + deltaY) + 'px'; + }; + + const stopDrag = () => { + isDragging = false; + + // 移除全局事件监听 + document.removeEventListener('mousemove', handleMouseMove); + document.removeEventListener('mouseup', stopDrag); + }; + + // 为标题栏绑定拖动事件 + headerEl.addEventListener('mousedown', startDrag); + }); + } + }, + + resizeable: { + bind(el, binding, vnode) { + // 确保元素已插入DOM + vnode.context.$nextTick(() => { + const dialogEl = el.querySelector('.el-dialog'); + if (!dialogEl) return; + + // 设置初始样式 + dialogEl.style.position = 'fixed'; + dialogEl.style.top = '100px'; + dialogEl.style.left = (window.innerWidth - dialogEl.offsetWidth) / 2 + 'px'; + + // 创建拖拽手柄 + const createHandle = (direction) => { + const handle = document.createElement('div'); + handle.className = `resize-handle ${direction}`; + handle.style.position = 'absolute'; + handle.style.zIndex = '10'; + + switch (direction) { + case 'left': + case 'right': + handle.style.width = '6px'; + handle.style.height = '100%'; + handle.style.top = '0'; + handle.style.cursor = 'ew-resize'; + break; + case 'top': + case 'bottom': + handle.style.width = '100%'; + handle.style.height = '6px'; + handle.style.left = '0'; + handle.style.cursor = 'ns-resize'; + break; + case 'top-left': + case 'top-right': + case 'bottom-left': + case 'bottom-right': + handle.style.width = '10px'; + handle.style.height = '10px'; + handle.style.zIndex = '20'; + break; + } + + switch (direction) { + case 'left': + handle.style.left = '0'; + break; + case 'right': + handle.style.right = '0'; + break; + case 'top': + handle.style.top = '0'; + break; + case 'bottom': + handle.style.bottom = '0'; + break; + case 'top-left': + handle.style.top = '0'; + handle.style.left = '0'; + handle.style.cursor = 'nw-resize'; + break; + case 'top-right': + handle.style.top = '0'; + handle.style.right = '0'; + handle.style.cursor = 'ne-resize'; + break; + case 'bottom-left': + handle.style.bottom = '0'; + handle.style.left = '0'; + handle.style.cursor = 'sw-resize'; + break; + case 'bottom-right': + handle.style.bottom = '0'; + handle.style.right = '0'; + handle.style.cursor = 'se-resize'; + break; + } + + // 防止拖拽手柄的事件冒泡到标题栏 + handle.addEventListener('mousedown', (e) => { + e.stopPropagation(); + }); + + dialogEl.appendChild(handle); + return handle; + }; + + // 创建8个拖拽手柄 + const handles = { + left: createHandle('left'), + right: createHandle('right'), + top: createHandle('top'), + bottom: createHandle('bottom'), + topLeft: createHandle('top-left'), + topRight: createHandle('top-right'), + bottomLeft: createHandle('bottom-left'), + bottomRight: createHandle('bottom-right') + }; + + // 添加拖拽事件处理 + let isResizing = false; + let resizeDirection = ''; + let startX = 0; + let startY = 0; + let startWidth = 0; + let startHeight = 0; + let startLeft = 0; + let startTop = 0; + + const startResize = (direction, event) => { + event.preventDefault(); + event.stopPropagation(); + + isResizing = true; + resizeDirection = direction; + + startX = event.clientX; + startY = event.clientY; + startWidth = dialogEl.offsetWidth; + startHeight = dialogEl.offsetHeight; + + // 统一使用计算后的样式值 + startLeft = parseInt(dialogEl.style.left) || 0; + startTop = parseInt(dialogEl.style.top) || 0; + + // 添加全局事件监听 + document.addEventListener('mousemove', handleMouseMove); + document.addEventListener('mouseup', stopResize); + }; + + const handleMouseMove = (event) => { + if (!isResizing) return; + + const deltaX = event.clientX - startX; + const deltaY = event.clientY - startY; + + switch (resizeDirection) { + case 'right': + dialogEl.style.width = Math.max(400, startWidth + deltaX) + 'px'; + break; + case 'left': + const newWidth = Math.max(400, startWidth - deltaX); + dialogEl.style.width = newWidth + 'px'; + dialogEl.style.left = (startLeft + startWidth - newWidth) + 'px'; + break; + case 'bottom': + dialogEl.style.height = Math.max(600, startHeight + deltaY) + 'px'; + break; + case 'top': + // 当窗口高度达到最小值时,不再调整高度和位置 + if (startHeight - deltaY >= 600) { + dialogEl.style.height = (startHeight - deltaY) + 'px'; + dialogEl.style.top = (startTop + deltaY) + 'px'; + } + break; + case 'bottom-right': + dialogEl.style.width = Math.max(400, startWidth + deltaX) + 'px'; + dialogEl.style.height = Math.max(600, startHeight + deltaY) + 'px'; + break; + case 'bottom-left': + const newWidthBL = Math.max(400, startWidth - deltaX); + dialogEl.style.width = newWidthBL + 'px'; + dialogEl.style.left = (startLeft + startWidth - newWidthBL) + 'px'; + dialogEl.style.height = Math.max(600, startHeight + deltaY) + 'px'; + break; + case 'top-right': + // 当窗口高度达到最小值时,不再调整高度和位置 + if (startHeight - deltaY >= 600) { + dialogEl.style.height = (startHeight - deltaY) + 'px'; + dialogEl.style.top = (startTop + deltaY) + 'px'; + } + dialogEl.style.width = Math.max(400, startWidth + deltaX) + 'px'; + break; + case 'top-left': + // 当窗口高度达到最小值时,不再调整高度和位置 + if (startHeight - deltaY >= 600) { + dialogEl.style.height = (startHeight - deltaY) + 'px'; + dialogEl.style.top = (startTop + deltaY) + 'px'; + } + const newWidthTL = Math.max(400, startWidth - deltaX); + dialogEl.style.width = newWidthTL + 'px'; + dialogEl.style.left = (startLeft + startWidth - newWidthTL) + 'px'; + break; + } + }; + + const stopResize = () => { + isResizing = false; + resizeDirection = ''; + + // 移除全局事件监听 + document.removeEventListener('mousemove', handleMouseMove); + document.removeEventListener('mouseup', stopResize); + }; + + // 为每个手柄绑定事件 + handles.left.addEventListener('mousedown', (e) => startResize('left', e)); + handles.right.addEventListener('mousedown', (e) => startResize('right', e)); + handles.top.addEventListener('mousedown', (e) => startResize('top', e)); + handles.bottom.addEventListener('mousedown', (e) => startResize('bottom', e)); + handles.topLeft.addEventListener('mousedown', (e) => startResize('top-left', e)); + handles.topRight.addEventListener('mousedown', (e) => startResize('top-right', e)); + handles.bottomLeft.addEventListener('mousedown', (e) => startResize('bottom-left', e)); + handles.bottomRight.addEventListener('mousedown', (e) => startResize('bottom-right', e)); + }); + } + } + }, computed: { ...mapState('app', ['showAICallMinimized']), showMinimizedWindow() { @@ -121,6 +410,7 @@ export default { }, data() { return { + openImg, AIContent: '', isLoading: false, windowState: 'maximized', // 'maximized' 或 'minimized' @@ -153,6 +443,12 @@ export default { } }, methods: { +// / 关闭最小化窗口 +closeMinimizedWindow() { + this.$store.commit('app/SET_SHOW_AI_CALL_MINIMIZED', false); + this.$store.commit('app/SET_SHOW_AI_CALL', false); + this.windowState = 'maximized'; +}, getMinWidow(vis){ // this.showAICallMinimized = vis this.windowState = 'minimized'; @@ -165,6 +461,7 @@ export default { minimizeWindow() { this.windowState = 'minimized'; + this.$store.commit('app/SET_SHOW_AI_CALL_MINIMIZED', true); }, maximizeWindow() { @@ -258,11 +555,14 @@ export default { background-size: cover; border-radius: 8px; overflow: hidden; + display: flex; + flex-direction: column; //background-color: rgba(255, 255, 255, 0.8); } ::v-deep .el-dialog__body{ padding: 10px; + flex:1; //font-size: 12px; *{ font-size:unset ; @@ -279,6 +579,7 @@ export default { font-weight: 600; color: #333; padding-right: 20px; + cursor: move; /* 添加拖动样式 */ .icon { width: 24px; @@ -310,7 +611,8 @@ export default { padding: 20px; background-color: transparent; border-radius: 8px; - height: 550px; + min-height: 500px; + height:100%; position: relative; //margin-bottom: 20px; display: flex; diff --git a/src/views/portal/case/Detail.vue b/src/views/portal/case/Detail.vue index 2e6ecaf8..8ea10183 100644 --- a/src/views/portal/case/Detail.vue +++ b/src/views/portal/case/Detail.vue @@ -1,7 +1,9 @@