rj-grid 0.2.2 → 0.2.3
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 +328 -98
- package/dist/rj-grid.js +195 -54
- package/dist/style.css +21 -2
- package/dist/types/src/RjContextMenu.vue.d.ts +2 -2
- package/dist/types/src/RjGrid.vue.d.ts +23 -0
- package/dist/types/src/nlq.d.ts +10 -2
- package/dist/types/src/types.d.ts +2 -0
- package/dist/types/src/useColumnState.d.ts +1 -0
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -1,98 +1,328 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="docs/images/01-overview.png" alt="rj-grid 综合功能总览" width="100%" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">rj-grid</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<b>零第三方依赖的企业级 Vue 3 数据网格 —— 对标 AG Grid 的全功能,MIT 免费、gzip 约 93 KB。</b><br/>
|
|
9
|
+
虚拟滚动 · 冻结列 · 分组透视 · 树形 · 编辑撤销 · 公式引擎 · SSRM 服务端行模型 · 主题 & i18n · 打印/CSV/Excel/PDF · 离线自然语言查询(NLQ)
|
|
10
|
+
</p>
|
|
11
|
+
|
|
12
|
+
<p align="center">
|
|
13
|
+
<a href="https://www.npmjs.com/package/rj-grid"><img src="https://img.shields.io/npm/v/rj-grid.svg?logo=npm&color=cb3837" alt="npm version"/></a>
|
|
14
|
+
<a href="https://github.com/rjding/rjGrid"><img src="https://img.shields.io/github/stars/rjding/rjGrid?logo=github&color=181717" alt="GitHub stars"/></a>
|
|
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
|
+
<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
|
+
<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"/>
|
|
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"/>
|
|
21
|
+
<img src="https://img.shields.io/badge/types-TypeScript-blue.svg?logo=typescript" alt="TypeScript"/>
|
|
22
|
+
</p>
|
|
23
|
+
|
|
24
|
+
<p align="center">
|
|
25
|
+
<a href="#-快速开始">快速开始</a> ·
|
|
26
|
+
<a href="#-能力演示">能力演示</a> ·
|
|
27
|
+
<a href="#-与-ag-grid-对比">与 AG Grid 对比</a> ·
|
|
28
|
+
<a href="docs/RjGrid使用手册.md">完整手册</a> ·
|
|
29
|
+
<a href="https://github.com/rjding/rjGrid">GitHub</a> ·
|
|
30
|
+
<a href="https://gitee.com/rjding/rj-grid">Gitee</a> ·
|
|
31
|
+
<a href="README_EN.md">English</a>
|
|
32
|
+
</p>
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 💡 为什么选 rj-grid
|
|
37
|
+
|
|
38
|
+
想象一下:一个 `<rj-grid>` 标签,就能替换掉你项目里那些「几万行就卡死、想加个分组又得换库」的表格——而**不额外引入任何第三方依赖**,也不用给商业表格库交授权费。
|
|
39
|
+
|
|
40
|
+
- **真·零依赖**:运行时只需 `vue`,连可选的图表都是按需 `import('echarts')`。不捆绑、不污染你的 lockfile。
|
|
41
|
+
- **小得离谱**:gzip 约 93 KB,却装下了别人几个库加起来的功能量。
|
|
42
|
+
- **10 万行丝滑**:行列双向虚拟滚动,实测 100,000 行 × 12 列秒开(生成仅约 12 ms)。
|
|
43
|
+
- **对标 AG Grid 全功能**:树形 / 分组 / 透视 / SSRM / 公式 / 主题 / i18n / 导出 / NLQ 一应俱全。
|
|
44
|
+
- **TypeScript 原生**:完整的类型推导与 `.d.ts`,编辑器全程提示,不是「先跑起来再说」的糙活。
|
|
45
|
+
- **免费商用**:MIT 协议,个人和企业都能放心用。
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## ✨ 特性一览
|
|
50
|
+
|
|
51
|
+
| 分类 | 你会得到的能力 |
|
|
52
|
+
|---|---|
|
|
53
|
+
| 渲染 | 行列虚拟滚动(10 万行流畅)、冻结列、多级表头、密度三档、钉行、全宽行 |
|
|
54
|
+
| 数据 | 客户端 / 分页 / 无限滚动 / **SSRM 服务端行模型**(按需块缓存)四种模式 |
|
|
55
|
+
| 分组 | 树形任意深度、拖拽分组、多级分组 + 组页脚聚合、列透视(含高基数护栏) |
|
|
56
|
+
| 编辑 | 8 类编辑器、校验、撤销/重做、批量事务回填、内置新增/编辑行弹窗 |
|
|
57
|
+
| 公式 | 零依赖 Excel 风格公式:`=B2*C2`、`SUM/COUNTIF/SUMIF`、区域引用、循环引用检测 |
|
|
58
|
+
| 筛选 | 列头漏斗 / 浮动筛选行 / 快速搜索 / 高级过滤(跨列 AND/OR 表达式树)四路叠加 |
|
|
59
|
+
| 外观 | 主题引擎(4 预设 × 明暗 × 强调色 × 自定义 CSS 变量)、i18n(中/英 + 文案覆盖)、图标替换 |
|
|
60
|
+
| 输出 | 打印 / CSV / Excel / PDF,支持选中行 / 当前视图 / 后端导出三种范围 |
|
|
61
|
+
| AI | 纯离线确定性 **NLQ**,中英双语随 i18n 切换:中文用「数量大于50 按单价降序」、英文用 `qty > 50 sort by price desc`,回显随语言 |
|
|
62
|
+
| 状态 | `stateKey` 自动持久化 + `getState/setState` 编程式存取,刷新不丢视图 |
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 🚀 快速开始
|
|
67
|
+
|
|
68
|
+
> 三步,两分钟,跑起来。
|
|
69
|
+
|
|
70
|
+
**① 安装**
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
npm install rj-grid
|
|
74
|
+
# 或 pnpm add rj-grid / yarn add rj-grid
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**② 引入组件与样式**
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
// main.ts —— 样式全局引一次即可
|
|
81
|
+
import 'rj-grid/style.css'
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**③ 直接使用**
|
|
85
|
+
|
|
86
|
+
```vue
|
|
87
|
+
<template>
|
|
88
|
+
<rj-grid :columns="cols" :rows="rows" row-key="id" :height="480" show-toolbar />
|
|
89
|
+
</template>
|
|
90
|
+
|
|
91
|
+
<script setup lang="ts">
|
|
92
|
+
import { RjGrid } from 'rj-grid' // ⚠️ 必须「值导入」,不能只写 type
|
|
93
|
+
import type { RjColumn, RjRowData } from 'rj-grid'
|
|
94
|
+
|
|
95
|
+
const cols: RjColumn[] = [
|
|
96
|
+
{ field: 'name', title: '名称', width: 160, filter: 'text' },
|
|
97
|
+
{ field: 'qty', title: '数量', type: 'num', aggFunc: 'sum' },
|
|
98
|
+
{ field: 'price', title: '单价', type: 'money', aggFunc: 'avg' }
|
|
99
|
+
]
|
|
100
|
+
const rows: RjRowData[] = [
|
|
101
|
+
{ id: 1, name: '轴承', qty: 100, price: 12.5 },
|
|
102
|
+
{ id: 2, name: '电机', qty: 30, price: 480 }
|
|
103
|
+
]
|
|
104
|
+
</script>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
`show-toolbar` 一开,冻结列、分组、筛选、导出、列显隐全部自带,无需再写一行代码。想解锁更多能力,加个属性即可 —— 每个特性的完整参数见 [📖 使用手册](docs/RjGrid使用手册.md)。
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## 🎬 能力演示
|
|
112
|
+
|
|
113
|
+
真实产品截图/动图,全部来自 `playground` 演示页:
|
|
114
|
+
|
|
115
|
+
<table>
|
|
116
|
+
<tr>
|
|
117
|
+
<td width="50%">
|
|
118
|
+
<b>🎨 主题引擎 · 4 预设 × 明暗 × 多语言</b><br/>
|
|
119
|
+
<img src="docs/images/theme-cycle.gif" alt="主题切换动画" width="100%"/>
|
|
120
|
+
</td>
|
|
121
|
+
<td width="50%">
|
|
122
|
+
<b>🤖 离线自然语言查询(NLQ)</b><br/>
|
|
123
|
+
输入一句话,自动完成「筛选 + 排序 + 分组」。<br/>
|
|
124
|
+
<img src="docs/images/nlq-query.gif" alt="NLQ 查询动画" width="100%"/>
|
|
125
|
+
</td>
|
|
126
|
+
</tr>
|
|
127
|
+
<tr>
|
|
128
|
+
<td>
|
|
129
|
+
<b>🌲 树形层级 · 一键展开 / 折叠</b><br/>
|
|
130
|
+
<img src="docs/images/tree-expand.gif" alt="树形展开折叠动画" width="100%"/>
|
|
131
|
+
</td>
|
|
132
|
+
<td>
|
|
133
|
+
<b>🔍 快速过滤 · 跨全列即时匹配高亮</b><br/>
|
|
134
|
+
<img src="docs/images/quick-filter.gif" alt="快速过滤动画" width="100%"/>
|
|
135
|
+
</td>
|
|
136
|
+
</tr>
|
|
137
|
+
<tr>
|
|
138
|
+
<td>
|
|
139
|
+
<b>🧮 公式引擎 · Excel 风格零依赖</b><br/>
|
|
140
|
+
<img src="docs/images/15-formula.png" alt="公式列" width="100%"/>
|
|
141
|
+
</td>
|
|
142
|
+
<td>
|
|
143
|
+
<b>📦 内置行编辑 / 新增弹窗 · 由列定义自动生成表单</b><br/>
|
|
144
|
+
<img src="docs/images/08-row-form.png" alt="行弹窗" width="100%"/>
|
|
145
|
+
</td>
|
|
146
|
+
</tr>
|
|
147
|
+
<tr>
|
|
148
|
+
<td>
|
|
149
|
+
<b>📊 分组聚合 + 组页脚</b><br/>
|
|
150
|
+
<img src="docs/images/12-group.png" alt="分组聚合" width="100%"/>
|
|
151
|
+
</td>
|
|
152
|
+
<td>
|
|
153
|
+
<b>⚡ 10 万行虚拟滚动 · 生成仅约 12 ms</b><br/>
|
|
154
|
+
<img src="docs/images/10-perf-100k.png" alt="大数据性能" width="100%"/>
|
|
155
|
+
</td>
|
|
156
|
+
</tr>
|
|
157
|
+
<tr>
|
|
158
|
+
<td>
|
|
159
|
+
<b>↕️ 行拖动 · 拖手柄重排行序</b><br/>
|
|
160
|
+
<img src="docs/images/row-drag.gif" alt="行拖动动画" width="100%"/>
|
|
161
|
+
</td>
|
|
162
|
+
<td>
|
|
163
|
+
<b>⇄ 列拖动 · 列菜单「列」页签拖拽换序(列序实时改变)</b><br/>
|
|
164
|
+
<img src="docs/images/col-drag.gif" alt="列拖动动画" width="100%"/>
|
|
165
|
+
</td>
|
|
166
|
+
</tr>
|
|
167
|
+
<tr>
|
|
168
|
+
<td colspan="2">
|
|
169
|
+
<b>➕ 动态添加查询字段 · queryable 一行代码获得可配置查询栏</b><br/>
|
|
170
|
+
<img src="docs/images/query-field.gif" alt="动态查询字段动画" width="100%"/>
|
|
171
|
+
</td>
|
|
172
|
+
</tr>
|
|
173
|
+
<tr>
|
|
174
|
+
<td width="50%">
|
|
175
|
+
<b>🔎 服务端查询 + 分页 · 条件栏与页器同行</b><br/>
|
|
176
|
+
<img src="docs/images/13-server-pagination.png" alt="服务端查询分页" width="100%"/>
|
|
177
|
+
</td>
|
|
178
|
+
<td width="50%">
|
|
179
|
+
<b>☰ 密度三档 · 一屏看更多 / 宽松易读自由切</b><br/>
|
|
180
|
+
<img src="docs/images/21-density.png" alt="显示密度切换" width="100%"/>
|
|
181
|
+
</td>
|
|
182
|
+
</tr>
|
|
183
|
+
<tr>
|
|
184
|
+
<td width="50%">
|
|
185
|
+
<b>💾 保存视图 · 一键存当前查询/列布局/排序为快照</b><br/>
|
|
186
|
+
<img src="docs/images/save-view.gif" alt="保存视图动画" width="100%"/>
|
|
187
|
+
</td>
|
|
188
|
+
<td width="50%">
|
|
189
|
+
<b>▦ 工具面板 · 列显隐/分组/透视拖拽管理</b><br/>
|
|
190
|
+
<img src="docs/images/panel.gif" alt="工具面板动画" width="100%"/>
|
|
191
|
+
</td>
|
|
192
|
+
</tr>
|
|
193
|
+
<tr>
|
|
194
|
+
<td colspan="2">
|
|
195
|
+
<b>🖨 打印 / 导出 · 前端(选中行/当前视图)+ 后端导出三档可选</b><br/>
|
|
196
|
+
<img src="docs/images/print-export.gif" alt="打印导出范围动画" width="100%"/>
|
|
197
|
+
</td>
|
|
198
|
+
</tr>
|
|
199
|
+
</table>
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## 🔍 与 AG Grid 对比
|
|
204
|
+
|
|
205
|
+
| 维度 | rj-grid | AG Grid |
|
|
206
|
+
|---|---|---|
|
|
207
|
+
| 授权 / 费用 | ✅ MIT 完全免费 | ⚠️ 企业级特性需商业授权 |
|
|
208
|
+
| 第三方运行时依赖 | ✅ 仅 `vue` | ⚠️ 自带框架与模块体系 |
|
|
209
|
+
| gzip 体积 | ✅ 约 93 KB | 显著更大 |
|
|
210
|
+
| Vue 3 原生 | ✅ 值导入即用,非二次封装 | 提供 Vue 封装层 |
|
|
211
|
+
| 离线自然语言查询 | ✅ 内置纯确定性 NLQ | ❌ 无 |
|
|
212
|
+
| 虚拟滚动 / 分组 / 透视 / SSRM / 公式 / 主题 / 导出 | ✅ 全部内置 | ✅ 部分在付费版 |
|
|
213
|
+
|
|
214
|
+
> rj-grid 的定位不是「山寨 AG Grid」,而是给 Vue 项目一个**免费、轻量、开箱即用**的高质量选择。
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## 🧩 数据模式(按需选择)
|
|
219
|
+
|
|
220
|
+
```vue
|
|
221
|
+
<!-- 客户端:全量入 rows,排序/筛选/分组全在浏览器,虚拟滚动扛 10 万行 -->
|
|
222
|
+
<rj-grid :columns="cols" :rows="rows" row-key="id" />
|
|
223
|
+
|
|
224
|
+
<!-- 分页:后端分页,loadData 自动携带排序/筛选/页码,分页器位置由 pager-position 决定 -->
|
|
225
|
+
<rj-grid :columns="cols" data-mode="pagination" :load-data="loadData" :page-size="20" />
|
|
226
|
+
|
|
227
|
+
<!-- 无限滚动:滚动到底按块续取,无页码 -->
|
|
228
|
+
<rj-grid :columns="cols" data-mode="infinite" :load-data="loadData" />
|
|
229
|
+
|
|
230
|
+
<!-- SSRM 服务端行模型:分组/大数据块缓存,按需分块加载 -->
|
|
231
|
+
<rj-grid :columns="cols" data-mode="serverSide" :load-data="loadData" server-side-grouping />
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
```ts
|
|
235
|
+
import type { RjLoadServerParams } from 'rj-grid'
|
|
236
|
+
// params 自动带 start/end/page/pageSize/sort/filters/quickFilterText/rowGroup…,平铺给后端即可
|
|
237
|
+
async function loadData(p: RjLoadServerParams) {
|
|
238
|
+
const res = await api.queryPage(p)
|
|
239
|
+
return { rows: res.list, total: res.total, success: true }
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
各模式的完整配置与回调签名见 [手册 §6 数据模式](docs/RjGrid使用手册.md)。
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## 🛠 兼容性与技术栈
|
|
248
|
+
|
|
249
|
+
- **框架**:Vue `^3.4.0`(唯一必装 peer 依赖)
|
|
250
|
+
- **可选**:`echarts >= 5.0.0`(仅「集成图表」对话框用到,未安装时优雅降级不崩页)
|
|
251
|
+
- **语言**:TypeScript 全量类型,`.d.ts` 随包发布
|
|
252
|
+
- **样式**:单一 `rj-grid/style.css`,主题走 CSS 变量,可按需覆盖
|
|
253
|
+
- **构建**:Vite 库模式 ESM 单文件,`sideEffects` 仅 CSS,Tree-shaking 友好
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## 🖥 本地运行演示页
|
|
258
|
+
|
|
259
|
+
演示页(`playground/`)独立起服、不依赖宿主项目,8 个标签就是能力地图:
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
git clone https://github.com/rjding/rjGrid.git # 国内可用镜像:git clone https://gitee.com/rjding/rj-grid.git
|
|
263
|
+
cd rjGrid
|
|
264
|
+
pnpm install
|
|
265
|
+
pnpm dev # 默认 http://localhost:5173
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
> ① 综合功能 ② 大数据性能 ③ 树形/分组/透视 ④ 服务端模式 ⑤ SSRM 块缓存 ⑥ 公式引擎 ⑦ 主题 & 国际化 ⑧ AI 自然语言查询
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
<details>
|
|
273
|
+
<summary><b>📚 维护者信息(仓库结构 / 开发命令 / 发布纪律)</b></summary>
|
|
274
|
+
|
|
275
|
+
### 仓库布局
|
|
276
|
+
|
|
277
|
+
| 路径 | 作用 |
|
|
278
|
+
|---|---|
|
|
279
|
+
| `index.ts` | 包入口(值导出 `RjGrid` + NLQ / 查询条件内核 + 全部公共类型) |
|
|
280
|
+
| `src/` | 组件与引擎源码(`src/types.ts` 是类型权威) |
|
|
281
|
+
| `__tests__/` | 346 个单测用例,入口 `__tests__/run.ts` |
|
|
282
|
+
| `build/rjDistCheck.mjs` | 产物体检五守卫(构建末尾自动跑) |
|
|
283
|
+
| `vite.lib.config.ts` | 库构建:ESM 单文件 + 单 `style.css`,external `vue`/`echarts`,不出 sourcemap |
|
|
284
|
+
| `playground/` | 8 标签演示页 |
|
|
285
|
+
| `docs/RjGrid使用手册.md` | 完整使用手册(能力、API、坑与边界) |
|
|
286
|
+
| `dist/` | 发布产物,随库入库 |
|
|
287
|
+
|
|
288
|
+
### 开发命令
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
pnpm test # 单测 346 passed
|
|
292
|
+
pnpm ts # vue-tsc --noEmit
|
|
293
|
+
pnpm lint # eslint + stylelint
|
|
294
|
+
pnpm build # vite lib → vue-tsc 产 d.ts → 产物体检五守卫
|
|
295
|
+
pnpm size # 体积报告
|
|
296
|
+
pnpm dev # playground 演示页
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### 发布新版本
|
|
300
|
+
|
|
301
|
+
改完源码 → `npm version patch|minor|major`(自动 bump + commit + tag)→ `git push --follow-tags` → `npm publish`(`prepublishOnly` 会自动 `pnpm build && pnpm test`,杜绝发出旧 dist)。
|
|
302
|
+
|
|
303
|
+
### 宿主接入补充
|
|
304
|
+
|
|
305
|
+
- 从 npm 安装目录名规范(`node_modules/rj-grid`),样式可直接 `import 'rj-grid/style.css'`。
|
|
306
|
+
- 组件侧必须**值导入** `import { RjGrid } from 'rj-grid'`,只写 type 导入会在运行期报 `Failed to resolve component: rj-grid`。
|
|
307
|
+
- 走 git URL 时 pnpm 会把依赖装进带 `#<commit>` 的目录名,vite 资源 URL 含裸 `#` 会被当片段丢掉 → dev 下 404,此时用 CSS `@import` 垫片(详见手册 §15.4)。
|
|
308
|
+
- `dist` 入库仅为兼容 git URL 安装路径;`sourcemap: false` 是源码保护而非可选项,产物五守卫同时在把关。
|
|
309
|
+
|
|
310
|
+
</details>
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
## 🤝 贡献
|
|
315
|
+
|
|
316
|
+
欢迎 Issue 与 PR:提 bug、要特性、补文档都行。改动请附带相应单测,保证 `pnpm test && pnpm ts && pnpm lint && pnpm build` 全绿。
|
|
317
|
+
|
|
318
|
+
## 📄 许可证
|
|
319
|
+
|
|
320
|
+
[MIT](LICENSE) — 个人与企业均可免费使用、修改与再分发。
|
|
321
|
+
|
|
322
|
+
## ☕ 支持作者
|
|
323
|
+
|
|
324
|
+
如果 rj-grid 帮到了你,欢迎点个 ⭐ Star,或请作者喝杯咖啡:
|
|
325
|
+
|
|
326
|
+
<p align="center">
|
|
327
|
+
<img src="docs/88888.png" alt="小小支援,大大的爱" width="240"/>
|
|
328
|
+
</p>
|
package/dist/rj-grid.js
CHANGED
|
@@ -564,6 +564,9 @@ function useColumnState(sourceColumns) {
|
|
|
564
564
|
widthMap.set(colIdOf(c), clampWidth(Math.round(cur[i] * factor), c));
|
|
565
565
|
});
|
|
566
566
|
}
|
|
567
|
+
function clearWidths() {
|
|
568
|
+
widthMap.clear();
|
|
569
|
+
}
|
|
567
570
|
function moveColumn(dragId, targetId) {
|
|
568
571
|
if (dragId === targetId)
|
|
569
572
|
return;
|
|
@@ -637,6 +640,7 @@ function useColumnState(sourceColumns) {
|
|
|
637
640
|
setAutoWidth,
|
|
638
641
|
hasSizedWidth,
|
|
639
642
|
sizeToFit,
|
|
643
|
+
clearWidths,
|
|
640
644
|
moveColumn,
|
|
641
645
|
togglePin,
|
|
642
646
|
toggleHide,
|
|
@@ -4058,6 +4062,7 @@ const zhCN = {
|
|
|
4058
4062
|
expServerNoPdf: "后端导出不含 PDF(浏览器打印属前端渲染),已改用前端范围",
|
|
4059
4063
|
expServerMissing: "未接入后端导出:请设置 serverExport 回调",
|
|
4060
4064
|
expFailed: "导出失败",
|
|
4065
|
+
printCap: "数据量较大:仅打印前 {n} 行(共 {total} 行)。请缩小范围或走后端导出获取全量",
|
|
4061
4066
|
resetState: "重置列状态",
|
|
4062
4067
|
groupBanner: "⬇ 将列标题拖到此处进行行分组(或点面板“分组”页签)",
|
|
4063
4068
|
// 加载 / 空态
|
|
@@ -4222,6 +4227,7 @@ const zhCN = {
|
|
|
4222
4227
|
querySearch: "查询",
|
|
4223
4228
|
queryReset: "重置",
|
|
4224
4229
|
querySaveView: "存为视图",
|
|
4230
|
+
queryRemove: "移除该条件",
|
|
4225
4231
|
queryInput: "请输入",
|
|
4226
4232
|
// 行编辑弹窗与内置确认框(查询栏操作按钮)
|
|
4227
4233
|
rowFormTitle: "编辑行",
|
|
@@ -4294,6 +4300,7 @@ const enUS = {
|
|
|
4294
4300
|
expServerNoPdf: "Server export has no PDF (browser printing is front-end); fell back to a front-end range",
|
|
4295
4301
|
expServerMissing: "No server export wired up: provide a serverExport callback",
|
|
4296
4302
|
expFailed: "Export failed",
|
|
4303
|
+
printCap: "Large data set: printing the first {n} of {total} rows only. Narrow the range or use Server export for the full set",
|
|
4297
4304
|
resetState: "Reset column state",
|
|
4298
4305
|
groupBanner: "⬇ Drag column headers here to group rows (or Panel → Group)",
|
|
4299
4306
|
loading: "Loading…",
|
|
@@ -4444,6 +4451,7 @@ const enUS = {
|
|
|
4444
4451
|
querySearch: "Search",
|
|
4445
4452
|
queryReset: "Reset",
|
|
4446
4453
|
querySaveView: "Save as view",
|
|
4454
|
+
queryRemove: "Remove this condition",
|
|
4447
4455
|
queryInput: "Enter",
|
|
4448
4456
|
// Row edit dialog & built-in confirm (query bar action buttons)
|
|
4449
4457
|
rowFormTitle: "Edit Row",
|
|
@@ -4879,7 +4887,9 @@ function parseNLQ(text, columns) {
|
|
|
4879
4887
|
return { ...empty, message: "empty" };
|
|
4880
4888
|
const result = { ok: false, filters: [], clauses: [] };
|
|
4881
4889
|
let buf = raw;
|
|
4882
|
-
const lim = buf.match(
|
|
4890
|
+
const lim = buf.match(
|
|
4891
|
+
/(?:前|取|返回|最多|top|first|limit|show(?:\s+me)?|give\s+me)\s*(?:the\s+)?(\d+)\s*(?:行|条|个|名|件|rows?|records?|items?|results?)?/i
|
|
4892
|
+
);
|
|
4883
4893
|
if (lim) {
|
|
4884
4894
|
result.limit = parseInt(lim[1], 10);
|
|
4885
4895
|
buf = blank(buf, lim.index, lim[0].length);
|
|
@@ -4903,6 +4913,7 @@ function parseNLQ(text, columns) {
|
|
|
4903
4913
|
if (col) {
|
|
4904
4914
|
result.groupBy = col.field || col.title || col.colId;
|
|
4905
4915
|
result.groupColId = col.colId;
|
|
4916
|
+
result.groupTitle = col.title || col.field || col.colId;
|
|
4906
4917
|
buf = blank(buf, g.start, g.len);
|
|
4907
4918
|
}
|
|
4908
4919
|
}
|
|
@@ -4911,14 +4922,21 @@ function parseNLQ(text, columns) {
|
|
|
4911
4922
|
/sort\s*by\s+([^,,、;;]+)/i,
|
|
4912
4923
|
/([^,,、;;\s]+?)(?:升序|降序|倒序|从大到小|从小到大)/i,
|
|
4913
4924
|
// 比较级:X最高/最低/最大/最小/最贵/最便宜/最多/最少(可带尾随「的」一并消费,避免泄漏进相邻筛选值)
|
|
4914
|
-
/([^,,、;;\s]+?)最(?:高|低|大|小|贵|便宜|多|少)的?/i
|
|
4925
|
+
/([^,,、;;\s]+?)最(?:高|低|大|小|贵|便宜|多|少)的?/i,
|
|
4926
|
+
// 英文比较级(后缀式):X highest / X most expensive / X cheapest(不含裸 most/least,以免吞掉 at most/at least)
|
|
4927
|
+
/([a-z][a-z ]*?)\s+(?:the\s+)?(?:highest|lowest|largest|biggest|smallest|most expensive|least expensive|cheapest)\b/i,
|
|
4928
|
+
// 英文比较级(前缀式):highest X / cheapest X
|
|
4929
|
+
/\b(?:highest|lowest|largest|biggest|smallest|most expensive|cheapest|least expensive)\s+(?:the\s+)?([a-z][a-z ]*?)(?=$|[,,、;;.]|\s+(?:and|by|of)\b)/i
|
|
4915
4930
|
]);
|
|
4916
4931
|
if (s) {
|
|
4917
4932
|
const col = resolveColumn(s.name, columns);
|
|
4918
4933
|
if (col) {
|
|
4919
4934
|
const dirWord = (s.word || "").toLowerCase();
|
|
4920
|
-
const desc = /降序|倒序|从大到小|desc
|
|
4935
|
+
const desc = /降序|倒序|从大到小|desc|最高|最大|最贵|最多|highest|largest|biggest|most expensive/.test(
|
|
4936
|
+
dirWord
|
|
4937
|
+
);
|
|
4921
4938
|
result.sort = { field: col.field || col.colId, dir: desc ? "desc" : "asc" };
|
|
4939
|
+
result.sortTitle = col.title || col.field || col.colId;
|
|
4922
4940
|
buf = blank(buf, s.start, s.len);
|
|
4923
4941
|
}
|
|
4924
4942
|
}
|
|
@@ -5154,21 +5172,72 @@ function mergeClauses(clauses, columns) {
|
|
|
5154
5172
|
}
|
|
5155
5173
|
return out;
|
|
5156
5174
|
}
|
|
5157
|
-
|
|
5175
|
+
const OP_LABEL = {
|
|
5176
|
+
zh: {
|
|
5177
|
+
eq: "=",
|
|
5178
|
+
ne: "≠",
|
|
5179
|
+
gt: ">",
|
|
5180
|
+
gte: "≥",
|
|
5181
|
+
lt: "<",
|
|
5182
|
+
lte: "≤",
|
|
5183
|
+
contains: "包含",
|
|
5184
|
+
notContains: "不包含",
|
|
5185
|
+
startsWith: "开头是",
|
|
5186
|
+
endsWith: "结尾为",
|
|
5187
|
+
blank: "为空",
|
|
5188
|
+
notBlank: "非空",
|
|
5189
|
+
in: "属于",
|
|
5190
|
+
notIn: "不属于",
|
|
5191
|
+
inRange: "介于"
|
|
5192
|
+
},
|
|
5193
|
+
en: {
|
|
5194
|
+
eq: "=",
|
|
5195
|
+
ne: "≠",
|
|
5196
|
+
gt: ">",
|
|
5197
|
+
gte: "≥",
|
|
5198
|
+
lt: "<",
|
|
5199
|
+
lte: "≤",
|
|
5200
|
+
contains: "contains",
|
|
5201
|
+
notContains: "not contains",
|
|
5202
|
+
startsWith: "starts with",
|
|
5203
|
+
endsWith: "ends with",
|
|
5204
|
+
blank: "is empty",
|
|
5205
|
+
notBlank: "is not empty",
|
|
5206
|
+
in: "is",
|
|
5207
|
+
notIn: "not",
|
|
5208
|
+
inRange: "between"
|
|
5209
|
+
}
|
|
5210
|
+
};
|
|
5211
|
+
function explainNLQ(r, lang = "zh") {
|
|
5212
|
+
const en = lang === "en";
|
|
5213
|
+
const labels = OP_LABEL[lang];
|
|
5158
5214
|
const parts = [];
|
|
5159
5215
|
for (const c of r.clauses) {
|
|
5160
|
-
const
|
|
5161
|
-
|
|
5216
|
+
const opLabel = labels[c.op] || c.op;
|
|
5217
|
+
const name = c.title || c.field || c.colId;
|
|
5218
|
+
let val;
|
|
5219
|
+
if (c.op === "blank" || c.op === "notBlank")
|
|
5220
|
+
val = "";
|
|
5221
|
+
else if (c.value2 != null)
|
|
5222
|
+
val = `${c.value1}~${c.value2}`;
|
|
5223
|
+
else if (Array.isArray(c.value1))
|
|
5224
|
+
val = c.value1.join(en ? " / " : "、");
|
|
5225
|
+
else
|
|
5226
|
+
val = String(c.value1 ?? "");
|
|
5227
|
+
const glue = en || /^[=<>≤≥≠]/.test(opLabel) ? " " : "";
|
|
5228
|
+
parts.push(`${name} ${opLabel}${glue}${val}`.trim());
|
|
5162
5229
|
}
|
|
5163
5230
|
if (r.sort)
|
|
5164
|
-
parts.push(
|
|
5231
|
+
parts.push(
|
|
5232
|
+
en ? `sort by ${r.sortTitle || r.sort.field} ${r.sort.dir}` : `按${r.sortTitle || r.sort.field} ${r.sort.dir === "desc" ? "降序" : "升序"}`
|
|
5233
|
+
);
|
|
5165
5234
|
if (r.groupBy)
|
|
5166
|
-
parts.push(`group ${r.groupBy}`);
|
|
5235
|
+
parts.push(en ? `group by ${r.groupTitle || r.groupBy}` : `按${r.groupTitle || r.groupBy}分组`);
|
|
5167
5236
|
if (r.limit)
|
|
5168
|
-
parts.push(`top ${r.limit}`);
|
|
5237
|
+
parts.push(en ? `top ${r.limit}` : `前${r.limit}`);
|
|
5169
5238
|
if (r.search)
|
|
5170
|
-
parts.push(`search "${r.search}"`);
|
|
5171
|
-
return parts.join("
|
|
5239
|
+
parts.push(en ? `search "${r.search}"` : `搜索“${r.search}”`);
|
|
5240
|
+
return parts.join(" · ");
|
|
5172
5241
|
}
|
|
5173
5242
|
const csvCell = (v) => {
|
|
5174
5243
|
if (v == null)
|
|
@@ -7694,7 +7763,7 @@ const _sfc_main$a = /* @__PURE__ */ defineComponent({
|
|
|
7694
7763
|
onMounted(() => {
|
|
7695
7764
|
const el = menuRef.value;
|
|
7696
7765
|
if (el)
|
|
7697
|
-
emit("reposition", el.offsetHeight);
|
|
7766
|
+
emit("reposition", el.offsetHeight, el.offsetWidth);
|
|
7698
7767
|
});
|
|
7699
7768
|
const hoverIdx = ref(-1);
|
|
7700
7769
|
function onClick(item) {
|
|
@@ -9026,7 +9095,7 @@ const _hoisted_3$4 = ["value", "onChange"];
|
|
|
9026
9095
|
const _hoisted_4$3 = ["value"];
|
|
9027
9096
|
const _hoisted_5$3 = ["value", "placeholder", "onInput"];
|
|
9028
9097
|
const _hoisted_6$3 = ["value", "placeholder", "onInput"];
|
|
9029
|
-
const _hoisted_7$2 = ["onClick"];
|
|
9098
|
+
const _hoisted_7$2 = ["title", "onClick"];
|
|
9030
9099
|
const _hoisted_8$2 = {
|
|
9031
9100
|
value: "",
|
|
9032
9101
|
disabled: ""
|
|
@@ -9259,7 +9328,7 @@ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
|
|
|
9259
9328
|
}, null, 40, _hoisted_6$3)),
|
|
9260
9329
|
createElementVNode("span", {
|
|
9261
9330
|
class: "rj-query-del",
|
|
9262
|
-
title: "
|
|
9331
|
+
title: unref(t)("queryRemove"),
|
|
9263
9332
|
onClick: ($event) => remove(i)
|
|
9264
9333
|
}, "✕", 8, _hoisted_7$2)
|
|
9265
9334
|
]);
|
|
@@ -9849,6 +9918,7 @@ function buildPrintHtml(input, opts = {}) {
|
|
|
9849
9918
|
const headBg = o.headerDark ? "#4472c4" : "#eef1f6";
|
|
9850
9919
|
const headColor = o.headerDark ? "#ffffff" : "#1f2329";
|
|
9851
9920
|
const zebraRule = o.zebra ? "tbody tr:nth-child(even) td{background:#f7f9fc}" : "";
|
|
9921
|
+
const rowBreakRule = input.matrix.length > 300 ? "tr { break-inside: auto; page-break-inside: auto; }" : "tr { page-break-inside: avoid; break-inside: avoid; }";
|
|
9852
9922
|
const style = `
|
|
9853
9923
|
@page { ${pageBox} margin: ${o.margins}mm; }
|
|
9854
9924
|
${o.pageNumbers ? `@page { @bottom-center { content: ${pageContentCss(o.pageNumberText)}; font-size: 10px; color: #999; } }` : ""}
|
|
@@ -9860,7 +9930,7 @@ body { font-family: -apple-system, "Segoe UI", "Microsoft YaHei", Arial, sans-se
|
|
|
9860
9930
|
.rj-print-sub { font-size: 12px; color: #666; margin: 0 0 10px; }
|
|
9861
9931
|
table { border-collapse: collapse; width: 100%; table-layout: ${o.scaleToFit ? "auto" : "fixed"}; font-size: 12px; }
|
|
9862
9932
|
thead { display: table-header-group; }
|
|
9863
|
-
|
|
9933
|
+
${rowBreakRule}
|
|
9864
9934
|
th, td { border: ${border}; padding: 4px 8px; text-align: left; vertical-align: top; word-break: break-word; }
|
|
9865
9935
|
thead th { background: ${headBg}; color: ${headColor}; font-weight: 600; text-align: center; }
|
|
9866
9936
|
${zebraRule}
|
|
@@ -9948,19 +10018,19 @@ const _hoisted_7 = {
|
|
|
9948
10018
|
};
|
|
9949
10019
|
const _hoisted_8 = { key: 0 };
|
|
9950
10020
|
const _hoisted_9 = ["onClick"];
|
|
9951
|
-
const _hoisted_10 = ["
|
|
9952
|
-
const _hoisted_11 = ["
|
|
9953
|
-
const _hoisted_12 = ["
|
|
9954
|
-
const _hoisted_13 = ["
|
|
10021
|
+
const _hoisted_10 = ["data-tip", "aria-label"];
|
|
10022
|
+
const _hoisted_11 = ["data-tip", "aria-label"];
|
|
10023
|
+
const _hoisted_12 = ["data-tip", "aria-label"];
|
|
10024
|
+
const _hoisted_13 = ["data-tip", "aria-label"];
|
|
9955
10025
|
const _hoisted_14 = {
|
|
9956
10026
|
key: 5,
|
|
9957
10027
|
class: "rj-export-group"
|
|
9958
10028
|
};
|
|
9959
|
-
const _hoisted_15 = ["
|
|
9960
|
-
const _hoisted_16 = ["
|
|
9961
|
-
const _hoisted_17 = ["
|
|
9962
|
-
const _hoisted_18 = ["
|
|
9963
|
-
const _hoisted_19 = ["
|
|
10029
|
+
const _hoisted_15 = ["data-tip"];
|
|
10030
|
+
const _hoisted_16 = ["data-tip"];
|
|
10031
|
+
const _hoisted_17 = ["data-tip"];
|
|
10032
|
+
const _hoisted_18 = ["data-tip"];
|
|
10033
|
+
const _hoisted_19 = ["data-tip", "aria-label"];
|
|
9964
10034
|
const _hoisted_20 = { style: { "display": "flex", "flex": "1", "min-height": "0" } };
|
|
9965
10035
|
const _hoisted_21 = ["role"];
|
|
9966
10036
|
const _hoisted_22 = ["aria-rowindex", "aria-selected", "data-rk"];
|
|
@@ -10112,6 +10182,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
10112
10182
|
exportRange: { default: "auto" },
|
|
10113
10183
|
serverExport: {},
|
|
10114
10184
|
exportFileName: {},
|
|
10185
|
+
printMaxRows: { default: 1e3 },
|
|
10115
10186
|
exportRawValues: { type: Boolean },
|
|
10116
10187
|
statusBar: { type: Boolean, default: true },
|
|
10117
10188
|
statusAggregations: { default: () => ["sum", "avg", "count", "min", "max"] },
|
|
@@ -10508,6 +10579,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
10508
10579
|
const quickPop = ref(null);
|
|
10509
10580
|
const quickInputRef = ref();
|
|
10510
10581
|
function toggleQuickPop(ev) {
|
|
10582
|
+
tip.value = null;
|
|
10511
10583
|
if (quickPop.value) {
|
|
10512
10584
|
quickPop.value = null;
|
|
10513
10585
|
return;
|
|
@@ -12590,25 +12662,50 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
12590
12662
|
}));
|
|
12591
12663
|
});
|
|
12592
12664
|
const menu = ref(null);
|
|
12593
|
-
|
|
12665
|
+
const tip = ref(null);
|
|
12666
|
+
function onTipOver(e) {
|
|
12667
|
+
var _a2, _b;
|
|
12668
|
+
const host = e.currentTarget;
|
|
12669
|
+
const el = (_b = (_a2 = e.target) == null ? void 0 : _a2.closest) == null ? void 0 : _b.call(_a2, "[data-tip]");
|
|
12670
|
+
if (!el || !host.contains(el))
|
|
12671
|
+
return;
|
|
12672
|
+
const r = el.getBoundingClientRect();
|
|
12673
|
+
tip.value = { text: el.getAttribute("data-tip") || "", x: r.right, y: r.bottom + 6 };
|
|
12674
|
+
}
|
|
12675
|
+
function onTipOut(e) {
|
|
12676
|
+
var _a2, _b;
|
|
12677
|
+
const el = (_b = (_a2 = e.target) == null ? void 0 : _a2.closest) == null ? void 0 : _b.call(_a2, "[data-tip]");
|
|
12678
|
+
const to = e.relatedTarget;
|
|
12679
|
+
if (el && to && el.contains(to))
|
|
12680
|
+
return;
|
|
12681
|
+
tip.value = null;
|
|
12682
|
+
}
|
|
12683
|
+
function openMenuAt(x, y, items, above, estW = 220) {
|
|
12594
12684
|
if (!items.length)
|
|
12595
12685
|
return;
|
|
12686
|
+
tip.value = null;
|
|
12596
12687
|
const est = items.length * 28 + 16;
|
|
12597
12688
|
const bottom = window.innerHeight - 8;
|
|
12689
|
+
const xc = Math.max(8, Math.min(x, window.innerWidth - estW - 8));
|
|
12598
12690
|
if (y + est <= bottom) {
|
|
12599
|
-
menu.value = { items, x, y, limit: bottom };
|
|
12691
|
+
menu.value = { items, x: xc, y, limit: bottom };
|
|
12600
12692
|
return;
|
|
12601
12693
|
}
|
|
12602
12694
|
const lim = (above ?? y) - 6;
|
|
12603
|
-
menu.value = { items, x, y: Math.max(8, (above ?? y) - est - 8), limit: lim };
|
|
12695
|
+
menu.value = { items, x: xc, y: Math.max(8, (above ?? y) - est - 8), limit: lim };
|
|
12604
12696
|
}
|
|
12605
|
-
function onMenuReposition(h2) {
|
|
12697
|
+
function onMenuReposition(h2, w) {
|
|
12606
12698
|
const m = menu.value;
|
|
12607
12699
|
if (!m)
|
|
12608
12700
|
return;
|
|
12609
12701
|
const lim = m.limit ?? window.innerHeight - 8;
|
|
12702
|
+
const next = { ...m };
|
|
12610
12703
|
if (m.y + h2 > lim)
|
|
12611
|
-
|
|
12704
|
+
next.y = Math.max(8, lim - h2);
|
|
12705
|
+
if (w && m.x + w > window.innerWidth - 8)
|
|
12706
|
+
next.x = Math.max(8, window.innerWidth - 8 - w);
|
|
12707
|
+
if (next.y !== m.y || next.x !== m.x)
|
|
12708
|
+
menu.value = next;
|
|
12612
12709
|
}
|
|
12613
12710
|
function onMenuSelect(item) {
|
|
12614
12711
|
var _a2;
|
|
@@ -12890,7 +12987,9 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
12890
12987
|
{ isSeparator: true },
|
|
12891
12988
|
{ name: t("scopeServer"), action: () => callServerExport(fmt) }
|
|
12892
12989
|
);
|
|
12893
|
-
|
|
12990
|
+
const el = ev.currentTarget;
|
|
12991
|
+
const r = el.getBoundingClientRect();
|
|
12992
|
+
openMenuAt(r.left, r.bottom + 6, items, r.top);
|
|
12894
12993
|
}
|
|
12895
12994
|
function runFormat(fmt, scope) {
|
|
12896
12995
|
if (fmt === "print")
|
|
@@ -13010,7 +13109,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
13010
13109
|
return v.join(" ");
|
|
13011
13110
|
return displayOf(col, v, row, 0);
|
|
13012
13111
|
}
|
|
13013
|
-
function buildPrintInput(params) {
|
|
13112
|
+
function buildPrintInput(params, limit = 0) {
|
|
13014
13113
|
const cols = exportColumnsOf(params);
|
|
13015
13114
|
const columns = cols.map((c) => {
|
|
13016
13115
|
var _a2;
|
|
@@ -13022,26 +13121,32 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
13022
13121
|
});
|
|
13023
13122
|
const matrix = [];
|
|
13024
13123
|
const rowStyles = [];
|
|
13124
|
+
const capped = limit > 0;
|
|
13125
|
+
const full = () => capped && matrix.length >= limit;
|
|
13025
13126
|
const pushRow = (d, kind) => {
|
|
13026
13127
|
matrix.push(cols.map((c) => printTextOf(c, d.data)));
|
|
13027
13128
|
rowStyles.push(kind);
|
|
13028
13129
|
};
|
|
13029
13130
|
const scope = scopeOf(params);
|
|
13030
13131
|
if (scope === "view") {
|
|
13031
|
-
rowModel.processed.value.displayRows
|
|
13132
|
+
for (const d of rowModel.processed.value.displayRows) {
|
|
13133
|
+
if (full())
|
|
13134
|
+
break;
|
|
13032
13135
|
if (d.type === "group" && !d.isFooter)
|
|
13033
13136
|
pushRow(d, 1);
|
|
13034
13137
|
else if (d.type === "row")
|
|
13035
13138
|
pushRow(d, 0);
|
|
13036
|
-
}
|
|
13139
|
+
}
|
|
13037
13140
|
} else {
|
|
13038
|
-
pickExportRows(scope, exportRowSource(), false)
|
|
13141
|
+
for (const r of pickExportRows(scope, exportRowSource(), false)) {
|
|
13142
|
+
if (full())
|
|
13143
|
+
break;
|
|
13039
13144
|
matrix.push(cols.map((c) => printTextOf(c, r)));
|
|
13040
13145
|
rowStyles.push(0);
|
|
13041
|
-
}
|
|
13146
|
+
}
|
|
13042
13147
|
}
|
|
13043
13148
|
const srow = rowModel.summaryRow.value;
|
|
13044
|
-
if (scope === "view" && props.showSummary && srow) {
|
|
13149
|
+
if (scope === "view" && props.showSummary && srow && !full()) {
|
|
13045
13150
|
matrix.push(
|
|
13046
13151
|
cols.map((c) => {
|
|
13047
13152
|
const raw = srow[colIdOf(c)] ?? cellRawValue(c, srow);
|
|
@@ -13079,8 +13184,22 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
13079
13184
|
warnIfLoadedOnly(scopeOf(params));
|
|
13080
13185
|
withExportBusy(() => runPrint(params));
|
|
13081
13186
|
}
|
|
13187
|
+
function printRowEstimate(scope) {
|
|
13188
|
+
if (scope === "view")
|
|
13189
|
+
return rowModel.processed.value.displayRows.reduce(
|
|
13190
|
+
(n, d) => n + (d.type === "row" || d.type === "group" && !d.isFooter ? 1 : 0),
|
|
13191
|
+
0
|
|
13192
|
+
);
|
|
13193
|
+
return pickExportRows(scope, exportRowSource(), false).length;
|
|
13194
|
+
}
|
|
13082
13195
|
function runPrint(params) {
|
|
13083
|
-
|
|
13196
|
+
const cap = props.printMaxRows;
|
|
13197
|
+
const total = printRowEstimate(scopeOf(params));
|
|
13198
|
+
const limit = cap > 0 && total > cap ? cap : 0;
|
|
13199
|
+
const input = buildPrintInput(params, limit);
|
|
13200
|
+
if (limit)
|
|
13201
|
+
showToast(t("printCap", { n: cap, total }));
|
|
13202
|
+
printHtml(input, printOpts(params));
|
|
13084
13203
|
}
|
|
13085
13204
|
const rowGroupPayload = computed(() => {
|
|
13086
13205
|
void aggRev.value;
|
|
@@ -13575,6 +13694,13 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
13575
13694
|
scheduleSave();
|
|
13576
13695
|
dispatchEvent("columnEverythingChanged", {});
|
|
13577
13696
|
},
|
|
13697
|
+
/** 清除宽度覆盖:把列宽还原到列定义/内容自适应默认值(配合 autoSizeAll 做「自适应↔还原」切换) */
|
|
13698
|
+
resetColumnWidths: () => {
|
|
13699
|
+
colState.clearWidths();
|
|
13700
|
+
applyDefaultAutoWidths();
|
|
13701
|
+
scheduleSave();
|
|
13702
|
+
dispatchEvent("columnEverythingChanged", {});
|
|
13703
|
+
},
|
|
13578
13704
|
// 主题 / i18n(运行时切换)
|
|
13579
13705
|
setTheme: (params) => {
|
|
13580
13706
|
themeState.value = { ...params };
|
|
@@ -13816,18 +13942,24 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
13816
13942
|
onDragover: _cache[21] || (_cache[21] = withModifiers(() => {
|
|
13817
13943
|
}, ["stop"])),
|
|
13818
13944
|
onDrop: _cache[22] || (_cache[22] = withModifiers(() => {
|
|
13819
|
-
}, ["stop"]))
|
|
13945
|
+
}, ["stop"])),
|
|
13946
|
+
onPointerover: onTipOver,
|
|
13947
|
+
onPointerout: onTipOut,
|
|
13948
|
+
onFocusin: onTipOver,
|
|
13949
|
+
onFocusout: onTipOut
|
|
13820
13950
|
}, [
|
|
13821
13951
|
_ctx.quickFilterEnabled ? (openBlock(), createElementBlock("button", {
|
|
13822
13952
|
key: 0,
|
|
13823
13953
|
class: normalizeClass(["rj-btn rj-tool-btn rj-quick-btn", { "is-active": !!unref(rowModel).quickFilter.value }]),
|
|
13824
|
-
|
|
13954
|
+
"data-tip": t("quickBtn"),
|
|
13955
|
+
"aria-label": t("quickBtn"),
|
|
13825
13956
|
onClick: _cache[9] || (_cache[9] = ($event) => toggleQuickPop($event))
|
|
13826
13957
|
}, "🔍", 10, _hoisted_10)) : createCommentVNode("", true),
|
|
13827
13958
|
_ctx.viewable ? (openBlock(), createElementBlock("button", {
|
|
13828
13959
|
key: 1,
|
|
13829
13960
|
class: normalizeClass(["rj-btn rj-tool-btn rj-view-btn", { "is-active": !!currentViewId.value }]),
|
|
13830
|
-
|
|
13961
|
+
"data-tip": t("viewBtn"),
|
|
13962
|
+
"aria-label": t("viewBtn"),
|
|
13831
13963
|
onClick: _cache[10] || (_cache[10] = ($event) => openViewMenu($event))
|
|
13832
13964
|
}, "◈", 10, _hoisted_11)) : createCommentVNode("", true),
|
|
13833
13965
|
showExpandCollapse.value ? (openBlock(), createElementBlock(Fragment, { key: 2 }, [
|
|
@@ -13847,12 +13979,14 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
13847
13979
|
}, toDisplayString(t("chart")), 1)) : createCommentVNode("", true),
|
|
13848
13980
|
createElementVNode("button", {
|
|
13849
13981
|
class: "rj-btn",
|
|
13850
|
-
|
|
13982
|
+
"data-tip": t("density") + " · " + DENSITY_LABELS.value[densityIdx.value],
|
|
13983
|
+
"aria-label": t("density"),
|
|
13851
13984
|
onClick: _cache[14] || (_cache[14] = ($event) => densityIdx.value = (densityIdx.value + 1) % 3)
|
|
13852
13985
|
}, toDisplayString(["▤", "☰", "▥"][densityIdx.value]), 9, _hoisted_12),
|
|
13853
13986
|
createElementVNode("button", {
|
|
13854
13987
|
class: "rj-btn",
|
|
13855
|
-
|
|
13988
|
+
"data-tip": dark.value ? t("toLight") : t("toDark"),
|
|
13989
|
+
"aria-label": dark.value ? t("toLight") : t("toDark"),
|
|
13856
13990
|
onClick: _cache[15] || (_cache[15] = ($event) => toggleDark())
|
|
13857
13991
|
}, toDisplayString(dark.value ? "☀" : "🌙"), 9, _hoisted_13),
|
|
13858
13992
|
_ctx.toolPanel ? (openBlock(), createElementBlock("button", {
|
|
@@ -13863,29 +13997,30 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
13863
13997
|
_ctx.exportable ? (openBlock(), createElementBlock("div", _hoisted_14, [
|
|
13864
13998
|
createElementVNode("button", {
|
|
13865
13999
|
class: "rj-btn rj-btn-export rj-export-btn",
|
|
13866
|
-
|
|
14000
|
+
"data-tip": t("printTip"),
|
|
13867
14001
|
onClick: _cache[17] || (_cache[17] = ($event) => openRangeMenu($event, "print"))
|
|
13868
14002
|
}, toDisplayString(t("printBtn")), 9, _hoisted_15),
|
|
13869
14003
|
createElementVNode("button", {
|
|
13870
14004
|
class: "rj-btn rj-btn-export rj-export-btn",
|
|
13871
|
-
|
|
14005
|
+
"data-tip": t("csvTip"),
|
|
13872
14006
|
onClick: _cache[18] || (_cache[18] = ($event) => openRangeMenu($event, "csv"))
|
|
13873
14007
|
}, " CSV ", 8, _hoisted_16),
|
|
13874
14008
|
createElementVNode("button", {
|
|
13875
14009
|
class: "rj-btn rj-btn-export rj-export-btn",
|
|
13876
|
-
|
|
14010
|
+
"data-tip": t("pdfTip"),
|
|
13877
14011
|
onClick: _cache[19] || (_cache[19] = ($event) => openRangeMenu($event, "pdf"))
|
|
13878
14012
|
}, " PDF ", 8, _hoisted_17),
|
|
13879
14013
|
createElementVNode("button", {
|
|
13880
14014
|
class: "rj-btn rj-btn-export rj-export-btn",
|
|
13881
|
-
|
|
14015
|
+
"data-tip": t("excelTip"),
|
|
13882
14016
|
onClick: _cache[20] || (_cache[20] = ($event) => openRangeMenu($event, "excel"))
|
|
13883
14017
|
}, " Excel ", 8, _hoisted_18)
|
|
13884
14018
|
])) : createCommentVNode("", true),
|
|
13885
14019
|
_ctx.stateKey ? (openBlock(), createElementBlock("button", {
|
|
13886
14020
|
key: 6,
|
|
13887
14021
|
class: "rj-btn",
|
|
13888
|
-
|
|
14022
|
+
"data-tip": t("resetState"),
|
|
14023
|
+
"aria-label": t("resetState"),
|
|
13889
14024
|
onClick: resetState
|
|
13890
14025
|
}, "↺", 8, _hoisted_19)) : createCommentVNode("", true)
|
|
13891
14026
|
], 32)) : createCommentVNode("", true)
|
|
@@ -14452,8 +14587,14 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
14452
14587
|
onClear: clearAdvancedFilter,
|
|
14453
14588
|
onClose: _cache[43] || (_cache[43] = ($event) => advDialog.value = null)
|
|
14454
14589
|
}, null, 8, ["model", "columns", "x", "y"])) : createCommentVNode("", true),
|
|
14455
|
-
|
|
14590
|
+
tip.value ? (openBlock(), createElementBlock("div", {
|
|
14456
14591
|
key: 8,
|
|
14592
|
+
class: "rj-tip",
|
|
14593
|
+
role: "tooltip",
|
|
14594
|
+
style: normalizeStyle({ left: tip.value.x + "px", top: tip.value.y + "px" })
|
|
14595
|
+
}, toDisplayString(tip.value.text), 5)) : createCommentVNode("", true),
|
|
14596
|
+
menu.value ? (openBlock(), createBlock(_sfc_main$a, {
|
|
14597
|
+
key: 9,
|
|
14457
14598
|
items: menu.value.items,
|
|
14458
14599
|
x: menu.value.x,
|
|
14459
14600
|
y: menu.value.y,
|
|
@@ -14461,7 +14602,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
14461
14602
|
onReposition: onMenuReposition
|
|
14462
14603
|
}, null, 8, ["items", "x", "y"])) : createCommentVNode("", true),
|
|
14463
14604
|
colMenu.value ? (openBlock(), createBlock(_sfc_main$9, {
|
|
14464
|
-
key:
|
|
14605
|
+
key: 10,
|
|
14465
14606
|
col: colMenu.value.col,
|
|
14466
14607
|
"col-id": colMenu.value.colId,
|
|
14467
14608
|
x: colMenu.value.x,
|
|
@@ -14489,13 +14630,13 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
14489
14630
|
onColDrop
|
|
14490
14631
|
}, null, 8, ["col", "col-id", "x", "y", "can-sort", "can-filter", "can-group", "sort-dir", "pinned", "filter-type", "filter-model", "unique-values", "columns"])) : createCommentVNode("", true),
|
|
14491
14632
|
chartOpen.value ? (openBlock(), createBlock(_sfc_main$6, {
|
|
14492
|
-
key:
|
|
14633
|
+
key: 11,
|
|
14493
14634
|
columns: pipelineCols.value,
|
|
14494
14635
|
rows: chartRows.value,
|
|
14495
14636
|
onClose: _cache[44] || (_cache[44] = ($event) => chartOpen.value = false)
|
|
14496
14637
|
}, null, 8, ["columns", "rows"])) : createCommentVNode("", true),
|
|
14497
14638
|
rowFormDlg.value ? (openBlock(), createBlock(_sfc_main$3, {
|
|
14498
|
-
key:
|
|
14639
|
+
key: 12,
|
|
14499
14640
|
fields: rowFormDlg.value.fields,
|
|
14500
14641
|
rows: rowFormDlg.value.rows,
|
|
14501
14642
|
mode: rowFormDlg.value.mode,
|
|
@@ -14505,13 +14646,13 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
14505
14646
|
onClose: _cache[45] || (_cache[45] = ($event) => rowFormDlg.value = null)
|
|
14506
14647
|
}, null, 8, ["fields", "rows", "mode", "title", "width"])) : createCommentVNode("", true),
|
|
14507
14648
|
confirmDlg.value ? (openBlock(), createBlock(_sfc_main$2, {
|
|
14508
|
-
key:
|
|
14649
|
+
key: 13,
|
|
14509
14650
|
message: confirmDlg.value.message,
|
|
14510
14651
|
onOk: onConfirmOk,
|
|
14511
14652
|
onCancel: _cache[46] || (_cache[46] = ($event) => confirmDlg.value = null)
|
|
14512
14653
|
}, null, 8, ["message"])) : createCommentVNode("", true),
|
|
14513
14654
|
dragGhost.value ? (openBlock(), createElementBlock("div", {
|
|
14514
|
-
key:
|
|
14655
|
+
key: 14,
|
|
14515
14656
|
ref_key: "dragGhostRef",
|
|
14516
14657
|
ref: dragGhostRef,
|
|
14517
14658
|
class: "rj-drag-ghost",
|
|
@@ -14532,7 +14673,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
14532
14673
|
!dragGhost.value.cells.length ? (openBlock(), createElementBlock("span", _hoisted_51, toDisplayString(t("dragRow")), 1)) : createCommentVNode("", true)
|
|
14533
14674
|
], 4)) : createCommentVNode("", true),
|
|
14534
14675
|
imgPreview.value ? (openBlock(), createElementBlock("div", {
|
|
14535
|
-
key:
|
|
14676
|
+
key: 15,
|
|
14536
14677
|
class: "rj-img-viewer",
|
|
14537
14678
|
role: "dialog",
|
|
14538
14679
|
"aria-modal": "true",
|
package/dist/style.css
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
--rj-text-secondary: #909399;
|
|
11
11
|
--rj-primary: #3b76f6;
|
|
12
12
|
--rj-primary-bg: #eaf1fe;
|
|
13
|
-
--rj-hover-bg: #
|
|
13
|
+
--rj-hover-bg: #e6edf9;
|
|
14
14
|
--rj-selected-bg: #e2edfd;
|
|
15
15
|
--rj-range-bg: rgba(59, 118, 246, 0.1);
|
|
16
16
|
--rj-fill-bg: rgba(59, 118, 246, 0.16);
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
--rj-text-secondary: #8a919f;
|
|
53
53
|
--rj-primary: #5c8dfb;
|
|
54
54
|
--rj-primary-bg: #24324d;
|
|
55
|
-
--rj-hover-bg: #
|
|
55
|
+
--rj-hover-bg: #313a4d;
|
|
56
56
|
--rj-selected-bg: #2a3a5c;
|
|
57
57
|
--rj-mask: rgba(30, 34, 42, 0.75);
|
|
58
58
|
--rj-flash-bg: #5a4c1e;
|
|
@@ -509,6 +509,25 @@
|
|
|
509
509
|
font-weight: 500;
|
|
510
510
|
}
|
|
511
511
|
|
|
512
|
+
.rj-tip {
|
|
513
|
+
position: fixed;
|
|
514
|
+
z-index: 3100;
|
|
515
|
+
width: max-content;
|
|
516
|
+
max-width: 240px;
|
|
517
|
+
padding: 3px 8px;
|
|
518
|
+
font-size: 12px;
|
|
519
|
+
font-weight: 400;
|
|
520
|
+
line-height: 1.4;
|
|
521
|
+
color: var(--rj-bg);
|
|
522
|
+
text-align: left;
|
|
523
|
+
white-space: normal;
|
|
524
|
+
pointer-events: none;
|
|
525
|
+
background: var(--rj-text);
|
|
526
|
+
border-radius: var(--rj-radius);
|
|
527
|
+
box-shadow: var(--rj-shadow);
|
|
528
|
+
transform: translateX(-100%);
|
|
529
|
+
}
|
|
530
|
+
|
|
512
531
|
.rj-pager {
|
|
513
532
|
display: flex;
|
|
514
533
|
align-items: center;
|
|
@@ -5,14 +5,14 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
|
|
|
5
5
|
y: number;
|
|
6
6
|
}>>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
7
7
|
select: (item: RjMenuItem) => void;
|
|
8
|
-
reposition: (h: number) => void;
|
|
8
|
+
reposition: (h: number, w: number) => void;
|
|
9
9
|
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<__VLS_TypePropsToRuntimeProps<{
|
|
10
10
|
items: RjMenuItem[];
|
|
11
11
|
x: number;
|
|
12
12
|
y: number;
|
|
13
13
|
}>>> & Readonly<{
|
|
14
14
|
onSelect?: ((item: RjMenuItem) => any) | undefined;
|
|
15
|
-
onReposition?: ((h: number) => any) | undefined;
|
|
15
|
+
onReposition?: ((h: number, w: number) => any) | undefined;
|
|
16
16
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
17
17
|
export default _default;
|
|
18
18
|
type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
|
|
@@ -96,6 +96,12 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<im
|
|
|
96
96
|
*/
|
|
97
97
|
serverExport?: ((params: RjServerExportParams) => void | Promise<void>) | undefined;
|
|
98
98
|
exportFileName?: string | undefined;
|
|
99
|
+
/**
|
|
100
|
+
* 打印 / PDF 单次最大行数护栏:浏览器打印靠把整表排版进隐藏 iframe,
|
|
101
|
+
* 上万行会生成十几 MB HTML 并让主线程卡死(页面假死)。超过此上限只打印前 N 行并提示,
|
|
102
|
+
* 需全量请先筛选 / 用分页 / 走后端导出,或按宿主机器性能调大本值。置 0 或负数则不限。
|
|
103
|
+
*/
|
|
104
|
+
printMaxRows?: number | undefined;
|
|
99
105
|
/** 导出取值口径:默认导出「所见即所得」的格式化文本(与屏幕一致、单文件内口径统一);
|
|
100
106
|
* 置 true 则导出原始类型值,让 Excel 里数字仍是数字(对齐 AG Grid useCellValuesForExports) */
|
|
101
107
|
exportRawValues?: boolean | undefined;
|
|
@@ -182,6 +188,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<im
|
|
|
182
188
|
copyHeadersToClipboard: boolean;
|
|
183
189
|
markDirtyCells: boolean;
|
|
184
190
|
rowHover: boolean;
|
|
191
|
+
printMaxRows: number;
|
|
185
192
|
queryable: boolean;
|
|
186
193
|
viewable: boolean;
|
|
187
194
|
queryFields: () => never[];
|
|
@@ -303,6 +310,12 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<im
|
|
|
303
310
|
*/
|
|
304
311
|
serverExport?: ((params: RjServerExportParams) => void | Promise<void>) | undefined;
|
|
305
312
|
exportFileName?: string | undefined;
|
|
313
|
+
/**
|
|
314
|
+
* 打印 / PDF 单次最大行数护栏:浏览器打印靠把整表排版进隐藏 iframe,
|
|
315
|
+
* 上万行会生成十几 MB HTML 并让主线程卡死(页面假死)。超过此上限只打印前 N 行并提示,
|
|
316
|
+
* 需全量请先筛选 / 用分页 / 走后端导出,或按宿主机器性能调大本值。置 0 或负数则不限。
|
|
317
|
+
*/
|
|
318
|
+
printMaxRows?: number | undefined;
|
|
306
319
|
/** 导出取值口径:默认导出「所见即所得」的格式化文本(与屏幕一致、单文件内口径统一);
|
|
307
320
|
* 置 true 则导出原始类型值,让 Excel 里数字仍是数字(对齐 AG Grid useCellValuesForExports) */
|
|
308
321
|
exportRawValues?: boolean | undefined;
|
|
@@ -389,6 +402,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<im
|
|
|
389
402
|
copyHeadersToClipboard: boolean;
|
|
390
403
|
markDirtyCells: boolean;
|
|
391
404
|
rowHover: boolean;
|
|
405
|
+
printMaxRows: number;
|
|
392
406
|
queryable: boolean;
|
|
393
407
|
viewable: boolean;
|
|
394
408
|
queryFields: () => never[];
|
|
@@ -472,6 +486,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<im
|
|
|
472
486
|
detailHeight: number;
|
|
473
487
|
fullWidthHeight: number;
|
|
474
488
|
exportRange: "auto" | RjExportScopeResolved;
|
|
489
|
+
printMaxRows: number;
|
|
475
490
|
statusBar: boolean;
|
|
476
491
|
statusAggregations: ("sum" | "avg" | "min" | "max" | "count")[];
|
|
477
492
|
undoRedoCellEditing: boolean;
|
|
@@ -594,6 +609,8 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<im
|
|
|
594
609
|
autoSizeColumn: (colId: string) => void;
|
|
595
610
|
autoSizeAll: () => void;
|
|
596
611
|
sizeColumnsToFit: () => void;
|
|
612
|
+
/** 清除宽度覆盖:把列宽还原到列定义/内容自适应默认值(配合 autoSizeAll 做「自适应↔还原」切换) */
|
|
613
|
+
resetColumnWidths: () => void;
|
|
597
614
|
setTheme: (params: RjThemeParams) => void;
|
|
598
615
|
getTheme: () => {
|
|
599
616
|
preset?: "legacy" | "alpine" | "quartz" | "material" | undefined;
|
|
@@ -728,6 +745,8 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<im
|
|
|
728
745
|
autoSizeColumn: (colId: string) => void;
|
|
729
746
|
autoSizeAll: () => void;
|
|
730
747
|
sizeColumnsToFit: () => void;
|
|
748
|
+
/** 清除宽度覆盖:把列宽还原到列定义/内容自适应默认值(配合 autoSizeAll 做「自适应↔还原」切换) */
|
|
749
|
+
resetColumnWidths: () => void;
|
|
731
750
|
setTheme: (params: RjThemeParams) => void;
|
|
732
751
|
getTheme: () => {
|
|
733
752
|
preset?: "legacy" | "alpine" | "quartz" | "material" | undefined;
|
|
@@ -866,6 +885,8 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<im
|
|
|
866
885
|
autoSizeColumn: (colId: string) => void;
|
|
867
886
|
autoSizeAll: () => void;
|
|
868
887
|
sizeColumnsToFit: () => void;
|
|
888
|
+
/** 清除宽度覆盖:把列宽还原到列定义/内容自适应默认值(配合 autoSizeAll 做「自适应↔还原」切换) */
|
|
889
|
+
resetColumnWidths: () => void;
|
|
869
890
|
setTheme: (params: RjThemeParams) => void;
|
|
870
891
|
getTheme: () => {
|
|
871
892
|
preset?: "legacy" | "alpine" | "quartz" | "material" | undefined;
|
|
@@ -1001,6 +1022,8 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<im
|
|
|
1001
1022
|
autoSizeColumn: (colId: string) => void;
|
|
1002
1023
|
autoSizeAll: () => void;
|
|
1003
1024
|
sizeColumnsToFit: () => void;
|
|
1025
|
+
/** 清除宽度覆盖:把列宽还原到列定义/内容自适应默认值(配合 autoSizeAll 做「自适应↔还原」切换) */
|
|
1026
|
+
resetColumnWidths: () => void;
|
|
1004
1027
|
setTheme: (params: RjThemeParams) => void;
|
|
1005
1028
|
getTheme: () => {
|
|
1006
1029
|
preset?: "legacy" | "alpine" | "quartz" | "material" | undefined;
|
package/dist/types/src/nlq.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { RjFilterModel, RjSortState } from './types';
|
|
2
|
+
import type { RjLang } from './locale';
|
|
2
3
|
export type RjNlqFilterType = 'text' | 'number' | 'date' | 'select';
|
|
3
4
|
/** 参与解析的列描述(由网格从列定义构建) */
|
|
4
5
|
export interface RjNlqColumn {
|
|
@@ -39,13 +40,20 @@ export interface RjNlqResult {
|
|
|
39
40
|
model: RjFilterModel;
|
|
40
41
|
}[];
|
|
41
42
|
sort?: RjSortState;
|
|
43
|
+
/** 排序列展示名(title,供 explainNLQ 本地化回显) */
|
|
44
|
+
sortTitle?: string;
|
|
42
45
|
groupBy?: string;
|
|
43
46
|
groupColId?: string;
|
|
47
|
+
/** 分组列展示名(title,供 explainNLQ 本地化回显) */
|
|
48
|
+
groupTitle?: string;
|
|
44
49
|
limit?: number;
|
|
45
50
|
search?: string;
|
|
46
51
|
clauses: RjNlqClause[];
|
|
47
52
|
}
|
|
48
53
|
/** 解析自然语言查询 */
|
|
49
54
|
export declare function parseNLQ(text: string, columns: RjNlqColumn[]): RjNlqResult;
|
|
50
|
-
/**
|
|
51
|
-
|
|
55
|
+
/**
|
|
56
|
+
* 生成人类可读的解析摘要(供 UI 回显)。传 lang 则随语言本地化:
|
|
57
|
+
* 中文如「数量 > 100 · 按金额 降序 · 前5 · 搜索“轴承”」,英文如「qty > 100 · sort by amount desc · top 5 · search "bolt"」。
|
|
58
|
+
*/
|
|
59
|
+
export declare function explainNLQ(r: RjNlqResult, lang?: RjLang): string;
|
|
@@ -630,6 +630,8 @@ export interface RjGridApi extends ComponentPublicInstance {
|
|
|
630
630
|
autoSizeAll: () => void;
|
|
631
631
|
/** 列宽:按视口宽度等比缩放普通区列(对标 sizeColumnsToFit) */
|
|
632
632
|
sizeColumnsToFit: () => void;
|
|
633
|
+
/** 清除全部列宽覆盖,还原到列定义/内容自适应默认宽(与 autoSizeAll 配合做自适应↔还原切换) */
|
|
634
|
+
resetColumnWidths: () => void;
|
|
633
635
|
/** 主题引擎(对标 AG Grid Theming):运行时替换预设/明暗/强调色等 */
|
|
634
636
|
setTheme: (params: RjThemeParams) => void;
|
|
635
637
|
/** 读取当前生效的主题参数 */
|
|
@@ -60,6 +60,7 @@ export declare function useColumnState(sourceColumns: () => RjColumn[]): {
|
|
|
60
60
|
setAutoWidth: (colId: string, width: number) => void;
|
|
61
61
|
hasSizedWidth: (colId: string) => boolean;
|
|
62
62
|
sizeToFit: () => void;
|
|
63
|
+
clearWidths: () => void;
|
|
63
64
|
moveColumn: (dragId: string, targetId: string) => void;
|
|
64
65
|
togglePin: (colId: string, pin: 'left' | 'right' | null) => void;
|
|
65
66
|
toggleHide: (colId: string, hide?: boolean) => void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rj-grid",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "零第三方依赖的自研 Vue3 虚拟表格:虚拟滚动 / 冻结列 / 行拖拽 / 分组透视 / 公式 / SSRM / 主题 i18n / 自然语言查询",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
}
|
|
47
47
|
},
|
|
48
48
|
"scripts": {
|
|
49
|
+
"start": "vite --config vite.playground.config.ts",
|
|
49
50
|
"dev": "vite --config vite.playground.config.ts",
|
|
50
51
|
"build:play": "vite build --config vite.playground.config.ts",
|
|
51
52
|
"preview:play": "vite preview --config vite.playground.config.ts",
|
|
@@ -55,6 +56,8 @@
|
|
|
55
56
|
"lint": "eslint --fix --ext .ts,.vue index.ts src __tests__ playground && stylelint \"src/styles/*.scss\"",
|
|
56
57
|
"ts": "node --max_old_space_size=8192 ./node_modules/vue-tsc/bin/vue-tsc.js --noEmit -p tsconfig.json",
|
|
57
58
|
"size": "node ./node_modules/vite/bin/vite.js build --config vite.size.config.ts && node build/rjSizeReport.mjs",
|
|
59
|
+
"publish:github": "node scripts/publish-github.mjs",
|
|
60
|
+
"publish:github:push": "node scripts/publish-github.mjs --push",
|
|
58
61
|
"prepublishOnly": "pnpm build && pnpm test"
|
|
59
62
|
},
|
|
60
63
|
"keywords": [
|