feat(roundtable): 深链接第一步任务/行动展示 + xdfx 行动详情接入会商
- Step1 深链接(taskId)下:左栏顶部「业务链选择」隐藏,改显当前任务(rwfx/3qfx:任务名称+描述) 或当前行动(xdfx:行动名称+叙事);顶栏「业务链条」入口隐藏;「新建任务」改「重新分析」 (复位 autoStarted + resetToStep1,对同一任务重做意图分析) - xdfx 行动详情接入会商:fetchActionDetail 取到即 persistActionDetail 缓存;新增 readActionDetail/persistActionDetail + ACTION_DETAIL_STORAGE_KEY;resolveTaskDeeplinkTarget 会商分支为 xdfx 把 actionId/actionName 带入 roundtablePrefill - xdfx 首条交给任务理解的消息 = 任务名称 + 任务描述 + 行动名称 - 「原任务已有结果」(目的树预览 headerLeftSlot) 仅 rwfx-A(6BF) 显示 注:行动详情 mock(actionName/narration) 在 config.yaml(按惯例不提交,单独管理)。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
b1b1ff98f5
commit
b513a0d56c
2 files changed
+160
-15
No files matched your search
@@ -35,6 +35,9 @@ export interface CopTaskDetail {
|
|||||||
/** 任务详情整包暂存的 sessionStorage key(目标页/后续可读取)。 */
|
/** 任务详情整包暂存的 sessionStorage key(目标页/后续可读取)。 */
|
||||||
export const COP_TASK_DETAIL_STORAGE_KEY = "login.copTaskDetail";
|
export const COP_TASK_DETAIL_STORAGE_KEY = "login.copTaskDetail";
|
||||||
|
|
||||||
|
/** 行动详情整包暂存的 sessionStorage key(xdfx 行动分析:会商/单智能体读取行动名称/叙事)。 */
|
||||||
|
export const ACTION_DETAIL_STORAGE_KEY = "login.actionDetail";
|
||||||
|
|
||||||
/** goPath 基础码 → 业务码(配置管理 businessCode)。 */
|
/** goPath 基础码 → 业务码(配置管理 businessCode)。 */
|
||||||
const GOPATH_BUSINESS_CODE: Record<string, string> = {
|
const GOPATH_BUSINESS_CODE: Record<string, string> = {
|
||||||
"3qfx": "3Q", // 三情分析
|
"3qfx": "3Q", // 三情分析
|
||||||
@@ -111,6 +114,25 @@ export function readCopTaskDetail(): CopTaskDetail | null {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 把行动详情整包暂存到 sessionStorage(xdfx 行动分析用;隐私模式/quota 异常时静默失败)。 */
|
||||||
|
export function persistActionDetail(detail: ActionDetail): void {
|
||||||
|
try {
|
||||||
|
sessionStorage.setItem(ACTION_DETAIL_STORAGE_KEY, JSON.stringify(detail));
|
||||||
|
} catch {
|
||||||
|
/* noop */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 读取暂存的行动详情(会商左上角「当前行动」、单智能体行动详情卡都可读)。 */
|
||||||
|
export function readActionDetail(): ActionDetail | null {
|
||||||
|
try {
|
||||||
|
const raw = sessionStorage.getItem(ACTION_DETAIL_STORAGE_KEY);
|
||||||
|
return raw ? (JSON.parse(raw) as ActionDetail) : null;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** 行动详情接口 ``{action_detail_url}/{actionId}`` 返回的 ``data`` 字段(xdfx 行动分析用)。 */
|
/** 行动详情接口 ``{action_detail_url}/{actionId}`` 返回的 ``data`` 字段(xdfx 行动分析用)。 */
|
||||||
export interface ActionDetail {
|
export interface ActionDetail {
|
||||||
/** 行动id(深链 ?taskId= 传入的就是它)。 */
|
/** 行动id(深链 ?taskId= 传入的就是它)。 */
|
||||||
@@ -148,7 +170,7 @@ export async function fetchActionDetail(actionId: string): Promise<ActionDetail
|
|||||||
const data = body && typeof body === "object" ? (body as { data?: unknown }).data : null;
|
const data = body && typeof body === "object" ? (body as { data?: unknown }).data : null;
|
||||||
if (!data || typeof data !== "object") return null;
|
if (!data || typeof data !== "object") return null;
|
||||||
const d = data as Record<string, unknown>;
|
const d = data as Record<string, unknown>;
|
||||||
return {
|
const detail: ActionDetail = {
|
||||||
id: d.id != null ? String(d.id) : "",
|
id: d.id != null ? String(d.id) : "",
|
||||||
taskId: d.taskId != null ? String(d.taskId) : "",
|
taskId: d.taskId != null ? String(d.taskId) : "",
|
||||||
purposeId: d.purposeId != null ? String(d.purposeId) : "",
|
purposeId: d.purposeId != null ? String(d.purposeId) : "",
|
||||||
@@ -157,6 +179,10 @@ export async function fetchActionDetail(actionId: string): Promise<ActionDetail
|
|||||||
typeof d.actionStatus === "number" || typeof d.actionStatus === "string" ? d.actionStatus : "",
|
typeof d.actionStatus === "number" || typeof d.actionStatus === "string" ? d.actionStatus : "",
|
||||||
narration: typeof d.narration === "string" ? d.narration : "",
|
narration: typeof d.narration === "string" ? d.narration : "",
|
||||||
};
|
};
|
||||||
|
// 取到即整包暂存:登录解析任务id 时(resolveDeeplinkTaskId→fetchTaskIdFromAction)就会缓存它,
|
||||||
|
// 之后会商左上角「当前行动」、单智能体行动详情卡都能直接 readActionDetail(),避免重复请求。
|
||||||
|
persistActionDetail(detail);
|
||||||
|
return detail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -228,6 +254,15 @@ export async function resolveTaskDeeplinkTarget(
|
|||||||
if (parsed.roundtable) {
|
if (parsed.roundtable) {
|
||||||
// 多智能体会商:嵌进对应业务的「任务管理」布局;businessCode 让会商页自动选用配置的业务链条;
|
// 多智能体会商:嵌进对应业务的「任务管理」布局;businessCode 让会商页自动选用配置的业务链条;
|
||||||
// taskId 让会商页按任务隔离存取草稿(一个 taskId 多条记录),并触发第三步自动结构化输出。
|
// taskId 让会商页按任务隔离存取草稿(一个 taskId 多条记录),并触发第三步自动结构化输出。
|
||||||
|
// xdfx(行动分析):根是「行动」——把行动名称随首条消息交给任务理解,左上角展示「当前行动」。
|
||||||
|
// 行动详情登录解析任务id 时已缓存(fetchActionDetail 内 persistActionDetail);这里优先读缓存。
|
||||||
|
let actionName = "";
|
||||||
|
let actionId = "";
|
||||||
|
if (parsed.businessCode === XDFX_BUSINESS_CODE && rawId) {
|
||||||
|
actionId = rawId;
|
||||||
|
const ad = readActionDetail() ?? (await fetchActionDetail(rawId));
|
||||||
|
actionName = ad?.actionName ?? "";
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
path: `${taskBase}/roundtable`,
|
path: `${taskBase}/roundtable`,
|
||||||
state: {
|
state: {
|
||||||
@@ -236,6 +271,8 @@ export async function resolveTaskDeeplinkTarget(
|
|||||||
taskGoal: detail.taskContent,
|
taskGoal: detail.taskContent,
|
||||||
businessCode: parsed.businessCode,
|
businessCode: parsed.businessCode,
|
||||||
taskId: taskId || undefined,
|
taskId: taskId || undefined,
|
||||||
|
...(actionId ? { actionId } : {}),
|
||||||
|
...(actionName ? { actionName } : {}),
|
||||||
autoStart: true,
|
autoStart: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ import {
|
|||||||
Loader2,
|
Loader2,
|
||||||
Pencil,
|
Pencil,
|
||||||
Plus,
|
Plus,
|
||||||
|
RotateCw,
|
||||||
Save,
|
Save,
|
||||||
Settings,
|
Settings,
|
||||||
Sparkles,
|
Sparkles,
|
||||||
@@ -80,6 +81,7 @@ import { RecommendAgentsDialog } from "@/roundtable-planning/components/Recommen
|
|||||||
import { BusinessChainListDialog } from "@/roundtable-planning/components/BusinessChainListDialog";
|
import { BusinessChainListDialog } from "@/roundtable-planning/components/BusinessChainListDialog";
|
||||||
import { DispatchChainJobModal } from "@/roundtable-planning/components/DispatchChainJobModal";
|
import { DispatchChainJobModal } from "@/roundtable-planning/components/DispatchChainJobModal";
|
||||||
import { Step1Panel } from "@/roundtable-planning/components/Step1Panel";
|
import { Step1Panel } from "@/roundtable-planning/components/Step1Panel";
|
||||||
|
import { readActionDetail, readCopTaskDetail } from "@/core/auth/task-deeplink";
|
||||||
import { Step2Panel } from "@/roundtable-planning/components/Step2Panel";
|
import { Step2Panel } from "@/roundtable-planning/components/Step2Panel";
|
||||||
import { Step3Panel } from "@/roundtable-planning/components/Step3Panel";
|
import { Step3Panel } from "@/roundtable-planning/components/Step3Panel";
|
||||||
import type {
|
import type {
|
||||||
@@ -159,6 +161,10 @@ interface RoundtablePrefill {
|
|||||||
businessCode?: string;
|
businessCode?: string;
|
||||||
/** 外部任务 id(无界抽屉):聊天记录按此存取、打开时回显最新一条。 */
|
/** 外部任务 id(无界抽屉):聊天记录按此存取、打开时回显最新一条。 */
|
||||||
taskId?: string;
|
taskId?: string;
|
||||||
|
/** xdfx 深链:原始行动 id(URL ?taskId= 传入的就是它)。供会商取行动详情用。 */
|
||||||
|
actionId?: string;
|
||||||
|
/** xdfx 深链:行动名称(注入 Step 1 首条用户消息——任务名称+任务描述+行动名称)。 */
|
||||||
|
actionName?: string;
|
||||||
/** 是否进入即自动开跑 Step 1 意图分析。 */
|
/** 是否进入即自动开跑 Step 1 意图分析。 */
|
||||||
autoStart?: boolean;
|
autoStart?: boolean;
|
||||||
}
|
}
|
||||||
@@ -1083,7 +1089,13 @@ export default function RoundtablePlanningPage() {
|
|||||||
if (!step1.intentThreadId || step1.intentReady) return;
|
if (!step1.intentThreadId || step1.intentReady) return;
|
||||||
const title = prefill.taskTitle?.trim();
|
const title = prefill.taskTitle?.trim();
|
||||||
const goal = prefill.taskGoal?.trim();
|
const goal = prefill.taskGoal?.trim();
|
||||||
const text = [title ? `任务名称:${title}` : "", goal ? `任务描述:${goal}` : ""]
|
// xdfx(行动分析):除任务名称/描述外,再带上「行动名称」一起交给任务理解智能体。
|
||||||
|
const actionName = prefill.businessCode === "7BF" ? prefill.actionName?.trim() : "";
|
||||||
|
const text = [
|
||||||
|
title ? `任务名称:${title}` : "",
|
||||||
|
goal ? `任务描述:${goal}` : "",
|
||||||
|
actionName ? `行动名称:${actionName}` : "",
|
||||||
|
]
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join("\n");
|
.join("\n");
|
||||||
if (!text) return;
|
if (!text) return;
|
||||||
@@ -1485,6 +1497,15 @@ export default function RoundtablePlanningPage() {
|
|||||||
triggerToast("✨ 已开始新任务,请在第一步与任务理解智能体澄清需求");
|
triggerToast("✨ 已开始新任务,请在第一步与任务理解智能体澄清需求");
|
||||||
}, [resetToStep1, triggerToast]);
|
}, [resetToStep1, triggerToast]);
|
||||||
|
|
||||||
|
// 深链接(taskId)模式专用的「重新分析」:清空第一步会话、保留当前任务(prefill 不动),并复位
|
||||||
|
// autoStarted 闸门,让 C2 自动把「任务名称/描述」重新作为首条消息发出,对同一任务重做意图分析。
|
||||||
|
// 与「新建任务」(全新空白任务) 区分——深链接下任务是固定的,重来=重新分析这条任务。
|
||||||
|
const handleReanalyze = useCallback(() => {
|
||||||
|
autoStartedRef.current = false;
|
||||||
|
resetToStep1();
|
||||||
|
triggerToast("🔄 已重新分析当前任务");
|
||||||
|
}, [resetToStep1, triggerToast]);
|
||||||
|
|
||||||
// 无界抽屉保活复用:父页面重开抽屉时 `bus.$emit('roundtable:reset')` → 子应用回到第一步。
|
// 无界抽屉保活复用:父页面重开抽屉时 `bus.$emit('roundtable:reset')` → 子应用回到第一步。
|
||||||
// 非无界环境下 onWujieEvent 返回 no-op,安全无副作用。
|
// 非无界环境下 onWujieEvent 返回 no-op,安全无副作用。
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -1857,7 +1878,8 @@ export default function RoundtablePlanningPage() {
|
|||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!inWujieEmbed && (
|
{/* 深链接(taskId)模式:业务链由 businessCode 自动决定,隐藏手动「业务链条」入口。 */}
|
||||||
|
{!inWujieEmbed && !prefillRef.current?.taskId && (
|
||||||
<button
|
<button
|
||||||
id="business-chain-btn"
|
id="business-chain-btn"
|
||||||
onClick={() => setIsChainListOpen(true)}
|
onClick={() => setIsChainListOpen(true)}
|
||||||
@@ -1869,15 +1891,28 @@ export default function RoundtablePlanningPage() {
|
|||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<button
|
{/* 深链接(taskId)模式:任务固定,把「新建任务」换成「重新分析」——清空会话、对同一任务重做意图分析。 */}
|
||||||
id="new-task-btn"
|
{prefillRef.current?.taskId ? (
|
||||||
onClick={handleStartNewTask}
|
<button
|
||||||
title="清空当前会话,从第一步开始一个全新任务"
|
id="reanalyze-task-btn"
|
||||||
className="bg-emerald-600 text-white hover:bg-emerald-700 text-xs font-bold px-3 py-2 rounded-xl flex items-center gap-1.5 transition-all shadow-sm shadow-emerald-500/10 active:scale-95"
|
onClick={handleReanalyze}
|
||||||
>
|
title="清空当前会话,对当前任务重新做意图分析"
|
||||||
<Sparkles className="w-3.5 h-3.5" />
|
className="bg-emerald-600 text-white hover:bg-emerald-700 text-xs font-bold px-3 py-2 rounded-xl flex items-center gap-1.5 transition-all shadow-sm shadow-emerald-500/10 active:scale-95"
|
||||||
新建任务
|
>
|
||||||
</button>
|
<RotateCw className="w-3.5 h-3.5" />
|
||||||
|
重新分析
|
||||||
|
</button>
|
||||||
|
) : (
|
||||||
|
<button
|
||||||
|
id="new-task-btn"
|
||||||
|
onClick={handleStartNewTask}
|
||||||
|
title="清空当前会话,从第一步开始一个全新任务"
|
||||||
|
className="bg-emerald-600 text-white hover:bg-emerald-700 text-xs font-bold px-3 py-2 rounded-xl flex items-center gap-1.5 transition-all shadow-sm shadow-emerald-500/10 active:scale-95"
|
||||||
|
>
|
||||||
|
<Sparkles className="w-3.5 h-3.5" />
|
||||||
|
新建任务
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
|
||||||
<button
|
<button
|
||||||
id="save-draft-header-btn"
|
id="save-draft-header-btn"
|
||||||
@@ -1969,6 +2004,7 @@ export default function RoundtablePlanningPage() {
|
|||||||
onOpenDraft={drafts.handleLoadDraft}
|
onOpenDraft={drafts.handleLoadDraft}
|
||||||
activeDraftId={drafts.currentDraftId}
|
activeDraftId={drafts.currentDraftId}
|
||||||
entryRailTaskId={prefillRef.current?.taskId ?? null}
|
entryRailTaskId={prefillRef.current?.taskId ?? null}
|
||||||
|
entryRailBusinessCode={prefillRef.current?.businessCode ?? null}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* MIDDLE VIEWPORT */}
|
{/* MIDDLE VIEWPORT */}
|
||||||
@@ -1979,7 +2015,10 @@ export default function RoundtablePlanningPage() {
|
|||||||
{currentStep === 1 && (
|
{currentStep === 1 && (
|
||||||
<Step1Panel
|
<Step1Panel
|
||||||
headerLeftSlot={
|
headerLeftSlot={
|
||||||
prefillRef.current?.taskId && purposeLevels.length > 0 ? (
|
// 「原任务已有结果」(目的树预览)只在 rwfx-A(6BF)模式显示;xdfx/3qfx 不显示。
|
||||||
|
prefillRef.current?.taskId &&
|
||||||
|
prefillRef.current?.businessCode === "6BF" &&
|
||||||
|
purposeLevels.length > 0 ? (
|
||||||
<PurposeFlowPreview
|
<PurposeFlowPreview
|
||||||
levels={purposeLevels}
|
levels={purposeLevels}
|
||||||
onOpen={() => setIsTaskPurposeOpen(true)}
|
onOpen={() => setIsTaskPurposeOpen(true)}
|
||||||
@@ -2498,6 +2537,8 @@ interface LeftSidebarProps {
|
|||||||
activeDraftId: string | null;
|
activeDraftId: string | null;
|
||||||
/** 深链 taskId 模式:Step1 落地左栏「分析记录」只列该任务的草稿。 */
|
/** 深链 taskId 模式:Step1 落地左栏「分析记录」只列该任务的草稿。 */
|
||||||
entryRailTaskId?: string | null;
|
entryRailTaskId?: string | null;
|
||||||
|
/** 深链业务码:左上角卡片据此决定显示「当前任务」(rwfx/3qfx) 还是「当前行动」(xdfx)。 */
|
||||||
|
entryRailBusinessCode?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Step2SandboxSidebarSync({
|
function Step2SandboxSidebarSync({
|
||||||
@@ -2544,6 +2585,7 @@ function LeftSidebar({
|
|||||||
onOpenDraft,
|
onOpenDraft,
|
||||||
activeDraftId,
|
activeDraftId,
|
||||||
entryRailTaskId,
|
entryRailTaskId,
|
||||||
|
entryRailBusinessCode,
|
||||||
}: LeftSidebarProps) {
|
}: LeftSidebarProps) {
|
||||||
// 整片脱敏:左侧面板(任务概览/参与角色/人工参与等)的所有文本——标题、动态内容、
|
// 整片脱敏:左侧面板(任务概览/参与角色/人工参与等)的所有文本——标题、动态内容、
|
||||||
// 嵌套子组件文本一并脱敏。消息列表与沙箱是另外的容器,不挂此 Hook,保持原文。
|
// 嵌套子组件文本一并脱敏。消息列表与沙箱是另外的容器,不挂此 Hook,保持原文。
|
||||||
@@ -2681,6 +2723,7 @@ function LeftSidebar({
|
|||||||
onOpenDraft={onOpenDraft}
|
onOpenDraft={onOpenDraft}
|
||||||
activeDraftId={activeDraftId}
|
activeDraftId={activeDraftId}
|
||||||
taskId={entryRailTaskId ?? null}
|
taskId={entryRailTaskId ?? null}
|
||||||
|
businessCode={entryRailBusinessCode ?? null}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</section>
|
</section>
|
||||||
@@ -2727,6 +2770,7 @@ function RoundtableEntryRail({
|
|||||||
onOpenDraft,
|
onOpenDraft,
|
||||||
activeDraftId,
|
activeDraftId,
|
||||||
taskId,
|
taskId,
|
||||||
|
businessCode,
|
||||||
}: {
|
}: {
|
||||||
selectedChainId: string | null;
|
selectedChainId: string | null;
|
||||||
onSelectChain: (chain: BusinessChain) => void;
|
onSelectChain: (chain: BusinessChain) => void;
|
||||||
@@ -2734,12 +2778,25 @@ function RoundtableEntryRail({
|
|||||||
activeDraftId: string | null;
|
activeDraftId: string | null;
|
||||||
/** 深链 taskId 模式:分析记录只列该任务的草稿。 */
|
/** 深链 taskId 模式:分析记录只列该任务的草稿。 */
|
||||||
taskId?: string | null;
|
taskId?: string | null;
|
||||||
|
/** 深链业务码:xdfx(7BF) 左上角显示「当前行动」,其余显示「当前任务」。 */
|
||||||
|
businessCode?: string | null;
|
||||||
}) {
|
}) {
|
||||||
const [chains, setChains] = useState<BusinessChain[]>([]);
|
const [chains, setChains] = useState<BusinessChain[]>([]);
|
||||||
const [expandedChainId, setExpandedChainId] = useState<string | null>(null);
|
const [expandedChainId, setExpandedChainId] = useState<string | null>(null);
|
||||||
const { drafts: records, refresh } = useRoundtableDrafts(taskId);
|
const { drafts: records, refresh } = useRoundtableDrafts(taskId);
|
||||||
|
// 深链接(taskId)模式:左上角不显示「业务链选择」(链条已由 businessCode 自动决定),改为展示
|
||||||
|
// 当前任务(rwfx/3qfx)或当前行动(xdfx)。xdfx 的根是「行动」,故展示行动名称 + 叙事。
|
||||||
|
const deeplink = Boolean(taskId);
|
||||||
|
const isXdfx = businessCode === "7BF";
|
||||||
|
const taskDetail = deeplink && !isXdfx ? readCopTaskDetail() : null;
|
||||||
|
const actionDetail = deeplink && isXdfx ? readActionDetail() : null;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
// 深链接模式不展示业务链选择 → 不必拉公共链条。
|
||||||
|
if (deeplink) {
|
||||||
|
void refresh();
|
||||||
|
return;
|
||||||
|
}
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
void listChains("public")
|
void listChains("public")
|
||||||
.then((all) => {
|
.then((all) => {
|
||||||
@@ -2752,7 +2809,7 @@ function RoundtableEntryRail({
|
|||||||
return () => {
|
return () => {
|
||||||
cancelled = true;
|
cancelled = true;
|
||||||
};
|
};
|
||||||
}, [refresh]);
|
}, [refresh, deeplink]);
|
||||||
|
|
||||||
const formatTime = (value: string) => {
|
const formatTime = (value: string) => {
|
||||||
const date = new Date(value);
|
const date = new Date(value);
|
||||||
@@ -2768,7 +2825,57 @@ function RoundtableEntryRail({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* 业务链(公共,前 3 个) */}
|
{/* 深链接(taskId)模式:左上角展示「当前任务」(rwfx/3qfx)或「当前行动」(xdfx),替代业务链选择。 */}
|
||||||
|
{deeplink ? (
|
||||||
|
isXdfx ? (
|
||||||
|
<div className="bg-white border border-[#ECE7E4] rounded-2xl p-4 shadow-[0_4px_20px_rgba(0,0,0,0.02)]">
|
||||||
|
<div className="flex items-center gap-2 mb-3">
|
||||||
|
<span className="flex items-center justify-center w-5 h-5 rounded-md bg-primary text-primary-foreground">
|
||||||
|
<Target className="w-3 h-3" strokeWidth={2.5} />
|
||||||
|
</span>
|
||||||
|
<h2 className="text-sm font-semibold tracking-wide text-slate-900">当前行动</h2>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div>
|
||||||
|
<p className="text-[10px] font-semibold uppercase tracking-wide text-slate-400">行动名称</p>
|
||||||
|
<p className="mt-0.5 text-xs font-semibold leading-relaxed text-slate-800">
|
||||||
|
{actionDetail?.actionName?.trim() || "(未获取到行动名称)"}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-[10px] font-semibold uppercase tracking-wide text-slate-400">行动叙事</p>
|
||||||
|
<p className="mt-0.5 whitespace-pre-wrap text-[11px] leading-relaxed text-slate-600">
|
||||||
|
{actionDetail?.narration?.trim() || "(未获取到行动叙事)"}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="bg-white border border-[#ECE7E4] rounded-2xl p-4 shadow-[0_4px_20px_rgba(0,0,0,0.02)]">
|
||||||
|
<div className="flex items-center gap-2 mb-3">
|
||||||
|
<span className="flex items-center justify-center w-5 h-5 rounded-md bg-primary text-primary-foreground">
|
||||||
|
<Clipboard className="w-3 h-3" strokeWidth={2.5} />
|
||||||
|
</span>
|
||||||
|
<h2 className="text-sm font-semibold tracking-wide text-slate-900">当前任务</h2>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div>
|
||||||
|
<p className="text-[10px] font-semibold uppercase tracking-wide text-slate-400">任务名称</p>
|
||||||
|
<p className="mt-0.5 text-xs font-semibold leading-relaxed text-slate-800">
|
||||||
|
{taskDetail?.taskName?.trim() || "(未获取到任务名称)"}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-[10px] font-semibold uppercase tracking-wide text-slate-400">任务描述</p>
|
||||||
|
<p className="mt-0.5 whitespace-pre-wrap text-[11px] leading-relaxed text-slate-600">
|
||||||
|
{taskDetail?.taskContent?.trim() || "(未获取到任务描述)"}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
) : (
|
||||||
|
/* 业务链(公共,前 3 个) */
|
||||||
<div className="bg-white border border-[#ECE7E4] rounded-2xl p-4 shadow-[0_4px_20px_rgba(0,0,0,0.02)] transition-shadow duration-300 hover:shadow-[0_4px_24px_rgba(45,37,34,0.04)]">
|
<div className="bg-white border border-[#ECE7E4] rounded-2xl p-4 shadow-[0_4px_20px_rgba(0,0,0,0.02)] transition-shadow duration-300 hover:shadow-[0_4px_24px_rgba(45,37,34,0.04)]">
|
||||||
<div className="flex items-center gap-2 mb-3">
|
<div className="flex items-center gap-2 mb-3">
|
||||||
<span className="flex items-center justify-center w-5 h-5 rounded-md bg-primary text-primary-foreground">
|
<span className="flex items-center justify-center w-5 h-5 rounded-md bg-primary text-primary-foreground">
|
||||||
@@ -2949,6 +3056,7 @@ function RoundtableEntryRail({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* 分析记录(圆桌历史草稿) */}
|
{/* 分析记录(圆桌历史草稿) */}
|
||||||
<div className="bg-white border border-[#ECE7E4] rounded-2xl p-4 shadow-[0_4px_20px_rgba(0,0,0,0.02)] flex-1 flex flex-col min-h-[200px] overflow-hidden">
|
<div className="bg-white border border-[#ECE7E4] rounded-2xl p-4 shadow-[0_4px_20px_rgba(0,0,0,0.02)] flex-1 flex flex-col min-h-[200px] overflow-hidden">
|
||||||
|
|||||||
Reference in new issue
Block a user