JavaScript 引用

本文档介绍了 Odoo JavaScript 框架。该框架在代码行数方面并不是一个大型应用程序,但它非常通用,因为它基本上是一个将声明式界面描述转换为可与数据库中的每个模型和记录进行交互的实时应用程序的机器。甚至可以使用网页客户端来修改网页客户端的界面。

概览

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

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

  • 网站:这是 Odoo 的公开部分。它允许未识别的用户浏览部分内容、购物或执行许多操作,如同客户一样。这是一个典型的网站:包含各种路由、控制器以及一些 JavaScript 代码来使其正常运行。

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

一些 JavaScript 代码适用于这三个使用场景,并被打包在一起(请参见下面的 assets 部分)。本文档将主要关注网络客户端的架构。

网页客户端

单页应用

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

Odoo 网页客户端 JavaScript 代码概览

在这里,我们对 web 插件中的网页客户端代码做一个简要概述。路径将相对于 web/static/src 来描述。以下描述并非详尽无遗;其目的是仅向读者提供架构的概览。

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

  • core/: 此文件夹包含构成 JavaScript 框架最低层的代码,这些代码可以在网页客户端、网站、门户和销售点应用程序中使用。

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

  • webclient/webclient.js:这是真正的 webclient 组件。它主要是对动作容器和导航栏的封装,并在启动应用程序时执行一些必需的操作,例如加载网址的状态。

  • webclient/actions/: 此文件夹包含用于显示和切换操作的代码。

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

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

  • search/ 所有这些文件定义了搜索视图(从网页客户端的角度来看,它并不是一个视图,仅从服务器的角度来看才是)。

如果文件未被加载/更新该怎么办

文件可能无法正确加载的原因有很多。以下是一些您可以尝试解决该问题的方法:

  • 请确保您已保存文件;忘记保存是每个人都会遇到的事情。

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

  • 在文件开头添加 console.log(),以便查看文件是否已被加载。如果未被加载,可能是该文件不在正确的资产包中,或者资产包未更新。

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

    • 重新启动服务器将在下一次请求资产包时强制检查其是否为最新版本。

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

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

  • 请在更改代码后刷新页面。Odoo 当前尚未提供任何热模块重新加载机制。

加载 JavaScript 代码

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

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

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

虽然可以在全局作用域中进行开发,但这会带来一些问题:

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

  • 存在一个单一的命名空间,这可能导致命名冲突。

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

使用模块系统有助于解决这些问题:因为模块会指定其依赖项,模块系统可以按正确顺序加载它们,或者在依赖项缺失或存在循环依赖时发出错误。模块还拥有自己的命名空间,并可以选择导出哪些内容,从而防止暴露实现细节和避免命名冲突。

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

由于这一原因,Odoo 有一个资产包系统。在这些包中,JavaScript 文件是 ES 模块,并在顶部有特殊的注释。这些模块将被一起打包并转换,以便我们的模块加载器使用。虽然您可以编写不使用此模块系统的代码,但通常不建议这样做。

(参见 原生 JavaScript 模块

修补类

在我们尽最大努力提供不需要它的扩展点时,有时需要*就地*修改现有类的行为。其目标是拥有一个机制来更改类以及所有未来/当前的实例。这是通过使用 patch 实用函数来实现的:

/** @odoo-module */
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 导入。

字段注册表

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

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

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

此注册表包含网络客户端已知的所有 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 进行),或者可能需要直接调用一个控制器(该控制器位于某些路线中)。

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

    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(提示)样式:

  • 信息: 用于在某个不会失败的操作之后显示一些信息反馈。

  • success: 用户执行了一个有时可能会失败的操作,但这次没有失败。

  • 警告: 用户执行了一个只能部分完成的动作。在某些情况出现错误,但并非直接由用户引起,或不具有特别可操作性时也适用。

  • success: 用户尝试执行一个动作,但该动作无法完成。

通知也可以用于在不干扰用户工作流的情况下向用户提问,例如通过 VOIP 接收到的电话:可以显示一个粘性通知,并带有两个按钮用于 接受拒绝

显示通知

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

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

  • display_notification 客户端动作允许从 Python 触发通知的显示(例如,在用户点击类型为对象的按钮时调用的方法中)。此客户端动作使用通知服务。

通知有一些 选项

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

  • message: 字符串,可选。通知的内容。可以是用于显示格式化文本的标记对象。

  • sticky: 布尔值,可选(默认为 false)。如果为 true,通知将保持显示直到用户将其关闭。否则,通知将在短时间内自动关闭。

  • 类型: 字符串,可选(默认值为 “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 客户端会显示一些小部件,例如消息菜单。

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

目前没有针对系统托盘项(systray items)的特定接口。它们是 Owl 组件,可以像其他组件一样与其环境进行通信,例如通过与服务进行交互。

添加新的系统托盘项

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

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

系统托盘中的项目是根据它们在系统托盘注册表中的序列进行排序的。

翻译管理

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

  • 每个可翻译的字符串都使用特殊函数 _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);

请注意字符串本身是固定的。这使得翻译函数可以在使用它进行插值之前获取翻译后的字符串。

会话

网页客户端需要一些来自 Python 的信息才能正常运行。为了避免通过 JavaScript 发起网络请求与服务器进行额外的往返交互,这些信息会直接在页面中进行序列化,并可以通过 @web/session 模块在 JS 中访问。

将信息添加到会话

/web 路线被加载时,服务器会将此信息注入到一个脚本标签中。该信息是通过调用模型 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;
...

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

视图

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

虽然视图只是 owl 组件,但内置视图通常具有相同的结构:一个名为 “SomethingController” 的组件作为视图的根。该组件会创建某个 “模型”(负责管理数据的对象)的实例,并包含一个名为 “渲染器” 的子组件,用于处理显示逻辑。

字段

编辑和创建数据是网页客户端体验的重要组成部分。大部分工作都是通过字段小部件(field widgets)完成的,这些小部件了解字段类型以及值应该如何显示和编辑的具体细节。

装饰

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

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

有效的装饰名称包括:

  • 装饰-bf

  • 装饰-它

  • 装饰-危险

  • 装饰-信息

  • 装饰-静音

  • 装饰-主要

  • 装饰-成功

  • 装饰-警告

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

非关系型字段

我们在此记录所有默认提供的非关系型字段,顺序不限。

整数 (integer)

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

  • 支持的字段类型:integer

选项:

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

    在编辑模式下,字段会以输入框的形式呈现,其 HTML 属性 type 被设置为 `”number”`(以便用户可以利用原生支持,尤其是在移动设备上)。在这种情况下,默认格式化功能会被禁用,以避免不兼容问题。

    <field name="int_value" options="{'type': 'number'}" />
    
  • step: 当用户点击按钮时,设置步长值进行增减(仅适用于类型为 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"

    在编辑模式下,字段会以输入框的形式呈现,其 HTML 属性 type 被设置为 `”number”`(以便用户可以利用原生支持,尤其是在移动设备上)。在这种情况下,默认格式化功能会被禁用,以避免不兼容问题。

    <field name="int_value" options="{'type': 'number'}" />
    
  • step: 当用户点击按钮时,设置步长值进行增减(仅适用于类型为 number 的输入框,默认值为 1

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

    默认情况下,数字会根据区域设置进行格式化。此选项将防止字段的值被格式化。

    <field name="int_value" options="{'format': false}" />
    
时间(float_time

此小部件的目标是正确显示表示时间间隔(以小时为单位)的浮点数值。例如,0.5 应格式化为 0:30,或者 4.75 对应 4:45

  • 支持的字段类型:float

浮点因子 (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 的字段的默认字段类型。它包含一个文本框和一个日期选择器。

  • 支持的字段类型: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'}" />
    
  • warn_future: 如果值在今天之后(基于今天)则显示警告。

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

这是类型为 datetime 的字段的默认字段类型。值始终以客户端的时区显示。

  • 支持的字段类型:datetime

选项:

  • 查看 日期字段 选项

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

    <field name="datetimefield" options="{'rounding': 10}" />
    
  • show_seconds: 当设置为 false 时,会从日期时间字段中隐藏秒数。该字段仍然可以接受日期时间值,但在用户界面中将隐藏秒数(默认:true)。

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

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

此小部件允许用户从单一选择器中选择开始日期和结束日期。

  • 支持的字段类型:datedatetime

选项:

  • 查看 日期字段日期和时间字段 选项

  • 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'}" />
    
剩余天数(remaining_days

此小部件可用于日期和日期时间字段。在只读模式下,它会显示该字段值与今天的天数差。在编辑模式下,该小部件会变为常规的日期或日期时间字段。

  • 支持的字段类型:datedatetime

货币 (monetary)

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

  • 支持的字段类型:货币, 浮点数

选项:

  • currency_field: 另一个字段名称,该字段应为对货币的多对一关系。

    <field name="value" widget="monetary" options="{'currency_field': 'currency_id'}" />
    
文本 (text)

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

  • 支持的字段类型:text

处理 (handle)

此字段的作用是作为 handle 显示,并允许通过拖放操作对各个记录进行重新排序。

警告

它必须在用于对记录进行排序的字段上进行指定。

警告

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

  • 支持的字段类型:integer

邮件(email

此字段显示邮件地址。使用它的主要原因是它以带有正确 href 的超链接形式呈现,并且处于只读模式。

  • 支持的字段类型:char

电话 (phone)

此字段显示电话号码。使用它的主要原因是它以带有正确 href 的超链接形式呈现,在只读模式下显示,但仅在某些情况下:我们只希望在设备可以拨打此特定号码时才使其可点击。

  • 支持的字段类型:char

网址 (url)

此字段以只读模式显示网址。使用它的主要原因是它可以作为带有适当 CSS 类和 href 的超链接进行渲染。

此外,锚点标签的文本可以通过 text 属性进行自定义(这不会改变 href 值)。

  • 支持的字段类型:char

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

选项:

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

领域(domain

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

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

  • 支持的字段类型:char

链接按钮 (link_button)

LinkButton 小部件实际上只是显示一个带有图标和文本值作为内容的 span。该链接是可点击的,点击后会以它的值作为网址在新浏览器窗口中打开。

  • 支持的字段类型:char

图片文件 (image)

此小部件用于将二进制值表示为图片。在某些情况下,服务器会返回一个 bin_size 而不是真实的图片(bin_size 是一个表示文件大小的字符串,例如 "6.5kb")。在这种情况下,小部件将创建一个具有对应于服务器上图片的来源属性的图片。

  • 支持的字段类型:binary

选项:

  • preview_image: 如果图片仅以 bin_size 加载,则此选项可用于通知网页客户端,当前字段的默认字段名不是当前字段的名称,而是另一个字段的名称。

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

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

二进制文件 (binary)

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

  • 支持的字段类型:binary

属性:

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

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

选项:

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

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

优先级(priority

此小部件以一组星星的形式呈现,允许用户点击以选择一个值或不选择。例如,这可用于将任务标记为高优先级。

请注意,此小部件也支持在“只读”模式下运行,这并不常见。

  • 支持的字段类型:选择

图片附件 (attachment_image)

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

  • 支持的字段类型:many2one

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

这个小部件用于渲染一个简单的不可编辑的标签。这仅用于显示信息,而不是进行编辑。

  • 支持的字段类型:选择

选项:

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

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

这是一个专用的选择小部件。它假设记录中有一些硬编码的字段,在视图中存在:stage_idlegend_normallegend_blockedlegend_done。这主要用于在项目中显示和更改任务的状态,并在下拉菜单中显示附加信息。

  • 支持的字段类型:选择

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

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

  • 支持的字段类型:选择

选项:

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

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

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

  • 支持的字段类型:boolean

切换(boolean_toggle

显示一个切换开关以表示布尔值。这是 boolean 字段的一个子字段,主要用于不同的外观展示。

  • 支持的字段类型:boolean

统计信息(statinfo

此小部件用于在 统计按钮 中表示统计数据。它基本上只是一个带有数字的标签。

  • 支持的字段类型:integerfloat

选项:

  • 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>
    
百分比饼图(percentpie

此小部件用于在 统计按钮 中表示统计数据。这类似于 statinfo 小部件,但信息以 **饼图**(从空到满)形式呈现。请注意,该值被解释为百分比(介于 0100 之间的数字)。

  • 支持的字段类型:integerfloat

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

以进度条的形式表示一个值(从 0 到某个值)

  • 支持的字段类型:integerfloat

选项:

  • 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。

  • 支持的字段类型:chartext

徽章 (badge)

显示一个带有引导程序徽章的内联元素。

  • 支持的字段类型:charselectionmany2one

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

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

关系字段

选择 (selection)

  • 支持的字段类型:选择

属性:

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

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

这是一个 FieldSelection 的子字段,但专门用于以单选按钮的形式显示所有有效选项。

请注意,如果在 many2one 记录上使用,则会进行更多 RPC 调用以获取关联记录的 name_gets。

  • 支持的字段类型:selectionmany2one

选项:

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

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

这是一个 selection 字段的子字段,但专门用于以矩形徽章的形式显示所有有效选项。

  • 支持的字段类型:selectionmany2one

<field name="recommended_activity_type_id" widget="selection_badge" />
许多对一(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 条形码 (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.employeemany2one 字段。

  • 支持的字段类型: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 标签(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}" />
    
Many2many 标签 - 表单视图 (form.many2many_tags)

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

  • 支持的字段类型:many2many

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

用于看板视图的 many2many_tags 小部件的专用化。

  • 支持的字段类型:many2many

许多对多复选框(many2many_checkboxes

此字段显示一组复选框,并允许用户选择部分选项。请注意,显示的值数量限制为 100。此限制不可自定义。这仅仅是为了处理极端情况,当此小部件错误地设置在一个具有大量关联模型(comodel)的字段上时,列表视图更为合适,因为它支持分页和筛选。

  • 支持的字段类型: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

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

  • 支持的字段类型:selectionmany2one

引用 (reference)

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

  • 支持的字段类型:charreference

选项:

  • 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" />

客户端操作

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

客户端动作是一个根据上下文具有多种含义的术语:

  • 从服务器的角度来看,这是一个 ir_action 模型的记录,其中包含一个类型为字符的字段 tag

  • 从网页客户端的角度来看,它是一个在动作注册表中以相同键名注册的 Owl 组件。

每当一个菜单项与客户端动作相关联时,打开它将从服务器获取该动作的定义,然后在动作注册表中查找其标签以获取组件定义。该组件将由动作容器进行渲染。

添加客户端动作

一个客户端动作是一个将控制导航栏下方屏幕部分的组件。定义一个客户端动作就像创建一个 Owl 组件并将其添加到动作注册表中一样简单。

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

然后,要在网页客户端中使用客户端动作,我们需要创建一个客户端动作记录(模型 ir.actions.client 的记录),并设置适当的 tag 属性:

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