fix: 页面优化,工具栏显示

This commit is contained in:
old burden 2026-03-30 13:05:05 +08:00
parent 0e94beb477
commit 5ba6c9f746
2 changed files with 108 additions and 9 deletions

View File

@ -399,10 +399,44 @@ const clear = () => {
hideMentionPanel() 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({ defineExpose({
getContentItems, getContentItems,
getPlainText, getPlainText,
clear clear,
getDraftState,
applyDraftState
}) })
onMounted(() => { onMounted(() => {

View File

@ -86,8 +86,8 @@
<div class="rich-editor-container"> <div class="rich-editor-container">
<VideoRichEditor <VideoRichEditor
ref="videoRichEditor" ref="videoRichEditor"
:show-toolbar="videoMode !== 'text-to-video'" :show-toolbar="videoMode === 'image-reference'"
@text-change="bumpEditorVisualTick" @text-change="onVideoEditorTextChange"
:placeholder=" :placeholder="
$t('common.textVideoPlaceholder') || $t('common.textVideoPlaceholder') ||
'描述画面与动态,例如:阳光下的女孩在海边起舞…' '描述画面与动态,例如:阳光下的女孩在海边起舞…'
@ -223,6 +223,8 @@
<script> <script>
import VideoRichEditor from '@/components/VideoRichEditor.vue' import VideoRichEditor from '@/components/VideoRichEditor.vue'
const REFERENCE_DRAFT_STORAGE_KEY = 'portalVideoGen_referenceDraft_v1'
export default { export default {
name: 'VideoGen', name: 'VideoGen',
data() { data() {
@ -254,7 +256,9 @@ export default {
selectedRatio: '', selectedRatio: '',
selectedDuration: null, selectedDuration: null,
selectedResolution: '', selectedResolution: '',
maxPollAttempts: 40, // 30 30 15
maxPollAttempts: 30,
pollIntervalMs: 30000,
taskRows: [] taskRows: []
} }
}, },
@ -301,6 +305,40 @@ export default {
this.editorVisualTick++ 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 一致) */ /** 编辑器内插入的参考图 URL与 getContentItems 一致) */
firstReferenceImageUrlFromEditor() { firstReferenceImageUrlFromEditor() {
const items = this.$refs.videoRichEditor?.getContentItems?.() || [] const items = this.$refs.videoRichEditor?.getContentItems?.() || []
@ -313,11 +351,18 @@ export default {
}, },
pickVideoMode(m) { pickVideoMode(m) {
if (this.videoMode === 'image-reference') {
this.saveReferenceDraftFromEditor()
}
this.videoMode = m this.videoMode = m
this.firstUrl = '' this.firstUrl = ''
this.lastUrl = '' this.lastUrl = ''
this.$nextTick(() => { this.$nextTick(() => {
if (m === 'image-reference') {
this.restoreReferenceDraftToEditor()
} else {
this.$refs.videoRichEditor?.clear?.() this.$refs.videoRichEditor?.clear?.()
}
this.bumpEditorVisualTick() this.bumpEditorVisualTick()
}) })
}, },
@ -498,7 +543,9 @@ export default {
this.interval = setInterval(() => { this.interval = setInterval(() => {
attempts++ attempts++
if (attempts > this.maxPollAttempts) { if (attempts > this.maxPollAttempts) {
this.$message.warning('视频生成超时') this.$message.warning(
'等待结果超时:任务可能仍在云端生成,可稍后在「我的视频任务」刷新或向客服提供任务 ID'
)
this.destroyInterval() this.destroyInterval()
return return
} }
@ -507,12 +554,30 @@ export default {
url: `api/portal/video/tasks/${videoId}`, url: `api/portal/video/tasks/${videoId}`,
method: 'GET' method: 'GET'
}).then((res) => { }).then((res) => {
if (res.code == 200 && res.data.status === 'succeeded') { if (res.code != 200) {
this.videoUrl = res.data.content?.video_url || res.data.video_url
this.destroyInterval() 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() { destroyInterval() {