5c45629495
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 1s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 3s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Check push changed paths (push) Successful in 4m37s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 4m37s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 4m50s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 5m5s
AI Code Review / AI Code Review (pull_request) Successful in 7m56s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 4m40s
CI/CD Pipeline / Build Staging API Image (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 8m15s
CI/CD Pipeline / Build Staging Worker Image (push) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Validate - Code Quality (push) Successful in 8m37s
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 1m48s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m55s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 10m20s
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 2m1s
CI/CD Pipeline / Retag skipped Staging API Image (push) Successful in 2m18s
CI/CD Pipeline / CI Gate (pull_request) Successful in 1m49s
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Successful in 2m16s
CI/CD Pipeline / Integration Tests (push) Successful in 4m27s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m0s
CI/CD Pipeline / Unit Tests (push) Successful in 15m57s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 2m25s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 4m10s
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Staging E2E Tests (push) Successful in 4m44s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com> Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
118 lines
4.1 KiB
TypeScript
118 lines
4.1 KiB
TypeScript
/**
|
||
* 上传队列面板
|
||
* 展示批量上传中每个文件的独立状态/进度;失败可重试、可移除、可清空已完成。
|
||
* 上传中的素材卡片同时也会出现在素材网格(后端 prepare 预建 asset),
|
||
* 此面板用于展示真实传输进度与失败重试入口。
|
||
*/
|
||
import React from "react"
|
||
import {
|
||
LoadingOutlined,
|
||
CheckCircleFilled,
|
||
CloseCircleFilled,
|
||
ReloadOutlined,
|
||
CloseOutlined,
|
||
} from "@ant-design/icons"
|
||
import type { UploadItem } from "../hooks/useAssetUpload"
|
||
|
||
export interface UploadQueuePanelProps {
|
||
items: UploadItem[]
|
||
onRetry: (tempId: string) => void
|
||
onRemove: (tempId: string) => void
|
||
onClearFinished: () => void
|
||
}
|
||
|
||
const STATUS_TEXT: Record<UploadItem["status"], string> = {
|
||
preparing: "排队中…",
|
||
uploading: "上传中",
|
||
ingesting: "转码中…",
|
||
done: "已完成",
|
||
error: "上传失败",
|
||
}
|
||
|
||
const UploadQueuePanel: React.FC<UploadQueuePanelProps> = ({
|
||
items,
|
||
onRetry,
|
||
onRemove,
|
||
onClearFinished,
|
||
}) => {
|
||
if (items.length === 0) return null
|
||
const finishedCount = items.filter((it) => it.status === "done").length
|
||
|
||
return (
|
||
<div className="xx-upload-queue">
|
||
<div className="xx-upload-queue-header">
|
||
<span className="xx-upload-queue-title">
|
||
上传任务({items.length}
|
||
{finishedCount > 0 ? `,已完成 ${finishedCount}` : ""})
|
||
</span>
|
||
{finishedCount > 0 && (
|
||
<button type="button" className="xx-link-btn" onClick={onClearFinished}>
|
||
清空已完成
|
||
</button>
|
||
)}
|
||
</div>
|
||
<div className="xx-upload-queue-list">
|
||
{items.map((it) => {
|
||
const isActive = it.status === "preparing" || it.status === "uploading"
|
||
const showProgress = it.status === "uploading" || it.status === "ingesting"
|
||
return (
|
||
<div key={it.tempId} className={`xx-upload-queue-item xx-upload-queue-${it.status}`}>
|
||
<span className="xx-upload-queue-icon">
|
||
{it.status === "done" || it.duplicated ? (
|
||
<CheckCircleFilled style={{ color: "#22c55e" }} />
|
||
) : it.status === "error" ? (
|
||
<CloseCircleFilled style={{ color: "#ef4444" }} />
|
||
) : (
|
||
<LoadingOutlined style={{ color: "var(--primary-color)" }} />
|
||
)}
|
||
</span>
|
||
<div className="xx-upload-queue-body">
|
||
<div className="xx-upload-queue-name" title={it.fileName}>
|
||
{it.fileName}
|
||
</div>
|
||
{showProgress ? (
|
||
<div className="xx-upload-queue-progress">
|
||
<div
|
||
className="xx-upload-queue-progress-bar"
|
||
style={{ width: `${it.status === "ingesting" ? 100 : it.progress}%` }}
|
||
/>
|
||
</div>
|
||
) : null}
|
||
<div className="xx-upload-queue-status">
|
||
{it.duplicated ? "素材已存在,已跳过" : STATUS_TEXT[it.status]}
|
||
{it.status === "uploading" ? ` ${it.progress}%` : ""}
|
||
{it.status === "error" && it.error ? `:${it.error}` : ""}
|
||
</div>
|
||
</div>
|
||
<span className="xx-upload-queue-actions">
|
||
{it.status === "error" && (
|
||
<button
|
||
type="button"
|
||
className="xx-upload-queue-btn"
|
||
title="重试"
|
||
onClick={() => onRetry(it.tempId)}
|
||
>
|
||
<ReloadOutlined />
|
||
</button>
|
||
)}
|
||
{(it.status === "error" || it.status === "done") && !isActive && (
|
||
<button
|
||
type="button"
|
||
className="xx-upload-queue-btn"
|
||
title="移除"
|
||
onClick={() => onRemove(it.tempId)}
|
||
>
|
||
<CloseOutlined />
|
||
</button>
|
||
)}
|
||
</span>
|
||
</div>
|
||
)
|
||
})}
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
export default UploadQueuePanel
|