rj-grid 0.2.3 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  <h1 align="center">rj-grid</h1>
6
6
 
7
7
  <p align="center">
8
- <b>零第三方依赖的企业级 Vue 3 数据网格 —— 对标 AG Grid 的全功能,MIT 免费、gzip 约 93 KB。</b><br/>
8
+ <b>零第三方依赖的企业级 Vue 3 数据网格 —— 对标 AG Grid 的全功能,MIT 免费、gzip 约 110 KB。</b><br/>
9
9
  虚拟滚动 · 冻结列 · 分组透视 · 树形 · 编辑撤销 · 公式引擎 · SSRM 服务端行模型 · 主题 & i18n · 打印/CSV/Excel/PDF · 离线自然语言查询(NLQ)
10
10
  </p>
11
11
 
@@ -15,9 +15,9 @@
15
15
  <a href="https://gitee.com/rjding/rj-grid"><img src="https://img.shields.io/badge/Gitee-rj--grid-orange?logo=gitee&logoColor=white" alt="Gitee mirror"/></a>
16
16
  <a href="https://github.com/rjding/rjGrid/blob/master/LICENSE"><img src="https://img.shields.io/badge/license-MIT-green.svg" alt="License MIT"/></a>
17
17
  <a href="https://gitee.com/rjding/rj-grid"><img src="https://img.shields.io/badge/third--party%20deps-0-blue.svg" alt="Zero dependencies"/></a>
18
- <img src="https://img.shields.io/badge/gzip-~93KB-lightgrey.svg" alt="Bundle size"/>
18
+ <img src="https://img.shields.io/badge/gzip-~110KB-lightgrey.svg" alt="Bundle size"/>
19
19
  <a href="https://vuejs.org/"><img src="https://img.shields.io/badge/vue-3.x-brightgreen.svg?logo=vuedotjs" alt="Vue 3"/></a>
20
- <img src="https://img.shields.io/badge/tests-346%20passed-yellowgreen.svg" alt="Tests"/>
20
+ <img src="https://img.shields.io/badge/tests-407%20passed-yellowgreen.svg" alt="Tests"/>
21
21
  <img src="https://img.shields.io/badge/types-TypeScript-blue.svg?logo=typescript" alt="TypeScript"/>
22
22
  </p>
23
23
 
@@ -38,7 +38,7 @@
38
38
  想象一下:一个 `<rj-grid>` 标签,就能替换掉你项目里那些「几万行就卡死、想加个分组又得换库」的表格——而**不额外引入任何第三方依赖**,也不用给商业表格库交授权费。
39
39
 
40
40
  - **真·零依赖**:运行时只需 `vue`,连可选的图表都是按需 `import('echarts')`。不捆绑、不污染你的 lockfile。
41
- - **小得离谱**:gzip 约 93 KB,却装下了别人几个库加起来的功能量。
41
+ - **小得离谱**:gzip 约 110 KB,却装下了别人几个库加起来的功能量。
42
42
  - **10 万行丝滑**:行列双向虚拟滚动,实测 100,000 行 × 12 列秒开(生成仅约 12 ms)。
43
43
  - **对标 AG Grid 全功能**:树形 / 分组 / 透视 / SSRM / 公式 / 主题 / i18n / 导出 / NLQ 一应俱全。
44
44
  - **TypeScript 原生**:完整的类型推导与 `.d.ts`,编辑器全程提示,不是「先跑起来再说」的糙活。
@@ -50,14 +50,14 @@
50
50
 
51
51
  | 分类 | 你会得到的能力 |
52
52
  |---|---|
53
- | 渲染 | 行列虚拟滚动(10 万行流畅)、冻结列、多级表头、密度三档、钉行、全宽行 |
53
+ | 渲染 | 行列虚拟滚动(10 万行流畅)、冻结列、多级表头、密度三档、钉行、全宽行;**单击单元格即选中行**(`selectOnCellClick`,无需勾复选框) |
54
54
  | 数据 | 客户端 / 分页 / 无限滚动 / **SSRM 服务端行模型**(按需块缓存)四种模式 |
55
55
  | 分组 | 树形任意深度、拖拽分组、多级分组 + 组页脚聚合、列透视(含高基数护栏) |
56
56
  | 编辑 | 8 类编辑器、校验、撤销/重做、批量事务回填、内置新增/编辑行弹窗 |
57
57
  | 公式 | 零依赖 Excel 风格公式:`=B2*C2`、`SUM/COUNTIF/SUMIF`、区域引用、循环引用检测 |
58
58
  | 筛选 | 列头漏斗 / 浮动筛选行 / 快速搜索 / 高级过滤(跨列 AND/OR 表达式树)四路叠加 |
59
59
  | 外观 | 主题引擎(4 预设 × 明暗 × 强调色 × 自定义 CSS 变量)、i18n(中/英 + 文案覆盖)、图标替换 |
60
- | 输出 | 打印 / CSV / Excel / PDF,支持选中行 / 当前视图 / 后端导出三种范围 |
60
+ | 输出 | 打印 / CSV / Excel / PDF,支持选中行 / 当前视图 / 后端导出三种范围;四个按钮可逐个显隐(`showPrint`/`showCsv`/`showPdf`/`showExcel`) |
61
61
  | AI | 纯离线确定性 **NLQ**,中英双语随 i18n 切换:中文用「数量大于50 按单价降序」、英文用 `qty > 50 sort by price desc`,回显随语言 |
62
62
  | 状态 | `stateKey` 自动持久化 + `getState/setState` 编程式存取,刷新不丢视图 |
63
63
 
@@ -206,7 +206,7 @@ const rows: RjRowData[] = [
206
206
  |---|---|---|
207
207
  | 授权 / 费用 | ✅ MIT 完全免费 | ⚠️ 企业级特性需商业授权 |
208
208
  | 第三方运行时依赖 | ✅ 仅 `vue` | ⚠️ 自带框架与模块体系 |
209
- | gzip 体积 | ✅ 约 93 KB | 显著更大 |
209
+ | gzip 体积 | ✅ 约 110 KB | 显著更大 |
210
210
  | Vue 3 原生 | ✅ 值导入即用,非二次封装 | 提供 Vue 封装层 |
211
211
  | 离线自然语言查询 | ✅ 内置纯确定性 NLQ | ❌ 无 |
212
212
  | 虚拟滚动 / 分组 / 透视 / SSRM / 公式 / 主题 / 导出 | ✅ 全部内置 | ✅ 部分在付费版 |
@@ -278,7 +278,7 @@ pnpm dev # 默认 http://localhost:5173
278
278
  |---|---|
279
279
  | `index.ts` | 包入口(值导出 `RjGrid` + NLQ / 查询条件内核 + 全部公共类型) |
280
280
  | `src/` | 组件与引擎源码(`src/types.ts` 是类型权威) |
281
- | `__tests__/` | 346 个单测用例,入口 `__tests__/run.ts` |
281
+ | `__tests__/` | 407 个单测用例,入口 `__tests__/run.ts` |
282
282
  | `build/rjDistCheck.mjs` | 产物体检五守卫(构建末尾自动跑) |
283
283
  | `vite.lib.config.ts` | 库构建:ESM 单文件 + 单 `style.css`,external `vue`/`echarts`,不出 sourcemap |
284
284
  | `playground/` | 8 标签演示页 |
@@ -288,7 +288,7 @@ pnpm dev # 默认 http://localhost:5173
288
288
  ### 开发命令
289
289
 
290
290
  ```bash
291
- pnpm test # 单测 346 passed
291
+ pnpm test # 单测 407 passed
292
292
  pnpm ts # vue-tsc --noEmit
293
293
  pnpm lint # eslint + stylelint
294
294
  pnpm build # vite lib → vue-tsc 产 d.ts → 产物体检五守卫
package/dist/rj-grid.js CHANGED
@@ -9131,7 +9131,7 @@ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
9131
9131
  actions: {},
9132
9132
  selectedRows: {}
9133
9133
  },
9134
- emits: ["update:modelValue", "search", "action-click"],
9134
+ emits: ["update:modelValue", "search", "reset", "action-click"],
9135
9135
  setup(__props, { emit: __emit }) {
9136
9136
  const props = __props;
9137
9137
  const emit = __emit;
@@ -9214,8 +9214,7 @@ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
9214
9214
  emitList(next);
9215
9215
  }
9216
9216
  function clearAll() {
9217
- emitList([]);
9218
- emit("search");
9217
+ emit("reset");
9219
9218
  }
9220
9219
  function readVal(ev, numeric) {
9221
9220
  const raw = ev.target.value;
@@ -10149,9 +10148,14 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
10149
10148
  showGroupPanel: { type: Boolean, default: true },
10150
10149
  chartable: { type: Boolean, default: true },
10151
10150
  exportable: { type: Boolean, default: true },
10151
+ showPrint: { type: Boolean, default: true },
10152
+ showCsv: { type: Boolean, default: true },
10153
+ showPdf: { type: Boolean, default: true },
10154
+ showExcel: { type: Boolean, default: true },
10152
10155
  colReorder: { type: Boolean, default: true },
10153
10156
  resizable: { type: Boolean, default: true },
10154
10157
  rowSelection: { type: [Boolean, String], default: false },
10158
+ selectOnCellClick: { type: Boolean, default: true },
10155
10159
  keepSelectionCrossPage: { type: Boolean },
10156
10160
  editable: { type: Boolean, default: false },
10157
10161
  rangeSelection: { type: Boolean, default: true },
@@ -10507,6 +10511,11 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
10507
10511
  emit("filter-change");
10508
10512
  dispatchEvent("filterChanged", {});
10509
10513
  }
10514
+ function onQueryReset() {
10515
+ const cur = savedViews.views.value.find((v) => v.id === currentViewId.value);
10516
+ queryConditions.value = cur ? cloneConditions(cur.conditions || []) : [];
10517
+ onQuerySearch();
10518
+ }
10510
10519
  function applyView(v, viewId) {
10511
10520
  var _a2;
10512
10521
  const view = "conditions" in v ? v : null;
@@ -10899,6 +10908,17 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
10899
10908
  }
10900
10909
  notifySelection();
10901
10910
  }
10911
+ function selectRowByClick(d) {
10912
+ if (selection.size === 1 && selection.has(d.key))
10913
+ return;
10914
+ selection.clear();
10915
+ if (props.keepSelectionCrossPage)
10916
+ preserveMap.clear();
10917
+ selection.add(d.key);
10918
+ if (props.keepSelectionCrossPage)
10919
+ preserveMap.set(d.key, d.data);
10920
+ notifySelection();
10921
+ }
10902
10922
  function selectedRows() {
10903
10923
  const rows = rowModel.processed.value.displayRows.filter((d) => selection.has(d.key)).map((d) => d.data);
10904
10924
  Array.from(preserveMap.values()).forEach((r) => {
@@ -12019,6 +12039,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
12019
12039
  colIndex: pos.c,
12020
12040
  column: leaf.col
12021
12041
  });
12042
+ if (props.selectOnCellClick && e.button === 0 && !e.ctrlKey && !e.metaKey && !e.shiftKey && !e.altKey && drow && drow.type === "row" && !(e.target instanceof Element && e.target.closest(".rj-checkbox")))
12043
+ selectRowByClick(drow);
12022
12044
  }
12023
12045
  if (!props.rangeSelection || e.button !== 0 || !pos)
12024
12046
  return;
@@ -13852,6 +13874,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
13852
13874
  actions: _ctx.queryActions,
13853
13875
  "selected-rows": selectedRows(),
13854
13876
  onSearch: onQuerySearch,
13877
+ onReset: onQueryReset,
13855
13878
  onActionClick: runQueryAction
13856
13879
  }, createSlots({ _: 2 }, [
13857
13880
  _ctx.$slots["query-actions"] ? {
@@ -13994,27 +14017,31 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
13994
14017
  class: normalizeClass(["rj-btn", { "is-active": panelOpen.value }]),
13995
14018
  onClick: _cache[16] || (_cache[16] = ($event) => panelOpen.value = !panelOpen.value)
13996
14019
  }, toDisplayString(t("panel")), 3)) : createCommentVNode("", true),
13997
- _ctx.exportable ? (openBlock(), createElementBlock("div", _hoisted_14, [
13998
- createElementVNode("button", {
14020
+ _ctx.exportable && (_ctx.showPrint || _ctx.showCsv || _ctx.showPdf || _ctx.showExcel) ? (openBlock(), createElementBlock("div", _hoisted_14, [
14021
+ _ctx.showPrint ? (openBlock(), createElementBlock("button", {
14022
+ key: 0,
13999
14023
  class: "rj-btn rj-btn-export rj-export-btn",
14000
14024
  "data-tip": t("printTip"),
14001
14025
  onClick: _cache[17] || (_cache[17] = ($event) => openRangeMenu($event, "print"))
14002
- }, toDisplayString(t("printBtn")), 9, _hoisted_15),
14003
- createElementVNode("button", {
14026
+ }, toDisplayString(t("printBtn")), 9, _hoisted_15)) : createCommentVNode("", true),
14027
+ _ctx.showCsv ? (openBlock(), createElementBlock("button", {
14028
+ key: 1,
14004
14029
  class: "rj-btn rj-btn-export rj-export-btn",
14005
14030
  "data-tip": t("csvTip"),
14006
14031
  onClick: _cache[18] || (_cache[18] = ($event) => openRangeMenu($event, "csv"))
14007
- }, " CSV ", 8, _hoisted_16),
14008
- createElementVNode("button", {
14032
+ }, " CSV ", 8, _hoisted_16)) : createCommentVNode("", true),
14033
+ _ctx.showPdf ? (openBlock(), createElementBlock("button", {
14034
+ key: 2,
14009
14035
  class: "rj-btn rj-btn-export rj-export-btn",
14010
14036
  "data-tip": t("pdfTip"),
14011
14037
  onClick: _cache[19] || (_cache[19] = ($event) => openRangeMenu($event, "pdf"))
14012
- }, " PDF ", 8, _hoisted_17),
14013
- createElementVNode("button", {
14038
+ }, " PDF ", 8, _hoisted_17)) : createCommentVNode("", true),
14039
+ _ctx.showExcel ? (openBlock(), createElementBlock("button", {
14040
+ key: 3,
14014
14041
  class: "rj-btn rj-btn-export rj-export-btn",
14015
14042
  "data-tip": t("excelTip"),
14016
14043
  onClick: _cache[20] || (_cache[20] = ($event) => openRangeMenu($event, "excel"))
14017
- }, " Excel ", 8, _hoisted_18)
14044
+ }, " Excel ", 8, _hoisted_18)) : createCommentVNode("", true)
14018
14045
  ])) : createCommentVNode("", true),
14019
14046
  _ctx.stateKey ? (openBlock(), createElementBlock("button", {
14020
14047
  key: 6,
@@ -46,9 +46,16 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<im
46
46
  showGroupPanel?: boolean | undefined;
47
47
  chartable?: boolean | undefined;
48
48
  exportable?: boolean | undefined;
49
+ /** 工具栏各导出/打印按钮单独显隐(仅在 exportable 为真时生效);默认全 true,可按需关掉其中任意几个 */
50
+ showPrint?: boolean | undefined;
51
+ showCsv?: boolean | undefined;
52
+ showPdf?: boolean | undefined;
53
+ showExcel?: boolean | undefined;
49
54
  colReorder?: boolean | undefined;
50
55
  resizable?: boolean | undefined;
51
56
  rowSelection?: false | "multiple" | "single" | undefined;
57
+ /** 单击数据行单元格即选中该行(替换式,无需再点复选框);按住 Ctrl/Shift/Alt 仍走区域选择,复选框保留多选,双击仍编辑。默认 true */
58
+ selectOnCellClick?: boolean | undefined;
52
59
  keepSelectionCrossPage?: boolean | undefined;
53
60
  editable?: boolean | undefined;
54
61
  rangeSelection?: boolean | undefined;
@@ -157,9 +164,14 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<im
157
164
  showGroupPanel: boolean;
158
165
  chartable: boolean;
159
166
  exportable: boolean;
167
+ showPrint: boolean;
168
+ showCsv: boolean;
169
+ showPdf: boolean;
170
+ showExcel: boolean;
160
171
  colReorder: boolean;
161
172
  resizable: boolean;
162
173
  rowSelection: boolean;
174
+ selectOnCellClick: boolean;
163
175
  editable: boolean;
164
176
  rangeSelection: boolean;
165
177
  clipboard: boolean;
@@ -260,9 +272,16 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<im
260
272
  showGroupPanel?: boolean | undefined;
261
273
  chartable?: boolean | undefined;
262
274
  exportable?: boolean | undefined;
275
+ /** 工具栏各导出/打印按钮单独显隐(仅在 exportable 为真时生效);默认全 true,可按需关掉其中任意几个 */
276
+ showPrint?: boolean | undefined;
277
+ showCsv?: boolean | undefined;
278
+ showPdf?: boolean | undefined;
279
+ showExcel?: boolean | undefined;
263
280
  colReorder?: boolean | undefined;
264
281
  resizable?: boolean | undefined;
265
282
  rowSelection?: false | "multiple" | "single" | undefined;
283
+ /** 单击数据行单元格即选中该行(替换式,无需再点复选框);按住 Ctrl/Shift/Alt 仍走区域选择,复选框保留多选,双击仍编辑。默认 true */
284
+ selectOnCellClick?: boolean | undefined;
266
285
  keepSelectionCrossPage?: boolean | undefined;
267
286
  editable?: boolean | undefined;
268
287
  rangeSelection?: boolean | undefined;
@@ -371,9 +390,14 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<im
371
390
  showGroupPanel: boolean;
372
391
  chartable: boolean;
373
392
  exportable: boolean;
393
+ showPrint: boolean;
394
+ showCsv: boolean;
395
+ showPdf: boolean;
396
+ showExcel: boolean;
374
397
  colReorder: boolean;
375
398
  resizable: boolean;
376
399
  rowSelection: boolean;
400
+ selectOnCellClick: boolean;
377
401
  editable: boolean;
378
402
  rangeSelection: boolean;
379
403
  clipboard: boolean;
@@ -465,9 +489,14 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<im
465
489
  showGroupPanel: boolean;
466
490
  chartable: boolean;
467
491
  exportable: boolean;
492
+ showPrint: boolean;
493
+ showCsv: boolean;
494
+ showPdf: boolean;
495
+ showExcel: boolean;
468
496
  colReorder: boolean;
469
497
  resizable: boolean;
470
498
  rowSelection: false | "multiple" | "single";
499
+ selectOnCellClick: boolean;
471
500
  rangeSelection: boolean;
472
501
  clipboard: boolean;
473
502
  contextMenu: boolean | ((ctx: any) => RjMenuItem[]);
@@ -9,6 +9,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<im
9
9
  }>>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
10
10
  "update:modelValue": (v: RjQueryCondition[]) => void;
11
11
  search: () => void;
12
+ reset: () => void;
12
13
  "action-click": (a: RjQueryAction) => void;
13
14
  }, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<__VLS_TypePropsToRuntimeProps<{
14
15
  fields: RjQueryFieldDef[];
@@ -19,6 +20,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<im
19
20
  selectedRows?: RjRowData[] | undefined;
20
21
  }>>> & Readonly<{
21
22
  onSearch?: (() => any) | undefined;
23
+ onReset?: (() => any) | undefined;
22
24
  "onUpdate:modelValue"?: ((v: RjQueryCondition[]) => any) | undefined;
23
25
  "onAction-click"?: ((a: RjQueryAction) => any) | undefined;
24
26
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>, Readonly<{
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rj-grid",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "description": "零第三方依赖的自研 Vue3 虚拟表格:虚拟滚动 / 冻结列 / 行拖拽 / 分组透视 / 公式 / SSRM / 主题 i18n / 自然语言查询",
5
5
  "type": "module",
6
6
  "license": "MIT",