/** * DefaultView — 角色化默认首屏视图(task 23.3,Req 25.1–25.5)。 * * 给定登录用户角色,本组件渲染与该角色匹配的默认视图首屏,并将角色匹配的功能入口 * 呈现于无需额外导航即可见的位置(Req 25.4)。目标视图复用任务 15 的角色化视图 * (renderView/renderPortfolio)作为导航目标;此处呈现进入这些视图的功能入口 * (而非领域侧的完整视图实现)。 * * 路由目标由纯函数 `resolveDefaultView` 决定(见 routing.ts,Property 81): * 商务/销售 → SalesView、风控 → RiskView、管理层 → ManagementDashboard。 * 对 `无角色` 渲染「需分配角色」提示视图,且不呈现任何评估数据(Req 25.5)。 * * 可访问性:以 `
` 区域 + 标题层级表达结构;功能入口以 `Nav` 语义化导航 * 暴露(landmark),便于辅助技术直接定位(Req 25.4)。视觉值统一取自 Design Tokens。 */ import type { CSSProperties } from 'react'; import { Card, Nav } from '../design-system/index.js'; import type { NavItem } from '../design-system/index.js'; import { colorVar, FONT_FAMILY, space, typographyStyle } from '../design-system/components/styles.js'; import { resolveDefaultView } from './routing.js'; import type { Role, Route } from './routing.js'; /** 单条功能入口定义(角色匹配,呈现为导航目标)。 */ interface EntryPoint { /** 唯一键(亦作为导航目标标识)。 */ readonly key: string; /** 显示文本。 */ readonly label: string; /** 进入目标视图的路由片段(占位链接,领域侧视图于任务 15 实现)。 */ readonly href: string; } /** 每个角色默认视图的标题与可见功能入口(Req 25.4)。 */ interface ViewDescriptor { /** 默认视图标题。 */ readonly heading: string; /** 功能入口导航的无障碍标签。 */ readonly navLabel: string; /** 角色匹配的功能入口集合(首屏可见,无需额外导航)。 */ readonly entryPoints: readonly EntryPoint[]; } /** * 路由 → 默认视图描述符。功能入口对应任务 15 角色化视图的关键能力区块: * - SalesView:结论 / 接受条件 / 风险调整后报价(Req 13.1)。 * - RiskView:评分明细 / 红线检查 / 缺口尽调(Req 13.2)。 * - ManagementDashboard:风险热力图 / TopN 风险 / 利润 vs 风险看板(Req 13.3)。 * `AssignRolePrompt` 不在此表内——其不呈现任何评估数据(Req 25.5)。 */ const VIEW_DESCRIPTORS: Readonly, ViewDescriptor>> = { SalesView: { heading: '商务/销售视图', navLabel: '商务/销售功能入口', entryPoints: [ { key: 'sales-conclusion', label: '评估结论', href: '#/sales/conclusion' }, { key: 'sales-acceptance', label: '接受条件', href: '#/sales/acceptance' }, { key: 'sales-quote', label: '风险调整后报价', href: '#/sales/quote' }, ], }, RiskView: { heading: '风控视图', navLabel: '风控功能入口', entryPoints: [ { key: 'risk-scoring', label: '评分明细', href: '#/risk/scoring' }, { key: 'risk-redline', label: '红线检查', href: '#/risk/redline' }, { key: 'risk-gap', label: '缺口尽调', href: '#/risk/gap' }, ], }, ManagementDashboard: { heading: '管理层看板', navLabel: '管理层功能入口', entryPoints: [ { key: 'mgmt-heatmap', label: '风险热力图', href: '#/management/heatmap' }, { key: 'mgmt-topn', label: 'TopN 风险', href: '#/management/topn' }, { key: 'mgmt-profit-risk', label: '利润 vs 风险看板', href: '#/management/profit-risk' }, ], }, } as const; /** `DefaultView` 组件属性。 */ export interface DefaultViewProps { /** 登录用户角色。 */ readonly role: Role; } /** * 渲染角色匹配的默认首屏视图。 * * - 已分配业务角色:渲染对应视图标题与首屏可见的功能入口导航(Req 25.1–25.4)。 * - 无角色:渲染「需分配角色」提示,且不呈现任何评估数据(Req 25.5)。 */ export function DefaultView({ role }: DefaultViewProps): JSX.Element { const { route, showsAssessmentData } = resolveDefaultView(role); const containerStyle: CSSProperties = { display: 'flex', flexDirection: 'column', gap: `${space(4)}px`, fontFamily: FONT_FAMILY, color: colorVar('color.text.primary'), }; if (route === 'AssignRolePrompt') { // Req 25.5:未分配业务角色 → 提示分配角色,且不呈现任何评估数据。 return (

需分配角色

当前账号尚未分配商务/销售、风控或管理层角色,暂无法查看评估数据。 请联系管理员为您分配相应角色后重试。

); } const descriptor = VIEW_DESCRIPTORS[route]; const navItems: readonly NavItem[] = descriptor.entryPoints.map((entry) => ({ key: entry.key, label: entry.label, href: entry.href, })); return (

{descriptor.heading}

{/* Req 25.4:角色匹配的功能入口呈现于无需额外导航即可见的位置。 */}
); }