diff --git a/frontend-web/src/roundtable-planning/api/chains.ts b/frontend-web/src/roundtable-planning/api/chains.ts index 6138efef..b57bf26d 100644 --- a/frontend-web/src/roundtable-planning/api/chains.ts +++ b/frontend-web/src/roundtable-planning/api/chains.ts @@ -54,8 +54,13 @@ export interface ChainUpdatePayload { isPublic?: boolean; } -/** 列表筛选范围:`mine` = 我的;`public` = 所有已发布的公共链条。 */ -export type ChainScope = "mine" | "public"; +/** + * 列表筛选范围: + * - `mine` = 我的; + * - `public` = 所有已发布的公共链条; + * - `all` = 所有账号的全部链条(**仅管理员**;后端对非管理员请求 `all` 退化为 `mine`)。 + */ +export type ChainScope = "mine" | "public" | "all"; const BASE = () => `${getBackendBaseURL()}/api/roundtable-chains`; @@ -146,7 +151,7 @@ function fromUpdate(p: ChainUpdatePayload) { * - `"public"`:所有已发布的公共链条(任何账号可见 / 可选入研讨)。 */ export async function listChains(scope: ChainScope = "mine"): Promise { - const url = scope === "public" ? `${BASE()}?scope=public` : BASE(); + const url = scope === "mine" ? BASE() : `${BASE()}?scope=${scope}`; const res = await apiFetch(url, { method: "GET" }); const data = await readJson<{ chains: ServerChain[] }>(res, "list chains"); return (data.chains ?? []).map(toChain); diff --git a/frontend-web/src/roundtable-planning/components/BusinessChainListDialog.tsx b/frontend-web/src/roundtable-planning/components/BusinessChainListDialog.tsx index 1b813bda..04353b30 100644 --- a/frontend-web/src/roundtable-planning/components/BusinessChainListDialog.tsx +++ b/frontend-web/src/roundtable-planning/components/BusinessChainListDialog.tsx @@ -31,6 +31,7 @@ import { import { cn } from "@/lib/utils"; import { useDesensitizeSubtree } from "@/roundtable-planning/lib/use-desensitize-subtree"; +import { getStoredAuth } from "@/core/auth"; import { listAgents } from "@/core/agents"; import { listChains, setChainPublic, type ChainScope } from "../api/chains"; @@ -71,7 +72,9 @@ export function BusinessChainListBody({ const [chains, setChains] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); - // 筛选:我的 / 公共(已发布)。 + // 管理员:额外多一个「全部」筛选,且可编辑 / 发布任意账号的链条。 + const isAdmin = getStoredAuth()?.system_role === "admin"; + // 筛选:我的 / 公共(已发布)/(管理员)全部。 const [scope, setScope] = useState("mine"); const [publishingId, setPublishingId] = useState(null); // 实时名称表(id 小写 → 最新 name):用于把席位的落库快照名刷新成最新(agent 改名同步)。 @@ -147,9 +150,9 @@ export function BusinessChainListBody({ return ( <> - {/* 筛选:我的 / 公共 */} + {/* 筛选:我的 / 公共 /(管理员)全部 */}
- {(["mine", "public"] as const).map((s) => ( + {((isAdmin ? ["mine", "public", "all"] : ["mine", "public"]) as ChainScope[]).map((s) => ( ))}
@@ -195,6 +198,7 @@ export function BusinessChainListBody({ onConfigure(chain.id)} @@ -245,18 +249,20 @@ export function BusinessChainListDialog({ function ChainRow({ chain, + canManage, nameById, publishing, onSettings, onTogglePublic, }: { chain: BusinessChain; + /** 能否编辑 / 发布(本人链条 或 管理员)。 */ + canManage: boolean; nameById: Map; publishing: boolean; onSettings: () => void; onTogglePublic: () => void; }) { - const isMine = chain.isMine !== false; // 配置者用户名:后端返回 email,展示时取 @ 前的本地部分更像「用户名」。 const ownerName = chain.ownerName ? chain.ownerName.split("@")[0] : ""; return ( @@ -274,8 +280,8 @@ function ChainRow({ )}
- {/* 发布 / 取消发布:仅本人的链条可操作。 */} - {isMine && ( + {/* 发布 / 取消发布:本人的链条或管理员可操作。 */} + {canManage && (
- {/* 操作按钮:仅本人链条可发布 / 设置 / 删除(公共里别人的链条只读浏览)。 */} - {isMine && ( + {/* 操作按钮:本人链条或管理员可发布 / 设置 / 删除(普通用户看别人的链条只读浏览)。 */} + {canManage && (