| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205 | 'use strict';/** * * * @author Zhong * @date 2018/6/28 * @version */const pmShare = (function () {    const spreadDom = $('#shareSpread');    let shareSeleted = null;    let spreadObj = {workBook: null, sheet: null};    let preSelection = null;    //项目分享类型,由别人分享给自己的,和自己分享给别人的    const shareType = {receive: 'receive', shareTo: 'shareTo'};    //操作类型    const oprType = {copy: 'copy', cancel: 'cancel'};    let tree = null,        actualIDShareInfo = {};//项目真实树ID与项目分享信息映射    let curCopySelTree = null;  //拷贝工程建设项目选项树    const treeCol = 0;    const treeSetting = {        tree: {            id: 'ID',            pid: 'ParentID',            nid: 'NextSiblingID',            rootId: -1,            autoUpdate: false        }    };    const headers = [        {name: '工程列表', dataCode: 'name', width: 300, rateWidth: 0.55, vAlign: 'center', hAlign: 'left'},        {name: '来自', dataCode: 'from', width: 80, rateWidth: 0.15, vAlign: 'center', hAlign: 'left'},        {name: '分享时间', dataCode: 'shareDate', width: 140, rateWidth: 0.15, vAlign: 'center', hAlign: 'left'},        {name: '工程造价', dataCode: 'engineeringCost', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},        {name: '分部分项合计', dataCode: 'subEngineering', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},        {name: '措施项目合计', dataCode: 'measure', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},        {name: '其他项目合计', dataCode: 'other', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},        {name: '规费', dataCode: 'charge', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},        {name: '税金', dataCode: 'tax', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},        {name: '占造价比例(%)', dataCode: 'rate', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},        {name: '建筑面积', dataCode: 'buildingArea', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},        {name: '单方造价', dataCode: 'perCost', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},        {name: '工程专业', dataCode: 'feeStandardName', width: 100, vAlign: 'center', hAlign: 'left'},    ];    const spreadOpts = {        workBook: {            tabStripVisible:  false,            allowContextMenu: false,            allowCopyPasteExcelStyle : false,            allowExtendPasteRange: false,            allowUserDragDrop : false,            allowUserDragFill: false,            scrollbarMaxAlign : true        },        sheet: {            isProtected: true,            frozenlineColor : '#ababab',            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);        }        preSelection = newSel;    }    //渲染时方法,停止渲染    //@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.setColumnWidth(i, headers[i].width, GC.Spread.Sheets.SheetArea.colHeader);                if(headers[i].formatter){                    sheet.setFormatter(-1, i, headers[i].formatter);                }                sheet.setValue(0, i, headers[i].name, GC.Spread.Sheets.SheetArea.colHeader);                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]);        }    }    //建表    //@return {void}    function buildSheet(){        spreadObj.workBook = new GC.Spread.Sheets.Workbook(spreadDom[0], {sheetCount: 1});        sheetCommonObj.spreadDefaultStyle(spreadObj.workBook);        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(本用户id) {Object}project(项目) @return {Object} || {Null}    function getShareInfo(userID, project) {        if (!project.actualTreeInfo) {            return null;        }        //获取跟本用户和选中项目相关的分享信息        let shareList = [];        let actualID = project.actualTreeInfo.ID,            actualData = actualIDShareInfo[actualID];        while (actualData) {            for (let data of actualData.shareInfo) {                if (data.userID === userID) {                    shareList.push(data);                    break;                }            }            actualData = actualIDShareInfo[actualData.ParentID];        }        //获取最新分享        shareList.sort(function (a, b) {            //return Date.parse(b.shareDate) - Date.parse(a.shareDate)            return Date.parse(b.updateDate) - Date.parse(a.updateDate);        });        return shareList[0] || null;    }    //此项目是否可以拷贝    //@param {String}userID {Object}project @return {Boolean}    function isAllowCopy(userID, project){        let myShareInfo = getShareInfo(userID, project);        if (!myShareInfo) {            return false;        }        return !!myShareInfo.allowCopy;    }    //此项目是否可以协作    //@param {String}userID {Object}project @return {Boolean}    function isAllowCoop(userID, project) {        let myShareInfo = getShareInfo(userID, project);        if (!myShareInfo) {            return false;        }        return !!myShareInfo.allowCooperate;    }    //获取树节点    //@param {Object}tree @return {Object}    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];            if (node && node.data.projType === projectType.tender) {                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;            //点击单位工程            if(node.data.projType === projectType.tender){                let thisClick = Date.now(),                    open = false;                if (this.preNode === node && this.preClick && thisClick - this.preClick <= 300) {                    open = true;                    projTreeObj.openTender(node.data.actualTreeInfo.ID, node.parent, 200);                }                this.preClick = open ? null : thisClick;                this.preNode = open ? null : node;            }            if (!node || node.children.length === 0) {                return;            }            if (hitinfo.x >= centerX - halfBoxLength - 2 && hitinfo.x <= centerX + halfBoxLength + 2 &&                hitinfo.y >= centerY - halfBoxLength - 2 && hitinfo.y <= centerY + halfBoxLength + 2) {                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.processMouseEnter = function (hitinfo) {            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 node = tree.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);            }        };        TreeNodeCellType.prototype.processMouseLeave = function (hitinfo) {            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 TreeNodeCellType();    }    //互动单元格    function getInteractionCell() {        let editImg = document.getElementById('edit_pic'),            workImgWidth = 13,            workImgHeight = 13,            copyImg = document.getElementById('copy_pic'),            copyImgWidth = 13,            copyImgHeight = 13;        let InteractionCell = function () {        };        InteractionCell.prototype = new GC.Spread.Sheets.CellTypes.Text();        InteractionCell.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 node = tree.items[options.row];            // Draw Text            GC.Spread.Sheets.CellTypes.Text.prototype.paint.apply(this, arguments);            if (node && (node.data.projType === projectType.tender||node.data.projType === projectType.project)) {                let text = options.sheet.getText(options.row, options.col);                let acStyle = options.sheet.getActualStyle(options.row, options.col),                    zoom = options.sheet.zoom();                let textLength = this.getAutoFitWidth(value, text, acStyle, zoom, {sheet: options.sheet, row: options.row, col: options.col, sheetArea: GC.Spread.Sheets.SheetArea.viewport});                const imgIndent = 5;                let nowX  = Math.floor(x) + textLength + imgIndent,                    nowY = Math.floor((y + (y + h)) / 2) - 7;                if (node.data.allowCooperate) {                    ctx.drawImage(editImg, nowX, nowY, workImgWidth, workImgHeight);                    nowX += workImgWidth;                }                if (node.data.allowCopy) {                    ctx.drawImage(copyImg, nowX, nowY, copyImgWidth, copyImgHeight);                }            }        };        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 = `<i class="fa fa-tablet"> ${node.data.userInfo.mobile ? node.data.userInfo.mobile : ''}</i>`;                        $('#userinfo').find('li:first-child').html(mobileHtml);                        let emailHtml = `<i class="fa fa-envelope-o"> ${node.data.userInfo.email ? node.data.userInfo.email : ''}</i>`;                        $('#userinfo').find('li:last-child').html(emailHtml);                        $('#userinfo').modal('show');                    }                }            }        };        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();    }    function isUnread(unreadList, node) {        if (!unreadList) {            return false;        }        const actualID = node && node.data && node.data.actualTreeInfo && node.data.actualTreeInfo.ID || null;        if (!actualID) {            return false;        }        return !!unreadList.find(ID => ID === actualID);    }    const foreColor = '#007bff';    const dangerColor = '#dc3545';    // 标记已读    // 打开任意的单位工程,都会将其父分享条目标记和自身为已读     // eg:被分享了一个建设项目,和其下一个单位工程,打开该一个单位工程,建设项目标记为已读、该单位工程也标记为已读    function handleMarkRead(unreadList, markReadProjectIDs) {        const col = headers.findIndex(item => item.dataCode === 'shareDate');        const sheet = spreadObj.workBook.getActiveSheet();        const style = new GC.Spread.Sheets.Style();        projTreeObj.renderSheetFuc(sheet, function () {            markReadProjectIDs.forEach(projectID => {                SHARE_TO.removeUnread(projectID, unreadList);                tree.items.forEach(node => {                    if (node.data && node.data.actualTreeInfo && node.data.actualTreeInfo.ID === projectID) {                        const row = node.serialNo();                        sheet.setStyle(row, col, style);                    }                });            });        });    }    //显示树结构数据    //@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, treeCol).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 === 'from'){                        let style = new GC.Spread.Sheets.Style();                        style.foreColor = foreColor;                        sheet.setStyle(i, j, style);                        sheet.getCell(i, j).cellType(getInteractionCell());                    } else if (dataCode === 'shareDate') {                        let style = new GC.Spread.Sheets.Style();                        if (isUnread(unreadShareList, nodes[i])) {                            style.foreColor = dangerColor;                        }                        sheet.setStyle(i, j, style);                    }                    sheet.setValue(i, j, nodes[i].data[dataCode] !== null && typeof nodes[i].data[dataCode] !== 'undefined' ? nodes[i].data[dataCode] : '');                }            }        };        renderSheetFunc(sheet, fuc);    }    // 获取实际树ID为某值的所有节点    function getNodesByActualID(ID, items) {        return items.filter(node => node.data && node.data.actualTreeInfo && node.data.actualTreeInfo.ID === ID);    }    // 刷新显示某些节点    function refreshNodes(nodes, headers) {        const sheet = spreadObj.workBook.getActiveSheet();        const fuc = function(){            for (let i = 0; i < nodes.length; i++) {                const row = nodes[i].serialNo();                for (let j = 0; j < headers.length; j++) {                    const dataCode = headers[j].dataCode;                    if (dataCode === 'from') {                        const style = new GC.Spread.Sheets.Style();                        style.foreColor = foreColor;                        sheet.setStyle(row, j, style);                        sheet.getCell(row, j).cellType(getInteractionCell());                    }                    sheet.setValue(row, j, nodes[i].data[dataCode] !== null && typeof nodes[i].data[dataCode] !== 'undefined' ? nodes[i].data[dataCode] : '');                }            }        };        renderSheetFunc(sheet, fuc);    }    //同一棵树,可能存在相同数据显示多条的问题(传入的datas中不存在相同数据)    //将真实树结构数据存在actualTreeInfo中,外部树结构数据用uuid重置。    //@param {Array}datas    function setTreeInfo(datas) {        let IDMapping = {};        for (let data of datas) {            //项目真实ID与项目分享信息映射,方便确定项目的权限            if (!actualIDShareInfo[data.ID]) {                actualIDShareInfo[data.ID] = {ID: data.ID, ParentID: data.ParentID, NextSiblingID: data.NextSiblingID, shareInfo: data.shareInfo};            }            IDMapping[data.ID] = uuid.v1();        }        for (let data of datas) {            data.actualTreeInfo = {ID: data.ID, ParentID: data.ParentID, NextSiblingID: data.NextSiblingID};            data.ID = IDMapping[data.ID];            data.NextSiblingID = IDMapping[data.NextSiblingID] ? IDMapping[data.NextSiblingID] : -1;            data.ParentID = IDMapping[data.ParentID] ? IDMapping[data.ParentID] : -1;        }    }    //整理同层数据的NextSiblingID,ParentID    //@param {Array}datas {Number || String}pid @return {void}    function sortSameDepthData(datas, pid) {        for (let i = 0; i < datas.length; i++) {            let data = datas[i],                nextData = datas[i + 1];            data.NextSiblingID = nextData ? nextData.ID : -1;            data.ParentID = pid;        }    }    //给项目设置分享信息:由xx分享、分享时间、分享给我,含有userInfo信息的文件为他人直接分享的文件,他人分享父级文件,子文件不含有userInfo信息    //@param {Array}datas @return {void}    function setShareInfo(datas) {        for (let data of datas) {            if (data.userInfo) {                //shareInfo中我的条目                let selfInfo = _.find(data.shareInfo, {userID: userID});                data.shareDate = selfInfo ? selfInfo.shareDate : ''                data.from = data.userInfo.name;                data.to = '分享给 我';                data.cancel = '清除';            }        }    }    //给项目设置汇总信息    //@param {Array}projs {Object}summaryInfo    function setSummaryInfo(grouped, summaryInfo) {        if (!summaryInfo) {            return;        }        let allDatas = [];        for (let data of grouped) {            allDatas.push(data);            if (data.children && data.children.length > 0) {                allDatas = allDatas.concat(data.children);            }        }        for(let proj of allDatas){            let summaryProj = summaryInfo[proj.ID];            if(summaryProj){                proj.engineeringCost = summaryProj.engineeringCost;                proj.subEngineering = summaryProj.subEngineering;                proj.measure = summaryProj.measure;                proj.safetyConstruction = summaryProj.safetyConstruction;                proj.other = summaryProj.other;                proj.charge = summaryProj.charge;                proj.tax = summaryProj.tax;                proj.rate = summaryProj.rate;                proj.buildingArea = summaryProj.buildingArea;                proj.perCost = summaryProj.perCost;            }        }    }    //从同层树数据获取第一个节点ID    //@param {Array}treeDatas树的数据 @return {String}第一个节点的虚拟树ID    function getFirstID(treeDatas) {        let treeMapping = {};        //建立ID索引        for (let data of treeDatas) {            //新建一个简单对象,防止污染treeDatas的数据            treeMapping[data.ID] = {ID: data.ID, prev: null, next: null};        }        //绑定prev next        for (let data of treeDatas) {            let me =  treeMapping[data.ID],                next = treeMapping[data.NextSiblingID];            if (next) {                me.next = next;                next.prev = me;            }        }        //返回没有prev属性的数据        let result = _.find(treeDatas, function (data) {            return !treeMapping[data.ID].prev        });        return  result ? result.ID : -1;    }    //获取可成树的数据    //@param {Array}datas @return {Array}    function getTreeDatas(groupedDatas, ungroupedDatas){        //设置新的树结构数据        for (let data of groupedDatas) {            setTreeInfo([data].concat(data.children));        }        let engs = _.filter(ungroupedDatas, {projType: projectType.engineering}),            tenders = _.filter(ungroupedDatas, {projType: projectType.tender});        for (let data of engs) {            setTreeInfo([data].concat(data.children));        }        setTreeInfo(tenders);        let rst = [];        //整理树结构        sortSameDepthData(groupedDatas, -1);        //第一个根节点数据        let firstID = getFirstID(groupedDatas);        //新建未分类建设项目及单项工程        let ungroupedProj = {ID: uuid.v1(), ParentID: -1, NextSiblingID: firstID, name: '未分类建设项目', projType: projectType.project};        let ungroupedEng = {ID: uuid.v1(), ParentID: ungroupedProj.ID, NextSiblingID: -1, name: '未分类单项工程', projType: projectType.engineering};        //将未分类的数据归类        sortSameDepthData(engs, ungroupedProj.ID);        sortSameDepthData(tenders, ungroupedEng.ID);        //未分类单项工程处于同层第一个节点        ungroupedEng.NextSiblingID = engs[0] ? engs[0].ID : ungroupedEng.NextSiblingID;        let allDatas = groupedDatas.concat(ungroupedDatas);        //设置分享信息及操作信息        setShareInfo(allDatas);        for (let data of allDatas) {            rst.push(data);            if (data.children) {                rst = rst.concat(data.children);            }        }        rst.push(ungroupedProj);        rst.push(ungroupedEng);        return rst;    }    //按照时间排序    //@param {Array}datas @return {void}    function sortByDate(datas){        datas.sort(function (a, b) {            let shareInfoA = _.find(a.shareInfo, {userID}),                shareInfoB = _.find(b.shareInfo, {userID});            let aV = shareInfoA ? Date.parse(shareInfoA.shareDate) : 0,                bV = shareInfoB ? Date.parse(shareInfoB.shareDate) : 0;            //时间越晚越靠前            if (aV > bV) {                return -1;            } else if (aV < bV) {                return 1;            }            return 0;        });    }    //设置节点数据权限    //@param {Array}datas项目数据    function setPermissionsInfo(datas) {        //data.allowCopy与shareInfo里allowCopy的区别:        //data.allowCopy为该单位实际的权限(跟着最新的分享信息走,可能随着父项)        for (let data of datas) {            if(data.projType == projectType.project) data.allowCopy = isAllowCopy(userID, data); //20200715 专业版要求能复制建设项目            if (data.projType === projectType.tender) {                data.allowCopy = isAllowCopy(userID, data);                data.allowCooperate = isAllowCoop(userID, data);            }        }            }    //建立树    //@return void    function initShareTree(){        $.bootstrapLoading.start();        //获取分享数据        CommonAjax.post('/pm/api/receiveProjects', {user_id: userID}, function (rstData) {            actualIDShareInfo = {};            // 排序 --分享的文件按照时间先后顺序排序,分享文件下的子文件,按照原本树结构显示,不需要排序            sortByDate(rstData.grouped);            sortByDate(rstData.ungrouped);            //设置汇总信息            if (rstData.summaryInfo) {                setSummaryInfo(rstData.grouped, rstData.summaryInfo.grouped);                setSummaryInfo(rstData.ungrouped, rstData.summaryInfo.ungrouped);            }            let treeDatas = getTreeDatas(rstData.grouped, rstData.ungrouped);            setPermissionsInfo(treeDatas);            tree = pmTree.createNew(treeSetting, treeDatas);            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.sheet.frozenColumnCount(4);            spreadObj.workBook.refresh();            $.bootstrapLoading.end();        });    }    //初始化右键菜单    function initContextMenu() {        $.contextMenu({            selector: '#shareSpread',            build: function ($trigger, e) {                let target = SheetDataHelper.safeRightClickSelection($trigger, e, spreadObj.workBook);                initSelection({row: target.row, rowCount: 1}, preSelection ? preSelection : null, spreadObj.sheet);                return target.hitTestType === GC.Spread.Sheets.SheetArea.viewport || target.hitTestType === GC.Spread.Sheets.SheetArea.rowHeader;            },            items: {                "copy": {                    name: "拷贝工程",                    icon: 'fa-copy',                    disabled: function () {                        let selected = tree.selected;                        return !(selected && selected.data.allowCopy && selected.data.projType === projectType.tender);                    },                    callback: function (key, opt) {                        $('#copyShare').modal('show');                    }                },                "copyProject": {                  name: "拷贝建设项目",                  icon: 'fa-copy',                  disabled: function () {                      let selected = tree.selected;                      return !(selected && selected.data.allowCopy && selected.data.projType === projectType.project);                  },                  callback: function (key, opt) {                      if($(".p-title").text().includes('免费')){                        hintBox.versionBox('此功能仅在专业版中提供,免费公用版可选择单个分段进行拷贝');                        return;                      }                      copyContructionProject(tree.selected);                  }                },                "cancel": {                    name: "清除",                    icon: 'fa-remove',                    disabled: function () {                        let selected = tree.selected;                        return !(selected && selected.data.cancel && selected.data.cancel === '清除');                    },                    callback: function (key, opt) {                        let $p = $('<p>').text(`点“确定”按钮,确认清除分享文件 “${tree.selected.data.name}”。`);                        $('#cancelShare').find('.modal-body').empty();                        $('#cancelShare').find('.modal-body').append($p);                        $('#cancelShare').modal('show');                    }                }            }        });    }    //初始化视图    //@return void    function initView(){        if(tree){            tree = null;        }        if(spreadObj.workBook){            spreadObj.workBook.destroy();            spreadObj.workBook = null;        }        initContextMenu();        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 = $('<option>').val(eng.ID).text(eng.name);                $('#copyShare_selectEng').append(opt);            }        });    }    //从其他建设项目中复制中,建设项目的文件层次结构名称和顺序    //@param {Array}treeData @return {Array}    function getFileHierarchyInfo(treeData){        curCopySelTree = idTree.createNew({id: 'ID', pid: 'ParentID', nid: 'NextSiblingID', rootId: -1});        curCopySelTree.loadDatas(treeData);        let items = curCopySelTree.items;        let rst = [];        function getFileHierarchyName(node){            let nodeName = node.data.name;            let name = [];            while (node.parent){                name.push(node.parent.data.name ? node.parent.data.name : '');                node = node.parent;            }            name = name.reverse();            name.push(nodeName);            return name.join('\\');        }        for(let node of items){            if(node.children.length === 0 ){//project                rst.push({ID: node.data.ID, fileHierarchyName: getFileHierarchyName(node)})            }        }        return rst;    }    //设置拷贝工程下拉选择    //@return {void}    function setCopyModal(){        //获取建设项目        let projQuery = {$or: [{deleteInfo: null}, {'deleteInfo.deleted': false}], projType: {$in: [projectType.project, projectType.folder]}, userID: userID};        CommonAjax.post('/pm/api/getProjectsByQuery', {user_id: userID, query: projQuery, options: '-_id'}, function (rstData) {            let fileHierarchyData = getFileHierarchyInfo(rstData);            $('#copyShare_selectProj').empty();            for(let proj of fileHierarchyData){                let opt = $('<option>').val(proj.ID).text(proj.fileHierarchyName);                $('#copyShare_selectProj').append(opt);            }            //初始选择            if(fileHierarchyData.length > 0){                setEng(fileHierarchyData[0].ID);            }        });    }    //拷贝分享的工程    //@param {Object}selected {Number}parentID @return {void}    async function copyShareProject(selected, projID, engID){        try {            if(!engID || !selected){                return;            }            let copyMap = {copy: null, update: null};            let newName = getCopyName(selected);            //获取单项工程的单位工程            let tenderQuery = {$or: [{deleteInfo: null}, {'deleteInfo.deleted': false}], userID: userID, ParentID: engID};            const rstData = await ajaxPost('/pm/api/getProjectsByQuery', {user_id: userID, query: tenderQuery, options: '-_id -property'}, false, 10000);            let updateTender = null;            for(let tender of rstData){                if(tender.name === newName){                    $('#copyShare_name').text('已存在此单位工程。');                    $('#copyShare_name').addClass('text-danger');                    return;                }                if(tender.NextSiblingID == -1){                    updateTender = tender;                }            }            //更新前节点            if(updateTender){                copyMap.update = {query: {ID: updateTender.ID}};            }            //拷贝            let copyData = {                userID: userID,                ID: selected.data.actualTreeInfo.ID,                NextSiblingID: -1,                ParentID: engID,                name: newName,                shareInfo: [],                compilation: selected.data.compilation,                createDateTime: selected.data.createDateTime,                fileVer: selected.data.fileVer ? selected.data.fileVer : '',                projType: selected.data.projType,                property: {},                recentDateTime: selected.data.recentDateTime,                fullFolder: selected.data.fullFolder            };            copyData.property.rootProjectID = projID;            copyMap.copy = {document: copyData};            $('#copyShare').modal('hide');            $.bootstrapLoading.progressStart('拷贝项目', true);            $("#progress_modal_body").text('正在拷贝项目,请稍候……');            await ajaxPost('/pm/api/copyProjects', {projectMap: copyMap, user_id: userID, tenderCount: 1});            importProcessChecking(null, null, projTreeObj.emitTreeChange);        } catch (err) {            alert(err);        }    }    //拷贝分享的建设项目    //@param {Object}selected     async function copyContructionProject(selected){      try {        let newName = getCopyName(selected);        //获取单项工程的单位工程        let projectQuery = {$or: [{deleteInfo: null}, {'deleteInfo.deleted': false}], userID: userID,projType: "Project"};        const rstData = await ajaxPost('/pm/api/getProjectsByQuery', {user_id: userID, query: projectQuery, options: '-_id -property'}, false, 10000);        for(let project of rstData){            if(project.name === newName){                alert("已存在此建设项目");                return;            }        }        let tenderCount = 0;        if(selected.children) {          for(let c of selected.children){            if(c.children) tenderCount += c.children.length;          }        }        let key = uuid.v1();        $.bootstrapLoading.progressStart('拷贝建设项目', true);        $("#progress_modal_body").text('正在拷贝建设项目,请稍候……');        await ajaxPost('/pm/api/copyConstructionProject', {user_id: userID, tenderCount: tenderCount,key:key,projectID:selected.data.actualTreeInfo.ID,newName:newName});        importProcessChecking(key, null, projTreeObj.emitTreeChange);      } catch (error) {        console.log(error);      }    }    //获取拷贝后的名称    //@param {Object}node @return {String}    function getCopyName(node) {        //当前单位工程可能没有分享的用户信息,可能他人分享的是父级文件,userInfo在父级文件中        let orgName = node.data.name,            userInfo = node.data.userInfo;        while (node && !userInfo) {            node = node.parent;            userInfo = node.data.userInfo;        }        return `${orgName} (${userInfo.name}分享拷贝)`;    }    //清除了该节点后,可能还有该节点的数据在树上(树允许有重复数据),需要更新分享信息    function updateAfterCancel(userID, projectID) {        for (let item of tree.items) {            if (item.data.actualTreeInfo && item.data.actualTreeInfo.ID === projectID) {                _.remove(item.data.shareInfo, function (data) {                    return data.userID === userID;                });            }        }    }    // 处理节点操作属性变更(是否可拷贝、是否可编辑)    function handlePropChange(projectID, prop) {        const actualShareData = actualIDShareInfo[projectID];        if (actualShareData) {            const shareItem = actualShareData.shareInfo.find(s => s.userID === userID);            if(shareItem) {                Object.assign(shareItem, prop);            }        }        const nodes = getNodesByActualID(projectID, tree.items);        nodes.forEach(node => {            const shareItem = node.data.shareInfo.find(s => s.userID === userID);            if(shareItem) {                Object.assign(shareItem, prop);            }        });        const treeData = tree.items.map(item => item.data);        setPermissionsInfo(treeData);        showTreeData(tree.items, headers);    }    // 处理清除    /* function handleCancelShare(cancelProjID, callback) {        $.bootstrapLoading.start();        CommonAjax.post('/pm/api/share', {user_id: userID, type: oprType.cancel,  projectID: cancelProjID, shareData:[{userID: userID}]}, function (rstData) {            const node = tree.items.find(item => item.data.actualTreeInfo && item.data.actualTreeInfo.ID === cancelProjID);            if (node) {                tree.removeNode(node);            }            //更新与清除节点数据相同,且未被清除缓存分享信息            updateAfterCancel(userID, cancelProjID);            //重新设置actualIDShareInfo,以正确更新权限(清除了分享信息后,可能会导致权限变化 eg:清除了新的分享,则存留的分享项目采用旧的)            actualIDShareInfo = {};            let treeDatas = [];            for (let item of tree.items) {                treeDatas.push(item.data);                let actualTreeInfo = item.data.actualTreeInfo;                if (actualTreeInfo && !actualIDShareInfo[actualTreeInfo.ID]) {                    actualIDShareInfo[actualTreeInfo.ID] = {                        ID: actualTreeInfo.ID,                        ParentID: actualTreeInfo.ParentID,                        NextSiblingID: actualTreeInfo.NextSiblingID,                        shareInfo: item.data.shareInfo                    };                }            }            //重新设置权限            setPermissionsInfo(treeDatas);            showTreeData(tree.items, headers);            $.bootstrapLoading.end();            if (callback) {                callback(rstData);            }        }, function () {            $.bootstrapLoading.end();        });    } */    function handleCancelShare(cancelProjID) {        const node = tree.items.find(item => item.data.actualTreeInfo && item.data.actualTreeInfo.ID === cancelProjID);        if (node) {            tree.removeNode(node);        }        //更新与清除节点数据相同,且未被清除缓存分享信息        updateAfterCancel(userID, cancelProjID);        //重新设置actualIDShareInfo,以正确更新权限(清除了分享信息后,可能会导致权限变化 eg:清除了新的分享,则存留的分享项目采用旧的)        actualIDShareInfo = {};        let treeDatas = [];        for (let item of tree.items) {            treeDatas.push(item.data);            let actualTreeInfo = item.data.actualTreeInfo;            if (actualTreeInfo && !actualIDShareInfo[actualTreeInfo.ID]) {                actualIDShareInfo[actualTreeInfo.ID] = {                    ID: actualTreeInfo.ID,                    ParentID: actualTreeInfo.ParentID,                    NextSiblingID: actualTreeInfo.NextSiblingID,                    shareInfo: item.data.shareInfo                };            }        }        //重新设置权限        setPermissionsInfo(treeDatas);        showTreeData(tree.items, headers);    }    //事件监听器    //@return void    function eventListener(){        //tab        $('#tab_pm_share').on('shown.bs.tab', function () {            //侧滑隐藏            $('.slide-sidebar').removeClass('open');            $('.slide-sidebar').css('width', '0');            projTreeObj.tree = null;            if(projTreeObj.workBook){                projTreeObj.workBook.destroy();                projTreeObj.workBook = null;            }            gcTreeObj.tree = null;            if(gcTreeObj.workBook){                gcTreeObj.workBook.destroy();                gcTreeObj.workBook = null;            }            initView();        });        //关闭拷贝工程        $('#copyShare').on('hidden.bs.modal', function () {            $('#copyShareProj-info').hide();            $('#copyShareEng-info').hide();        });        //打开拷贝工程        $('#copyShare').on('shown.bs.modal', function () {            setCopyModal();            //更改显示名称            let newName = getCopyName(shareSeleted);            $('#copyShare_name').html(`拷贝后,工程将重命名为 "<b>${newName}</b>"`);            $('#copyShare_name').removeClass('text-danger');        });        //拷贝工程改变选择建设项目        $('#copyShare_selectProj').change(function () {            //更改显示名称            let newName = getCopyName(shareSeleted);            $('#copyShare_name').html(`拷贝后,工程将重命名为 "<b>${newName}</b>"`);            $('#copyShare_name').removeClass('text-danger');            $('#copyShareProj-info').hide();            $('#copyShareEng-info').hide();            let curSelID = $(this).select().val();            setEng(parseInt(curSelID));        });        //拷贝工程改变选择单项工程        $('#copyShare_selectEng').change(function () {            //更改显示名称            let newName = getCopyName(shareSeleted);            $('#copyShare_name').html(`拷贝后,工程将重命名为 "<b>${newName}</b>"`);            $('#copyShare_name').removeClass('text-danger');        });        //确认拷贝        $('#copyShare_confirm').click(function () {            let selProj = $('#copyShare_selectProj').select().val();            if(!selProj){                $('#copyShareProj-info').show();                return;            }            //目标建设项目的计税方法与单位工程的一致时,才可拷贝            if (curCopySelTree) {                let projectNode = curCopySelTree.nodes[curCopySelTree.prefix + selProj];                if (!projectNode || !projectNode.data.property || projectNode.data.property.taxType != tree.selected.data.taxType){                    alert('当前单位工程计税方法与目标建设项目不一致,不可复制。');                    return;                }            }            let selEng = $('#copyShare_selectEng').select().val();            if(!selEng){                $('#copyShareEng-info').show();                return;            }            copyShareProject(tree.selected, parseInt(selProj), parseInt(selEng));        });        //清除分享        $('#cancelShareConfirm').click(function (data) {            $.bootstrapLoading.start();            const cancelProjID = tree.selected.data.actualTreeInfo.ID;            const permissionType = commonConstants.SharePermissionChangeType.CANCEL;            CommonAjax.post('/pm/api/share', { user_id: userID, type: oprType.cancel, permissionType, projectID: cancelProjID, shareData: [{ userID: userID }] }, function (rstData) {                handleCancelShare(cancelProjID);                // 推送已打开的项目,通知已取消分享                SHARE_TO.emitPermissionChange(permissionType, userID, cancelProjID, rstData.emitTenders);                // 清除已读                SHARE_TO.removeUnread(cancelProjID, unreadShareList);                $.bootstrapLoading.end();            }, function () {                $.bootstrapLoading.end();            });        });    }    return {        spreadObj,         headers,         initView,         eventListener,         initShareTree,         handlePropChange,        handleCancelShare,        handleMarkRead    }})();$(document).ready(function () {    pmShare.eventListener();});
 |