fix(web): 技能页 bg-paper/删除虚构创作中徽标/设置页 try-finally/文风页移动端定高 grid
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { BookOpen, ChevronRight, Clock3, Sparkles } from "lucide-react";
|
import { BookOpen, ChevronRight, Clock3 } from "lucide-react";
|
||||||
|
|
||||||
import { Badge } from "@/components/ui/Badge";
|
import { Badge } from "@/components/ui/Badge";
|
||||||
import type { ProjectResponse } from "@/lib/api/types";
|
import type { ProjectResponse } from "@/lib/api/types";
|
||||||
@@ -67,12 +67,8 @@ export function ProjectCard({ project, compact = false }: ProjectCardProps) {
|
|||||||
</h2>
|
</h2>
|
||||||
<div className="mt-2 flex flex-wrap gap-2">
|
<div className="mt-2 flex flex-wrap gap-2">
|
||||||
{project.genre ? <Badge>{project.genre}</Badge> : null}
|
{project.genre ? <Badge>{project.genre}</Badge> : null}
|
||||||
<Badge variant="accent">
|
|
||||||
<Sparkles className="h-3 w-3" aria-hidden="true" />
|
|
||||||
创作中
|
|
||||||
</Badge>
|
|
||||||
{pendingCount > 0 ? (
|
{pendingCount > 0 ? (
|
||||||
<Badge variant="warning">{pendingCount} 待审稿</Badge>
|
<Badge variant="warning">{pendingCount} 待审</Badge>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import { Select } from "@/components/ui/Select";
|
|||||||
import { StatusNote } from "@/components/ui/StatusNote";
|
import { StatusNote } from "@/components/ui/StatusNote";
|
||||||
import { TextInput } from "@/components/ui/TextInput";
|
import { TextInput } from "@/components/ui/TextInput";
|
||||||
import { api } from "@/lib/api/client";
|
import { api } from "@/lib/api/client";
|
||||||
|
import { cardClass } from "@/lib/ui/variants";
|
||||||
import {
|
import {
|
||||||
API_KEY_PROVIDERS,
|
API_KEY_PROVIDERS,
|
||||||
KNOWN_PROVIDERS,
|
KNOWN_PROVIDERS,
|
||||||
@@ -91,10 +92,10 @@ export function ProvidersSettings({
|
|||||||
|
|
||||||
const saveRouting = async (): Promise<void> => {
|
const saveRouting = async (): Promise<void> => {
|
||||||
setSavingRouting(true);
|
setSavingRouting(true);
|
||||||
|
try {
|
||||||
const { data, error } = await api.PUT("/settings/providers", {
|
const { data, error } = await api.PUT("/settings/providers", {
|
||||||
body: { tier_routing: draftsToRoutingInput(routing) },
|
body: { tier_routing: draftsToRoutingInput(routing) },
|
||||||
});
|
});
|
||||||
setSavingRouting(false);
|
|
||||||
if (error || !data) {
|
if (error || !data) {
|
||||||
toast("保存档位路由失败,请重试", "error");
|
toast("保存档位路由失败,请重试", "error");
|
||||||
return;
|
return;
|
||||||
@@ -102,6 +103,11 @@ export function ProvidersSettings({
|
|||||||
setProviders(data.providers ?? []);
|
setProviders(data.providers ?? []);
|
||||||
setRouting(toRoutingDrafts(data.tier_routing ?? []));
|
setRouting(toRoutingDrafts(data.tier_routing ?? []));
|
||||||
toast("档位路由已保存", "success");
|
toast("档位路由已保存", "success");
|
||||||
|
} catch {
|
||||||
|
toast("保存档位路由失败,请检查后端连接", "error");
|
||||||
|
} finally {
|
||||||
|
setSavingRouting(false);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const saveCredential = async (providerId: string): Promise<void> => {
|
const saveCredential = async (providerId: string): Promise<void> => {
|
||||||
@@ -111,10 +117,10 @@ export function ProvidersSettings({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setSavingId(providerId);
|
setSavingId(providerId);
|
||||||
|
try {
|
||||||
const { data, error } = await api.PUT("/settings/providers", {
|
const { data, error } = await api.PUT("/settings/providers", {
|
||||||
body: { credentials: [{ provider: providerId, api_key: apiKey }] },
|
body: { credentials: [{ provider: providerId, api_key: apiKey }] },
|
||||||
});
|
});
|
||||||
setSavingId(null);
|
|
||||||
if (error || !data) {
|
if (error || !data) {
|
||||||
toast("保存凭据失败,请重试", "error");
|
toast("保存凭据失败,请重试", "error");
|
||||||
return;
|
return;
|
||||||
@@ -122,14 +128,19 @@ export function ProvidersSettings({
|
|||||||
setProviders(data.providers ?? []);
|
setProviders(data.providers ?? []);
|
||||||
setDrafts((prev) => ({ ...prev, [providerId]: "" }));
|
setDrafts((prev) => ({ ...prev, [providerId]: "" }));
|
||||||
toast("凭据已保存", "success");
|
toast("凭据已保存", "success");
|
||||||
|
} catch {
|
||||||
|
toast("保存凭据失败,请检查后端连接", "error");
|
||||||
|
} finally {
|
||||||
|
setSavingId(null);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const testConnection = async (providerId: string): Promise<void> => {
|
const testConnection = async (providerId: string): Promise<void> => {
|
||||||
setTestingId(providerId);
|
setTestingId(providerId);
|
||||||
|
try {
|
||||||
const { data, error } = await api.POST("/settings/providers/test", {
|
const { data, error } = await api.POST("/settings/providers/test", {
|
||||||
body: { provider: providerId },
|
body: { provider: providerId },
|
||||||
});
|
});
|
||||||
setTestingId(null);
|
|
||||||
if (error || !data) {
|
if (error || !data) {
|
||||||
toast("测试连接失败", "error");
|
toast("测试连接失败", "error");
|
||||||
return;
|
return;
|
||||||
@@ -138,16 +149,21 @@ export function ProvidersSettings({
|
|||||||
...prev,
|
...prev,
|
||||||
[providerId]: { ok: data.ok, capabilities: data.capabilities },
|
[providerId]: { ok: data.ok, capabilities: data.capabilities },
|
||||||
}));
|
}));
|
||||||
toast(data.ok ? "连接成功" : "连接未通过", data.ok ? "success" : "error");
|
toast(
|
||||||
|
data.ok ? "连接成功" : "连接未通过",
|
||||||
|
data.ok ? "success" : "error",
|
||||||
|
);
|
||||||
|
} catch {
|
||||||
|
toast("测试连接失败,请检查后端连接", "error");
|
||||||
|
} finally {
|
||||||
|
setTestingId(null);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="grid gap-6 lg:grid-cols-[12rem_1fr]">
|
<div className="grid gap-6 lg:grid-cols-[12rem_1fr]">
|
||||||
<aside className="hidden lg:block">
|
<aside className="hidden lg:block">
|
||||||
<nav
|
<nav aria-label="设置分组" className={cardClass("sticky top-4 p-2")}>
|
||||||
aria-label="设置分组"
|
|
||||||
className="sticky top-4 rounded border border-line bg-panel p-2"
|
|
||||||
>
|
|
||||||
<SettingsNavButton
|
<SettingsNavButton
|
||||||
active={activeSection === "routing"}
|
active={activeSection === "routing"}
|
||||||
icon={<Route className="h-4 w-4" aria-hidden="true" />}
|
icon={<Route className="h-4 w-4" aria-hidden="true" />}
|
||||||
|
|||||||
@@ -46,19 +46,19 @@ export function SkillsPage({ project, skills }: SkillsPageProps) {
|
|||||||
description="按来源、档位和表权限汇总当前可用技能。"
|
description="按来源、档位和表权限汇总当前可用技能。"
|
||||||
/>
|
/>
|
||||||
<dl className="mt-4 grid grid-cols-3 gap-2 text-center">
|
<dl className="mt-4 grid grid-cols-3 gap-2 text-center">
|
||||||
<div className="rounded border border-line bg-paper p-3">
|
<div className="rounded border border-line bg-bg p-3">
|
||||||
<dt className="text-xs text-ink-soft">总数</dt>
|
<dt className="text-xs text-ink-soft">总数</dt>
|
||||||
<dd className="mt-1 font-serif text-2xl text-ink">
|
<dd className="mt-1 font-serif text-2xl text-ink">
|
||||||
{summary.total}
|
{summary.total}
|
||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
<div className="rounded border border-line bg-paper p-3">
|
<div className="rounded border border-line bg-bg p-3">
|
||||||
<dt className="text-xs text-ink-soft">可写</dt>
|
<dt className="text-xs text-ink-soft">可写</dt>
|
||||||
<dd className="mt-1 font-serif text-2xl text-ink">
|
<dd className="mt-1 font-serif text-2xl text-ink">
|
||||||
{summary.writableCount}
|
{summary.writableCount}
|
||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
<div className="rounded border border-line bg-paper p-3">
|
<div className="rounded border border-line bg-bg p-3">
|
||||||
<dt className="text-xs text-ink-soft">只读</dt>
|
<dt className="text-xs text-ink-soft">只读</dt>
|
||||||
<dd className="mt-1 font-serif text-2xl text-ink">
|
<dd className="mt-1 font-serif text-2xl text-ink">
|
||||||
{summary.readonlyCount}
|
{summary.readonlyCount}
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ export function StylePage({ project, initialFingerprint }: StylePageProps) {
|
|||||||
projectId={project.id}
|
projectId={project.id}
|
||||||
activeNav="style"
|
activeNav="style"
|
||||||
>
|
>
|
||||||
<div className="grid h-[calc(100vh-var(--chrome,4rem))] grid-cols-1 lg:grid-cols-[28rem_1fr]">
|
<div className="flex min-h-[calc(100vh-var(--chrome,4rem))] flex-col lg:grid lg:h-[calc(100vh-var(--chrome,4rem))] lg:min-h-0 lg:grid-cols-[28rem_1fr]">
|
||||||
<section className="flex flex-col overflow-auto border-r border-line bg-panel px-6 py-6">
|
<section className="flex flex-col border-line bg-panel px-6 py-6 lg:overflow-auto lg:border-r">
|
||||||
<h1 className="mb-3 font-serif text-lg text-ink">学习文风</h1>
|
<h1 className="mb-3 font-serif text-lg text-ink">学习文风</h1>
|
||||||
<StyleUpload
|
<StyleUpload
|
||||||
busy={learn.busy}
|
busy={learn.busy}
|
||||||
@@ -39,7 +39,7 @@ export function StylePage({ project, initialFingerprint }: StylePageProps) {
|
|||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="overflow-auto bg-bg px-6 py-6">
|
<section className="bg-bg px-6 py-6 lg:overflow-auto">
|
||||||
<FingerprintView fingerprint={learn.fingerprint} />
|
<FingerprintView fingerprint={learn.fingerprint} />
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user