本文示例代码可查看github仓库:odoo13_file_preview

文件预览效果图展示

效果描述:

  • 1.当点击图片或者文件时展开图片。
  • 2.当点击关闭按钮时关闭图片预览。
  • 3.当点击下载按钮时,下载文件。

缺点:

  • 当预览图片大小超过1000px的时候,不会动态变小;
  • 点击查看一个文件,当点击另一个文件时,上一个文件不会自动关闭。

图片预览效果图

pdf预览效果图

文件预览实现

编写base.xml

base.xml文件用来实现文件的上传及删除操作

在static/base.xml中添加如下内容

<template>
<div t-name="PdcDocument.files" class="o_attachments" aria-atomic="true">
<!-- uploaded files -->
<t t-foreach="widget.value.data" t-as="file">
<t t-if="!file.data.upload" t-call="PdcDocument.attachment_preview"/>
</t>
<!-- uploading files -->
<t t-foreach="widget.uploadingFiles" t-as="file">
<t t-set="upload" t-value="true"/>
<t t-call="PdcDocument.attachment_preview"/>
</t>
</div> <t t-name="PdcDocument.attachment_preview">
<t t-set="url" t-value="widget.metadata[file.id] ? widget.metadata[file.id].url : false"/>
<t t-if="file.data" t-set="file" t-value="file.data"/>
<t t-set="editable" t-value="widget.mode === 'edit'"/>
<t t-if="file.mimetype" t-set="mimetype" t-value="file.mimetype"/>
<div t-attf-class="o_attachment o_attachment_many2many #{ editable ? 'o_attachment_editable' : '' } #{upload ? 'o_attachment_uploading' : ''}"
t-att-title="file.name">
<div class="o_attachment_wrap">
<t t-set="ext" t-value="file.name.replace(/^.*\./, '')"/>
<div class="o_image_box float-left" t-att-data-id="file.id">
<div t-att-title="'Download ' + file.name" aria-label="Download">
<span class="o_image o_hover" t-att-data-id="FileId" t-att-data-mimetype="mimetype"
t-att-data-ext="ext" role="img"/>
</div>
</div> <div class="caption">
<a class="ml4" t-att-href="url" t-att-title="'Download ' + file.name">
<t t-esc='file.name'/>
</a>
</div>
<div class="caption small">
<div class="ml4 small text-uppercase" t-att-title="'Download ' + file.name">
<b>
<t t-esc='ext'/>
</b>
</div>
<div t-if="editable" class="progress o_attachment_progress_bar">
<div class="progress-bar progress-bar-striped active" style="width: 100%">Uploading</div>
</div>
</div> <div t-if="editable" class="o_attachment_uploaded">
<i class="text-success fa fa-check" role="img" aria-label="Uploaded" title="Uploaded"/>
</div>
<div t-if="editable" class="o_attachment_delete" t-att-data-id="file.id">
<span class="text-white" role="img" aria-label="Delete" title="Delete">×</span>
</div>
</div>
</div>
</t>
</template>

base.xml

编写js文件

js文件用来对数据进行处理

static/js/file_preview.js

odoo.define("Upload_skim_pdf", function (require) {
"use strict";
var AbstractField = require("web.AbstractField");
var field_registry = require("web.field_registry");
var core = require('web.core'); var qweb = core.qweb;
var Upload_skim_pdf = AbstractField.extend({
template: "FieldBinaryFileUploader",
template_files: "PdcDocument.files",
supportedFieldTypes: ['many2many'],
fieldsToFetch: {
name: { type: 'char' },
mimetype: { type: 'char' },
},
events: {
'click .o_attach': '_onAttach',
'click .o_attachment_delete': '_onDelete',
'change .o_input_file': '_onFileChanged',
'click .o_image_box': '_onFilePDF',
'click .pdc_close' : '_onclosePDF',
},
/**
* @constructor
*/
init: function () {
this._super.apply(this, arguments); if (this.field.type !== 'many2many' || this.field.relation !== 'ir.attachment') {
var msg = _t("The type of the field '%s' must be a many2many field with a relation to 'ir.attachment' model.");
throw _.str.sprintf(msg, this.field.string);
} this.uploadedFiles = {};
this.uploadingFiles = [];
this.fileupload_id = _.uniqueId('oe_fileupload_temp');
$(window).on(this.fileupload_id, this._onFileLoaded.bind(this)); this.metadata = {};
},
destroy: function () {
this._super();
$(window).off(this.fileupload_id);
}, //--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
_getFileId: function (attachment) {
return attachment.id
},
_getId: function (attachment) {
return attachment.attributes[1].value
},
_generatedMetadata: function () {
var self = this;
_.each(this.value.data, function (record) {
// tagging `allowUnlink` ascertains if the attachment was user
// uploaded or was an existing or system generated attachment
self.metadata[record.id] = {
allowUnlink: self.uploadedFiles[record.data.id] || false,
FileId: self._getFileId(record.data)
};
});
},
_render: function () {
// render the attachments ; as the attachments will changes after each
// _setValue, we put the rendering here to ensure they will be updated
console.log("test123");
this._generatedMetadata();
this.$('.oe_placeholder_files, .o_attachments')
.replaceWith($(qweb.render(this.template_files, {
widget: this,
})));
this.$('.oe_fileupload').show(); // display image thumbnail
this.$('.o_image[data-mimetype^="image"]').each(function () {
var $img = $(this);
if (/gif|jpe|jpg|png/.test($img.data('mimetype')) && $img.data('src')) {
$img.css('background-image', "url('" + $img.data('src') + "')");
}
});
},
_onAttach: function () {
// This widget uses a hidden form to upload files. Clicking on 'Attach'
// will simulate a click on the related input.
this.$('.o_input_file').click();
},
_onclosePDF: function () {
console.log(this.$el.find('.zPDF_iframe').remove());
console.log('111111');
},
_onDelete: function (ev) {
ev.preventDefault();
ev.stopPropagation(); var fileID = $(ev.currentTarget).data('id');
var record = _.findWhere(this.value.data, { res_id: fileID });
if (record) {
this._setValue({
operation: 'FORGET',
ids: [record.id],
});
var metadata = this.metadata[record.id];
if (!metadata || metadata.allowUnlink) {
this._rpc({
model: 'ir.attachment',
method: 'unlink',
args: [record.res_id],
});
}
}
},
_onFileChanged: function (ev) {
var self = this;
ev.stopPropagation(); var files = ev.target.files;
var attachment_ids = this.value.res_ids; // Don't create an attachment if the upload window is cancelled.
if (files.length === 0)
return; _.each(files, function (file) {
var record = _.find(self.value.data, function (attachment) {
return attachment.data.name === file.name;
});
if (record) {
var metadata = self.metadata[record.id];
if (!metadata || metadata.allowUnlink) {
// there is a existing attachment with the same name so we
// replace it
attachment_ids = _.without(attachment_ids, record.res_id);
self._rpc({
model: 'ir.attachment',
method: 'unlink',
args: [record.res_id],
});
}
}
self.uploadingFiles.push(file);
}); this._setValue({
operation: 'REPLACE_WITH',
ids: attachment_ids,
}); this.$('form.o_form_binary_form').submit();
this.$('.oe_fileupload').hide();
ev.target.value = "";
},
_onFileLoaded: function () {
var self = this;
// the first argument isn't a file but the jQuery.Event
var files = Array.prototype.slice.call(arguments, 1);
// files has been uploaded, clear uploading
this.uploadingFiles = []; var attachment_ids = this.value.res_ids;
_.each(files, function (file) {
if (file.error) {
self.do_warn(_t('Uploading Error'), file.error);
} else {
attachment_ids.push(file.id);
self.uploadedFiles[file.id] = true;
}
}); this._setValue({
operation: 'REPLACE_WITH',
ids: attachment_ids,
});
},
_onFilePDF: function (ev) {
var self = this;
var fieldId = self._getId(ev.currentTarget);
self.$el.append(`
<div class="zPDF_iframe">
<div class="pdc_close btn btn-primary">关闭</div>&nbsp;&nbsp;&nbsp;
<div class="btn btn-primary"><a href="/web/content/${fieldId}?download=true" style="text-decoration: none; color: white">下载</a></div><br>
<iframe class="zPDF" scrolling="no" id="main" name="main" frameborder="0" style="min-height:600px;width:1000px;height:100%;" src="/web/content/${fieldId}"></iframe>
</div>
`)
}
}); field_registry.add("Upload_skim_pdf", Upload_skim_pdf);
return Upload_skim_pdf
});

file_preview.js

引入js文件

在views/import_js.xml文件中添加如下内容

<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="assets_backend" name="file_preview_tpl" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script src="/file_preview/static/js/file_preview.js" />
</xpath>
</template>
</odoo>

同时,记得在__mainfest__.py文件中引入上述文件

    'data': [
'views/import_src.xml',
],
'qweb': [
"static/base.xml"
],

至此,即可在odoo中完成一个自定义widget,接下来只要使用定义的widget即可。

文件预览widget的使用

在form视图中使用widget示例代码

<record id="file_preview_view_form" model="ir.ui.view">
<field name="name">file.preview.form</field>
<field name="model">file.preview</field>
<field name="arch" type="xml">
<form string="文件预览">
<sheet>
<group>
<field name="name"/>
</group>
<notebook>
<page string="图片">
<field name="img_ids" widget="Upload_skim_pdf" />
</page>
<page string="附件">
<field name="attachment_ids" widget="Upload_skim_pdf" />
</page>
</notebook>
</sheet>
</form>
</field>
</record>

odoo13之文件预览widget/模块的更多相关文章

  1. java实现office文件预览

    不知觉就过了这个久了,继上篇java实现文件上传下载后,今天给大家分享一篇java实现的对office文件预览功能. 相信大家在平常的项目中会遇到需要对文件实现预览功能,这里不用下载节省很多事.大家请 ...

  2. Qt SD卡 文件系统挂载、文件预览

    /********************************************************************************** * Qt SD卡 文件系统挂载. ...

  3. Jquery.Treeview+Jquery UI制作Web文件预览

    效果图: 前台Html: <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="D ...

  4. Vue PDF文件预览vue-pdf

       最近做项目,遇到预览PDF这个功能,在网上找了找,大多推荐的是pdf.js,不过在Vue中还是想偷懒直接npm组件,最后找到了一个还不错的Vue-pdf 组件,GitHub地址:https:// ...

  5. 关于pc端 app端pdf,word xls等文件预览的功能

    第一种用H5标签<iframe>标签实现 返回的文件类型,文件流,文件流返回必须在设置 contentType对应的Mime Type, 返回文件的物理位置. 已经实测可以支持的文件类型 ...

  6. 手把手教你用 Spring Boot搭建一个在线文件预览系统!支持ppt、doc等多种类型文件预览

    昨晚搭建环境都花了好一会时间,主要在浪费在了安装 openoffice 这个依赖环境上(Mac 需要手动安装). 然后,又一步一步功能演示,记录,调试项目,并且简单研究了一下核心代码之后才把这篇文章写 ...

  7. java 文件转成pdf文件 预览

    一.前端代码 //预览功能 preview: function () { //判断选中状态 var ids =""; var num = 0; $(".checkbox& ...

  8. COS控制台进阶 - 文件预览和在线编辑

    导语 | COS控制台新上线了文件预览功能,用户可在控制台内直接预览.编辑文件内容. 前不久,微软发布了 vscode for web 的公告,是基于web的在线代码编辑器,无需下载安装可以直接在we ...

  9. 利用tornado实现表格文件预览

    项目介绍   本文将介绍笔者的一个项目,主要是利用tornado实现表格文件的预览,能够浏览的表格文件支持CSV以及Excel文件.预览的界面如下:   下面我们将看到这个功能是如何通过tornado ...

随机推荐

  1. pandas | 使用pandas进行数据处理——DataFrame篇

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是pandas数据处理专题的第二篇文章,我们一起来聊聊pandas当中最重要的数据结构--DataFrame. 上一篇文章当中我们介绍了 ...

  2. day38 作业

    实现并发的里两种方式 # 第一种 from multiprocessing import Process import time class MyProcess(Process): def run(s ...

  3. python实现二维码、条形码识别

    环境: python 3.7 Win7 依赖包安装: pip install pillow pip install opencv-python pip install opencv-contrib-p ...

  4. 使用Python进行XML解析

    XML 指可扩展标记语言(eXtensible Markup Language),常被设计用来传输和存储数据. 在进行医学图像标注时,我们常使用XML格式文件来存储标注,以下展示了使用Python来提 ...

  5. python 网络爬虫报错“UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8b in position”解决方案

    Python3.x爬虫, 发现报错“UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8b in position 1:invalid sta ...

  6. nginx一个端口配置多个不同服务映射

    upstream tomcat_server{ server 127.0.0.1:8087; server 192.168.149.117:8088; } server { listen 8088; ...

  7. Vuex里的module选项和移动端布局

    Vuex里的modules 在store文件夹里创建一个modules的文件夹,里面随意创建一个.js文件,然后export输出

  8. [日常摘要] -- 阻塞IO与非阻塞IO篇

    NIO操作过程 非阻塞读/写操作 读-- 从通道读取数据到buffer,同时可以继续做别的事情,但数据都到buffer之后,线程再继续处理数据 写-- 一个线程请求写入一些数据到某通道,但不需要等待它 ...

  9. 网络流(EK算法)

    poj1273 #include <iostream> #include <cstdio> #include <cstring> #include <queu ...

  10. 跟老刘学运维day02~新手必须掌握的Linux命令(2)

    第2章 Linux命令 1.Shell 计算机硬件:由运算器.控制器.存储器.输入/输出设备等共同组成 Shell:人与硬件的翻译官,人要想使用硬件,需要服务程序 Bash四大好处: (1)通过上下方 ...