Files
ttstd-infinite-canvas/web/src/constant/credits.tsx
ddcat666 ea15000541 feat: 完成短剧项目空间与结构化资产创作闭环 (#38)
* feat(canvas): 短剧项目空间 - 建立项目章节与画布关联 MVP

* feat(canvas): 短剧项目空间 - 完善项目资产、镜头与流程闭环

Refs #30

* fix(deploy): 本地部署 - 修复前端构建并忽略本地 PostgreSQL 配置

* feat(*): 短剧项目空间 - 完成项目、章节、资产、角色与画布创作闭环

Refs #30

---------

Co-authored-by: ddCat <ddcat666@88.com>
2026-07-27 10:45:11 +08:00

35 lines
1.4 KiB
TypeScript

import type { ComponentProps } from "react";
import { Coins } from "lucide-react";
export function CreditSymbol({ className, ...props }: ComponentProps<"span">) {
return (
<span {...props} className={`inline-flex items-center justify-center ${className || ""}`}>
<Coins className="size-[1em]" strokeWidth={2.2} />
</span>
);
}
export type ModelCreditCost = {
model: string;
billingMode: "fixed_request" | "per_second";
unitPriceMicrocredits: number;
};
function modelCreditCost(modelCosts: ModelCreditCost[] | undefined, model: string) {
return modelCosts?.find((item) => item.model === model) || null;
}
export function formatCredits(value: number, maximumFractionDigits = 6) {
return (value / 1_000_000).toLocaleString("zh-CN", { maximumFractionDigits });
}
export function requestCreditCost(options: { channelMode: string; modelCosts?: ModelCreditCost[]; model: string; count?: string | number; seconds?: string | number }) {
if (options.channelMode !== "remote") return null;
const cost = modelCreditCost(options.modelCosts, options.model);
if (!cost) return null;
const quantity = cost.billingMode === "per_second"
? Math.max(1, Math.floor(Math.abs(Number(options.seconds)) || 1))
: Math.max(1, Math.floor(Math.abs(Number(options.count)) || 1));
return (cost.unitPriceMicrocredits / 1_000_000) * quantity;
}