client-scripts
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseFrappe Client Scripts Reference
Frappe客户端脚本参考文档
Complete reference for client-side JavaScript development in Frappe Framework.
Frappe框架下客户端JavaScript开发的完整参考指南。
When to Use This Skill
适用场景
- Writing form scripts (refresh, validate, field events)
- Manipulating form fields (show/hide, require, read-only)
- Creating dialogs and prompts
- Making API calls from client
- Customizing list views
- Adding custom buttons
- Handling child table events
- 编写表单脚本(刷新、验证、字段事件)
- 操作表单字段(显示/隐藏、设置必填、只读)
- 创建对话框与提示框
- 从客户端发起API调用
- 定制列表视图
- 添加自定义按钮
- 处理子表格事件
Form Script Location
表单脚本位置
my_app/
└── my_module/
└── doctype/
└── my_doctype/
└── my_doctype.js # Client scriptmy_app/
└── my_module/
└── doctype/
└── my_doctype/
└── my_doctype.js # Client scriptForm Events
表单事件
Complete Event Reference
完整事件参考
javascript
frappe.ui.form.on('My DocType', {
// === LOAD EVENTS ===
setup: function(frm) {
// Called once when form is created (before data loads)
// Use for: setting queries, initializing variables
frm.set_query('customer', () => ({ filters: { status: 'Active' } }));
},
onload: function(frm) {
// Called when form data is loaded (before refresh)
// Use for: setting defaults for new docs
if (frm.is_new()) {
frm.set_value('posting_date', frappe.datetime.nowdate());
}
},
onload_post_render: function(frm) {
// Called after form is rendered
// Use for: DOM manipulation, focus setting
frm.get_field('customer').focus();
},
refresh: function(frm) {
// Called every time form refreshes
// Use for: custom buttons, field toggles, indicators
if (!frm.is_new()) {
frm.add_custom_button(__('Action'), () => do_action(frm));
}
frm.toggle_display('section_name', frm.doc.show_section);
},
// === SAVE EVENTS ===
validate: function(frm) {
// Called before save - return false to prevent
if (frm.doc.end_date < frm.doc.start_date) {
frappe.msgprint(__('End Date cannot be before Start Date'));
return false;
}
},
before_save: function(frm) {
// Called after validate, before server request
frm.doc.last_updated_by = frappe.session.user;
},
after_save: function(frm) {
// Called after successful save
frappe.show_alert({
message: __('Saved successfully'),
indicator: 'green'
});
},
// === WORKFLOW EVENTS ===
before_submit: function(frm) {
// Called before document submission
},
on_submit: function(frm) {
// Called after successful submission
},
before_cancel: function(frm) {
// Called before cancellation
},
after_cancel: function(frm) {
// Called after cancellation
},
// === FIELD EVENTS ===
customer: function(frm) {
// Called when 'customer' field changes
if (frm.doc.customer) {
fetch_customer_details(frm);
}
},
posting_date: function(frm) {
// Called when 'posting_date' field changes
calculate_due_date(frm);
}
});javascript
frappe.ui.form.on('My DocType', {
// === 加载事件 ===
setup: function(frm) {
// 表单创建时调用一次(数据加载前)
// 用途:设置查询、初始化变量
frm.set_query('customer', () => ({ filters: { status: 'Active' } }));
},
onload: function(frm) {
// 表单数据加载完成后调用(刷新前)
// 用途:为新文档设置默认值
if (frm.is_new()) {
frm.set_value('posting_date', frappe.datetime.nowdate());
}
},
onload_post_render: function(frm) {
// 表单渲染完成后调用
// 用途:DOM操作、设置焦点
frm.get_field('customer').focus();
},
refresh: function(frm) {
// 每次表单刷新时调用
// 用途:添加自定义按钮、切换字段显示、设置指示器
if (!frm.is_new()) {
frm.add_custom_button(__('Action'), () => do_action(frm));
}
frm.toggle_display('section_name', frm.doc.show_section);
},
// === 保存事件 ===
validate: function(frm) {
// 保存前调用 - 返回false可阻止保存
if (frm.doc.end_date < frm.doc.start_date) {
frappe.msgprint(__('End Date cannot be before Start Date'));
return false;
}
},
before_save: function(frm) {
// 验证通过后、发起服务器请求前调用
frm.doc.last_updated_by = frappe.session.user;
},
after_save: function(frm) {
// 保存成功后调用
frappe.show_alert({
message: __('Saved successfully'),
indicator: 'green'
});
},
// === 工作流事件 ===
before_submit: function(frm) {
// 文档提交前调用
},
on_submit: function(frm) {
// 提交成功后调用
},
before_cancel: function(frm) {
// 取消前调用
},
after_cancel: function(frm) {
// 取消成功后调用
},
// === 字段事件 ===
customer: function(frm) {
// 当'customer'字段变更时调用
if (frm.doc.customer) {
fetch_customer_details(frm);
}
},
posting_date: function(frm) {
// 当'posting_date'字段变更时调用
calculate_due_date(frm);
}
});Field Manipulation
字段操作
Display Properties
显示属性
javascript
// Show/hide field
frm.toggle_display('fieldname', true); // Show
frm.toggle_display('fieldname', false); // Hide
frm.toggle_display(['field1', 'field2'], condition);
// Set read-only
frm.set_df_property('fieldname', 'read_only', 1);
frm.toggle_enable('fieldname', false); // Disable
// Set required
frm.set_df_property('fieldname', 'reqd', 1);
frm.toggle_reqd('fieldname', true);
frm.toggle_reqd(['field1', 'field2'], condition);
// Set hidden
frm.set_df_property('fieldname', 'hidden', 1);
// Change label
frm.set_df_property('fieldname', 'label', 'New Label');
// Change description
frm.set_df_property('fieldname', 'description', 'Help text');
// Change options (for Select)
frm.set_df_property('fieldname', 'options', 'Option1\nOption2\nOption3');
// Refresh after changes
frm.refresh_field('fieldname');
frm.refresh_fields();javascript
// 显示/隐藏字段
frm.toggle_display('fieldname', true); // 显示
frm.toggle_display('fieldname', false); // 隐藏
frm.toggle_display(['field1', 'field2'], condition);
// 设置只读
frm.set_df_property('fieldname', 'read_only', 1);
frm.toggle_enable('fieldname', false); // 禁用
// 设置必填
frm.set_df_property('fieldname', 'reqd', 1);
frm.toggle_reqd('fieldname', true);
frm.toggle_reqd(['field1', 'field2'], condition);
// 设置隐藏
frm.set_df_property('fieldname', 'hidden', 1);
// 修改标签
frm.set_df_property('fieldname', 'label', 'New Label');
// 修改描述
frm.set_df_property('fieldname', 'description', 'Help text');
// 修改选项(下拉框)
frm.set_df_property('fieldname', 'options', 'Option1\nOption2\nOption3');
// 修改后刷新
frm.refresh_field('fieldname');
frm.refresh_fields();Set Values
设置值
javascript
// Set single value
frm.set_value('fieldname', value);
// Set multiple values
frm.set_value({
'field1': 'value1',
'field2': 'value2',
'field3': 'value3'
});
// Set with callback
frm.set_value('fieldname', value).then(() => {
// After value is set
});
// Clear field
frm.set_value('fieldname', null);
frm.set_value('fieldname', '');
// Set default value
frm.set_df_property('fieldname', 'default', 'default_value');javascript
// 设置单个值
frm.set_value('fieldname', value);
// 设置多个值
frm.set_value({
'field1': 'value1',
'field2': 'value2',
'field3': 'value3'
});
// 设置值并添加回调
frm.set_value('fieldname', value).then(() => {
// 值设置完成后执行
});
// 清空字段
frm.set_value('fieldname', null);
frm.set_value('fieldname', '');
// 设置默认值
frm.set_df_property('fieldname', 'default', 'default_value');Link Field Queries
链接字段查询
javascript
// Basic filter
frm.set_query('customer', function() {
return {
filters: {
status: 'Active',
customer_type: 'Company'
}
};
});
// Dynamic filter based on form values
frm.set_query('item_code', function() {
return {
filters: {
item_group: frm.doc.item_group,
is_stock_item: 1
}
};
});
// Filter in child table
frm.set_query('item_code', 'items', function(doc, cdt, cdn) {
let row = locals[cdt][cdn];
return {
filters: {
warehouse: row.warehouse || doc.default_warehouse
}
};
});
// Custom query (server method)
frm.set_query('supplier', function() {
return {
query: 'my_app.api.get_suppliers',
filters: {
region: frm.doc.region
}
};
});
// Clear query
frm.set_query('fieldname', null);javascript
// 基础过滤
frm.set_query('customer', function() {
return {
filters: {
status: 'Active',
customer_type: 'Company'
}
};
});
// 基于表单值的动态过滤
frm.set_query('item_code', function() {
return {
filters: {
item_group: frm.doc.item_group,
is_stock_item: 1
}
};
});
// 子表格中的过滤
frm.set_query('item_code', 'items', function(doc, cdt, cdn) {
let row = locals[cdt][cdn];
return {
filters: {
warehouse: row.warehouse || doc.default_warehouse
}
};
});
// 自定义查询(服务器方法)
frm.set_query('supplier', function() {
return {
query: 'my_app.api.get_suppliers',
filters: {
region: frm.doc.region
}
};
});
// 清除查询
frm.set_query('fieldname', null);Custom Buttons
自定义按钮
javascript
refresh: function(frm) {
// Simple button
frm.add_custom_button(__('Do Something'), function() {
do_something(frm);
});
// Button in group/dropdown
frm.add_custom_button(__('Action 1'), function() {
action_1(frm);
}, __('Actions'));
frm.add_custom_button(__('Action 2'), function() {
action_2(frm);
}, __('Actions'));
// Primary button (highlighted)
frm.add_custom_button(__('Submit'), function() {
submit_doc(frm);
}).addClass('btn-primary');
// Button with icon
let btn = frm.add_custom_button(__('Print'), function() {
print_doc(frm);
});
btn.prepend('<i class="fa fa-print"></i> ');
// Conditional buttons
if (frm.doc.status === 'Draft') {
frm.add_custom_button(__('Submit for Review'), function() {
submit_for_review(frm);
});
}
// Remove button
frm.remove_custom_button(__('Do Something'));
frm.remove_custom_button(__('Action 1'), __('Actions'));
// Clear all buttons
frm.clear_custom_buttons();
// Page actions
frm.page.set_primary_action(__('Save'), function() {
frm.save();
});
frm.page.set_secondary_action(__('Cancel'), function() {
frappe.set_route('List', 'My DocType');
});
}javascript
refresh: function(frm) {
// 简单按钮
frm.add_custom_button(__('Do Something'), function() {
do_something(frm);
});
// 分组/下拉菜单中的按钮
frm.add_custom_button(__('Action 1'), function() {
action_1(frm);
}, __('Actions'));
frm.add_custom_button(__('Action 2'), function() {
action_2(frm);
}, __('Actions'));
// 主按钮(高亮显示)
frm.add_custom_button(__('Submit'), function() {
submit_doc(frm);
}).addClass('btn-primary');
// 带图标的按钮
let btn = frm.add_custom_button(__('Print'), function() {
print_doc(frm);
});
btn.prepend('<i class="fa fa-print"></i> ');
// 条件按钮
if (frm.doc.status === 'Draft') {
frm.add_custom_button(__('Submit for Review'), function() {
submit_for_review(frm);
});
}
// 移除按钮
frm.remove_custom_button(__('Do Something'));
frm.remove_custom_button(__('Action 1'), __('Actions'));
// 清除所有按钮
frm.clear_custom_buttons();
// 页面操作
frm.page.set_primary_action(__('Save'), function() {
frm.save();
});
frm.page.set_secondary_action(__('Cancel'), function() {
frappe.set_route('List', 'My DocType');
});
}Child Table Operations
子表格操作
Events
事件
javascript
frappe.ui.form.on('My DocType Item', {
// Row added
items_add: function(frm, cdt, cdn) {
let row = locals[cdt][cdn];
row.warehouse = frm.doc.default_warehouse;
frm.refresh_field('items');
},
// Before row removed (can prevent)
before_items_remove: function(frm, cdt, cdn) {
let row = locals[cdt][cdn];
if (row.is_mandatory) {
frappe.throw(__('Cannot remove mandatory item'));
}
},
// Row removed
items_remove: function(frm, cdt, cdn) {
calculate_total(frm);
},
// Field in row changes
qty: function(frm, cdt, cdn) {
let row = locals[cdt][cdn];
row.amount = flt(row.qty) * flt(row.rate);
frm.refresh_field('items');
calculate_total(frm);
},
rate: function(frm, cdt, cdn) {
let row = locals[cdt][cdn];
row.amount = flt(row.qty) * flt(row.rate);
frm.refresh_field('items');
calculate_total(frm);
},
item_code: function(frm, cdt, cdn) {
let row = locals[cdt][cdn];
if (row.item_code) {
frappe.call({
method: 'my_app.api.get_item_details',
args: { item_code: row.item_code },
callback: function(r) {
if (r.message) {
frappe.model.set_value(cdt, cdn, {
'rate': r.message.rate,
'uom': r.message.uom,
'description': r.message.description
});
}
}
});
}
}
});
function calculate_total(frm) {
let total = 0;
frm.doc.items.forEach(item => {
total += flt(item.amount);
});
frm.set_value('total', total);
}javascript
frappe.ui.form.on('My DocType Item', {
// 行添加完成
items_add: function(frm, cdt, cdn) {
let row = locals[cdt][cdn];
row.warehouse = frm.doc.default_warehouse;
frm.refresh_field('items');
},
// 行移除前调用(可阻止移除)
before_items_remove: function(frm, cdt, cdn) {
let row = locals[cdt][cdn];
if (row.is_mandatory) {
frappe.throw(__('Cannot remove mandatory item'));
}
},
// 行移除完成
items_remove: function(frm, cdt, cdn) {
calculate_total(frm);
},
// 行内字段变更
qty: function(frm, cdt, cdn) {
let row = locals[cdt][cdn];
row.amount = flt(row.qty) * flt(row.rate);
frm.refresh_field('items');
calculate_total(frm);
},
rate: function(frm, cdt, cdn) {
let row = locals[cdt][cdn];
row.amount = flt(row.qty) * flt(row.rate);
frm.refresh_field('items');
calculate_total(frm);
},
item_code: function(frm, cdt, cdn) {
let row = locals[cdt][cdn];
if (row.item_code) {
frappe.call({
method: 'my_app.api.get_item_details',
args: { item_code: row.item_code },
callback: function(r) {
if (r.message) {
frappe.model.set_value(cdt, cdn, {
'rate': r.message.rate,
'uom': r.message.uom,
'description': r.message.description
});
}
}
});
}
}
});
function calculate_total(frm) {
let total = 0;
frm.doc.items.forEach(item => {
total += flt(item.amount);
});
frm.set_value('total', total);
}Manipulating Rows
行操作
javascript
// Add row
let row = frm.add_child('items', {
item_code: 'ITEM-001',
qty: 10,
rate: 100
});
frm.refresh_field('items');
// Get row by index
let first_row = frm.doc.items[0];
// Get row by name
let row = locals['My DocType Item'][cdn];
// Update row
frappe.model.set_value(cdt, cdn, 'fieldname', value);
frappe.model.set_value(cdt, cdn, {
'field1': 'value1',
'field2': 'value2'
});
// Remove row
frm.get_field('items').grid.grid_rows[0].remove();
frm.refresh_field('items');
// Remove all rows
frm.clear_table('items');
frm.refresh_field('items');
// Iterate rows
frm.doc.items.forEach((item, idx) => {
console.log(idx, item.item_code);
});javascript
// 添加行
let row = frm.add_child('items', {
item_code: 'ITEM-001',
qty: 10,
rate: 100
});
frm.refresh_field('items');
// 通过索引获取行
let first_row = frm.doc.items[0];
// 通过名称获取行
let row = locals['My DocType Item'][cdn];
// 更新行
frappe.model.set_value(cdt, cdn, 'fieldname', value);
frappe.model.set_value(cdt, cdn, {
'field1': 'value1',
'field2': 'value2'
});
// 移除行
frm.get_field('items').grid.grid_rows[0].remove();
frm.refresh_field('items');
// 移除所有行
frm.clear_table('items');
frm.refresh_field('items');
// 遍历行
frm.doc.items.forEach((item, idx) => {
console.log(idx, item.item_code);
});Dialogs
对话框
Simple Prompt
简单提示框
javascript
// Single field
frappe.prompt(
{
fieldname: 'reason',
fieldtype: 'Small Text',
label: 'Reason',
reqd: 1
},
function(values) {
console.log(values.reason);
},
__('Enter Reason'),
__('Submit')
);javascript
// 单个字段
frappe.prompt(
{
fieldname: 'reason',
fieldtype: 'Small Text',
label: 'Reason',
reqd: 1
},
function(values) {
console.log(values.reason);
},
__('Enter Reason'),
__('Submit')
);Multi-field Prompt
多字段提示框
javascript
frappe.prompt([
{
fieldname: 'customer',
fieldtype: 'Link',
options: 'Customer',
label: 'Customer',
reqd: 1
},
{
fieldname: 'date',
fieldtype: 'Date',
label: 'Date',
default: frappe.datetime.nowdate()
},
{
fieldname: 'priority',
fieldtype: 'Select',
label: 'Priority',
options: 'Low\nMedium\nHigh',
default: 'Medium'
}
], function(values) {
process_data(values);
}, __('Enter Details'), __('Process'));javascript
frappe.prompt([
{
fieldname: 'customer',
fieldtype: 'Link',
options: 'Customer',
label: 'Customer',
reqd: 1
},
{
fieldname: 'date',
fieldtype: 'Date',
label: 'Date',
default: frappe.datetime.nowdate()
},
{
fieldname: 'priority',
fieldtype: 'Select',
label: 'Priority',
options: 'Low\nMedium\nHigh',
default: 'Medium'
}
], function(values) {
process_data(values);
}, __('Enter Details'), __('Process'));Custom Dialog
自定义对话框
javascript
let dialog = new frappe.ui.Dialog({
title: __('Custom Dialog'),
fields: [
{
fieldname: 'customer',
fieldtype: 'Link',
options: 'Customer',
label: __('Customer'),
reqd: 1,
get_query: function() {
return { filters: { status: 'Active' } };
},
change: function() {
// Field change handler
let value = dialog.get_value('customer');
if (value) {
dialog.set_value('customer_name', 'Loading...');
}
}
},
{ fieldtype: 'Column Break' },
{
fieldname: 'customer_name',
fieldtype: 'Data',
label: __('Customer Name'),
read_only: 1
},
{ fieldtype: 'Section Break', label: 'Items' },
{
fieldname: 'items',
fieldtype: 'Table',
label: __('Items'),
cannot_add_rows: false,
in_place_edit: true,
fields: [
{
fieldname: 'item',
fieldtype: 'Link',
options: 'Item',
in_list_view: 1,
label: __('Item')
},
{
fieldname: 'qty',
fieldtype: 'Float',
in_list_view: 1,
label: __('Qty')
}
]
}
],
size: 'large', // small, large, extra-large
primary_action_label: __('Submit'),
primary_action: function(values) {
console.log(values);
dialog.hide();
process_dialog(values);
},
secondary_action_label: __('Cancel')
});
dialog.show();
// Set values
dialog.set_value('customer', 'CUST-001');
dialog.set_values({
'customer': 'CUST-001',
'date': frappe.datetime.nowdate()
});
// Get values
let values = dialog.get_values();
let customer = dialog.get_value('customer');
// Access fields
let field = dialog.get_field('customer');
field.set_description('Select active customer');javascript
let dialog = new frappe.ui.Dialog({
title: __('Custom Dialog'),
fields: [
{
fieldname: 'customer',
fieldtype: 'Link',
options: 'Customer',
label: __('Customer'),
reqd: 1,
get_query: function() {
return { filters: { status: 'Active' } };
},
change: function() {
// 字段变更处理器
let value = dialog.get_value('customer');
if (value) {
dialog.set_value('customer_name', 'Loading...');
}
}
},
{ fieldtype: 'Column Break' },
{
fieldname: 'customer_name',
fieldtype: 'Data',
label: __('Customer Name'),
read_only: 1
},
{ fieldtype: 'Section Break', label: 'Items' },
{
fieldname: 'items',
fieldtype: 'Table',
label: __('Items'),
cannot_add_rows: false,
in_place_edit: true,
fields: [
{
fieldname: 'item',
fieldtype: 'Link',
options: 'Item',
in_list_view: 1,
label: __('Item')
},
{
fieldname: 'qty',
fieldtype: 'Float',
in_list_view: 1,
label: __('Qty')
}
]
}
],
size: 'large', // small, large, extra-large
primary_action_label: __('Submit'),
primary_action: function(values) {
console.log(values);
dialog.hide();
process_dialog(values);
},
secondary_action_label: __('Cancel')
});
dialog.show();
// 设置值
dialog.set_value('customer', 'CUST-001');
dialog.set_values({
'customer': 'CUST-001',
'date': frappe.datetime.nowdate()
});
// 获取值
let values = dialog.get_values();
let customer = dialog.get_value('customer');
// 访问字段
let field = dialog.get_field('customer');
field.set_description('Select active customer');Confirmation Dialog
确认对话框
javascript
frappe.confirm(
__('Are you sure you want to delete this?'),
function() {
// On Yes
delete_record();
},
function() {
// On No (optional)
}
);javascript
frappe.confirm(
__('Are you sure you want to delete this?'),
function() {
// 确认后执行
delete_record();
},
function() {
// 取消后执行(可选)
}
);API Calls
API调用
frappe.call
frappe.call
javascript
// Basic call
frappe.call({
method: 'my_app.api.get_data',
args: {
customer: frm.doc.customer
},
callback: function(r) {
if (r.message) {
frm.set_value('data', r.message);
}
}
});
// With loading indicator
frappe.call({
method: 'my_app.api.process',
args: { data: frm.doc },
freeze: true,
freeze_message: __('Processing...'),
callback: function(r) {
frappe.msgprint(__('Done!'));
},
error: function(r) {
frappe.msgprint(__('Error occurred'));
}
});
// Async/await
async function getData() {
const r = await frappe.call({
method: 'my_app.api.get_data',
args: { id: 123 }
});
return r.message;
}
// Promise chain
frappe.call({
method: 'my_app.api.get_data'
}).then(r => {
return frappe.call({
method: 'my_app.api.process',
args: { data: r.message }
});
}).then(r => {
console.log('Done', r.message);
});javascript
// 基础调用
frappe.call({
method: 'my_app.api.get_data',
args: {
customer: frm.doc.customer
},
callback: function(r) {
if (r.message) {
frm.set_value('data', r.message);
}
}
});
// 带加载指示器的调用
frappe.call({
method: 'my_app.api.process',
args: { data: frm.doc },
freeze: true,
freeze_message: __('Processing...'),
callback: function(r) {
frappe.msgprint(__('Done!'));
},
error: function(r) {
frappe.msgprint(__('Error occurred'));
}
});
// Async/await 方式
async function getData() {
const r = await frappe.call({
method: 'my_app.api.get_data',
args: { id: 123 }
});
return r.message;
}
// Promise链式调用
frappe.call({
method: 'my_app.api.get_data'
}).then(r => {
return frappe.call({
method: 'my_app.api.process',
args: { data: r.message }
});
}).then(r => {
console.log('Done', r.message);
});Messages & Alerts
消息与提示
javascript
// Toast alert
frappe.show_alert({
message: __('Success!'),
indicator: 'green' // green, blue, orange, red
}, 5); // seconds
// Message dialog
frappe.msgprint({
title: __('Information'),
message: __('This is important'),
indicator: 'blue'
});
// Error (stops execution)
frappe.throw(__('Cannot proceed'));
// Confirmation required
frappe.validated = false; // In validate eventjavascript
// 提示弹窗
frappe.show_alert({
message: __('Success!'),
indicator: 'green' // green, blue, orange, red
}, 5); // 显示时长(秒)
// 消息对话框
frappe.msgprint({
title: __('Information'),
message: __('This is important'),
indicator: 'blue'
});
// 错误提示(终止执行)
frappe.throw(__('Cannot proceed'));
// 标记验证不通过
frappe.validated = false; // 在validate事件中使用Utilities
工具函数
javascript
// Date/Time
frappe.datetime.nowdate(); // "2024-01-15"
frappe.datetime.now_datetime(); // "2024-01-15 10:30:00"
frappe.datetime.add_days("2024-01-15", 7);
frappe.datetime.add_months("2024-01-15", 1);
// Formatting
frappe.format(1234.56, {fieldtype: 'Currency'});
format_currency(1234.56, 'USD');
flt(value); // Float
cint(value); // Integer
// Navigation
frappe.set_route('Form', 'Customer', 'CUST-001');
frappe.set_route('List', 'Customer');
frappe.new_doc('Customer');
// Translation
__('Translate this');
__('Hello {0}', [name]);javascript
// 日期/时间
frappe.datetime.nowdate(); // "2024-01-15"
frappe.datetime.now_datetime(); // "2024-01-15 10:30:00"
frappe.datetime.add_days("2024-01-15", 7);
frappe.datetime.add_months("2024-01-15", 1);
// 格式化
frappe.format(1234.56, {fieldtype: 'Currency'});
format_currency(1234.56, 'USD');
flt(value); // 转换为浮点数
cint(value); // 转换为整数
// 页面导航
frappe.set_route('Form', 'Customer', 'CUST-001');
frappe.set_route('List', 'Customer');
frappe.new_doc('Customer');
// 翻译
__('Translate this');
__('Hello {0}', [name]);