docs(plan): v0.2 adds Pi subagents and scheduled-jobs board
Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
1 parent
b839ed4056
commit
16ab2a6c84
97 files changed
+592
-648
No files matched your search
@@ -42,21 +42,21 @@ const SetupForm = AdminSetupRequest.extend({ confirm: z.string() }).refine((v) =
|
||||
|
||||
/** 后端错误码 → 文案(不直接透传后端 message,setup token 类除外) */
|
||||
function errorText(err: unknown, mode: Mode): string {
|
||||
if (!(err instanceof ApiRequestError)) return "发生未知错误,请重试";
|
||||
if (!(err instanceof ApiRequestError)) return "请求失败,稍后重试";
|
||||
switch (err.code) {
|
||||
case "rate_limited":
|
||||
return "失败次数过多,请 15 分钟后再试";
|
||||
return "失败次数过多,15 分钟后再试";
|
||||
case "upstream_unavailable":
|
||||
return "无法连接服务,请检查服务端是否在运行";
|
||||
return "连不上服务端,确认它在运行";
|
||||
case "unauthorized":
|
||||
if (mode === "totp") return "验证码错误或已使用,请等待下一个验证码";
|
||||
if (mode === "setup") return "初始化口令无效,请以服务端日志里最新打印的为准";
|
||||
if (mode === "totp") return "验证码错误或已用过,等下一个验证码再试";
|
||||
if (mode === "setup") return "初始化口令无效,用服务端日志里最新的一条";
|
||||
return "用户名或密码错误";
|
||||
case "validation_failed":
|
||||
case "bad_request":
|
||||
return "输入格式不正确";
|
||||
case "conflict":
|
||||
return "管理员已初始化,请直接登录";
|
||||
return "管理员已初始化,直接登录";
|
||||
default:
|
||||
return err.message || "登录失败";
|
||||
}
|
||||
@@ -130,7 +130,7 @@ export default function LoginPage() {
|
||||
const fe: Record<string, string> = {};
|
||||
for (const i of parsed.error.issues) fe[String(i.path[0])] ??= i.message;
|
||||
if (fe.setupToken) fe.setupToken = "初始化口令至少 16 个字符";
|
||||
if (fe.username && !username.trim()) fe.username = "请输入用户名";
|
||||
if (fe.username && !username.trim()) fe.username = "输入用户名";
|
||||
setFieldErrors(fe);
|
||||
return;
|
||||
}
|
||||
@@ -152,8 +152,8 @@ export default function LoginPage() {
|
||||
if (!parsed.success) {
|
||||
const fe: Record<string, string> = {};
|
||||
for (const i of parsed.error.issues) fe[String(i.path[0])] ??= i.message;
|
||||
if (fe.username) fe.username = "请输入用户名";
|
||||
if (fe.password) fe.password = "请输入密码";
|
||||
if (fe.username) fe.username = "输入用户名";
|
||||
if (fe.password) fe.password = "输入密码";
|
||||
setFieldErrors(fe);
|
||||
return;
|
||||
}
|
||||
@@ -169,7 +169,7 @@ export default function LoginPage() {
|
||||
} catch (err) {
|
||||
if (err instanceof ApiRequestError && err.code === "precondition_failed") {
|
||||
setMode("setup");
|
||||
setError("管理员尚未初始化,请先完成初始化");
|
||||
setError("管理员尚未初始化");
|
||||
} else {
|
||||
setError(errorText(err, mode));
|
||||
}
|
||||
@@ -210,10 +210,10 @@ export default function LoginPage() {
|
||||
<section className="hidden lg:block">
|
||||
<p className="text-label font-semibold tracking-[0.18em] text-muted-foreground uppercase">媒体自动化</p>
|
||||
<h1 className="mt-3 max-w-xl font-display text-display-sm leading-tight font-semibold text-foreground">
|
||||
把想看的片子交代一句,剩下的交给流水线。
|
||||
订阅、下载、整理入库
|
||||
</h1>
|
||||
<p className="mt-4 max-w-lg text-lead text-muted-foreground">
|
||||
订阅、选片、下载、核验、入库,每一步都有记录可查;拿不准的事项会停下来等你决定。
|
||||
每一步都有记录。拿不准的事项进待处理,等你决定。
|
||||
</p>
|
||||
<ul className="mt-8 space-y-3 text-body text-muted-foreground">
|
||||
<li className="flex items-center gap-2.5">
|
||||
@@ -222,7 +222,7 @@ export default function LoginPage() {
|
||||
</li>
|
||||
<li className="flex items-center gap-2.5">
|
||||
<LockKeyhole className="h-4 w-4 text-foreground/70" />
|
||||
凭证加密存储,任何页面都不回显
|
||||
凭证加密存储,页面不回显
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
@@ -235,7 +235,7 @@ export default function LoginPage() {
|
||||
<div className="mt-4 flex gap-2.5 rounded-lg border border-border bg-foreground/[0.03] p-3 text-meta text-muted-foreground">
|
||||
<Terminal className="mt-0.5 h-4 w-4 shrink-0" />
|
||||
<p>
|
||||
初始化口令只在服务端首次启动时打印到日志一次,可用
|
||||
初始化口令在服务端日志里,用
|
||||
<code className="mx-1 rounded-tight bg-foreground/[0.06] px-1 font-mono">
|
||||
docker compose logs app | grep 'setup token'
|
||||
</code>
|
||||
|
||||
Reference in new issue
Block a user