odoo与透视图结合

345 阅读2分钟

最近提出的一个需求,对数据进行汇总,最好能展示出来,后来看到蚂蚁数据可视化中的s2比较合适就做了一下,效果如图:

image.png 简单说一下思路:通过JS将S2引入,然后使用RPC通过调用模型中的方法获取数据,按照S2文档出入数据,然后“ir.actions.client”展示Qweb模板,将表格展示出来。

  1. 创建一个菜单(创建一个按钮也可以)
<menuitem id="menu_example_data_s2"

    name="表格分析(S2)"

    action="action_example_s2"

    parent="menu_report_odoo"

    sequence="10"

/>
  1. 创建action:使用的action是“ir.actions.client”,用来打开模板
<record id="action_example_s2" model="ir.actions.client">

    <field name="name">表格分析(S2)</field>

    <field name="tag">example.data.s2</field>

    <field name="target">new</field>

</record>
  1. 要展示的模型:模型中返回数据格式在S2文档中会有要求,所以在JS调用方法时,将数据按照格式返回即可。
class ExampleData(models.Model):

    _name = 'example.data'

    _description = '示例数据'

    def _get_country(self):

    """

    默认为中国

    :return:

    """

        country_id = self.env['res.country'].search([('name', '=', '中国')], limit=1)

        if country_id:

            return country_id.id

    order_name = fields.Char(

    string='订单号'

    )

    country_id = fields.Many2one(

    comodel_name='res.country',

    string='国家',

    default=_get_country

    )

    state_id = fields.Many2one(

    comodel_name='res.country.state',

    string='省份',

    domain="[('country_id', '=', country_id)]"

    )

    city_id = fields.Many2one(

    comodel_name='res.city',

    string='市/县/区',

    # domain="[('state_id', '=', state_id)]"

    )

    product_id = fields.Many2one(

    comodel_name='example.product',

    string='选购产品',

    )

    product_amount = fields.Float(

    string='购买数量'

    )

    product_price = fields.Float(

    string='产品单价',

    related='product_id.price',

    store=True,

    readonly=False

    )

    purchase_date = fields.Date(

    string='采购时间'

    )

    product_total = fields.Float(

    string='购买总价',

    compute='_compute_get_total_price',

    store=True

    )

    @api.model

    def create(self, vals_list):

        name = vals_list.get('order_name')

        if not name:

            vals_list['order_name'] = self._pro_name()

        return super(ExampleData, self).create(vals_list)

    @api.depends('product_price', 'product_amount')

    def _compute_get_total_price(self):

        for rec in self:

            rec.product_total = rec.product_amount * rec.product_price

    def _pro_name(self):

    """

    生成序列号

    :return:

    """

        new_code = self.env['ir.sequence'].get('example.data')

        if new_code:

            return new_code

        else:
    
            self.env['ir.sequence'].sudo().create({

            'name': '订单记录',

            'code': 'example.data',

            'prefix': 'ED-%(year)s-%(month)s-%(day)s-',

            'padding': 3,

            'number_increment': 1,

            'number_next_actual': 1,

            'implementation': 'standard',

            'active': True,

            'company_id': False

            })

            new_code = self.env['ir.sequence'].get('example.data')

            if new_code:

                return new_code

    def get_data_list(self):

    """

    返回S2表格需要的数据

    :return:

    """

        data = []

        data_ids = self.search([])

        data_dict = {

        'fields': {

        'rows': ['country', 'province', 'order_code', 'product'],

        'columns': [],

        'values': ['product_amount', 'product_price']

        },

        'meta': [

        {

        'field': 'country',

        'name': '国家',

        },

        {

        'field': 'province',

        'name': '省份',

        },

        {

        'field': 'product',

        'name': '产品',

        },

        {

        'field': 'product_price',

        'name': '单价',

        },

        {

        'field': 'product_amount',

        'name': '数量',

        },

        {

        'field': 'order_code',

        'name': '订单号',

        },

        ],

        'data': []

        }

        for rec in data_ids:

        info = {

            'country': rec.country_id.name,

            'province': rec.state_id.name,

            'product': rec.product_id.name,

            'product_amount': rec.product_amount,

            'product_price': rec.product_price,

            'order_code': rec.order_name,

            # 'action': 'action_view_detail_form',

            # 'rec_id': rec.id

        }

        data.append(info)

        data_dict['data'] = data

        return data_dict

    def action_view_detail_form(self, order_name):

    """

    查看每条记录的form

    :return:

    """

        order_id = self.search([('order_name', '=', order_name)], limit=1)

        view_id = self.env.ref('odoo_report.example_date_form_wizard_view').id

        action = {

        'name': '查看订单',

        'type': 'ir.actions.act_window',

        'view_mode': 'form',

        'res_model': 'example.data',

        'views': [(view_id, 'form')],

        'view_id': view_id,

        'target': 'new',

        'res_id': order_id.id,

        'context': {

        'create': 0,

        'edit': 0,

        },

        }

        print(action)

        return action
  1. 编写JS,主要就是引入S2,对数据进行处理
odoo.define('example_data.s2', function (require) {

    "use strict";

    var AbstractAction = require('web.AbstractAction');

    var core = require('web.core');

    var ExampleDataS2 = AbstractAction.extend({

        # 引入Qweb模板

        template: 'ExampleDataS2',

        event: {},

        init: function (parent, action) {

        var self = this;

        this._super.apply(this, arguments);

        // 挡在单据跳转时可以获取到当前action的值

        this.params = action.params;

    },

    start: function () {

        var self = this;

        var params = this.params

        # 使用RPC获取模型中的数据

        this._rpc({

        model: 'example.data',

        method: 'get_data_list',

        args: [[]],

        }).then(function (data) {

            console.log('获取的数据', data)

            self._show_data_list(data);

        })

    },

    # 对数据进行处理

    _show_data_list: function (data) {

        var self = this;

        var container = document.getElementById('example_data_s2');

        const s2options = {

            width: 900,

            height: 450,

            interaction: {

            // 仅支持rows里面的

                linkFields: ['order_code'],

            },

        conditions: {

            text: [

                {

                    field: 'product_amount',

                    mapping(fieldValue, data) {

                        return {

                        fill: "#ffc107",

                        };

            }

          },

            {

                field: 'product_price',

                mapping(fieldValue, data) {

                    return {

                    fill: "#28a745",

                };

            }

    }

    ],

    // background: [

    // {

    // field: 'product_price',

    // mapping(fieldValue, data) {

    // if (fieldValue) {

    // return {

    // fill: "#28a745",

    // };

    // }

    // }

    // }

    // ]

    }

    };

    const s2 = new S2.PivotSheet(container, data, s2options);

    // 链接跳转

    console.log(S2.S2Event.GLOBAL_LINK_FIELD_JUMP)

    s2.on(S2.S2Event.GLOBAL_LINK_FIELD_JUMP, (a) => {

        console.log('data的值', a)

        const {key, record} = a

        const value = record['order_code']

        if (value) {

            return this._rpc({

                model: 'example.data',

                method: 'action_view_detail_form',

                args: [[], value],

        }).then(function (result) {

               self.do_action(result);

        });

        } else {

            return this.do_warn('警告', '禁止此操作')

        }

        });

        s2.render();

    }

    });

    core.action_registry.add('example.data.s2', ExampleDataS2);

})
  1. 展示模板,模板写的比较简单。
<template>

    <t t-name="ExampleDataS2">

        <div style="padding: 20px; background-color: #FFF">

            <t t-call="example_data"/>

        </div>

    </t>

    <t t-name="example_data">

        <div>

            <div id="example_data_s2" style="height: 100%; width: 100%"/>

        </div>

    </t>

</template>
  1. 引入Qweb以及S2
<template id="odoo_report.assets_end" inherit_id="web.assets_backend">

        <xpath expr="." position="inside">

            <script type="text/javascript" src="/odoo_report/static/js/s2/s2.js"/>

        </xpath>

</template>

image.png 注意:odoo的版本为14,s2文档链接s2.antv.vision/manual/intr…

S2中其实还有许多功能都比较实用的,自己可以摸索一下,若有不当之处,还望指出。