93 lines
3.0 KiB
TypeScript
93 lines
3.0 KiB
TypeScript
import React from "react"
|
|
import { PROGRESS_STEPS } from "../constants/cloneModal"
|
|
import type { ProgressStep } from "../types/cloneModal"
|
|
import type { ModalPhase } from "../types/cloneModal"
|
|
|
|
interface ProgressViewProps {
|
|
phase: ModalPhase
|
|
}
|
|
|
|
const getProgressIndex = (phase: ModalPhase): number => {
|
|
switch (phase) {
|
|
case "uploading":
|
|
return 0
|
|
case "cloning":
|
|
return 1
|
|
case "done":
|
|
return 2
|
|
default:
|
|
return -1
|
|
}
|
|
}
|
|
|
|
const ProgressView: React.FC<ProgressViewProps> = ({ phase }) => {
|
|
const progressIndex = getProgressIndex(phase)
|
|
const isDone = phase === "done"
|
|
|
|
return (
|
|
<div className="xx-clonemodal-progress-body">
|
|
{/* 步骤指示器 */}
|
|
<div className="xx-clonemodal-steps-progress">
|
|
{PROGRESS_STEPS.map((step: ProgressStep, idx: number) => {
|
|
const isActive = idx === progressIndex && !isDone
|
|
const stepDone = idx < progressIndex || isDone
|
|
const stepClass = [
|
|
"xx-clonemodal-step-progress",
|
|
isActive ? "xx-clonemodal-step-progress--active" : "",
|
|
stepDone ? "xx-clonemodal-step-progress--done" : "",
|
|
]
|
|
.filter(Boolean)
|
|
.join(" ")
|
|
|
|
return (
|
|
<React.Fragment key={step.key}>
|
|
{idx > 0 && (
|
|
<div
|
|
className={`xx-clonemodal-step-connector${stepDone ? " xx-clonemodal-step-connector--done" : ""}`}
|
|
/>
|
|
)}
|
|
<div className={stepClass}>
|
|
<div className="xx-clonemodal-step-icon">{stepDone ? "✓" : step.icon}</div>
|
|
<span className="xx-clonemodal-step-label">{step.label}</span>
|
|
</div>
|
|
</React.Fragment>
|
|
)
|
|
})}
|
|
</div>
|
|
|
|
{/* 完成阶段 */}
|
|
{isDone && (
|
|
<div className="xx-clonemodal-success">
|
|
<div className="xx-clonemodal-success-icon">🎉</div>
|
|
<h3 className="xx-clonemodal-success-title">克隆已提交</h3>
|
|
<p className="xx-clonemodal-success-desc">
|
|
音色正在生成中,完成后将出现在「我的克隆」列表中
|
|
</p>
|
|
</div>
|
|
)}
|
|
|
|
{/* 进行中阶段 */}
|
|
{!isDone && (
|
|
<div className="xx-clonemodal-progress-info">
|
|
{phase === "uploading" && (
|
|
<>
|
|
<div className="xx-clonemodal-progress-spinner" />
|
|
<p className="xx-clonemodal-progress-text">正在上传音频文件…</p>
|
|
<p className="xx-clonemodal-progress-sub">请稍候,正在将音频上传至服务器</p>
|
|
</>
|
|
)}
|
|
{phase === "cloning" && (
|
|
<>
|
|
<div className="xx-clonemodal-progress-spinner xx-clonemodal-progress-spinner--cloning" />
|
|
<p className="xx-clonemodal-progress-text">AI 正在克隆你的声音…</p>
|
|
<p className="xx-clonemodal-progress-sub">正在分析声音特征,生成专属音色模型</p>
|
|
</>
|
|
)}
|
|
</div>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default ProgressView
|