演示

报表

如何用 AppRegistry.report.add 向全局报表区贡献内容,并实现嵌套报表路由与基于 API 的报表页。

概述

Shell 拥有报表区。插件在 register() 中注册一个 page(通常是带嵌套 Routes 的 hub)。重聚合放在后端。

  • AppRegistry.report.add({ pluginName, page })
  • page 一般为 hub + 嵌套 Routes
  • 子路径必须是相对路径(无前导 /)
  • 用与报表查询相同的 API 做权限控制

1. 用 AppRegistry.report.add 注册

在 register() 中传入 { pluginName, page }。

  • pluginName = metadata.name
  • page 必须是 JSX
TSXfrontend/src/index.tsx
1import type { AppRegistryState, PluginModule } from "@quan-erp/shared-types"; 2import metadata from "../module.metadata.json" with { type: "json" }; 3import { MyModuleReports } from "./page/report"; 4 5const Plugin: PluginModule = { 6 register(AppRegistry: AppRegistryState) { 7 AppRegistry.report.add({ 8 pluginName: metadata.name, 9 page: <MyModuleReports />, 10 }); 11 }, 12}; 13 14export default Plugin;

2. 报表 hub + 嵌套路由

多个报表时做落地 hub,并用嵌套 Routes。子路径不要以 / 开头。

  • 使用 react-router-dom 的 Routes / Route
  • index = hub;子路由 = 各报表
  • 文案必须本地化
TSXfrontend/src/page/report/index.tsx
1import { Route, Routes, useNavigate } from "react-router-dom"; 2import { Page, PageContent, PageTitle } from "@quan-erp/shared-ui"; 3import metadata from "../../../module.metadata.json" with { type: "json" }; 4import { EmployeesReport } from "./employees-report"; 5 6const reportList = [ 7 { 8 id: "employees", 9 name: "Employees", 10 description: "Headcount and status breakdown", 11 path: "employees", 12 element: <EmployeesReport />, 13 }, 14]; 15 16export function MyModuleReports() { 17 const navigate = useNavigate(); 18 19 return ( 20 <Routes> 21 <Route 22 index 23 element={ 24 <Page pluginName={metadata.name}> 25 <PageTitle> 26 <span>Module reports</span> 27 </PageTitle> 28 <PageContent> 29 <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mt-4"> 30 {reportList.map((item) => ( 31 <button 32 key={item.id} 33 type="button" 34 className="text-left border rounded-xl p-4 hover:shadow-md transition" 35 onClick={() => navigate(item.path)} 36 > 37 <div className="font-medium">{item.name}</div> 38 <div className="text-sm text-muted-foreground"> 39 {item.description} 40 </div> 41 </button> 42 ))} 43 </div> 44 </PageContent> 45 </Page> 46 } 47 /> 48 {reportList.map((item) => ( 49 <Route key={item.path} path={item.path} element={item.element} /> 50 ))} 51 </Routes> 52 ); 53}

3. 数据层

通过 withApiMetadataFetchFn + React Query 加载。重聚合放在后端。

  • Declare report endpoints in .api.ts; consume via .queries.ts
  • Pass requiredApis / Protected using the same API objects
  • Prefer server-side aggregates over shipping huge raw tables to the browser

4. 表格

DataTable 不来自 shared-ui — 使用插件内本地 DataTable。

TSXlocal DataTable
import { DataTable } from "../../components/DataTable"; // columns + rows from your report query hook <DataTable columns={columns} data={rows} />

关键规则

  • 只在 register() 中 report.add
  • pluginName 必须等于 metadata.name
  • 嵌套路径必须是相对路径
  • 本地化 UI 文案

检查清单

  • Create page/report hub with nested Routes
  • AppRegistry.report.add({ pluginName, page }) in register()
  • Wire report APIs with withApiMetadataFetchFn + React Query
  • Relative sub-paths; localize labels
  • Verify under Reports after quan-erp watch and install

常见失败

  • 报表不出现 — 未注册 / pluginName 错误
  • 嵌套页空白 — 路径带了前导 /
  • 深链 404 — 缺少嵌套 Routes
  • 权限错误 — requiredApis 不一致