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