123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- class ExportExcel {
- workBook = null;
- sheet = null;
- border = new GC.Spread.Sheets.LineBorder('#000', GC.Spread.Sheets.LineStyle.thin);
- excelIo = new GC.Spread.Excel.IO();
- $info = $('#excel-info');
- // 表格当前画到的行
- curRow = 0;
- billTree = null;
- curBillNode = null;
- libID = '';
- // 表格块,类型为ExcelBlock实例
- blocks = [];
- // 清单ID - 清单精灵映射
- billIDElfMap = {};
- // 叶子清单ID
- leafIDs = [];
- // 叶子清单总数量
- total = 0;
- constructor(workBook, billTree, libID) {
- this.workBook = workBook;
- this.sheet = this.workBook.getSheet(0);
- this.initSheet();
- this.billTree = billTree;
- this.libID = libID;
- this.leafIDs = billTree.items.filter(node => !node.children.length).map(node => node.data.ID);
- this.total = this.leafIDs.length;
- }
- // 导出
- async export() {
- if (!this.workBook) {
- return;
- }
- const json = this.workBook.toJSON();
- this.excelIo.save(json, function (blob) {
- saveAs(blob, '清单精灵排版.xlsx');
- }, function (e) {
- // process error
- alert(e);
- console.log(e);
- });
- }
- // 将数据画在表格上
- async paintOnSheet() {
- this.updateProcessInfo();
- // let i = 0;
- this.sheet.suspendPaint();
- this.sheet.suspendEvent();
- for (const billNode of this.billTree.items) {
- // 画标题
- if (this.curRow >= this.sheet.getRowCount()) {
- this.sheet.addRows(this.curRow, 2);
- }
- this.sheet.setFormatter(this.curRow, 0, '@');
- this.sheet.setFormatter(this.curRow, 1, '@');
- this.sheet.setText(this.curRow, 0, billNode.data.code);
- this.sheet.setText(this.curRow++, 1, billNode.data.name);
- // 画表格
- if (!billNode.children.length) {
- this.curRow++; // 空行
- const elfTree = await this.getElfTree(billNode.data.ID);
- if (!elfTree) {
- continue;
- }
- const block = this.getBlock(elfTree);
- if (!block.length) {
- continue;
- }
- const blockRange = this.getBlockRange(elfTree);
- this.checkRange(blockRange);
- const range = this.sheet.getRange(block[0].row + this.curRow, block[0].col, blockRange.rowCount, blockRange.colCount)
- // 画单元格
- console.log(billNode.data);
- console.log(block);
- this.drawCell(block);
- // 画边框
- this.drawBorder(range)
- // i++;
- this.curRow += blockRange.rowCount + 1;
- }
- /* if (i === 100) {
- break;
- } */
- }
- const range = this.sheet.getRange(0, 0, this.sheet.getRowCount(), this.sheet.getColumnCount());
- range.vAlign(GC.Spread.Sheets.VerticalAlign.center);
- range.wordWrap(true);
- this.sheet.resumeEvent();
- this.sheet.resumePaint();
- if (this.total === this.curProcessCount) {
- this.afterPaint();
- }
- }
- /* ========================================================以下为私有方法============================================== */
- // 当前到多少条叶子清单
- get curProcessCount () {
- return this.total - this.leafIDs.length;
- }
- // 画完表格后的处理
- afterPaint() {
- $('#excel-dialog').width('800px');
- $('#excel-spread').show();
- this.workBook.refresh();
- $('#export-excel-confirm').show();
- }
- // 超出范围追加行列
- checkRange(blockRange) {
- // 不够行数,追加行数
- const needRows = this.curRow + blockRange.rowCount;
- const curRowCount = this.sheet.getRowCount();
- if (curRowCount < needRows) {
- this.sheet.addRows(this.curRow, needRows - curRowCount + 5);
- }
- // 不够列数,追加列数
- const curColCount = this.sheet.getColumnCount();
- if (curColCount < blockRange.colCount) {
- this.sheet.addColumns(curColCount - 1, blockRange.colCount - curColCount);
- }
- }
- // 画单元格、合并单元格
- drawCell(block) {
- block.forEach(item => {
- const row = item.row + this.curRow;
- this.sheet.addSpan(row, item.col, item.rowCount, item.colCount);
- this.sheet.setFormatter(row, item.col, '@');
- this.sheet.setText(row, item.col, item.text);
- });
- }
- // 画边框
- drawBorder(range) {
- range.setBorder(this.border, { all: true })
- }
- // 更新进度信息
- updateProcessInfo() {
- this.$info.text(`导出清单中: ${this.curProcessCount} / ${this.total}`)
- }
- // 精灵树数据转换为表格块单元格数据
- getBlock(elfTree) {
- return elfTree.items.map(node => {
- // rowCount、colCount标记合并单元格范围
- const rowCount = node.posterityLeafCount() || 1;
- const parentRow = node.parent && node.parent.cellInfo ? node.parent.cellInfo.row : 0;
- // let prevRowCount = node.preSibling && node.preSibling.cellInfo ? node.preSibling.cellInfo.row + node.preSibling.cellInfo.rowCount - parentRow : 0;
- const prev = node.prevNode();
- let prevRowCount = prev && prev.cellInfo ? prev.cellInfo.row + prev.cellInfo.rowCount - parentRow : 0;
- const row = parentRow + prevRowCount;
- const col = node.depth();
- const name = node.data.type === itemType.ration ? node.data.name.split(' ')[0] : node.data.name;
- const text = `${isProcessNode(node) && node.data.require ? '* ' : ''}${name}`
- node.cellInfo = {
- row,
- col,
- rowCount,
- };
- return {
- row,
- col,
- rowCount,
- text,
- colCount: 1,
- }
- })
- }
- // 根据精灵树数据,获取表格块range
- getBlockRange(elfTree) {
- const rowCount = elfTree.roots.reduce((prev, node) => prev + (node.posterityLeafCount() || 1), 0);
- const a = Date.now();
- const colCount = Math.max(...elfTree.items.map(node => node.depth())) + 1;
- console.log(Date.now() - a);
- return {
- rowCount,
- colCount
- }
- }
- // 获取清单的精灵树
- async getElfTree(billID) {
- const items = await this.getElfItems(billID);
- if (!items || !items.length) {
- return null;
- }
- const tree = idTree.createNew({ id: 'ID', pid: 'ParentID', nid: 'NextSiblingID', rootId: -1, autoUpdate: true });
- tree.loadDatas(items);
- return tree;
- }
- // 获取清单的精灵数据
- async getElfItems(billID) {
- if (this.billIDElfMap[billID]) {
- return this.billIDElfMap[billID];
- }
- if (!this.leafIDs.length) {
- return null;
- }
- const count = 20; // 每次拉取数据条数
- const billIDs = this.leafIDs.splice(0, count)
- await setTimeoutSync(null, 100);
- const items = await ajaxPost('/billsGuidance/api/getItemsByBillIDs', { guidanceLibID: this.libID, billIDs });
- this.updateProcessInfo();
- items.forEach(item => {
- (this.billIDElfMap[item.billsID] || (this.billIDElfMap[item.billsID] = [])).push(item)
- });
- return this.billIDElfMap[billID];
- }
- initSheet() {
- this.sheet.name('清单精灵');
- for (let col = 0; col < this.sheet.getColumnCount(); col++) {
- this.sheet.setColumnWidth(col, 100);
- }
- }
- }
|