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
}
到这里 就全部结束了