Merge branch 'dhk-3': 会商第一步分析记录按业务链筛选
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
commit
dc5b83e8cd
1 file changed
+95
-2
@@ -40,6 +40,7 @@ import {
|
|||||||
Clock,
|
Clock,
|
||||||
Cpu,
|
Cpu,
|
||||||
Download,
|
Download,
|
||||||
|
Filter,
|
||||||
History,
|
History,
|
||||||
Layers,
|
Layers,
|
||||||
ListOrdered,
|
ListOrdered,
|
||||||
@@ -61,6 +62,14 @@ import {
|
|||||||
import { useTheme } from "@/contexts/ThemeContext";
|
import { useTheme } from "@/contexts/ThemeContext";
|
||||||
import { useArtifacts } from "@/components/workspace/artifacts";
|
import { useArtifacts } from "@/components/workspace/artifacts";
|
||||||
import { useSidebarSafe } from "@/components/ui/sidebar";
|
import { useSidebarSafe } from "@/components/ui/sidebar";
|
||||||
|
import {
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownMenuLabel,
|
||||||
|
DropdownMenuRadioGroup,
|
||||||
|
DropdownMenuRadioItem,
|
||||||
|
DropdownMenuTrigger,
|
||||||
|
} from "@/components/ui/dropdown-menu";
|
||||||
import { desensitize } from "@/lib/desensitize";
|
import { desensitize } from "@/lib/desensitize";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { useDesensitizeSubtree } from "@/roundtable-planning/lib/use-desensitize-subtree";
|
import { useDesensitizeSubtree } from "@/roundtable-planning/lib/use-desensitize-subtree";
|
||||||
@@ -2860,6 +2869,10 @@ function getChainStageGroups(chain: BusinessChain): BusinessChain["seats"][] {
|
|||||||
return chain.seats.map((s) => [s]);
|
return chain.seats.map((s) => [s]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 分析记录「按业务链筛选」的两个特殊值:全部 / 无业务链(自由模式)。 */
|
||||||
|
const RECORD_FILTER_ALL = "__all__";
|
||||||
|
const RECORD_FILTER_FREE = "__free__";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 需求 0616 #2:多智能体会商 Step1(落地)左栏入口栏。
|
* 需求 0616 #2:多智能体会商 Step1(落地)左栏入口栏。
|
||||||
* - 业务链:仅公共链条(``listChains("public")``)前 3 个;点击以该链席位启动会商。
|
* - 业务链:仅公共链条(``listChains("public")``)前 3 个;点击以该链席位启动会商。
|
||||||
@@ -2886,6 +2899,38 @@ function RoundtableEntryRail({
|
|||||||
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);
|
||||||
|
// 分析记录「按业务链筛选」—— 选项从已加载草稿的 chainTitle 去重得到,
|
||||||
|
// 无业务链的草稿(自由 / recommend 模式)归入「自由模式」。
|
||||||
|
const [chainFilter, setChainFilter] = useState<string>(RECORD_FILTER_ALL);
|
||||||
|
const chainFilterOptions = useMemo(() => {
|
||||||
|
const titles = new Set<string>();
|
||||||
|
let hasFree = false;
|
||||||
|
for (const rec of records) {
|
||||||
|
const title = rec.chainTitle?.trim();
|
||||||
|
if (title) titles.add(title);
|
||||||
|
else hasFree = true;
|
||||||
|
}
|
||||||
|
const opts = Array.from(titles)
|
||||||
|
.sort((a, b) => a.localeCompare(b, "zh-CN"))
|
||||||
|
.map((title) => ({ value: title, label: title }));
|
||||||
|
if (hasFree) opts.push({ value: RECORD_FILTER_FREE, label: "自由模式" });
|
||||||
|
return opts;
|
||||||
|
}, [records]);
|
||||||
|
const filteredRecords = useMemo(() => {
|
||||||
|
if (chainFilter === RECORD_FILTER_ALL) return records;
|
||||||
|
if (chainFilter === RECORD_FILTER_FREE)
|
||||||
|
return records.filter((rec) => !rec.chainTitle?.trim());
|
||||||
|
return records.filter((rec) => rec.chainTitle?.trim() === chainFilter);
|
||||||
|
}, [records, chainFilter]);
|
||||||
|
// 草稿刷新后所选业务链可能已不存在(被删/改名)→ 回落到「全部」,避免列表空白无解。
|
||||||
|
useEffect(() => {
|
||||||
|
if (
|
||||||
|
chainFilter !== RECORD_FILTER_ALL &&
|
||||||
|
!chainFilterOptions.some((opt) => opt.value === chainFilter)
|
||||||
|
) {
|
||||||
|
setChainFilter(RECORD_FILTER_ALL);
|
||||||
|
}
|
||||||
|
}, [chainFilter, chainFilterOptions]);
|
||||||
// 深链接(taskId)模式:左上角不显示「业务链选择」(链条已由 businessCode 自动决定),改为展示
|
// 深链接(taskId)模式:左上角不显示「业务链选择」(链条已由 businessCode 自动决定),改为展示
|
||||||
// 当前任务(rwfx/3qfx)或当前行动(xdfx)。xdfx 的根是「行动」,故展示行动名称 + 叙事。
|
// 当前任务(rwfx/3qfx)或当前行动(xdfx)。xdfx 的根是「行动」,故展示行动名称 + 叙事。
|
||||||
const deeplink = Boolean(taskId);
|
const deeplink = Boolean(taskId);
|
||||||
@@ -3159,13 +3204,59 @@ function RoundtableEntryRail({
|
|||||||
<History className="w-3 h-3" strokeWidth={2.5} />
|
<History className="w-3 h-3" strokeWidth={2.5} />
|
||||||
</span>
|
</span>
|
||||||
<h2 className="text-sm font-semibold tracking-wide text-slate-900">分析记录</h2>
|
<h2 className="text-sm font-semibold tracking-wide text-slate-900">分析记录</h2>
|
||||||
|
{/* 按业务链筛选 —— 仅当存在多于 1 个可选业务链时才显示图标按钮。 */}
|
||||||
|
{chainFilterOptions.length > 1 && (
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownMenuTrigger asChild>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
title="按业务链筛选"
|
||||||
|
aria-label="按业务链筛选"
|
||||||
|
className={cn(
|
||||||
|
"ml-auto flex h-6 w-6 shrink-0 items-center justify-center rounded-md border transition-colors",
|
||||||
|
chainFilter === RECORD_FILTER_ALL
|
||||||
|
? "border-[#ECE7E4] text-neutral-400 hover:border-primary/30 hover:text-primary"
|
||||||
|
: "border-primary/30 bg-primary/5 text-primary",
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Filter className="h-3 w-3" strokeWidth={2.5} />
|
||||||
|
</button>
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent align="end" className="min-w-[12rem]">
|
||||||
|
<DropdownMenuLabel className="text-[16px] text-neutral-500">
|
||||||
|
按业务链筛选
|
||||||
|
</DropdownMenuLabel>
|
||||||
|
<DropdownMenuRadioGroup
|
||||||
|
value={chainFilter}
|
||||||
|
onValueChange={setChainFilter}
|
||||||
|
>
|
||||||
|
<DropdownMenuRadioItem value={RECORD_FILTER_ALL} className="text-[16px]">
|
||||||
|
全部
|
||||||
|
</DropdownMenuRadioItem>
|
||||||
|
{chainFilterOptions.map((opt) => (
|
||||||
|
<DropdownMenuRadioItem
|
||||||
|
key={opt.value}
|
||||||
|
value={opt.value}
|
||||||
|
className="text-[16px]"
|
||||||
|
>
|
||||||
|
<span className="truncate">{opt.label}</span>
|
||||||
|
</DropdownMenuRadioItem>
|
||||||
|
))}
|
||||||
|
</DropdownMenuRadioGroup>
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{records.length === 0 ? (
|
{records.length === 0 ? (
|
||||||
<p className="flex-1 text-xs text-neutral-400 text-center py-8">暂无分析记录</p>
|
<p className="flex-1 text-xs text-neutral-400 text-center py-8">暂无分析记录</p>
|
||||||
|
) : filteredRecords.length === 0 ? (
|
||||||
|
<p className="flex-1 text-xs text-neutral-400 text-center py-8">
|
||||||
|
该业务链下暂无分析记录
|
||||||
|
</p>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<div className="space-y-2 overflow-y-auto flex-1 px-1 py-0.5 custom-scrollbar">
|
<div className="space-y-2 overflow-y-auto flex-1 px-1 py-0.5 custom-scrollbar">
|
||||||
{records.map((rec) => {
|
{filteredRecords.map((rec) => {
|
||||||
// 已完成:进行到第 3 步(执行过方案总结报告)
|
// 已完成:进行到第 3 步(执行过方案总结报告)
|
||||||
const completed = rec.furthestStep === 3;
|
const completed = rec.furthestStep === 3;
|
||||||
// 选中:当前已加载的草稿(正在查看的那条)
|
// 选中:当前已加载的草稿(正在查看的那条)
|
||||||
@@ -3230,7 +3321,9 @@ function RoundtableEntryRail({
|
|||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-2 pt-2 border-t border-neutral-100 text-center text-[11px] text-neutral-400">
|
<div className="mt-2 pt-2 border-t border-neutral-100 text-center text-[11px] text-neutral-400">
|
||||||
共 {records.length} 条分析记录
|
{chainFilter === RECORD_FILTER_ALL
|
||||||
|
? `共 ${records.length} 条分析记录`
|
||||||
|
: `筛选出 ${filteredRecords.length} / ${records.length} 条分析记录`}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in new issue
Block a user