feat: add task workflow and asset downloads

This commit is contained in:
inman
2026-05-29 12:32:02 +08:00
parent f9c3393f84
commit 63e62d444c
61 changed files with 2773 additions and 2181 deletions

View File

@@ -1,7 +1,7 @@
"use client";
import { useEffect, useMemo, useRef, useState } from "react";
import { Eye, ImageIcon, Info, Loader2, Music, RefreshCw, Trash2, X } from "lucide-react";
import { Download, Eye, ImageIcon, Info, Loader2, Music, RefreshCw, Trash2, X } from "lucide-react";
import { clampPage, pageItems, Pagination } from "@/components/pagination";
import { modalEnter, modalExit, pulseFeedback, revealChildren, runScopedMotion } from "@/lib/ui/motion";
import type { Asset, GenerationJob } from "@/lib/types";
@@ -208,6 +208,9 @@ export function AssetManager() {
<button className="button mini-button" type="button" title="预览" aria-label={`预览 ${asset.name}`} onClick={() => setPreviewAsset(asset)}>
<Eye size={15} />
</button>
<a className="button mini-button" href={assetDownloadUrl(asset)} title="下载" aria-label={`下载 ${asset.name}`}>
<Download size={15} />
</a>
<button className="button danger mini-button" type="button" title="删除" aria-label={`删除 ${asset.name}`} onClick={() => removeAsset(asset)} disabled={deletingAssetId === asset.id}>
{deletingAssetId === asset.id ? <Loader2 className="spin" size={15} /> : <Trash2 size={15} />}
</button>
@@ -264,9 +267,14 @@ export function AssetManager() {
<strong>{previewAsset.name}</strong>
<span className="muted compact-hint">{kindLabel(previewAsset)} / {sourceLabel(previewAsset.source)} / {formatDate(previewAsset.createdAt)}</span>
</div>
<button className="icon-button" type="button" title="关闭预览" aria-label="关闭预览" ref={closeButtonRef} onClick={closePreview}>
<X size={18} />
</button>
<div className="asset-preview-actions">
<a className="icon-button" href={assetDownloadUrl(previewAsset)} title="下载" aria-label={`下载 ${previewAsset.name}`}>
<Download size={18} />
</a>
<button className="icon-button" type="button" title="关闭预览" aria-label="关闭预览" ref={closeButtonRef} onClick={closePreview}>
<X size={18} />
</button>
</div>
</div>
<div className="asset-preview-media">
{renderAssetPreviewLarge(previewAsset)}
@@ -372,6 +380,10 @@ function renderAssetPreviewLarge(asset: Asset) {
);
}
function assetDownloadUrl(asset: Asset) {
return `/api/assets/${encodeURIComponent(asset.id)}/download`;
}
function isResultAsset(asset: Asset, outputAssetIds: Set<string>) {
if (!outputAssetIds.has(asset.id)) return false;
if (asset.kind === "mask" || asset.tags.includes("mask") || typeof asset.metadata.maskRule === "string") return false;