Merge branch 'seedance' of https://gitea.06zk.com/best_yunwei/ai_images into seedance

This commit is contained in:
yys 2026-04-07 10:40:31 +08:00
commit 23817f7850
3 changed files with 144 additions and 18 deletions

View File

@ -28,6 +28,7 @@
@keyup="handleKeyup"
@click="handleEditorClick"
@keydown="handleKeydown"
@paste="handlePaste"
></div>
<!-- @ 图片选择面板 -->
@ -187,6 +188,64 @@ export default {
}
}
const insertPlainTextAtCursor = (text) => {
if (!editorRef.value || text == null) return
const normalized = String(text).replace(/\r\n/g, '\n').replace(/\r/g, '\n')
editorRef.value.focus()
const selection = window.getSelection()
if (!selection || selection.rangeCount === 0) return
let range = selection.getRangeAt(0)
if (!editorRef.value.contains(range.commonAncestorContainer)) {
const r = document.createRange()
r.selectNodeContents(editorRef.value)
r.collapse(false)
selection.removeAllRanges()
selection.addRange(r)
range = selection.getRangeAt(0)
}
range.deleteContents()
const lines = normalized.split('\n')
const fragment = document.createDocumentFragment()
lines.forEach((line, index) => {
if (line) fragment.appendChild(document.createTextNode(line))
if (index < lines.length - 1) fragment.appendChild(document.createElement('br'))
})
range.insertNode(fragment)
range.collapse(false)
selection.removeAllRanges()
selection.addRange(range)
}
const handlePaste = (e) => {
if (!editorRef.value) return
const cd = e.clipboardData
if (!cd) return
const items = cd.items
if (items) {
for (let i = 0; i < items.length; i++) {
if (items[i].type.indexOf('image') !== -1) {
const blob = items[i].getAsFile()
const reader = new FileReader()
reader.onload = (event) => {
insertImage(event.target.result, 'pasted-image')
}
reader.readAsDataURL(blob)
e.preventDefault()
return
}
}
}
let text = cd.getData('text/plain') || ''
if (!text && cd.getData('text/html')) {
const tmp = document.createElement('div')
tmp.innerHTML = cd.getData('text/html')
text = tmp.innerText || ''
}
e.preventDefault()
insertPlainTextAtCursor(text)
handleInput()
}
// @
const showMentionPanel = () => {
if (props.uploadedImages && props.uploadedImages.length > 0) {
@ -261,23 +320,6 @@ export default {
onMounted(() => {
if (editorRef.value) {
editorRef.value.innerHTML = props.modelValue || ''
//
editorRef.value.addEventListener('paste', (e) => {
const items = e.clipboardData.items
for (let i = 0; i < items.length; i++) {
if (items[i].type.indexOf('image') !== -1) {
const blob = items[i].getAsFile()
const reader = new FileReader()
reader.onload = (event) => {
insertImage(event.target.result, 'pasted-image')
}
reader.readAsDataURL(blob)
e.preventDefault()
break
}
}
})
}
})
@ -292,6 +334,7 @@ export default {
handleInput,
handleKeyup,
handleKeydown,
handlePaste,
handleEditorClick,
insertMentionImage,
clear
@ -342,6 +385,11 @@ export default {
outline: none;
overflow-y: auto;
/* 覆盖粘贴残留的内联颜色,保证深底上始终可读 */
:deep(*) {
color: #fff !important;
}
&:empty:before {
content: attr(data-placeholder);
color: #666;

View File

@ -193,6 +193,7 @@
contenteditable="true"
:data-placeholder="placeholder"
@input="onEditorInput"
@paste="onEditorPaste"
@keydown="onEditorKeydown"
@keyup="onEditorKeyup"
@click="onEditorClick"></div>
@ -916,6 +917,64 @@ const restoreSelection = () => {
selection.addRange(range)
}
const insertPlainTextInEditor = (text) => {
if (!editorRef.value) return
const normalizedText = text.replace(/\r\n/g, '\n').replace(/\r/g, '\n')
editorRef.value.focus()
restoreSelection()
const selection = window.getSelection()
if (!selection || selection.rangeCount === 0) return
let range = selection.getRangeAt(0)
if (!editorRef.value.contains(range.commonAncestorContainer)) {
const r = document.createRange()
r.selectNodeContents(editorRef.value)
r.collapse(false)
selection.removeAllRanges()
selection.addRange(r)
range = selection.getRangeAt(0)
}
range.deleteContents()
const lines = normalizedText.split('\n')
const fragment = document.createDocumentFragment()
lines.forEach((line, index) => {
if (line) fragment.appendChild(document.createTextNode(line))
if (index < lines.length - 1) fragment.appendChild(document.createElement('br'))
})
range.insertNode(fragment)
range.collapse(false)
selection.removeAllRanges()
selection.addRange(range)
saveSelection()
}
const onEditorPaste = (e) => {
if (!editorRef.value) return
const cd = e.clipboardData
if (!cd) return
const items = cd.items
if (items) {
for (const item of items) {
if (item.kind === 'file' && item.type && item.type.startsWith('image/')) {
return
}
}
}
let text = cd.getData('text/plain') || ''
if (!text) {
const html = cd.getData('text/html')
if (html) {
const tmp = document.createElement('div')
tmp.innerHTML = html
text = tmp.innerText || ''
}
}
if (!text) return
e.preventDefault()
insertPlainTextInEditor(text)
setPrompt(getEditorPlainText())
saveSelection()
}
const hasActiveMentionTrigger = () => {
const selection = window.getSelection()
if (!selection || selection.rangeCount === 0) return false
@ -2255,6 +2314,16 @@ defineExpose({
word-break: break-word;
overflow-y: auto;
scrollbar-color: rgba(255, 255, 255, 0.22) rgba(255, 255, 255, 0.06);
color: rgba(255, 255, 255, 0.92);
:deep(*) {
color: rgba(255, 255, 255, 0.92) !important;
}
:deep(.vg-inline-ref-audio) {
color: rgba(255, 255, 255, 0.88) !important;
background: rgba(0, 202, 224, 0.12);
}
}
.vg-rich-editor:empty:before {

View File

@ -496,6 +496,15 @@ onMounted(() => {
overflow-y: auto;
color: rgba(255, 255, 255, 0.9);
caret-color: #00cae0;
:deep(*) {
color: rgba(255, 255, 255, 0.9) !important;
}
:deep(.inline-rich-reference) {
color: #5eebf5 !important;
background: rgba(0, 202, 224, 0.15);
}
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 14px;
padding: 16px 18px;