'use strict'; /** * * * @author Zhong * @date 2018/6/28 * @version */ const pmShare = (function () { const spreadDom = $('#shareSpread'); let spreadObj = {workBook: null, sheet: null}; //项目分享类型,由别人分享给自己的,和自己分享给别人的 const shareType = {receive: 'receive', shareTo: 'shareTo'}; let tree = null; const treeSetting = { tree: { id: 'ID', pid: 'ParentID', nid: 'NextSiblingID', rootId: -1, autoUpdate: false } }; const headers = [ {name: '工程列表', dataCode: 'name', width: 0.55, vAlign: 'center', hAlign: 'left'}, {name: '由...分享', dataCode: 'from', width: 0.15, vAlign: 'center', hAlign: 'left'}, {name: '分享给...', dataCode: 'to', width: 0.15, vAlign: 'center', hAlign: 'left'}, {name: '操作', dataCode: 'operation', width: 0.15, vAlign: 'center', hAlign: 'left'}, ]; const spreadOpts = { workBook: { tabStripVisible: false, allowContextMenu: false, allowCopyPasteExcelStyle : false, allowExtendPasteRange: false, allowUserDragDrop : false, allowUserDragFill: false, scrollbarMaxAlign : true }, sheet: { isProtected: true, protectionOptions: {allowResizeRows: true, allowResizeColumns: true}, clipBoardOptions: GC.Spread.Sheets.ClipboardPasteOptions.values } }; const spreadEvents = { SelectionChanging: function (sender, info) { initSelection(info.newSelections[0], info.oldSelections[0]); } }; //设置选中行底色 //@param function setSelStyle(sel, backColor,sheet) { sel.row = sel.row === -1 ? 0 : sel.row; renderSheetFunc(sheet, function () { let style = projTreeObj.getSelStyle(backColor); for(let i = 0; i < sel.rowCount; i++){ let row = i + sel.row; sheet.setStyle(row, -1, style); } }); } //初始化焦点 //@param {Object}newSel {Object}oldSel @return {void} function initSelection(newSel, oldSel = null) { let node = tree.items[newSel.row]; tree.selected = node; shareSeleted = node; //恢复底色 if(oldSel){ setSelStyle(oldSel, projTreeObj.setting.style.defalutBackColor, spreadObj.sheet); } //设置选中行底色 if(newSel){ setSelStyle(newSel, projTreeObj.setting.style.selectedColor, spreadObj.sheet); } } //渲染时方法,停止渲染 //@param {Object}sheet {Function}func @return {void} function renderSheetFunc(sheet, func){ sheet.suspendEvent(); sheet.suspendPaint(); if(func){ func(); } sheet.resumeEvent(); sheet.resumePaint(); } //设置表选项 //@param {Object}workBook {Object}opts @return {void} function setSpreadOptions (workBook, opts) { for(let opt in opts.workBook){ workBook.options[opt] = opts.workBook[opt]; } for(let opt in opts.sheet){ workBook.getActiveSheet().options[opt] = opts.sheet[opt]; } } //建表头 //@param {Object}sheet {Array}headers @return {void} function buildHeader(sheet, headers) { let fuc = function () { sheet.setColumnCount(headers.length); sheet.setRowHeight(0, 40, GC.Spread.Sheets.SheetArea.colHeader); let spreadWidth = getWorkBookWidth(); for(let i = 0, len = headers.length; i < len; i++){ sheet.setValue(0, i, headers[i].name, GC.Spread.Sheets.SheetArea.colHeader); sheet.setColumnWidth(i, spreadWidth * headers[i].width, GC.Spread.Sheets.SheetArea.colHeader); if(headers[i].formatter){ sheet.setFormatter(-1, i, headers[i].formatter); } sheet.getRange(-1, i, -1, 1).hAlign(GC.Spread.Sheets.HorizontalAlign[headers[i]['hAlign']]); sheet.getRange(-1, i, -1, 1).vAlign(GC.Spread.Sheets.VerticalAlign[headers[i]['vAlign']]); } }; renderSheetFunc(sheet, fuc); } //表监听事件 //@param {Object}workBook @return {void} function bindEvent(workBook, events) { if(Object.keys(events).length === 0){ return; } const Events = GC.Spread.Sheets.Events; for(let event in events){ workBook.bind(Events[event], events[event]); } } //建表 // function buildSheet(){ spreadObj.workBook = new GC.Spread.Sheets.Workbook(spreadDom[0], {sheetCount: 1}); spreadObj.sheet = spreadObj.workBook.getActiveSheet(); setSpreadOptions(spreadObj.workBook, spreadOpts); bindEvent(spreadObj.workBook, spreadEvents); buildHeader(spreadObj.sheet, headers); //全表不可编辑 spreadObj.sheet.getRange(-1, -1, -1, -1).locked(true); } //此项目是否可以拷贝 //@param {String}userID {Object}project @return {Boolean} function isAllowCopy(userID, project){ for(let shareData of project.shareInfo){ if(shareData.userID === userID){ return shareData.allowCopy; } } return false; } // // function getTreeNodeCell(tree){ let indent = 20; let levelIndent = -5; let halfBoxLength = 5; let halfExpandLength = 3; let imgWidth = 18; let imgHeight = 14; let TreeNodeCellType = function () { }; TreeNodeCellType.prototype = new GC.Spread.Sheets.CellTypes.Text(); TreeNodeCellType.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]; let showTreeLine = true; if (!node) { return; } 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 Sibling Line if (showTreeLine) { // Draw Horizontal Line if (centerX < x + w) { drawLine(ctx, centerX, centerY, Math.min(x1, x + w), centerY, 'gray'); let img; if(node.data.projType === projectType.folder){ img = document.getElementById('folder_open_pic'); imgWidth = 15; } else if(node.data.projType === projectType.project){ img = document.getElementById('proj_pic'); imgWidth = 18; } else if(node.data.projType === projectType.engineering){ img = document.getElementById('eng_pic'); imgWidth = 14; } else if(node.data.projType === projectType.tender){ img = document.getElementById('tender_pic'); imgWidth = 14; } ctx.drawImage(img, centerX+indent/2+3, centerY - 7, imgWidth,imgHeight); } // Draw Vertical Line if (centerX < x + w) { 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 if (showTreeLine) { var parent = node.parent, parentCenterX = centerX - indent - levelIndent; while (parent.parent) { if (!parent.isLast()) { if (parentCenterX < x + w) { drawLine(ctx, parentCenterX, y, parentCenterX, y + h, 'gray'); } } parent = parent.parent; parentCenterX -= (indent + levelIndent); } }; // Draw Text arguments[2] = x + (node.depth() + 1) * indent + node.depth() * levelIndent + imgWidth + 3; arguments[4] = w - (node.depth() + 1) * indent - node.depth() * levelIndent - imgWidth - 3; GC.Spread.Sheets.CellTypes.Text.prototype.paint.apply(this, arguments); }; TreeNodeCellType.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; }; TreeNodeCellType.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(node.data.projType === projectType.tender && withingClickArea()){ let newTab = window.open('about:blank'); BeforeOpenProject(node.data.ID, {'fullFolder': GetFullFolder(node.parent)}, function () { let mainUrl = `/main?project=${node.data.ID}`; CommonAjax.get(mainUrl, [], function () { newTab.location.href = mainUrl; }); }); } if (!node || node.children.length === 0) { return; } 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(); } }; TreeNodeCellType.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; }; return new TreeNodeCellType(); } // // function getInteractionCell() { let InteractionCell = function () { }; InteractionCell.prototype = new GC.Spread.Sheets.CellTypes.Text(); InteractionCell.prototype.getHitInfo = function (x, y, cellStyle, cellRect, context) { return { x: x, y: y, row: context.row, col: context.col, cellStyle: cellStyle, cellRect: cellRect, sheetArea: context.sheetArea, isReservedLocation: true }; }; InteractionCell.prototype.processMouseDown = function (hitinfo) { let dataCode = headers[hitinfo.col]['dataCode']; let node = tree.items[hitinfo.row]; 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}); if(hitinfo.x - hitinfo.cellRect.x > 0 && hitinfo.x - hitinfo.cellRect.x < textLength){ //由..分享,弹出分享者信息 if(dataCode === 'from'){ if(node.data.shareType === shareType.receive){ $('#userinfo').find('h4').text(node.data.userInfo.name); $('#userinfo').find('h6').text(node.data.userInfo.company); let mobileHtml = ` ${node.data.userInfo.mobile ? node.data.userInfo.mobile : ''}`; $('#userinfo').find('li:first-child').html(mobileHtml); let emailHtml = ` ${node.data.userInfo.email ? node.data.userInfo.email : ''}`; $('#userinfo').find('li:last-child').html(emailHtml); $('#userinfo').modal('show'); } } //分享给 else if(dataCode === 'to'){ if(node.data.shareType === shareType.shareTo){ setShareToModal(node); $('#shareTo').modal('show'); } } //操作 else if(dataCode === 'operation'){ if(node.data.operation === '添加分享'){ $('#sharePhone').val(''); $('#share-info').hide(); $('#share').find('.card').hide(); $('#share').modal('show'); $('#allowCopy').prop('checked', false); $('#allowCopyHint').hide(); } else if(node.data.operation === '拷贝工程'){ $('#copyShare').modal('show'); } else { return; } } //清除 else if(dataCode === 'delete'){ gcTreeObj.oprProj('#delPoj', node) } //恢复单价文件 else if(dataCode === 'unitPriceFile'){ gcTreeObj.recoveryUnitPrc(node); } //清除单价文件 else if(dataCode === 'unitPriceFile_delete'){ gcTreeObj.deleteUnitPrc(node); } //恢复费率文件 else if(dataCode === 'feeRateFile'){ gcTreeObj.recoveryFeeRate(node); } //清除费率文件 else if(dataCode === 'feeRateFile_delete'){ gcTreeObj.deleteFeeRate(node); } } }; InteractionCell.prototype.processMouseMove = function (hitInfo) { let dataCode = headers[hitInfo.col]['dataCode']; let node = tree.items[hitInfo.row]; let sheet = hitInfo.sheet; let div = sheet.getParent().getHost(); let canvasId = div.id + "vp_vp"; let canvas = $(`#${canvasId}`)[0]; //改变鼠标图案 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}); if (sheet && hitInfo.x - hitInfo.cellRect.x > 0 && hitInfo.x - hitInfo.cellRect.x < textLength) { canvas.style.cursor='pointer'; return true; }else{ canvas.style.cursor='default'; } return false; }; return new InteractionCell(); } //设置分享给界面数据 //@param {Object}selected @return {void} function setShareToModal(selected){ $('#shareToInfo').empty(); if(!selected){ return; } let userIDs = []; for(let user of selected.data.shareInfo){ userIDs.push(user.userID); } CommonAjax.post('/user/getUsers', {userIDs: userIDs}, function (rstData) { for(let userInfo of rstData){ for(let user of selected.data.shareInfo){ if(user.userID === userInfo._id){ user.name = userInfo.real_name; user.company = userInfo.company; user.mobile = userInfo.mobile; user.email = userInfo.email; } } } let infoArr = []; for(let user of selected.data.shareInfo){ let infoHtml = ` ${user.name} ${user.company} ${user.mobile} ${user.email} `; infoArr.push(infoHtml); } let infoHtml = infoArr.join(''); $('#shareToInfo').html(infoHtml); }); } //更新项目分享信息 //@param {Object}selected function updateShareInfo(selected){ if(!selected){ return; } let usersTr = $('#shareToInfo').find('tr'); let newShareInfo = []; for(let i = 0; i < usersTr.length; i++){ let userTr = usersTr[i]; let allowCopy = $(userTr).find('input:first').prop('checked'); let cancelShare = $(userTr).find('input:last').prop('checked'); selected.data.shareInfo[i].allowCopy = allowCopy; if(!cancelShare){ newShareInfo.push(selected.data.shareInfo[i]); } } CommonAjax.post('/pm/api/updateProjects', {user_id: userID, updateData: [{updateType: 'update', updateData: {ID: selected.data.ID, shareInfo: newShareInfo}}]}, function () { selected.data.shareInfo = newShareInfo; if(newShareInfo.length === 0){ renderSheetFunc(spreadObj.sheet, function () { let rIdx = selected.serialNo(); tree.removeNode(selected); spreadObj.sheet.deleteRows(rIdx, 1); spreadObj.sheet.setRowCount(tree.items); initSelection({row: spreadObj.sheet.getActiveRowIndex(), rowCount: 1},null); }); } }); } const foreColor = '#007bff'; //显示树结构数据 //@param {Array}nodes {Array}headers @return {void} function showTreeData(nodes, headers){ let sheet = spreadObj.workBook.getActiveSheet(); let fuc = function(){ sheet.setRowCount(nodes.length); for(let i = 0; i < nodes.length; i++){ let treeNodeCell = getTreeNodeCell(tree); sheet.getCell(i, 0).cellType(treeNodeCell); for(let j = 0; j < headers.length; j++){ sheet.getRange(-1, j, -1, 1).hAlign(GC.Spread.Sheets.HorizontalAlign[headers[j]['hAlign']]); sheet.getRange(-1, j, -1, 1).vAlign(GC.Spread.Sheets.VerticalAlign[headers[j]['vAlign']]); let dataCode = headers[j].dataCode; if(dataCode === 'operation'){ let style = new GC.Spread.Sheets.Style(); style.foreColor = foreColor; sheet.setStyle(i, j, style); sheet.getCell(i, j).cellType(getInteractionCell()); } else if(dataCode === 'from'){ if(nodes[i].data.shareType && nodes[i].data.shareType === shareType.receive){ let style = new GC.Spread.Sheets.Style(); style.foreColor = foreColor; sheet.setStyle(i, j, style); sheet.getCell(i, j).cellType(getInteractionCell()); } } else if(dataCode === 'to'){ if(nodes[i].data.shareType && nodes[i].data.shareType === shareType.shareTo){ let style = new GC.Spread.Sheets.Style(); style.foreColor = foreColor; sheet.setStyle(i, j, style); sheet.getCell(i, j).cellType(getInteractionCell()); } } /* else if(dataCode === 'delete' || dataCode === 'unitPriceFile_delete' || dataCode === 'feeRateFile_delete'){ let style = new GC.Spread.Sheets.Style(); style.foreColor = me.setting.style.delForeColor; sheet.setStyle(-1, j, style); }*/ sheet.setValue(i, j, nodes[i].data[dataCode] ? nodes[i].data[dataCode] : ''); //me.setCellValue({row: i, col: j}, nodes[i]); } } }; renderSheetFunc(sheet, fuc); } //将数据转换为可成树的数据,因为获取的数据不来自同一棵树 //@param {Array}datas function buildTreeDatas(datas){ let IDMap = {}; for(let i = 0; i < datas.length; i++){ let data = datas[i]; let nextData = datas[i + 1]; data.NextSiblingID = nextData ? nextData.ID : -1; data.ParentID = -1; IDMap[data.ID] = data; if(data.shareType === shareType.receive){ if(data.userInfo){ data.from = `由 ${data.userInfo.name} 分享`; data.to = '分享给 我'; data.operation = isAllowCopy(userID, data) ? '拷贝工程' : ''; } } else { data.from = '由 我 分享'; data.to = '分享给...'; data.operation = '添加分享'; } } } //建立树 //@return void function initShareTree(){ $.bootstrapLoading.start(); //获取分享数据 CommonAjax.post('/pm/api/getShareProjects', {user_id: userID}, function (rstData) { let projDatas = rstData.receive.concat(rstData.share); buildTreeDatas(projDatas); tree = pmTree.createNew(treeSetting, projDatas); console.log(tree); tree.selected = tree.items[0]; showTreeData(tree.items, headers); //初始选择 let initSel = spreadObj.sheet.getSelections()[0] ? spreadObj.sheet.getSelections()[0] : {row: 0, rowCount: 1}; initSelection(initSel); autoFlashHeight(); spreadObj.workBook.refresh(); $.bootstrapLoading.end(); }); } //初始化视图 //@return void function initView(){ if(tree){ tree = null; } if(spreadObj.workBook){ spreadObj.workBook.destroy(); spreadObj.workBook = null; } buildSheet(); initShareTree(); } //根据建设项目获取单项工程 //@param {Number}projID @return {void} function setEng(projID){ let engQuery = {$or: [{deleteInfo: null}, {'deleteInfo.deleted': false}], projType: projectType.engineering, userID: userID, ParentID: projID}; CommonAjax.post('/pm/api/getProjectsByQuery', {user_id: userID, query: engQuery, options: '-_id -property'}, function (rstData) { $('#copyShare_selectEng').empty(); for(let eng of rstData){ let opt = $('