完成AI辅导员修改
This commit is contained in:
@@ -295,6 +295,9 @@ export default {
|
||||
// 启动鼠标跟踪
|
||||
this.startMouseTracking()
|
||||
|
||||
// 添加图片点击事件委托
|
||||
this.setupImagePreviewEvents()
|
||||
|
||||
// 确保DOM完全渲染后再初始化聊天
|
||||
this.$nextTick(() => {
|
||||
setTimeout(async () => {
|
||||
@@ -345,6 +348,12 @@ export default {
|
||||
// 停止鼠标跟踪
|
||||
this.stopMouseTracking()
|
||||
|
||||
// 移除图片点击事件监听器
|
||||
const messageList = this.$refs.messageList
|
||||
if (messageList && this.imageClickHandler) {
|
||||
messageList.removeEventListener('click', this.imageClickHandler)
|
||||
}
|
||||
|
||||
// 取消正在进行的请求
|
||||
if (this.currentCancel) {
|
||||
this.currentCancel()
|
||||
@@ -1112,7 +1121,10 @@ export default {
|
||||
|
||||
// 渲染markdown
|
||||
const html = this.md.render(text)
|
||||
const sanitizedHtml = DOMPurify.sanitize(html)
|
||||
let sanitizedHtml = DOMPurify.sanitize(html)
|
||||
|
||||
// 处理图片:添加样式和点击预览功能
|
||||
sanitizedHtml = this.processImages(sanitizedHtml)
|
||||
|
||||
// 缓存管理:如果缓存超过最大大小,删除最旧的条目
|
||||
if (this.markdownCache.size >= this.maxCacheSize) {
|
||||
@@ -1126,6 +1138,107 @@ export default {
|
||||
return sanitizedHtml
|
||||
},
|
||||
|
||||
/**
|
||||
* 处理图片:添加样式和点击预览功能
|
||||
*/
|
||||
processImages(html) {
|
||||
// 创建临时DOM元素来处理HTML
|
||||
const tempDiv = document.createElement('div')
|
||||
tempDiv.innerHTML = html
|
||||
|
||||
// 查找所有图片元素
|
||||
const images = tempDiv.querySelectorAll('img')
|
||||
|
||||
images.forEach((img, index) => {
|
||||
// 添加样式
|
||||
img.style.maxWidth = '100%'
|
||||
img.style.height = 'auto'
|
||||
img.style.cursor = 'pointer'
|
||||
img.style.borderRadius = '8px'
|
||||
img.style.boxShadow = '0 2px 8px rgba(0, 0, 0, 0.1)'
|
||||
img.style.transition = 'all 0.3s ease'
|
||||
|
||||
// 添加hover效果的class
|
||||
img.classList.add('markdown-image')
|
||||
|
||||
// 添加唯一标识符用于后续绑定事件
|
||||
img.setAttribute('data-preview-src', img.src)
|
||||
img.setAttribute('data-preview-image', 'true')
|
||||
|
||||
// 添加加载错误处理
|
||||
img.setAttribute('onerror', 'this.style.display="none"')
|
||||
})
|
||||
|
||||
return tempDiv.innerHTML
|
||||
},
|
||||
|
||||
/**
|
||||
* 图片预览功能
|
||||
*/
|
||||
previewImage(src) {
|
||||
// 创建预览遮罩层
|
||||
const overlay = document.createElement('div')
|
||||
overlay.style.cssText = `
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 9999;
|
||||
cursor: pointer;
|
||||
`
|
||||
|
||||
// 创建预览图片
|
||||
const previewImg = document.createElement('img')
|
||||
previewImg.src = src
|
||||
previewImg.style.cssText = `
|
||||
max-width: 90%;
|
||||
max-height: 90%;
|
||||
object-fit: contain;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
|
||||
`
|
||||
|
||||
// 点击遮罩层关闭预览
|
||||
overlay.addEventListener('click', () => {
|
||||
document.body.removeChild(overlay)
|
||||
})
|
||||
|
||||
// 阻止图片点击事件冒泡
|
||||
previewImg.addEventListener('click', (e) => {
|
||||
e.stopPropagation()
|
||||
})
|
||||
|
||||
overlay.appendChild(previewImg)
|
||||
document.body.appendChild(overlay)
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置图片预览事件委托
|
||||
*/
|
||||
setupImagePreviewEvents() {
|
||||
// 创建事件处理函数
|
||||
this.imageClickHandler = (e) => {
|
||||
// 检查点击的是否是标记为预览的图片
|
||||
if (e.target.tagName === 'IMG' && e.target.getAttribute('data-preview-image') === 'true') {
|
||||
const src = e.target.getAttribute('data-preview-src')
|
||||
if (src) {
|
||||
this.previewImage(src)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 使用事件委托在消息列表容器上监听点击事件
|
||||
const messageList = this.$refs.messageList
|
||||
if (messageList) {
|
||||
messageList.addEventListener('click', this.imageClickHandler)
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 节流更新内容
|
||||
*/
|
||||
@@ -2633,6 +2746,23 @@ export default {
|
||||
color: #722ed1 !important;
|
||||
}
|
||||
|
||||
/* Markdown 图片样式 */
|
||||
.content-text .markdown-image {
|
||||
max-width: 100% !important;
|
||||
height: auto !important;
|
||||
cursor: pointer !important;
|
||||
border-radius: 8px !important;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1) !important;
|
||||
transition: all 0.3s ease !important;
|
||||
display: block;
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
.content-text .markdown-image:hover {
|
||||
transform: scale(1.02);
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15) !important;
|
||||
}
|
||||
|
||||
/* 消息限制提示样式 */
|
||||
.message-limit-notice {
|
||||
background: #f6f8fa;
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<!-- 其他页面内容 -->
|
||||
<!-- 触发按钮,控制弹窗显示隐藏 -->
|
||||
<div class="ai-hover" @click="toggleAI">
|
||||
<span v-if="!showAI" style="font-size: 30px; font-weight: bold;">AI</span>
|
||||
<AiIcon v-if="!showAI" :size="48" color="white" />
|
||||
<i v-else class="el-icon-close" style="font-size: 20px;"></i>
|
||||
</div>
|
||||
<!-- 聊天弹窗,通过 v-if 控制显隐 -->
|
||||
@@ -40,6 +40,7 @@ import ResizeMixin from './mixin/ResizeHandler'
|
||||
import { mapState } from 'vuex'
|
||||
import variables from '@/assets/styles/variables.scss'
|
||||
import ChatPopup from '../layout/components/Aichat/ChatPopup.vue'
|
||||
import AiIcon from '@/components/AiIcon/index.vue'
|
||||
|
||||
import {
|
||||
initCoze
|
||||
@@ -57,7 +58,8 @@ export default {
|
||||
Settings,
|
||||
Sidebar,
|
||||
TagsView,
|
||||
ChatPopup // 注册ChatPopup组件
|
||||
ChatPopup, // 注册ChatPopup组件
|
||||
AiIcon // 注册AiIcon组件
|
||||
},
|
||||
mixins: [ResizeMixin],
|
||||
data() {
|
||||
|
||||
Reference in New Issue
Block a user