excel-preview.js 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. ;(function (factory) {
  2. if (typeof define === 'function' && define.amd) {
  3. define(['jquery'], factory);
  4. } else {
  5. factory(jQuery);
  6. }
  7. }(function ($) {
  8. 'use strict';
  9. // Default options
  10. const pluginName = "excelPreview";
  11. var defaults = {
  12. height: 500
  13. };
  14. // Constructor, initialise everything you need here
  15. var Plugin = function (element, options) {
  16. this.element = element;
  17. this.settings = $.extend({}, defaults, options);
  18. this._defaults = defaults;
  19. this._name = pluginName;
  20. defaults = this.settings;
  21. this.init();
  22. };
  23. // Plugin methods and shared properties
  24. Plugin.prototype = {
  25. // Reset constructor - http://goo.gl/EcWdiy
  26. constructor: Plugin,
  27. init: function () {
  28. var e = this;
  29. let input = $(e.element).prev('input[type=file]');
  30. $(e.element).prev('input[type=file]').fileinput(e.settings).on('change', function (file) {
  31. e.excelPreview(file);
  32. })
  33. },
  34. excelPreview: function (file) {
  35. var e = this;
  36. loadFile(file, e.element);
  37. $(e.element).prev('input[type=file]').fileinput('refresh');
  38. return true;
  39. }
  40. }
  41. function loadFile(event, ele) {
  42. let file = event.target.files;
  43. if(file.length == 0)return;
  44. var fileReader = new FileReader();
  45. fileReader.onload = (ev) => {
  46. try {
  47. var data = ev.target.result,
  48. workbook = XLSX.read(data, {
  49. type: 'binary',
  50. cellStyles: true
  51. }), // 以二进制流方式读取得到整份excel表格对象
  52. persons = []; // 存储获取到的数据
  53. } catch (e) {
  54. console.log('文件类型不正确');
  55. return;
  56. }
  57. //所有表名
  58. var sheetNames = workbook.SheetNames; // 返回 ['sheet1', 'sheet2']
  59. initTabs(ele, sheetNames, workbook);
  60. $(event.target).data('excel-data', getTableData(workbook.Sheets[sheetNames[0]]));
  61. $(event.target).trigger('excel-data-change');
  62. // //根据表名获取对应某张表
  63. // var worksheet = workbook.Sheets[sheetNames[0]];
  64. }
  65. fileReader.readAsBinaryString(file[0]);
  66. }
  67. function initTabs(ele, sheetNames, workbook) {
  68. $(ele).empty().append(`<div class="box box-default">
  69. <div class="excel-box">
  70. <ul class="nav nav-tabs" role="tablist">
  71. </ul>
  72. <div class="tab-content" >
  73. <div role="tabpanel" class="tab-pane active">
  74. </div>
  75. </div>
  76. </div>
  77. </div>`);
  78. sheetNames.forEach(sheet => {
  79. let tabNav = $(ele).find(".nav-tabs");
  80. let nav = $(`<li role="presentation"><a role="tab" data-toggle="tab">${sheet}</a></li>`);
  81. nav.find('a').on('click', (e) => {
  82. tabChange($(e.target), workbook, tabNav);
  83. });
  84. tabNav.append(nav);
  85. tabChange(tabNav.find(' li:first > a'), workbook, tabNav);
  86. tabNav.find("li:first").addClass('active');
  87. })
  88. }
  89. function getTableData(sheet) {
  90. const headers = [];
  91. if(Object.keys(sheet).length == 0 || !sheet['!ref']) {
  92. return {
  93. columns: [],
  94. data: []
  95. }
  96. }
  97. const range = XLSX.utils.decode_range(sheet['!ref'])
  98. let C
  99. const R = range.s.r /* start in the first row */
  100. for (C = range.s.c; C <= range.e.c; ++C) { /* walk every column in the range */
  101. var cell = sheet[XLSX.utils.encode_cell({ c: C, r: R })] /* find the cell in the first row */
  102. headers.push({
  103. field: 'column_' + C,
  104. title: 'column_' + C
  105. })
  106. }
  107. let datas = [];
  108. /* Also can use XLSX.utils.sheet_to_json(sheet, {header:1, blankRows: false}); but my dependencies blankRows not work*/
  109. for(let rowIndex = range.s.r; rowIndex <= range.e.r; ++rowIndex) {
  110. let data = {};
  111. for (let colIndex = range.s.c; colIndex <= range.e.c; ++colIndex) { /* walk every column in the range */
  112. var cell = sheet[XLSX.utils.encode_cell({ c: colIndex, r: rowIndex })]; /* find the cell in the first row */
  113. data['column_' + colIndex] = XLSX.utils.format_cell(cell);
  114. }
  115. (Object.values(data).join('').length > 0) && datas.push(data);
  116. }
  117. return {
  118. columns: headers,
  119. data: datas
  120. }
  121. }
  122. function mergeCell(merge, $table) {
  123. let rowspan = Math.abs(merge.e.r - merge.s.r + 1);
  124. let colspan = Math.abs(merge.e.c - merge.s.c + 1);
  125. $table.bootstrapTable('mergeCells', {
  126. index: merge.s.r,
  127. field: 'column_' + merge.s.c,
  128. rowspan: rowspan,
  129. colspan: colspan
  130. });
  131. }
  132. function mergeCells(worksheet, $table) {
  133. var merges = worksheet['!merges'];
  134. if (!merges) { return; }
  135. merges.forEach((merge, index) => {
  136. mergeCell(merge, $table);
  137. })
  138. }
  139. /**
  140. * key = AA2, start: A1, end = AA8, return {r: 1, c: 26}
  141. * @param {*} key
  142. * @param {*} start
  143. * @param {*} end
  144. */
  145. function getRowColIndex(key, start) {
  146. start = CUSTOM_UTIL.splitRC(start);
  147. key = CUSTOM_UTIL.splitRC(key);
  148. let col = key.c - start.c ;
  149. let row = CUSTOM_UTIL.computeR(key.r, start.r);
  150. return {
  151. r: col,
  152. c: row
  153. }
  154. }
  155. function setCellStyle(rowColIndex, style, $table) {
  156. var cellDom = $table.find("tbody").find('tr:eq(' + rowColIndex.r + ')').find('td:eq(' + rowColIndex.c + ')');
  157. if(style.font) {
  158. cellDom.css('fontWeight', style.font.bold ? 'bold' : 'normal');
  159. if(style.font.color) {
  160. style.font.color.rgb = style.font.color.rgb == 'FFFFFF' ? 'FF000000' : style.font.color.rgb;
  161. cellDom.css('color', CUSTOM_UTIL.rgbaToRgb(style.font.color.rgb));
  162. }
  163. }
  164. if (style.fill && style.fill.fgColor) {
  165. cellDom.css('backgroundColor', CUSTOM_UTIL.rgbaToRgb(style.fill.fgColor));
  166. }
  167. if (style.alignment && style.alignment.horizontal) {
  168. let alignMap = {'bottom': 'left', 'center': 'center', 'top': 'right'};
  169. cellDom.css('textAlign', alignMap[style.alignment.horizontal]);
  170. }
  171. }
  172. function setStyles(worksheet, $table) {
  173. var range = worksheet['!ref'].split(":");
  174. var start = range[0], end = range[1];
  175. for(let key in worksheet) {
  176. if(key >= start && key <= end) {
  177. var rowColIndex = getRowColIndex(key, start, end);
  178. var style = worksheet[key].s;
  179. if(!style) {return;}
  180. setCellStyle(rowColIndex, style, $table);
  181. }
  182. }
  183. }
  184. function loadTabContent(sheetName, workbook, $table) {
  185. var worksheet = workbook.Sheets[sheetName];
  186. var tableConf = {
  187. height: defaults.height,
  188. showHeader: false,
  189. classes: 'table table-bordered'
  190. };
  191. var tableData = getTableData(worksheet);
  192. $.extend(tableConf, tableData)
  193. $table.bootstrapTable(tableConf);
  194. if(Object.keys(worksheet).length > 0 && worksheet['!ref']) {
  195. setStyles(worksheet, $table);
  196. mergeCells(worksheet, $table);
  197. }
  198. }
  199. function tabChange(target, workbook, tabNav) {
  200. let sheetName = target.html();
  201. tabNav.find("li").removeClass('active');
  202. target.parent('li').addClass('active');
  203. let $table = $(`<div class="table-container"><table></table></div>`);
  204. tabNav.next('div.tab-content').find('.tab-pane').empty().append($table);
  205. loadTabContent(sheetName, workbook, $table.find('table'));
  206. }
  207. // Create the jQuery plugin
  208. $.fn[ pluginName ] = function (options) {
  209. // Do a deep copy of the options - http://goo.gl/gOSSrg
  210. options = $.extend(true, {}, defaults, options);
  211. return this.each(function () {
  212. var $this = $(this);
  213. // Create a new instance for each element in the matched jQuery set
  214. // Also save the instance so it can be accessed later to use methods/properties etc
  215. // e.g.
  216. // var instance = $('.element').data('plugin');
  217. // instance.someMethod();
  218. if ( !$.data( $this, "plugin_" + pluginName ) ) {
  219. $.data( $this, "plugin_" + pluginName, new Plugin( this, options ) );
  220. }
  221. });
  222. };
  223. // Expose defaults and Constructor (allowing overriding of prototype methods for example)
  224. $.fn[ pluginName ].defaults = defaults;
  225. $.fn[ pluginName ].Plugin = Plugin;
  226. }));