feat(skill-addresses): 将「技能地址管理」并入管理员「技能管理」页的标签页

- SkillAddressesPage 主体抽成可复用的 SkillAddressesPanel(默认导出保留旧路由作直链回退)
- AdminSkillsPage 顶部加 Tabs:技能列表 + 技能地址管理(嵌入 panel)
- 移除 page-sidebar 左下角设置下拉里两处独立的「技能地址管理」入口
- 同步更新前后端 CLAUDE.md 文档

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
吉鑫升andClaude Opus 4.8 committed 2026-06-22 17:35:42 +08:00
1 parent f8228847ab
commit 26557b30a0
5 files changed
+64 -39

No files matched your search

@@ -9,7 +9,6 @@ import {
FolderOpen,
ListTree,
MousePointerClick,
Replace,
Settings,
ShieldAlert,
User,
@@ -223,14 +222,6 @@ function SecondaryNavSidebar() {
按钮管理
</DropdownMenuItem>
)}
{isAdmin && (
<DropdownMenuItem
onClick={() => navigate("/page/strategy/admin/skill-addresses")}
>
<Replace className="size-4" />
技能地址管理
</DropdownMenuItem>
)}
{canManageSensitiveWords() && (
<DropdownMenuItem
onClick={() => navigate("/page/strategy/admin/sensitive-words")}
@@ -517,12 +508,6 @@ function LegacyAccordionSidebar({
按钮管理
</DropdownMenuItem>
)}
{isAdmin && (
<DropdownMenuItem onClick={() => navigate("/page/strategy/admin/skill-addresses")}>
<Replace className="size-4" />
技能地址管理
</DropdownMenuItem>
)}
{canManageSensitiveWords() && (
<DropdownMenuItem onClick={() => navigate("/page/strategy/admin/sensitive-words")}>
<ShieldAlert className="size-4" />
+50 -19
View File
@@ -3,6 +3,7 @@
import {
ChevronLeftIcon,
ChevronRightIcon,
Replace,
SearchIcon,
SparklesIcon,
} from "lucide-react";
@@ -10,6 +11,7 @@ import { useEffect, useMemo, useState } from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import {
WorkspaceBody,
WorkspaceContainer,
@@ -19,6 +21,7 @@ import { SkillRow } from "@/components/workspace/settings/skill-settings-page";
import { getStoredAuth } from "@/core/auth";
import { useAllSkillsAdmin } from "@/core/skills/hooks";
import { desensitize } from "@/lib/desensitize";
import { SkillAddressesPanel } from "./SkillAddressesPage";
const PAGE_SIZE = 10;
@@ -52,27 +55,47 @@ export default function AdminSkillsPage() {
<WorkspaceContainer>
<WorkspaceHeader />
<WorkspaceBody>
<div className="flex size-full min-h-0 flex-col">
<div className="flex items-start justify-between gap-4 border-b px-6 py-4">
<div>
<Tabs
defaultValue="skills"
className="flex size-full min-h-0 flex-col gap-0"
>
<div className="flex items-center justify-between gap-4 border-b px-6 pt-4">
<div className="flex items-center gap-4">
<h1 className="text-xl font-semibold">技能管理</h1>
<p className="text-muted-foreground mt-0.5 text-sm">
管理员视图:查看、编辑、删除所有用户的技能(包括内置技能与未发布的自定义技能)。
</p>
</div>
<div className="relative w-64 shrink-0">
<SearchIcon className="text-muted-foreground absolute left-2.5 top-1/2 size-4 -translate-y-1/2" />
<Input
value={search}
onChange={(e) => setSearch(e.target.value)}
placeholder="按名称搜索"
className="pl-8"
/>
<TabsList>
<TabsTrigger value="skills">
<SparklesIcon />
技能列表
</TabsTrigger>
<TabsTrigger value="addresses">
<Replace />
技能地址管理
</TabsTrigger>
</TabsList>
</div>
</div>
<div className="flex flex-1 flex-col gap-4 overflow-y-auto p-6">
{isLoading && (
<TabsContent
value="skills"
className="mt-0 flex min-h-0 flex-1 flex-col overflow-hidden"
>
<div className="flex items-start justify-between gap-4 border-b px-6 py-4">
<p className="text-muted-foreground text-sm">
管理员视图:查看、编辑、删除所有用户的技能(包括内置技能与未发布的自定义技能)。
</p>
<div className="relative w-64 shrink-0">
<SearchIcon className="text-muted-foreground absolute left-2.5 top-1/2 size-4 -translate-y-1/2" />
<Input
value={search}
onChange={(e) => setSearch(e.target.value)}
placeholder="按名称搜索"
className="pl-8"
/>
</div>
</div>
<div className="flex flex-1 flex-col gap-4 overflow-y-auto p-6">
{isLoading && (
<div className="text-muted-foreground flex h-40 items-center justify-center text-sm">
加载中…
</div>
@@ -132,8 +155,16 @@ export default function AdminSkillsPage() {
</Button>
</div>
)}
</div>
</div>
</div>
</TabsContent>
<TabsContent
value="addresses"
className="mt-0 min-h-0 flex-1 overflow-hidden"
>
<SkillAddressesPanel />
</TabsContent>
</Tabs>
</WorkspaceBody>
</WorkspaceContainer>
);
@@ -72,7 +72,7 @@ function KindBadge({ kind }: { kind: AddressKind }) {
);
}
export default function SkillAddressesPage() {
export function SkillAddressesPanel() {
const isAdmin = getStoredAuth()?.system_role === "admin";
const [kinds, setKinds] = useState<AddressKind[]>(ALL_KINDS);
@@ -462,6 +462,10 @@ export default function SkillAddressesPage() {
);
}
export default function SkillAddressesPage() {
return <SkillAddressesPanel />;
}
function GroupRow({
group,
value,