This page looks best with JavaScript enabled

Tạo widget dashboard với thư viện Chart trong Odoo

 ·  ☕ 9 phút đọc · 👀... views

Trong bài viết lần này, mình sẽ hướng dẫn các bạn tạo ra 1 widget để hỗ trợ chúng ta vẽ dashboard

1.Thư viện Chart Odoo

Đầu tiên chúng ta sẽ tìm hiểu về thư viện Chart của Odoo, bạn có thể tìm thấy nó theo đường dẫn ‘/web/static/lib/Chart/Chart.js’

Các biểu đồ được sử dụng phổ biến trong Chart.js bao gồm:

  • Scatter Plot Chart
  • Line Chart
  • Bar Chart
  • Pie Chart
  • Doughnut Chart

Để có thể sử dụng biểu đồ Chart trong Odoo chúng ta có thể thêm vào file xml, sau đó thêm vào file manifest như sau:

Tiếp theo chúng ta cần thêm đoạn code sau vào nơi mà chúng ta muốn hiển thị biểu đồ trong file xml như sau:

<canvas id="chart_example" height="400px" width="400px"/>

Về cơ bản thì cú pháp để truyền tham số vào Chart sẽ như sau:

new Chart(“id of canvas”, {
    type = “type of graph”,
    data = { “data of the graph” },
    options = {“options of the graph” }
});

type, data, options sẽ phụ thuôc vào loại biểu đồ mà chúng ta muốn hiển thị, mình sẽ đưa ra một số loại biểu đồ cũng như cách sử dụng của chúng dưới đây

Scatter Plot Chart

Dưới đây là đoạn code ví dụ cho biểu đồ này:

var chart = new Chart("chart_example", {
    type: "scatter",
    data: {
        datasets: [{
            data: [{
                x: 10,
                y: 10
            }, {
                x: 20,
                y: 20
            }, {
                x: 30,
                y: 30
            }, {
                x: 40,
                y: 40
            }, {
                x: 50,
                y: 50
            }],
            pointBackgroundColor: "black",
        }]
    },
    options: {}
});

Để có thể hiển thị lên giao diện Chart trong odoo, có rất nhiều cách khác nhau, tuy nhiên ở bài viết lần này mình sẽ tạo 1 widget cho từng biểu đồ cũng như thêm trực tiếp dữ liệu tạo vào trong file js, thực tế các dữ liệu mà chúng ta truyền vào như, chiều rộng, kích thước các cột, số liệu ra sao chúng ta phải xử lý bên python, có thể viết field đó là compute hoặc gọi rpc
Code js widget như sau:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
odoo.define('chart_dashboard.chart_dashboard_scatter', function (require) {
    "use strict";

    var fieldRegistry = require('web.field_registry');
    var AbstractField = require('web.AbstractField');
    var core = require('web.core');
    var _t = core._t;

    var FieldChartWidget = AbstractField.extend({
        supportedFieldTypes: ['char', 'text'],
        jsLibs: [
            '/web/static/lib/Chart/Chart.js',
        ],
        _render: function () {
            var self = this;
            var $canvas = $('<canvas/>');
            if (this.chart) {
                this.chart.destroy();
            }
            this.$el.empty();
            this.$el.append($canvas);
            this.chart = new Chart($canvas, {
                type: "scatter",
                data: {
                    datasets: [{
                        data: [{
                            x: 10,
                            y: 10
                        }, {
                            x: 20,
                            y: 20
                        }, {
                            x: 30,
                            y: 30
                        }, {
                            x: 40,
                            y: 40
                        }, {
                            x: 50,
                            y: 50
                        }],
                        pointBackgroundColor: "black",
                    }]
                },
                options: {}
            });
            return this._super.apply(this, arguments);
        },
    });

    fieldRegistry.add('chart_scatter', FieldChartWidget);

    return {
        FieldChartWidget: FieldChartWidget
    };
});

Code file xml mình để như sau:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
 <record model="ir.ui.view" id="chart_dashboard">
            <field name="name">chart_dasboard</field>
            <field name="model">chart.dashboard</field>
            <field name="arch" type="xml">
                <form checkDirty="false">
                     <div class="row">
                        <div class="col-6">
                            <div class="text-uppercase default-color">
                                <div><em class="fa fa-list-ol" /> Dashboard Scatter
                                </div><hr/>
                                <field name="value1" widget="chart_scatter" class="dashboard_ren_chart"/>
                            </div>
                        </div>
                     </div>
                </form>
            </field>
        </record>

Mình có thêm 1 file css

1
2
3
.dashboard_ren_chart {
    width: 50%;
}

Và đây là kết quả:

Line Chart

Đoạn code chúng ta truyền vào đối với biểu đồ này như sau:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
var chart = new Chart("chart_example", {
    type: "line",
    data: {
        labels: [10, 20, 30, 40, 50],
        datasets: [{
            data: [10, 20, 30, 40, 50],
            pointBackgroundColor: "black",
        }]
    },
    option: {}
});

Mình cũng sẽ tạo 1 widget như sau:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
odoo.define('chart_dashboard.chart_dashboard_line', function (require) {
    "use strict";

    var fieldRegistry = require('web.field_registry');
    var AbstractField = require('web.AbstractField');
    var core = require('web.core');
    var _t = core._t;

    var FieldChartWidget = AbstractField.extend({
        supportedFieldTypes: ['char', 'text'],
        jsLibs: [
            '/web/static/lib/Chart/Chart.js',
        ],
        _render: function () {
            var self = this;
            var $canvas = $('<canvas/>');
            if (this.chart) {
                this.chart.destroy();
            }
            this.$el.empty();
            this.$el.append($canvas);
            this.chart = new Chart($canvas, {
                type: "line",
                data: {
                    labels: [10, 20, 30, 40, 50],
                    datasets: [{
                        data: [10, 20, 30, 40, 50],
                        pointBackgroundColor: "black",
                    }]
                },
                option: {}
            });
            return this._super.apply(this, arguments);
        },
    });

    fieldRegistry.add('chart_line', FieldChartWidget);

    return {
        FieldChartWidget: FieldChartWidget
    };
});

Và đây là kết quả

Bar Chart

Biểu đồ dạng thanh được sử dụng nhiều nhất trong odoo, chúng ta cũng có thể tùy chỉnh màu sắc, chiều rộng chiều cao…
Dưới đây là đoạn code ví dụ:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
var chart = new Chart("chart_example", {
    type: "bar",
    data: {
        labels: ["bar1", "bar2", "bar3", "bar4"],
        datasets: [{
            backgroundColor: "black",
            data: [0, 10, 20, 30]
        }]
    },
    options: {}
});

Chúng ta sẽ viết 1 widget như sau:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
odoo.define('chart_dashboard.chart_dashboard_bar', function (require) {
    "use strict";

    var fieldRegistry = require('web.field_registry');
    var AbstractField = require('web.AbstractField');
    var core = require('web.core');
    var _t = core._t;

    var FieldChartWidget = AbstractField.extend({
        supportedFieldTypes: ['char', 'text'],
        jsLibs: [
            '/web/static/lib/Chart/Chart.js',
        ],
        _render: function () {
            var self = this;
            var $canvas = $('<canvas/>');
            if (this.chart) {
                this.chart.destroy();
            }
            this.$el.empty();
            this.$el.append($canvas);
            this.chart = new Chart($canvas, {
                type: "bar",
                data: {
                    labels: ["bar1", "bar2", "bar3", "bar4"],
                    datasets: [{
                        backgroundColor: "black",
                        data: [0, 10, 20, 30]
                    }]
                },
                options: {}
            });
            return this._super.apply(this, arguments);
        },
    });

    fieldRegistry.add('chart_bar', FieldChartWidget);

    return {
        FieldChartWidget: FieldChartWidget
    };
});

Và đây là kết quả

Pie Chart

Tiếp theo chúng ta đến với biểu đồ tròn, dưới đây là đoạn code ví dụ:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
var chart = new Chart("chart_example", {
    type: "pie",
    data: {
        datasets: [{
            backgroundColor: "black",
            data: [0, 10, 20, 30, 40]
        }]
    },
    options: {}
});

Chúng ta sẽ tạo 1 widget như sau:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
odoo.define('chart_dashboard.chart_dashboard_bar', function (require) {
    "use strict";

    var fieldRegistry = require('web.field_registry');
    var AbstractField = require('web.AbstractField');
    var core = require('web.core');
    var _t = core._t;

    var FieldChartWidget = AbstractField.extend({
        supportedFieldTypes: ['char', 'text'],
        jsLibs: [
            '/web/static/lib/Chart/Chart.js',
        ],
        _render: function () {
            var self = this;
            var $canvas = $('<canvas/>');
            if (this.chart) {
                this.chart.destroy();
            }
            this.$el.empty();
            this.$el.append($canvas);
            this.chart = new Chart($canvas, {
                type: "bar",
                data: {
                    labels: ["bar1", "bar2", "bar3", "bar4"],
                    datasets: [{
                        backgroundColor: "black",
                        data: [0, 10, 20, 30]
                    }]
                },
                options: {}
            });
            return this._super.apply(this, arguments);
        },
    });

    fieldRegistry.add('chart_bar', FieldChartWidget);

    return {
        FieldChartWidget: FieldChartWidget
    };
});

Và đây là kết quả

Doughnut chart

Biểu đồ này cũng tương tự như biểu đồ tròn, dưới đây là đoạn code mẫu

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
var chart = new Chart("chart_example", {
    type: "doughnut",
    data: {
        datasets: [{
            backgroundColor: "black",
            data: [0, 10, 20, 30, 40]
        }]
    },
    options: {
    }
});

Chúng ta sẽ viết 1 widget như sau:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
odoo.define('chart_dashboard.chart_dashboard_doughnut', function (require) {
    "use strict";

    var fieldRegistry = require('web.field_registry');
    var AbstractField = require('web.AbstractField');
    var core = require('web.core');
    var _t = core._t;

    var FieldChartWidget = AbstractField.extend({
        supportedFieldTypes: ['char', 'text'],
        jsLibs: [
            '/web/static/lib/Chart/Chart.js',
        ],
        _render: function () {
            var self = this;
            var $canvas = $('<canvas/>');
            if (this.chart) {
                this.chart.destroy();
            }
            this.$el.empty();
            this.$el.append($canvas);
            this.chart = new Chart($canvas, {
                type: "doughnut",
                data: {
                    datasets: [{
                        backgroundColor: "black",
                        data: [0, 10, 20, 30, 40]
                    }]
                },
                options: {}
            });
            return this._super.apply(this, arguments);
        },
    });

    fieldRegistry.add('chart_doughnut', FieldChartWidget);

    return {
        FieldChartWidget: FieldChartWidget
    };
});

dưới đây là kết quả:

2. Truyền dữ liệu từ field vào widget dashboard


Bước đầu tiên chúng ta sẽ tạo ra 1 ir.actions.server mục đích để khi chúng ta bấm vào chart_dashboard, chúng ta sẽ truyền giá trị tương ứng vào view thông qua hàm python viết trong ir.actions.server

Đây là đoạn code view cơ bản mình đã viết trong đó record có id là chart_dashboard sẽ là dashboard mà chúng ta cần xử lý trong bài viết lần này

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<odoo>
    <data>
        <record model="ir.ui.view" id="chart_dashboard">
            <field name="name">chart_dasboard</field>
            <field name="model">chart.dashboard</field>
            <field name="arch" type="xml">
                <form checkDirty="false">
                </form>
            </field>
        </record>
        <record model="ir.actions.server" id="chart_dashboard_server_action">
            <field name="name">Dashboard</field>
            <field name="model_id" ref="chart_dashboard.model_chart_dashboard" />
            <field name="state">code</field>
            <field name="code">
                action=model.show_dashboard()
            </field>
        </record>
        <record model="ir.actions.act_window" id="chart_dashboard_action_window">
            <field name="name">chart_dashboard window</field>
            <field name="res_model">chart.dashboard</field>
            <field name="view_mode">form</field>
            <field name="view_id" ref="chart_dashboard" />
            <field name="target">inline</field>
        </record>

        <!-- Top menu item -->
        <menuitem name="chart_dashboard" id="chart_dashboard_menu_root"
                  web_icon="chart_dashboard,static/description/img.png"/>
        <menuitem id="chart_dashboard_menu"
                  action="chart_dashboard_server_action"
                  parent="chart_dashboard_menu_root"
                  name="Chart Dashboard"
                  sequence="1"/>
    </data>
</odoo>

ở phần 1, dữ liệu mình truyền vào widget là trong file js, tuy nhiên thực tế, chúng ta sẽ truyền từ python qua. Cụ thể mình sẽ viết 1 field compute, trả về giá trị như mình truyền vào file js bên trên như sau:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
    type: "doughnut",
    data: {
        datasets: [{
            backgroundColor: "black",
            data: [0, 10, 20, 30, 40]
        }]
    },
    options: {
    }
}

Chúng ta có thể lấy được giá trị của field từ hàm _render thông qua biến this.value, khi lấy được giá trị field rồi, chúng ta sẽ chỉnh sửa để cho vào js trong widget

Chúng ta sẽ tạo 1 field và viết hàm compute cho nó như sau:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
value6 = fields.Text(compute="_compute_value_6")
def _compute_value_6(self):
    for rc in self:
        rc.value6 = json.dumps({
            'type': "doughnut",
            'data': {
                'datasets': [{
                    'backgroundColor': "black",
                    'data': [0, 10, 20, 30, 40]
                }]
            },
            'options': {}
        })

Trong hàm _render, chúng ta thử log gía trị this.value xem nó trả ra gì nhé!

Chúng ta chỉ cần sửa hàm _render như sau, chúng ta sẽ có kết quả hiển thị biểu đồ tương tự:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
 _render: function () {
            var self = this;
            var $canvas = $('<canvas/>');
            if (this.chart) {
                this.chart.destroy();
            }
            this.$el.empty();
            this.$el.append($canvas);
            var config = JSON.parse(this.value);
            this.chart = new Chart($canvas,config)
            return this._super.apply(this, arguments);
        },

Bài viết về dashboard trong Odoo của mình cũng dừng lại ở đây, hẹn mọi người vào những bài viết tiếp theo nhé!😀

Chia sẻ
Support the author with

Hùng Phạm
Viết bởi
Hùng Phạm
Web/Mobile Developer