Browse Source

Merge branch '1.0.0_online' of http://smartcost.f3322.net:3000/SmartCost/ConstructionCost into 1.0.0_online

zhangweicheng 6 năm trước cách đây
mục cha
commit
e66a99717a

+ 1 - 0
modules/all_models/projects.js

@@ -10,6 +10,7 @@ const collectionName = 'projects';
 const shareSchema = new Schema({
     userID: String, //userID
     allowCopy: {type: Boolean, default: false},
+    allowCooperate: {type: Boolean, default: false},
     shareDate: String,
 }, {versionKey: false, _id: false});
 const ProjectSchema = new Schema({

+ 8 - 7
modules/main/routes/main_route.js

@@ -11,16 +11,16 @@ module.exports =function (app) {
     app.get('/main', baseController.init, function(req, res) {
         let pm = require('../../pm/controllers/pm_controller');
 
-        pm.checkProjectRight(req.session.sessionUser.id, req.query.project, async function (hasRight) {
+        pm.checkProjectRight(req.session.sessionUser.id, req.query.project, async function (hasRight, projectData, shareInfo) {
             if (hasRight) {
-                // 获取项目信息
-                const projectId = req.query.project;
-                const projectData = await projectModel.project.getProject(projectId);
-                //分享的项目,只读
-                let projectReadOnly = false;
+                //分享的项目,只读、协作(允许编辑)
+                let projectReadOnly = false,
+                    projectCooperate = false;
                 if(req.session.sessionUser.id !== projectData.userID){
                     projectData._doc.readOnly = true;
-                    projectReadOnly = true;
+                    projectCooperate = !!shareInfo.allowCooperate;
+                    //允许协作的项目允许编辑,非只读
+                    projectReadOnly = !projectCooperate;
                 }
                 res.render('building_saas/main/html/main.html',
                     {
@@ -30,6 +30,7 @@ module.exports =function (app) {
                         compilationName: req.session.sessionCompilation.name,
                         versionName: `纵横建筑云计价(${req.session.compilationVersion})`,
                         projectReadOnly: projectReadOnly,
+                        projectCooperate: projectCooperate,
                         LicenseKey:config.getLicenseKey(process.env.NODE_ENV),
                         overWriteUrl:req.session.sessionCompilation.overWriteUrl
                     });

+ 8 - 8
modules/pm/controllers/pm_controller.js

@@ -52,13 +52,13 @@ module.exports = {
              * result._doc.userID(Number): MongoDB
              * userId(String): Session.userID
              */
-            let isShare = false;
-            //判断是否是打开分享的项目
+            let shareInfo = null;
+            //判断是否是打开分享的项目,分享项目shareInfo不为null
             if(userId !== result.userID){
-                isShare = await pm_facade.isShare(userId, result);
+                shareInfo = await pm_facade.getShareInfo(userId, result);
             }
-            if ((userId === result.userID || isShare) && result._doc.projType === projType.tender) {
-                callback(true);
+            if ((userId === result.userID || shareInfo) && result._doc.projType === projType.tender) {
+                callback(true, result, shareInfo);
             } else {
                 callback(false);
             }
@@ -67,8 +67,6 @@ module.exports = {
         });
     },
     getProjects: async function(req, res){
-        console.log(`req.session.sessionCompilation`);
-        console.log(req.session.sessionCompilation);
          await ProjectsData.getUserProjects(req.session.sessionUser.id, req.session.sessionCompilation._id, function(err, message, projects){
             if (projects) {
                 callback(req, res, err, message, projects);
@@ -536,12 +534,14 @@ module.exports = {
                 for (let sData of data.shareData) {
                     await projectModel.update({ID: data.projectID, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]}, {$addToSet: {shareInfo: sData}});
                 }
+            } else if (data.type === 'update') {
+                await projectModel.update({ID: data.projectID, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]}, {$set: {shareInfo: data.shareData}});
             }
             //取消分享
             else {
                 await projectModel.update({ID: data.projectID, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]}, {$pull: {shareInfo: {userID: {$in: shareUserIDs}}}});
             }
-            callback(req, res, 0, 'success', null);
+            callback(req, res, 0, 'success', data.shareData);
         }
         catch (err){
             callback(req, res, 1, err, null);

+ 29 - 0
modules/pm/facade/pm_facade.js

@@ -57,6 +57,7 @@ module.exports={
     projectType: projectType,
     getPosterityProjects: getPosterityProjects,
     isShare: isShare,
+    getShareInfo: getShareInfo,
     prepareInitialData: prepareInitialData,
 };
 
@@ -872,6 +873,34 @@ async function getPosterityProjects(projectIDs) {
     return rst;
 }
 
+//根据项目获得分享信息(分享层级不一定在项目级)(以最新为准)
+//@param {String}userId {Object}tender @return {Object} || {null}
+async function getShareInfo(userId, project) {
+    //与该用户相关的分享
+    let shareList = [];
+    while (project) {
+        for(let shareData of project.shareInfo){
+            if(shareData.userID === userId){
+                shareList.push(shareData);
+                break;
+            }
+        }
+        project = await projectModel.findOne({ID: project.ParentID}, '-_id shareInfo ID ParentID');
+    }
+    //获取最新分享
+    shareList.sort(function (a, b) {
+        let aV = Date.parse(a.shareDate),
+            bV = Date.parse(b.shareDate);
+        if (aV > bV) {
+            return -1;
+        } else if (aV < bV) {
+            return 1;
+        }
+        return 0;
+    });
+    return shareList[0] || null;
+}
+
 //打开的单位工程是否是被分享的.
 async function isShare(userId, project){
     //判断是否是打开分享的项目,属于分享文件的子项也算

+ 1 - 3
public/web/slideResize.js

@@ -18,7 +18,7 @@ const SlideResize = (function() {
     //设置水平拖动条的宽度
     //@param {Object dom}resize滚动条
     function setResizeWidth (resize) {
-        const fixedWidth = 10;
+        const fixedWidth = 5;
         //滚动条节点 及 同层非滚动条节点的索引
         let bros = resize.parent().children();
         let index = bros.index(resize),
@@ -156,8 +156,6 @@ const SlideResize = (function() {
                 eleObj.topSpread.height(topChange - limit.notTopSpread);
                 //设置下部分div高度
                 eleObj.bottom.height(bottomChange);
-                console.log(eleObj.bottom);
-                console.log(bottomChange);
                 //设置下部分div内spread高度
                 eleObj.bottomSpread.height(bottomChange - limit.notBottomSpread);
                 mouseMoveCount += Math.abs(moveSize);

+ 1 - 1
web/building_saas/complementary_ration_lib/html/dinge.html

@@ -19,7 +19,7 @@
     <link rel="icon" type="image/gif" href="/web/building_saas/css/animated_favicon1.gif">
     <style type="text/css">
         div.resize-y{
-            height: 10px;
+            height: 5px;
             background: #efefef;
             width: 100%;
             cursor: s-resize;

+ 2 - 2
web/building_saas/complementary_ration_lib/js/coe.js

@@ -147,8 +147,8 @@ function getZmhsAdjResize() {
     };
     zmhsAdjResize.limit = {
         min: 150,
-        max: `$(window).height()-$('.header').height()-150-10`,
-        totalHeight: `$(window).height()-$('.header').height()-10`,
+        max: `$(window).height()-$('.header').height()-150-5`,
+        totalHeight: `$(window).height()-$('.header').height()-5`,
         notTopSpread: 0,
         notBottomSpread: 0,
     };

+ 1 - 1
web/building_saas/complementary_ration_lib/js/gljSelect.js

@@ -136,7 +136,7 @@ let gljSelOprObj = {
                 }
                 if(!isExist){
                     thisGlj.consumeAmt = 0;
-                    me.selectedList.push(thisGlj);
+                    me.selectedList.push(_.cloneDeep(thisGlj));
                 }
             }
             else if(val === false){

+ 2 - 2
web/building_saas/complementary_ration_lib/js/ration.js

@@ -34,8 +34,8 @@ function getRationSubResize() {
     };
     rationSubResize.limit = {
         min: 150,
-        max: `$(window).height()-$('.header').height()-$('.tools-bar').height()-150-10`,
-        totalHeight: `$(window).height()-$('.header').height()-$('.tools-bar').height()-10`,
+        max: `$(window).height()-$('.header').height()-$('.tools-bar').height()-150-5`,
+        totalHeight: `$(window).height()-$('.header').height()-$('.tools-bar').height()-5`,
         notTopSpread: 0,
         notBottomSpread: $('#subContent ul').height(),
     };

+ 1 - 1
web/building_saas/css/custom.css

@@ -16,7 +16,7 @@ div.resize{
     cursor: s-resize;
 }
 div.resize-y{
-    height: 10px;
+    height: 5px;
     background: #efefef;
     width: 100%;
     cursor: s-resize;

+ 1 - 0
web/building_saas/main/html/calc_program_manage.html

@@ -14,6 +14,7 @@
     </div>
     <div class="toolsbar px-1" />
     <div class="container-fluid">
+        <div style="height:35px;width:100%;line-height:35px;font-size:15px;">总计算程序-设置</div>
         <div class="row">
             <div class="col-lg-2 p-0">
 <!--                <div id="divSelect" style="text-align:left;height:45px;line-height:45px;">

+ 2 - 0
web/building_saas/main/html/main.html

@@ -39,6 +39,8 @@
         let userAccount = '<%- userAccount %>';
         let userID = '<%- userID %>';
         let projectReadOnly = JSON.parse('<%- projectReadOnly %>');
+        let projectCooperate = JSON.parse('<%- projectCooperate %>');
+        console.log(projectCooperate);
         const G_SHOW_BLOCK_LIB = true;
 //        const G_SHOW_BLOCK_LIB = false;
     </script>

+ 2 - 2
web/building_saas/main/js/main.js

@@ -60,10 +60,10 @@ function getMainResizeEles() {
     };
     mainResizeEles.limit = {
         min: 180,
-        max: `$(window).height()-$('.header').height()-$('#headerToolsBar').height()-180-10`,
+        max: `$(window).height()-$('.header').height()-$('#headerToolsBar').height()-180-5`,
         notTopSpread: 0,
         notBottomSpread: $('#bottom_div ul').height(),
-        totalHeight: `$(window).height()-$('.header').height()-$('#headerToolsBar').height()-10`
+        totalHeight: `$(window).height()-$('.header').height()-$('#headerToolsBar').height()-5`
     };
     return mainResizeEles;
 }

+ 1 - 1
web/building_saas/main/js/models/main_consts.js

@@ -145,7 +145,7 @@ const rationFrom = {
     std: 'std',
     cpt: 'cpt'
 };
-const leafBillGetFeeType = {
+let leafBillGetFeeType = {
     rationContent: 0,
     rationPriceConverse: 1,
     rationPrice: 2,

+ 46 - 24
web/building_saas/main/js/views/calc_program_manage.js

@@ -6,6 +6,8 @@ let calcProgramManage = {
     datas: [],
     mainSpread: null,
     detailSpread: null,
+    mainSheet: null,
+    detailSheet: null,
     mainSetting: {
         header:[
             // {headerName:"ID",headerWidth:80,dataCode:"ID", hAlign: "center"},
@@ -49,30 +51,30 @@ let calcProgramManage = {
             me.detailSpread = null;
         };
         me.mainSpread = sheetCommonObj.buildSheet($('#mainSpread')[0], me.mainSetting, me.datas.length);
+        me.mainSheet = me.mainSpread.getSheet(0);
         sheetCommonObj.spreadDefaultStyle(me.mainSpread);
         me.detailSpread = sheetCommonObj.buildSheet($('#detailSpread')[0], me.detailSetting, me.datas[0].calcItems.length);
+        me.detailSheet = me.detailSpread.getSheet(0);
         sheetCommonObj.spreadDefaultStyle(me.detailSpread);
         let arr = projectObj.project.calcProgram.compiledFeeTypeNames.slice();
         // arr.delete('暂估费');
         let fieldName = new GC.Spread.Sheets.CellTypes.ComboBox();
         fieldName.items(arr);
-        me.detailSpread.getSheet(0).getRange(-1, 4, -1, 1).cellType(fieldName);
+        me.detailSheet.getRange(-1, 4, -1, 1).cellType(fieldName);
 
-        me.mainSpread.getSheet(0).bind(GC.Spread.Sheets.Events.EnterCell, me.onMainEnterCell);
-        me.detailSpread.getSheet(0).bind(GC.Spread.Sheets.Events.ValueChanged, me.onDetailValueChanged);
-        me.detailSpread.getSheet(0).bind(GC.Spread.Sheets.Events.RangeChanged, me.onRangeChanged);
-        me.detailSpread.getSheet(0).bind(GC.Spread.Sheets.Events.EnterCell, me.onDetailEnterCell);
-        me.detailSpread.getSheet(0).bind(GC.Spread.Sheets.Events.ClipboardPasting, me.onClipboardPasting);
+        me.mainSheet.bind(GC.Spread.Sheets.Events.EnterCell, me.onMainEnterCell);
+        me.detailSheet.bind(GC.Spread.Sheets.Events.ValueChanged, me.onDetailValueChanged);
+        me.detailSheet.bind(GC.Spread.Sheets.Events.RangeChanged, me.onRangeChanged);
+        me.detailSheet.bind(GC.Spread.Sheets.Events.EnterCell, me.onDetailEnterCell);
+        me.detailSheet.bind(GC.Spread.Sheets.Events.ClipboardPasting, me.onClipboardPasting);
+        sheetCommonObj.showData(me.mainSheet, me.mainSetting, me.datas);
 
-        let mSheet = me.mainSpread.getSheet(0);
-        sheetCommonObj.showData(mSheet, me.mainSetting, me.datas);
-
-        let dSheet = me.detailSpread.getSheet(0);
-        dSheet.name('calc_detail');
-        feeRateObject.setFeeRateCellCol(dSheet,_.findIndex(me.detailSetting.header,{'dataCode':'feeRate'}));
-        dSheet.getRange(-1, _.findIndex(me.detailSetting.header, {'dataCode': 'dispExprUser'}), -1, 1).cellType(calcBaseView.getCalcBaseCellType('ration'));
-        sheetCommonObj.showData(dSheet, me.detailSetting, me.datas[0].calcItems);
-        customRowHeader(dSheet, me.datas[0].calcItems.length);
+        me.detailSheet.name('calc_detail');
+        feeRateObject.setFeeRateCellCol(me.detailSheet, _.findIndex(me.detailSetting.header,{'dataCode':'feeRate'}));
+        me.detailSheet.getRange(-1, _.findIndex(me.detailSetting.header, {'dataCode': 'dispExprUser'}), -1, 1).cellType(calcBaseView.getCalcBaseCellType('ration'));
+        sheetCommonObj.showData(me.detailSheet, me.detailSetting, me.datas[0].calcItems);
+        me.getfeeRateColor(me.datas[0].calcItems);
+        customRowHeader(me.detailSheet, me.datas[0].calcItems.length);
         if(!projectReadOnly){
             me.loadMainContextMenu();
             me.loadDetailContextMenu();
@@ -109,11 +111,11 @@ let calcProgramManage = {
         var row = args.sheet.getActiveRowIndex();
 
         me.detailSpread.suspendPaint();
-        var dSheet = me.detailSpread.getSheet(0);
         var dData = me.datas[row].calcItems;
-        dSheet.setRowCount(dData.length, GC.Spread.Sheets.SheetArea.viewport);
-        sheetCommonObj.showData(dSheet, me.detailSetting, dData);
-        customRowHeader(dSheet, dData.length);
+        me.detailSheet.setRowCount(dData.length, GC.Spread.Sheets.SheetArea.viewport);
+        sheetCommonObj.showData(me.detailSheet, me.detailSetting, dData);
+        me.getfeeRateColor(dData);
+        customRowHeader(me.detailSheet, dData.length);
         me.detailSpread.resumePaint();
     },
     onRangeChanged:function (sender,args) {
@@ -254,14 +256,20 @@ let calcProgramManage = {
                         newTemplate.custom = true;
                         newTemplate.calcItems = [];
                         $.extend(true, newTemplate.calcItems, template.calcItems);
+                        // 清理掉费率ID关联
+                        for (let ci of newTemplate.calcItems){
+                            if (ci.feeRateID || ci.feeRateID == null)
+                                delete ci.feeRateID;
+                        };
 
                         let data = {
                             'projectID': projectObj.project.ID(),
                             'ID': newTemplate.ID,
                             'name': newTemplate.name,
                             'custom': newTemplate.custom,
-                            'calcItems': template.calcItems
+                            'calcItems': newTemplate.calcItems
                         };
+
                         calcProgramManage.addTemplate(data, function (rst) {
                             if (rst){
                                 let ts = projectObj.project.calcProgram.templates;
@@ -269,11 +277,12 @@ let calcProgramManage = {
                                 projectObj.project.calcProgram.compileTemplateMaps();
                                 projectObj.project.calcProgram.compileTemplate(newTemplate);
                                 calcProgramManage.buildSheet();
-                                calcProgramManage.mainSpread.getActiveSheet().setSelection(ts.length - 1, 0, 1, 1);
+                                calcProgramManage.mainSheet.setSelection(ts.length - 1, 0, 1, 1);
+                                calcProgramManage.mainSheet.showRow(ts.length - 1, GC.Spread.Sheets.VerticalPosition.center);
                                 calcProgramManage.refreshDetailSheet();
+                                $.bootstrapLoading.end();
                             }
                         });
-                        $.bootstrapLoading.end();
                     }
                 },
                 "reNameTemplate": {
@@ -335,6 +344,7 @@ let calcProgramManage = {
                         return !canDelete;
                     },
                     callback: function () {
+                        $.bootstrapLoading.start();
                         let template = calcProgramManage.getSelectionInfo().template;
                         if (analyzer.templateIsUsed(template.ID)) {
                             $.bootstrapLoading.end();
@@ -349,12 +359,14 @@ let calcProgramManage = {
                             };
                             calcProgramManage.deleteTemplate(data, function (rst) {
                                 if (rst){
-                                    let idx = calcProgramManage.mainSpread.getActiveSheet().getActiveRowIndex();
+                                    let idx = calcProgramManage.mainSheet.getActiveRowIndex();
                                     projectObj.project.calcProgram.templates.splice(idx, 1);
                                     projectObj.project.calcProgram.compileTemplateMaps();
                                     calcProgramManage.buildSheet();
-                                    calcProgramManage.mainSpread.getActiveSheet().setSelection(idx - 1, 0, 1, 1);
+                                    calcProgramManage.mainSheet.setSelection(idx - 1, 0, 1, 1);
+                                    calcProgramManage.mainSheet.showRow(idx - 1, GC.Spread.Sheets.VerticalPosition.center);
                                     calcProgramManage.refreshDetailSheet();
+                                    $.bootstrapLoading.end();
                                 }
                             });
                         };
@@ -505,8 +517,18 @@ let calcProgramManage = {
             let detailSheet = me.detailSpread.getActiveSheet();
             detailSheet.setRowCount(calcItems.length);
             sheetCommonObj.showData(detailSheet, me.detailSetting, calcItems);
+            me.getfeeRateColor(calcItems);
             customRowHeader(detailSheet, calcItems.length);
         }
+    },
+    getfeeRateColor: function (calcItems) {    // 有费率ID关联的变个色
+        var me = this;
+        for (let i = 0; i < calcItems.length; i++) {
+            if (calcItems[i].feeRateID != undefined && calcItems[i].feeRateID != null)
+                me.detailSheet.getCell(i, 3).foreColor("#0aa8ea")
+            else
+                me.detailSheet.getCell(i, 3).foreColor("black");
+        }
     }
 };
 

+ 3 - 3
web/building_saas/main/js/views/project_glj_view.js

@@ -1081,10 +1081,10 @@ function getProjectResizeEles() {
     };
     pojGljResizeEles.limit = {
         min: 150,
-        max: `$(window).height()-$('.header').height()-$('#projectGljToolsBar').height()-150-10`,//10: resize.height()
+        max: `$(window).height()-$('.header').height()-$('#projectGljToolsBar').height()-150-5`,//5: resize.height()
         notTopSpread: 0,
-        notBottomSpread: $('#projectGljBottom ul').height(),
-        totalHeight: `$(window).height()-$('.header').height()-$('#projectGljToolsBar').height()-10`
+        notBottomSpread: 0,
+        totalHeight: `$(window).height()-$('.header').height()-$('#projectGljToolsBar').height()-5`
     };
     return pojGljResizeEles;
 }

+ 4 - 1
web/building_saas/main/js/views/project_info.js

@@ -19,8 +19,11 @@ var projectInfoObj = {
                 <span class="text-muted px-1">\</span>
                  <span><i class="fa fa-sticky-note-o"></i></span>
                 <span class="text-truncate"  data-toggle="tooltip" data-placement="bottom" data-original-title="${proj.name}">&nbsp;${proj.name}</span>
-                ${projectReadOnly ? '' +
+                ${projectReadOnly ?
                 '<span data-toggle="tooltip" data-placement="bottom" data-original-title="当前的工程状态为“只读”,如果要进行编辑,请在项目管理-分享界面,使用“拷贝工程”功能。">(只读)</span>' 
+                : ''}
+                ${projectCooperate ? 
+                '<span data-toggle="tooltip" data-placement="bottom" data-original-title="当前的工程状态为“协作”,可直接编辑分享人的原始数据。">(协作)</span>'
                 : ''}`;
             fullPath.push(newHtml);
 

+ 12 - 5
web/building_saas/main/js/views/project_view.js

@@ -1,7 +1,6 @@
 /**
  * Created by Mai on 2017/6/21.
  */
-
 var projectObj = {
     project: null,
     mainSpread: null,
@@ -1315,8 +1314,6 @@ var projectObj = {
                         if (projectReadOnly) {
                             return true;
                         }
-                        // var selected = project.mainTree.selected;
-                        // return project.Ration.addRationChecking(selected);  // Vincent, 2018-01-02
                         return !project.Ration.canAdd(project.mainTree.selected);
                     },
                     callback: function (key, opt) {
@@ -1356,6 +1353,13 @@ var projectObj = {
                         insertEquipment:{
                             name:"设备" ,
                             icon: 'fa-sign-in',
+                            visible: function () {
+                                if (typeof isCQ2018 != 'undefined') {
+                                    return false;
+                                }else{
+                                    return true;
+                                }
+                            },
                             callback:function(key){
                                 project.Ration.insertVolumePrice(gljType.EQUIPMENT);
                             }
@@ -2283,8 +2287,11 @@ $('#poj-set').on('show.bs.modal', function () {
         }
     }
     if (projectObj.project) {
-        let ft = projectObj.project.property.billsCalcMode ? projectObj.project.property.billsCalcMode : leafBillGetFeeType.rationContent;
-        let zg = projectObj.project.property.zanguCalcMode ? projectObj.project.property.zanguCalcMode : zanguCalcType.common;
+        //江西重定义了leafBillGetFeeType的内容
+        let ft = projectObj.project.property.billsCalcMode !== undefined &&
+                 projectObj.project.property.billsCalcMode !== null ? projectObj.project.property.billsCalcMode : leafBillGetFeeType.rationContent;
+        let zg = projectObj.project.property.zanguCalcMode !== undefined &&
+                 projectObj.project.property.zanguCalcMode !== null ? projectObj.project.property.zanguCalcMode : zanguCalcType.common;
         setCalcFlag($('#rationContent'), leafBillGetFeeType.rationContent, ft);
         setCalcFlag($('#rationPriceConverse'), leafBillGetFeeType.rationPriceConverse, ft);
         setCalcFlag($('#rationPrice'), leafBillGetFeeType.rationPrice, ft);

+ 9 - 9
web/building_saas/main/js/views/side_tools.js

@@ -60,10 +60,10 @@ rationLibResizeEles.eleObj = {
 };
 rationLibResizeEles.limit = {
     min: 150,
-    max: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#deToolsBar').height()-150-10`,//10: resize.height()
+    max: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#deToolsBar').height()-150-5`,//5: resize.height()
     notTopSpread: 0,
     notBottomSpread: 0,
-    totalHeight: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#deToolsBar').height()-10`
+    totalHeight: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#deToolsBar').height()-5`
 };
 SlideResize.verticalSlide(rationLibResizeEles.eleObj, rationLibResizeEles.limit, function () {
     rationLibObj.refreshSpread();
@@ -82,10 +82,10 @@ function getLocateLibResize(){
     };
     resizeObj.limit = {
         min: 150,
-        max: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#searchPanel').height()-150-10`,//10: resize.height()
+        max: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#searchPanel').height()-150-5`,//5: resize.height()
         notTopSpread: 0,
         notBottomSpread: 0,
-        totalHeight: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#searchPanel').height()-10`
+        totalHeight: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#searchPanel').height()-5`
     };
     return resizeObj;
 }
@@ -106,10 +106,10 @@ blockLibTopMid.eleObj = {
 };
 blockLibTopMid.limit = {
     min: 100,
-    max: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#kmbkToolsBar').height()-$('#kmbkBottomDiv').height()-100-10*2`,
+    max: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#kmbkToolsBar').height()-$('#kmbkBottomDiv').height()-100-5*2`,
     notTopSpread: 0,
     notBottomSpread: 0,
-    totalHeight: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#kmbkToolsBar').height()-$('#kmbkBottomDiv').height()-10*2` //10: resize.height()
+    totalHeight: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#kmbkToolsBar').height()-$('#kmbkBottomDiv').height()-5*2` //5: resize.height()
 };
 SlideResize.verticalSlide(blockLibTopMid.eleObj, blockLibTopMid.limit, function () {
     blockLibObj.refreshSpread();
@@ -127,10 +127,10 @@ blockLibMidBottom.eleObj = {
 };
 blockLibMidBottom.limit = {
     min: 100,
-    max: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#kmbkToolsBar').height()-$('#kmbkTopDiv').height()-100-10*2`,
+    max: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#kmbkToolsBar').height()-$('#kmbkTopDiv').height()-100-5*2`,
     notTopSpread: 0,
     notBottomSpread: 0,
-    totalHeight: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#kmbkToolsBar').height()-$('#kmbkTopDiv').height()-10*2` //10: resize.height()
+    totalHeight: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#kmbkToolsBar').height()-$('#kmbkTopDiv').height()-5*2` //5: resize.height()
 };
 SlideResize.verticalSlide(blockLibMidBottom.eleObj, blockLibMidBottom.limit, function () {
     blockLibObj.refreshSpread();
@@ -144,7 +144,7 @@ let blockLibMulti = {
         {container: $('#kmbkMidDiv'), spread: $('#div_block_bill'), notSpread: 0, defaultProportion: 0.15},
         {container: $('#kmbkBottomDiv'), spread: $('#div_block_ration'), notSpread: 0, defaultProportion: 0.25},
     ],
-    totalHeight: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#kmbkToolsBar').height()-10*2`
+    totalHeight: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#kmbkToolsBar').height()-5*2`
 };
 
 //加载各库内部上下高度(有的库需要上下拖动)

+ 7 - 4
web/building_saas/pm/html/project-management.html

@@ -48,6 +48,8 @@
 <img src="/web/dest/css/img/tender.png" id="tender_pic" style="display: none">
 <img src="/web/dest/css/img/refresh.png" id="refresh_pic" style="display: none">
 <img src="/web/dest/css/img/share.png" id="share_pic" style="display: none">
+<img src="/web/dest/css/img/copy.png" id="copy_pic" style="display: none">
+<img src="/web/dest/css/img/work.png" id="work_pic" style="display: none">
 <div class="header">
     <div class="top-msg clearfix">
         <div class="alert alert-warning mb-0 py-0" role="alert" style="display: none;">
@@ -77,9 +79,9 @@
                         <li class="nav-item" data-original-title="全部" data-placement="right" data-toggle="tooltip">
                             <a class="nav-link active" href="#pm_all" role="tab" id="tab_pm_all" data-toggle="tab"><i class="fa fa-bars"></i></a>
                         </li>
-                        <li class="nav-item" data-original-title="最近使用" data-placement="right" data-toggle="tooltip">
+                        <!--<li class="nav-item" data-original-title="最近使用" data-placement="right" data-toggle="tooltip">
                             <a class="nav-link" href="javascript:void(0);"><i class="fa fa-bookmark"></i></a>
-                        </li>
+                        </li>-->
                         <li class="nav-item" data-original-title="分享" data-placement="right" data-toggle="tooltip">
                             <a class="nav-link" href="#pm_share" id="tab_pm_share" data-toggle="tab"><i class="fa fa-share-alt"></i></a>
                         </li>
@@ -727,8 +729,8 @@
                 </div>
                 <table class="table table-sm" id="shareFindDiv">
                     <tbody style="display: block">
-                    <tr><th style="width: 112px;">姓名</th><th style="width: 165px;">公司</th><th style="width: 136px;">手机</th><th style="width: 160px;">邮箱</th><th style="width: 90px;">允许拷贝</th><th style="width: 90px;">添加分享</th></tr>
-                    <tr><td id="user_name">张三</td><td id="user_company">XX公司</td><td id="user_mobile">12345678900</td><td id="user_email"></td><td><input id="allowCopy" type="checkbox"></td><td><a id="share-confirm" href="javascript:void(0)" class="btn btn-sm btn-primary">添加分享</a></td></tr>
+                    <tr><th style="width: 112px;">姓名</th><th style="width: 165px;">公司</th><th style="width: 136px;">手机</th><th style="width: 160px;">邮箱</th><th style="width: 90px;">允许拷贝</th><th style="width: 90px;">允许协作</th><th style="width: 90px;">添加分享</th></tr>
+                    <tr><td id="user_name">张三</td><td id="user_company">XX公司</td><td id="user_mobile">12345678900</td><td id="user_email"></td><td><input id="allowCopy" type="checkbox"></td><td><input id="allowCooperate" type="checkbox"></td><td><a id="share-confirm" href="javascript:void(0)" class="btn btn-sm btn-primary">添加分享</a></td></tr>
                     </tbody>
                 </table>
                 <p id="share-info" class="text-danger">不存在手机号 15812777651 的用户</p>
@@ -899,5 +901,6 @@
     let engineeringList = '<%- engineeringList %>';
     let compilationData = '<%- compilationData %>';
     compilationData = JSON.parse(compilationData.replace(/[\s\r\n]/g, ""));//去掉空格字符
+    document.styleSheets[0].insertRule('body {background-color: red}, 0');
 </script>
 </html>

+ 36 - 12
web/building_saas/pm/js/pm_newMain.js

@@ -335,9 +335,6 @@ const projTreeObj = {
                         $('#shareFindDiv').hide();
                         setShareToModal(selected);
                         $('#share').modal('show');
-                        //默认允许拷贝
-                        $('#allowCopy').prop('checked', true);
-                        $('#allowCopyHint').show();
                         setTimeout(function () {
                             $('#sharePhone').focus();
                         }, 200);
@@ -3545,6 +3542,7 @@ function shareTender(){
     const userInfo = $('#shareFindDiv');
     const addUser = $('#addShareUser');
     const copyInput = $('#allowCopy');
+    const coopInput = $('#allowCooperate');
     const shareConfirm = $('#share-confirm');
     shareConfirm.addClass('disabled');
     //可分享才可添加用户
@@ -3581,6 +3579,8 @@ function shareTender(){
             $('#user_email').text(userData.email ? userData.email : '');
             //默认可拷贝
             copyInput.prop('checked', true);
+            //默认不可协作
+            coopInput.prop('checked', false);
             userInfo.show();
             //判断项目是否已经分享
             CommonAjax.post('/pm/api/getProjectShareInfo', {user_id: userID, projectID: shareSeleted.data.ID}, function (rstData) {
@@ -3609,11 +3609,12 @@ $('#share-confirm').click(function(){
     $.bootstrapLoading.start();
     const perHeight = 30;
     let allowCopy = $('#allowCopy').prop('checked'),
+        allowCoop = $('#allowCooperate').prop('checked');
         userName = $('#user_name').text() || '',
         userCompany = $('#user_company').text() || '',
         userMobile = $('#user_mobile').text() || '',
         userEmail = $('#user_email').text() || '';
-    let shareData = [{userID: shareUserID, allowCopy: allowCopy}];
+    let shareData = [{userID: shareUserID, allowCopy: allowCopy, allowCooperate: allowCoop}];
     //分享
     CommonAjax.post('/pm/api/share', {user_id: userID, type: shareType.create,  projectID: shareSeleted.data.ID, shareData: shareData}, function (rstData) {
         //更新已分享table
@@ -3623,6 +3624,7 @@ $('#share-confirm').click(function(){
                         <td style="width: 136px">${userMobile}</td>
                         <td style="width: 136px">${userEmail}</td>
                         <td style="width: 90px;"><input value="allowCopy" ${allowCopy ? 'checked' : ''} type="checkbox"></td>
+                        <td style="width: 90px;"><input value="allowCooperate" ${allowCoop ? 'checked' : ''} type="checkbox"></td>
                         <td style="width: 90px;"><input value="cancelShare" type="checkbox"></td>
                      </tr>`);
         let tbodyTotalHeight = $('#shareToInfo').height() + perHeight > 200 ? 200 : $('#shareToInfo').height() + perHeight;
@@ -3646,7 +3648,7 @@ $('#share-confirm').click(function(){
     });
 });
 //允许拷贝
-$('#allowCopy').change(function () {
+/*$('#allowCopy').change(function () {
     let checked = $(this).prop('checked');
     if(checked){
         $('#allowCopyHint').show();
@@ -3654,7 +3656,7 @@ $('#allowCopy').change(function () {
     else{
         $('#allowCopyHint').hide();
     }
-});
+});*/
 
 //批量替换文件,切换建设项目
 $('#otherProject').change(function(){
@@ -3715,6 +3717,7 @@ function setShareToModal(selected){
                                           <th style="width: 136px;">手机</th>
                                           <th style="width: 136px;">邮箱</th>
                                           <th style="width: 90px;">允许拷贝</th>
+                                          <th style="width: 90px;">允许协作</th>
                                           <th style="width: 90px;">取消分享</th>
                                </tr>`;
         infoArr.push(theadHtml);
@@ -3725,6 +3728,7 @@ function setShareToModal(selected){
                                           <td style="width: 136px;">${user.mobile}</td>
                                           <td style="width: 160px;">${user.email}</td>
                                           <td style="width: 90px;"><input value="allowCopy" ${user.allowCopy ? 'checked' : ''} type="checkbox"></td>
+                                          <td style="width: 90px;"><input value="allowCooperate" ${user.allowCooperate ? 'checked' : ''} type="checkbox"></td>
                                           <td style="width: 90px;"><input value="cancelShare" type="checkbox"></td>
                                </tr>`;
             infoArr.push(infoHtml);
@@ -3745,24 +3749,44 @@ function updateShareInfo(selected){
     if (usersTr && usersTr.length > 0) {
         usersTr = usersTr.slice(1);
     }
-    let newShareInfo = [];
+    let newShareInfo = [],
+        orgShareInfo = [];
+    //数据不同才提交
+    for (let shareData of selected.data.shareInfo) {
+        orgShareInfo.push({userID: shareData.userID, allowCopy: shareData.allowCopy, allowCooperate: shareData.allowCooperate})
+    }
     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');
+        let allowCopy = $(userTr).find('input:eq(0)').prop('checked');
+        let allowCoop = $(userTr).find('input:eq(1)').prop('checked');
+        let cancelShare = $(userTr).find('input:eq(2)').prop('checked');
         selected.data.shareInfo[i].allowCopy = allowCopy;
+        selected.data.shareInfo[i].allowCooperate = allowCoop;
         if(!cancelShare){
-            newShareInfo.push(selected.data.shareInfo[i]);
+            //newShareInfo.push(selected.data.shareInfo[i]);
+            newShareInfo.push({userID: selected.data.shareInfo[i].userID, allowCopy: allowCopy, allowCooperate: allowCoop});
         }
     }
-    CommonAjax.post('/pm/api/updateProjects', {user_id: userID, updateData: [{updateType: 'update', updateData: {ID: selected.data.ID, shareInfo: newShareInfo}}]}, function () {
-        selected.data.shareInfo = newShareInfo;
+    if (_.isEqual(newShareInfo, orgShareInfo)) {
+        return;
+    }
+    CommonAjax.post('/pm/api/share', {user_id: userID, type: 'update', projectID: selected.data.ID, shareData: newShareInfo}, function (shareData) {
+        selected.data.shareInfo = shareData;
         let sheet = projTreeObj.workBook.getSheet(0);
         projTreeObj.renderSheetFuc(sheet, function () {
             sheet.invalidateLayout();
             sheet.repaint();
         });
     });
+    /*CommonAjax.post('/pm/api/updateProjects', {user_id: userID, updateData: [{updateType: 'update', updateData: {ID: selected.data.ID, shareInfo: newShareInfo}}]}, function () {
+        //todo 更新
+        selected.data.shareInfo = newShareInfo;
+        let sheet = projTreeObj.workBook.getSheet(0);
+        projTreeObj.renderSheetFuc(sheet, function () {
+            sheet.invalidateLayout();
+            sheet.repaint();
+        });
+    });*/
 }
 
 //刷新建设项目汇总金额信息

+ 173 - 84
web/building_saas/pm/js/pm_share.js

@@ -16,7 +16,8 @@ const pmShare = (function () {
     const shareType = {receive: 'receive', shareTo: 'shareTo'};
     //操作类型
     const oprType = {copy: 'copy', cancel: 'cancel'};
-    let tree = null;
+    let tree = null,
+        actualIDShareInfo = {};//项目真实树ID与项目分享信息映射
     const treeCol = 0;
     const treeSetting = {
         tree: {
@@ -29,9 +30,8 @@ const pmShare = (function () {
     };
     const headers = [
         {name: '工程列表', dataCode: 'name', width: 300, rateWidth: 0.55, vAlign: 'center', hAlign: 'left'},
-        {name: '由...分享', dataCode: 'from', width: 120, rateWidth: 0.15, vAlign: 'center', hAlign: 'left'},
-     /*   {name: '拷贝工程', dataCode: 'copy', width: 100, rateWidth: 0.075, vAlign: 'center', hAlign: 'left'},
-        {name: '清除', dataCode: 'cancel', width: 100, rateWidth: 0.075, 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'},
@@ -125,12 +125,6 @@ const pmShare = (function () {
                 if(headers[i].formatter){
                     sheet.setFormatter(-1, i, headers[i].formatter);
                 }
-              /*  if(headers[i].dataCode === oprType.copy){
-                    //合并列
-                    sheet.addSpan(0, i, 1, 2, GC.Spread.Sheets.SheetArea.colHeader);
-                    sheet.setValue(0, i, '操作', GC.Spread.Sheets.SheetArea.colHeader);
-                    continue;
-                }*/
                 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']]);
@@ -162,15 +156,56 @@ const pmShare = (function () {
         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) {
+            let aV = Date.parse(a.shareDate),
+                bV = Date.parse(b.shareDate);
+            if (aV > bV) {
+                return -1;
+            } else if (aV < bV) {
+                return 1;
+            }
+            return 0;
+        });
+        return shareList[0] || null;
+
+    }
     //此项目是否可以拷贝
     //@param {String}userID {Object}project @return {Boolean}
     function isAllowCopy(userID, project){
-        for(let shareData of project.shareInfo){
-            if(shareData.userID === userID){
-                return shareData.allowCopy;
-            }
+        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 false;
+        return !!myShareInfo.allowCooperate;
     }
     //获取树节点
     //@param {Object}tree @return {Object}
@@ -398,9 +433,44 @@ const pmShare = (function () {
     }
     //互动单元格
     function getInteractionCell() {
+        let workImg = document.getElementById('work_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) {
+                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});
+                let nowX  = Math.floor(x) + textLength + 3,
+                    nowY = Math.floor((y + (y + h)) / 2) - 7;
+                if (node.data.allowCooperate) {
+                    ctx.drawImage(workImg, 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,
@@ -434,36 +504,6 @@ const pmShare = (function () {
                         $('#userinfo').modal('show');
                     }
                 }
-                //分享给
-                else if(dataCode === 'to'){
-                    if(node.data.shareType === shareType.shareTo){
-                        setShareToModal(node);
-                        $('#shareTo').modal('show');
-                    }
-                }
-                //操作
-                else if(dataCode === oprType.copy){
-                   /* if(node.data.copy === '添加分享'){
-                        $('#sharePhone').val('');
-                        $('#share-info').hide();
-                        $('#share').find('.card').hide();
-                        $('#share').modal('show');
-                        $('#allowCopy').prop('checked', false);
-                        $('#allowCopyHint').hide();
-                    }
-                    else*/
-                    if(node.data.copy === '拷贝工程'){
-                        $('#copyShare').modal('show');
-                    }
-                }
-                else if (dataCode === oprType.cancel) {
-                    if (node.data.cancel === '清除') {
-                        let $p = $('<p>').text(`点“确定”按钮,确认清除分享文件 “${node.data.name}”。`);
-                        $('#cancelShare').find('.modal-body').empty();
-                        $('#cancelShare').find('.modal-body').append($p);
-                        $('#cancelShare').modal('show');
-                    }
-                }
             }
         };
         InteractionCell.prototype.processMouseMove = function (hitInfo) {
@@ -573,45 +613,28 @@ const pmShare = (function () {
                     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 === oprType.copy){
+                    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 === oprType.cancel) {
-                        let style = new GC.Spread.Sheets.Style();
-                        style.foreColor = cancelForeColor;
-                        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());
-                        }
-                    }
                     sheet.setValue(i, j, nodes[i].data[dataCode] !== null && typeof nodes[i].data[dataCode] !== 'undefined' ? nodes[i].data[dataCode] : '');
                 }
             }
         };
         renderSheetFunc(sheet, fuc);
     }
-    //同一棵树,可能存在相同数据显示多条的问题(传入的datas中不存在相同数据),将真实树结构数据存在actualTreeInfo中,外部树结构数据用uuid重置。
+    //同一棵树,可能存在相同数据显示多条的问题(传入的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) {
@@ -631,21 +654,17 @@ const pmShare = (function () {
             data.ParentID = pid;
         }
     }
-    //给项目设置分享信息:由xx分享、分享给我、可进行的操作,含有userInfo信息的文件为他人直接分享的文件,他人分享父级文件,子文件不含有userInfo信息
+    //给项目设置分享信息:由xx分享、分享时间、分享给我,含有userInfo信息的文件为他人直接分享的文件,他人分享父级文件,子文件不含有userInfo信息
     //@param {Array}datas @return {void}
     function setShareInfo(datas) {
         for (let data of datas) {
             if (data.userInfo) {
-                data.from = `由 ${data.userInfo.name} 分享`;
+                //shareInfo中我的条目
+                let selfInfo = _.find(data.shareInfo, {userID: userID});
+                data.shareDate = selfInfo ? selfInfo.shareDate : ''
+                data.from = data.userInfo.name;
                 data.to = '分享给 我';
                 data.cancel = '清除';
-
-                //拷贝操作只允许到单位工程级
-                let tendersCanCopy = isAllowCopy(userID, data);
-                let tenders = data.projType === projectType.tender ? [data] : _.filter(data.children, {projType: projectType.tender});
-                for (let tender of tenders) {
-                    tender.copy = tendersCanCopy ? '拷贝工程' : '';
-                }
             }
         }
     }
@@ -678,6 +697,30 @@ const pmShare = (function () {
             }
         }
     }
+    //从同层树数据获取第一个节点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){
@@ -694,12 +737,14 @@ const pmShare = (function () {
         let rst = [];
         //整理树结构
         sortSameDepthData(groupedDatas, -1);
+        //第一个根节点数据
+        let firstID = getFirstID(groupedDatas);
         //新建未分类建设项目及单项工程
-        let ungroupedProj = {ID: uuid.v1(), ParentID: -1, NextSiblingID: -1, name: '未分类建设项目', projType: projectType.project};
+        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};
-        if (groupedDatas.length > 0) {
+        /*if (groupedDatas.length > 0) {
             groupedDatas[groupedDatas.length - 1].NextSiblingID = ungroupedProj.ID;
-        }
+        }*/
         //将未分类的数据归类
         sortSameDepthData(engs, ungroupedProj.ID);
         sortSameDepthData(tenders, ungroupedEng.ID);
@@ -735,6 +780,19 @@ const pmShare = (function () {
             return 0;
         });
     }
+    //设置节点数据权限
+    //@param {Array}datas项目数据
+    function setPermissionsInfo(datas) {
+        //data.allowCopy与shareInfo里allowCopy的区别:
+        //data.allowCopy为该单位实际的权限(跟着最新的分享信息走,可能随着父项)
+        for (let data of datas) {
+            if (data.projType === projectType.tender) {
+                data.allowCopy = isAllowCopy(userID, data);
+                data.allowCooperate = isAllowCoop(userID, data);
+            }
+        }
+        
+    }
     //建立树
     //@return void
     function initShareTree(){
@@ -750,6 +808,7 @@ const pmShare = (function () {
                 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);
@@ -777,7 +836,7 @@ const pmShare = (function () {
                     icon: 'fa-copy',
                     disabled: function () {
                         let selected = tree.selected;
-                        return !(selected && selected.data.copy && selected.data.copy === '拷贝工程');
+                        return !(selected && selected.data.allowCopy);
                     },
                     callback: function (key, opt) {
                         $('#copyShare').modal('show');
@@ -1001,12 +1060,42 @@ const pmShare = (function () {
             copyShareProject(tree.selected, parseInt(selProj), parseInt(selEng));
         });
         //清除分享
+        //清除了该节点后,可能还有该节点的数据在树上(树允许有重复数据),需要更新分享信息
+        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;
+                    });
+                }
+            }
+        }
         $('#cancelShareConfirm').click(function () {
             $.bootstrapLoading.start();
-            CommonAjax.post('/pm/api/share', {user_id: userID, type: oprType.cancel,  projectID: tree.selected.data.actualTreeInfo.ID, shareData:[{userID: userID}]}, function (rstData) {
-                $.bootstrapLoading.end();
+            let cancelProjID = tree.selected.data.actualTreeInfo.ID;
+            CommonAjax.post('/pm/api/share', {user_id: userID, type: oprType.cancel,  projectID: cancelProjID, shareData:[{userID: userID}]}, function (rstData) {
                 tree.removeNode(tree.selected);
+                //更新与清除节点数据相同,且为被清除缓存分享信息
+                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();
             }, function () {
                 $.bootstrapLoading.end();
             });

+ 1 - 1
web/common/html/header.html

@@ -2,7 +2,7 @@
     <% if(controller === 'boot' || controller === 'pm'){ %>
     <!--<a style="text-decoration: none" href="javascript:void(0);" class="header-logo">-->
     <% }else { %>
-    <div class="mx-2"><a href="/pm" class="btn btn-sm" data-toggle="tooltip" title="返回"><i class="fa fa-angle-left" style="font-size:24px"></i></a></div>
+    <div class="mx-2"><a href="/pm" class="btn btn-sm" data-toggle="tooltip" title="返回项目管理"><i class="fa fa-angle-left" style="font-size:24px"></i></a></div>
         <!--<a style="text-decoration: none" href="/pm" class="header-logo">-->
     <% } %>
     <div class="header-logo">

BIN
web/dest/css/img/copy.png


BIN
web/dest/css/img/work.png


+ 10 - 1
web/over_write/js/jiangxi_2017.js

@@ -448,7 +448,16 @@ if(typeof $ !== 'undefined' && $('#cbClassList')){
 if (typeof calcBaseView !== 'undefined') {
     calcBaseView.billsCBClass = {ALL: [], FBFX: [], CSXM: [], QTXM: [], FBF: [], RCJ: [], GF: [], SJ: [], GJXM: []};
 }
-
+// (江西)项目属性-关于计算中的取费方式默认勾选子目单价取费(反算)方式。
+// 根据重写去给项目的billsCalcMode赋值比这种形式麻烦
+if (typeof leafBillGetFeeType !== 'undefined') {
+    leafBillGetFeeType = {
+        rationPriceConverse: 0,
+        rationContent: 1,
+        rationPrice: 2,
+        billsPrice: 3
+    };
+}