完善视频提炼和视频复刻完善提交测试
This commit is contained in:
@@ -3,6 +3,7 @@ import type { ChangeEvent, CSSProperties, KeyboardEvent } from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
import { Check, RefreshCw, Settings2, Trash2, Upload, User, UserPlus, X } from "lucide-react";
|
||||
import { api } from "../api";
|
||||
import { useFileDrop } from "../components/use-file-drop";
|
||||
import { generationErrorText } from "../generation-error";
|
||||
import type { ModelEntity } from "../types";
|
||||
import { SystemLoading } from "../components/loading";
|
||||
@@ -120,6 +121,11 @@ function ModelDetailModal({ model, close, onZoom, onSaved, onNotify, onBillingCh
|
||||
setSaving(false);
|
||||
}
|
||||
}
|
||||
const portraitDrop = useFileDrop(
|
||||
(files) => selectPortrait(files[0]),
|
||||
{ disabled: saving, accept: (f) => f.type.startsWith("image/") }
|
||||
);
|
||||
|
||||
function selectPortrait(file?: File) {
|
||||
if (!file || currentModel.is_official || saving) return;
|
||||
clearPendingPortrait();
|
||||
@@ -203,7 +209,8 @@ function ModelDetailModal({ model, close, onZoom, onSaved, onNotify, onBillingCh
|
||||
</div>
|
||||
<input ref={portraitFileRef} type="file" accept="image/*" hidden onChange={(event) => { const file = event.target.files?.[0]; event.target.value = ""; selectPortrait(file); }} />
|
||||
<div
|
||||
className={`placeholder model-detail-portrait${portraitUrl ? " has-mock-media" : ""}`}
|
||||
className={`placeholder model-detail-portrait${portraitUrl ? " has-mock-media" : ""}${portraitDrop.dragging ? " is-dragover" : ""}`}
|
||||
{...(model.is_official ? {} : portraitDrop.dropProps)}
|
||||
style={portraitUrl ? mediaStyle(portraitUrl) : undefined}
|
||||
role={portraitUrl ? "button" : undefined}
|
||||
tabIndex={portraitUrl ? 0 : undefined}
|
||||
@@ -307,9 +314,18 @@ export function ModelsPage({ onNotify, onBillingChanged }: {
|
||||
|
||||
useEffect(() => { setSelected(new Set()); }, [tab]);
|
||||
|
||||
const modelDrop = useFileDrop(
|
||||
(files) => { void acceptModelFile(files[0]); },
|
||||
{ disabled: uploading, accept: (f) => f.type.startsWith("image/") }
|
||||
);
|
||||
|
||||
async function onPick(e: ChangeEvent<HTMLInputElement>) {
|
||||
const file = e.target.files?.[0];
|
||||
e.target.value = "";
|
||||
await acceptModelFile(file);
|
||||
}
|
||||
|
||||
async function acceptModelFile(file?: File | null) {
|
||||
if (!file) return;
|
||||
setUploading(true);
|
||||
try {
|
||||
@@ -357,7 +373,7 @@ export function ModelsPage({ onNotify, onBillingChanged }: {
|
||||
</button>
|
||||
<button className="ml-primary" type="button" disabled={uploading} onClick={() => fileRef.current?.click()}>
|
||||
<UserPlus />
|
||||
<span>{uploading ? "上传中…" : "添加模特"}</span>
|
||||
<span>{uploading ? "上传中…" : modelDrop.dragging ? "松开即可添加" : "添加模特"}</span>
|
||||
</button>
|
||||
<input ref={fileRef} type="file" accept="image/*" hidden onChange={onPick} />
|
||||
</div>
|
||||
@@ -388,7 +404,7 @@ export function ModelsPage({ onNotify, onBillingChanged }: {
|
||||
<span>点右上「添加模特」上传一张形象图,或在图片/视频流程里生成</span>
|
||||
</div>
|
||||
) : (
|
||||
<div className="ml-grid">
|
||||
<div className={`ml-grid${modelDrop.dragging ? " is-dragover" : ""}`} {...modelDrop.dropProps}>
|
||||
{items.map((m) => {
|
||||
const selectable = !m.is_official;
|
||||
const isSelected = selected.has(m.id);
|
||||
|
||||
Reference in New Issue
Block a user