113 lines
2.8 KiB
Vue
113 lines
2.8 KiB
Vue
<!-- 任务状态组件,负责展示生成任务的状态点、文案和错误详情。 -->
|
||
<script setup lang="ts">
|
||
import { computed } from "vue";
|
||
import type { GenerationTask } from "@/api/creative";
|
||
|
||
const props = defineProps<{ status?: string; task?: GenerationTask; cancellable?: boolean }>();
|
||
const emit = defineEmits<{ cancel: [task: GenerationTask] }>();
|
||
const labels: Record<string, string> = {
|
||
pending_submission: "排队中",
|
||
submitting: "排队中",
|
||
submitted: "已提交",
|
||
processing: "处理中",
|
||
result_ready: "结果入库中",
|
||
downloading: "结果入库中",
|
||
succeeded: "已完成",
|
||
failed: "失败",
|
||
cancel_requested: "取消处理中",
|
||
cancelled: "已取消",
|
||
draft: "待上传",
|
||
uploaded: "待分析",
|
||
analyzing: "分析中",
|
||
review: "待确认",
|
||
generating: "生成中",
|
||
completed: "已完成",
|
||
};
|
||
const value = computed(() => props.task?.status || props.status || "idle");
|
||
const label = computed(() => labels[value.value] || (value.value === "idle" ? "未生成" : value.value));
|
||
const tone = computed(
|
||
() =>
|
||
({
|
||
succeeded: "success",
|
||
completed: "success",
|
||
review: "success",
|
||
failed: "danger",
|
||
cancelled: "muted",
|
||
})[value.value] || (["idle", "draft", "uploaded"].includes(value.value) ? "muted" : "active"),
|
||
);
|
||
const canCancel = computed(
|
||
() =>
|
||
props.cancellable &&
|
||
props.task &&
|
||
["pending_submission", "submitted", "processing", "cancel_requested"].includes(value.value),
|
||
);
|
||
</script>
|
||
|
||
<template>
|
||
<span
|
||
class="task-state"
|
||
:class="`task-state--${tone}`"
|
||
><i></i>{{ label }}</span
|
||
>
|
||
<button
|
||
v-if="canCancel"
|
||
class="task-cancel"
|
||
type="button"
|
||
:disabled="value === 'cancel_requested'"
|
||
@click="emit('cancel', task!)"
|
||
>
|
||
取消
|
||
</button>
|
||
</template>
|
||
|
||
<style scoped lang="scss">
|
||
.task-state {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 7px;
|
||
color: var(--web-task-idle-text);
|
||
font-size: 12px;
|
||
white-space: nowrap;
|
||
}
|
||
.task-state i {
|
||
width: 6px;
|
||
height: 6px;
|
||
background: var(--web-task-idle-dot);
|
||
border-radius: 50%;
|
||
}
|
||
.task-state--active i {
|
||
background: var(--creative-accent, var(--web-creative-accent));
|
||
box-shadow: 0 0 0 3px var(--web-task-running-ring);
|
||
}
|
||
.task-state--success {
|
||
color: var(--web-task-success-text);
|
||
}
|
||
.task-state--success i {
|
||
background: var(--web-task-success-dot);
|
||
}
|
||
.task-state--danger {
|
||
color: var(--web-task-failed-text);
|
||
}
|
||
.task-state--danger i {
|
||
background: var(--web-task-failed-dot);
|
||
}
|
||
.task-state--muted {
|
||
color: var(--web-empty-text);
|
||
}
|
||
.task-cancel {
|
||
padding: 0;
|
||
color: var(--web-task-cancelled);
|
||
background: transparent;
|
||
border: 0;
|
||
font-size: 12px;
|
||
cursor: pointer;
|
||
}
|
||
.task-cancel:hover {
|
||
color: var(--creative-accent, var(--web-creative-accent));
|
||
}
|
||
.task-cancel:disabled {
|
||
color: var(--web-task-detail);
|
||
cursor: default;
|
||
}
|
||
</style>
|