From 4ce526064767aacf74c93b9b07228e10fa29db28 Mon Sep 17 00:00:00 2001 From: zichun Date: Mon, 11 May 2026 09:23:15 +0800 Subject: [PATCH] docs: en wiki — add BI / KPI / Charts engine chapter --- en/docs/reference/maintainer/bi-engine.md | 170 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ en/docs/reference/maintainer/tech-stack.md | 2 +- en/mkdocs.yml | 1 + 3 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 en/docs/reference/maintainer/bi-engine.md diff --git a/en/docs/reference/maintainer/bi-engine.md b/en/docs/reference/maintainer/bi-engine.md new file mode 100644 index 0000000..9874ae4 --- /dev/null +++ b/en/docs/reference/maintainer/bi-engine.md @@ -0,0 +1,170 @@ +# BI / KPI / Charts engine + +xly does **not** ship a generic OLAP / cube engine (no Mondrian, no +Saiku, no MDX; the bundled `olap4j-1.2.0.jar` has zero Java imports +and is dead weight — see [tech-stack.md](tech-stack.md#3-cache-in-memory) +note on OLAP4J). + +What xly *does* ship is a **homebrewed metadata-driven dashboard + +KPI layer** built on the same primitives as everything else in the +framework: rows in `gds*` metadata tables pointing at `Sp_*` stored +procedures, rendered through generic Java services. This page maps it +end-to-end. + +## Three pieces + +| Piece | Surface | Backing tables | Service | +|---|---|---|---| +| **Charts** (cards, bar/line/pie/gauge widgets, dashboards) | `/indexPage/commonChar` modules in FROUNT; 图表配置 admin in BACK | `gdsconfigcharmaster` (3,006 rows), `gdsconfigcharslave` (1,951 rows) | `CharServiceImpl` (2,219 lines, one of the heaviest in xlyBusinessService) | +| **KPI** (per-employee / per-module performance scoring) | KPI screens in BACK / FROUNT (e.g., `行为KPI项目设置`, `5.经营KPI分析`, `异常清除KPI任务表`) | `kpimaster` (124,524 rows), `kpidetail` (1,308), `kpimodule` (44), `kpimoduleuser`, `kpimoduleuserday`, `kpislavel` | `KpiServiceImpl` (833 lines, in `xlyBusinessService/.../KPIService/`) + `BusinessModelKpiServiceImpl` (901 lines) + `FlushModleKpiThread` (background refresh) | +| **Pre-baked aggregation procs** | Invoked by chart rows | n/a | 20 `Sp_chart_*` procedures + 2 `Sp_KPI_*` procedures + `spKPImodule` | + +## Charts: how a dashboard renders + +A chart in xly is a row in `gdsconfigcharmaster` with this shape (key columns): + +| Column | Role | +|---|---| +| `sId` | Chart id | +| `sParentId` | The owning module (`gdsmodule.sId`) | +| `sChinese` / `sEnglish` / `sBig5` | Chart title | +| `sCharType` | Widget type — see distribution below | +| `sProcedureName` | The stored procedure that produces the chart's data | +| `sProcedureParam` | JSON parameter spec for the proc | +| `iWidth` | Layout span (24-column grid) | + +`sCharType` distribution in the live dev DB: + +| `sCharType` | Count | What it renders | +|---|---:|---| +| `Div` | 1558 | Container / layout-only block | +| `sLabel` | 1143 | Single-value text card (e.g., "今日销售额: ¥X") | +| `Progress` | 137 | Progress bar | +| `sPie` | 52 | Pie chart | +| `commonList` | 45 | Embedded data grid (re-uses the universal grid) | +| `sColumnarGroup` | 30 | Grouped bar chart | +| `sColumnar` | 28 | Single-series bar chart | +| `sBrokenLine` | 5 | Line chart | +| `sBar` | 3 | Horizontal bar chart | +| `ColorBlock` | 3 | Color-coded heatmap-style block | +| `sGauge` | 2 | Gauge / dial widget | + +Slave rows (`gdsconfigcharslave`) carry the per-series / per-column +breakout for charts that need multiple data series. + +The runtime path: + +``` +SPA opens a /indexPage/commonChar?sModelsId= + │ + ▼ +GET /xlyEntry/business/getModelBysId/ + → returns the dashboard's metadata composite (formData includes + the chart layout from gdsconfigcharmaster + slave rows) + │ + ▼ +For each chart: + POST /xlyEntry/business/getXxx (CharServiceImpl method) with the + chart's sProcedureName + sProcedureParam + → CharServiceImpl invokes the named Sp_chart_* proc through + generic procedure dispatch + │ + ▼ +SPA renders each card using ECharts (frontend), one card per chart row +``` + +## The 20 `Sp_chart_*` procs + +| Proc | What it computes | +|---|---| +| `Sp_chart_home_11`, `Sp_chart_home_13` | Homepage dashboard cards | +| `Sp_chart_TodayOrder`, `Sp_chart_TodayOrder_hm`, `Sp_chart_ThisMonthQty`, `Sp_chart_MonthOrder`, `Sp_chart_MonthTeamQty` | Today / current-month order counts and team output | +| `Sp_chart_TodayProfit`, `Sp_chart_MonthProfit`, `Sp_chart_TodayReceivables`, `Sp_chart_TodayReceive`, `Sp_chart_expenses` | Financial: profit, receivables, expense rollups | +| `Sp_chart_EquipmentLoad`, `Sp_chart_EquipmentLoad1`, `Sp_chart_EquipmentLod1`, `Sp_chart_EquipmentLast`, `Sp_chart_sMachine_speed`, `Sp_chart_Bottleneck` | Shop-floor: equipment utilisation, last-running state, current bottleneck | +| `Sp_chart_OrderProcess`, `Sp_chart_WorkOrderProcess` | Order / work-order progress timelines | + +Each follows the standard `(IN sLoginId, IN sBrId, IN sSuId, ...) → +result-set` shape so generic dispatch can call it. The +[multi-tenant scoping](../../concepts/multi-tenancy.md) flows through +naturally — every chart is automatically tenant-filtered. + +## Pre-built dashboard modules in this dev DB + +`/indexPage/commonChar` is the shared route. The dev DB has 6 modules +mapped to it: + +| Module sId | 中文 | +|---|---| +| `19211681019715464089035510` | 销售图表分析 (Sales chart analysis) | +| `19211681019715481435115760` | 财务图表分析 (Financial chart analysis) | +| `19211681019715481435298200` | 生产图表分析 (Production chart analysis) | +| `19211681019715708435449190` | 销售大数据分析 ("sales big-data analysis") | +| `19211681019715708471874620` | 采购大数据分析 (Procurement big-data analysis) | +| `101251240115015889205266000` | 采购价格分析查询 (Procurement price analysis) | + +All six are metadata-driven via `gdsconfigcharmaster` rows — no Java +code change needed to add or modify them. + +## KPI subsystem + +`kpi*` is a **per-employee performance-scoring** layer separate from +the chart rendering. The shape: + +| Table | Role | Live row count | +|---|---|---:| +| `kpimaster` | Per-employee per-period KPI rollup. The volume table — one row per employee per scored event. | 124,524 | +| `kpidetail` | Detail rows backing each `kpimaster` aggregate. | 1,308 | +| `kpimodule` | KPI definitions — which modules / metrics participate. | 44 | +| `kpimoduleuser` | Per-user KPI assignments. | 0 (unassigned in dev DB) | +| `kpimoduleuserday` | Daily KPI bucket per user. | 1 | +| `kpislavel` | KPI level / band definitions. | 0 | + +Java side: + +- `KpiServiceImpl.java` (833 lines, in `xlyBusinessService/.../KPIService/`) — the read/write API for KPI events. +- `BusinessModelKpiServiceImpl.java` (901 lines) — the computation layer that turns business-event data into KPI rows. +- `FlushModleKpiThread.java` — background recompute worker. +- `KpimasterCloum.java` enum (xlyPersist) — column-name constants. + +Procs: + +- `Sp_KPI_DetailByEmployee` — per-employee detail report. +- `Sp_KPI_SumByEmployee` — per-employee summary rollup. +- `spKPImodule` — recompute KPI for a module. + +There is also a sizable customer override under +`script/客户/`: e.g., `script/标版/30100101/spKPImodule.sql` and +several `Sp_SalesOrder_Kpi*` procs (matches the +[per-customer SQL override channel](../../slices/05-customer-sql-override.md) +— customers who want different KPI rules ship their own proc). + +## Why this matters + +xly's BI layer demonstrates the data-driven thesis at scale: + +1. **Adding a new dashboard card requires no Java change** — a PM + inserts a `gdsconfigcharmaster` row pointing at a `Sp_chart_*` proc, + sets `sCharType` and `iWidth`, the SPA picks it up on the next + `getModelBysId` cache miss. +2. **Adding a new chart proc** does require a SQL author (the proc + has to follow the standard tenant-scoped shape so generic dispatch + can call it through `CharServiceImpl`). +3. **No OLAP cube, no MDX, no semantic layer.** Each chart is a + purpose-built SQL stored procedure. This trades reusability for + simplicity — perfect-fit aggregations, no general-purpose ad-hoc + query builder. + +## What this is *not* + +- **Not a self-service BI tool.** Customers cannot point at any + table and build a chart through drag-and-drop; new charts require + a SQL stored procedure and an admin who knows how to register the + metadata row. +- **Not real-time analytics infrastructure.** Charts run their procs + on cache miss against the OLTP MySQL schema. There is no separate + warehouse, no incremental aggregation pipeline, no streaming layer. + Heavy charts on large customers will execute heavy SQL on the live DB. +- **Not column-store / OLAP-engine-backed.** The `olap4j` jars in + `xlyPersist/build.gradle` have zero Java imports — they're + classpath-only dead weight. xly uses MySQL's regular row-store via + MyBatis through generic procedure dispatch. diff --git a/en/docs/reference/maintainer/tech-stack.md b/en/docs/reference/maintainer/tech-stack.md index dd43e81..2ce2a5a 100644 --- a/en/docs/reference/maintainer/tech-stack.md +++ b/en/docs/reference/maintainer/tech-stack.md @@ -120,7 +120,7 @@ third-party code. | commons-jexl3 | 3.1 | `xlyPersist/build.gradle` | (Pulled in by jxls; no direct imports detected.) | | EasyExcel | 4.0.3 (local jars: `easyexcel-4.0.3.jar` + `-support-4.0.3.jar` + `-core-4.0.3.jar`) | `xlyPersist/build.gradle` | 10 files in `xlyBusinessService/src/` import `com.alibaba.excel.*`. | | JasperReports | `jasperreports-6.0.0.jar` + `jasperreports-fonts-6.0.0.jar` (local jars) | `xlyPersist/build.gradle` | 11 files import `net.sf.jasperreports.*` (xlyPersist=5, xlyEntry=3, xlyBusinessService=3). | -| OLAP4J | `olap4j-1.2.0.jar` + `olap4j-xmlaserver-1.2.0.jar` (local jars) | `xlyPersist/build.gradle` | 1 file in `xlyPersist/src/` imports `org.olap4j.*`. | +| OLAP4J | `olap4j-1.2.0.jar` + `olap4j-xmlaserver-1.2.0.jar` (local jars) | `xlyPersist/build.gradle` (the `-xmlaserver` line is also commented out) | **0 Java imports of `org.olap4j.*` anywhere in source.** Dead jars on the classpath; xly's BI/dashboard layer ([bi-engine.md](bi-engine.md)) is stored-proc-driven, not OLAP-cube-driven. | | ZXing | core 3.4.0 + javase 3.4.0 | `xlyPersist/build.gradle` | 5 files import `com.google.zxing.*` (xlyPersist=4, xlyEntry=1). | | Barcode4J | `barcode4j-light` 2.0 | `xlyPersist/build.gradle` | 1 file in `xlyPersist/src/` imports `org.krysalis.barcode4j.*`. | | Pinyin4j | 2.5.0 | `xlyPersist/build.gradle` | 1 file: `xlyPersist/src/main/java/com/xly/utils/ChineseCharacterUtil.java`. | diff --git a/en/mkdocs.yml b/en/mkdocs.yml index b355804..fa135a3 100644 --- a/en/mkdocs.yml +++ b/en/mkdocs.yml @@ -113,6 +113,7 @@ nav: - "SQL templates (xlyEntry/templesql/)": reference/maintainer/sql-templates.md - "Multi-service deployment": reference/maintainer/deployment.md - "Metadata-management services (xlyManage)": reference/maintainer/management-services.md + - "BI / KPI / Charts engine": reference/maintainer/bi-engine.md - "Activiti integration": reference/maintainer/activiti.md - 5. API Reference: - api-reference/index.md -- libgit2 0.22.2