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" @keyup="handleKeyup"
@click="handleEditorClick" @click="handleEditorClick"
@keydown="handleKeydown" @keydown="handleKeydown"
@paste="handlePaste"
></div> ></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 = () => { const showMentionPanel = () => {
if (props.uploadedImages && props.uploadedImages.length > 0) { if (props.uploadedImages && props.uploadedImages.length > 0) {
@ -261,23 +320,6 @@ export default {
onMounted(() => { onMounted(() => {
if (editorRef.value) { if (editorRef.value) {
editorRef.value.innerHTML = props.modelValue || '' 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, handleInput,
handleKeyup, handleKeyup,
handleKeydown, handleKeydown,
handlePaste,
handleEditorClick, handleEditorClick,
insertMentionImage, insertMentionImage,
clear clear
@ -341,7 +384,12 @@ export default {
font-size: 14px; font-size: 14px;
outline: none; outline: none;
overflow-y: auto; overflow-y: auto;
/* 覆盖粘贴残留的内联颜色,保证深底上始终可读 */
:deep(*) {
color: #fff !important;
}
&:empty:before { &:empty:before {
content: attr(data-placeholder); content: attr(data-placeholder);
color: #666; color: #666;

View File

@ -193,6 +193,7 @@
contenteditable="true" contenteditable="true"
:data-placeholder="placeholder" :data-placeholder="placeholder"
@input="onEditorInput" @input="onEditorInput"
@paste="onEditorPaste"
@keydown="onEditorKeydown" @keydown="onEditorKeydown"
@keyup="onEditorKeyup" @keyup="onEditorKeyup"
@click="onEditorClick"></div> @click="onEditorClick"></div>
@ -916,6 +917,64 @@ const restoreSelection = () => {
selection.addRange(range) 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 hasActiveMentionTrigger = () => {
const selection = window.getSelection() const selection = window.getSelection()
if (!selection || selection.rangeCount === 0) return false if (!selection || selection.rangeCount === 0) return false
@ -2255,6 +2314,16 @@ defineExpose({
word-break: break-word; word-break: break-word;
overflow-y: auto; overflow-y: auto;
scrollbar-color: rgba(255, 255, 255, 0.22) rgba(255, 255, 255, 0.06); 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 { .vg-rich-editor:empty:before {

View File

@ -496,6 +496,15 @@ onMounted(() => {
overflow-y: auto; overflow-y: auto;
color: rgba(255, 255, 255, 0.9); color: rgba(255, 255, 255, 0.9);
caret-color: #00cae0; 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: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 14px; border-radius: 14px;
padding: 16px 18px; padding: 16px 18px;