Tham khảo Javascript

Tài liệu này trình bày khung Javascript SoOn. Framework này không phải là một ứng dụng lớn về mặt dòng mã, nhưng nó khá chung chung, vì về cơ bản nó là một cỗ máy biến mô tả giao diện khai báo thành một ứng dụng trực tiếp, có thể tương tác với mọi mô hình và bản ghi trong cơ sở dữ liệu. Thậm chí có thể sử dụng máy khách web để sửa đổi giao diện của máy khách web.

Tổng quan

Khung Javascript được thiết kế để hoạt động với ba trường hợp sử dụng chính:

  • web client: đây là ứng dụng web riêng tư, nơi người ta có thể xem và chỉnh sửa dữ liệu doanh nghiệp. Đây là một ứng dụng một trang (trang không bao giờ được tải lại, chỉ có dữ liệu mới được lấy từ máy chủ bất cứ khi nào cần)

  • trang web: đây là phần công khai của SoOn. Nó cho phép một người dùng không xác định duyệt một số nội dung, mua sắm hoặc thực hiện nhiều hành động với tư cách là khách hàng. Đây là một trang web cổ điển: có nhiều tuyến đường khác nhau với bộ điều khiển và một số javascript để làm cho nó hoạt động.

  • điểm bán hàng: đây là giao diện dành cho điểm bán hàng. Nó là một ứng dụng trang đơn chuyên dụng.

Some javascript code is common to these three use cases, and is bundled together (see below in the assets section). This document will focus mostly on the architecture of the web client.

Máy khách web

Ứng dụng một trang

The web client is a single-page application: instead of requesting a full page from the server each time the user performs an action, it only loads what is needed to update the user interface (UI) as a result of that action. While doing this, it also takes care of updating information in the URL, so that, in most cases, refreshing the page or closing the browser and opening it again shows you the same thing.

Tổng quan về mã JS của máy khách web

Here, we give a very quick overview of the web client code, in the web addon. The paths will be described relative to web/static/src. The following description is deliberately not exhaustive; the goal is only to give the reader a bird's eye view of the architecture.

  • module_loader.js: this is the file that defines the Odoo javascript module system. It needs to be loaded before any other JS module.

  • core/: this folder contains code that forms the lowest level of the javascript framework and that can be used in the web client as well as the website, portal, and point of sale application.

  • weblient/: this folder contains files that are specific to the web client and cannot be used in the website or point of sale, such as the action manager and the action service.

  • webclient/webclient.js: this is the webclient component proper. It is mostly a wrapper for the action container and the navbar, and does a few things that are required upon starting the application, such as loading the state of the url.

  • webclient/actions/: this folder contains the code responsible for displaying and switching between actions.

  • views/: this folder contains the code for the view infrastructure, as well as most of the views (some types of views are added by other addons).

  • views/fields/: contains the definition of the various field components, as well as some utilities used by multiple fields.

  • search/ all these files define the search view (it is not a view in the point of view of the web client, only from the server point of view)

Phải làm gì nếu một tập tin không được tải/cập nhật

Có nhiều lý do khác nhau khiến một tập tin có thể không được tải đúng cách. Dưới đây là một số điều bạn có thể thử để giải quyết vấn đề:

  • Make sure you saved your file; forgetting to do that happens to the best of us.

  • Take a look at the console (in the dev tools, usually opened with F12) and check for errors.

  • Try adding a console.log() at the beginning of your file so you can see if a file has been loaded or not. If it is not loaded, if may not be in the proper assets bundle, or the asset bundle may not be up to date.

  • Depending on your settings, the server may not regenerate the assets bundles after a file has been modified; there are a few options to solve this:

    • restarting the server will force it to check if the asset bundle is up to date the next time it is requested

    • in debug mode, there is an option in the debug menu ( button in the navbar) to force the server to regenerate the assets bundle on the fly without restarting.

    • starting the server with the --dev=xml option will force the server to check if an asset bundle is up to date every time it is requested. We advise you to use this option when actively developing, but not in production.

  • Make sure you refresh your page after changing the code. Odoo currently does not have any hot module reloading mechanism.

Đang tải mã Javascript

Large applications are usually broken up into smaller files, that need to be connected together. Some file may need to use code defined in another file. There are two ways of sharing code between files:

  • using the global scope (the window object) to read/write references to some objects or functions,

  • using a module system that will provide a way for each modules to export or import values, and will make sure that they are loaded in a proper order.

Mặc dù có thể hoạt động ở phạm vi toàn cầu nhưng điều này có một số vấn đề:

  • It is difficult to ensure that implementation details are not exposed: function declarations in the global scope are accessible to all other code.

  • There is a single namespace, creating great potential for naming conflicts.

  • Dependencies are implicit: if a piece of code depends on another, the order in which they are loaded is important, but difficult to guarantee.

Using a module system helps resolve these issues: because modules specify their dependencies, the module system can load them in the proper order or emit an error if dependencies are missing or circular. Modules also form their own namespace, and can choose what to export, preventing exposure of implementation detail and naming collisions.

While we could use ECMAScript (ES) modules directly, there are a number of disadvantages to that approach: each ES module requires a network round trip, which becomes very slow when you have hundreds of files, and many files in Odoo need to be present despite not being imported by anything because they simply add code that the framework will use instead of the other way around.

Because of this, Odoo has a system of asset bundles. In these bundles, JavaScript files are ES modules with a special annotation at the top. These modules will be bundled together and transpiled to be usable by our module loader. While you can write code that doesn't use this module system, it is generally not recommended.

(see Mô-đun Javascript gốc)

Patching classes

While we do our best to provide extension points that don't require it, it is sometimes necessary to modify the behavior of an existing class in place. The goal is to have a mechanism to change a class and all future/present instances. This is done by using the patch utility function:

/** @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");
    },
});

When patching methods, you need to patch the class' prototype, but if you would like to patch a static property of the class, you need to patch the class itself.

Patching is a dangerous operation and should be done with care as it will modify all instances of the class, even if they have already been created. To avoid weird issues, patches should be applied as soon as possible, at the top-level of your module. Patching classes at runtime can result in extremely difficult to debug issues if the class has already been instanciated.

Đăng ký

A common need in the Odoo ecosystem is to extend/change the behaviour of the base system from the outside (by installing an application, i.e. a different module). For example, one may need to add a new field widget in some views. In that case, and many others, the usual process is to create the desired component, then add it to a registry (registering step), to make the rest of the web client aware of its existence.

There are a few registries available in the system. The registries that are used by the framework are categories on the main registry, that can be imported from @web/core/registry

field registry

Sổ đăng ký trường chứa tất cả các tiện ích trường được máy khách web biết đến. Bất cứ khi nào một chế độ xem (thường là biểu mẫu hoặc danh sách/kanban) cần một tiện ích trường, đây sẽ là nơi nó sẽ tìm. Một trường hợp sử dụng điển hình trông như thế này:

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

registry.category("fields").add("pad", {
  component: PadField,
  supportedTypes: ["char"],
  // ...
});
xem sổ đăng ký

This registry contains all JS views known to the web client.

đăng ký hành động

We keep track of all client actions in this registry. This is where the action manager looks up whenever it needs to create a client action. Client actions can be a function - the function will be called when the action is invoked, and the returned value will be executed as a follow up action if needed - or an Owl component that will be displayed when executing that action.

Dịch vụ

Within the webclient, there are some concerns that cannot be handled by a single component, as the concern is transversal, involves many components, or needs to maintain some state for as long as the application is alive.

Services are a solution to these problems: they are created during application startup, are available to components through the hook useService, and stay alive for the entire lifetime of the application.

For example, we have the orm service whose job is to allow interacting with business objects on the server.

Here is a simplified example on how the orm service is implemented:

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

Using services

Services are available in the environment, but should generally be used through the useService hook, which prevents calling methods on the service after a component has been destroyed, and prevents further code from executing after a method call if the component was destroyed during the call.

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

Talking to the server

There are typically two use cases when working on Odoo: one may need to call a method on a (python) model (this goes through the controller /web/dataset/call_kw), or one may need to directly call a controller (available on some route).

  • Calling a method on a python model is done through the orm service:

    return this.orm.call("some.model", "some_method", [some, args]);
    
  • Directly calling a controller is done through the rpc service:

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

Ghi chú

The rpc service doesn't really perform what is generally understood as a remote procedure call (RPC), but for historical reasons, within Odoo we generally call any network request performed in JavaScript an RPC. As highlighted in the previous paragraph, if you want to call a method on a model, you should use the orm service.

Thông báo

The Odoo framework has a standard way to communicate various information to the user: notifications, which are displayed on the top right of the user interface. The types of notification follow the bootstrap toasts:

  • info: useful to display some informational feedback as a consequence of an action that cannot fail.

  • success: the user performed an action that can sometimes fail but didn't.

  • warning: the user performed an action that could only be partially completed. Also useful if something is wrong but wasn't caused by the user directly, or is not particularly actionable.

  • success: the user tried to performed an action but it couldn't be completed.

Notifications can also be used to ask a question to the user without disturbing their workflow: e.g. a phone call received through VOIP: a sticky notification could be displayed with two buttons to Accept or Decline.

Displaying notifications

There are two ways to display notifications in Odoo:

  • The notification service allows component to display notifications from JS code by calling the add method.

  • The display_notification client action allows to trigger the display of a notification from python (e.g. in the method called when the user clicked on a button of type object). This client action uses the notification service.

Notifications have a few options:

  • tiêu đề: chuỗi, tùy chọn. Điều này sẽ được hiển thị ở trên cùng dưới dạng tiêu đề.

  • message: string, optional. The content of the notification. Can be a markup object to display formatted text.

  • dính: boolean, tùy chọn (mặc định là sai). Nếu đúng, thông báo sẽ tồn tại cho đến khi người dùng loại bỏ nó. Nếu không, thông báo sẽ tự động bị đóng sau một khoảng thời gian trễ ngắn.

  • type: string, optional (default "warning"). Determines the style of the notification. Possible values: "info", "success", "warning", "danger"

  • className: string, optional. This is a css class name that will be automatically added to the notification. This could be useful for styling purpose, even though its use is discouraged.

Here are some examples on how to display notifications in 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",
});

And in 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,
        }
    }

hệ thống

The Systray is the right part of the navbar in the interface, where the web client displays a few widgets, such as the messaging menu.

When the systray is created by the navbar, it will look for all registered systray items and display them.

There is currently no specific API for systray items. They are Owl components, and can communicate with their environment just like other components, e.g. by interacting with services.

Thêm một mục Systray mới

Items can be added to the systray by adding them to the "systray" registry:

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

The items are ordered in the systray according to their sequence in the systray registry.

Quản lý dịch thuật

Some translations are made on the server side (basically all text strings rendered or processed by the server), but there are strings in the static files that need to be translated. The way it currently works is the following:

  • each translatable string is tagged with the special function _t

  • các chuỗi này được máy chủ sử dụng để tạo các tệp PO thích hợp

  • bất cứ khi nào máy khách web được tải, nó sẽ gọi tuyến /web/webclient/translations, tuyến này trả về danh sách tất cả các thuật ngữ có thể dịch được

  • at runtime, whenever the function _t is called, it will look up in this list in order to find a translation, and return it or the original string if none is found.

Lưu ý rằng các bản dịch được giải thích chi tiết hơn, từ quan điểm của máy chủ, trong tài liệu Mô-đun dịch.

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

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

Note that using the translation function requires some care: the string given as an argument cannot be dynamic, as it is extracted statically from the code to generate the PO files and serves as the identifier for the term to translate. If you need to inject some dynamic content in the string, _t supports placeholders:

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

Notice how the string itself is fixed. This allows the translation function to retrieve the translated string before using it for interpolation.

Phiên họp

The webclient needs some information from the python to function properly. To avoid an extra round-trip with the server by making a network request in JavaScript, this information is serialized directly in the page, and can be accessed in JS through the @web/session module.

Thêm thông tin vào phiên

When the /web route is loaded, the server injects this information in a script tag. The information is obtained by calling the method session_info of the model ir.http. You can override this method to add information to the returned dictionary.

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

Bây giờ, giá trị có thể được lấy bằng javascript bằng cách đọc nó trong phiên:

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

Note that this mechanism is designed to reduce the amount of communication needed by the web client to be ready. It is only appropriate for data which is cheap to compute (a slow session_info call will delay the loading for the web client for everyone), and for data which is required early in the initialization process.

Giao diện

The word "view" has more than one meaning. This section is about the design of the javascript code of the views, not the structure of the arch or anything else.

While views are just owl components, the built-in views generally have the same structure: a component called "SomethingController" which is the root of the view. This component creates an instance of some "model" (an object responsible for managing the data), and has a subcomponent called a "renderer" that handles the display logic.

Lĩnh vực

Một phần hay của trải nghiệm máy khách web là chỉnh sửa và tạo dữ liệu. Hầu hết công việc đó được thực hiện với sự trợ giúp của các tiện ích trường, chúng nhận biết loại trường và các chi tiết cụ thể về cách hiển thị và chỉnh sửa một giá trị.

đồ trang trí

Giống như chế độ xem danh sách, các tiện ích trường có hỗ trợ trang trí đơn giản. Mục tiêu của việc trang trí là có một cách đơn giản để chỉ định màu văn bản tùy thuộc vào trạng thái hiện tại của bản ghi. Ví dụ:

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

Tên trang trí hợp lệ là:

  • trang trí-bf

  • trang trí-nó

  • trang trí-nguy hiểm

  • thông tin trang trí

  • trang trí tắt tiếng

  • trang trí-chính

  • trang trí-thành công

  • trang trí-cảnh báo

Mỗi trang trí trang trí-X sẽ được ánh xạ tới một lớp css text-X, là lớp css khởi động tiêu chuẩn (ngoại trừ text-ittext-bf, được xử lý bởi odoo và tương ứng với in nghiêng và in đậm). Lưu ý rằng giá trị của thuộc tính trang trí phải là biểu thức python hợp lệ, biểu thức này sẽ được đánh giá bằng bản ghi làm bối cảnh đánh giá.

Các trường không quan hệ

Chúng tôi ghi lại ở đây tất cả các trường không quan hệ có sẵn theo mặc định, không theo thứ tự cụ thể.

Số nguyên (số nguyên)

Đây là loại trường mặc định cho các trường loại số nguyên.

  • Các loại trường được hỗ trợ: số nguyên

Tùy chọn:

  • type: cài đặt loại đầu vào ("văn bản"` theo mặc định, có thể được đặt trên "số")

    Trong chế độ chỉnh sửa, trường được hiển thị dưới dạng đầu vào với loại thuộc tính HTML được đặt trên "số" (để người dùng có thể hưởng lợi từ hỗ trợ gốc, đặc biệt là trên thiết bị di động). Trong trường hợp này, định dạng mặc định bị tắt để tránh tình trạng không tương thích.

    <field name="int_value" options="{'type': 'number'}" />
    
  • step: đặt bước lên và xuống giá trị khi người dùng nhấp vào nút (chỉ dành cho đầu vào loại số, 1 theo mặc định)

    <field name="int_value" options="{'type': 'number', 'step': 100}" />
    
  • format: số có nên được định dạng hay không. (true theo mặc định)

    Theo mặc định, các số được định dạng theo tham số miền địa phương. Tùy chọn này sẽ ngăn giá trị của trường được định dạng.

    <field name="int_value" options='{"format": false}' />
    
Phao (phao)

Đây là loại trường mặc định cho các trường loại float.

  • Các loại trường được hỗ trợ: float

Thuộc tính:

  • chữ số: hiển thị độ chính xác

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

Tùy chọn:

  • type: cài đặt loại đầu vào ("văn bản"` theo mặc định, có thể được đặt trên "số")

    Trong chế độ chỉnh sửa, trường được hiển thị dưới dạng đầu vào với loại thuộc tính HTML được đặt trên "số" (để người dùng có thể hưởng lợi từ hỗ trợ gốc, đặc biệt là trên thiết bị di động). Trong trường hợp này, định dạng mặc định bị tắt để tránh tình trạng không tương thích.

    <field name="int_value" options="{'type': 'number'}" />
    
  • step: đặt bước lên và xuống giá trị khi người dùng nhấp vào nút (chỉ dành cho đầu vào loại số, 1 theo mặc định)

    <field name="int_value" options="{'type': 'number', 'step': 0.1}" />
    
  • format: số có nên được định dạng hay không. (true theo mặc định)

    Theo mặc định, các số được định dạng theo tham số miền địa phương. Tùy chọn này sẽ ngăn giá trị của trường được định dạng.

    <field name="int_value" options="{'format': false}" />
    
Thời gian (float_time)

Mục tiêu của tiện ích này là hiển thị chính xác giá trị float biểu thị một khoảng thời gian (tính bằng giờ). Vì vậy, ví dụ: 0,5 phải được định dạng là 0:30 hoặc 4,75 tương ứng với 4:45.

  • Các loại trường được hỗ trợ: float

Hệ số nổi (float_factor)

Tiện ích này nhằm mục đích hiển thị chính xác giá trị float được chuyển đổi bằng cách sử dụng hệ số được cung cấp trong các tùy chọn của nó. Vì vậy, ví dụ: giá trị được lưu trong cơ sở dữ liệu là 0,5 và hệ số là 3, giá trị tiện ích phải được định dạng là 1,5.

  • Các loại trường được hỗ trợ: float

Chuyển đổi nổi (float_toggle)

Mục tiêu của tiện ích này là thay thế trường nhập bằng một nút chứa một loạt các giá trị có thể có (được đưa ra trong các tùy chọn). Mỗi lần nhấp cho phép người dùng lặp trong phạm vi. Mục đích ở đây là hạn chế giá trị trường trong một lựa chọn được xác định trước. Ngoài ra, tiện ích này hỗ trợ chuyển đổi hệ số dưới dạng tiện ích float_factor (Giá trị phạm vi phải là kết quả của chuyển đổi).

  • Các loại trường được hỗ trợ: float

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

Đây là loại trường mặc định cho các trường loại boolean.

  • Các loại trường được hỗ trợ: boolean

Char (char)

Đây là loại trường mặc định cho các trường loại char.

  • Các loại trường được hỗ trợ: char

Ngày (ngày)

Đây là loại trường mặc định cho các trường loại ngày. Nó bao gồm một hộp văn bản và một bộ chọn ngày.

  • Các loại trường được hỗ trợ: ngày

Tùy chọn:

  • min_date / max_date: đặt ngày giới hạn cho các giá trị được chấp nhận. Theo mặc định, ngày được chấp nhận sớm nhất là 1000-01-01 và ngày muộn nhất là 9999-12-31. Các giá trị được chấp nhận là ngày có định dạng SQL (yyyy-MM-dd HH:mm:ss) hoặc "hôm nay".

    <field name="datefield" options="{'min_date': 'today', 'max_date': '2023-12-31'}" />
    
  • Warn_future: hiển thị cảnh báo nếu giá trị nằm trong tương lai (dựa trên hôm nay).

    <field name="datefield" options="{'warn_future': true}" />
    
Ngày & Giờ (datetime)

Đây là loại trường mặc định cho các trường loại datetime. Các giá trị luôn nằm trong múi giờ của khách hàng.

  • Các loại trường được hỗ trợ: datetime

Tùy chọn:

  • xem các tùy chọn Trường ngày

  • làm tròn: số gia được sử dụng để tạo số phút có sẵn trong bộ chọn thời gian. Điều này không ảnh hưởng đến giá trị thực tế, chỉ ảnh hưởng đến số lượng tùy chọn có sẵn trong danh sách thả xuống chọn (mặc định: 5).

    <field name="datetimefield" options="{'rounding': 10}" />
    
Phạm vi ngày (phạm vi ngày)

Tiện ích này cho phép người dùng chọn ngày bắt đầu và ngày kết thúc từ một bộ chọn duy nhất.

  • Các loại trường được hỗ trợ: date, datetime

Tùy chọn:

  • xem Trường ngày hoặc Trường ngày & giờ tùy chọn

  • start_date_field: trường được sử dụng để lấy/đặt giá trị bắt đầu của phạm vi ngày (không thể sử dụng với end_date_field).

    <field name="end_date" widget="daterange" options="{'start_date_field': 'start_date'}" />
    
  • end_date_field: trường được sử dụng để lấy/đặt giá trị cuối của phạm vi ngày (không thể sử dụng với start_date_field).

    <field name="start_date" widget="daterange" options="{'end_date_field': 'end_date'}" />
    
Số Ngày Còn Lại (remaining_days)

Tiện ích này có thể được sử dụng trên các trường ngày và giờ. Ở chế độ chỉ đọc, nó hiển thị delta (tính theo ngày) giữa giá trị của trường và ngày hôm nay. Tiện ích sẽ chuyển thành trường ngày hoặc giờ thông thường ở chế độ chỉnh sửa.

  • Các loại trường được hỗ trợ: date, datetime

Tiền tệ (tiền tệ)

Đây là loại trường mặc định cho các trường loại tiền tệ. Nó được sử dụng để hiển thị một loại tiền tệ. Nếu có một trường tiền tệ được cung cấp trong tùy chọn, nó sẽ sử dụng trường đó, nếu không, nó sẽ quay trở lại loại tiền mặc định (trong phiên)

  • Các loại trường được hỗ trợ: tiền tệ, float

Tùy chọn:

  • currency_field: một tên trường khác phải là many2one trên đơn vị tiền tệ.

    <field name="value" widget="monetary" options="{'currency_field': 'currency_id'}" />
    
Văn bản (văn bản)

Đây là loại trường mặc định cho các trường loại văn bản.

  • Các loại trường được hỗ trợ: text

Tay cầm (tay cầm)

Nhiệm vụ của trường này là được hiển thị dưới dạng tay cầm và cho phép sắp xếp lại các bản ghi khác nhau bằng cách kéo và thả chúng.

Cảnh báo

Nó phải được chỉ định trên trường mà các bản ghi được sắp xếp.

Cảnh báo

Việc có nhiều trường có tiện ích xử lý trên cùng một danh sách không được hỗ trợ.

  • Các loại trường được hỗ trợ: số nguyên

Thư điện tử (email)

Trường này hiển thị địa chỉ email. Lý do chính để sử dụng nó là vì nó được hiển thị dưới dạng thẻ liên kết với href thích hợp, ở chế độ chỉ đọc.

  • Các loại trường được hỗ trợ: char

Điện thoại (điện thoại)

Trường này hiển thị một số điện thoại. Lý do chính để sử dụng nó là vì nó được hiển thị dưới dạng thẻ liên kết với href thích hợp, ở chế độ chỉ đọc, nhưng chỉ trong một số trường hợp: chúng tôi chỉ muốn làm cho nó có thể nhấp được nếu thiết bị có thể gọi số cụ thể này.

  • Các loại trường được hỗ trợ: char

URL (url)

Trường này hiển thị một url (ở chế độ chỉ đọc). Lý do chính để sử dụng nó là vì nó được hiển thị dưới dạng thẻ liên kết với các lớp css và href thích hợp.

Ngoài ra, văn bản của thẻ liên kết có thể được tùy chỉnh bằng thuộc tính text (nó sẽ không thay đổi giá trị href).

  • Các loại trường được hỗ trợ: char

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

Tùy chọn:

  • website_path: (mặc định: false) theo mặc định, tiện ích buộc (nếu chưa phải như vậy) giá trị href bắt đầu bằng "http://" ngoại trừ nếu tùy chọn này được đặt thành true, do đó cho phép chuyển hướng đến trang web riêng của cơ sở dữ liệu.

Tên miền (tên miền)

Trường domain cho phép người dùng xây dựng miền tiền tố kỹ thuật nhờ giao diện dạng cây và xem các bản ghi đã chọn trong thời gian thực. Trong chế độ gỡ lỗi, cũng có một đầu vào để có thể nhập trực tiếp miền tiền tố char (hoặc để xây dựng các miền nâng cao mà giao diện dạng cây không cho phép).

Lưu ý rằng điều này được giới hạn ở các miền tĩnh (không có biểu thức động hoặc quyền truy cập vào biến ngữ cảnh).

  • Các loại trường được hỗ trợ: char

Nút liên kết (link_button)

Tiện ích LinkButton thực sự chỉ hiển thị một khoảng có biểu tượng và giá trị văn bản làm nội dung. Liên kết có thể nhấp vào được và sẽ mở một cửa sổ trình duyệt mới với giá trị là url.

  • Các loại trường được hỗ trợ: char

Tệp hình ảnh (hình ảnh)

Tiện ích này được sử dụng để thể hiện giá trị nhị phân dưới dạng hình ảnh. Trong một số trường hợp, máy chủ trả về bin_size thay vì hình ảnh thực (bin_size là một chuỗi biểu thị kích thước tệp, chẳng hạn như "6,5kb"). Trong trường hợp đó, widget sẽ tạo một hình ảnh có thuộc tính nguồn tương ứng với hình ảnh trên máy chủ.

  • Các loại trường được hỗ trợ: nhị phân

Tùy chọn:

  • preview_image: nếu hình ảnh chỉ được tải dưới dạng bin_size, thì tùy chọn này rất hữu ích để thông báo cho máy khách web rằng tên trường mặc định không phải là tên của trường hiện tại mà là tên của một trường khác.

    <field name="image" widget="image" options="{'preview_image': 'image_128'}" />
    
  • accepted_file_extensions: phần mở rộng tệp mà người dùng có thể chọn từ hộp thoại nhập tệp (giá trị mặc định là "image/*")

    (cf: thuộc tính accept trên <input type="file" />)

Tệp nhị phân (nhị phân)

Tiện ích chung để cho phép lưu/tải xuống tệp nhị phân.

  • Các loại trường được hỗ trợ: nhị phân

Thuộc tính:

  • tên tệp: lưu tệp nhị phân sẽ mất tên tệp vì nó chỉ lưu giá trị nhị phân. Tên tệp có thể được lưu trong trường khác. Để làm điều đó, thuộc tính filename phải được đặt thành một trường có trong dạng xem.

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

Tùy chọn:

  • accepted_file_extensions: phần mở rộng tệp mà người dùng có thể chọn từ hộp thoại nhập tệp

    (cf: thuộc tính accept trên <input type="file" />)

Ưu tiên (ưu tiên)

Tiện ích này được hiển thị dưới dạng tập hợp các ngôi sao, cho phép người dùng nhấp vào nó để chọn giá trị hoặc không. Điều này rất hữu ích, chẳng hạn như để đánh dấu một nhiệm vụ có mức độ ưu tiên cao.

Lưu ý rằng tiện ích này cũng hoạt động ở chế độ chỉ đọc, điều này không bình thường.

  • Các loại trường được hỗ trợ: selection

Tệp đính kèm hình ảnh (attachment_image)

Tiện ích hình ảnh cho các trường man2one. Nếu trường được đặt, tiện ích này sẽ được hiển thị dưới dạng hình ảnh có url src thích hợp. Tiện ích này không có hành vi khác ở chế độ chỉnh sửa hoặc chỉ đọc, nó chỉ hữu ích khi xem hình ảnh.

  • Các loại trường được hỗ trợ: many2one

<field name="displayed_image_id" widget="attachment_image" />
Lựa chọn nhãn (label_selection)

Tiện ích này hiển thị một nhãn đơn giản không thể chỉnh sửa. Điều này chỉ hữu ích để hiển thị một số thông tin, không chỉnh sửa nó.

  • Các loại trường được hỗ trợ: selection

Tùy chọn:

  • classes: ánh xạ từ giá trị lựa chọn sang tên lớp CSS

    <field
        name="state"
        widget="label_selection"
        options="{
            'classes': {
                'draft': 'default',
                'cancel': 'default',
                'none': 'danger',
            },
        }"
    />
    
Lựa chọn trạng thái (state_selection)

Đây là một tiện ích lựa chọn chuyên dụng. Nó giả định rằng bản ghi có một số trường được mã hóa cứng, hiển thị trong dạng xem: stage_id, legend_normal, legend_blocked, legend_done. Điều này chủ yếu được sử dụng để hiển thị và thay đổi trạng thái của một tác vụ trong dự án, với thông tin bổ sung được hiển thị trong danh sách thả xuống.

  • Các loại trường được hỗ trợ: selection

<field name="kanban_state" widget="state_selection" />
Lựa chọn trạng thái - Chế độ xem danh sách (list.state_selection)

Trong chế độ xem danh sách, trường state_selection hiển thị nhãn bên cạnh biểu tượng theo mặc định.

  • Các loại trường được hỗ trợ: selection

Tùy chọn:

  • hide_label: ẩn nhãn bên cạnh biểu tượng

    <field name="kanban_state" widget="state_selection" options="{'hide_label': true}" />
    
Yêu thích (boolean_favorite)

Tiện ích này được hiển thị dưới dạng ngôi sao trống (hoặc không), tùy thuộc vào giá trị boolean. Lưu ý rằng nó cũng có thể được chỉnh sửa ở chế độ chỉ đọc.

  • Các loại trường được hỗ trợ: boolean

Chuyển đổi (boolean_toggle)

Hiển thị một nút chuyển đổi để thể hiện một boolean. Đây là trường con của trường boolean, chủ yếu được sử dụng để có giao diện khác.

  • Các loại trường được hỗ trợ: boolean

Thông tin thống kê (statinfo)

Tiện ích này nhằm mục đích thể hiện thông tin thống kê trong một nút thống . Về cơ bản nó chỉ là một nhãn có số.

  • Các loại trường được hỗ trợ: số nguyên, float

Tùy chọn:

  • label_field: nếu được cung cấp, tiện ích sẽ sử dụng giá trị của label_field làm văn bản.

    <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>
    
Phần Trăm Bánh (percentpie)

Tiện ích này nhằm mục đích thể hiện thông tin thống kê trong một nút thống . Tiện ích này tương tự như tiện ích statininfo nhưng thông tin được thể hiện dưới dạng biểu đồ hình tròn (trống đến đầy). Lưu ý rằng giá trị được hiểu là phần trăm (một số nằm trong khoảng từ 0 đến 100).

  • Các loại trường được hỗ trợ: số nguyên, float

<field name="replied_ratio" string="Replied" widget="percentpie" />
Thanh tiến trình (thanh tiến trình)

Biểu thị một giá trị dưới dạng thanh tiến trình (từ 0 đến một giá trị nào đó)

  • Các loại trường được hỗ trợ: số nguyên, float

Tùy chọn:

  • editable: boolean xác định xem giá trị có thể chỉnh sửa được không

  • current_value: lấy giá trị hiện tại từ trường phải có trong dạng xem

  • max_value: lấy giá trị tối đa từ trường phải có trong dạng xem

  • edit_max_value: boolean xác định xem max_value có thể chỉnh sửa được không

  • title: tiêu đề của thanh, hiển thị trên đầu thanh

    -> chưa được dịch, thay vào đó hãy sử dụng thuộc tính title (không phải tùy chọn) nếu thuật ngữ đó phải được dịch

<field
    name="absence_of_today"
    widget="progressbar"
    options="{
        'current_value': 'absence_of_today',
        'max_value': 'total_employee',
        'editable': false,
    }"
/>
Biểu đồ bảng điều khiển tạp chí (dashboard_graph)

Đây là một tiện ích chuyên dụng hơn, hữu ích để hiển thị biểu đồ biểu thị một tập hợp dữ liệu. Ví dụ: nó được sử dụng trong chế độ xem kanban của bảng điều khiển kế toán.

Nó giả định rằng trường này là một chuỗi JSON của một tập hợp dữ liệu.

  • Các loại trường được hỗ trợ: char

Thuộc tính:

  • graph_type: chuỗi, có thể là "line" hoặc "bar"

    <field name="dashboard_graph_data" widget="dashboard_graph" graph_type="line" />
    
Biên tập viên Ace (ace)

Tiện ích này được thiết kế để sử dụng trên các trường Văn bản. Nó cung cấp Ace Editor để chỉnh sửa XML và Python.

  • Các loại trường được hỗ trợ: char, text

Huy hiệu (huy hiệu)

Hiển thị giá trị bên trong viên thuốc huy hiệu bootstrap.

  • Các loại trường được hỗ trợ: char, selection, many2one

Theo mặc định, huy hiệu có nền màu xám nhạt nhưng có thể tùy chỉnh bằng cách sử dụng cơ chế Decoration. Ví dụ: để hiển thị huy hiệu màu đỏ theo một điều kiện nhất định:

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

Các trường quan hệ

Lựa chọn (lựa chọn)

  • Các loại trường được hỗ trợ: selection

Thuộc tính:

  • placeholder: một chuỗi được sử dụng để hiển thị một số thông tin khi không có giá trị nào được chọn

    <field name="tax_id" widget="selection" placeholder="Select a tax" />
    
Đài phát thanh (đài phát thanh)

Đây là trường con của FielSelection, nhưng được chuyên dùng để hiển thị tất cả các lựa chọn hợp lệ dưới dạng nút radio.

Lưu ý rằng nếu được sử dụng trên bản ghi many2one thì sẽ có nhiều rpcs hơn được thực hiện để tìm nạp name_gets của các bản ghi liên quan.

  • Các loại trường được hỗ trợ: selection, many2one

Tùy chọn:

  • horizontal: nếu true, các nút radio sẽ được hiển thị theo chiều ngang.

    <field name="recommended_activity_type_id" widget="radio" options="{'horizontal': true}"/>
    
Lựa chọn huy hiệu (selection_badge)

Đây là trường con của trường lựa chọn, nhưng được chuyên dùng để hiển thị tất cả các lựa chọn hợp lệ dưới dạng huy hiệu hình chữ nhật.

  • Các loại trường được hỗ trợ: selection, many2one

<field name="recommended_activity_type_id" widget="selection_badge" />
Many2one (many2one)

Tiện ích mặc định cho các trường many2one.

  • Các loại trường được hỗ trợ: many2one

Thuộc tính:

  • can_create: cho phép tạo các bản ghi liên quan (được ưu tiên hơn tùy chọn no_create)

  • can_write: cho phép chỉnh sửa các bản ghi liên quan (mặc định: true)

Tùy chọn:

  • quick_create: cho phép tạo nhanh các bản ghi liên quan (mặc định: true)

  • no_create: ngăn việc tạo các bản ghi liên quan - ẩn cả hai mục menu thả xuống Tạo "xxx"Tạo và chỉnh sửa (mặc định: false)

  • no_quick_create: ngăn việc tạo nhanh các bản ghi liên quan - ẩn mục menu thả xuống Tạo "xxx" (mặc định: false)

  • no_create_edit: ẩn mục menu thả xuống Tạo và chỉnh sửa (mặc định: false)

  • create_name_field: khi tạo bản ghi liên quan, nếu tùy chọn này được đặt, giá trị của create_name_field sẽ được điền bằng giá trị của đầu vào (mặc định: name)

  • always_reload: boolean, mặc định là false. Nếu true, tiện ích sẽ luôn thực hiện thêm name_get để tìm nạp giá trị tên của nó. Điều này được sử dụng trong trường hợp phương thức name_get bị ghi đè (vui lòng không làm điều đó)

  • no_open: boolean, mặc định là false. Nếu được đặt thành true, many2one sẽ không chuyển hướng đến bản ghi khi nhấp vào nó (ở chế độ chỉ đọc)

<field name="currency_id" options="{'no_create': true, 'no_open': true}" />
Mã vạch Many2one (many2one_barcode)

Tiện ích dành cho trường many2one cho phép mở camera từ thiết bị di động (Android/iOS) để quét mã vạch.

Chuyên môn hóa trường many2one nơi người dùng được phép sử dụng máy ảnh gốc để quét mã vạch. Sau đó, nó sử dụng name_search để tìm kiếm giá trị này.

Nếu tiện ích này được đặt và người dùng không sử dụng ứng dụng di động, nó sẽ chuyển sang many2one (Many2OneField) thông thường

  • Các loại trường được hỗ trợ: many2one

Avatar của Many2one (many2one_avatar)

Tiện ích này chỉ được hỗ trợ trên các trường many2one trỏ đến mô hình kế thừa từ image.mixin. Ở chế độ chỉ đọc, nó hiển thị hình ảnh của bản ghi liên quan bên cạnh display_name của nó. Lưu ý rằng display_name không phải là liên kết có thể nhấp vào trong trường hợp này. Trong bản chỉnh sửa, nó hoạt động giống hệt như many2one thông thường.

  • Các loại trường được hỗ trợ: many2one

Người dùng Avatar Many2one (many2one_avatar_user)

Tiện ích này là một chuyên biệt của Many2OneAvatar. Khi nhấp vào hình đại diện, chúng tôi sẽ mở cửa sổ trò chuyện với người dùng tương ứng. Tiện ích này chỉ có thể được đặt trên các trường many2one trỏ đến mô hình res.users.

  • Các loại trường được hỗ trợ: many2one (trỏ tới res.users)

Nhân viên Avatar của Many2one (many2one_avatar_employee)

Tương tự như many2one_avatar_user, nhưng đối với các trường many2one trỏ đến hr.employee.

  • Các loại trường được hỗ trợ: many2one (trỏ tới hr.employee)

Many2many (many2many)

Tiện ích mặc định cho các trường many2many.

  • Các loại trường được hỗ trợ: many2many

Thuộc tính:

  • mode: chuỗi, chế độ xem mặc định để hiển thị

  • domain: giới hạn dữ liệu trong một miền cụ thể

Tùy chọn:

  • create_text: cho phép tùy chỉnh văn bản hiển thị khi thêm bản ghi mới

  • link: miền xác định liệu các bản ghi có thể được thêm vào mối quan hệ hay không (mặc định: true).

  • unlink: miền xác định liệu các bản ghi có thể bị xóa khỏi mối quan hệ hay không (mặc định: true).

Tệp nhị phân Many2many (many2many_binary)

Tiện ích này giúp người dùng tải lên hoặc xóa một hoặc nhiều tệp cùng một lúc.

Lưu ý rằng tiện ích này dành riêng cho mô hình ir.attachment.

  • Các loại trường được hỗ trợ: many2many

Tùy chọn:

  • accepted_file_extensions: phần mở rộng tệp mà người dùng có thể chọn từ hộp thoại nhập tệp

    (cf: thuộc tính accept trên <input type="file" />)

Thẻ Many2many (many2many_tags)

Hiển thị trường many2many dưới dạng danh sách các thẻ.

  • Các loại trường được hỗ trợ: many2many

Tùy chọn:

  • create: miền xác định xem có thể tạo thẻ mới hay không (mặc định: true).

    <field name="category_id" widget="many2many_tags" options="{'create': [['some_other_field', '>', 24]]}" />
    
  • color_field: tên của trường số, sẽ có trong dạng xem. Một màu sẽ được chọn tùy thuộc vào giá trị của nó.

    <field name="category_id" widget="many2many_tags" options="{'color_field': 'color'}" />
    
  • no_edit_color: đặt thành true để loại bỏ khả năng thay đổi màu của thẻ (mặc định: false).

    <field name="category_id" widget="many2many_tags" options="{'color_field': 'color', 'no_edit_color': true}" />
    
Thẻ Many2many - Chế độ xem biểu mẫu (form.many2many_tags)

Chuyên môn hóa tiện ích many2many_tags dành cho chế độ xem biểu mẫu. Nó có một số mã bổ sung để cho phép chỉnh sửa màu của thẻ.

  • Các loại trường được hỗ trợ: many2many

Thẻ Many2many - Chế độ xem Kanban (kanban.many2many_tags)

Chuyên môn hóa tiện ích many2many_tags cho chế độ xem kanban.

  • Các loại trường được hỗ trợ: many2many

Hộp kiểm Many2many (many2many_checkboxes)

Trường này hiển thị danh sách các hộp kiểm và cho phép người dùng chọn một tập hợp con các lựa chọn. Lưu ý rằng số lượng giá trị được hiển thị được giới hạn ở 100. Giới hạn này không thể tùy chỉnh. Nó chỉ đơn giản cho phép xử lý các trường hợp cực đoan khi tiện ích này được đặt sai trên một trường có comodel lớn. Trong những trường hợp đó, chế độ xem danh sách sẽ phù hợp hơn vì nó cho phép phân trang và lọc.

  • Các loại trường được hỗ trợ: many2many

One2many (one2many)

Tiện ích mặc định cho các trường one2many. Nó thường hiển thị dữ liệu trong chế độ xem danh sách phụ hoặc chế độ xem kanban phụ.

  • Các loại trường được hỗ trợ: one2many

Tùy chọn:

  • tạo: miền xác định xem có thể tạo các bản ghi liên quan hay không (mặc định: true).

  • delete: miền xác định xem các bản ghi liên quan có thể bị xóa hay không (mặc định: true).

    <field name="turtles" options="{'create': [['some_other_field', '>', 24]]}" />
    
  • create_text: một chuỗi được sử dụng để tùy chỉnh nhãn/văn bản 'Thêm'.

    <field name="turtles" options="{'create_text': 'Add turtle'}" />
    
Thanh trạng thái (thanh trạng thái)

Đây là một trường dành riêng cho các dạng xem biểu mẫu. Đây là thanh nằm trên cùng của nhiều biểu mẫu đại diện cho một luồng và cho phép chọn một trạng thái cụ thể.

  • Các loại trường được hỗ trợ: selection, many2one

Tham khảo (tham khảo)

Trường reference là sự kết hợp của trường select (đối với mô hình) và trường many2one (đối với giá trị của nó). Nó cho phép lựa chọn một bản ghi trên một mô hình tùy ý.

  • Các loại trường được hỗ trợ: char, reference

Tùy chọn:

  • model_field: tên của ir.model chứa mô hình của các bản ghi có thể được chọn. Khi tùy chọn này được đặt, phần chọn của trường tham chiếu sẽ không được hiển thị.

Widget

Ngày trong tuần (week_days)

Tiện ích này hiển thị danh sách các hộp kiểm cho các ngày trong tuần, 1 hộp kiểm cho mỗi ngày và cho phép người dùng chọn một tập hợp con các lựa chọn.

<widget name="week_days" />

Hành động của khách hàng

A client action is a component that can be displayed as the main element in the webclient, occupying all the space below the navbar, just like an act_window_action. This is useful when you need a component that is not closely linked to an existing view or a specific model. For example, the Discuss application is a client action.

Hành động của khách hàng là một thuật ngữ có nhiều ý nghĩa khác nhau, tùy thuộc vào ngữ cảnh:

  • từ góc nhìn của máy chủ, nó là bản ghi của mô hình ir_action, với trường tag thuộc loại char

  • from the perspective of the web client, it is an Owl component registered in the action registry under the same key its tag

Whenever a menu item is associated with a client action, opening it will simply fetch the action definition from the server, then lookup its tag in the action registry to get the component definition. This component will then be rendered by the action container.

Thêm hành động của khách hàng

A client action is a component that will control the part of the screen below the navbar. Defining a client action is as simple as creating an Owl component and adding it to the action registry.

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

Sau đó, để sử dụng hành động của máy khách trong máy khách web, chúng ta cần tạo một bản ghi hành động của máy khách (bản ghi của mô hình ir.actions.client) với thuộc tính tag thích hợp:

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