/** * 块模板库管理。 * Created by CSL on 2018-09-19. */ var blockLibObj = { mainSpread: null, mainSheet: null, mainTree: null, mainTreeController: null, mainSetting: { "emptyRowHeader": true, "rowHeaderWidth": 15, "emptyRows":0, "headRows":1, "headRowHeight":[30], "defaultRowHeight": 21, "treeCol": 9, "cols":[{ "width":400, "readOnly": true, "head":{ "titleNames":["名称"], "spanCols":[1], "spanRows":[1], "vAlign":[1], "hAlign":[1], "font":["Arial"] }, "data":{ "field":"name", "vAlign":1, "hAlign":0, "font":"Arial" } }] }, mainDatas: [], billSpread: null, billSheet: null, billSetting: { header: [ {headerName: "项目编码", headerWidth: 90, dataCode: "code", dataType: "String", hAlign: "center"}, {headerName: "项目名称", headerWidth: 100, dataCode: "name", dataType: "String"}, {headerName: "单位", headerWidth: 40, dataCode: "unit", dataType: "String", hAlign: "center"}, {headerName: "综合单价", headerWidth: 70, dataCode: "unitFee", dataType: "Number"}, {headerName: "项目特征", headerWidth: 160, dataCode: "itemCharacterText", dataType: "String"} ], view: { lockColumns: [0, 1, 2, 3, 4] } }, rationSpread: null, rationSheet: null, rationSetting: { header: [ {headerName: "编码", headerWidth: 45, dataCode: "code", dataType: "String", hAlign: "center"}, {headerName: "名称", headerWidth: 100, dataCode: "name", dataType: "String"}, {headerName: "单位", headerWidth: 40, dataCode: "unit", dataType: "String", hAlign: "center"}, {headerName: "含量", headerWidth: 40, dataCode: "contain", dataType: "Number"}, {headerName: "取费专业", headerWidth: 70, dataCode: "programName", dataType: "String", hAlign: "center"}, {headerName: "综合单价", headerWidth: 70, dataCode: "unitFee", dataType: "Number"}, {headerName: "子目换算状态", headerWidth: 90, dataCode: "adjustState", dataType: "String"} ], view: { lockColumns: [0, 1, 2, 3, 4, 5, 6] } }, buildSheet: function () { $.bootstrapLoading.start(); let me = this; me.mainDatas = [ {ID: 1, ParentID: -1, NextSiblingID: 2, name: '分类1', type: 1}, {ID: 2, ParentID: -1, NextSiblingID: 3, name: '分类2', type: 1}, {ID: 3, ParentID: -1, NextSiblingID: 4, name: '分类3', type: 1}, // {ID: 105, ParentID: 1, NextSiblingID: 106, name: '块1', type: 2}, // {ID: 106, ParentID: 1, NextSiblingID: 107, name: '块2', type: 2}, {ID: 7, ParentID: -1, NextSiblingID: 8, name: '分类7', type: 1}, {ID: 9, ParentID: -1, NextSiblingID: -1, name: '分类9', type: 1}//, // {ID: 201, ParentID: 52, NextSiblingID: -1, name: '块201', type: 2} ]; if (me.mainSpread) { me.mainSpread.destroy(); me.mainSpread = null; }; if (me.billSpread) { me.billSpread.destroy(); me.billSpread = null; }; if (me.rationSpread) { me.rationSpread.destroy(); me.rationSpread = null; }; me.mainSpread = SheetDataHelper.createNewSpread($('#div_block_tree')[0]); // me.mainSpread = TREE_SHEET_HELPER.createNewSpread($('#div_block_tree')[0]); me.mainSheet = me.mainSpread.getSheet(0); me.mainSheet.name('blockLibSheet'); sheetCommonObj.spreadDefaultStyle(me.mainSpread); function showBlockTree(datas) { me.mainTree = idTree.createNew({id: 'ID', pid: 'ParentID', nid: 'NextSiblingID', rootId: -1, autoUpdate: false}); me.mainTreeController = TREE_SHEET_CONTROLLER.createNew(me.mainTree, me.mainSheet, me.mainSetting); me.mainTree.loadDatas(datas); me.mainTreeController.showTreeData(); me.mainSheet.getRange(-1, 0, -1, 1).cellType(me.getTreeCell(me.mainTree)); me.mainTree.selected = me.mainTree.items[0]; me.mainTreeController.bind(TREE_SHEET_CONTROLLER.eventName.treeSelectedChanged, function (node) { blockLibObj.loadDetailDatas(node); }); }; showBlockTree(me.mainDatas); me.billSpread = sheetCommonObj.buildSheet($('#div_block_bill')[0], me.billSetting, 1); me.billSheet = me.billSpread.getSheet(0); sheetCommonObj.spreadDefaultStyle(me.billSpread); me.billSheet.setColumnWidth(0, 20, GC.Spread.Sheets.SheetArea.rowHeader); me.rationSpread = sheetCommonObj.buildSheet($('#div_block_ration')[0], me.rationSetting, 1); me.rationSheet = me.rationSpread.getSheet(0); sheetCommonObj.spreadDefaultStyle(me.rationSpread); me.rationSheet.setColumnWidth(0, 20, GC.Spread.Sheets.SheetArea.rowHeader); me.loadTreeContextMenu(); me.mainSpread.bind(GC.Spread.Sheets.Events.EnterCell, me.onEnterCell); me.mainSpread.bind(GC.Spread.Sheets.Events.CellDoubleClick, this.onCellDoubleClick); $.bootstrapLoading.end(); }, loadDetailDatas: function (node){ let me = this; if (!node) return; if (node.data.type == 2){ let bill = node.data; let rations = bill.children; sheetCommonObj.showData(me.billSheet, me.billSetting, [bill]); let rCount = (rations.length > 0) ? rations.length : 1; me.rationSheet.setRowCount(rCount, GC.Spread.Sheets.SheetArea.viewport); sheetCommonObj.showData(me.rationSheet, me.rationSetting, rations); } else{ sheetCommonObj.cleanSheet(me.billSheet, me.billSetting, 1); sheetCommonObj.cleanSheet(me.rationSheet, me.rationSetting, 1); } }, getTreeCell: function (tree) { let me = this; let indent = 20, levelIndent = -5, halfBoxLength = 5, halfExpandLength = 3, imgWidth = 14, imgHeight = 14; let TreeCell = function () {}; TreeCell.prototype = new GC.Spread.Sheets.CellTypes.Text(); TreeCell.prototype.paint = function (ctx, value, x, y, w, h, style, options) { if (style.backColor) { ctx.save(); ctx.fillStyle = style.backColor; ctx.fillRect(x, y, w, h); ctx.restore(); } else { ctx.clearRect(x, y, w, h); }; let drawLine = function (canvas, x1, y1, x2, y2, color) { ctx.save(); ctx.translate(0.5, 0.5); ctx.beginPath(); ctx.moveTo(x1, y1); ctx.lineTo(x2, y2); ctx.strokeStyle = color; ctx.stroke(); ctx.restore(); }; let drawExpandBox = function (ctx, x, y, w, h, centerX, centerY, expanded) { let rect = {}, h1, h2, offset = 1; rect.top = centerY - halfBoxLength; rect.bottom = centerY + halfBoxLength; rect.left = centerX - halfBoxLength; rect.right = centerX + halfBoxLength; if (rect.left < x + w) { rect.right = Math.min(rect.right, x + w); ctx.save(); ctx.translate(0.5, 0.5); ctx.strokeStyle = 'black'; ctx.beginPath(); ctx.moveTo(rect.left, rect.top); ctx.lineTo(rect.left, rect.bottom); ctx.lineTo(rect.right, rect.bottom); ctx.lineTo(rect.right, rect.top); ctx.lineTo(rect.left, rect.top); ctx.stroke(); ctx.fillStyle = 'white'; ctx.fill(); ctx.restore(); // Draw Horizontal Line h1 = centerX - halfExpandLength; h2 = Math.min(centerX + halfExpandLength, x + w); if (h2 > h1) { drawLine(ctx, h1, centerY, h2, centerY, 'black'); } // Draw Vertical Line if (!expanded && (centerX < x + w)) { drawLine(ctx, centerX, centerY - halfExpandLength, centerX, centerY + halfExpandLength, 'black'); } } }; let node = tree.items[options.row]; if (!node) return; let showTreeLine = true; let centerX = Math.floor(x) + node.depth() * indent + node.depth() * levelIndent + indent / 2; let x1 = centerX + indent / 2; let centerY = Math.floor((y + (y + h)) / 2); let y1; // Draw Horizontal Line、Image、sibling Vertical Line if (centerX < x + w) { // Draw Horizontal Line drawLine(ctx, centerX, centerY, Math.min(x1, x + w), centerY, 'gray'); // Draw Image let imgId; if (node.data.type === 0) imgId = 'blockLib_pic' else if (node.data.type === 1) imgId = 'folder_pic' else if (node.data.type === 2) { imgId = 'block_pic'; }; let img = document.getElementById(imgId); ctx.drawImage(img, centerX+indent/2+3, centerY - 7, imgWidth, imgHeight); // Draw Vertical Line y1 = node.isLast() ? centerY : y + h; if (node.isFirst() && !node.parent/*.parent*/) { drawLine(ctx, centerX, centerY, centerX, y1, 'gray'); } else { drawLine(ctx, centerX, y, centerX, y1, 'gray'); } } // Draw Expand Box if (node.children.length > 0) { drawExpandBox(ctx, x, y, w, h, centerX, centerY, node.expanded); } // Draw Parent Line var curNode = node.parent, parentCenterX = centerX - indent - levelIndent; while (curNode) { if (!curNode.isLast()) { if (parentCenterX < x + w) { drawLine(ctx, parentCenterX, y, parentCenterX, y + h, 'gray'); } } curNode = curNode.parent; parentCenterX -= (indent + levelIndent); } // Draw Text x = x + (node.depth() + 1) * indent + node.depth() * levelIndent + imgWidth + 3; w = w - (node.depth() + 1) * indent - node.depth() * levelIndent - imgWidth - 3; GC.Spread.Sheets.CellTypes.Text.prototype.paint.apply(this, arguments); }; TreeCell.prototype.getHitInfo = function (x, y, cellStyle, cellRect, context) { let info = {x: x, y: y, row: context.row, col: context.col, cellStyle: cellStyle, cellRect: cellRect, sheetArea: context.sheetArea}; let node = tree.items[info.row]; let offset = -1; let centerX = info.cellRect.x + offset + node.depth() * indent + node.depth() * levelIndent + indent / 2; let text = context.sheet.getText(info.row, info.col); let value = context.sheet.getValue(info.row, info.col); let acStyle = context.sheet.getActualStyle(info.row, info.col), zoom = context.sheet.zoom(); let textLength = this.getAutoFitWidth(value, text, acStyle, zoom, {sheet: context.sheet, row: info.row, col: info.col, sheetArea: GC.Spread.Sheets.SheetArea.viewport}); if(info.x > centerX + halfBoxLength && info.x < centerX + halfBoxLength + imgWidth + indent/2+3 + textLength){ info.isReservedLocation = true; } return info; }; TreeCell.prototype.processMouseDown = function (hitinfo) { let offset = -1; let node = tree.items[hitinfo.row]; let centerX = hitinfo.cellRect.x + offset + node.depth() * indent + node.depth() * levelIndent + indent / 2; let centerY = (hitinfo.cellRect.y + offset + (hitinfo.cellRect.y + offset + hitinfo.cellRect.height)) / 2; let text = hitinfo.sheet.getText(hitinfo.row, hitinfo.col); let value = hitinfo.sheet.getValue(hitinfo.row, hitinfo.col); let acStyle = hitinfo.sheet.getActualStyle(hitinfo.row, hitinfo.col), zoom = hitinfo.sheet.zoom(); let textLength = this.getAutoFitWidth(value, text, acStyle, zoom, {sheet: hitinfo.sheet, row: hitinfo.row, col: hitinfo.col, sheetArea: GC.Spread.Sheets.SheetArea.viewport}); //(图标+名字)区域 function withingClickArea(){ return hitinfo.x > centerX + halfBoxLength && hitinfo.x < centerX + halfBoxLength + imgWidth + indent/2+3 + textLength; } if (hitinfo.x > centerX - halfBoxLength && hitinfo.x < centerX + halfBoxLength && hitinfo.y > centerY - halfBoxLength && hitinfo.y < centerY + halfBoxLength) { node.setExpanded(!node.expanded); TREE_SHEET_HELPER.massOperationSheet(hitinfo.sheet, function () { let iCount = node.posterityCount(), i, child; for (i = 0; i < iCount; i++) { child = tree.items[hitinfo.row + i + 1]; hitinfo.sheet.setRowVisible(hitinfo.row + i + 1, child.visible, hitinfo.sheetArea); } hitinfo.sheet.invalidateLayout(); }); hitinfo.sheet.repaint(); } }; TreeCell.prototype.processMouseMove = function (hitInfo) { let sheet = hitInfo.sheet; let div = sheet.getParent().getHost(); let canvasId = div.id + "vp_vp"; /* let canvas = $(`#${canvasId}`)[0]; //改变鼠标图案 if (sheet && hitInfo.isReservedLocation) { canvas.style.cursor='pointer'; return true; }else{ canvas.style.cursor='default'; }*/ return false; }; TreeCell.prototype.processMouseEnter = function (hitinfo) { let text = hitinfo.sheet.getText(hitinfo.row, hitinfo.col); let value = hitinfo.sheet.getValue(hitinfo.row, hitinfo.col); let tag = hitinfo.sheet.getTag(hitinfo.row, hitinfo.col); let acStyle = hitinfo.sheet.getActualStyle(hitinfo.row, hitinfo.col), zoom = hitinfo.sheet.zoom(); let node = me.mainTree.items[hitinfo.row]; let nodeIndent = node ? (node.depth() + 1) * indent + node.depth() * levelIndent + imgWidth + 3 : 0; let textLength = this.getAutoFitWidth(value, text, acStyle, zoom, {sheet: hitinfo.sheet, row: hitinfo.row, col: hitinfo.col, sheetArea: GC.Spread.Sheets.SheetArea.viewport}); let cellWidth = hitinfo.sheet.getCell(-1, hitinfo.col).width(); if(textLength > cellWidth - nodeIndent){ TREE_SHEET_HELPER.showTipsDiv(text,{pos: {}},hitinfo); } }; TreeCell.prototype.processMouseLeave = function (hitinfo) { let me = this; TREE_SHEET_HELPER.tipDiv = 'hide'; if (TREE_SHEET_HELPER._toolTipElement) { $(TREE_SHEET_HELPER._toolTipElement).hide(); TREE_SHEET_HELPER._toolTipElement = null; }; TREE_SHEET_HELPER.tipDivCheck();//延时检查:当tips正在show的时候,就调用了hide方法,会导致tips一直存在,所以设置一个超时处理 }; return new TreeCell(); }, newNode: function (nodeType, nodeName, categoryID, source){ // 1 分类(只用前两个参数) 2 块文件 let tree = blockLibObj.mainTree; let pID = -1, nID = -1; let select = tree.selected; if (nodeType == 1){ if (!select) { nID = -1; } else if (select.data.type == 1){ nID = select.getNextSiblingID(); } else if (select.data.type == 2){ nID = select.parent.getNextSiblingID(); }; } else if (nodeType == 2) { pID = categoryID; nID = -1; } let newNode = tree.insert(pID, nID); newNode.data.type = nodeType; newNode.data.fileName = nodeName; if (nodeType == 2){ let bill = source.datas[0]; newNode.data.compilationID = source.compilationID; newNode.data.copyTime = source.copyTime; newNode.data.firstNodeType = source.firstNodeType; newNode.data.isFBFX = source.isFBFX; newNode.data.code = bill.code; newNode.data.name = bill.name; newNode.data.unit = bill.unit; newNode.data.itemCharacterText = bill.itemCharacterText; newNode.data.unitFee = (bill.feesIndex && bill.feesIndex.common) ? bill.feesIndex.common.unitFee : 0; newNode.data.children = bill.children; for (let r of bill.children){ r.unitFee = (r.feesIndex && r.feesIndex.common) ? r.feesIndex.common.unitFee : 0; if (r.programID) r.programName = projectObj.project.calcProgram.compiledTemplateMaps[r.programID]; // delete r.ID; // 这个不能删! delete r.billsItemID; delete r.fees; delete r.feesIndex; }; } tree.selected = newNode; let sheet = blockLibObj.mainSheet; sheet.suspendPaint(); sheet.suspendEvent(); let idx = tree.items.indexOf(newNode); sheet.addRows(idx, 1); sheet.getRange(idx, 0, 1, 1).locked(true); sheet.setValue(idx, 0, newNode.data.fileName); sheet.setSelection(idx, 0, 1, 1); sheet.resumeEvent(); sheet.resumePaint(); }, reName: function (node, newName){ if (newName == '') return; node.data.fileName = newName; let idx = blockLibObj.mainTree.items.indexOf(node); blockLibObj.mainSheet.setValue(idx, 0, newName); }, moveBlock: function (parentID) { // this.mainTreeController.moveTo(parentID); }, delete: function () { this.mainTreeController.delete(); }, getCategories: function () { let nodes = [], node = blockLibObj.mainTree.items[0]; nodes.push(node); while (node.nextSibling != null){ node = node.nextSibling; nodes.push(node); }; return nodes; }, curIsBlock: function () { return this.mainTree.selected.data.type == 2; }, curIsCategory: function () { return this.mainTree.selected.data.type == 1; }, refreshSpread: function (){ if (this.mainSpread) this.mainSpread.refresh(); if (this.billSpread) this.billSpread.refresh(); if (this.rationSpread) this.rationSpread.refresh(); }, loadTreeContextMenu: function (){ let me = this; $.contextMenu({ selector: '#div_block_tree', build: function ($trigger, e) { SheetDataHelper.safeRightClickSelection($trigger, e, me.mainSpread); me.onEnterCell(); }, items: { "oneToOneClone": { name: '一对一克隆', icon: "fa-battery-empty", disabled: function () { let ok = me.curIsBlock() && calcTools.isLeafBill(projectObj.project.mainTree.selected); return !ok; }, visible: function(key, opt){ return true; }, callback: function (key, opt) { me.onCellDoubleClick(); } }, "oneToMoreClone": { name: '一对多克隆', icon: "fa-battery-half", disabled: function () { let ok = me.curIsBlock() && calcTools.isParentBill(projectObj.project.mainTree.selected); return !ok; }, visible: function(key, opt){ return true; }, callback: function (key, opt) { } }, "moreToMoreClone": { name: '多对多克隆', icon: "fa-battery-full", disabled: function () { let ok = me.curIsCategory() && calcTools.isParentBill(projectObj.project.mainTree.selected); return !ok; }, visible: function(key, opt){ return true; }, callback: function (key, opt) { } }, "delete": { name: '删除', icon: "delete", disabled: function () { }, visible: function(key, opt){ return true; }, callback: function (key, opt) { me.delete(); } }, "moveBlock": { name: '移动模板', icon: "cut", disabled: function () { return true; }, visible: function(key, opt){ return me.curIsBlock(); }, callback: function (key, opt) { } } } }); }, onEnterCell: function (sender, args) { let me = blockLibObj; me.mainTree.selected = me.mainTree.items[me.mainSheet.getActiveRowIndex()]; }, onCellDoubleClick: function (sender, args) { let projectNode = projectObj.project.mainTree.selected; if (!calcTools.isLeafBill(projectNode)) return; $("#blockAdjustOptions").modal({show: true}); }, oneToOneClone: function (projectNode, block) { // 这里再次封装成伟城的块文件格式,可直接使用伟城的“粘贴块”接口。 // 这里结构作出调整:忽略叶子清单层,直接从定额开始(跟粘贴块有区别),始终强制在叶子清单下插入定额。 // 该操作前提:当前块文件的全部数据已从后台取到前台。 let vBlock_WC = { compilationID: block.data.compilationID, copyTime: block.data.copyTime, firstNodeType: 1, // 强制改成1 (因为是从清单下的定额开始。清单自身的还是保留,暂不使用使用)。 isFBFX: block.data.isFBFX, datas: block.data.children // rations }; BlockController.confirmPaste(vBlock_WC, projectNode, 'sub'); }, oneToMoreCloneXX: function () { // } }; $(document).ready(function(){ $('#blockLibTab').on('click', function (){ if ($("#kmbk").is(":visible")){ if (!blockLibObj.mainSpread){ blockLibObj.buildSheet(); }; } }); $('#btn_block_newFolder').on('click', function (){ $('#input_block_newFolder').val(''); }); $('#btn_block_newFolder_add').on('click', function (){ let name = $('#input_block_newFolder').val(); if (name != '') blockLibObj.newNode(1, name); }); $('#btn_block_reName').on('click', function (){ let select = blockLibObj.mainTree.selected; $('#input_block_reName').val(select.data.fileName); }); $('#btn_block_reName_OK').on('click', function (){ let select = blockLibObj.mainTree.selected; let oldName = select.data.fileName; let newName = $('#input_block_reName').val(); if (oldName != newName) blockLibObj.reName(select, newName); }); });