fix: 交互优化

This commit is contained in:
old burden 2026-03-31 14:40:53 +08:00
parent 1edf9601c0
commit 4cb3f4eb88
2 changed files with 62 additions and 12 deletions

View File

@ -111,9 +111,9 @@
@click="onEditorClick"></div>
<div v-if="mentionVisible" class="vg-mention-panel">
<div
v-for="item in mentionCandidates"
v-for="(item, idx) in mentionCandidates"
:key="item.key"
class="vg-mention-item"
:class="['vg-mention-item', { active: idx === mentionActiveIndex }]"
@mousedown.prevent="selectMentionItem(item)">
<img :src="item.url" alt="" class="vg-mention-thumb" />
</div>
@ -179,6 +179,7 @@ const internalMediaList = ref(Array.isArray(props.mediaList) ? [...props.mediaLi
const currentUploadIndex = ref(-1) // for first/last frame mode
const savedSelectionRange = ref(null)
const mentionVisible = ref(false)
const mentionActiveIndex = ref(-1)
watch(
() => props.modelValue,
@ -221,7 +222,10 @@ onMounted(() => {
const mediaList = computed(() => internalMediaList.value)
const mentionCandidates = computed(() =>
(mediaList.value || [])
.filter((i) => i?.mediaType === 'image' && i?.url)
.filter((i) => {
const u = String(i?.url || '').trim()
return i?.mediaType === 'image' && !i?.isUploading && /^https?:\/\//i.test(u)
})
.map((i, idx) => ({
key: i.id || i.url || String(idx),
url: i.url
@ -394,6 +398,9 @@ const clearAll = () => {
: x
)
)
if (isReferenceMode) {
Message.success('已上传完成')
}
try {
URL.revokeObjectURL(localPreview)
@ -603,6 +610,12 @@ const onEditorInput = () => {
setPrompt(getEditorPlainText())
saveSelection()
mentionVisible.value = isReference.value && hasActiveMentionTrigger()
if (mentionVisible.value) {
const max = mentionCandidates.value.length - 1
mentionActiveIndex.value = max >= 0 ? Math.min(Math.max(mentionActiveIndex.value, 0), max) : -1
} else {
mentionActiveIndex.value = -1
}
}
const findClosestMentionInEditor = (el) => {
@ -636,9 +649,41 @@ const onEditorClick = (e) => {
}
saveSelection()
mentionVisible.value = isReference.value && hasActiveMentionTrigger()
mentionActiveIndex.value = mentionVisible.value && mentionCandidates.value.length ? 0 : -1
}
const onEditorKeydown = (e) => {
if (mentionVisible.value) {
if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
e.preventDefault()
const len = mentionCandidates.value.length
if (len > 0) {
if (mentionActiveIndex.value < 0) {
mentionActiveIndex.value = 0
} else {
const delta = e.key === 'ArrowDown' ? 1 : -1
mentionActiveIndex.value = (mentionActiveIndex.value + delta + len) % len
}
}
return
}
if (e.key === 'Enter') {
const idx = mentionActiveIndex.value >= 0 ? mentionActiveIndex.value : 0
const picked = mentionCandidates.value[idx]
if (picked) {
e.preventDefault()
selectMentionItem(picked)
return
}
}
if (e.key === 'Escape') {
e.preventDefault()
mentionVisible.value = false
mentionActiveIndex.value = -1
return
}
}
if (!isReference.value || !editorRef.value) return
const sel = window.getSelection()
if (!sel || sel.rangeCount === 0) return
@ -731,9 +776,17 @@ const onEditorKeyup = (e) => {
saveSelection()
if (e.key === 'Escape') {
mentionVisible.value = false
mentionActiveIndex.value = -1
return
}
mentionVisible.value = isReference.value && hasActiveMentionTrigger()
if (mentionVisible.value && e.key === '@' && mentionCandidates.value.length === 0) {
Message.warning('请等待上传完成后再引用')
mentionVisible.value = false
mentionActiveIndex.value = -1
return
}
mentionActiveIndex.value = mentionVisible.value && mentionCandidates.value.length ? 0 : -1
}
const selectMentionItem = (item) => {
@ -780,6 +833,7 @@ const selectMentionItem = (item) => {
saveSelection()
mentionVisible.value = false
mentionActiveIndex.value = -1
renumberAllReferenceMentions()
setPrompt(getEditorPlainText())
}
@ -791,6 +845,7 @@ defineExpose({
setPrompt('')
if (editorRef.value) editorRef.value.innerHTML = ''
mentionVisible.value = false
mentionActiveIndex.value = -1
}
})
</script>
@ -1163,6 +1218,10 @@ defineExpose({
background: rgba(255, 255, 255, 0.06);
}
.vg-mention-item.active {
background: rgba(0, 202, 224, 0.18);
}
.vg-mention-thumb {
width: 30px;
height: 30px;

View File

@ -764,10 +764,6 @@ export default {
}
if (this.videoMode === 'image-reference') {
if (attachments.length === 0) {
this.$message.error('请至少上传一张参考图')
return
}
const compose = this.$refs.videoComposeRef
const contentItems =
compose && typeof compose.getImageReferenceContentItems === 'function'
@ -778,11 +774,6 @@ export default {
this.$message.error('参考图内容格式异常,请重试')
return
}
const refUrls = contentItems.filter((x, idx) => idx > 0 && x?.type === 'image_url')
if (!refUrls.length) {
this.$message.error('请通过 @ 在描述中插入参考图')
return
}
params.text = first.text || text
params.content = contentItems
}