diff --git a/portal-ui/src/components/VideoComposeCard.vue b/portal-ui/src/components/VideoComposeCard.vue index 19525ce..f39dc20 100644 --- a/portal-ui/src/components/VideoComposeCard.vue +++ b/portal-ui/src/components/VideoComposeCard.vue @@ -47,6 +47,16 @@ +
+
+
+
+
继续上传
+
+
{{ mediaList.length }}/{{ maxMediaCount }}
@@ -677,12 +687,12 @@ const confirmPickAssets = () => { } } else { const remain = props.maxMediaCount - mediaList.value.length - if (remain <= 0 && !isReferenceMode) { + if (remain <= 0) { Message.warning(`最多添加 ${props.maxMediaCount} 个参考素材`) return } - const selected = files.slice(0, remain || files.length) + const selected = files.slice(0, remain) const uploadingEntries = [] for (const file of selected) { @@ -1987,6 +1997,38 @@ defineExpose({ flex-shrink: 0; } +.vg-compose-add-tile { + cursor: pointer; + border: 1px dashed rgba(0, 202, 224, 0.45); + background: rgba(0, 202, 224, 0.06); + transition: all 0.15s ease-in-out; +} + +.vg-compose-add-tile:hover { + border-color: rgba(0, 202, 224, 0.75); + background: rgba(0, 202, 224, 0.1); +} + +.vg-compose-add-preview { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 4px; +} + +.vg-compose-add-icon { + font-size: 24px; + color: rgba(0, 202, 224, 0.75); + line-height: 1; +} + +.vg-compose-add-text { + font-size: 11px; + color: rgba(255, 255, 255, 0.65); + line-height: 1.2; +} + .vg-compose-media-preview { width: 100%; height: 100%; @@ -2042,7 +2084,8 @@ defineExpose({ padding: 8px 10px 10px; background: rgba(0, 0, 0, 0.18); box-sizing: border-box; - overflow: hidden; + /* @候选面板 absolute 需要溢出显示;否则会被父级裁切 */ + overflow: visible; } .vg-compose-right-body { @@ -2079,7 +2122,8 @@ defineExpose({ flex: 1 1 0%; min-height: 0; min-width: 0; - overflow: hidden; + /* @候选面板为 absolute,会在内容较多时溢出裁切;需要显示完整 */ + overflow: visible; display: flex; flex-direction: column; } @@ -2191,7 +2235,6 @@ defineExpose({ max-height: 72px; object-fit: cover; border-radius: 6px; - vertical-align: middle; pointer-events: none; } @@ -2202,7 +2245,6 @@ defineExpose({ border-radius: 6px; object-fit: cover; pointer-events: none; - vertical-align: middle; } .vg-rich-editor :deep(.vg-inline-ref-audio) { @@ -2255,7 +2297,8 @@ defineExpose({ border: 1px solid rgba(255, 255, 255, 0.12); border-radius: 10px; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45); - z-index: 20; + /* 层级要足够高,避免 @候选面板在参考图模式下被上层区域遮挡 */ + z-index: 99999; } .vg-mention-item { diff --git a/portal-ui/src/views/AssetManage.vue b/portal-ui/src/views/AssetManage.vue index 8c8e5b8..321fedb 100644 --- a/portal-ui/src/views/AssetManage.vue +++ b/portal-ui/src/views/AssetManage.vue @@ -182,7 +182,25 @@ - +
+ +
+
+
+
点击选择或拖拽上传
+
+
{{ createForm.fileName || '未选择文件' }}
@@ -240,6 +258,7 @@ export default { name: '', assetType: 'Image' }, + createUploadDragOver: false, filters: { groupId: '', name: '', @@ -370,10 +389,30 @@ export default { this.createForm.groupId = gid this.searchAssets(1) }, + triggerCreateFilePicker() { + const el = this.$refs.createAssetFileInput + if (el && typeof el.click === 'function') el.click() + }, + onCreateUploadDragEnter() { + this.createUploadDragOver = true + }, + onCreateUploadDragOver() { + this.createUploadDragOver = true + }, + onCreateUploadDragLeave() { + this.createUploadDragOver = false + }, + onCreateUploadDrop(e) { + this.createUploadDragOver = false + const file = e?.dataTransfer?.files?.[0] + if (!file) return + this.createForm.file = file + this.createForm.fileName = file?.name || '' + }, onFileChange(e) { - const file = e?.target?.files?.[0] - this.createForm.file = file || null - this.createForm.fileName = file?.name || '' + const file = e?.target?.files?.[0] + this.createForm.file = file || null + this.createForm.fileName = file?.name || '' }, async createAsset() { const groupId = String(this.createForm.groupId || '').trim() @@ -772,6 +811,52 @@ export default { color: rgba(255, 255, 255, 0.88); } +.asset-file-dropzone { + width: 100%; + max-width: 100%; + min-height: 38px; + padding: 10px 12px; + border-radius: 10px; + border: 1px dashed rgba(255, 255, 255, 0.18); + background: rgba(0, 0, 0, 0.18); + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: all 0.15s ease-in-out; + box-sizing: border-box; +} + +.asset-file-dropzone--dragover { + border-color: rgba(0, 202, 224, 0.65); + background: rgba(0, 202, 224, 0.06); +} + +.asset-file-dropzone-content { + display: flex; + align-items: center; + gap: 10px; +} + +.asset-file-dropzone-icon { + width: 28px; + height: 28px; + border-radius: 8px; + border: 1px solid rgba(0, 202, 224, 0.35); + background: rgba(0, 202, 224, 0.08); + color: rgba(0, 202, 224, 0.8); + display: flex; + align-items: center; + justify-content: center; + font-size: 18px; + flex-shrink: 0; +} + +.asset-file-dropzone-text { + font-size: 13px; + color: rgba(255, 255, 255, 0.7); +} + .asset-file-hint { margin-top: 6px; font-size: 12px; diff --git a/portal-ui/src/views/VideoGen.vue b/portal-ui/src/views/VideoGen.vue index ba5e78f..c6d505f 100644 --- a/portal-ui/src/views/VideoGen.vue +++ b/portal-ui/src/views/VideoGen.vue @@ -1081,9 +1081,12 @@ export default { } params.text = first.text || text params.content = contentItems - const firstPreview = attachments.find((x) => x?.mediaType === 'image' && /^https?:\/\//i.test(String(x?.url || ''))) + // 后端要求:reference_url 需要使用资产标识(asset://assetId)时优先传 asset:// + // 展示用仍然可以是 https url,但提交 content/reference_url 要与 assetId 关联。 + const firstPreview = attachments.find((x) => x?.mediaType === 'image') if (firstPreview) { - params.referenceUrl = firstPreview.url + const aid = String(firstPreview?.assetId || '').trim() + params.referenceUrl = aid ? `asset://${aid}` : firstPreview.url } }