2023-07-02 10:22:02 +08:00

153 lines
5.4 KiB
JavaScript

import Spreadsheet from 'x-data-spreadsheet';
import {getData, readExcelData, transferExcelToSpreadSheet} from '../../vue-excel/src/excel';
import {renderImage, clearCache} from '../../vue-excel/src/media';
import {readOnlyInput} from '../../vue-excel/src/hack';
import {debounce} from 'lodash';
class JsExcelPreview {
container = null;
wrapper = null;
wrapperMain = null;
options = {};
requestOptions = {};
mediasSource = [];
workbookDataSource = {
_worksheets:[]
};
sheetIndex = 1;
ctx = null;
xs = null;
offset = null;
observer = null;
constructor(container, options={}, requestOptions={}) {
this.container = container;
this.options = {minColLength: 20, ...options};
this.requestOptions = requestOptions;
this.createWrapper();
this.initSpreadsheet();
this.hack();
}
createWrapper(){
this.wrapper = document.createElement('div');
this.wrapper.className = 'vue-office-excel';
this.wrapperMain = document.createElement('div');
this.wrapperMain.className = 'vue-office-excel-main';
this.wrapper.appendChild(this.wrapperMain);
this.container.appendChild(this.wrapper);
}
initSpreadsheet(){
this.xs = new Spreadsheet(this.wrapperMain, {
mode: 'read',
showToolbar: false,
showContextmenu: this.options.showContextmenu || false,
view: {
height: () => this.wrapper && this.wrapper.clientHeight || 300,
width: () => this.wrapper && this.wrapper.clientWidth || 300,
},
row: {
height: 24,
len: 100
},
col: {
len: 26,
width: 80,
indexWidth: 60,
minWidth: 60,
},
autoFocus: false
}).loadData({});
let that = this;
let swapFunc = this.xs.bottombar.swapFunc;
this.xs.bottombar.swapFunc = function (index) {
swapFunc.call(that.xs.bottombar, index);
that.sheetIndex = index + 1;
setTimeout(()=>{
that.xs.reRender();
renderImage(that.ctx, that.mediasSource,that.workbookDataSource._worksheets[that.sheetIndex], that.offset);
});
};
let clear = this.xs.sheet.editor.clear;
this.xs.sheet.editor.clear = function (...args){
clear.apply(that.xs.sheet.editor, args);
setTimeout(()=>{
renderImage(that.ctx, that.mediasSource,that.workbookDataSource._worksheets[that.sheetIndex], that.offset);
});
};
let setOffset = this.xs.sheet.editor.setOffset;
this.xs.sheet.editor.setOffset = function (...args){
setOffset.apply(that.xs.sheet.editor, args);
that.offset = args[0];
renderImage(that.ctx, that.mediasSource,that.workbookDataSource._worksheets[that.sheetIndex], that.offset);
};
const canvas = this.wrapperMain.querySelector('canvas');
this.ctx = canvas.getContext('2d');
}
renderExcel(buffer){
return readExcelData(buffer).then(workbook => {
if (!workbook._worksheets || workbook._worksheets.length === 0) {
throw new Error('未获取到数据,可能文件格式不正确或文件已损坏');
}
const {workbookData, medias, workbookSource} = transferExcelToSpreadSheet(workbook, this.options);
this.mediasSource = medias;
this.workbookDataSource = workbookSource;
this.offset = null;
this.sheetIndex = 1;
clearCache();
this.xs.loadData(workbookData);
renderImage(this.ctx, this.mediasSource,this.workbookDataSource._worksheets[this.sheetIndex], this.offset);
}).catch(e => {
this.mediasSource = [];
this.workbookDataSource = {
_worksheets:[]
};
clearCache();
this.xs.loadData({});
return Promise.reject(e);
});
}
hack(){
const observerCallback = debounce(readOnlyInput, 200).bind(this, this.wrapperMain);
this.observer = new MutationObserver(observerCallback);
const observerConfig = { attributes: true, childList: true, subtree: true };
this.observer.observe(this.wrapperMain, observerConfig);
observerCallback(this.wrapperMain);
}
setOptions(options) {
this.options = options;
}
setRequestOptions(requestOptions) {
this.requestOptions = requestOptions;
}
preview(src){
return new Promise(((resolve, reject) => {
getData(src, this.requestOptions).then((res)=>{
this.renderExcel(res).then(resolve);
}).catch(e => {
this.xs.loadData({});
reject(e);
});
}));
}
destroy(){
this.observer.disconnect();
this.container.removeChild(this.wrapper);
this.container = null;
this.wrapper = null;
this.wrapperMain = null;
this.ctx = null;
this.xs = null;
this.observer = null;
this.options = null;
this.requestOptions = null;
this.mediasSource = null;
this.workbookDataSource = null;
}
}
export function init(container, options, requestOptions){
return new JsExcelPreview(container, options, requestOptions);
}