大量优化修改扣积分规则

This commit is contained in:
Azmat@qq.com
2026-09-04 17:20:22 +08:00
parent 3e904479d9
commit 15718a60bf
41 changed files with 1590 additions and 429 deletions
@@ -1,13 +1,16 @@
import { useEffect, useRef, useState } from "react";
import { useEffect, useMemo, useRef, useState } from "react";
import { ChevronDown, SlidersHorizontal, Sparkles } from "lucide-react";
import { CustomSelect } from "./custom-select";
import { modelDurations, modelResolutions } from "./free-create/constants";
import type { ModelConfig } from "../types";
/** 无目录时的回落清单(展示名,与会话 params.model 历史值兼容)。 */
export const OMNI_VIDEO_MODELS = ["Seedance 2.5", "Seedance 2.0", "Seedance 2.0 Fast", "Seedance 2.0 Mini"];
export const OMNI_IMAGE_MODELS = ["Seedream5.0", "YQ image2"];
export const OMNI_RESOLUTIONS = ["1080p", "720p", "480p"];
export const OMNI_RATIOS = ["9:16", "16:9", "1:1", "4:3", "3:4"];
export const OMNI_VIDEO_DURATIONS = [
"4 秒", "5 秒", "6 秒", "7 秒", "8 秒", "9 秒", "10 秒",
"智能时长", "4 秒", "5 秒", "6 秒", "7 秒", "8 秒", "9 秒", "10 秒",
"11 秒", "12 秒", "13 秒", "14 秒", "15 秒", "30 秒",
];
export const OMNI_IMAGE_COUNTS = ["1 张", "2 张", "4 张", "8 张"];
@@ -20,6 +23,59 @@ function withCurrent(values: string[], current: string) {
return current && !values.includes(current) ? [current, ...values] : values;
}
function modelOptionLabel(config: ModelConfig): string {
return (config.display_name || config.name || "").trim();
}
/** 忽略空格/横杠/大小写,兼容旧会话「Seedance 2.0 Mini」对上后台「Seedance-2.0-Mini」。 */
function normalizeModelKey(value: string): string {
return String(value || "").toLowerCase().replace(/[\s_\-·.]+/g, "");
}
/** 会话里存的是展示名;用 display_name / name 都能对上目录项。 */
export function findCatalogModel(
configs: ModelConfig[] | undefined,
label: string,
capability: "video" | "image",
): ModelConfig | undefined {
const list = (configs || []).filter((c) => c.capability === capability && c.status !== "disabled");
const key = (label || "").trim();
if (!key) return list[0];
const norm = normalizeModelKey(key);
return (
list.find((c) => modelOptionLabel(c) === key)
|| list.find((c) => c.name === key)
|| list.find((c) => normalizeModelKey(modelOptionLabel(c)) === norm)
|| list.find((c) => normalizeModelKey(c.name) === norm)
|| list.find((c) => {
const dn = normalizeModelKey(c.display_name || "");
const nm = normalizeModelKey(c.name || "");
return (dn && (dn.includes(norm) || norm.includes(dn))) || (nm && (nm.includes(norm) || norm.includes(nm)));
})
);
}
function catalogModelLabels(
configs: ModelConfig[] | undefined,
capability: "video" | "image",
fallback: string[],
): string[] {
const labels = (configs || [])
.filter((c) => c.capability === capability)
.map(modelOptionLabel)
.filter(Boolean);
const seen = new Set<string>();
const unique = labels.filter((x) => (seen.has(x) ? false : (seen.add(x), true)));
return unique.length ? unique : fallback;
}
function durationLabelsForModel(config: ModelConfig | undefined, isVideo: boolean): string[] {
if (!isVideo) return [...OMNI_IMAGE_COUNTS];
const seconds = modelDurations(config);
if (!seconds.length) return [...OMNI_VIDEO_DURATIONS];
return ["智能时长", ...seconds.map((n) => `${n} 秒`)];
}
export function OmniParamBar({
isVideo,
disabled,
@@ -27,6 +83,7 @@ export function OmniParamBar({
resolution,
ratio,
duration,
catalogModels,
onModel,
onResolution,
onRatio,
@@ -38,6 +95,7 @@ export function OmniParamBar({
resolution: string;
ratio: string;
duration: string;
catalogModels?: ModelConfig[];
onModel: (value: string) => void;
onResolution: (value: string) => void;
onRatio: (value: string) => void;
@@ -47,6 +105,20 @@ export function OmniParamBar({
const [customOn, setCustomOn] = useState(isVideo ? duration !== "智能时长" : true);
const wrapRef = useRef<HTMLDivElement>(null);
const capability = isVideo ? "video" as const : "image" as const;
const selected = useMemo(
() => findCatalogModel(catalogModels, model, capability),
[catalogModels, model, capability],
);
const models = withCurrent(
catalogModelLabels(catalogModels, capability, isVideo ? OMNI_VIDEO_MODELS : OMNI_IMAGE_MODELS),
model,
);
const allowedRes = isVideo ? modelResolutions(selected) : [];
const resolutions = withCurrent(allowedRes.length ? allowedRes : OMNI_RESOLUTIONS, resolution);
const durations = withCurrent(durationLabelsForModel(selected, isVideo), duration);
useEffect(() => {
setCustomOn(isVideo ? duration !== "智能时长" : true);
}, [isVideo, duration]);
@@ -60,8 +132,18 @@ export function OmniParamBar({
return () => document.removeEventListener("mousedown", onDown);
}, [menuOpen]);
const models = withCurrent(isVideo ? OMNI_VIDEO_MODELS : OMNI_IMAGE_MODELS, model);
const durations = isVideo ? OMNI_VIDEO_DURATIONS : OMNI_IMAGE_COUNTS;
useEffect(() => {
if (!selected || !isVideo) return;
const nextRes = modelResolutions(selected);
if (nextRes.length && resolution && !nextRes.includes(resolution)) {
onResolution(nextRes.includes("720p") ? "720p" : nextRes[0]);
}
const nextDur = durationLabelsForModel(selected, true);
if (duration && duration !== "智能时长" && !nextDur.includes(duration)) {
onDuration(nextDur.includes("8 秒") ? "8 秒" : (nextDur.find((x) => x !== "智能时长") || "智能时长"));
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selected?.id, isVideo]);
return (
<>
@@ -84,7 +166,7 @@ export function OmniParamBar({
disabled={disabled}
value={resolution}
onChange={onResolution}
options={toOptions(withCurrent(OMNI_RESOLUTIONS, resolution))}
options={toOptions(resolutions)}
/>
</label>
<label className="omni-parameter">
@@ -136,7 +218,7 @@ export function OmniParamBar({
</div>
) : null}
<div className="omni-duration-values" hidden={isVideo && !customOn}>
{durations.map((value) => (
{(isVideo ? durations.filter((value) => value !== "智能时长") : durations).map((value) => (
<button
type="button"
key={value}