随着Odoo在各个行业领域的深入应用,对Odoo的前端交互体验要求也越来越高。
我们在项目开发中常常会遇到,需要上传文件并预览的问题。
这里是我遇到的需求,并完成的一个小demo。
在Odoo中实现文件上传
首先我们需要在qweb页面中加入上传的xml
<div style="width: 1200px; margin-top:10px;margin-right: 52px; display: flex; height: 28px; line-height: 28px">
<!-- 展示已选文件的位置-->
<span style="width:70px;font-weight:bold;">附件 </span>
<div class="uploader_file_box">
</div>
<!-- 上传部分-->
<div class="uploader_input">
<label class="fa fa-plus btn btn-white-up" style="font-weight:bold;" for="fileinput"> 选择上传附件</label>
<input id="fileinput" class="uploader-file-input" type="file" multiple="multiple" value="Select Files"></input>
</div>
</div>
# css部分
/*上传文件按钮*/
.uploader_input{
width: 120px;
}
.uploader-file-input{
display: none;
}
/*上传文件展示位置*/
.uploader_file_box{
display: flex;
}
.uploader__file-list__item{
padding:0 1rem;
display: flex;
background-color: #dfdfdf;
margin-right: 10px;
}
.btn-white-up{
background-color: #fff;
border: 1px dashed #cccccc ;
}
.uploader__file-list__text{
max-width: 100px;
padding-right: 10px;
display: inline-block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.uploader__file-list__text:hover{
color: #478aee;
}
.js-upload-remove-button{
cursor: pointer;
在完成css部分后,我们在项目的页面上会得到一个这样的上传组件 ⬇
# js部分上传的事件及监听
点击选择上传附件后,会调用默认的input的上传功能,并给输入框监听change事件,拿到上传的文件。
this.$buttons.find('#fileinput').on('change', this.proxy("selectFile")) //读取上传的文件
# 开始上传文件start
//当前页面全局定义的
var fileOption={
fileTypeWhiteList: [ 'ppt','pptx', 'xls','xlsx','pdf','doc','docx'],//校验的格式
}
var fileState = {
fileBatch:[],
fileListIndex:0
}
var upfilelength=0;
//文件上传 start
// 获取文件
selectFile:function (e){
e.preventDefault();
e.stopPropagation();
//这里可以加一个校验
var files = e.target.files || e.dataTransfer.files || e.dataTransfer.getData;
for (var i = 0; i < files.length; i++) {
Self.addfile(files[i]);
}
},
//上传文件
addfile:function (file){
let self = this;
var fileSize = file.size;
//判断文件大小
if( parseInt(fileSize/1024/1024)>=20){
this.displayNotification({
title: "系统提示",
message: '单个文件上传不能超过20MB',
type: 'danger',
sticky: false
});
return
}
var upfiles = file;
if (fileOption.fileTypeWhiteList.indexOf((this.getExtension(file.name)).toLowerCase()) !== -1) {
framework.blockUI()//调用loading....
//调用接口并在上次完成后调用查询接口查询到上传了的文件
self.getUpdataList();
})
} else {
// 不在提示文件不可上传
let mesg = '不支持该格式的文件,请上传以下格式的文件ppt,pptx,xls,xlsx,pdf,doc,docx;'
Self.displayNotification({
title: "系统提示",
message: mesg,
type: 'danger',
sticky: false
});
return
}
},
//反显上传的数据
//我这里是调用接口去查询上传后的数据
getUpdataList:function (){
let self = this;
//先清除后加
$('#fileinput').val('');
$('.uploader_file_box').children().remove();
this._rpc({
route: 'xxxxxxx',
params:{
xxxx:xxxxx,
}
}).then(res=>{
var upfileList = res.data;
if(upfileList.length>0){
approveFileFlag = false;
upfilelength = upfileList.length;
for (let i = 0; i <upfileList.length; i++) {
let fileItem = upfileList[i];
self.files_show(fileItem)
}
}else{
approveFileFlag = true;
$('.uploader_file_box').children().remove();
}
console.log(res,'已上传的文件')
})
},
//页面渲染上传的文件展示js创建以上传的文件
files_show:function (file){
var fileName = file.name;
var fileId = file.id;
var filesdow = file.local_url
var fileNameWrapper = $('<span class="uploader__file-list__text" title="'+fileName+'">'+ '<a href="'+filesdow+'" download="'+fileName+'" target="view_window">'+fileName+'</a>' +'</span>');//文件名称
fileState.fileListIndex++;
//创建一个放入的
var listItem = $('<li class="uploader__file-list__item" data-index="' + fileId + '"></li>');//文件展示的每一条的盒子
var removeLink = $('<span class="uploader__file-list__button"><i class=" js-upload-remove-button fa fa-close" data-index="' + fileId + '"></i></span>');
fileState.fileBatch.push({filesdow: filesdow, id: fileId, fileName: fileName,});//保存文件
//校验是否需要删除,校验部分,根据自己的需求,自己去调整
if(quot_status==0&&(!approve_type)){
listItem.append(fileNameWrapper).append(removeLink);
}else {
listItem.append(fileNameWrapper);
}
$('.uploader_file_box').append(listItem);
this.bindEvents();
},
//挂载事件的方法因为解决查询多次已上传文件时删除文件事件的触发问题
bindEvents:function (){
//先集体移然后集体添加
$('.js-upload-remove-button').unbind("click");
//在集体添加事件
$('.js-upload-remove-button').on('click',this.removeItemHandler);
},
//删除已上传的文件,待确认
removeItemHandler:function (e){
let self = this;
e.preventDefault();
var removeIndex = $(e.target).data('index');
Dialog.confirm(self, '确定删除?', {
title: '提示',
confirm_callback: function () {
Self.removeItem(removeIndex);
$(e.target).parent().parent().remove();
},
})
},
//删除上传的数据
removeItem(id){
let self = this;
let removId = id;
this._rpc({
route: '/xxxx/xxxxdel',
params:{
xxxid:xxxx
}
}).then(res=>{
self.displayNotification({
title: "系统提示",
message: res['msg'],
type: 'success',
sticky: false
});
self.getUpdataList();//删了后要查询并反显数据
})
//这部分是做多数据一次上传需要我这边没用到
for (var i = 0; i < fileState.fileBatch.length; i++) {
if (fileState.fileBatch[i].id === parseInt(id)) {
fileState.fileBatch.splice(i, 1);
break;
}
}
},
//规则校验
getExtension:function(path){
var basename = path.split(/[\\/]/).pop();
var pos = basename.lastIndexOf('.');
if (basename === '' || pos < 1) {
return '';
}
return basename.slice(pos + 1);
},
//文件上传end
完成文件上传后,接下来就是重头部分——文件的预览。
文件预览分为两种情况,在Odoo中,其实PDF的文件是可以直接预览的,而Excel、Word、txt等文件格式则不行,那么如何解决这个问题呢?
在Odoo中实现不同文件预览
# 引入对应的js组件
预览文件,需要使用到外部的js相关组件库:
https://officetohtml.js.org/ 组件方案来源
能够开源的,目前只支持docx和xlsx等相关原生Office的预览功能,我们可以去官网的GitHub 上下载。
在这里,我们需要在引入文件的地方引入对应的js部分 ⬇
<!--PDF-->
<link rel="stylesheet" href="/quotation/static/src/js/include/pdf/pdf.viewer.css"/>
<script src="/quotation/static/src/js/include/pdf/pdf.js"></script>
<!--Docs-->
<script src="/quotation/static/src/js/include/docx/jszip-utils.js"></script>
<script src="/quotation/static/src/js/include/docx/mammoth.browser.min.js"></script>
<!--All Spreadsheet -->
<link rel="stylesheet" href="/quotation/static/src/js/include/SheetJS/handsontable.full.min.css"/>
<script type="text/javascript" src="/quotation/static/src/js/include/SheetJS/handsontable.full.min.js"></script>
<script type="text/javascript" src="/quotation/static/src/js/include/SheetJS/xlsx.full.min.js"></script>
<!--Image viewer-->
<link rel="stylesheet" href="/quotation/static/src/js/include/verySimpleImageViewer/css/jquery.verySimpleImageViewer.css"/>
<script type="text/javascript" src="/quotation/static/src/js/include/verySimpleImageViewer/js/jquery.verySimpleImageViewer.js"></script>
<!-- officeToHtml-->
<script src="/quotationmail.DocumentViewer/static/src/js/include/officeToHtml/officeToHtml.js"></script>
<link rel="stylesheet" href="/quotation/static/src/js/include/officeToHtml/officeToHtml.css"/>
对应的文件直接放到对应的js文件目录下即可。
需要注意的是,这个步骤需要在上面执行上传的js的前面进行置入,接下来就是点击文件后预览文件了。
# PDF、txt等文件预览的样式
这里预览的盒子css的样式就不写了,因为根据每个人的情况不同,所需的预览方式也不同。
下面分享的样式,修改了上面盒子点击事件后的js部分代码,因为我需要的是下载文件,用户在本地预览,所以增加的是a标签。
在实际应用中,可以去掉改写方法。
//挂载事件的方法
bindEvents:function (){
//先集体移然后集体添加
$('.js-upload-remove-button').unbind("click");
//在集体添加事件
$('.js-upload-remove-button').on('click',this.removeItemHandler);
//添加文件的点击事件
$('.uploader__file-list__text').unbind("click");
$('.uploader__file-list__text').on('click',this.previewsShow)
},
// 预览
previewsShow:function (){
// 点击时先获取是那个文件,并找到对应文件的url地址,
var file_path = "path/to/file.pptx";
// 先清除
$('.body').remove('#resolte-contaniner')
//在添加,或者可以先写到上面的xml中这样就不需要创建
let previewbox = `<div id="resolte-contaniner"></div>`
$('.body').append(previewbox);
//读取远程文件对象时
//可以预设不同文件的不同清空的预设
$("#resolte-contaniner").officeToHtml({
url: file_path,
inputObjId: "select_file",
pdfSetting: {
setLang: "he",
thumbnailViewBtn: true,
searchBtn: true,
nextPreviousBtn: true,
pageNumberTxt: true,
totalPagesLabel: true,
zoomBtns: true,
scaleSelector: true,
presantationModeBtn: true,
openFileBtn: true,
printBtn: true,
downloadBtn: true,
bookmarkBtn: true,
secondaryToolbarBtn: true,
firstPageBtn: true,
lastPageBtn: true,
pageRotateCwBtn: true,
pageRotateCcwBtn: true,
cursorSelectTextToolbarBtn: true,
cursorHandToolbarBtn: true
}
});
},
如:Execl预览后,图片如下⬇
PDF 不做颜色,不用这个,只用原生的就可以了。
txt 的文件内容获取方式是在文件的file里。
然后通过reader.readAsText(file)就可以读取到txt的内容。同时,我们要对文件进行校验格式,以免用户上传时,文件格式的问题引发其他错误。
当然在这里,我们也可以在这个文件中,扩展或者改写文件触发的一些机制来实现不同的需求 ⬇
以上就是关于在Odoo上实现文件预览,单纯的前端解决方案,欢迎各位提出更好的解决方案!
本期作者:神州数码云基地 沈童