扫码阅读
手机扫码阅读

Odoo | 硬核组件开发!全文没一句废话!

250 2023-09-07


Odoo

神州数码云基地

在 Odoo 上的尝试、调研与分享


本期内容

Widget组件开发

搜索栏组件是我们经常会使用到的,且大多数时候我们会默认它存在。然而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.xmlsearch_widget.js

并对上述的JSON数据进行渲染,这里搜索栏的样式可以借助bootstrap的栅格布局。

代码如下:

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

具体业务场景还需因人而异~

有更好的办法或疑问请

⬇欢迎加入社群一起讨论哦⬇


本期作者

前端开发工程师 丁涛


原文链接: http://mp.weixin.qq.com/s?__biz=Mzg5MzUyOTgwMQ==&mid=2247508142&idx=1&sn=51321db785d4feaca1ed4551748939af&chksm=c02f9b08f758121e20aeb3e0aba91d0b2069d62e2c3f66bf731ee5c09c496933eb4c7ae9687f#rd