Files
learning-system-portal/src/views/portal/case/AICall.vue

967 lines
30 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div>
<!-- 最大化状态的弹窗 -->
<el-dialog
v-if="dialogVisible && windowState === 'maximized'"
:visible="true"
:close-on-click-modal="false"
:show-close="true"
@close="onClose"
class="case-expert-dialog"
:modal="false"
:fullscreen="false"
top="0"
v-resizeable
v-draggable
>
<!-- 标题 -->
<div slot="title" class="dialog-title">
<span>案例专家</span>
<el-button
style="color:#96999f"
style="color:#96999f"
type="text"
class="window-control-btn"
@click="minimizeWindow"
>
<i class="el-icon-minus"></i>
</el-button>
</div>
<!-- 内容区域 -->
<div class="content-wrapper">
<div
class="welcome-message"
ref="messageContainer"
@scroll="handleScroll"
@wheel="handleWheel"
>
<div class="message-text" v-for="(item, index) in messageList" :key="index">
<messages :messageData="item" :suggestions="suggestions" @getMinWindow="minimizeWindow"></messages>
</div>
<div class="message-suggestions" v-if="messageList.length > 0 && messageList[messageList.length-1].textCompleted">
<div class="suggestion-item" v-for="(item, index) in suggestions" :key="index">
<a @click="sendSuggestions(item)"> {{ item }} </a>
</div>
</div>
<div v-if="isLoading" class="loading-message">
<div class="loading-dots">
<span></span>
<span></span>
<span></span>
</div>
</div>
</div>
<!-- 输入框区域 -->
<send-message
v-model="AIContent"
:message-list="messageList"
:suggestions="suggestions"
@loading="handleLoading"
@update-message="updateMessage"
@update-suggestions="updateSuggestions"
@new-conversation="startNewConversation"
:disabled="isLoading"
class="input-area-wrapper"
ref="sendMessage"
/>
</div>
</el-dialog>
<!-- 最小化状态的弹窗 -->
<div
class="minimized-window"
v-show="windowState === 'minimized' && showMinimizedWindow"
@click="onMinimizedWindowClick"
>
<div class="minimized-content">
<span class="window-title">案例专家</span>
<div style="display: flex;align-items: center">
<el-button
type="text"
class="window-control-btn"
@click.stop="onMinimizedWindowClick"
>
<img :src="openImg" alt="" style="width: 17px">
</el-button>
<el-button
style="margin-left: 1px;color:#96999f"
type="text"
class="window-control-btn"
@click.stop="closeMinimizedWindow"
>
<i class="el-icon-close"></i>
</el-button>
</div>
</div>
<div style="display: flex;align-items: center">
<el-button
type="text"
class="window-control-btn"
@click.stop="onMinimizedWindowClick"
>
<img :src="openImg" alt="" style="width: 17px">
</el-button>
<el-button
style="margin-left: 1px;color:#96999f"
type="text"
class="window-control-btn"
@click.stop="closeMinimizedWindow"
>
<i class="el-icon-close"></i>
</el-button>
</div>
</div>
<div class="minimized-message">
<div v-if="messageList.length <= 1 && messageList[0].isBot">
当前暂无对话内容去创建对话吧
</div>
<div v-else>
{{ getLastUserMessage() }}
</div>
</div>
</div>
</div>
</template>
<script>
import { mapState } from 'vuex'
import messages from './components/messages.vue'
import sendMessage from './components/sendMessage.vue'
import openImg from './components/open.png'
import openImg from './components/open.png'
export default {
name: 'CaseExpertDialog',
props: {
dialogVisible: {
type: Boolean,
default: false
}
},
components: {
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;
// 检查是否有保存的位置状态
const savedPosition = sessionStorage.getItem('aiCallDialogPosition');
if (savedPosition) {
const { left, top } = JSON.parse(savedPosition);
dialogEl.style.left = left + 'px';
dialogEl.style.top = top + 'px';
} else {
// 设置初始样式
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;
// 保存当前位置到 sessionStorage
const currentPosition = {
left: parseInt(dialogEl.style.left),
top: parseInt(dialogEl.style.top)
};
// sessionStorage.setItem('aiCallDialogPosition', JSON.stringify(currentPosition));
// 移除全局事件监听
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;
// 检查是否有保存的尺寸状态
const savedSize = sessionStorage.getItem('aiCallDialogSize');
if (savedSize) {
const { width, height, left, top } = JSON.parse(savedSize);
dialogEl.style.width = width + 'px';
dialogEl.style.height = height + 'px';
dialogEl.style.left = left + 'px';
dialogEl.style.top = top + 'px';
} else {
// 设置初始样式
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;
let newWidth, newHeight, newLeft, newTop;
switch (resizeDirection) {
case 'right':
newWidth = Math.max(400, startWidth + deltaX);
dialogEl.style.width = newWidth + 'px';
break;
case 'left':
newWidth = Math.max(400, startWidth - deltaX);
newLeft = startLeft + startWidth - newWidth;
dialogEl.style.width = newWidth + 'px';
dialogEl.style.left = newLeft + 'px';
break;
case 'bottom':
newHeight = Math.max(600, startHeight + deltaY);
dialogEl.style.height = newHeight + 'px';
break;
case 'top':
// 当窗口高度达到最小值时,不再调整高度和位置
if (startHeight - deltaY >= 600) {
newHeight = startHeight - deltaY;
newTop = startTop + deltaY;
dialogEl.style.height = newHeight + 'px';
dialogEl.style.top = newTop + 'px';
}
break;
case 'bottom-right':
newWidth = Math.max(400, startWidth + deltaX);
newHeight = Math.max(600, startHeight + deltaY);
dialogEl.style.width = newWidth + 'px';
dialogEl.style.height = newHeight + 'px';
break;
case 'bottom-left':
newWidth = Math.max(400, startWidth - deltaX);
newHeight = Math.max(600, startHeight + deltaY);
newLeft = startLeft + startWidth - newWidth;
dialogEl.style.width = newWidth + 'px';
dialogEl.style.left = newLeft + 'px';
dialogEl.style.height = newHeight + 'px';
break;
case 'top-right':
// 当窗口高度达到最小值时,不再调整高度和位置
if (startHeight - deltaY >= 600) {
newHeight = startHeight - deltaY;
newTop = startTop + deltaY;
newWidth = Math.max(400, startWidth + deltaX);
dialogEl.style.height = newHeight + 'px';
dialogEl.style.top = newTop + 'px';
dialogEl.style.width = newWidth + 'px';
}
break;
case 'top-left':
// 当窗口高度达到最小值时,不再调整高度和位置
if (startHeight - deltaY >= 600) {
newHeight = startHeight - deltaY;
newTop = startTop + deltaY;
newWidth = Math.max(400, startWidth - deltaX);
newLeft = startLeft + startWidth - newWidth;
dialogEl.style.height = newHeight + 'px';
dialogEl.style.top = newTop + 'px';
dialogEl.style.width = newWidth + 'px';
dialogEl.style.left = newLeft + 'px';
}
break;
}
let doc = document.querySelector('.welcome-message')
let sendBox = document.querySelector('.input-area-wrapper');
// sendBox 的高度
if (doc && sendBox) {
doc.style.height = `calc(${dialogEl.style.height} - ${sendBox.offsetHeight}px - 120px)`;
}
};
const stopResize = () => {
isResizing = false;
resizeDirection = '';
// 保存当前尺寸和位置到 sessionStorage
const currentSize = {
width: parseInt(dialogEl.style.width),
height: parseInt(dialogEl.style.height),
left: parseInt(dialogEl.style.left),
top: parseInt(dialogEl.style.top)
};
sessionStorage.setItem('aiCallDialogSize', JSON.stringify(currentSize));
// 移除全局事件监听
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() {
// 只有在Vuex状态为true时才显示最小化窗口
return this.showAICallMinimized;
}
},
data() {
return {
openImg,
openImg,
AIContent: '',
isLoading: false,
windowState: 'maximized', // 'maximized' 或 'minimized'
messageList: [
{
typing:true,
isBot: true, // 是否为机器人
text: `<p><b>您好!我是京东方案例智能问答助手,随时为您服务。</b></p>
text: `<p><b>您好我是京东方案例智能问答助手随时为您服务</b></p>
<p>我可以帮您快速查找和解读平台内的各类案例内容只需输入您想了解的问题或关键词我会从案例库中精准匹配相关信息并提供清晰的解答每条回答都会附上来源链接方便您随时查阅原始案例全文</p>
<p>我还会根据您的提问智能推荐相关延伸问题助您更高效地探索知识解决问题</p>
<p>现在欢迎随时向我提问开启高效的知识查询体验吧</p>`
}
],
suggestions:[],
isAutoScroll: true, // 是否自动滚动
// 添加一个标志位,用于标识组件是否已经初始化完成
isComponentReady: false
isAutoScroll: true, // 是否自动滚动
// 添加一个标志位,用于标识组件是否已经初始化完成
isComponentReady: false
}
},
mounted() {
// 组件挂载完成后,标记为已准备就绪
this.$nextTick(() => {
this.isComponentReady = true;
});
},
mounted() {
// 组件挂载完成后,标记为已准备就绪
this.$nextTick(() => {
this.isComponentReady = true;
});
},
watch: {
dialogVisible: {
handler(newVal) {
console.log('dialogVisible发生变化');
console.log(newVal);
console.log(this.windowState);
if (newVal) {
this.$nextTick(() => {
// 获取对话框元素
const dialogEl = document.querySelector('.case-expert-dialog .el-dialog');
if (dialogEl) {
// 检查是否有保存的尺寸状态
const savedSize = sessionStorage.getItem('aiCallDialogSize');
if (savedSize) {
const { width, height, left, top } = JSON.parse(savedSize);
dialogEl.style.width = width + 'px';
dialogEl.style.height = height + 'px';
dialogEl.style.left = left + 'px';
dialogEl.style.top = top + 'px';
}
// 检查是否有保存的位置状态
// const savedPosition = sessionStorage.getItem('aiCallDialogPosition');
// if (savedPosition) {
// const { left, top } = JSON.parse(savedPosition);
// dialogEl.style.left = left + 'px';
// dialogEl.style.top = top + 'px';
// }
}
let doc = document.querySelector('.welcome-message')
let sendBox = document.querySelector('.input-area-wrapper');
// 只有在没有保存的尺寸状态时才使用默认值
if (doc && sendBox) {
const savedSize = sessionStorage.getItem('aiCallDialogSize');
if (!savedSize) {
doc.style.height = `calc(600px - ${sendBox.offsetHeight}px - 120px)`;
} else {
const { height } = JSON.parse(savedSize);
doc.style.height = `calc(${height}px - ${sendBox.offsetHeight}px - 120px)`;
}
}
});
}
},
immediate: true
},
messageList: {
handler() {
// 只有在组件准备就绪后才执行滚动操作
if (this.isComponentReady) {
this.$nextTick(() => {
this.scrollToBottom();
});
}
// 只有在组件准备就绪后才执行滚动操作
if (this.isComponentReady) {
this.$nextTick(() => {
this.scrollToBottom();
});
}
},
deep: true
}
},
methods: {
// / 关闭最小化窗口
closeMinimizedWindow() {
this.$store.commit('app/SET_SHOW_AI_CALL_MINIMIZED', false);
this.$store.commit('app/SET_SHOW_AI_CALL', false);
this.windowState = 'maximized';
},
// / 关闭最小化窗口
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';
},
onClose() {
console.log('关闭弹窗')
// 清除保存的状态
sessionStorage.removeItem('aiCallDialogSize');
// sessionStorage.removeItem('aiCallDialogPosition');
this.$emit('close')
// 可以在这里执行其他逻辑
},
minimizeWindow() {
this.windowState = 'minimized';
this.$store.commit('app/SET_SHOW_AI_CALL_MINIMIZED', true);
this.$store.commit('app/SET_SHOW_AI_CALL_MINIMIZED', true);
},
maximizeWindow() {
this.windowState = 'maximized';
},
getLastUserMessage() {
// 从后往前找用户消息
for (let i = this.messageList.length - 1; i >= 0; i--) {
if (!this.messageList[i].isBot) {
// 移除HTML标签只返回纯文本
const tempDiv = document.createElement('div');
tempDiv.innerHTML = this.messageList[i].text;
return tempDiv.textContent || tempDiv.innerText || '';
}
}
return '';
},
// 处理加载状态
handleLoading(status) {
console.log('handleLoading---'+status);
this.isLoading = status;
},
// 更新消息
updateMessage(message) {
// 由于Vue的响应式系统message对象的更改会自动更新视图
// 这里不需要额外的操作
},
updateSuggestions(arr){
this.suggestions = arr
},
// 处理建议
sendSuggestions(item){
// this.suggestions = []
this.AIContent = item
setTimeout(()=>{
this.$refs.sendMessage.handleSend()
this.AIContent = ''
},500)
},
startNewConversation() {
// 重置对话时,先标记组件为未准备就绪状态
this.isComponentReady = false;
// 重置对话时,先标记组件为未准备就绪状态
this.isComponentReady = false;
this.messageList = [
{
isBot: true,
text: `<p><b>您好我是京东方案例智能问答助手随时为您服务</b></p>
text: `<p><b>您好!我是京东方案例智能问答助手,随时为您服务。</b></p>
<p>我可以帮您快速查找和解读平台内的各类案例内容。只需输入您想了解的问题或关键词,我会从案例库中精准匹配相关信息,并提供清晰的解答。每条回答都会附上来源链接,方便您随时查阅原始案例全文。</p>
<p>我还会根据您的提问,智能推荐相关延伸问题,助您更高效地探索知识、解决问题。</p>
<p>现在,欢迎随时向我提问,开启高效的知识查询体验吧!</p>`
}
];
this.AIContent = '';
this.isLoading = false;
// 在下一个 tick 中重新标记为准备就绪
this.$nextTick(() => {
this.isComponentReady = true;
});
// 在下一个 tick 中重新标记为准备就绪
this.$nextTick(() => {
this.isComponentReady = true;
});
},
// 处理滚动事件
handleScroll(event) {
const element = event.target;
// 判断是否滚动到底部
const isAtBottom = element.scrollHeight - element.scrollTop <= element.clientHeight + 1;
// 如果滚动到底部,则开启自动滚动
// 如果离开底部,则关闭自动滚动
this.isAutoScroll = isAtBottom;
},
// 滚动到底部
scrollToBottom() {
if (this.isAutoScroll && this.$refs.messageContainer) {
this.$refs.messageContainer.scrollTop = this.$refs.messageContainer.scrollHeight;
}
},
// 处理鼠标滚轮事件
handleWheel(event) {
const element = this.$refs.messageContainer;
if (!element) return;
// 阻止事件冒泡,防止滚动底层页面
event.stopPropagation();
// 计算滚动方向和距离
const delta = event.deltaY || event.detail || event.wheelDelta;
// 检查是否可以继续滚动
if (delta < 0 && element.scrollTop === 0) {
// 向上滚动且已在顶部,阻止默认行为
event.preventDefault();
} else if (delta > 0 && element.scrollHeight - element.scrollTop <= element.clientHeight) {
// 向下滚动且已在底部,阻止默认行为
event.preventDefault();
} else {
// 允许在容器内滚动
element.scrollTop += delta;
event.preventDefault();
}
},
// 最小化窗口的点击事件处理方法
onMinimizedWindowClick() {
// 当点击最小化窗口时如果dialogVisible为false则通过事件通知父组件显示对话框
if (!this.dialogVisible) {
this.$emit('restore');
}
// 然后将窗口状态设置为最大化
this.windowState = 'maximized';
}
}
}
</script>
<style scoped lang="scss">
::v-deep .el-dialog__wrapper{
position: unset!important;
}
.case-expert-dialog {
::v-deep .el-dialog{
background: url("./components/u762.svg") no-repeat ;
background-size: cover;
border-radius: 8px;
overflow: hidden;
display: flex;
flex-direction: column;
pointer-events: auto;
z-index: 2000;
//background-color: rgba(255, 255, 255, 0.8);
}
::v-deep .el-dialog__body{
padding: 10px;
flex:1;
flex:1;
//font-size: 12px;
*{
font-size:unset ;
}
}
.dialog-title {
background: transparent;
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
font-size: 16px;
font-weight: 600;
color: #333;
padding-right: 20px;
cursor: move; /* 添加拖动样式 */
cursor: move; /* 添加拖动样式 */
.icon {
width: 24px;
height: 24px;
}
.window-control-btn {
font-size: 18px;
padding: 5px 10px;
color: #333; /* 黑色图标 */
}
}
.message-suggestions{
display: flex;
flex-direction: column;
.suggestion-item{
cursor: pointer;
float: right;
padding: 5px 15px;
box-sizing: border-box;
background-color: rgba(228, 231, 237, 1);
border-radius: 5px;
margin-bottom: 5px;
}
}
.content-wrapper {
padding: 20px;
background-color: transparent;
border-radius: 8px;
min-height: 500px;
height:100%;
min-height: 500px;
height:100%;
position: relative;
//margin-bottom: 20px;
display: flex;
flex-direction: column;
.welcome-message {
display: flex;
flex-direction: column;
align-items: flex-start;
margin-bottom: 10px;
height: 400px;
//flex:1;
height: 400px;
//flex:1;
overflow-y: auto;
.avatar {
margin-right: 12px;
img {
width: 32px;
height: 32px;
border-radius: 50%;
background-color: #007aff;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 14px;
}
}
.message-text {
width: 100%;
//margin-bottom: 15px;
p {
color: #333;
//font-size: 14px;
line-height: 1.6;
margin: 8px 0;
}
}
.loading-message {
display: flex;
align-items: center;
width: 100%;
margin-bottom: 15px;
.avatar {
width: 32px;
height: 32px;
border-radius: 50%;
background-color: #007aff;
margin-right: 12px;
}
.loading-dots {
display: flex;
align-items: center;
span {
display: inline-block;
width: 8px;
height: 8px;
border-radius: 50%;
background-color: #999;
margin-right: 5px;
animation: loading 1.4s infinite ease-in-out both;
&:nth-child(1) {
animation-delay: -0.32s;
}
&:nth-child(2) {
animation-delay: -0.16s;
}
}
}
}
}
.input-area-wrapper {
//position: absolute;
//bottom: 10px;
//width: calc(100% - 40px);
}
@keyframes loading {
0%, 80%, 100% {
transform: scale(0);
}
40% {
transform: scale(1);
}
}
}
}
.minimized-window {
position: fixed;
right: 20px;
bottom: 20px;
width: 300px;
background: url("./components/u762.svg") no-repeat;
background-size: cover;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
z-index: 2000;
cursor: pointer;
.minimized-content {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 15px;
border-bottom: 1px solid #eee;
.window-title {
font-weight: 600;
color: #333;
}
.window-control-btn {
font-size: 16px;
padding: 3px 8px;
color: #000000; /* 黑色图标 */
}
}
.minimized-message {
padding: 15px;
font-size: 14px;
color: #666;
min-height: 60px;
display: flex;
align-items: center;
}
}
</style>