自定义odoo搜索栏

发布时间 2023-10-28 21:45:19作者: CrossPython

前言
搜索栏组件是我们经常会使用到的,且大多数时候我们会默认它存在。然而Odoo的原生searchBar似乎有些不太符合国内的使用习惯的。

我们使用Odoo Widget可以创建一个公共的组件进行组件复用,本期就先尝试封装一个公共的搜索栏组件,来看看应该如何实现吧~

本篇代码很硬核,强烈建议收藏反复观看!!

数据封装
既然想实现一个公共的搜索栏组件,搜索栏需要根据tree视图的列内容来展示搜索项,需要由接口将搜索栏的数据进行返回,这里我们模仿接口数据来直接进行封装,并可以对搜索栏数据初始化,JSON数据如下: 

 

let search_mes= [
        {
            tag: 'input',
            type: 'text',
            title: '客户名称',
            name: 'customer_name',  //作为渲染搜索项class的name唯一值
            value: 'test1',
            placeholder: '请输入'
        },
        {
            tag: 'select',
            type: 'text',
            title: '项目类型',
            name: 'project_type',
            value: '个人',
            option: [
                {text: '请选择', value: ''},
                {text: '个人', selected: 'selected', value: '1'},
                {text: '商业', value: '2'}
            ]
        },
        {
            tag: 'select',
            type: 'text',
            name: 'id_information',
            title: '证件信息',
            option: [
                {text: '请选择', value: ''},
                {text: '个人', value: '1'},
                {text: '商业', value: '2'}
            ]
        },
        {
            tag: 'select',
            type: 'text',
            title: '客户类型',
            name: 'customer_type',
            option: [
                {text: '请选择', value: ''},
                {text: '企业', value: '1'}
            ]
        },
        {
            tag: 'input',
            type: 'text',
            title: '手机号码',
            name: 'tele_phone',
            value: '14242141',
            placeholder: '请输入'
        },
        {
            tag: 'select',
            type: 'text',
            title: '会员等级',
            name: 'level_of_membership',
            option: [
                {text: '请选择', value: ''},
                {text: '个人', value: '1'},
                {text: '商业', value: '2'}
            ]
        },
        {
            tag: 'input',
            type: 'date',
            title: '入会时间',
            name: 'initiation_time',
            value: '2022-07-13'
        },
        {
            tag: 'select',
            type: 'text',
            title: '渠道',
            name: 'join_channel',
            option: [
                {text: '请选择', value: ''},
                {text: '个人', value: '1'},
                {text: '商业', value: '2'}
            ]
        },
        {
            tag: 'input',
            type: 'text',
            title: '卡号',
            name: 'membership_card_number',
            placeholder: '请输入'
        },
        {
            tag: 'select',
            type: 'text',
            title: '业务选择',
            name: 'joining_city',
            option: [
                {text: '请选择', value: ''},
                {text: '当前业主', value: '1'},
                {text: '历史业务', value: '2'},
                {text: '员工', value: '3'},
                {text: '业务VIP', value: '4'},
                {text: '其他', value: '5'}
            ]
        }
    ] 

  

 

数据渲染
创建search_widget.xml和search_widget.js,来对上述的JSON数据进行渲染,这里搜索栏的样式可以借助bootstrap的栅格布局。
代码如下:

 

<?xml version="1.0" encoding="utf-8" ?>
<template id="template" xml:space="preserve">
    <t t-name="search_tool_template">
        <t t-js="widget">
            console.log("widget", widget.widget);
        </t>
        <t t-set="input_mes" t-value="widget.searchPanel"></t>
        <div class="search_tools row" style="display: flex">
            <t t-foreach="input_mes" t-as="input_item">
                <div t-if="input_item.tag == 'input'" class="col-md-3 input_searth_style">
                    <span t-esc="input_item.title" style="width: 70px"></span>
                    <input t-att-class="input_item.name" t-att-value="input_item.value" t-att-type="input_item.type" t-att-placeholder="input_item.placeholder" style="width: 150px"/>
                </div>
                <div t-elif="input_item.tag == 'select'" class="col-md-3 input_searth_style">
                    <span t-esc="input_item.title" style="width: 70px"></span>
                    <select style="width: 150px" t-att-class="input_item.name">
                        <option t-att-value="item.value" t-esc="item.text" t-foreach="input_item.option" t-as="item" t-att-selected="item.selected"></option>
                    </select>
                </div>
            </t>
            <div>
                <button class="btn btn-primary search_btn">查询</button>
                <button class="btn btn-white remove_btn" style="margin-left: 10px">重置</button>
            </div>
        </div>
    </t>
</template> 

  

odoo.define('search_tool', function (require) {
    var Widget = require('web.Widget');
    var SearchTool = Widget.extend({
        events: _.extend({}, Widget.prototype.events, {
			//定义搜索按钮点击事件
            'click .search_btn': '_sidebarClicked',
			//定义重置按钮点击事件
			'click .remove_btn': '_removeClicked',
        }),
        template: 'search_tool_template',

        init: function (parent, searchData) {
            this._super.apply(this, arguments);
            this.searchPanel = searchData
        },

         _sidebarClicked: function (ev){
             console.log(this)
             this.__parentedParent.trigger_up('reload') //可以获取父级的model
        },


		_removeClicked:function (ev){
    		console.log('remove')
		}
    })
    return SearchTool
}) 

  

 

挂载至页面
根据上面的步骤,我们的一个搜索栏的组件就封装好了!接下来就是该如何挂载到页面上,对tree视图重写ListController.renderButtons方法。如下:

 

odoo.define('render_seacrh', function (require) {
    "use strict";
    var ListController = require('web.ListController');
	//引入search组件
    var SearchTool = require("search_tool");
    return ListController.extend({
        renderButtons: function () {
            this._super.apply(this, arguments);
            let self = this
            if (this.$buttons) {
                //这⾥找到刚才定义的按钮和输入框
                this.$buttons.find('.o_list_export_xlsx').addClass('d-none');
                this.$buttons.find(".export_excel_data").on('click', this.proxy('export_excel_data'));
                //将步骤一的JSON数据放到此处
                let search_mes= [
                        {
                            tag: 'input',
                            type: 'text',
                            title: '客户名称',
                            name: 'customer_name',
                            value: 'test1',
                            placeholder: '请输入'
                        },
                        {
                            tag: 'select',
                            type: 'text',
                            title: '是否是会员',
                            name: 'is_member',
                            value: '个人',
                            option: [
                                {text: '请选择'},
                                {text: '个人', selected: 'selected'},
                                {text: '商业'}
                            ]
                        },
                        {
                            tag: 'select',
                            type: 'text',
                            name: 'id_information',
                            title: '证件信息',
                            option: [
                                {text: '请选择'},
                                {text: '个人'},
                                {text: '商业'}
                            ]
                        },
                        {
                            tag: 'select',
                            type: 'text',
                            title: '客户类型',
                            name: 'customer_type',
                            option: [
                                {text: '请选择'},
                                {text: '企业'}
                            ]
                        },
                        {
                            tag: 'input',
                            type: 'text',
                            title: '手机号码',
                            name: 'tele_phone',
                            value: '14242141',
                            placeholder: '请输入'
                        },
                        {
                            tag: 'select',
                            type: 'text',
                            title: '会员等级',
                            name: 'level_of_membership',
                            option: [
                                {text: '请选择'},
                                {text: '个人'},
                                {text: '商业'}
                            ]
                        },
                        {
                            tag: 'input',
                            type: 'date',
                            title: '入会时间',
                            name: 'initiation_time',
                            value: '2022-07-13'
                        },
                        {
                            tag: 'select',
                            type: 'text',
                            title: '入会渠道',
                            name: 'join_channel',
                            option: [
                                {text: '请选择'},
                                {text: '个人'},
                                {text: '商业'}
                            ]
                        },
                        {
                            tag: 'input',
                            type: 'text',
                            title: '会员卡号',
                            name: 'membership_card_number',
                            placeholder: '请输入'
                        },
                        {
                            tag: 'select',
                            type: 'text',
                            title: '入会城市',
                            name: 'joining_city',
                            option: [
                                {text: '请选择'},
                                {text: '当前业主'},
                                {text: '历史业务'},
                                {text: '员工'},
                                {text: '业务VIP'},
                                {text: '其他'}
                            ]
                        }
                    ]
                // 实例化SearchTool,并挂载到this.$buttons上
                this.searchTool = new SearchTool(this,search_mes)
                this.searchTool.appendTo(this.$buttons)
            }
        },
    });
});

  

 

获取数据
在我们点击查询时也应当把搜索栏的数据内容拿出来,可以在搜索的点击事件里进行处理,在search_widget.js中扩展_sidebarClick方法和按钮重置_removeClicked方法。

 

_sidebarClicked: function (ev){
     let params = {}
	 //获取搜索栏数据
     for (let searchItem of this.searchPanel) {
            params[searchItem.name] = $('.' + searchItem.name).val()
     }
     console.log(params)
	 /** 业务逻辑 **/
}
_removeClicked:function (ev){
	//清空搜索栏数据
    for (let searchItem of this.searchPanel) {
        $('.' + searchItem.name).val('')
    }
}

  

 

最后将上述的文件引入资源项,让我们看看效果

 

 

这里主要介绍如何开发公共的Widget组件,具体的业务场景还需因人而异~