# system-module **Repository Path**: ruovea-component/system-module ## Basic Information - **Project Name**: system-module - **Description**: No description available - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-07-22 - **Last Updated**: 2026-07-22 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # @kegie/report KeGie.Admin 报表模块(图表配置 / 仪表盘 / 数据源 / 报表定义),以 **pnpm 源码包** 形式提供给各宿主项目复用。 - **不打 dist、不发 npm**——exports 直指 `./src/*`,由宿主 Vite 编译 - **依赖注入解耦**——request / auth / i18n / 菜单 / 表格组件全部由宿主装配时注入 - **零侵入**——包内不含 `/@/` 等宿主别名引用,可脱离 KeGie.Admin 运行 --- ## 一、目录结构 ``` src/ ├─ index.ts # 入口:导出 ReportPlugin + API + 类型 ├─ plugin.ts # Vue install(校验必填项 / provide / mergeLocaleMessage) ├─ context.ts # InjectionKey + useReportContext() ├─ types.ts # ReportPluginOptions ├─ routes.ts # 8 条静态路由(可选使用) ├─ api/ │ ├─ index.ts # 54 个 API 函数 │ ├─ http.ts # request 注入点 │ └─ endpoints.ts # URL 前缀(可覆盖) ├─ i18n/locales/ # 6 语言(en / fr-fr / ja-jp / vi-vn / zh-cn / zh-tw) ├─ components/scEcharts/ # 自包含 echarts 封装 └─ views/ # 18 个 .vue ├─ chartConfig/ # 图表配置(index / chartView / editChartConfig / ChartPreview) ├─ dashboard/ # 仪表盘(index / edit / admin / ChartCard / ReportChartCard / editDashboard) ├─ dataSource/ # 数据源(index / editDataSource) └─ definition/ # 报表定义(index / queryView / editDefinition / ChildTables / editColumnDisplay / editSearchConfig) ``` --- ## 二、宿主接入 ### 2.1 安装 宿主 `package.json` 用 `link:` 协议指向本仓库: ```json { "dependencies": { "@kegie/report": "link:../../report-module" } } ``` ```bash cd D:/app/report-module && pnpm install # 包内依赖(element-plus 等裸导入需要) cd <宿主> && pnpm install # 建立 link ``` ### 2.2 装配插件 在宿主 `main.ts` 中、`app.use(pinia)` 之后调用: ```ts // plugins/report.ts import { computed, defineAsyncComponent, type App } from 'vue'; import { storeToRefs } from 'pinia'; import { ReportPlugin } from '@kegie/report'; import request from '/@/utils/request'; import { auth } from '/@/utils/authFunction'; import { i18n } from '/@/i18n/index'; import { useThemeConfig } from '/@/stores/themeConfig'; import { apiSysMenuListGet, apiSysMenuAddMenusPost } from '/@/api/user/menu'; export function setupReport(app: App) { const { themeConfig } = storeToRefs(useThemeConfig()); app.use(ReportPlugin, { request: request as any, auth, i18n: i18n as any, isDark: computed(() => themeConfig.value.isIsDark), menuApi: { list: () => apiSysMenuListGet(), addMenus: (data: any) => apiSysMenuAddMenusPost(data), }, components: { Table: defineAsyncComponent(() => import('/@/components/table/index.vue')), TableSearch: defineAsyncComponent(() => import('/@/components/table/search.vue')), }, }); } ``` ```ts // main.ts import { setupReport } from '/@/plugins/report'; // ... app.use(pinia) 之后 setupReport(app); ``` --- ## 三、ReportPluginOptions 说明 | 字段 | 必填 | 说明 | |---|---|---| | `request` | ✅ | 宿主 axios 实例(已配 baseURL / token / 拦截器) | | `components.Table` | ✅ | 宿主表格组件(见下方契约) | | `components.TableSearch` | ➖ | 宿主搜索表单组件,缺省时列表页无搜索区 | | `auth` | ➖ | `(code: string) => boolean`,按钮权限校验,缺省 `() => true` | | `i18n` | ➖ | 宿主 vue-i18n 实例(用于 mergeLocaleMessage)——**有结构前提,见下方「i18n 注入约定」** | | `isDark` | ➖ | `Ref`,暗色主题(echarts 配色联动) | | `setRouteTitle` | ➖ | `(routeName, title) => void`,queryView 动态改菜单标题用 | | `menuApi` | ➖ | `{ list(), addMenus(data) }`,dashboard admin 页「添加菜单」能力;缺省时该按钮隐藏 | | `dictApi` | ➖ | 字典类型查询,缺省走 `GET /SysDictType/List` | | `endpoints` | ➖ | 覆盖 API URL 前缀:`{ chartConfig, dataSource, definition, dashboard }`,缺省 `/RptChartConfig` 等 | | `registerI18n` | ➖ | 是否自动 merge i18n,默认 `true` | ### i18n 注入约定(重要) 包内所有视图使用的 key 形如 `message.report.xxx`、`message.router.xxx`,即**带 `message.` 前缀**。 - KeGie.Admin 宿主的 locale 结构是「顶层平铺 + `message` 深拷贝 + `el`」(见 `Web/src/i18n/index.ts` 的 `deepMerge`),此时 `mergeLocaleMessage` 自动注册正常工作。 - **新宿主若 locale 无 `message` 这一层**,自动注册后所有 `t('message.report.xxx')` 会原样回显 key(界面丢失多语言)。此时有两种做法: 1. 设 `registerI18n: false`,在 `createI18n` 时自行按宿主结构注入: ```ts import { reportLocales } from '@kegie/report/i18n'; import zhCn from 'element-plus/es/locale/lang/zh-cn'; const messages: Record = {}; const elLocales: Record = { 'zh-cn': zhCn }; for (const [locale, msg] of Object.entries(reportLocales)) { messages[locale] = { ...msg, message: msg, el: elLocales[locale]?.el ?? {} }; } const i18n = createI18n({ legacy: false, locale: 'zh-cn', messages }); // app.use(ReportPlugin, { ..., registerI18n: false }) ``` 2. 保留 `registerI18n: true`,同时把视图里的 `$t('message.report.xxx')` 视为 key 路径前缀,由宿主在 merge 后补一层 `message` 别名。 包的 `exports` 已暴露 `./i18n` 子路径(`reportLocales`),方便宿主自行组装。 --- ## 四、Table / TableSearch 组件契约 包内列表页通过 `useReportContext().components.Table` 引用宿主组件,宿主必须满足以下隐式契约: ### Table **Props(v-bind 展开传入):** | Prop | 类型 | 说明 | |---|---|---| | `columns` | `ColumnItem[]` | 列配置 `{ prop, label, width, minWidth, align, type, isCheck, hideCheck, showOverflowTooltip }` | | `config` | `object` | `{ isStripe, isBorder, isSerialNo, isSelection, pageSize, hideExport, hideRefresh, hidePrint, hideSet }` | | `param` | `object` | 查询参数(分页 + 搜索条件合并) | | `getData` | `(param) => Promise<{rows, totalRows}>` | 数据加载函数 | **Slots:** `command`(顶部操作区)、各列具名 slot(`#propName="scope"`)、`#action="scope"`(操作列) **Events:** `sortHeader(columns)`、`selectionChange(rows)` **Expose:** `handleList()`(刷新)、`pageReset()`(重置到第 1 页) ### TableSearch **Props:** `search: SearchItem[]` — `{ label, prop, placeholder, required, type: 'input'|'select'|'datetime', options? }` **Events:** `search(formData)` --- ## 五、权限编码清单 宿主 `auth(code)` 需识别以下编码(对应后端 SysMenu 按钮权限): | 编码 | 位置 | 说明 | |---|---|---| | `rptDataSource:add` | dataSource | 新增数据源 | | `rptDataSource:edit` | dataSource | 编辑 | | `rptDataSource:delete` | dataSource | 删除 | | `rptDefinition:add` | definition | 新增报表定义 | | `rptDefinition:edit` | definition | 编辑 | | `rptDefinition:delete` | definition | 删除 | | `rptChartConfig:add` | chartConfig | 新增图表 | | `rptChartConfig:edit` | chartConfig | 编辑 | | `rptChartConfig:delete` | chartConfig | 删除 | | `rptChartConfig:batchDelete` | chartConfig | 批量删除 + 控制多选列显示 | | `rptDashboard:add` | dashboard/admin | 新增仪表盘 | | `rptDashboard:edit` | dashboard/admin、dashboard/edit | 编辑(含设计页保存按钮) | | `rptDashboard:delete` | dashboard/admin | 删除 | 未注入 `auth` 时所有按钮可见(缺省 `() => true`)。 --- ## 六、request 拦截器要求 包内 API 假定 `request` 实例已具备宿主统一拦截器: 1. **baseURL** 指向后端 API 根(如 `https://host/api`) 2. **请求头** 自动携带 `Authorization: Bearer `、`appKey`、`Accept-Language` 3. **响应结构** 返回 `RestfulResult` 或 `RestfulResult>`: ```json { "code": 200, "message": "", "data": { "rows": [], "totalRows": 0 } } ``` 4. **非 200 处理** 拦截器统一 `ElMessage` 报错并 reject(包内不做二次错误提示) 5. **GET body→query** 转换(删除接口走 `params`) 后端接口由 `RuoVea.OmiApi.Reports` 模块提供(动态 WebApi 自动暴露),URL 前缀默认 `/RptChartConfig` / `/RptDataSource` / `/RptDefinition` / `/RptDashboard`,可用 `endpoints` 覆盖。 --- ## 七、路由 ### 方式 A:宿主自行注册(推荐,与现有菜单体系一致) 宿主在自己的路由表中注册 8 条路由,component 指向包内视图: ```ts { path: '/report/chartConfig', name: 'reportChartConfig', component: () => import('@kegie/report/views/chartConfig/index.vue'), meta: { title: 'message.router.reportChartConfig', isHide: false, isKeepAlive: true, icon: 'ele-PieChart' }, } ``` > **注意**:`import` 路径必须带 `.vue` 扩展名,否则 Rollup 无法解析。 ### 方式 B:展开包内路由 ```ts import { reportRoutes } from '@kegie/report/routes'; const routes = [...reportRoutes]; ``` ### 8 条路由一览 | path | name | keepAlive | 说明 | |---|---|---|---| | `/report/chartConfig` | reportChartConfig | ✅ | 图表配置列表 | | `/report/dataSource` | reportDataSource | ✅ | 数据源列表 | | `/report/definition` | reportDefinition | ✅ | 报表定义列表 | | `/report/dashboard` | reportDashboard | ❌ | 仪表盘查看(带 `?code=xxx`) | | `/report/dashboard/edit` | reportDashboardEdit | ❌ | 仪表盘设计 | | `/report/dashboard/admin` | reportDashboardAdmin | ✅ | 仪表盘管理 | | `/report/chart` | reportChartView | ✅ | 单图表查看 | | `/report/queryByCode` | reportQueryByCodeView | ✅ | 按编码查询报表 | --- ## 八、KeepAlive 注意事项 包内 SFC 的 `name` 需保留用于 keep-alive 缓存: - `reportChartConfig` / `reportDataSource` / `reportDefinition` / `reportDashboardAdmin` / `reportChartView` / `reportQueryByCodeView` → 需缓存 - `reportDashboard` / `reportDashboardEdit` → 不缓存(实时数据 / 设计器) 宿主 `keepAliveNames` store 应包含上述需缓存的 name。 --- ## 九、常见问题 **Q: 报 `Rollup failed to resolve import "element-plus"`?** A: 未在 report-module 目录执行 `pnpm install`。link 模式下包内裸导入(`element-plus`、`vue` 等)从包自己的 node_modules 解析。 **Q: 报 `[@kegie/report] options.request 必填`?** A: 宿主未调用 `setupReport(app)`,或调用顺序在 `app.use(pinia)` 之前。 **Q: 列表页空白但无报错?** A: 检查 `components.Table` 是否注入;Table 组件 `getData` 返回结构是否为 `{ rows, totalRows }`。 **Q: i18n 显示 key 原文?** A: 未注入 `i18n` 选项,或宿主 locale 不在包支持的 6 种语言内(可设 `registerI18n: false` 自行 merge)。 --- ## 十、License MIT