文案(规则 / 命名):重写规则组、试算与命名模板文案
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
This commit is contained in:
1 parent
3853a65754
commit
0bf26b78c6
6 files changed
+20
-20
No files matched your search
@@ -25,13 +25,13 @@ const GROUP_ORDER = ["title", "episode", "tech", "id", "ours"] as const;
|
||||
|
||||
const ROLE: Record<NamingPreviewResult["segments"][number]["role"], { label: string; className: string }> = {
|
||||
category: { label: "分类", className: "text-muted-foreground" },
|
||||
root: { label: "作品根", className: "text-primary font-medium" },
|
||||
root: { label: "作品目录", className: "text-primary font-medium" },
|
||||
season: { label: "季目录", className: "text-foreground" },
|
||||
sub: { label: "子目录", className: "text-muted-foreground" },
|
||||
file: { label: "文件名", className: "text-foreground font-medium" },
|
||||
};
|
||||
|
||||
export const NAMING_NOTE = "已建立目录的作品不受模板影响,模板只决定新目录和新文件名。";
|
||||
export const NAMING_NOTE = "已建立目录的作品沿用原目录,模板只决定新目录和文件名。";
|
||||
|
||||
function useDebounced<T>(v: T, ms = 300): T {
|
||||
const [d, setD] = useState(v);
|
||||
@@ -167,7 +167,7 @@ export function NamingTemplateEditor({
|
||||
<span>
|
||||
{override && !value.trim()
|
||||
? `留空:沿用${inherited?.[active]?.source ?? "上级"}模板`
|
||||
: "/ 分目录,最后一段是文件名,须以 {{fileExt}} 结尾"}
|
||||
: "用 / 分目录,最后一段是文件名,以 {{fileExt}} 结尾"}
|
||||
</span>
|
||||
<span className="tabular-nums">{value.length} / 1024</span>
|
||||
</div>
|
||||
@@ -317,10 +317,10 @@ function PreviewBody({
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{r.usesBinding ? <Note>这部作品已有目录,目录沿用已建立的路径,模板只决定文件名。</Note> : null}
|
||||
{r.usesBinding ? <Note>这部作品已有目录,沿用原目录,模板只决定文件名。</Note> : null}
|
||||
{r.missing.length ? (
|
||||
<p className="text-meta text-muted-foreground">
|
||||
无值的变量(输出为空):<span className="font-mono">{r.missing.join("、")}</span>
|
||||
没有值的变量:<span className="font-mono">{r.missing.join("、")}</span>
|
||||
</p>
|
||||
) : null}
|
||||
{r.warnings.map((w) => (
|
||||
|
||||
@@ -108,7 +108,7 @@ export function RuleGroupEditor({
|
||||
|
||||
const save = async () => {
|
||||
if (!form.name.trim()) {
|
||||
setNameError("名称必填");
|
||||
setNameError("填写名称");
|
||||
return;
|
||||
}
|
||||
const scope: RuleGroupScope = {
|
||||
@@ -263,7 +263,7 @@ export function RuleGroupEditor({
|
||||
label="作用范围"
|
||||
hint={
|
||||
group && (group.scope.entityIds?.length || group.scope.siteIds?.length || group.scope.subscriptionId)
|
||||
? `另有:${scopeText({ ...group.scope, mediaTypes: undefined, mediaKinds: undefined } as RuleGroupScope)}(此处不改)`
|
||||
? `另有:${scopeText({ ...group.scope, mediaTypes: undefined, mediaKinds: undefined } as RuleGroupScope)}(这里不改)`
|
||||
: "不选 = 全部类型"
|
||||
}
|
||||
className="sm:col-span-2"
|
||||
@@ -277,15 +277,15 @@ export function RuleGroupEditor({
|
||||
</FormField>
|
||||
<div className="flex items-center justify-between gap-3 py-1 sm:col-span-2">
|
||||
<div className="min-w-0">
|
||||
<p className="text-caption font-medium text-foreground">一层都不中时拒绝</p>
|
||||
<p className="text-caption font-medium text-foreground">一层都没命中时拒绝</p>
|
||||
<p className="text-meta text-muted-foreground">
|
||||
{form.ladderRequired ? "资源至少要命中一层" : "只影响排序,不中的资源 pri 为 0"}
|
||||
{form.ladderRequired ? "资源至少要命中一层" : "只影响排序,没命中的资源 pri 为 0"}
|
||||
</p>
|
||||
</div>
|
||||
<Switch
|
||||
checked={form.ladderRequired}
|
||||
onCheckedChange={(v) => set("ladderRequired", v)}
|
||||
aria-label="一层都不中时拒绝"
|
||||
aria-label="一层都没命中时拒绝"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-3 py-1 sm:col-span-2">
|
||||
@@ -379,7 +379,7 @@ const FIELD_LABEL: Record<string, string> = {
|
||||
scope: "作用范围",
|
||||
layers: "阶梯",
|
||||
hardExcludes: "硬排除",
|
||||
ladderRequired: "一层不中拒绝",
|
||||
ladderRequired: "一层都没命中时拒绝",
|
||||
enabled: "启用",
|
||||
label: "名称",
|
||||
rule: "规则",
|
||||
|
||||
@@ -29,7 +29,7 @@ export const SUPPRESS_REASON: Record<string, string> = {
|
||||
disabled: "停用",
|
||||
"status:disabled": "停用",
|
||||
"status:deleted": "删除",
|
||||
edited: "修改语义",
|
||||
edited: "改了条件",
|
||||
};
|
||||
export const suppressReason = (r: string | null) => (r ? (SUPPRESS_REASON[r] ?? r) : "未注明");
|
||||
|
||||
@@ -59,5 +59,5 @@ export function ruleSummary(g: RuleGroup): string {
|
||||
parts.push(`${g.ladderRequired ? "要求" : "偏好"} ${g.layers.map((l) => exprToString(l.expr)).join(" > ")}`);
|
||||
for (const h of g.hardExcludes) parts.push(`排除 ${exprToString(h)}`);
|
||||
if (parts.length) return parts.join(";");
|
||||
return g.legacyKind ? "旧偏好标签,没有可评估的条件" : "没有条件";
|
||||
return g.legacyKind ? "旧版偏好,没有可评估的条件" : "没有条件";
|
||||
}
|
||||
@@ -47,7 +47,7 @@ export function ladderFrom(layers: RuleLayer[]): LadderState {
|
||||
|
||||
/** 保存用:有错误 / 解析中 / 有空层时不可保存 */
|
||||
export function ladderProblem(s: LadderState): string | null {
|
||||
if (s.parsing) return "规则串还在解析";
|
||||
if (s.parsing) return "规则串解析中";
|
||||
if (s.failure) return s.failure;
|
||||
if (s.errors.length) return "规则串有错误";
|
||||
if (s.cards?.some((c) => c.items.length === 0)) return "有空层";
|
||||
@@ -253,7 +253,7 @@ export function RuleStringField({
|
||||
<li key={`${e.code}-${e.position}-${i}`} className="text-meta text-destructive">
|
||||
<ErrorCaret text={state.text} position={e.position} />
|
||||
<span>
|
||||
第 {e.position + 1} 个字符{single ? "" : `(第 ${e.layer + 1} 层)`}:{e.message}
|
||||
第 {e.position + 1} 个字符{single ? "" : `(第 ${e.layer + 1} 层)`}:{e.message}
|
||||
</span>
|
||||
{e.suggestions?.length ? (
|
||||
<span className="ml-1 inline-flex flex-wrap gap-1 align-middle">
|
||||
@@ -338,7 +338,7 @@ function AtomChip({
|
||||
item.neg ? "border-destructive/35 bg-destructive/10 text-destructive" : "border-border bg-foreground/[0.03]",
|
||||
unknown && "border-warning/50",
|
||||
)}
|
||||
title={keyword ? `${keyword.name}:${keyword.description}` : "未知条件"}
|
||||
title={keyword ? `${keyword.name}:${keyword.description}` : "未知条件"}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
|
||||
@@ -150,7 +150,7 @@ function PreviewResult({ result }: { result: RulePreviewResult }) {
|
||||
</details>
|
||||
) : null}
|
||||
<p className="mt-1 text-meta text-muted-foreground sm:hidden">
|
||||
{[...it.excludedBy.map((x) => `排除 ${x}`), ...it.reasons.map(reasonText)].join(";")}
|
||||
{[...it.excludedBy.map((x) => `排除 ${x}`), ...it.reasons.map(reasonText)].join(";")}
|
||||
</p>
|
||||
</td>
|
||||
<td className="px-3 py-2 whitespace-nowrap">
|
||||
@@ -164,7 +164,7 @@ function PreviewResult({ result }: { result: RulePreviewResult }) {
|
||||
)}
|
||||
</td>
|
||||
<td className={cn("hidden px-3 py-2 text-meta text-muted-foreground sm:table-cell")}>
|
||||
{[...it.excludedBy.map((x) => `排除 ${x}`), ...it.reasons.map(reasonText)].join(";") || "—"}
|
||||
{[...it.excludedBy.map((x) => `排除 ${x}`), ...it.reasons.map(reasonText)].join(";") || "—"}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
|
||||
@@ -257,7 +257,7 @@ function atomSummary(a: RuleAtom): string {
|
||||
if (a.minSeeders !== null) p.push(`做种 ≥ ${a.minSeeders}`);
|
||||
if (a.publishDelayMinutes) p.push(`发布 ${a.publishDelayMinutes.min ?? 0}–${a.publishDelayMinutes.max ?? "∞"} 分钟`);
|
||||
if (a.free) p.push("免费");
|
||||
return p.join(";") || "没有条件";
|
||||
return p.join(";") || "没有条件";
|
||||
}
|
||||
|
||||
export function AtomsTab() {
|
||||
@@ -299,7 +299,7 @@ export function AtomsTab() {
|
||||
<Trash2 />
|
||||
</Button>
|
||||
}
|
||||
title={`删除条件 ${a.key}?`}
|
||||
title={`删除条件 ${a.key}?`}
|
||||
description="被规则组引用时不能删除。"
|
||||
confirmLabel="删除"
|
||||
destructive
|
||||
|
||||
Reference in new issue
Block a user