针对嘉立创 ERP(
jlcerp.com,基于 Element UI 的el-table/ Vue 2)的油猴脚本:在任意数据表格顶部注入控制行,提供 多列排序、双条件类型化筛选、计算列(表达式引擎)、隐藏列管理、列宽记忆、行号 等增强能力,并支持 跨域 iframe 子应用。
3.12https://mh.jlcerp.com/*、https://nw.jlcerp.com/*| 能力 | 说明 |
|---|---|
| 多列排序 | 每列三态循环(无 → 降序 → 升序),多列按点击顺序联合排序 |
| 双条件筛选 | 每列可设两个条件,支持「并且 / 或者」;可指定列类型(文本/数值/日期) |
| 计算列 | 用表达式按列名生成新列,支持算术/字符串/日期/条件/三元运算,可链式引用、可持久化 |
| 隐藏列 | 对话框管理:逐列隐藏/显示、全部显示 |
| 列宽记忆 | 拖动列宽自动记住;计算列按内容自适应;刷新/查询后自动恢复 |
| 行号 | 自动添加并随排序/筛选重排 |
| iframe | 进入跨域子应用(如 nw.jlcerp.com 嵌于 mh.jlcerp.com)处理其表格 |
| 自动复原 | 原始数据刷新(点查询)时自动撤销脚本产生的筛选/排序,避免污染 |
表格增强-排序-筛选-计算列(支持iframe).user.js 的全部内容粘贴进去保存(或直接把 .user.js 文件拖入浏览器安装)。@match https://mh.jlcerp.com/* 与 https://nw.jlcerp.com/*,访问对应站点即自动生效。// @match 你的域名/* 即可。需要的油猴权限(
@grant):GM_addStyle、GM_getValue、GM_setValue、GM_listValues、GM_deleteValue。
进入任意含数据表格的页面后,表格顶部会出现一行控制行,每一列对应:
⇅ 排序(反复点击循环切换)🔍 筛选× 清除该列筛选(有筛选时才出现)原始最后一列还会额外挂载:
× 恢复原始表格(移除控制行、清空脚本的所有改动)👁 列管理(隐藏/显示列、添加计算列、列宽管理)⇅ 循环 无序 → 降序 ↓ → 升序 ↑ → 无序。⇅,按点击先后作为优先级,先点的列优先比较。⇅ 图标会反映当前状态(↓/↑/空白)。点 🔍 打开筛选弹窗:
本列数据类型: [ 文本 ▾ ] 数值/日期可比较大小
条件一 [ 包含 ▾ ] [ 输入内容 ]
◉ 并且 ○ 或者
条件二 [ 等于 ▾ ] [ 输入内容 ]
读作:条件一「比较方式 + 内容」 并且/或者 条件二「比较方式 + 内容」
[清除筛选] [取消] [应用筛选]
并且 / 或者 单选连接。>、大于等于 ≥、小于 <、小于等于 ≤、等于 =、不等于 ≠入口:👁 列管理 → 添加计算列。
单价 * 数量()、#、空格等特殊符号时用方括号包裹:[单价(元)] * [数量]、[#订单号]| 类别 | 写法 | 示例 |
|---|---|---|
| 算术 | + - * / % |
10 % 3 = 1 |
| 比较 | > < >= <= = != |
结果为 是/否 |
| 逻辑 | and / or / not(也可 && || !) |
金额 > 1000 and 状态 = '已发' |
| 三元 | 条件 ? 真值 : 假值 |
金额 > 1000 ? '大单' : '小单' |
| 文本拼接 | & |
完成率 & '%' = 85% |
优先级:小括号 () → 乘除模 * / % → 加减 + - → 文本拼接 & → 比较 → not → and → or → 三元 ?:
数学
| 函数 | 说明 | 示例 |
|---|---|---|
round(x, n) |
四舍五入到 n 位小数 | round(3.14159, 2) = 3.14 |
abs(x) |
绝对值 | abs(-5) = 5 |
floor(x) / ceil(x) |
向下 / 向上取整 | floor(3.9) = 3;ceil(3.1) = 4 |
max(a,b,...) / min(a,b,...) |
最大 / 最小(可多参数) | max(1, 5, 3) = 5 |
mod(a, b) |
取余 | mod(10, 3) = 1 |
字符串
| 函数 | 说明 | 示例 |
|---|---|---|
concat(a, b, ...) |
拼接(等价 &) |
concat(姓, 名) |
left(s, n) / right(s, n) |
左 / 右取 n 个字符 | left(订单号, 4) |
mid(s, start, len) |
从第 start 个取 len 个(start 从 1) | mid(身份证, 7, 8) |
len(s) |
字符长度 | — |
replace(s, 旧, 新) |
替换 | replace(编号, '-', '') 去横线 |
upper(s) / lower(s) |
转大 / 小写 | — |
trim(s) |
去首尾空格 | — |
contains(s, 子串) |
是否包含,返回 是/否 | contains(备注, '急') |
日期(支持 2024-03-15 / 2024/3/15 / 2024.3.15)
| 函数 | 说明 | 示例 |
|---|---|---|
year(d) / month(d) / day(d) |
取年 / 月 / 日 | year(订单日期) |
today() |
今天 | — |
datediff(d1, d2, 单位) |
时间差,单位:second/minute/hour/day/month |
datediff(完工, 开工, 'day') |
dateadd(d, n, 单位) |
日期加 n 天/月 | dateadd(今天, 7, 'day') |
秒/分/时单位需要日期含时间部分(如
2024-03-15 12:30:00)。
条件
| 函数 | 说明 | 示例 |
|---|---|---|
if(条件, 真值, 假值) |
条件分支,可嵌套 | if(分 >= 90, 'A', if(分 >= 60, 'B', 'C')) |
后定义的计算列可引用前面已定义的计算列。例:
金额 = 单价 * 数量税额 = 金额 * 0.13用 ↑ / ↓ 调整求值顺序,被引用的列必须排在前面。
单元格里的数字若带千分位逗号或货币符号会自动去除:
"¥1,234.50" → 1234.5"12.5kg" → 12.5"85%" → 85比较时若两边都能转数字则按数值比,否则按文本比。
#ERR: 原因 并标红,不影响其它单元格与排序/筛选。金额 : 单价 * 数量
含税金额 : round(单价 * 数量 * 1.13, 2)
客户等级 : if(金额 >= 10000, 'VIP', if(金额 >= 1000, '普通', '零散'))
工期天数 : datediff(完工日期, 开工日期, 'day')
编号清洗 : upper(replace(编号, ' ', ''))
百分比 : round(完成率 * 100, 1) & '%'
是否超期 : 完工日期 > today() ? '超期' : '正常'
点 👁 打开列管理弹窗:
隐藏 / 显示 切换、记住列宽 / 清除列宽全部显示、添加计算列、全部清除列宽、关闭display:none,不删除数据,恢复后原样可见× / 👁)受保护不会被隐藏style="width" 写入,优先级高于 el-table 的 width 属性,不会被 el-table 的 doLayout 重渲染覆盖,告别闪烁/拉锯。MutationObserver 守护,el-table 重建列节点时自动重设。自动在表格添加行号列,排序/筛选后重新编号,常显稳定。
所有配置通过 GM_setValue 持久化,按 URL + 原始表头指纹 隔离(同结构表刷新可恢复,不同表头互不串扰):
| 数据 | 存储 key 前缀 | 说明 |
|---|---|---|
| 计算列定义 | calcCols_ |
可由「保存计算列,刷新后仍在」开关控制 |
| 隐藏列 | colHidden_ |
已隐藏的列名列表 |
| 列宽记忆 | colWidths_ |
{列名: 宽度},只记用户调过的列 |
计算列定义以原始表头(加入计算列之前)作为指纹,避免 key 漂移与内容重复;旧版本污染的存储 key 会被自动迁移清理。
mh.jlcerp.com 作为主应用外壳,内部以跨域 iframe 加载 nw.jlcerp.com 子应用。脚本会:
iframe;@match 命中后自行处理。表格排序与筛选增强/
├─ 表格增强-排序-筛选-计算列(支持iframe).user.js # 主脚本(单 IIFE,内联表达式引擎)
├─ src/
│ ├─ expr-engine.js # 表达式引擎(tokenize / parse / evalAst / validate)—— 单一事实源
│ ├─ calc-manager.js # 计算列链式求值(computeRowValues)
│ └─ calc-store.js # 持久化 key 生成与读写(makeKey / CalcStore)
├─ tests/
│ ├─ test.expr-engine.js
│ ├─ test.manager.js
│ └─ test.store.js
└─ docs/
└─ superpowers/ # 设计文档与实施计划
src/下的引擎是单一事实源,user.js内联同一份逻辑。修改引擎后需同步两边并跑测试。
引擎/管理器/存储均有 Node 单元测试(零外部依赖):
node tests/test.expr-engine.js # tokenize / parse / eval / validate
node tests/test.manager.js # 链式求值
node tests/test.store.js # key 生成与读写
主脚本语法检查:
node --check "表格增强-排序-筛选-计算列(支持iframe).user.js"
修改 src/expr-engine.js 后,请把对应实现同步内联进 user.js,并保证两端测试通过。
| 版本 | 主要内容 |
|---|---|
3.x |
列宽改用 inline style 锁定(根治与 el-table 的拉锯/闪烁);加载延迟 + col 重建守护;计算列按内容自适应;查询场景列宽即时恢复 |
3.x |
筛选弹窗改为「内联前缀式」(条件一/二标签 + 比较下拉 + 输入框)、与/或改单选、删除区间算法 |
3.x |
添加计算列入口移入列管理弹窗;新增「全部清除列宽」 |
2.x |
类型化筛选(文本/数值/日期)、隐藏列管理、记住列宽、datediff 增加秒/分/时 |
1.x |
表格排序、筛选、计算列表达式引擎初版 |
详见
git log。
Q:列宽加载后为什么不立刻生效,要等几秒?
A:el-table 首次渲染会多轮 doLayout 并可能重建列节点,脚本故意等其稳定后再锁定记忆列宽(默认 COL_WIDTH_APPLY_DELAY = 3000 ms,可在脚本里调小)。点查询(数据刷新)场景已改为即时恢复。
Q:计算列报 #ERR?
A:该单元格的表达式出错(如除零、无效日期、未知列名)。点「编辑」检查语法;保存前会自动校验列名是否真实存在。
Q:计算列引用另一计算列没生效?
A:被引用的计算列必须排在前面(定义顺序 = 求值顺序)。用 ↑ / ↓ 调整。
Q:筛选/排序在点查询后没了? A:这是设计行为——检测到原始数据刷新会自动清除脚本产生的筛选/排序,避免与框架渲染错位;重新设置即可。
Q:脚本在某个 el-table 站点不生效?
A:在脚本头追加 // @match 你的域名/*,并确保站点用的是 Element UI 的 el-table。
个人使用,按需修改。站点 @match 与样式针对 jlcerp.com,移植到其它 el-table 站点时通常只需改 @match。