/* * HTML内容生成docx文档(基于:https://github.com/evidenceprime/html-docx-js) * 江鸿宾(QQ33080907) * 最近修改:2020.12.28 * 本插件只用于作者参与的项目,未经许可请勿转载 */ /* global htmlDocx, saveAs, canvg */ (function ($) { $.fn.html2docx = function (filename) { if ($(this).length) { filename = filename || $('title').text() || '未命名' var ImageMaxWidth = 620 var imgscount = 0 var markup = null var $this = $(this).first() var svgs = $this.find('svg') if (typeof layer !== 'undefined') { layer.msg('正在生成,请稍候...', { icon: 16, time: 0, shade: [0.1, '#000'] }) } else if (typeof AMUI === 'object') { $('#btn-word').prop('disabled', true).find('i').attr('class', 'am-icon-circle-o-notch am-icon-spin') } else { $('#btn-word').prop('disabled', true).data('value', $('#btn-word').val()).val('请稍候...') } // 装载基础脚本 var deferreds = [] if (typeof saveAs === 'undefined') { deferreds.push($.ajax('/Scripts/FileSaver.min.js', { dataType: 'script', cache: true })) } if (typeof htmlDocx === 'undefined') { deferreds.push($.ajax('/Scripts/html-docx.js', { dataType: 'script', cache: true })) } if (svgs.length && typeof canvg === 'undefined') { deferreds.push($.ajax('/Scripts/canvg/umd.js', { dataType: 'script', cache: true })) } $.when.apply(null, deferreds).done(makedocx0) } return this // 处理svg元素,由于异步所以分离 function makedocx0() { if (svgs.length) { var deferreds = [] svgs.each(function () { var svg = $(this) var w = Math.min(svg.width(), ImageMaxWidth) var h = svg.height() * (w / svg.width()) var canvas = document.createElement('canvas') var ctx = canvas.getContext('2d') deferreds.push( canvg.Canvg.from(ctx, svg.prop('outerHTML')).then(function (v) { v.resize(w, h) v.render().then(function () { var url = canvas.toDataURL('image/png') svg.closest('div.chart').replaceWith('') canvas.remove() }) }) ) }) $.when.apply(null, deferreds).done(makedocx1) } else { makedocx1() } } // 生成docx:处理 function makedocx1() { // 克隆 markup = $this.clone() // 移除某些节点 markup.find('iframe,embed,style,input[type="hidden"],.no-word').remove() // 清除:注释、回车、标签之间的空格 var tag = markup.prop('tagName').toLowerCase() var html = markup.html().replace(//g, '').replace(//g, '').replace(/\n/g, '').replace(/>\s+<') markup = $('<' + tag + '>' + html + '') // 处理图片 var imgs = markup.find('img') imgscount = imgs.length if (imgscount === 0) { makedocx2() } else { var canvas = document.createElement('canvas') var ctx = canvas.getContext('2d') imgs.each(function () { var $img = $(this) var src = $img.attr('src') // 原来的对应图片 var img = $this.find('img[src="' + src + '"]').get(0) // 已经是base64编码的图片不再处理 if (src.indexOf('data:') === 0) { makedocx2() } else if (img) { var w = Math.min(img.width, ImageMaxWidth) if (w <= 16) { // 小于等于16的图片不处理 $img.remove() makedocx2() } else { var h = img.height * (w / img.width) var a = document.createElement('a') var dataURL = '' a.href = src // 同源 if (a.host === window.location.host) { ctx.clearRect(0, 0, canvas.width, canvas.height) canvas.width = w canvas.height = h ctx.drawImage(img, 0, 0, w, h) dataURL = canvas.toDataURL() $img.attr('src', dataURL).removeAttr('width') makedocx2() } else { // 外站 // 获取base64 var url = 'https://api.psy.com.cn/request/?url=' + src + '&dataurl=1' $.ajax({ url: url, success: function (dataURL) { $img.attr('src', dataURL).attr('width', w).attr('height', h) makedocx2() }, error: function () { $img.remove() makedocx2() } }) } a.remove() } } else { // 图片没有加载到的不处理 $img.remove() makedocx2() } }) canvas.remove() } } // 生成docx:生成 function makedocx2() { if (imgscount > 1) { imgscount-- } else { // 处理Echarts markup.find('div.chart[_echarts_instance_]').has('canvas,svg').each(function () { var id = $(this).attr('id') var $old = $this.find('#' + id) var option = $old.data('option') var theme = $old.data('theme') var width = $old.width() var height = $old.height() // 克隆的Echarts与已有的冲突,所以新建DOM,重新绘制 if (option) { if (typeof (option) === 'string') { option = JSON.parse(option) } // epqa量表象限图宽度固定 var $new = $('
') var dom = $new.get(0) $.extend(true, option, { animation: false, toolbox: { show: false }, tooltip: { show: false, trigger: 'none' } }) $(this).after($new) var mychart = echarts.init(dom, theme) mychart.setOption(option) var src = mychart.getDataURL({ backgroundColor: '#fff', excludeComponents: ['toolbox', 'tooltip'] }) $new.replaceWith('
') mychart.dispose() } $(this).remove() }) // 处理样式 markup.find('h1').css({ 'text-align': 'center' }) markup.find('h1 p').css({ 'text-indent': 0 }) markup.find('p').css({ 'text-indent': '2em' }) markup.find('table').css({ 'border-collapse': 'collapse', 'width': '100%' }).removeAttr('class') markup.find('th').css({ 'border': '1px solid #000', 'text-align': 'center', 'background-color': '#e8e8e8' }) markup.find('td').css({ 'border': '1px solid #000', 'text-align': 'center' }) markup.find('.am-text-primary').css({ 'color': '#5085FF' }).removeClass('am-text-primary') markup.find('.text-left,.am-text-left').css({ 'text-align': 'left' }).removeClass('text-left am-text-left') markup.find('.text-center,.am-text-center').css({ 'text-align': 'center' }).removeClass('text-center am-text-center') markup.find('.text-right,.am-text-right').css({ 'text-align': 'right' }).removeClass('text-right am-text-right') markup.find('.text-top').css({ 'vertical-align': 'top' }).removeClass('text-top') markup.find('[class=""]').removeAttr('class') markup.find('[contenteditable]').removeAttr('contenteditable') // 再次移除某些节点 markup.find('script').remove() // console.log(markup.html()) var content = '' + markup.html() + '' var converted = htmlDocx.asBlob(content) markup.remove() if (typeof layer !== 'undefined') { layer.closeAll() } else if (typeof AMUI === 'object') { $('#btn-word').prop('disabled', false).find('i').attr('class', 'am-icon-file-word-o') } else { $('#btn-word').prop('disabled', false).val($('#btn-word').data('value')) } saveAs(converted, filename + '.docx') } } } })(jQuery)