auto-save 2026-05-27 23:08 (~5)

This commit is contained in:
2026-05-27 23:08:22 +08:00
parent d7f72f6b42
commit 538b24a2fd
5 changed files with 72 additions and 11 deletions

View File

@@ -1,11 +1,5 @@
{
"entries": [
{
"files_changed": 1,
"message": "Codex 会话活跃 · 最近命令codex · 分支 main · 1 项未提交变更 · 最近提交fix: center scaled workbench vertically",
"ts": "2026-05-20T12:15:32Z",
"type": "session-heartbeat"
},
{
"files_changed": 2,
"hash": "bd64b94",
@@ -3199,6 +3193,13 @@
"message": "chore: harden production deploy scripts",
"hash": "b6a7e7b",
"files_changed": 2
},
{
"ts": "2026-05-27T23:02:52+08:00",
"type": "commit",
"message": "auto-save 2026-05-27 23:01 (~5)",
"hash": "d7f72f6",
"files_changed": 5
}
]
}

View File

@@ -74,6 +74,19 @@
</n-dropdown>
</div>
<!-- Resolution selector | 清晰度选择 -->
<div class="flex items-center justify-between">
<span class="text-xs text-[var(--text-secondary)]">清晰度</span>
<n-dropdown trigger="click" :options="resolutionOptions" @select="handleResolutionSelect">
<button class="flex items-center gap-1 text-sm text-[var(--text-primary)] hover:text-[var(--accent-color)]">
{{ localResolution }}
<n-icon :size="12">
<ChevronForwardOutline />
</n-icon>
</button>
</n-dropdown>
</div>
<!-- Connected inputs indicator | 连接输入指示 -->
<div
class="flex items-center gap-2 text-xs text-[var(--text-secondary)] py-1 border-t border-[var(--border-color)]">
@@ -154,7 +167,7 @@ import { useVideoGeneration } from '../../hooks'
import { updateNode, removeNode, duplicateNode, addNode, addEdge, nodes, edges } from '../../stores/canvas'
import NodeHandleMenu from './NodeHandleMenu.vue'
import { useModelStore } from '../../stores/pinia'
import { getModelRatioOptions, getModelDurationOptions, getModelConfig, DEFAULT_VIDEO_MODEL } from '../../stores/models'
import { getModelRatioOptions, getModelDurationOptions, getModelResolutionOptions, getModelConfig, DEFAULT_VIDEO_MODEL } from '../../stores/models'
// 使用 Pinia store 获取模型选项(根据渠道过滤)
const modelStore = useModelStore()
@@ -170,12 +183,25 @@ const { updateNodeInternals } = useVueFlow()
// Video generation hook | 视频生成 hook
const { loading, error, status, video: generatedVideo, progress, createVideoTaskOnly } = useVideoGeneration()
const currentModelDefaultResolution = (modelKey) => {
const config = getModelConfig(modelKey)
return config?.defaultParams?.resolution || config?.defaultResolution || config?.resolutions?.[0] || '720p'
}
const normalizeResolutionForModel = (modelKey, resolution) => {
const options = getModelResolutionOptions(modelKey)
const allowed = options.map(option => option.key)
if (resolution && allowed.includes(resolution)) return resolution
return currentModelDefaultResolution(modelKey)
}
// Local state | 本地状态
const showHandleMenu = ref(false)
const isGenerating = ref(false) // 任务创建中状态
const localModel = ref(props.data?.model || DEFAULT_VIDEO_MODEL)
const localRatio = ref(props.data?.ratio || '16:9')
const localDuration = ref(props.data?.dur || 5)
const localResolution = ref(props.data?.resolution || currentModelDefaultResolution(props.data?.model || DEFAULT_VIDEO_MODEL))
// Label editing state | Label 编辑状态
const isEditingLabel = ref(false)
@@ -244,6 +270,11 @@ const durationOptions = computed(() => {
return getModelDurationOptions(localModel.value)
})
// Resolution options based on model | 基于模型的清晰度选项
const resolutionOptions = computed(() => {
return getModelResolutionOptions(localModel.value)
})
// Handle model selection | 处理模型选择
const handleModelSelect = (key) => {
localModel.value = key
@@ -258,6 +289,9 @@ const handleModelSelect = (key) => {
localDuration.value = config.defaultParams.duration
updates.dur = config.defaultParams.duration
}
const nextResolution = currentModelDefaultResolution(key)
localResolution.value = nextResolution
updates.resolution = nextResolution
updateNode(props.id, updates)
}
@@ -284,6 +318,12 @@ const handleDurationSelect = (key) => {
updateNode(props.id, { dur: key })
}
// Handle resolution selection | 处理清晰度选择
const handleResolutionSelect = (key) => {
localResolution.value = key
updateNode(props.id, { resolution: key })
}
// Get connected inputs by role | 根据角色获取连接的输入
const getConnectedInputs = () => {
const connectedEdges = edges.value.filter(e => e.target === props.id)
@@ -411,6 +451,11 @@ const handleGenerate = async () => {
params.dur = localDuration.value
}
// Add resolution | 添加清晰度
if (localResolution.value) {
params.resolution = localResolution.value
}
// 只创建任务,获取 taskId不在这里轮询
const { taskId: newTaskId, url } = await createVideoTaskOnly(params)
@@ -492,7 +537,14 @@ onMounted(() => {
// 使用 store 中的默认模型或第一个可用模型
const selected = availableModels.find(m => m.key === modelStore.selectedVideoModel)?.key
localModel.value = selected || availableModels[0]?.key || DEFAULT_VIDEO_MODEL
updateNode(props.id, { model: localModel.value })
localResolution.value = normalizeResolutionForModel(localModel.value, localResolution.value)
updateNode(props.id, { model: localModel.value, resolution: localResolution.value })
} else {
const nextResolution = normalizeResolutionForModel(localModel.value, localResolution.value)
if (nextResolution !== localResolution.value || !props.data?.resolution) {
localResolution.value = nextResolution
updateNode(props.id, { resolution: nextResolution })
}
}
})
@@ -500,6 +552,13 @@ onMounted(() => {
watch(() => props.data?.model, (newModel) => {
if (newModel && newModel !== localModel.value) {
localModel.value = newModel
localResolution.value = normalizeResolutionForModel(newModel, props.data?.resolution || localResolution.value)
}
})
watch(() => props.data?.resolution, (newResolution) => {
if (newResolution && newResolution !== localResolution.value) {
localResolution.value = normalizeResolutionForModel(localModel.value, newResolution)
}
})

View File

@@ -282,7 +282,8 @@ export const useVideoGeneration = () => {
first_image: firstFile ? { kind: 'keyframe', frame_idx: 0 } : null,
last_image: lastFrameIdx !== null ? { kind: 'keyframe', frame_idx: lastFrameIdx } : null,
model: params.model || 'seedance',
size: normalizeVideoSize(params.ratio || params.size)
size: normalizeVideoSize(params.ratio || params.size),
resolution: params.resolution || '720p'
})
})
const created = newestGeneratedVideo(updated)

View File

@@ -150,7 +150,7 @@ export const getModelDurationOptions = (modelKey) => {
*/
export const getModelResolutionOptions = (modelKey) => {
const model = getModelConfig(modelKey) || VIDEO_MODELS.find(m => m.key === modelKey)
if (model?.resolutionOptions) {
if (model?.resolutionOptions?.length) {
return model.resolutionOptions
}
if (!model?.resolutions) return SEEDANCE_RESOLUTION_OPTIONS

View File

@@ -173,7 +173,7 @@ const normalizeRuntimeVideoModel = (item) => {
const sizeOptions = normalizeRuntimeSizeOptions(item.size_options)
const durationOptions = normalizeRuntimeDurationOptions(item.duration_options)
const resolutionOptions = normalizeRuntimeResolutionOptions(item.resolution_options)
const resolutions = resolutionOptions.map(option => option.key)
const resolutions = resolutionOptions.length ? resolutionOptions.map(option => option.key) : ['720p']
const defaultResolution = item.default_resolution || resolutions[0] || '720p'
return {
label: item.label || item.model || key,