暂无结果报告
+这次会商还没有生成第三步「结果绘制」的方案报告。
+加载中…
+ ) : ( + drafts.slice(0, 10).map((draft) => ( +`.
+ return `${window.location.origin}${window.location.pathname}#/roundtable-share/${shareCode}`;
+}
diff --git a/frontend-web/src/core/roundtable-draft-shares/hooks.ts b/frontend-web/src/core/roundtable-draft-shares/hooks.ts
new file mode 100644
index 00000000..98a10f5f
--- /dev/null
+++ b/frontend-web/src/core/roundtable-draft-shares/hooks.ts
@@ -0,0 +1,61 @@
+import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
+
+import {
+ createDraftShare,
+ importDraftShare,
+ listDraftShares,
+ previewDraftShare,
+ revokeDraftShare,
+ type DraftShareMode,
+} from "./api";
+
+export function useDraftShares(enabled = true) {
+ return useQuery({
+ queryKey: ["roundtable-draft-shares"],
+ queryFn: listDraftShares,
+ enabled,
+ });
+}
+
+export function useCreateDraftShare() {
+ const queryClient = useQueryClient();
+ return useMutation({
+ mutationFn: ({
+ draftId,
+ mode = "import",
+ }: {
+ draftId: string;
+ mode?: DraftShareMode;
+ }) => createDraftShare(draftId, mode),
+ onSuccess: () => {
+ void queryClient.invalidateQueries({ queryKey: ["roundtable-draft-shares"] });
+ },
+ });
+}
+
+export function useRevokeDraftShare() {
+ const queryClient = useQueryClient();
+ return useMutation({
+ mutationFn: (shareCode: string) => revokeDraftShare(shareCode),
+ onSuccess: () => {
+ void queryClient.invalidateQueries({ queryKey: ["roundtable-draft-shares"] });
+ },
+ });
+}
+
+export function usePreviewDraftShare() {
+ return useMutation({
+ mutationFn: (shareCode: string) => previewDraftShare(shareCode),
+ });
+}
+
+export function useImportDraftShare() {
+ const queryClient = useQueryClient();
+ return useMutation({
+ mutationFn: (shareCode: string) => importDraftShare(shareCode),
+ onSuccess: () => {
+ // Imported drafts show up in the user's roundtable history sidebar.
+ void queryClient.invalidateQueries({ queryKey: ["roundtable-drafts"] });
+ },
+ });
+}
diff --git a/frontend-web/src/pages/PublicRoundtableSharePage.tsx b/frontend-web/src/pages/PublicRoundtableSharePage.tsx
new file mode 100644
index 00000000..42c1392e
--- /dev/null
+++ b/frontend-web/src/pages/PublicRoundtableSharePage.tsx
@@ -0,0 +1,83 @@
+"use client";
+
+import { useQuery } from "@tanstack/react-query";
+import { Loader2 } from "lucide-react";
+import { useParams } from "react-router-dom";
+
+import { getPublicDraftShareSnapshot } from "@/core/roundtable-draft-shares/api";
+
+/**
+ * Public, read-only roundtable-result viewer.
+ *
+ * Reachable at `#/roundtable-share/` with NO authentication — anyone with
+ * the link can open it. It renders the Step 3「结果绘制」report (a self-contained
+ * HTML document) inside a sandboxed iframe with no `allow-scripts`, mirroring the
+ * scheduled-task HTML-page preview, so a shared report can never execute code in
+ * the app origin.
+ */
+export default function PublicRoundtableSharePage() {
+ const { shareCode } = useParams<{ shareCode: string }>();
+
+ const { data, isLoading, isError } = useQuery({
+ queryKey: ["public-roundtable-share", shareCode],
+ queryFn: () => getPublicDraftShareSnapshot(shareCode!),
+ enabled: !!shareCode,
+ retry: false,
+ refetchOnWindowFocus: false,
+ });
+
+ if (isLoading) {
+ return (
+
+
+ 正在加载分享内容…
+
+ );
+ }
+
+ if (isError || !data) {
+ return (
+
+ 分享不可用
+
+ 该分享链接不存在、已被撤销,或不是只读分享。
+
+
+ );
+ }
+
+ return (
+
+
+
+
+ {data.title || "未命名会商"}
+
+
+ 只读分享
+
+
+
+ 这是一份多智能体会商的结果报告快照(只读),你可以查看全部内容,但无法继续研讨。
+
+
+
+ {data.has_report ? (
+
+ ) : (
+
+ 暂无结果报告
+ 这次会商还没有生成第三步「结果绘制」的方案报告。
+
+ )}
+
+
+ );
+}
diff --git a/frontend-web/src/roundtable-planning/components/HighFidelityReport.tsx b/frontend-web/src/roundtable-planning/components/HighFidelityReport.tsx
index e2aa9978..7b0b81c4 100644
--- a/frontend-web/src/roundtable-planning/components/HighFidelityReport.tsx
+++ b/frontend-web/src/roundtable-planning/components/HighFidelityReport.tsx
@@ -9,7 +9,6 @@ import {
Eye,
FileText,
Loader2,
- Printer,
RefreshCw,
Sparkles,
} from "lucide-react";
@@ -335,16 +334,6 @@ export const HighFidelityReport: React.FC = ({
结果绘制
-