fix: 移除 dialogBox 中残留的平台分支,统一为 descriptor 接口方法

This commit is contained in:
王佑琳 2026-06-09 11:55:22 +08:00
parent ec81dce28a
commit 3507eddfb3
4 changed files with 80 additions and 159 deletions

View File

@ -104,16 +104,7 @@ const showUploader = computed(() => {
return platform.value.showImageUploader()
})
const uploaderBindings = computed(() => {
const p = platform.value
if (p.id === 'painting') {
return { limit: p.imageUploadLimit() }
}
if (p.id === 'video') {
return { modelType: p.modelType.value, imagesCount: p.imageUploadLimit() }
}
return {}
})
const uploaderBindings = computed(() => platform.value.getUploaderBindings())
const autoSizeConfig = computed(() => {
if (useDisplay.Sender_variant !== 'default') {
@ -125,8 +116,9 @@ const autoSizeConfig = computed(() => {
const handleStart = async () => {
const p = platform.value
if (props.type === 'Video' && p.model.value === 'Seedance 2.0') {
ElMessage.primary('敬请期待 Seedance 2.0')
const validationError = p.validateBeforeSubmit()
if (validationError) {
ElMessage.primary(validationError)
return
}
@ -195,11 +187,7 @@ watch(
[() => platform.value.model.value, () => platform.value.modelType.value],
async ([newModel, newModelType]) => {
if (!newModel) return
if (platform.value.id === 'video') {
await platform.value.loadConfig(newModel, newModelType)
} else {
platform.value.loadConfig(newModel)
}
await platform.value.loadConfig(newModel, newModelType)
},
)

View File

@ -26,7 +26,6 @@
<div
v-for="renderItem in visibleItems"
:key="getItemKey(renderItem.item, renderItem.index)"
:ref="el => setItemRef(el, renderItem.index)"
class="virtual-scroller-item"
:style="getItemStyle(renderItem)"
:data-index="renderItem.index"
@ -119,15 +118,11 @@ const emit = defineEmits(['scroll', 'scroll-start', 'scroll-end', 'visible-chang
const containerRef = ref(null)
const wrapperRef = ref(null)
const renderContainerRef = ref(null)
const itemRefs = new Map()
const itemHeights = ref(new Map())
const heightVersion = ref(0)
const resizeObserver = ref(null)
const scrollTop = ref(0)
const isScrolling = ref(false)
const scrollTimeout = ref(null)
const isInitialized = ref(false)
const pendingScrollToBottom = ref(false)
const previousDataLength = ref(0)
const containerStyle = computed(() => {
return {
@ -138,6 +133,7 @@ const containerStyle = computed(() => {
})
const totalHeight = computed(() => {
heightVersion.value // measureItem mutate Map
let height = 0
const len = computedData.value.length
@ -173,51 +169,50 @@ const visibleRange = computed(() => {
if (!renderContainerRef.value || computedData.value.length === 0) {
return { start: 0, end: 0, offset: 0 }
}
heightVersion.value // measureItem mutate Map
const viewportHeight = containerHeight.value
const currentScrollTop = scrollTop.value
const bufferCount = computedBuffer.value
let startIndex = 0
let endIndex = computedData.value.length - 1
let startOffset = 0
const len = computedData.value.length
//
let offset = 0
for (let i = 0; i < computedData.value.length; i++) {
const cachedHeight = itemHeights.value.get(i)
const height = cachedHeight !== undefined ? cachedHeight : props.estimatedHeight
let firstVisibleIdx = 0
for (let i = 0; i < len; i++) {
const height = itemHeights.value.get(i) ?? props.estimatedHeight
if (offset + height > currentScrollTop) {
startIndex = Math.max(0, i - bufferCount)
firstVisibleIdx = i
break
}
offset += height
}
startOffset = 0
for (let i = 0; i < startIndex; i++) {
const cachedHeight = itemHeights.value.get(i)
startOffset += cachedHeight !== undefined ? cachedHeight : props.estimatedHeight
}
offset = startOffset
endIndex = startIndex
for (let i = startIndex; i < computedData.value.length; i++) {
const cachedHeight = itemHeights.value.get(i)
const height = cachedHeight !== undefined ? cachedHeight : props.estimatedHeight
offset += height
if (offset > currentScrollTop + viewportHeight) {
endIndex = Math.min(computedData.value.length - 1, i + bufferCount)
break
const startIndex = Math.max(0, firstVisibleIdx - bufferCount)
// startOffset endIndex
let startOffset = 0
let endIndex = len - 1
offset = 0
for (let i = 0; i < len; i++) {
const height = itemHeights.value.get(i) ?? props.estimatedHeight
if (i < startIndex) {
startOffset += height
}
endIndex = i
if (i >= startIndex) {
if (offset + height > currentScrollTop + viewportHeight) {
endIndex = Math.min(len - 1, i + bufferCount)
break
}
endIndex = i
}
offset += height
}
return { start: Math.min(startIndex, endIndex), end: Math.max(startIndex, endIndex), offset: startOffset }
return { start: startIndex, end: endIndex, offset: startOffset }
})
const visibleItems = computed(() => {
@ -247,7 +242,6 @@ const wrapperStyle = computed(() => ({
direction: 'rtl',
height: '100%',
position: 'relative',
scrollbarWidth: 'auto',
overflow: 'hidden',
transform: 'rotate(180deg)',
width: '100%'
@ -302,28 +296,19 @@ const getItemStyle = (renderItem) => {
}
}
const setItemRef = (el, index) => {
if (el) {
itemRefs.set(index, el)
} else {
itemRefs.delete(index)
}
}
const measureItem = (index, element) => {
if (!element) return
const firstChild = element.firstElementChild
const targetElement = firstChild || element
const height = Math.ceil(targetElement.offsetHeight)
if (height > 0) {
const cachedHeight = itemHeights.value.get(index)
if (cachedHeight !== height) {
const newHeights = new Map(itemHeights.value)
newHeights.set(index, height)
itemHeights.value = newHeights
itemHeights.value.set(index, height)
heightVersion.value++
}
}
}
@ -357,29 +342,10 @@ const handleWheel = (event) => {
event.preventDefault()
}
const scrollCleanupTimeout = ref(null)
const handleScroll = (event) => {
const target = event.target
scrollTop.value = target.scrollTop
isScrolling.value = true
if (scrollTimeout.value) {
clearTimeout(scrollTimeout.value)
}
scrollTimeout.value = setTimeout(() => {
isScrolling.value = false
}, 150)
// ,100ms
if (scrollCleanupTimeout.value) {
clearTimeout(scrollCleanupTimeout.value)
}
scrollCleanupTimeout.value = setTimeout(() => {
cleanupExtraItems(visibleItems.value)
}, 300)
const st = target.scrollTop
const scrollHeight = target.scrollHeight
const clientHeight = target.clientHeight
@ -462,7 +428,6 @@ const getVisibleIndices = () => {
const resetMeasurements = () => {
itemHeights.value = new Map()
itemRefs.clear()
}
const isAtPageBottom = () => {
@ -478,13 +443,15 @@ const isAtPageTop = () => {
}
const observeVisibleItems = () => {
if (!resizeObserver.value) return
if (!resizeObserver.value || !renderContainerRef.value) return
resizeObserver.value.disconnect()
for (const [index, element] of itemRefs) {
if (element) {
resizeObserver.value.observe(element)
// visibleItems index DOM itemRefs DOM
for (const item of visibleItems.value) {
const el = renderContainerRef.value.querySelector(`[data-index="${item.index}"]`)
if (el) {
resizeObserver.value.observe(el)
}
}
}
@ -492,31 +459,28 @@ const observeVisibleItems = () => {
watch(() => computedData.value, (newData, oldData) => {
const oldLength = oldData?.length || 0
const newLength = newData.length
if (newLength !== oldLength) {
const newHeights = new Map()
const minLen = Math.min(oldLength, newLength)
for (let i = 0; i < minLen; i++) {
if (itemHeights.value.has(i)) {
newHeights.set(i, itemHeights.value.get(i))
}
}
itemHeights.value = newHeights
nextTick(() => {
observeVisibleItems()
})
}
previousDataLength.value = newLength
}, { deep: false })
watch(visibleItems, (newItems) => {
nextTick(() => {
observeVisibleItems()
cleanupExtraItems(newItems)
})
if (newItems.length > 0) {
const firstItem = newItems[0]
@ -525,56 +489,16 @@ watch(visibleItems, (newItems) => {
}
}, { deep: true })
const cleanupExtraItems = (currentVisibleItems) => {
if (!renderContainerRef.value || !currentVisibleItems.length) return
//
const visibleIndices = new Set(currentVisibleItems.map(item => item.index))
// render-container .virtual-scroller-item
const renderedItems = renderContainerRef.value.querySelectorAll('.virtual-scroller-item')
const toRemove = []
for (const el of renderedItems) {
const dataIndex = parseInt(el.getAttribute('data-index'), 10)
// data-index ,
if (!isNaN(dataIndex) && !visibleIndices.has(dataIndex)) {
toRemove.push(el)
}
}
// DOM
for (const el of toRemove) {
if (el.parentNode) {
el.parentNode.removeChild(el)
}
// itemRefs Map
const index = parseInt(el.getAttribute('data-index'), 10)
if (!isNaN(index)) {
itemRefs.delete(index)
}
}
if (toRemove.length > 0) {
console.log(`[VirtualScroller] 清理了 ${toRemove.length} 个多余DOM元素`)
}
}
onMounted(() => {
setupResizeObserver()
isInitialized.value = true
previousDataLength.value = computedData.value.length
nextTick(() => {
if (pendingScrollToBottom.value) {
pendingScrollToBottom.value = false
scrollToBottom()
}
observeVisibleItems()
cleanupExtraItems(visibleItems.value)
})
})
@ -582,16 +506,6 @@ onBeforeUnmount(() => {
if (resizeObserver.value) {
resizeObserver.value.disconnect()
}
if (scrollTimeout.value) {
clearTimeout(scrollTimeout.value)
}
if (scrollCleanupTimeout.value) {
clearTimeout(scrollCleanupTimeout.value)
}
itemRefs.clear()
})
defineExpose({

View File

@ -191,7 +191,7 @@ export function definePaintingPlatform() {
return fetchPlatformModels(code)
},
async loadConfig(modelName) {
async loadConfig(modelName, _modelType) {
const config = getModelConfig(modelName)
syncDefaults(config)
return config
@ -201,6 +201,14 @@ export function definePaintingPlatform() {
return 'Flux 2'
},
validateBeforeSubmit() {
return null // 无阻塞,返回 null 表示通过
},
getUploaderBindings() {
return { limit: imageUploadLimit() }
},
showImageUploader() {
if (modelType.value !== 'text') return true
return modelConfig.value?.inputType === 'image' || modelConfig.value?.inputType === 'both'

View File

@ -127,6 +127,17 @@ export function defineVideoPlatform() {
return 'LTX2.0'
},
validateBeforeSubmit() {
if (model.value === 'Seedance 2.0') {
return '敬请期待 Seedance 2.0'
}
return null // 通过
},
getUploaderBindings() {
return { modelType: modelType.value, imagesCount: imageUploadLimit() }
},
showImageUploader() {
return modelType.value !== 'text'
},