143 lines
2.8 KiB
Vue
143 lines
2.8 KiB
Vue
<template>
|
|
<footer class="poster-action-bar">
|
|
<div class="action-status">
|
|
<span class="status-text">{{ completionText }}</span>
|
|
<div class="progress-dots">
|
|
<span
|
|
v-for="item in completionItems"
|
|
:key="item.key"
|
|
class="dot"
|
|
:class="{ done: item.done }"
|
|
:title="item.label"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div class="action-buttons">
|
|
<el-button
|
|
v-if="draft.taskStatus === 'done' && draft.posterUrl"
|
|
@click="$emit('download')"
|
|
>
|
|
<el-icon><Download /></el-icon>
|
|
下载海报
|
|
</el-button>
|
|
<el-button
|
|
v-if="draft.taskStatus === 'done'"
|
|
@click="$emit('new-poster')"
|
|
>
|
|
新建海报
|
|
</el-button>
|
|
<el-button
|
|
v-if="draft.taskStatus === 'failed'"
|
|
@click="$emit('regenerate')"
|
|
>
|
|
重新生成
|
|
</el-button>
|
|
<el-button
|
|
type="primary"
|
|
:disabled="!canAct"
|
|
:loading="isGenerating"
|
|
@click="$emit('action')"
|
|
>
|
|
{{ isGenerating ? '生成中...' : actionLabel }}
|
|
</el-button>
|
|
</div>
|
|
</footer>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed } from 'vue'
|
|
import { Download } from '@element-plus/icons-vue'
|
|
import type { PosterDraft } from '@/composables/usePosterWorkspace'
|
|
|
|
const props = defineProps<{
|
|
draft: PosterDraft
|
|
completionText: string
|
|
completionItems: Array<{ key: string; label: string; done: boolean }>
|
|
actionLabel: string
|
|
actionState: string
|
|
canGenerate: boolean
|
|
}>()
|
|
|
|
defineEmits<{
|
|
action: []
|
|
download: []
|
|
regenerate: []
|
|
'new-poster': []
|
|
}>()
|
|
|
|
const isGenerating = computed(() =>
|
|
props.draft.taskStatus === 'submitting' ||
|
|
props.draft.taskStatus === 'queued' ||
|
|
props.draft.taskStatus === 'generating'
|
|
)
|
|
|
|
const canAct = computed(() => {
|
|
if (isGenerating.value) return false
|
|
return props.actionState !== 'generating'
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
.poster-action-bar {
|
|
height: 56px;
|
|
padding: 0 20px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 16px;
|
|
border-top: 1px solid var(--poster-border);
|
|
background: #fff;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.action-status {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
min-width: 0;
|
|
}
|
|
|
|
.status-text {
|
|
font-size: 13px;
|
|
color: var(--poster-muted);
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.progress-dots {
|
|
display: flex;
|
|
gap: 6px;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.dot {
|
|
width: 8px;
|
|
height: 8px;
|
|
border-radius: 50%;
|
|
background: #e5e7eb;
|
|
transition: background 0.2s;
|
|
}
|
|
|
|
.dot.done {
|
|
background: #16a34a;
|
|
}
|
|
|
|
.action-buttons {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
@media (max-width: 767px) {
|
|
.status-text {
|
|
display: none;
|
|
}
|
|
|
|
.poster-action-bar {
|
|
padding: 0 12px;
|
|
}
|
|
}
|
|
</style>
|