fix: 页面优化,工具栏显示
This commit is contained in:
parent
0e94beb477
commit
5ba6c9f746
|
|
@ -399,10 +399,44 @@ const clear = () => {
|
|||
hideMentionPanel()
|
||||
}
|
||||
|
||||
/** 供父组件持久化:参考图模式的 HTML + 素材列表 */
|
||||
const getDraftState = () => ({
|
||||
html: editorRef.value ? editorRef.value.innerHTML : '',
|
||||
mentionList: mentionImageList.value.map(({ url, refNo, mediaType }) => ({
|
||||
url,
|
||||
refNo,
|
||||
mediaType
|
||||
}))
|
||||
})
|
||||
|
||||
const applyDraftState = (draft) => {
|
||||
hideMentionPanel()
|
||||
savedSelectionRange.value = null
|
||||
if (!draft || typeof draft !== 'object') {
|
||||
clear()
|
||||
return
|
||||
}
|
||||
mentionImageList.value = Array.isArray(draft.mentionList)
|
||||
? draft.mentionList.map((x) => ({
|
||||
url: x.url,
|
||||
refNo: Number(x.refNo) || 0,
|
||||
mediaType: x.mediaType || 'image'
|
||||
}))
|
||||
: []
|
||||
if (editorRef.value) {
|
||||
editorRef.value.innerHTML = typeof draft.html === 'string' ? draft.html : ''
|
||||
}
|
||||
nextTick(() => {
|
||||
emit('text-change', getPlainText())
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
getContentItems,
|
||||
getPlainText,
|
||||
clear
|
||||
clear,
|
||||
getDraftState,
|
||||
applyDraftState
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
|
|
|
|||
|
|
@ -86,8 +86,8 @@
|
|||
<div class="rich-editor-container">
|
||||
<VideoRichEditor
|
||||
ref="videoRichEditor"
|
||||
:show-toolbar="videoMode !== 'text-to-video'"
|
||||
@text-change="bumpEditorVisualTick"
|
||||
:show-toolbar="videoMode === 'image-reference'"
|
||||
@text-change="onVideoEditorTextChange"
|
||||
:placeholder="
|
||||
$t('common.textVideoPlaceholder') ||
|
||||
'描述画面与动态,例如:阳光下的女孩在海边起舞…'
|
||||
|
|
@ -223,6 +223,8 @@
|
|||
<script>
|
||||
import VideoRichEditor from '@/components/VideoRichEditor.vue'
|
||||
|
||||
const REFERENCE_DRAFT_STORAGE_KEY = 'portalVideoGen_referenceDraft_v1'
|
||||
|
||||
export default {
|
||||
name: 'VideoGen',
|
||||
data() {
|
||||
|
|
@ -254,7 +256,9 @@ export default {
|
|||
selectedRatio: '',
|
||||
selectedDuration: null,
|
||||
selectedResolution: '',
|
||||
maxPollAttempts: 40,
|
||||
// 每 30 秒查询任务状态,最多 30 次(约 15 分钟)
|
||||
maxPollAttempts: 30,
|
||||
pollIntervalMs: 30000,
|
||||
taskRows: []
|
||||
}
|
||||
},
|
||||
|
|
@ -301,6 +305,40 @@ export default {
|
|||
this.editorVisualTick++
|
||||
},
|
||||
|
||||
onVideoEditorTextChange() {
|
||||
this.bumpEditorVisualTick()
|
||||
if (this.videoMode === 'image-reference') {
|
||||
this.saveReferenceDraftFromEditor()
|
||||
}
|
||||
},
|
||||
|
||||
saveReferenceDraftFromEditor() {
|
||||
const ed = this.$refs.videoRichEditor
|
||||
if (!ed || typeof ed.getDraftState !== 'function') return
|
||||
try {
|
||||
const draft = ed.getDraftState()
|
||||
localStorage.setItem(REFERENCE_DRAFT_STORAGE_KEY, JSON.stringify(draft))
|
||||
} catch (_) {
|
||||
/* ignore quota / private mode */
|
||||
}
|
||||
},
|
||||
|
||||
restoreReferenceDraftToEditor() {
|
||||
const ed = this.$refs.videoRichEditor
|
||||
if (!ed || typeof ed.applyDraftState !== 'function') return
|
||||
try {
|
||||
const raw = localStorage.getItem(REFERENCE_DRAFT_STORAGE_KEY)
|
||||
if (!raw) {
|
||||
ed.clear?.()
|
||||
return
|
||||
}
|
||||
const draft = JSON.parse(raw)
|
||||
ed.applyDraftState(draft)
|
||||
} catch (_) {
|
||||
ed.clear?.()
|
||||
}
|
||||
},
|
||||
|
||||
/** 编辑器内插入的参考图 URL(与 getContentItems 一致) */
|
||||
firstReferenceImageUrlFromEditor() {
|
||||
const items = this.$refs.videoRichEditor?.getContentItems?.() || []
|
||||
|
|
@ -313,11 +351,18 @@ export default {
|
|||
},
|
||||
|
||||
pickVideoMode(m) {
|
||||
if (this.videoMode === 'image-reference') {
|
||||
this.saveReferenceDraftFromEditor()
|
||||
}
|
||||
this.videoMode = m
|
||||
this.firstUrl = ''
|
||||
this.lastUrl = ''
|
||||
this.$nextTick(() => {
|
||||
this.$refs.videoRichEditor?.clear?.()
|
||||
if (m === 'image-reference') {
|
||||
this.restoreReferenceDraftToEditor()
|
||||
} else {
|
||||
this.$refs.videoRichEditor?.clear?.()
|
||||
}
|
||||
this.bumpEditorVisualTick()
|
||||
})
|
||||
},
|
||||
|
|
@ -498,7 +543,9 @@ export default {
|
|||
this.interval = setInterval(() => {
|
||||
attempts++
|
||||
if (attempts > this.maxPollAttempts) {
|
||||
this.$message.warning('视频生成超时')
|
||||
this.$message.warning(
|
||||
'等待结果超时:任务可能仍在云端生成,可稍后在「我的视频任务」刷新或向客服提供任务 ID'
|
||||
)
|
||||
this.destroyInterval()
|
||||
return
|
||||
}
|
||||
|
|
@ -507,12 +554,30 @@ export default {
|
|||
url: `api/portal/video/tasks/${videoId}`,
|
||||
method: 'GET'
|
||||
}).then((res) => {
|
||||
if (res.code == 200 && res.data.status === 'succeeded') {
|
||||
this.videoUrl = res.data.content?.video_url || res.data.video_url
|
||||
if (res.code != 200) {
|
||||
this.destroyInterval()
|
||||
this.$message.error(res.msg || '查询生成状态失败')
|
||||
return
|
||||
}
|
||||
const st = res.data != null && res.data.status != null ? String(res.data.status).toLowerCase().trim() : ''
|
||||
if (st === 'succeeded') {
|
||||
this.videoUrl = res.data.content?.video_url || res.data.video_url
|
||||
if (!this.videoUrl) {
|
||||
this.$message.warning('任务已完成但未返回视频地址,请稍后重试或联系管理员')
|
||||
}
|
||||
this.destroyInterval()
|
||||
return
|
||||
}
|
||||
if (st === 'failed' || st === 'cancelled' || st === 'canceled') {
|
||||
this.destroyInterval()
|
||||
this.$message.error(
|
||||
res.data.error?.message || res.data.message || '视频生成失败或已取消'
|
||||
)
|
||||
}
|
||||
}).catch(() => {
|
||||
/* 单次网络错误不停止轮询,避免偶发抖动 */
|
||||
})
|
||||
}, 3000)
|
||||
}, this.pollIntervalMs)
|
||||
},
|
||||
|
||||
destroyInterval() {
|
||||
|
|
|
|||
Loading…
Reference in New Issue