diff --git a/src/components/editor/CustomEditor.vue b/src/components/editor/CustomEditor.vue
index 27ddf87..1672b92 100644
--- a/src/components/editor/CustomEditor.vue
+++ b/src/components/editor/CustomEditor.vue
@@ -240,6 +240,22 @@ const insertMention = (member) => {
const handlePaste = (event) => {
event.preventDefault()
+ // 检查是否有图片
+ const items = event.clipboardData?.items
+ if (items) {
+ for (let i = 0; i < items.length; i++) {
+ if (items[i].type.indexOf('image') !== -1) {
+ // 获取粘贴的图片文件
+ const file = items[i].getAsFile()
+ if (file) {
+ // 使用现有的上传图片功能处理
+ onUploadFile([file])
+ return
+ }
+ }
+ }
+ }
+
// 获取粘贴的纯文本内容
const text = event.clipboardData?.getData('text/plain') || ''
@@ -295,10 +311,19 @@ const handleKeydown = (event) => {
console.log('editorContent.value', editorContent.value)
console.log('editorHtml.value', editorHtml.value)
// 确保编辑器内容不为空(文本、图片、文件或表情)
- if (editorContent.value.trim() ||
- editorHtml.value.includes('
item.type))
+ console.log('提及用户IDs:', messageData.mentionUids)
+ console.log('引用消息ID:', messageData.quoteId)
+
+ // 继续发送消息
sendMessage()
}
}
@@ -309,16 +334,26 @@ const handleKeydown = (event) => {
// 发送消息
const sendMessage = () => {
console.log('发送消息');
- // 检查编辑器是否有内容:文本、图片、文件或表情
- if (!editorContent.value.trim() &&
- !editorHtml.value.includes('
{
const tempDiv = document.createElement('div')
tempDiv.innerHTML = editorHtml.value
+ // 检查是否有引用元素
+ const quoteElements = tempDiv.querySelectorAll('.editor-quote')
+ let quoteInfo = null
+ if (quoteElements.length > 0 && quoteData.value) {
+ quoteInfo = {
+ msg_id: quoteData.value.msg_id,
+ title: quoteData.value.title,
+ describe: quoteData.value.describe,
+ image: quoteData.value.image
+ }
+ }
+
let textContent = ''
const nodes = Array.from(tempDiv.childNodes)
@@ -368,6 +415,11 @@ const parseEditorContent = () => {
if (node.nodeType === Node.TEXT_NODE) {
textContent += node.textContent
} else if (node.nodeType === Node.ELEMENT_NODE) {
+ // 跳过引用元素的处理,因为我们已经单独处理了
+ if (node.classList.contains('editor-quote')) {
+ return
+ }
+
if (node.classList.contains('mention')) {
const userId = node.getAttribute('data-user-id')
if (userId) {
@@ -377,8 +429,8 @@ const parseEditorContent = () => {
} else if (node.tagName === 'IMG') {
// 处理图片
const src = node.getAttribute('src')
- const width = node.getAttribute('width') || ''
- const height = node.getAttribute('height') || ''
+ const width = node.getAttribute('data-original-width') || node.getAttribute('width') || ''
+ const height = node.getAttribute('data-original-height') || node.getAttribute('height') || ''
const isEmoji = node.classList.contains('editor-emoji')
if (textContent.trim()) {
@@ -407,7 +459,9 @@ const parseEditorContent = () => {
// 处理普通图片
items.push({
type: 3,
- content: src + (width && height ? `?width=${width}&height=${height}` : '')
+ content: src + (width && height ? `?width=${width}&height=${height}` : ''),
+ width: width,
+ height: height
})
}
} else if (node.classList.contains('emoji')) {
@@ -447,11 +501,19 @@ const parseEditorContent = () => {
})
}
- return {
+ // 构建完整的消息数据结构
+ const result = {
items: items.length > 0 ? items : [{ type: 1, content: '' }],
mentionUids,
quoteId: quoteData.value?.msg_id || 0
}
+
+ // 如果有引用信息,添加到结果中
+ if (quoteInfo) {
+ result.quoteInfo = quoteInfo
+ }
+
+ return result
}
// 清空编辑器
@@ -479,17 +541,24 @@ const clearEditor = () => {
// 插入图片
-const insertImage = (url, width, height) => {
+const insertImage = (src, width, height) => {
const selection = window.getSelection()
if (!selection.rangeCount) return
const range = selection.getRangeAt(0)
+
+ // 创建图片元素
const img = document.createElement('img')
- img.src = url
- img.style.maxWidth = '200px'
+ img.src = src
+ img.className = 'editor-image'
+ img.alt = '图片'
img.style.maxHeight = '200px'
- if (width) img.setAttribute('width', width)
- if (height) img.setAttribute('height', height)
+ img.style.maxWidth = '100%'
+ img.style.objectFit = 'contain' // 保持原始比例
+
+ // 存储原始尺寸信息,但不直接设置宽高属性
+ if (width) img.setAttribute('data-original-width', width)
+ if (height) img.setAttribute('data-original-height', height)
range.deleteContents()
range.insertNode(img)
@@ -502,35 +571,6 @@ const insertImage = (url, width, height) => {
handleInput({ target: editorRef.value })
}
-// 插入文件
-const insertFile = (url, fileName, fileSize) => {
- const selection = window.getSelection()
- if (!selection.rangeCount) return
-
- const range = selection.getRangeAt(0)
-
- // 创建文件链接元素
- const fileLink = document.createElement('a')
- fileLink.href = url
- fileLink.target = '_blank'
- fileLink.className = 'editor-file'
- fileLink.textContent = fileName
- fileLink.setAttribute('data-size', formatFileSize(fileSize))
- fileLink.setAttribute('data-url', url) // 添加URL属性用于解析
- fileLink.setAttribute('data-name', fileName) // 添加文件名属性用于解析
- fileLink.setAttribute('data-size-raw', fileSize) // 添加原始文件大小属性用于解析
-
- range.deleteContents()
- range.insertNode(fileLink)
- range.setStartAfter(fileLink)
- range.collapse(true)
- selection.removeAllRanges()
- selection.addRange(range)
-
- editorRef.value.focus()
- handleInput({ target: editorRef.value })
-}
-
// 格式化文件大小
const formatFileSize = (size) => {
if (size < 1024) {
@@ -547,21 +587,61 @@ const formatFileSize = (size) => {
/**
* 文件上传处理
- * @param e 上传事件对象
+ * @param e 上传事件对象或文件数组
*/
- async function onUploadFile(e) {
- let file = e.target.files[0]
-
- e.target.value = null // 清空input,允许再次选择相同文件
-
+// 文件上传处理
+async function onUploadFile(e) {
+ let files;
+
+ // 判断参数类型
+ if (Array.isArray(e)) {
+ // 直接传入的文件数组
+ files = e;
+ } else {
+ // 传入的是事件对象
+ files = e.target.files;
+ e.target.value = null; // 清空input,允许再次选择相同文件
+ }
+
+ // 确保有文件
+ if (!files || files.length === 0) return;
+
+ // 处理第一个文件
+ const file = files[0];
+
console.log("文件类型"+file.type)
if (file.type.indexOf('image/') === 0) {
console.log("进入图片")
- // 处理图片文件 - 立即显示临时消息,然后上传
- let fn = emitCall('image_event', file, () => {})
- emit('editor-event', fn)
-
- return
+ // 创建临时URL
+ const tempUrl = URL.createObjectURL(file);
+
+ // 创建图片对象以获取尺寸
+ const image = new Image();
+ image.src = tempUrl;
+
+ image.onload = () => {
+ // 上传图片到服务器
+ const form = new FormData();
+ form.append('file', file);
+ form.append("source", "fonchain-chat"); // 图片来源标识
+ form.append("urlParam", `width=${image.width}&height=${image.height}`);
+
+ // 先将临时图片插入编辑器,不直接设置宽高,而是传递原始尺寸信息
+ insertImage(tempUrl, image.width, image.height);
+
+ // 上传图片并获取永久URL
+ uploadImg(form).then(({ code, data, message }) => {
+ if (code == 0) {
+ // 上传成功后,可以将临时URL替换为永久URL
+ // 但这里我们不做替换,因为临时URL在当前会话中已足够使用
+ console.log('图片上传成功:', data.ori_url);
+ } else {
+ window['$message'].error(message);
+ }
+ });
+ };
+
+ return;
}
if (file.type.indexOf('video/') === 0) {
@@ -1536,12 +1616,14 @@ const onVoteSubmit = (data) => {
* 添加圆角和鼠标指针样式
*/
.editor-image {
- max-width: 100px;
- max-height: 100px;
+ max-width: 300px;
+ max-height: 200px;
border-radius: 3px;
background-color: #48484d;
margin: 0px 2px;
cursor: pointer;
+ object-fit: contain; /* 保持原始比例 */
+ display: inline-block; /* 确保图片正确显示 */
}
/**
diff --git a/src/utils/auth.js b/src/utils/auth.js
index f4f176c..0383a0a 100644
--- a/src/utils/auth.js
+++ b/src/utils/auth.js
@@ -18,7 +18,7 @@ export function isLoggedIn() {
*/
export function getAccessToken() {
// return storage.get(AccessToken) || ''
- return JSON.parse(localStorage.getItem('token'))||'46d71a72d8d845ad7ed23eba9bdde260e635407190c2ce1bf7fd22088e41682ea07773ec65cae8946d2003f264d55961f96e0fc5da10eb96d3a348c1664e9644ce2108c311309f398ae8ea1b8200bfd490e5cb6e8c52c9e5d493cbabb163368f8351420451a631dbfa749829ee4cda49b77b5ed2d3dced5d0f2b7dd9ee76ba5465c84a17c23af040cd92b6b2a4ea48befbb5c729dcdad0a9c9668befe84074cc24f78899c1d947f8e7f94c7eda5325b8ed698df729e76febb98549ef3482ae942fb4f4a1c92d21836fa784728f0c5483aab2760a991b6b36e6b10c84f840a6433a6ecc31dee36e8f1c6158818bc89d22726726265e9af0db370a54ea5ee002b43662d571b84c8468ac15330f79503a5cd5e72282d8bee92749b1a3c1b7fd87ae70b64b90e437e84c1b558c64a35e181b2ecf5db3007680c3607eac1edee7f59d'
+ return JSON.parse(localStorage.getItem('token'))||'46d71a72d8d845ad7ed23eba9bdde260e635407190c2ce1bf7fd22088e41682ea07773ec65cae8946d2003f264d55961f96e0fc5da10eb96d3a348c1664e9644ce2108c311309f398ae8ea1b8200bfd490e5cb6e8c52c9e5d493cbabb163368f8351420451a631dbfa749829ee4cda49b77b5ed2d3dced5d0f2b7dd9ee76ba5465c84a17c23af040cd92b6b2a4ea48befbb5c729dcdad0a9c9668befe84074cc24f78899c1d947f8e7f94c7eda5325b8ed698df729e76febb98549ef3482ae942fb4f4a1c92d21836fa784728f0c5483aab2760a991b6b36e6b10c84f840a6433a6ecc31dee36e8f1c6158818bc89d22403363066ad3c046839f7b2cf8a6186da017388f197c0c3b219b1c04e7d986e9774b72664a22a6075cee77da3584b7a2131365913796a5fcabc8f4594284e480a592a84a40a9aa7f5f27c951a53a369c'
}
/**