layui在odoo12上的应用,用widget覆盖原字段视图
layui是一个前端框架,提供了许多前端的组件等,layui的详情自己官网地址:https://www.layui.com/doc/去查看
下面说一下最近用layui遇到的问题和解决方式:
问题:近期做项目时候遇到一个需要将odoo的日期字段,用一个日期范围去代替。
解决方式:layui提供了日期范围选择的组件,直接去layui官网找到相关案例,然后在本地定义组件去替换日期字段,详细如下:
1、前端视图
在字段中新增widget属性,用自定义的layui组件覆盖原xml字段视图
<field name="start_end" widget="date_range_select"/>
在模板template中新增一个模板:
<t t-name="datetime_inline">
<div class="layui-inline" style="width: 100%">
<input type="text" class="layui-input" id="datetime_inline" placeholder=" - "/>
</div>
</t>
在js文件中新增date_range_select文件,内容如下:
odoo.define("date_range_select", function (require) {
"use strict";
var AbstractField = require('web.AbstractField');
var field_registry = require('web.field_registry');
var date_range_select = AbstractField.extend({
template: 'datetime_inline',
init: function () {
this._super.apply(this, arguments);
},
start: function () {
var self = this;
setTimeout(function () {
if(self.mode==='readonly'){
self.el.innerHTML="<span>" +self.value + "</span>"
}
layui.use('laydate', function () {
var laydate = layui.laydate;
laydate.render({
elem: '#datetime_inline',
range: true,
format: 'yyyy/MM/dd',
done: function (value, date, endDate) {
self._setValue(value)
}
});
console.log('查看self', self)
})
},100);
},
});
field_registry.add('date_range_select', date_range_select);
return date_range_select
});
到这里 就定义完了一个日期选择组件
注意:form、tree视图都要加上widget
2、后端模型
容易采坑:由于刚开始后端模型中定义的start_end字段为Date类型,然而我们的前端字段已经被覆盖成了日期范围,得到的值是一个字符串,而不再是原来的耽搁日期,
所以后端模型无法 直接存储我们的日期范围这个值,所以需要将原来的Date字段,更改为Char字段去存储这个值,另外再新增start_date,end_date两个字段,
存储开始结束日期,便于之后搜索视图中使用
3、搜索视图
由于我们的日期字段被修改为日期范围,搜索的时候也是搜索一个日期范围,所以在搜索视图上也要做修改,用前端js实现过滤记录。我刚开始也想过在后端做过滤,
被否决了,原因是在后端做过滤,牵扯到当前页面已经加载完成,如果要在后端做搜索过滤就会涉及到做异步加载的问题,所以就在前端直接做过滤搜索了
1、在搜索模型中新增一个搜索模型,将对应的时间范围字段自定义一个名字为:date_range_select,
<div class="col-lg-3 col-sm-6 col-12">
<span for="date_range_select" options="{'placeholder': '时间控件选择'}"/>
</div>
2、注册我们定义的控件名字,将我们的组件指向layui定好的date类型,由于别人前期已经将date类型更改为日期范围,所以此处可以跳过一步
else if (this.field.name === 'date_range_select') {
type = 'date'
}
3、新增js文件search_pannel_extend.js 内容为:
odoo.define('search_pannel_extend', function (require) {
'use strict';
var widgetRegistry = require('web.widget_registry');
var search_pannel_default = require('layui_search_panel');
var core = require('web.core');
var proposition = require('layui_search_proposition');
var layui_search_proposition = proposition.layui_search_proposition;
var pyeval = require('web.py_utils');
var Widget = require('web.Widget');
var framework = require('web.framework');
var crash_manager = require('web.crash_manager');
var session = require('web.session');
search_pannel_default.include({
events: _.extend({}, search_pannel_default.prototype.events, {
'click .add_new': '_AddRecord',
'click .export': '_Export',
'click .import': '_Import'
}),
/**
* 新增记录
* @private
*/
_AddRecord: function (event) {
var self = this;
event.stopPropagation();
this.do_action({
name: '新增',
type: 'ir.actions.act_window',
view_type: 'form',
view_mode: 'form',
res_model: this.getParent().model_name,
views: [[false, 'form']],
flags: {mode: 'edit'},
target: 'new',
context: {'dialog_size': $(event.currentTarget).attr("dialog_size") || 'large'}
}, {
on_close: function () {
self.trigger_up('reload');
}
})
},
/**
* 导出
* @private
*/
_Export: function (event) {
var self = this;
var ids = self.get_records();
if (ids.length > 0) {
this.do_action({
'name': '导出',
'type': 'ir.actions.act_url',
'url': $(event.currentTarget).attr("url") + '?ids=' + JSON.stringify(ids),
'target': 'new',
'tfs_close': true
})
} else {
layer.msg('请勾选需要导出的行!', {icon: 2});
}
},
get_records: function () {
// 获取勾选项
var self = this;
var records = [];
var records_list = self.getParent().getParent().getSelectedRecords().map(function (record) {
records.push(record.res_id)
});
return records
},
/**
* 导入
* @private
*/
_Import: function (event) {
var self = this;
this.do_action({
name: '导入',
type: 'ir.actions.client',
tag: 'file_import',
context: {'dialog_size': 'medium', 'url': $(event.currentTarget).attr("url")},
target: 'new'
}, {
on_close: function () {
self.trigger_up('reload');
}
})
}
});
// 日期范围选择控件扩展
var date_range_select_search_pannel = search_pannel_default.extend({ events: _.extend({}, search_pannel_default.prototype.events, {
'click .report_repair': "_DateRange"
}), // 日期范围
_DateRange: function () {
var self = this;
this._rpc({
model: 'ir.model.data',
method: 'xmlid_to_res_id',
args: ['repairManageForXian.outsource_manage_project_form']
}).then(function (view_form_id) {
self.do_action({
name: '日期范围',
type: 'ir.actions.act_window',
view_type: 'form',
view_mode: 'form',
res_model: 'repair_manage.outsource_manage_project',
views: [[view_form_id, 'form']],
target: 'new'
}, {
on_close: function () {
self.trigger_up('reload');
}
})
})
}, // 读取模板,同时读取属性并构造搜索对象
renderElement: function () {
var $el;
var bHaveExt = false;
this.propositions = [];
$el = $(core.qweb.render(this.pannel_template, {widget: this}).trim());
var fields_place_holders = $el.find("[for]");
for (var i = 0; i < fields_place_holders.length; i++) {
var holder = fields_place_holders[i];
var filed_name = $(holder).attr('for');
var options = $(holder).attr('options') || "{'range': true}"; //因xml模板传过来为string类型,故此不能用Obj
options = pyeval.py_eval(options);
options.funcs = {};
var field = this.fields[filed_name];
// 如果有字段或者为聚合搜索输入框则渲染
if (field || filed_name === 'date_range_select') {
// 因原有field会被frozen冻结,所以需要复制一份调用
var copy_field = Object.assign({}, field);
// odoo12这里field没有name属性
copy_field.name = filed_name;
var prop = new layui_search_proposition(this, copy_field, options);
prop.replace(holder);
this.propositions.push(prop);
bHaveExt = true
}
}
this._replaceElement($el);
}, commit_search: function () {
var domains = [];
_.each(this.propositions, function (proposition) {
var domain = proposition.get_domain();
console.log(domain)
if (!domain) {
return
} else if (domain.length == 2){
domains.push([
['start_date', '<=', domain[1][2]],
['end_date', '>=', domain[0][2]]
])
} else {
domains.push(domain)
} });
this.trigger_up('search', {
domains: domains
});
} });
widgetRegistry.add('date_range_select_search_pannel', date_range_select_search_pannel);
return {
date_range_select_search_pannel: date_range_select_search_pannel
}
到这里 就全部结束了
layui在odoo12上的应用,用widget覆盖原字段视图的更多相关文章
- .net mvc + layui做图片上传(二)—— 使用流上传和下载图片
摘要:上篇文章写到一种上传图片的方法,其中提到那种方法的局限性,就是上传的文件只能保存在本项目目录下,在其他目录中访问不到该文件.这与浏览器的安全性机制有关,浏览器不允许用户用任意的路径访问服务器上的 ...
- .net mvc + layui做图片上传(一)
图片上传和展示是互联网应用中比较常见的一个功能,最近做的一个门户网站项目就有多个需要上传图片的功能模块.关于这部分内容,本来功能不复杂,但后面做起来却还是出现了一些波折.因为缺乏经验,对几种图片上传的 ...
- layui结合SpringMVC上传文件以及携带额外的参数上传文件
今天在使用layui的过程中,遇到了使用其上传文件的模块.自己感觉文件上传还是bootstrapfileinput插件比较好用一些,灵活方便,bootstrapfileinput使用方法参考:http ...
- .Net之Layui多图片上传
前言: 多图上传在一些特殊的需求中我们经常会遇到,其实多图上传的原理大家都有各自的见解.对于Layui多图上传和我之前所说的通过js获取文本框中的文件数组遍历提交的原理一样,只不过是Layui中的up ...
- 在选定的数据源上未找到名为“TitleSub”的字段或属
在.NET开发过程中时常会遇到“在选定的数据源上未找到名为“TitleSub”的字段或属性”的错误”,导致这类错误的原因有很多,在我的项目中,详细情况是这样:1.有两个控件:DropDownList类 ...
- layui + jfinal 实现上传下载
1.需要把jfinal的环境配置好 2.导入相关的库文件 layui的库文件 就是这两个文件需要导入到自己的页面 注意:jfinal总会把路径拦截,所以需要静态文件处理.本人不太懂.就网上找了下,说w ...
- Struts2配合layui多文件上传--下载
先说上传: 前台上传文件的js代码: var demoListView = $('#demoList') ,uploadListIns = upload.render({ elem: '#testLi ...
- php+layui实现图片上传与预览
端代码: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <titl ...
- Layui多文件上传进度条
Layui原生upload模块不支持文件上传进度条显示,百度,谷歌找了一下不太适用.后面找到一个别人修改好的JS,替换上去,修改一下页面显示即可使用,一下是部分代码 HTML: <div cla ...
随机推荐
- 【Windows10】如何使用Segoe MDL2 Assets图标
众所周知,在Windows 10中,微软引入了汉堡菜单,方便Android和ios的开发者移植程序,而不需要单独为Windows设计一套UI.但有人可能发现在symbol icon里根本找不到所谓的汉 ...
- web 基础(二) HTML5
web 基础(二) HTML5 一.HTML5 HTML5 是最新的 HTML 标准.是专门为承载丰富的 web 内容而设计的,并且无需额外插件.它拥有新的语义.图形以及多媒体元素.并提供的新元素和新 ...
- python基础之打/解包及运算符与控制流程
python基础之打/解包及运算符与控制流程 python中的解压缩(即序列类型的打包和解包) python提供了两个设计元祖和其他序列类型的处理的便利,也就是自动打包与自动解包功能,比如: data ...
- scala 数据结构(十一):流 Stream、视图 View、线程安全的集合、并行集合
1 流 Stream stream是一个集合.这个集合,可以用于存放无穷多个元素,但是这无穷个元素并不会一次性生产出来,而是需要用到多大的区间,就会动态的生产,末尾元素遵循lazy规则(即:要使用结果 ...
- 机器学习实战基础(十九):sklearn中数据集
sklearn提供的自带的数据集 sklearn 的数据集有好多个种 自带的小数据集(packaged dataset):sklearn.datasets.load_<name> 可在 ...
- 数据可视化之DAX篇(四) 熟练使用EARLIER函数,轻松获取当前行信息
https://zhuanlan.zhihu.com/p/64400583 前面利用PowerBI做数据分析的时候都是对整列的字段进行操作,并没有做更细化的分析,比如分析数据的每一行.提取某一行的数据 ...
- JVM系列-方法调用的原理
JVM系列-方法调用的原理 最近重新看了一些JVM方面的笔记和资料,收获颇丰,尤其解决了长久以来心中关于JVM方法管理的一些疑问.下面介绍一下JVM中有关方法调用的知识. 目的 方法调用,目的是选择方 ...
- 动手实现 LRU 算法,以及 Caffeine 和 Redis 中的缓存淘汰策略
我是风筝,公众号「古时的风筝」. 文章会收录在 JavaNewBee 中,更有 Java 后端知识图谱,从小白到大牛要走的路都在里面. 那天我在 LeetCode 上刷到一道 LRU 缓存机制的问题, ...
- Quartz.Net系列(十六):Misfire策略在SimpleScheduler和CronScheduler中的使用
1.场景 ①因为工作线程都在忙碌,所以导致某些Trigger得不到触发 也就是默认10个工作线程而我有15个Trigger同时触发 这就导致有5个不能被触发,而不幸的是Trigger所关联的Job执行 ...
- ES6面试
未完持续 概念 ECMAScript6(以下简称ES6)是 JavaScript 语言的下一代标准,前者是后者的规格,后者是前者的一种实现. ES6(新增的)一些特性 1.变.常量:let声明变量,c ...