2026-10-01 00:46:44 +08:00
|
|
|
"use client";
|
|
|
|
|
import {useEffect, useState} from "react";
|
|
|
|
|
import {ArrowRight, GitBranch, History, ShieldCheck} from "lucide-react";
|
|
|
|
|
import AgentNav from "@/components/xingbang/AgentNav";
|
|
|
|
|
import {messageOf} from "@/lib/prescreen";
|
|
|
|
|
import "./data-access/workspace.css";
|
2026-09-29 12:58:26 +08:00
|
|
|
|
2026-10-01 00:46:44 +08:00
|
|
|
/** 业务工作区首页(AC-53 / BR-50)。
|
|
|
|
|
*
|
|
|
|
|
* 三个模块**各有独立入口**:AI 预审 / 历史经验加工 / 轨迹复盘,指向各自的路由。
|
|
|
|
|
* 深色导航 + 浅色工作区取自已确认原型;不再以旧版聊天落地页作为唯一首屏。
|
|
|
|
|
* 本页只负责导航与项目上下文,不在这里叠加任何模块面板。
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
const MODULES = [
|
|
|
|
|
{key: "prescreen", href: "/prescreen-workbench", icon: ShieldCheck, name: "AI 预审",
|
|
|
|
|
summary: "按已发布方案执行受限编排,给出有依据的意见、缺证与未完成项。",
|
|
|
|
|
detail: "概率状态与依据 · 动态维度 · 推进沙盘"},
|
|
|
|
|
{key: "experience", href: "/experience-center", icon: History, name: "历史经验加工",
|
|
|
|
|
summary: "从历史过程恢复时间线,用真实模型提炼核查方法,经专家修订与独立审核发布。",
|
|
|
|
|
detail: "来源时间线 · 候选治理 · 卡片入方案"},
|
|
|
|
|
{key: "trajectory", href: "/trajectory-center", icon: GitBranch, name: "轨迹复盘",
|
|
|
|
|
summary: "只读回放每一次运行的步骤与版本依据,与会议结果对照。",
|
|
|
|
|
detail: "步骤与依据 · 失败保留 · 会议结果对照"},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
export default function BusinessHome() {
|
|
|
|
|
const [identity, setIdentity] = useState<any>(null);
|
|
|
|
|
const [projectId, setProjectId] = useState("");
|
|
|
|
|
const [error, setError] = useState("");
|
|
|
|
|
|
|
|
|
|
function headers(json = true) {
|
|
|
|
|
const token = sessionStorage.getItem("xingbang-access-token");
|
|
|
|
|
const role = sessionStorage.getItem("xingbang-demo-role");
|
|
|
|
|
return {...(json ? {"Content-Type": "application/json"} : {}),
|
|
|
|
|
...(token ? {Authorization: `Bearer ${token}`} : {}),
|
|
|
|
|
...(role ? {"X-Xingbang-Demo-Role": role} : {})};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
setProjectId(new URLSearchParams(location.search).get("project") || "");
|
|
|
|
|
fetch("/api/risk-agent/access/context", {headers: headers(false)})
|
|
|
|
|
.then(async (response) => {
|
|
|
|
|
if (!response.ok) throw Error(messageOf(await response.json().catch(() => ({})), "无法读取身份"));
|
|
|
|
|
setIdentity(await response.json());
|
|
|
|
|
})
|
|
|
|
|
.catch((e: any) => setError(e.message));
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
const withProject = (href: string) => projectId ? `${href}?project=${encodeURIComponent(projectId)}` : href;
|
|
|
|
|
return <div className="ra-app">
|
|
|
|
|
<AgentNav active="home" project={projectId || undefined} identity={identity || undefined}/>
|
|
|
|
|
<main className="ra-main">
|
|
|
|
|
<div className="ra-heading">
|
|
|
|
|
<div>
|
|
|
|
|
<div className="ra-eyebrow">业务工作区</div>
|
|
|
|
|
<h1>兴邦金租 · 智审工作台</h1>
|
|
|
|
|
<p>三个模块各有独立入口;项目上下文在模块之间保持。所有数值与结论都标明来源,未接入的能力会如实显示未完成。</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
{error && <div role="alert" className="ra-alert error">{error}</div>}
|
|
|
|
|
{projectId && <div className="ra-alert">当前项目上下文:<b>{projectId}</b>(在模块之间保持)</div>}
|
|
|
|
|
|
|
|
|
|
<div className="xb-project-grid">
|
|
|
|
|
{MODULES.map((item) => <a className="xb-project-card" key={item.key} href={withProject(item.href)}>
|
|
|
|
|
<span>{item.detail}</span>
|
|
|
|
|
<h2><item.icon size={18} aria-hidden="true"/> {item.name}</h2>
|
|
|
|
|
<p>{item.summary}</p>
|
|
|
|
|
<footer><small>进入模块</small><ArrowRight size={15} aria-hidden="true"/></footer>
|
|
|
|
|
</a>)}
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<section className="xb-panel xb-wide">
|
|
|
|
|
<h2>项目工作台</h2>
|
|
|
|
|
<p>需要按项目办理材料、报告与评审结论时,进入项目工作台。</p>
|
|
|
|
|
<div className="xb-actions"><a className="ra-button" href={withProject("/xingbang-workbench")}>进入项目工作台</a></div>
|
|
|
|
|
</section>
|
|
|
|
|
</main>
|
|
|
|
|
</div>;
|
2026-09-29 12:58:26 +08:00
|
|
|
}
|