@@ -3,16 +3,16 @@
|
||||
// processing 素材每 8s 轮询火山刷新状态(与基础资产送审轮询同节奏)。
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
import { Check, ChevronLeft, FolderPlus, Pencil, Trash2, Upload, Users, X } from "lucide-react";
|
||||
import { Check, CheckCircle2, ChevronLeft, CircleX, Clock3, FolderPlus, Pencil, Trash2, Upload, Users, X } from "lucide-react";
|
||||
import { api } from "../../api";
|
||||
import { useFileDrop } from "../use-file-drop";
|
||||
import type { FreeAssetGroup, FreeAssetItem, FreeVideoRef } from "../../types";
|
||||
import { useBodyScrollLock } from "../overlays";
|
||||
|
||||
const STATUS_PILL: Record<FreeAssetItem["status"], { cls: string; label: string }> = {
|
||||
processing: { cls: "pill-info", label: "审核中" },
|
||||
active: { cls: "pill-ok", label: "可用" },
|
||||
failed: { cls: "pill-err", label: "未通过" }
|
||||
const STATUS_ICON: Record<FreeAssetItem["status"], { cls: string; label: string; Icon: typeof CheckCircle2 }> = {
|
||||
processing: { cls: "is-processing", label: "审核中,暂不可引用", Icon: Clock3 },
|
||||
active: { cls: "is-active", label: "审核通过,可被引用", Icon: CheckCircle2 },
|
||||
failed: { cls: "is-failed", label: "审核未通过,无法引用", Icon: CircleX }
|
||||
};
|
||||
|
||||
export function AssetLibraryModal({ open, onClose, onPick, notify }: {
|
||||
@@ -122,7 +122,7 @@ export function AssetLibraryModal({ open, onClose, onPick, notify }: {
|
||||
form.append("file", file);
|
||||
const data = await api.uploadFreeAsset(activeGroup.id, form);
|
||||
setAssets((prev) => [data.asset, ...prev]);
|
||||
notify("success", "素材已上传,审核中");
|
||||
notify("info", "素材已提交审核,通过后即可引用");
|
||||
} catch (error) {
|
||||
notify("error", error instanceof Error ? error.message : "上传失败");
|
||||
} finally {
|
||||
@@ -149,7 +149,7 @@ export function AssetLibraryModal({ open, onClose, onPick, notify }: {
|
||||
const data = await api.quickUploadFreeAsset(form);
|
||||
setActiveGroup(data.group);
|
||||
setAssets([data.asset]);
|
||||
notify("success", "图片已上传到默认素材组,审核中");
|
||||
notify("info", "图片已提交审核,通过后即可引用");
|
||||
void loadGroupDetail(data.group);
|
||||
} catch (error) {
|
||||
notify("error", error instanceof Error ? error.message : "上传失败");
|
||||
@@ -443,7 +443,8 @@ export function AssetLibraryModal({ open, onClose, onPick, notify }: {
|
||||
) : (
|
||||
<div className="fc-lib-assets">
|
||||
{assets.map((item) => {
|
||||
const pill = STATUS_PILL[item.status];
|
||||
const statusIcon = STATUS_ICON[item.status];
|
||||
const StatusIcon = statusIcon.Icon;
|
||||
const isEditing = editingAssetId === item.id;
|
||||
const isDeleting = confirmDeleteAssetId === item.id;
|
||||
return (
|
||||
@@ -458,6 +459,9 @@ export function AssetLibraryModal({ open, onClose, onPick, notify }: {
|
||||
<div className="fc-lib-thumb">
|
||||
{item.thumb_url ? <img src={item.thumb_url} alt={item.name} /> : <span className="mono">{item.type === "audio" ? "♪" : item.type.toUpperCase()}</span>}
|
||||
{item.duration ? <span className="fc-ref-dur mono">{item.duration}s</span> : null}
|
||||
<span className={`fc-lib-status-icon ${statusIcon.cls}`} title={statusIcon.label} aria-label={statusIcon.label}>
|
||||
<StatusIcon size={14} strokeWidth={1.8} />
|
||||
</span>
|
||||
</div>
|
||||
{isEditing ? (
|
||||
<div className="fc-lib-rename-row" onClick={(event) => event.stopPropagation()}>
|
||||
@@ -489,7 +493,6 @@ export function AssetLibraryModal({ open, onClose, onPick, notify }: {
|
||||
) : (
|
||||
<div className="fc-lib-name" title={item.name}>{item.name}</div>
|
||||
)}
|
||||
<span className={`pill pill-l3 fc-lib-status ${pill.cls}`}><span className="dot" />{pill.label}</span>
|
||||
{item.status === "failed" && item.error_message && <div className="fc-lib-err mono" title={item.error_message}>{item.error_message}</div>}
|
||||
<div className="fc-lib-ops">
|
||||
<button type="button" title="重命名" onClick={(event) => { event.stopPropagation(); startRenameAsset(item); }}><Pencil size={12} /></button>
|
||||
|
||||
@@ -189,6 +189,140 @@ html[data-theme="dark"] .settings-page {
|
||||
/* --st-black 已改成浅字色,不能再当选中底用 */
|
||||
}
|
||||
|
||||
/* 平台后台:后台壳层保留了一组独立浅色变量,必须从根节点统一接入深色 token。 */
|
||||
html[data-theme="dark"] .admin-app {
|
||||
--st-muted: var(--black-alpha-64);
|
||||
--st-text: var(--accent-black);
|
||||
--st-line: var(--border-faint);
|
||||
--st-wash: var(--background-lighter);
|
||||
--st-hover: var(--black-alpha-4);
|
||||
--st-shadow: none;
|
||||
}
|
||||
html[data-theme="dark"] .admin-app .topbar {
|
||||
border-color: var(--border-faint);
|
||||
background: var(--surface);
|
||||
}
|
||||
html[data-theme="dark"] .admin-rail-mark,
|
||||
html[data-theme="dark"] .admin-group,
|
||||
html[data-theme="dark"] .admin-crumb,
|
||||
html[data-theme="dark"] .admin-crumb button {
|
||||
color: var(--black-alpha-56);
|
||||
}
|
||||
html[data-theme="dark"] .admin-link {
|
||||
color: var(--black-alpha-64);
|
||||
}
|
||||
html[data-theme="dark"] .admin-link:hover {
|
||||
color: var(--accent-black);
|
||||
background: var(--black-alpha-4);
|
||||
transform: none;
|
||||
}
|
||||
html[data-theme="dark"] .admin-link.active {
|
||||
color: var(--heat);
|
||||
background: var(--heat-12);
|
||||
}
|
||||
html[data-theme="dark"] .admin-foot {
|
||||
border-color: var(--border-faint);
|
||||
background: var(--surface);
|
||||
}
|
||||
html[data-theme="dark"] .admin-user {
|
||||
border: 1px solid var(--border-faint);
|
||||
background: var(--background-lighter);
|
||||
}
|
||||
html[data-theme="dark"] .admin-user .av {
|
||||
color: var(--accent-white);
|
||||
background: var(--heat);
|
||||
}
|
||||
html[data-theme="dark"] .admin-user-meta .nm {
|
||||
color: var(--accent-black);
|
||||
}
|
||||
html[data-theme="dark"] .admin-user-meta .rl,
|
||||
html[data-theme="dark"] .admin-logout {
|
||||
color: var(--black-alpha-56);
|
||||
}
|
||||
html[data-theme="dark"] .admin-logout:hover {
|
||||
color: var(--accent-black);
|
||||
background: var(--black-alpha-4);
|
||||
}
|
||||
html[data-theme="dark"] .admin-crumb button:hover,
|
||||
html[data-theme="dark"] .admin-crumb span {
|
||||
color: var(--accent-black);
|
||||
}
|
||||
html[data-theme="dark"] .admin-mode {
|
||||
color: var(--heat);
|
||||
background: var(--heat-12);
|
||||
}
|
||||
html[data-theme="dark"] .admin-welcome p,
|
||||
html[data-theme="dark"] .admin-group-label span,
|
||||
html[data-theme="dark"] .admin-page .page-head .sub,
|
||||
html[data-theme="dark"] .admin-page .page-head p,
|
||||
html[data-theme="dark"] .admin-page .page-head .sub .mono {
|
||||
color: var(--black-alpha-64);
|
||||
}
|
||||
html[data-theme="dark"] .admin-entry {
|
||||
border-color: var(--border-faint);
|
||||
color: var(--accent-black);
|
||||
background: var(--surface);
|
||||
box-shadow: none;
|
||||
}
|
||||
html[data-theme="dark"] .admin-entry:hover {
|
||||
border-color: var(--black-alpha-24);
|
||||
background: var(--background-lighter);
|
||||
box-shadow: none;
|
||||
transform: none;
|
||||
}
|
||||
html[data-theme="dark"] .admin-entry svg:last-child {
|
||||
color: var(--black-alpha-56);
|
||||
}
|
||||
html[data-theme="dark"] .admin-entry-copy small {
|
||||
color: var(--black-alpha-56);
|
||||
}
|
||||
html[data-theme="dark"] .tabs-sub {
|
||||
border-color: var(--border-faint);
|
||||
background: var(--background-lighter);
|
||||
}
|
||||
html[data-theme="dark"] .tab-sub.active {
|
||||
color: var(--accent-white);
|
||||
background: var(--heat);
|
||||
}
|
||||
html[data-theme="dark"] .admin-page table.t.admin-table,
|
||||
html[data-theme="dark"] .admin-attempt-list,
|
||||
html[data-theme="dark"] .gov-card,
|
||||
html[data-theme="dark"] .admin-page .card-hard {
|
||||
border-color: var(--border-faint);
|
||||
background: var(--surface);
|
||||
box-shadow: none;
|
||||
}
|
||||
html[data-theme="dark"] .admin-page table.t.admin-table thead th,
|
||||
html[data-theme="dark"] .admin-json,
|
||||
html[data-theme="dark"] .pt-textarea,
|
||||
html[data-theme="dark"] .admin-page .empty-state {
|
||||
border-color: var(--border-faint);
|
||||
background: var(--background-lighter);
|
||||
}
|
||||
html[data-theme="dark"] .gov-card.warn {
|
||||
border-color: var(--heat-20);
|
||||
background: var(--heat-12);
|
||||
}
|
||||
html[data-theme="dark"] .pt-vars code,
|
||||
html[data-theme="dark"] .qw-chip {
|
||||
border-color: var(--heat-20);
|
||||
color: var(--heat);
|
||||
background: var(--heat-12);
|
||||
}
|
||||
html[data-theme="dark"] .admin-drawer {
|
||||
--st-muted: var(--black-alpha-64);
|
||||
--st-text: var(--accent-black);
|
||||
--st-line: var(--border-faint);
|
||||
--st-wash: var(--background-lighter);
|
||||
border-color: var(--border-faint);
|
||||
background: var(--surface);
|
||||
}
|
||||
html[data-theme="dark"] .admin-bulk-bar {
|
||||
border-color: var(--border-faint);
|
||||
background: var(--surface-raised);
|
||||
box-shadow: var(--shadow-floating);
|
||||
}
|
||||
|
||||
/* 设置侧栏:选中项白底是 --st-black 被深色复用成字色导致 */
|
||||
html[data-theme="dark"] .settings-page .st-tab {
|
||||
color: rgba(232, 234, 237, 0.72);
|
||||
|
||||
@@ -936,6 +936,23 @@
|
||||
.fc-lib-rename-btn:disabled { opacity: .45; cursor: not-allowed; }
|
||||
.fc-lib-count { font-size: 10.5px; letter-spacing: 0.04em; color: var(--black-alpha-48); }
|
||||
.fc-lib-err { font-size: 10.5px; color: var(--accent-crimson); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
.fc-lib-status-icon {
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
right: 6px;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
border: 1px solid var(--border-faint);
|
||||
border-radius: var(--r-sm);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: var(--surface);
|
||||
color: var(--black-alpha-56);
|
||||
}
|
||||
.fc-lib-status-icon.is-active { background: var(--forest-bg); color: var(--accent-forest); border-color: var(--forest-bd); }
|
||||
.fc-lib-status-icon.is-processing { background: var(--heat-12); color: var(--heat); border-color: var(--heat-20); }
|
||||
.fc-lib-status-icon.is-failed { background: var(--crimson-bg); color: var(--accent-crimson); border-color: var(--crimson-bd); }
|
||||
.fc-lib-status {
|
||||
width: 100%;
|
||||
justify-content: flex-start;
|
||||
@@ -966,7 +983,7 @@
|
||||
height: 7px;
|
||||
background: currentColor;
|
||||
}
|
||||
.fc-lib-ops { position: absolute; top: 14px; right: 14px; display: flex; gap: 4px; opacity: 0; transition: opacity 0.2s; }
|
||||
.fc-lib-ops { position: absolute; top: 14px; left: 14px; display: flex; gap: 4px; opacity: 0; transition: opacity 0.2s; }
|
||||
.fc-lib-group:hover .fc-lib-ops, .fc-lib-asset:hover .fc-lib-ops { opacity: 1; }
|
||||
.fc-lib-ops button {
|
||||
width: 22px;
|
||||
|
||||
Reference in New Issue
Block a user