JavaScript 参考

本文介绍 Odoo JavaScript 框架。这个框架在代码行数上并不是一个大型应用,但它非常通用,因为其本质是一台机器,能把声明式的界面描述转换为一个实时应用,能够与数据库中的每个模型和记录交互。甚至可以使用 Web 客户端来修改 Web 客户端的界面。

概述

JavaScript 框架设计用于三种主要使用场景:

  • Web 客户端:这是私有的 Web 应用,在这里可以查看和编辑业务数据。它是一个单页应用(页面从不重新加载,只在需要时从服务器获取新数据)

  • 网站:这是 Odoo 的公开部分。它允许未识别身份的用户以客户身份浏览内容、购物或执行许多操作。这是一个典型的网站:包含带控制器的各种路由,以及一些让网站运转的 JavaScript。

  • 销售点:这是销售点的界面。它是一个专门化的单页应用。

有些 JavaScript 代码是这三种场景共用的,会被一起打包(参见下文资源部分)。本文档主要聚焦于 Web 客户端的架构。

Web 客户端

单页应用

Web 客户端是一个单页应用:它不会在用户每次执行操作时都向服务器请求完整页面,而只加载更新用户界面(UI)所需的内容。在此过程中,它还会负责更新 URL 中的信息,因此在大多数情况下,刷新页面或关闭浏览器再重新打开,看到的都是相同的内容。

Web 客户端 JS 代码概览

这里我们非常简要地概述 web 插件中的 Web 客户端代码。路径将相对于 web/static/src 来描述。以下描述有意并不详尽;目标只是让读者对架构有一个鸟瞰式的了解。

  • module_loader.js:这是定义 Odoo JavaScript 模块系统的文件。它需要先于任何其他 JS 模块加载。

  • core/:此文件夹包含构成 JavaScript 框架最底层的代码,可用于 Web 客户端以及网站、门户和销售点应用。

  • weblient/:此文件夹包含 Web 客户端专用的文件,无法在网站或销售点中使用,例如动作管理器和动作服务。

  • webclient/webclient.js:这是 webclient 组件本身。它主要是动作容器和导航栏的包装器,并执行一些启动应用时所需的操作,例如加载 URL 的状态。

  • webclient/actions/:此文件夹包含负责显示动作以及在动作之间切换的代码。

  • views/:此文件夹包含视图基础设施的代码,以及大多数视图(某些类型的视图由其他插件添加)。

  • views/fields/:包含各种字段组件的定义,以及一些被多个字段使用的工具函数。

  • search/ 所有这些文件定义了搜索视图(从 Web 客户端的角度看,它不是视图,只有从服务器的角度看才是)

文件未加载或未更新时该怎么办

文件未能正确加载有很多不同的原因。以下是一些可以尝试的解决办法:

  • 确保已保存文件;谁都会有忘记保存的时候。

  • 查看控制台(在开发者工具中,通常用 F12 打开)并检查是否有错误。

  • 尝试在文件开头添加 console.log(),以便查看文件是否已加载。如果没有加载,可能是它不在正确的资源包中,或者资源包不是最新的。

  • 根据你的设置,文件被修改后服务器可能不会重新生成资源包;有几种方法可以解决这个问题:

    • 重启服务器会强制它在下次被请求时检查资源包是否为最新

    • 在调试模式下,调试菜单中有一个选项(导航栏中的 按钮),可以强制服务器在不重启的情况下即时重新生成资源包。

    • 使用 --dev=xml 选项启动服务器,会强制服务器在每次请求时检查资源包是否为最新。我们建议在积极开发时使用此选项,但不要在生产环境中使用。

  • 修改代码后确保刷新页面。Odoo 目前没有任何热模块重载机制。

加载 JavaScript 代码

大型应用通常会被拆分成较小的文件,这些文件需要相互连接。有些文件可能需要使用另一个文件中定义的代码。在文件之间共享代码有两种方式:

  • 使用全局作用域(window 对象)来读取或写入对某些对象或函数的引用,

  • 使用模块系统,它为每个模块提供导出或导入值的方式,并确保它们以正确的顺序加载。

虽然可以在全局作用域中工作,但这会带来许多问题:

  • 很难确保实现细节不被暴露:全局作用域中的函数声明对所有其他代码都是可访问的。

  • 只有一个命名空间,很容易产生命名冲突。

  • 依赖是隐式的:如果一段代码依赖另一段代码,它们的加载顺序就很重要,但很难保证。

使用模块系统有助于解决这些问题:由于模块会声明自己的依赖,模块系统可以按正确顺序加载它们,或者在依赖缺失或循环时报错。模块还会形成自己的命名空间,并能选择导出什么,从而避免暴露实现细节和命名冲突。

虽然我们可以直接使用 ECMAScript(ES)模块,但这种方式有一些缺点:每个 ES 模块都需要一次网络往返,当有数百个文件时会变得非常慢;而且 Odoo 中的许多文件需要存在,尽管没有被任何东西导入,因为它们只是添加了框架会使用的代码,而不是反过来由框架导入。

因此,Odoo 有一套资源包机制。在这些资源包中,JavaScript 文件是带有顶部特殊注释的 ES 模块。这些模块会被一起打包并转译,以便我们的模块加载器能够使用。虽然你可以编写不使用此模块系统的代码,但通常并不推荐。

(参见 原生 JavaScript 模块)

修补类

尽管我们尽力提供无需这样做的扩展点,但有时仍需要 就地 修改现有类的行为。目标是提供一种机制,能够修改一个类以及所有未来和当前的实例。这通过使用 patch 工具函数来完成:

import { Hamster } from "@web/core/hamster"
import { patch } from "@web/core/utils/patch";

patch(Hamster.prototype, {
    sleep() {
        super.sleep(...arguments);
        console.log("zzzz");
    },
});

修补方法时,需要修补类的原型;但如果你想修补类的静态属性,则需要修补类本身。

修补是一项危险的操作,应谨慎进行,因为它会修改该类的所有实例,即使是已经创建的实例。为避免出现奇怪的问题,应尽早在模块顶层应用修补。如果类已经实例化,在运行时修补类可能导致极难调试的问题。

注册表

Odoo 生态中一个常见的需求是从外部(通过安装一个应用,即另一个模块)扩展或改变基础系统的行为。例如,可能需要为某些视图添加一个新的字段组件。在这种情况下以及许多其他情况下,通常的做法是先创建所需的组件,然后将其添加到注册表(注册步骤),让 Web 客户端的其余部分知道它的存在。

系统中有几个可用的注册表。框架所使用的注册表是主注册表上的类别,可以从 @web/core/registry 导入

字段注册表

字段注册表包含 Web 客户端已知的所有字段组件。每当视图(通常是表单或列表/看板)需要字段组件时,就会在这里查找。一个典型的使用场景如下所示:

import { registry } from "@web/core/registry";
class PadField extends Component { ... }

registry.category("fields").add("pad", {
  component: PadField,
  supportedTypes: ["char"],
  // ...
});
视图注册表

该注册表包含 Web 客户端已知的所有 JS 视图。

动作注册表

我们在此注册表中跟踪所有客户端动作。动作管理器在需要创建客户端动作时,会在此处查找。客户端动作可以是一个函数——调用该动作时函数会被调用,如有需要,其返回值将作为后续动作执行——也可以是一个 Owl 组件,执行该动作时会被显示。

服务

在 Web 客户端中,有些关注点无法由单个组件处理,因为这些关注点是横向的、涉及多个组件,或者需要在应用存活期间一直维护某些状态。

服务正是这些问题的解决方案:它们在应用启动时创建,组件可通过钩子 useService 获取,并且在应用的整个生命周期内保持存活。

例如,我们有 orm 服务,其职责是允许与服务器上的业务对象进行交互。

以下是一个简化示例,展示 orm 服务是如何实现的:

import { registry } from "@web/core/registry";
export const OrmService = {
    start() {
        return {
            read(...) { ... },
            write(...) { ... },
            unlink(...) { ... },
            ...
        }
    },
};
registry.category("services").add("orm", OrmService);

使用服务

服务在环境中可用,但通常应通过 useService 钩子使用,该钩子可防止在组件销毁后调用服务上的方法,并且在组件于方法调用期间被销毁时,阻止该方法调用之后继续执行代码。

class SomeComponent extends Component {
    setup() {
        this.orm = useService("orm");
    }
    // ...
    getActivityModelViewID(model) {
        return this.orm.call(model, "get_activity_view_id", this.params);
    }
}

与服务器通信

在 Odoo 中工作时通常有两种用例:可能需要调用(Python)模型上的方法(这会经过控制器 /web/dataset/call_kw),或者可能需要直接调用某个控制器(在某些路由上可用)。

  • 调用 Python 模型上的方法通过 orm 服务完成:

    return this.orm.call("some.model", "some_method", [some, args]);
    
  • 直接调用控制器则通过 rpc 服务完成:

    return this.rpc("/some/route/", {
        some: param,
    });
    

注解

rpc 服务实际上并不执行通常所理解的远程过程调用(RPC),但出于历史原因,在 Odoo 中我们通常将 JavaScript 中执行的任何网络请求都称为 RPC。正如上一段所强调的,如果要调用模型上的方法,应使用 orm 服务。

通知

Odoo 框架有一种向用户传达各类信息的标准方式:通知,它们显示在用户界面的右上角。通知类型沿用 Bootstrap 的 toast 提示样式:

  • info:适合在某个不会失败的动作完成后显示信息性反馈。

  • success:用户执行了一个有时可能失败但实际并未失败的动作。

  • warning:用户执行的动作只能部分完成。当出现问题但并非由用户直接引起,或该问题没有特别可采取的措施时也很有用。

  • success:用户尝试执行某个动作,但该动作未能完成。

通知还可以用来在不打扰用户工作流的情况下向其提问:例如,通过 VOIP 收到一通电话时,可以显示一个带有 接受 或 拒绝 两个按钮的常驻通知。

显示通知

在 Odoo 中有两种显示通知的方式:

  • notification 服务允许组件通过调用 add 方法从 JS 代码中显示通知。

  • display_notification 客户端动作允许从 Python 触发通知的显示(例如在用户点击 type 为 object 的按钮时所调用的方法中)。该客户端动作使用 notification 服务。

通知有几个 选项:

  • title:字符串,可选。它将作为标题显示在顶部。

  • message:字符串,可选。通知的内容。可以是一个 markup 对象,用于显示带格式的文本。

  • sticky:布尔值,可选(默认 false)。如果为 true,通知将一直保留,直到用户将其关闭。否则,通知会在短暂延迟后自动关闭。

  • type:字符串,可选(默认 “warning”)。决定通知的样式。可选值:”info”、”success”、”warning”、”danger”

  • className:字符串,可选。这是一个会自动添加到通知上的 CSS 类名。它可用于设置样式,尽管不鼓励使用。

以下是一些在 JS 中显示通知的示例:

// note that we call _t on the text to make sure it is properly translated.
this.notification.add({
    title: _t("Success"),
    message: _t("Your signature request has been sent.")
});
this.notification.add({
    title: _t("Error"),
    message: _t("Filter name is required."),
    type: "danger",
});

以及在 Python 中:

# note that we call _(string) on the text to make sure it is properly translated.
def show_notification(self):
    return {
        'type': 'ir.actions.client',
        'tag': 'display_notification',
        'params': {
            'title': _('Success'),
            'message': _('Your signature request has been sent.'),
            'sticky': False,
        }
    }

系统托盘

系统托盘是界面中导航栏的右侧部分,Web 客户端在此显示一些小部件,例如消息菜单。

当导航栏创建系统托盘时,它会查找所有已注册的托盘项并显示它们。

目前托盘项还没有专门的 API。它们是 Owl 组件,可以像其他组件一样与其环境通信,例如通过与服务交互。

添加新的托盘项

可以通过将项添加到 “systray” 注册表中来向系统托盘添加托盘项:

import { registry } from "@web/core/registry"
class MySystrayComponent extends Component {
    ...
}
registry.category("systray").add("MySystrayComponent", MySystrayComponent, { sequence: 1 });

各托盘项按照其在 systray 注册表中的顺序排列。

翻译管理

部分翻译在服务器端完成(基本上所有由服务器渲染或处理的文本字符串),但静态文件中也有一些字符串需要翻译。当前的工作方式如下:

  • 每个可翻译字符串都用特殊函数 _t 标记

  • 服务器使用这些字符串来生成相应的 PO 文件

  • 每当 Web 客户端加载时,它会调用路由 /web/webclient/translations,该路由返回所有可翻译术语的列表

  • 在运行时,每当调用函数 _t 时,它会在该列表中查找译文,并返回找到的译文;如果找不到,则返回原始字符串。

请注意,文档 翻译模块 从服务器视角更详细地解释了翻译。

import { _t } from "@web/core/l10n/translation";

class SomeComponent extends Component {
    static exampleString = _t("this should be translated");
    ...
    someMethod() {
        const str = _t("some text");
    }
}

请注意,使用翻译函数需要谨慎:作为参数传入的字符串不能是动态的,因为它是从代码中静态提取出来用于生成 PO 文件的,并作为待翻译术语的标识符。如果需要在字符串中注入动态内容,_t 支持占位符:

import { _t } from "@web/core/l10n/translation";
const str = _t("Hello %s, you have %s unread messages.", user.name, unreadCount);

注意字符串本身是固定的。这使得翻译函数能够在用于插值 之前 获取已翻译的字符串。

会话

Web 客户端需要从 Python 获取一些信息才能正常运行。为避免在 JavaScript 中发起网络请求而与服务器多一次往返,这些信息会直接序列化到页面中,并可在 JS 中通过 @web/session 模块访问。

向会话中添加信息

当加载 /web 路由时,服务器会将这些信息注入到一个 script 标签中。这些信息通过调用模型 ir.http 的 session_info 方法获取。你可以重写该方法,向返回的字典中添加信息。

from odoo import models
from odoo.http import request

class IrHttp(models.AbstractModel):
    _inherit = ['ir.http']

    def session_info(self):
        result = super(IrHttp, self).session_info()
        result['some_key'] = get_some_value_from_db()
        return result

现在,可以在 JavaScript 中通过读取会话来获取该值:

import { session } from "@web/session"
const myValue = session.some_key;
...

请注意,该机制旨在减少 Web 客户端准备就绪所需的通信量。它仅适用于计算成本较低的数据(缓慢的 session_info 调用会延迟所有人的 Web 客户端加载),以及初始化过程中早期就需要的数据。

视图

“view” 一词有多种含义。本节讨论的是视图的 JavaScript 代码设计,而不是 arch 的结构或其他内容。

虽然视图只是 Owl 组件,但内置视图通常具有相同的结构:一个名为 “SomethingController” 的组件作为视图的根组件。该组件会创建某个 “model”(负责管理数据的对象)的实例,并拥有一个名为 “renderer” 的子组件来处理显示逻辑。

字段

Web 客户端体验的很大一部分在于编辑和创建数据。这些工作大多借助字段小部件完成,字段小部件了解字段类型,也了解值应如何显示和编辑的具体细节。

装饰

与列表视图一样,字段小部件对装饰提供了简单的支持。装饰的目标是提供一种简单的方式,根据记录的当前状态指定文本颜色。例如:

<field name="state" decoration-danger="amount &lt; 10000"/>

有效的装饰名称有:

  • decoration-bf

  • decoration-it

  • decoration-danger

  • decoration-info

  • decoration-muted

  • decoration-primary

  • decoration-success

  • decoration-warning

每个装饰 decoration-X 都会映射到一个 CSS 类 text-X,这是一个标准的 Bootstrap CSS 类(text-it 和 text-bf 除外,它们由 Odoo 处理,分别对应斜体和粗体)。请注意,decoration 属性的值应是有效的 Python 表达式,将以记录作为求值上下文进行评估。

非关系字段

这里记录所有默认提供的非关系字段,顺序不分先后。

整数 (integer)

这是 integer 类型字段的默认字段类型。

  • 支持的字段类型:integer

选项:

  • type:设置输入类型(默认为 "text",可设置为 "number")

    在编辑模式下,该字段会渲染为一个 input,其 HTML 属性 type 设置为 "number" (这样用户可以利用原生支持,尤其是在移动端)。在这种情况下,默认格式化会被禁用,以避免不兼容。

    <field name="int_value" options="{'type': 'number'}" />
    
  • step:设置用户点击按钮时数值向上和向下调整的步长(仅适用于 type 为 number 的输入框,默认为 1)

    <field name="int_value" options="{'type': 'number', 'step': 100}" />
    
  • format:是否格式化数字。(默认为 true)

    默认情况下,数字会按照区域设置参数进行格式化。该选项会阻止对字段值进行格式化。

    <field name="int_value" options='{"format": false}' />
    
浮点数(float)

这是 float 类型字段的默认字段类型。

  • 支持的字段类型:float

属性:

  • digits:显示的精度

    <field name="factor" digits="[42,5]" />
    

选项:

  • type:设置输入类型(默认为 "text",可设置为 "number")

    在编辑模式下,该字段会渲染为一个 input,其 HTML 属性 type 设置为 "number" (这样用户可以利用原生支持,尤其是在移动端)。在这种情况下,默认格式化会被禁用,以避免不兼容。

    <field name="float_value" options="{'type': 'number'}" />
    
  • step:设置用户点击按钮时数值向上和向下调整的步长(仅适用于 type 为 number 的输入框,默认为 1)

    <field name="float_value" options="{'type': 'number', 'step': 0.1}" />
    
  • format:是否格式化数字。(默认为 true)

    默认情况下,数字会按照区域设置参数进行格式化。该选项会阻止对字段值进行格式化。

    <field name="float_value" options="{'format': false}" />
    
  • min_display_digits:要显示的最少小数位数。

    例如,如果设置为 3 且未提供小数精度:1.2 变为 "1.200",1.123 变为 "1.123",1.1234 变为 "1.1234"。

    <field name="float_value" options="{'min_display_digits': 3}" />
    
  • hide_trailing_zeros:隐藏最后一个非零数字右侧的零,例如 1.20 变为 1.2 (默认为 false)。

    <field name="float_value" options="{'hide_trailing_zeros': true}" />
    
时间(float_time)

该小部件的目标是正确显示表示时间间隔的浮点值(默认以小时为单位)。因此,例如 0.5 应格式化为 0h 30m,4.75 应格式化为 4h 45m。

  • 支持的字段类型:float

选项:

  • numeric:设置格式类型(默认为 false)

    如果设置为 true,格式将为 h:mm:ss。

    <field name="float_value" options="{'numeric': true}" />
    
  • show_seconds:显示秒(默认为 false)

    <field name="float_value" options="{'show_seconds': true}" />
    
  • unit:指定浮点值的时间单位(默认为 "hours")

    可用的时间单位有:"hours"、"minutes" 和 "seconds"。结果中始终会显示单位。如果为 "seconds",则 show_seconds 会被忽略,因为秒将始终显示。

    <field name="float_value" options="{'unit': 'minutes'}" />
    
浮点因子(float_factor)

该小部件旨在正确显示通过其选项中给定的因子转换后的浮点值。因此,例如数据库中保存的值为 0.5,因子为 3,则该小部件的值应格式化为 1.5。

  • 支持的字段类型:float

浮点切换(float_toggle)

该小部件的目标是用一个包含一系列可能值(在选项中给出)的按钮替换输入字段。每次点击都会让用户在该范围中循环。这样做的目的是将字段值限制在预定义的选项中。此外,该小部件支持与 float_factor 小部件相同的因子转换(范围值应是转换后的结果)。

  • 支持的字段类型:float

<field name="days_to_close" widget="float_toggle" options="{'factor': 2, 'range': [0, 4, 8]}" />
布尔值(boolean)

这是 boolean 类型字段的默认字段类型。

  • 支持的字段类型:boolean

字符(char)

这是 char 类型字段的默认字段类型。

  • 支持的字段类型:char

日期 (date)

这是 date 类型字段的默认字段类型。它由一个文本框和一个日期选择器组成。该字段将以如下可读格式显示日期:Dec 19, 1997。如果年份是当前年份,则会隐藏年份。编辑该字段时,将显示数字格式。该格式与当前语言中设置的格式相对应。

  • 支持的字段类型:date

选项:

  • min_date / max_date:设置可接受值的日期限制。默认情况下,最早可接受的日期是 1000-01-01,最晚是 9999-12-31。可接受的值为 SQL 格式的日期(yyyy-MM-dd HH:mm:ss)或 "today"。

    <field name="datefield" options="{'min_date': 'today', 'max_date': '2023-12-31'}" />
    
  • warning:指定何时显示警告(默认为 "none")。

    可用的警告模式有:"none"、"future" 和 "past"。根据所选模式,如果值位于未来或过去(以今天为基准),则显示警告。

    <field name="datefield" options="{'warning': 'future'}" />
    
  • numeric:设置为 true 时,按当前语言设置的格式显示日期。(默认:false)。

    <field name="datefield" options="{'numeric': true}" />
    
日期和时间 (datetime)

这是 datetime 类型字段的默认字段类型。值始终位于客户端时区。显示格式的行为与日期字段相同,请参阅 日期字段 的说明。可读格式如下:Dec 19, 1997, 10:45 AM。

  • 支持的字段类型:datetime

选项:

  • 请参阅 日期字段 的选项

  • rounding:用于生成时间选择器中可用分钟的增量。这不会影响实际值,只影响下拉选择框中可用选项的数量(默认:5)。

    <field name="datetimefield" options="{'rounding': 10}" />
    
  • show_seconds:设置为 true 时,显示 datetime 字段中的秒。该字段仍会接受 datetime 值,但秒会显示在界面中(默认:false)。

    <field name="datetimefield" widget="datetime" options="{'show_seconds': true}" />
    
  • show_time:设置为 false 时,隐藏 datetime 字段中的时间部分。该字段仍会接受 datetime 值,但时间部分会在界面中隐藏(默认:true)。

    <field name="datetimefield" widget="datetime" options="{'show_time': false}" />
    
  • show_date:设置为 false 时,隐藏 datetime 字段中的日期部分。该字段仍会接受 datetime 值,但日期部分会在界面中隐藏(默认:true)。

    <field name="datetimefield" widget="datetime" options="{'show_date': false}" />
    
日期范围 (daterange)

该小部件允许用户通过单个选择器选择开始日期和结束日期。

  • 支持的字段类型:date、datetime

选项:

  • 请参阅 日期字段 或 日期与时间字段 的选项

  • start_date_field:用于获取/设置日期范围起始值的字段(不能与 end_date_field 一起使用)。

    <field name="end_date" widget="daterange" options="{'start_date_field': 'start_date'}" />
    
  • end_date_field:用于获取/设置日期范围结束值的字段(不能与 start_date_field 一起使用)。

    <field name="start_date" widget="daterange" options="{'end_date_field': 'end_date'}" />
    
相对日期 (relative_date)

此小部件可用于日期和日期时间字段。在只读模式下,它会显示一个人类可读的相对日历字符串,该字符串根据字段值与今天之间的差异计算得出(例如 “昨天”、“今天”、“3 天后”、“下个月”)。确切格式取决于差异的大小:

  • 在 ±30 天内:单位被强制为 天 (例如 “5 天后”、“3 天前”)。

  • 在 31 到 99 天之间:Luxon 会自动选择最合适的单位(例如 “下个月”、“2 个月前”)。

  • 超过 ±99 天:此小部件回退为格式化后的日期字符串。

在编辑模式下,此小部件回退为常规的日期/日期时间字段。

  • 支持的字段类型:date、datetime

货币 (monetary)

这是 monetary 类型字段的默认字段类型。它用于显示货币。如果在选项中指定了货币字段,则使用该字段,否则回退到会话中的默认货币

  • 支持的字段类型:monetary、float

选项:

  • currency_field:另一个字段名称,该字段应为指向货币的 many2one。

    <field name="value" widget="monetary" options="{'currency_field': 'currency_id'}" />
    
  • hide_trailing_zeros:隐藏最后一个非零数字右侧的零,例如 1.20 变为 1.2 (默认为 false)。

    <field name="int_value" options="{'hide_trailing_zeros': true}" />
    
文本 (text)

这是 text 类型字段的默认字段类型。

  • 支持的字段类型:text

密码 (password)

此小部件在带有 type="password" 的输入框中渲染字段值,从而隐藏真实值。输入框旁边的眼睛按钮允许用户显示或隐藏该值。当字段需要存储敏感数据(例如 API 密钥、令牌)且默认情况下不应显示该值时,此小部件很有用。

  • 支持的字段类型:char、text

选项:

  • placeholder:当字段为空时在输入框中显示的占位符文本。

    <field name="api_key" widget="password" placeholder="Enter your API key"/>
    
拖拽手柄 (handle)

此字段的职责是显示为 handle,并允许通过拖放操作重新排列各个记录。

警告

必须在记录排序所依据的字段上指定它。

警告

不支持在同一列表中的多个字段上使用 handle 小部件。

  • 支持的字段类型:integer

电子邮件 (email)

此字段显示电子邮件地址。使用它的主要原因是:在只读模式下,它会被渲染为带有正确 href 的锚点标签。

  • 支持的字段类型:char

电话 (phone)

此字段显示电话号码。使用它的主要原因是:在只读模式下,它会被渲染为带有正确 href 的锚点标签,但仅在某些情况下如此:只有当设备能够拨打该特定号码时,我们才希望它可点击。

  • 支持的字段类型:char

URL (url)

此字段显示一个 url(在只读模式下)。使用它的主要原因是:它会被渲染为带有正确 css 类和 href 的锚点标签。

此外,还可以使用 text 属性自定义锚点标签的文字(这不会改变 href 值)。

  • 支持的字段类型:char

<field name="foo" widget="url" text="Some URL" />

选项:

  • website_path:(默认值:false)默认情况下,此小部件会强制 href 值以 "http://" 开头(如果尚未如此),除非将此选项设为 true,从而允许重定向到数据库自身的网站。

域 (domain)

domain 字段允许用户通过树状界面构造技术前缀形式的域,并实时查看所选的记录。在调试模式下,还会提供一个输入框,以便直接输入前缀字符形式的域(或构造树状界面无法构建的高级域)。

注意,这仅限于 静态 域(不支持动态表达式,也不能访问上下文变量)。

  • 支持的字段类型:char

选项:

  • model:编码域所适用的 res_model 的 char 字段名称。

  • foldable (默认值:false):如果为 true,则域字段会紧凑渲染,并在用户交互时展开。

  • in_dialog (默认值:false):如果为 true,则当用户想要编辑域时,此小部件会打开一个对话框;而默认情况下,域编辑器直接渲染在值下方。

  • count_limit (默认值:10000):域小部件会执行 search_count 请求来验证域,并指示匹配的记录数量。这些请求在大型表上可能开销很大,因此默认情况下 search_count 被限制为 10000。

链接按钮 (link_button)

LinkButton 小部件实际上只是显示一个包含图标和文本值内容的 span。该链接可点击,并会以该值作为 url 打开新的浏览器窗口。

  • 支持的字段类型:char

图像文件 (image)

此小部件用于将二进制值表示为图像。在某些情况下,服务器不会包含图像的 content。此时,此小部件会生成一个图像,其源属性指向服务器上的某个图像。

  • 支持的字段类型:binary

选项:

  • preview_image:如果图像内容不可用,此选项可用于告知 Web 客户端:默认字段名不是当前字段的名称,而是另一个字段的名称。

    <field name="image" widget="image" options="{'preview_image': 'image_128'}" />
    
  • accepted_file_extensions:用户可从文件输入对话框中选择的文件扩展名(默认值为 "image/*")

    (参见:<input type="file" /> 上的 accept 属性)

二进制文件 (binary)

用于保存/下载二进制文件的通用小部件。

  • 支持的字段类型:binary

属性:

  • filename:保存二进制文件会丢失其文件名,因为它只保存二进制值。文件名可以保存在另一个字段中。为此,应将 filename 属性设置为视图中存在的某个字段。

    <field name="raw" filename="datas_fname" />
    

选项:

  • accepted_file_extensions:用户可从文件输入对话框中选择的文件扩展名

    (参见:<input type="file" /> 上的 accept 属性)

优先级 (priority)

此小部件渲染为一组星星,允许用户点击以选择或不选择某个值。例如,这对于将任务标记为高优先级很有用。

注意,此小部件在 readonly 模式下也能工作,这一点并不常见。

  • 支持的字段类型:selection

图像附件 (attachment_image)

用于 many2one 字段的图像小部件。如果该字段已设置,此小部件将渲染为带有正确 src url 的图像。此小部件在编辑模式或只读模式下行为相同,仅用于查看图像。

  • 支持的字段类型:many2one

<field name="displayed_image_id" widget="attachment_image" />
标签选择 (label_selection)

此小部件渲染一个简单的不可编辑标签。它仅用于显示某些信息,而不是编辑信息。

  • 支持的字段类型:selection

选项:

  • classes:从选择值到 CSS 类名的映射

    <field
        name="state"
        widget="label_selection"
        options="{
            'classes': {
                'draft': 'default',
                'cancel': 'default',
                'none': 'danger',
            },
        }"
    />
    
状态选择 (state_selection)

这是一个专用的选择小部件。它假定记录包含一些硬编码字段,且这些字段存在于视图中:stage_id、legend_normal、legend_blocked、legend_done。它主要用于显示和更改项目中任务的状态,并在下拉列表中显示附加信息。

  • 支持的字段类型:selection

<field name="kanban_state" widget="state_selection" />
状态选择 - 列表视图 (list.state_selection)

在列表视图中,state_selection 字段默认显示图标旁边的标签。

  • 支持的字段类型:selection

选项:

  • hide_label:隐藏图标旁边的标签

    <field name="kanban_state" widget="state_selection" options="{'hide_label': true}" />
    
收藏 (boolean_favorite)

此小部件根据布尔值显示为空星(或实心星)。注意,它也可以在只读模式下编辑。

  • 支持的字段类型:boolean

开关 (boolean_toggle)

显示一个开关来表示布尔值。它是 boolean 字段的子字段,主要用于获得不同的外观。

  • 支持的字段类型:boolean

统计信息 (statinfo)

此小部件用于在 stat button 中表示统计信息。它基本上只是一个带数字的标签。

  • 支持的字段类型:integer、float

选项:

  • label_field:如果指定,此小部件将使用 label_field 的值作为文本。

    <button
        name="%(act_payslip_lines)d"
        icon="fa-money"
        type="action"
    >
        <field
            name="payslip_count"
            widget="statinfo"
            string="Payslip"
            options="{'label_field': 'label_tasks'}"
        />
    </button>
    
  • hide_trailing_zeros:隐藏最后一个非零数字右侧的零,例如 1.20 变为 1.2 (默认为 false)。

    <field name="int_value" widget="statinfo" options="{'hide_trailing_zeros': true}" />
    
百分比饼图 (percentpie)

此小部件用于在 stat button 中表示统计信息。它类似于 statinfo 小部件,但信息以 饼图 (从空到满)表示。注意,该值被解释为百分比(0 到 100 之间的数字)。

  • 支持的字段类型:integer、float

<field name="replied_ratio" string="Replied" widget="percentpie" />
进度条 (progressbar)

将值表示为进度条(从 0 到某个值)

  • 支持的字段类型:integer、float

选项:

  • editable:布尔值,决定 value 是否可编辑

  • current_value:从必须存在于视图中的字段获取当前值

  • max_value:从必须存在于视图中的字段获取最大值

  • edit_max_value:布尔值,决定 max_value 是否可编辑

  • title:进度条的标题,显示在进度条顶部

    -> 不翻译,如果该术语需要翻译,请改用 title 属性(而不是选项)

<field
    name="absence_of_today"
    widget="progressbar"
    options="{
        'current_value': 'absence_of_today',
        'max_value': 'total_employee',
        'editable': false,
    }"
/>
日记账仪表板图表 (dashboard_graph)

这是一个更为专用的小部件,用于显示表示一组数据的图表。例如,它用于会计仪表板的看板视图。

它假定该字段是一组数据的 JSON 序列化结果。

  • 支持的字段类型:char

属性:

  • graph_type:字符串,可以是 "line" 或 "bar"

    <field name="dashboard_graph_data" widget="dashboard_graph" graph_type="line" />
    
Ace 编辑器 (ace)

此小部件旨在用于文本字段。它提供 Ace 编辑器,用于编辑 XML 和 Python。

  • 支持的字段类型:char、text

徽章 (badge)

在 bootstrap 徽章胶囊中显示该值。

  • 支持的字段类型:char、selection、many2one

默认情况下,徽章具有浅灰色背景,但可以使用 装饰 机制进行自定义。例如,要在给定条件下显示红色徽章:

<field name="foo" widget="badge" decoration-danger="state == 'cancel'" />

关系字段

选择 (selection)

  • 支持的字段类型:selection

属性:

  • placeholder:当未选择任何值时用于显示一些信息的字符串

    <field name="tax_id" widget="selection" placeholder="Select a tax" />
    
单选 (radio)

这是 FielSelection 的子字段,但专门用于将所有有效选项显示为单选按钮。

注意,如果在 many2one 记录上使用,则会执行更多 rpc 来获取相关记录的 name_gets。

  • 支持的字段类型:selection、many2one

选项:

  • horizontal:如果为 true,单选按钮将水平显示。

    <field name="recommended_activity_type_id" widget="radio" options="{'horizontal': true}"/>
    
徽章选择 (badges_selection)

将选择字段值显示为一组可点击徽章的小部件。

  • 支持的字段类型:selection

选项:

  • badgeLimit:折叠为下拉列表之前显示的最大徽章数量。

  • icon_mapping:将每个选择值映射到图标类字符串的字典,例如 {'draft': 'fa-pencil', 'done': 'fa-check'}

  • default_icon:应用于在 icon_mapping 中没有条目的徽章的回退图标类

  • allowed_selection_field:同一记录上另一个字段的名称,该字段的值是选择键列表;只有匹配的选项会以徽章形式显示

<field name="state" widget="badges_selection"
    options="{'badgeLimit': 5,
              'icon_mapping': {'draft': 'fa-pencil', 'done': 'fa-check'},
              'allowed_selection_field': 'available_states'}" />
徽章 Many2one (badges_many2one)

将 many2one 字段值显示为一组可点击徽章的小部件,会从关联模型中加载可用记录。

  • 支持的字段类型:many2one

选项:

  • badgeLimit:折叠为下拉列表之前显示的最大徽章数量。

  • related_icon_field:关联模型上存放图标类字符串的字段名称;设置后,徽章将使用该图标渲染

  • default_icon:当未设置 related_icon_field 或关联模型记录没有该值时使用的回退图标类

<field name="category_id" widget="badges_many2one"
    options="{'badgeLimit': 4,
              'related_icon_field': 'icon',
              'default_icon': 'fa fa-tag'}" />
多对一 (many2one)

many2one 字段的默认小部件。

  • 支持的字段类型:many2one

属性:

  • can_create:允许创建相关记录(优先于 no_create 选项)

  • can_write:允许编辑相关记录(默认值:true)

选项:

  • quick_create:允许快速创建相关记录(默认值:true)

  • no_create:阻止创建相关记录 - 同时隐藏 创建 “xxx” 和 创建并编辑 下拉菜单项(默认值:false)

  • no_quick_create:阻止快速创建相关记录 - 隐藏 创建 “xxx” 下拉菜单项(默认值:false)

  • no_create_edit:隐藏 创建并编辑 下拉菜单项(默认值:false)

  • create_name_field:创建相关记录时,如果设置了此选项,将用输入框的值填充 create_name_field 的值(默认值:name)

  • always_reload:布尔值,默认为 false。如果为 true,此小部件将始终额外执行一次 name_get 以获取其名称值。这用于 name_get 方法被重写的情况(请不要这样做)

  • no_open:布尔值,默认为 false。如果设为 true,则在只读模式下点击 many2one 时不会跳转到该记录

<field name="currency_id" options="{'no_create': true, 'no_open': true}" />
多对一条码 (many2one_barcode)

用于 many2one 字段的部件,允许从移动设备(Android/iOS)打开相机来扫描条形码。

many2one 字段的专用实现,允许用户使用原生相机扫描条形码,然后通过 name_search 搜索该值。

如果设置此部件而用户未使用移动应用,它将回退为常规的 many2one (Many2OneField)

  • 支持的字段类型:many2one

多对一头像 (many2one_avatar)

此部件仅支持指向继承自 image.mixin 的模型的 many2one 字段。在只读模式下,它会在关联记录的 display_name 旁显示其图像。请注意,此处 display_name 不是可点击的链接。在编辑模式下,其行为与常规 many2one 完全相同。

  • 支持的字段类型:many2one

多对一头像用户 (many2one_avatar_user)

此部件是 Many2OneAvatar 的专用实现。点击头像时,会打开与对应用户的聊天窗口。此部件只能设置在指向 res.users 模型的 many2one 字段上。

  • 支持的字段类型:many2one (指向 res.users)

多对一头像员工 (many2one_avatar_employee)

与 many2one_avatar_user 相同,但用于指向 hr.employee 的 many2one 字段。

  • 支持的字段类型:many2one (指向 hr.employee)

多对多 (many2many)

many2many 字段的默认部件。

  • 支持的字段类型:many2many

属性:

  • mode:字符串,要显示的默认视图

  • domain:将数据限制在特定的域内

选项:

  • create_text:允许自定义添加新记录时显示的文本

  • link:决定能否将记录添加到该关系的域 (默认:true)。

  • unlink:决定能否将记录从该关系中移除的域 (默认:true)。

多对多二进制文件 (many2many_binary)

此部件帮助用户同时上传或删除一个或多个文件。

请注意,此部件专用于 ir.attachment 模型。

  • 支持的字段类型:many2many

选项:

  • accepted_file_extensions:用户可从文件输入对话框中选择的文件扩展名

    (参见:<input type="file" /> 上的 accept 属性)

多对多标签 (many2many_tags)

将 many2many 字段显示为标签列表。

  • 支持的字段类型:many2many

选项:

  • create:决定能否创建新标签的域 (默认:true)。

    <field name="category_id" widget="many2many_tags" options="{'create': [['some_other_field', '>', 24]]}" />
    
  • color_field:数值字段的名称,该字段应存在于视图中。将根据其值选择颜色。

    <field name="category_id" widget="many2many_tags" options="{'color_field': 'color'}" />
    
  • no_edit_color:设置为 true 以移除更改标签颜色的功能 (默认:false)。

    <field name="category_id" widget="many2many_tags" options="{'color_field': 'color', 'no_edit_color': true}" />
    
  • edit_tags:设置为 true 以允许通过点击标签来更新标签关联记录 (默认:false)。

    <field name="category_id" widget="many2many_tags" options="{'edit_tags': true}" />
    
  • tag_limit:要显示的标签数量。设置为 0 可始终显示所有标签 (默认:8)。

    <field name="category_id" widget="many2many_tags" options="{'tag_limit': 20}" />
    
多对多标签 - 表单视图 (form.many2many_tags)

用于表单视图的 many2many_tags 部件专用实现。它包含一些额外代码,以便编辑标签的颜色。

  • 支持的字段类型:many2many

多对多标签 - 看板视图 (kanban.many2many_tags)

用于看板视图的 many2many_tags 部件的只读专用实现。

  • 支持的字段类型:many2many

多对多标签彩色圆点 (many2many_tags_color_dot)

many2many_tags 部件的专用实现,它不在整个标签背景上着色,而是在标签文本前显示一个彩色圆点。

  • 支持的字段类型:many2many

多对多标签头像 (many2many_tags_avatar)

many2many_tags 部件的专用实现,用于显示头像列表。

  • 支持的字段类型:many2many

多对多标签头像 - 看板视图 (kanban.many2many_tags_avatar)

用于看板视图的 many2many_tags_avatar 部件专用实现,提供弹出框以便在看板视图中编辑标签(适用于非只读字段)。

  • 支持的字段类型:many2many

多对多复选框 (many2many_checkboxes)

此字段显示一个复选框列表,允许用户选择其中的一部分选项。请注意,显示值的数量限制为 100。该限制不可自定义。它仅用于处理将此类部件错误地设置到关联模型庞大的字段上的极端情况。在这些情况下,列表视图更为合适,因为它支持分页和筛选。

  • 支持的字段类型:many2many

一对多 (one2many)

one2many 字段的默认部件。它通常在子列表视图或子看板视图中显示数据。

  • 支持的字段类型:one2many

选项:

  • create:决定能否创建关联记录的域 (默认:true)。

  • delete:决定能否删除关联记录的域 (默认:true)。

    <field name="turtles" options="{'create': [['some_other_field', '>', 24]]}" />
    
  • create_text:用于自定义“添加”标签/文本的字符串。

    <field name="turtles" options="{'create_text': 'Add turtle'}" />
    
状态栏 (statusbar)

这是表单视图专用的字段。它是许多表单顶部的状态条,用于表示流程,并允许选择特定状态。

  • 支持的字段类型:selection、many2one

引用 (reference)

reference 字段由一个选择框(用于选择模型)和一个 many2one 字段(用于选择其值)组合而成。它允许在任意模型上选择记录。

  • 支持的字段类型:char、reference

选项:

  • model_field:包含可选记录所属模型的 ir.model 名称。设置此选项后,reference 字段的选择部分不会显示。

部件

丝带 (web_ribbon)

此部件在看板卡片或表单视图工作表的右上角显示一条丝带,例如用于指示已归档的记录。

<widget name="web_ribbon" title="Archived" bg_color="text-bg-danger"/>

属性:

  • title:丝带中显示的文本。

  • tooltip:丝带提示框中显示的文本。

  • bg-class:设置在丝带上的类名,通常用于定义丝带的颜色。

星期几 (week_days)

此部件显示一个星期的复选框列表,每天一个复选框,允许用户选择其中的一部分选项。

<widget name="week_days" />

客户端动作

客户端动作是一个组件,可作为主要元素显示在 Web 客户端中,占据导航栏下方的所有空间,就像 act_window_action 一样。当你需要一个与现有视图或特定模型没有紧密关联的组件时,这很有用。例如,Discuss 应用就是一个客户端动作。

客户端动作这一术语有多种含义,具体取决于上下文:

  • 从服务器的角度看,它是模型 ir_action 的一条记录,其中 tag 字段的类型为 char

  • 从 Web 客户端的角度看,它是一个 Owl 组件,以与其 tag 相同的键注册在动作注册表中

当菜单项与客户端动作关联时,打开它只会从服务器获取动作定义,然后在动作注册表中查找其 tag 以获取组件定义。随后,该组件将由动作容器渲染。

添加客户端动作

客户端动作是一个组件,用于控制导航栏下方的那部分屏幕。定义客户端动作只需创建一个 Owl 组件并将其添加到动作注册表中即可。

import { registry } from "@web/core/registry";
class MyClientAction extends Component { ... }
registry.category("actions").add("my-custom-action", ClientAction);

然后,要在 Web 客户端中使用该客户端动作,需要创建一个带有适当 tag 属性的客户端动作记录(模型 ir.actions.client 的记录):

<record id="my_client_action" model="ir.actions.client">
    <field name="name">Some Name</field>
    <field name="tag">my-custom-action</field>
</record>