用途
该技能用于在编写 ERPNext/Frappe 客户端 JavaScript 时提供语法参考。客户端脚本运行在浏览器中,控制 ERPNext/Frappe 的所有 UI 交互,可通过 Setup → Client Script 创建,也可放在自定义应用的 public/js/ 目录下。适用于 v14/v15/v16 版本(除非另有说明)。
主要能力
基本结构
frappe.ui.form.on('DocType Name', {
// Form-level events
setup(frm) { },
refresh(frm) { },
validate(frm) { },
// Field change events
fieldname(frm) { }
});
常用模式
| 操作 | 代码 |
|---|---|
| 设置值 | frm.set_value('field', value) |
| 隐藏字段 | frm.toggle_display('field', false) |
| 设为必填 | frm.toggle_reqd('field', true) |
| 调用服务端 | frappe.call({method: 'path.to.method', args: {}}) |
| 阻止保存 | frappe.throw('Error message') |
事件选择
- 一次性设置(查询、默认值)→ setup
- 显示/隐藏 UI、添加按钮 → refresh
- 保存前校验 → validate
- 保存后执行 → after_save
- 响应字段变更 → {fieldname}
值操作
// 设置单个值(异步,返回 Promise)
frm.set_value('status', 'Approved');
// 一次设置多个值
frm.set_value({
status: 'Approved',
priority: 'High'
});
// 获取值
let value = frm.doc.fieldname;
字段属性:
// 显示/隐藏
frm.toggle_display('priority', condition);
// 设为必填
frm.toggle_reqd('due_date', true);
// 设为只读
frm.toggle_enable('amount', false);
// 高级属性修改
frm.set_df_property('status', 'options', ['New', 'Open', 'Closed']);
frm.set_df_property('amount', 'read_only', 1);
链接字段过滤:
// 简单过滤
frm.set_query('customer', () => ({
filters: { disabled: 0 }
}));
// 子表内过滤
frm.set_query('item_code', 'items', (doc, cdt, cdn) => ({
filters: { is_sales_item: 1 }
}));
服务端通信
frappe.call(白名单方法):
frappe.call({
method: 'myapp.api.process_data',
args: { customer: frm.doc.customer },
freeze: true,
freeze_message: __('Processing...'),
callback: (r) => {
if (r.message) {
frm.set_value('result', r.message);
}
}
});
frm.call(文档方法):
// 调用文档控制器上的方法
frm.call('calculate_taxes', { include_shipping: true })
.then(r => frm.reload_doc());
Async/Await 模式:
async function fetchData(frm) {
let r = await frappe.call({
method: 'frappe.client.get_value',
args: {
doctype: 'Customer',
filters: { name: frm.doc.customer },
fieldname: 'credit_limit'
}
});
return r.message.credit_limit;
}
子表处理
添加行:
let row = frm.add_child('items', {
item_code: 'ITEM-001',
qty: 5,
rate: 100
});
frm.refresh_field('items'); // 修改后必须调用
编辑行:
frm.doc.items.forEach((row) => {
if (row.qty > 10) {
row.discount_percentage = 5;
}
});
frm.refresh_field('items');
子表事件:
frappe.ui.form.on('Sales Invoice Item', {
qty(frm, cdt, cdn) {
let row = frappe.get_doc(cdt, cdn);
frappe.model.set_value(cdt, cdn, 'amount', row.qty * row.rate);
},
items_add(frm, cdt, cdn) {
// 新增行
},
items_remove(frm) {
// 删除行
}
});
自定义按钮
frappe.ui.form.on('Sales Order', {
refresh(frm) {
if (frm.doc.docstatus === 1) {
// 分组按钮
frm.add_custom_button(__('Invoice'), () => {
// action
}, __('Create'));
// 主操作
frm.page.set_primary_action(__('Process'), () => {
frm.call('process').then(() => frm.reload_doc());
});
}
}
});
关键规则
- 修改子表后必须调用
frm.refresh_field('table') - 禁止使用
frm.doc.field = value,应使用frm.set_value() - 可翻译字符串必须使用
__('text') - validate 事件中使用
frappe.throw()阻止保存 - setup 事件仅用于一次性配置(不重复执行)
相关技能
- erpnext-impl-clientscripts — 实现工作流与决策树
- erpnext-errors-clientscripts — 错误处理模式
- erpnext-syntax-whitelisted — 可调用的服务端方法
限制
资料未提供该技能的安装方式、收费信息、平台支持范围及具体效果说明。