erpnext-syntax-clientscripts
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseERPNext Client Scripts Syntax (EN)
ERPNext客户端脚本语法指南
Client Scripts run in the browser and control all UI interactions in ERPNext/Frappe. They are created via Setup → Client Script or in custom apps under .
public/js/Version: v14/v15/v16 compatible (unless noted otherwise)
客户端脚本运行在浏览器中,控制ERPNext/Frappe中的所有UI交互。可通过设置 → 客户端脚本创建,或在自定义应用的目录下创建。
public/js/版本兼容: v14/v15/v16(除非另有说明)
Quick Reference
快速参考
Basic Structure
基本结构
javascript
frappe.ui.form.on('DocType Name', {
// Form-level events
setup(frm) { },
refresh(frm) { },
validate(frm) { },
// Field change events
fieldname(frm) { }
});javascript
frappe.ui.form.on('DocType Name', {
// 表单级事件
setup(frm) { },
refresh(frm) { },
validate(frm) { },
// 字段变更事件
fieldname(frm) { }
});Most Used Patterns
常用代码模式
| Action | Code |
|---|---|
| Set value | |
| Hide field | |
| Make field mandatory | |
| Call server | |
| Prevent save | |
| 操作 | 代码 |
|---|---|
| 设置字段值 | |
| 隐藏字段 | |
| 设置字段为必填 | |
| 调用服务器方法 | |
| 阻止保存 | |
Event Selection
事件选择
Which event should I use?
One-time setup (queries, defaults)?
└── setup
Show/hide UI, add buttons?
└── refresh
Validation before save?
└── validate
Do something right after save?
└── after_save
React to field change?
└── {fieldname}→ See references/events.md for complete event list and execution order.
应该使用哪个事件?
一次性初始化(查询、默认值设置)?
└── setup
显示/隐藏UI、添加按钮?
└── refresh
保存前验证?
└── validate
保存后执行操作?
└── after_save
响应字段变更?
└── {fieldname}→ 完整事件列表及执行顺序请参考 references/events.md。
Essential Methods
核心方法
Value Manipulation
值操作
javascript
// Set single value (async, returns Promise)
frm.set_value('status', 'Approved');
// Set multiple values at once
frm.set_value({
status: 'Approved',
priority: 'High'
});
// Get value
let value = frm.doc.fieldname;javascript
// 设置单个值(异步,返回Promise)
frm.set_value('status', 'Approved');
// 批量设置多个值
frm.set_value({
status: 'Approved',
priority: 'High'
});
// 获取值
let value = frm.doc.fieldname;Field Properties
字段属性
javascript
// Show/hide
frm.toggle_display('priority', condition);
// Make mandatory
frm.toggle_reqd('due_date', true);
// Make read-only
frm.toggle_enable('amount', false);
// Advanced property change
frm.set_df_property('status', 'options', ['New', 'Open', 'Closed']);
frm.set_df_property('amount', 'read_only', 1);javascript
// 显示/隐藏字段
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);Link Field Filters
链接字段筛选
javascript
// Simple filter
frm.set_query('customer', () => ({
filters: { disabled: 0 }
}));
// Filter in child table
frm.set_query('item_code', 'items', (doc, cdt, cdn) => ({
filters: { is_sales_item: 1 }
}));→ See references/methods.md for complete method signatures.
javascript
// 简单筛选
frm.set_query('customer', () => ({
filters: { disabled: 0 }
}));
// 子表格中的字段筛选
frm.set_query('item_code', 'items', (doc, cdt, cdn) => ({
filters: { is_sales_item: 1 }
}));→ 完整方法签名请参考 references/methods.md。
Server Communication
服务器通信
frappe.call (Whitelisted Methods)
frappe.call(调用白名单方法)
javascript
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);
}
}
});javascript
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 (Document Methods)
frm.call(调用文档控制器方法)
javascript
// Calls method on document controller
frm.call('calculate_taxes', { include_shipping: true })
.then(r => frm.reload_doc());javascript
// 调用文档控制器中的方法
frm.call('calculate_taxes', { include_shipping: true })
.then(r => frm.reload_doc());Async/Await Pattern
Async/Await 模式
javascript
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;
}javascript
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;
}Child Table Handling
子表格处理
Adding Rows
添加行
javascript
let row = frm.add_child('items', {
item_code: 'ITEM-001',
qty: 5,
rate: 100
});
frm.refresh_field('items'); // REQUIRED after modificationjavascript
let row = frm.add_child('items', {
item_code: 'ITEM-001',
qty: 5,
rate: 100
});
frm.refresh_field('items'); // 修改后必须调用此方法Editing Rows
编辑行
javascript
frm.doc.items.forEach((row) => {
if (row.qty > 10) {
row.discount_percentage = 5;
}
});
frm.refresh_field('items');javascript
frm.doc.items.forEach((row) => {
if (row.qty > 10) {
row.discount_percentage = 5;
}
});
frm.refresh_field('items');Child Table Events
子表格事件
javascript
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) {
// New row added
},
items_remove(frm) {
// Row removed
}
});→ See references/examples.md for complete child table examples.
javascript
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) {
// 删除行时触发
}
});→ 完整子表格示例请参考 references/examples.md。
Custom Buttons
自定义按钮
javascript
frappe.ui.form.on('Sales Order', {
refresh(frm) {
if (frm.doc.docstatus === 1) {
// Grouped buttons
frm.add_custom_button(__('Invoice'), () => {
// action
}, __('Create'));
// Primary action
frm.page.set_primary_action(__('Process'), () => {
frm.call('process').then(() => frm.reload_doc());
});
}
}
});javascript
frappe.ui.form.on('Sales Order', {
refresh(frm) {
if (frm.doc.docstatus === 1) {
// 分组按钮
frm.add_custom_button(__('Invoice'), () => {
// 执行操作
}, __('Create'));
// 主要操作按钮
frm.page.set_primary_action(__('Process'), () => {
frm.call('process').then(() => frm.reload_doc());
});
}
}
});Critical Rules
重要规则
- ALWAYS call after child table modifications
frm.refresh_field('table') - NEVER use — use
frm.doc.field = valuefrm.set_value() - ALWAYS use for translatable strings
__('text') - validate event: use to prevent save
frappe.throw() - setup event: only for one-time configuration (not repeated)
→ See references/anti-patterns.md for common mistakes.
- 务必在修改子表格后调用
frm.refresh_field('table') - 禁止直接使用,请使用
frm.doc.field = valuefrm.set_value() - 务必使用处理可翻译字符串
__('text') - validate事件:使用阻止保存
frappe.throw() - setup事件:仅用于一次性配置(不会重复执行)
→ 常见错误示例请参考 references/anti-patterns.md。
Related Skills
相关技能
- — Implementation workflows and decision trees
erpnext-impl-clientscripts - — Error handling patterns
erpnext-errors-clientscripts - — Server-side methods to call
erpnext-syntax-whitelisted
- — 实现工作流与决策树
erpnext-impl-clientscripts - — 错误处理模式
erpnext-errors-clientscripts - — 可调用的服务器端方法
erpnext-syntax-whitelisted