feat(core): 模型选择框换 restraint chip 下拉 + worker 并发出图(修 -P solo 串行)

UI:脚本助手模型框从『原生 select + inline style』换成复用设计系统的 chip 下拉(向上展开,新增共享 .align-up 变体),去 inline、合规范。并发:本地 worker 从 -P solo(单任务串行=一次只生成一张)改 -P threads -c 4;生产 k8s worker --concurrency 2→4。基础资产/故事板/视频出图可并行。loading 动画基础设施(卡内+全局 spinner)已验证存在。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
seaislee1209
2026-06-17 22:17:47 +08:00
co-authored by Claude Opus 4.8
parent edaa314261
commit 03e7949307
5 changed files with 32 additions and 13 deletions
+1
View File
@@ -869,6 +869,7 @@ main { position: relative; background: var(--background-base); min-width: 0; }
}
.chip-wrap.open .chip-menu { display: block; }
.chip-menu.align-right { left: auto; right: 0; }
.chip-menu.align-up { top: auto; bottom: calc(100% + 4px); }
.chip-menu .mi {
height: 32px; padding: 0 10px;
font-size: 13px; color: var(--accent-black);
+27 -10
View File
@@ -842,6 +842,16 @@ export function PipelinePage(props: {
// 脚本模型下拉:用户可选 豆包/GPT-5.5/Gemini(空 = 用后端默认文本模型)
const [scriptModelId, setScriptModelId] = useState<string>("");
const activeScriptModelId = scriptModelId || textModels?.[0]?.id || "";
// 模型选择小按钮(输入框下方)· 自建 restraint 下拉(幽灵触发 + popover 菜单),不再用原生 select + inline
const [modelMenuOpen, setModelMenuOpen] = useState(false);
const activeModel = textModels?.find((m) => m.id === activeScriptModelId);
const activeModelName = activeModel?.display_name || activeModel?.name || "默认模型";
useEffect(() => {
if (!modelMenuOpen) return;
const close = (e: MouseEvent) => { if (!(e.target as HTMLElement).closest(".chat-model-pick")) setModelMenuOpen(false); };
document.addEventListener("click", close);
return () => document.removeEventListener("click", close);
}, [modelMenuOpen]);
// 删除分镜的两步确认(行内变红,3 秒不二次点击自动复位;不用原生 confirm)
const [armedDelete, setArmedDelete] = useState<string | null>(null);
// 行35 · 单条分镜重跑 / 删除的即时反馈:正在处理的 shot id(按钮转「处理中」并禁用)
@@ -2267,17 +2277,24 @@ export function PipelinePage(props: {
<button className="chat-icon-btn" id="chat-upload-btn" type="button" title="上传脚本附件" aria-label="上传脚本附件" onClick={() => chatFileRef.current?.click()}>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M12 5v14M5 12h14" /></svg>
</button>
{/* 模型选择小按钮(输入框下方,对齐 ChatGPT/Lovart) */}
{/* 模型选择小按钮(输入框下方,对齐 ChatGPT/Lovart)· 复用 restraint chip 下拉,向上展开 */}
{textModels && textModels.length > 0 ? (
<select
className="setup-select"
style={{ height: 26, fontSize: 12, padding: "0 6px", maxWidth: 150, marginLeft: 6 }}
value={activeScriptModelId}
onChange={(event) => setScriptModelId(event.target.value)}
title="选择脚本生成模型(豆包 / GPT / Gemini)"
>
{textModels.map((m) => <option key={m.id} value={m.id}>{m.display_name || m.name}</option>)}
</select>
<div className={`chip-wrap${modelMenuOpen ? " open" : ""}`}>
<button type="button" className="chip" title="选择脚本生成模型(豆包 / GPT / Gemini)" onClick={() => setModelMenuOpen((v) => !v)}>
{activeModelName}
<svg className="caret" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="m6 9 6 6 6-6" /></svg>
</button>
<div className="chip-menu align-up">
{textModels.map((m) => (
<div key={m.id} className={`mi${m.id === activeScriptModelId ? " selected" : ""}`} role="menuitemradio" aria-checked={m.id === activeScriptModelId} tabIndex={0}
onClick={() => { setScriptModelId(m.id); setModelMenuOpen(false); }}
onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); setScriptModelId(m.id); setModelMenuOpen(false); } }}>
{m.display_name || m.name}
<svg className="mi-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.6" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6 9 17l-5-5" /></svg>
</div>
))}
</div>
</div>
) : null}
<span className="spacer"></span>
<button className="chat-send-btn" id="chat-send-btn" type="button" title="发送" aria-label="发送" disabled={loading || (!setupOpen && !chatText.trim() && pendingTagEdits.length === 0)} onClick={submitChat}>