Przeglądaj źródła

分享推送相关

vian 5 lat temu
rodzic
commit
90e01b4b4e

+ 6 - 4
modules/main/routes/main_route.js

@@ -17,8 +17,8 @@ module.exports =function (app) {
     const baseController = new BaseController();
     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, projectData, allowCooperate) {
+        const projectID = +req.query.project;
+        pm.checkProjectRight(req.session.sessionUser.id, projectID, async function (hasRight, projectData, isOpenShareProject, allowCooperate) {
             if (hasRight) {
                 //分享的项目,只读、协作(允许编辑)
                 let projectReadOnly = false,
@@ -30,7 +30,7 @@ module.exports =function (app) {
                     projectReadOnly = !projectCooperate;
                 }
                 let fileKind = '1'; //默认投标文件
-                let constructProject = await pmFacade.getConstructionProject(req.query.project);
+                let constructProject = await pmFacade.getConstructionProject(projectID);
                 if (constructProject && constructProject.property && constructProject.property.fileKind) {
                     fileKind = constructProject.property.fileKind;
                 }
@@ -39,6 +39,7 @@ module.exports =function (app) {
                 if(options){
                     options = await optionsDao.saveOptions(req.session.sessionUser.id, req.session.sessionCompilation._id, optionSetting);
                 }
+                const markReadProjectIDs = isOpenShareProject ? await pmFacade.markShareItemsRead(projectID, req.session.sessionUser.id) : [];
                 res.render('building_saas/main/html/main.html',
                     {
                         userAccount: req.session.userAccount,
@@ -52,7 +53,8 @@ module.exports =function (app) {
                         LicenseKey:config.getLicenseKey(process.env.NODE_ENV),
                         overWriteUrl:req.session.sessionCompilation.overWriteUrl,
                         fileKind: fileKind,
-                        options:JSON.stringify(options)
+                        options:JSON.stringify(options),
+                        markReadProjectIDs: JSON.stringify(markReadProjectIDs)
                     });
             } else {
                 res.redirect('/pm');

+ 10 - 5
modules/pm/controllers/pm_controller.js

@@ -61,13 +61,15 @@ module.exports = {
              * userId(String): Session.userID
              */
             let shareInfo = null;
+            let isOpenShareProject = false;
             //判断是否是打开分享的项目,分享项目shareInfo不为null
             if (userId !== result.userID) {
                 shareInfo = await pm_facade.getShareInfo(userId, result.ID);
+                isOpenShareProject = true;
             }
             if ((userId === result.userID || shareInfo) && result._doc.projType === projType.tender) {
                 const allowCooperate = (shareInfo || {}).allowCooperate;
-                callback(true, result, allowCooperate);
+                callback(true, result, isOpenShareProject, allowCooperate);
             } else {
                 callback(false);
             }
@@ -634,7 +636,7 @@ module.exports = {
     share: async function (req, res) {
         try {
             const data = JSON.parse(req.body.data);
-            const { type, shareData, projectID, count } = data;
+            const { type, permissionType, shareData, projectID, count } = data;
             const userID = req.session.sessionUser.id;
             const shareDate = moment(Date.now()).format('YYYY-MM-DD HH:mm:ss');
             shareData.forEach(item => item.shareDate = shareDate);
@@ -696,11 +698,14 @@ module.exports = {
             const rstTask = [
                 pm_facade.getRecentShareList(userID, count),
                 userModelObj.getContacts(userID)
-            ]
-            let rst = null;
+            ];
+            // 获取需要广播推送的单位工程
+            // shareData数组的形式是以前需求需要,现在的需求下,shareData数组必定只有一个元素
+            const emitTenders = await pm_facade.getShareInfoAfterChangePermission(permissionType, shareData[0].userID, projectID);
+            let rst = { emitTenders };
             if (!isSimpleUpdate) {
                 const [recentUsers, contacts] = await Promise.all(rstTask);
-                rst = { recentUsers, contacts };
+                Object.assign(rst, { recentUsers, contacts });
             }
             callback(req, res, 0, 'success', rst);
         }

+ 96 - 4
modules/pm/facade/pm_facade.js

@@ -20,6 +20,8 @@ module.exports={
     getUnreadShareListByCompilation,
     getShareTip,
     getShareState,
+    markShareItemsRead,
+    getShareInfoAfterChangePermission,
     moveProject:moveProject,
     accessToCopyProject,
     copyProject:copyProject,
@@ -108,7 +110,7 @@ import SectionTreeDao from '../../complementary_ration_lib/models/sectionTreeMod
 let sectionTreeDao = new SectionTreeDao();
 import CounterModel from "../../glj/models/counter_model";
 import moment from 'moment-timezone';
-const { fixedFlag } = require('../../../public/common_constants');
+const { fixedFlag, SharePermissionChangeType } = require('../../../public/common_constants');
 const notDeleted = [{deleteInfo: null}, {'deleteInfo.deleted': false}];
 import {
     defaultDecimal,
@@ -347,6 +349,96 @@ async function getShareState(projectID, receiver) {
     };
 }
 
+// 自身及父链上的分享数据(链距离最近的一个)
+async function getUpChainShareData(projectID, receiver) {
+    while (projectID != -1) {
+        const shareData = await shareListModel.findOne({ projectID, receiver }).lean();
+        if (shareData) {
+            return shareData;
+        }
+        const project = await projectModel.findOne({ ID: projectID }, '-_id ParentID').lean();
+        projectID = project ? project.ParentID : -1;
+    }
+    return null;
+}
+
+// 标记已读分享条目
+// 打开任意的单位工程,都会将其父分享条目标记和自身为已读 
+// eg:被分享了一个建设项目,和其下一个单位工程,打开该一个单位工程,建设项目标记为已读、该单位工程也标记为已读
+async function markShareItemsRead(projectID, userID) {
+    const upChainIDs = await getUpChainIDs(projectID);
+    const unreadList = await shareListModel.find({ projectID: { $in: upChainIDs }, receiver: userID, isRead: false }, '-_id ID projectID').lean();
+    const markReadProjectIDs = [];
+    const bulks = [];
+    unreadList.forEach(item => {
+        markReadProjectIDs.push(item.projectID);
+        bulks.push({
+            updateOne: {
+                filter: { ID: item.ID },
+                update: { isRead: true }
+            }
+        });
+    });
+    if (bulks.length) {
+        await shareListModel.bulkWrite(bulks);
+    }
+    return markReadProjectIDs;
+}
+
+/**
+ * 分享权限变更后,根据变更操作,获取相关项目的分享权限信息
+ * 不能简单根据某个项目的分享信息获得其权限,因为目前的分享可以重复分享(分享单位工程A、分享包含单位工程A的父项) 
+ * 最新的分享权限是由项目链上(所有子项、自身、父项...)最新的分享信息决定的
+ * @param {Number} permissionType - 分享权限变更类型
+ * @param {String} receiver - 用户ID
+ * @param {Number} projectID - 项目ID
+ */
+async function getShareInfoAfterChangePermission(permissionType, receiver, projectID) {
+    const project = await projectModel.findOne({ ID: projectID }, '-_id ID projType').lean();
+    if (!project) {
+        return [];
+    }
+    // UPDATE_COPY不触发推送给主页面的消息
+    const propChange = [SharePermissionChangeType.UPDATE_COOPERATE].includes(permissionType);
+    const cancelShare = permissionType === SharePermissionChangeType.CANCEL;
+    // 需要处理的单位工程
+    if (propChange && project.projType === projectType.tender) {
+        const shareData = await shareListModel.findOne({ projectID, receiver }, '-_id allowCooperate allowCopy updateDate').lean();
+        const tender = { ID: projectID };
+        if (shareData) {
+            Object.assign(tender, shareData);
+        }
+        return [tender];
+    }
+    if (propChange && project.projType !== projectType.tender) {
+        const projects = await getPosterityProjects([projectID], false, '-_id ID projType');
+        const tenders = projects.filter(p => p.projType === projectType.tender);
+        const shareData = await shareListModel.findOne({ projectID, receiver }, '-_id allowCooperate allowCopy updateDate').lean();
+        if (shareData) {
+            tenders.forEach(tender => Object.assign(tender, shareData));
+        }
+        return tenders
+    }
+    if (cancelShare && project.projType === projectType.tender) {
+        const shareData = await getUpChainShareData(projectID, receiver);
+        return shareData ? [] : [{ ID: projectID }];
+    }
+    if (cancelShare && project.projType !== projectType.tender) {
+        const projects = await getPosterityProjects([projectID], false, '-_id ID projType');
+        const tenders = [];
+        for (const p of projects) {
+            if (p.projType === projectType.tender) {
+                const shareData = await getUpChainShareData(p.ID, receiver);
+                if (!shareData) {
+                    tenders.push({ ID: p.ID });
+                }
+            }
+        }
+        return tenders;
+    }
+    return [];
+}
+
 //拷贝例题项目
 //@param {String}userID {Array}projIDs拷贝的例题项目ID(建设项目、文件夹)@return {Boolean}
 async function copyExample(userID, compilation, projIDs){
@@ -1500,10 +1592,10 @@ async function getUpChainIDs(projectID) {
 }
 
 //获取projectIDs文件下所有子项目(默认不包括projectIDs本身)
-async function getPosterityProjects(projectIDs, includeSelf = false) {
+async function getPosterityProjects(projectIDs, includeSelf = false, fields = '-_id') {
     let rst = [];
     if (includeSelf) {
-        const projects = await projectModel.find({ID: {$in: projectIDs}, $or: notDeleted}, '-_id').lean();
+        const projects = await projectModel.find({ID: {$in: projectIDs}, $or: notDeleted}, fields).lean();
         if (projects) {
             rst.push(...projects);
         }
@@ -1511,7 +1603,7 @@ async function getPosterityProjects(projectIDs, includeSelf = false) {
     async function getProjects(parentIDs) {
         if (parentIDs.length > 0) {
             let newIDs = [];
-            let projs = await projectModel.find({ParentID: {$in: parentIDs}, $or: notDeleted}, '-_id').lean();
+            let projs = await projectModel.find({ParentID: {$in: parentIDs}, $or: notDeleted}, fields).lean();
             for (let proj of projs) {
                 // 兼容旧的错误数据,可能ParentID和ID相同
                 if (parentIDs.includes(proj.ID)) {

+ 4 - 2
public/common_constants.js

@@ -156,8 +156,10 @@
     // 分享权限变更的类型
     const SharePermissionChangeType = {
         UPDATE_COOPERATE: 1,
-        CANCEL: 2,
-        SHARE: 3
+        UPDATE_COPY: 2,
+        CANCEL: 3,
+        SHARE: 4,
+        READ: 5
     };
 
     // 页面目标

+ 91 - 88
public/web/socket/connection.js

@@ -2,97 +2,100 @@
  * Created by zhangweicheng on 2017/8/7.
  */
 socketObject = {
-  roomInfo: null,
-  messages: [],
-  connect: function (from, payload) {
-      // 连接socket服务器
-      var hostName = window.location.hostname;
-      let me = this;
-      let port = window.location.protocol === 'http:' ? 3300 : 3301;
-      socket = io(window.location.protocol + '//' + hostName + ':' + port);
-      socket.on('connect', function () {
-          if (from == 'pm') {
-              me.roomInfo = {
-                  compilationUser: `${userID}@${compilationData._id}`,
-                  userID: userID
-              };
-        }else if(from == 'unitPrice'){
-          me.roomInfo = {
-            unitFile:unitPriceFileID
-          }
-        } else {
-            me.roomInfo={
-                feeRate:me.getFeeRateRoomID(),
-                unitFile:me.getUnitFileRoomID(),
-                userIDProjectID: `${userID}@${projectObj.project.ID()}`
+    roomInfo: null,
+    messages: [],
+    connect: function (from, payload) {
+        // 连接socket服务器
+        var hostName = window.location.hostname;
+        let me = this;
+        let port = window.location.protocol === 'http:' ? 3300 : 3301;
+        socket = io(window.location.protocol + '//' + hostName + ':' + port);
+        socket.on('connect', function () {
+            if (from == 'pm') {
+                me.roomInfo = {
+                    compilationUser: `${userID}@${compilationData._id}`,
+                    userID: userID
+                };
+            } else if (from == 'unitPrice') {
+                me.roomInfo = {
+                    unitFile: unitPriceFileID
+                }
+            } else {
+                me.roomInfo = {
+                    feeRate: me.getFeeRateRoomID(),
+                    unitFile: me.getUnitFileRoomID(),
+                    userIDProjectID: `${userID}@${projectObj.project.ID()}`
+                };
+                if (payload && payload.projectReadOnly === false) {
+                    me.roomInfo.projectID = `projectID${projectObj.project.ID()}`;
+                }
+            }
+            const emitData = {
+                roomData: me.roomInfo,
+                payload
             };
-              if (payload && payload.projectReadOnly === false) {
-                  me.roomInfo.projectID = `projectID${projectObj.project.ID()}`;
-              }
-          }
-          const emitData = {
-              roomData: me.roomInfo,
-              payload
-          };
-          socket.emit('join', emitData);
-          if (me.messages.length > 0) {//发送缓存消息;
-              for (let m of me.messages) {
-                  socket.emit(m.message, m.data);
-              }
-          }
-          console.log('连接成功');
-      });
+            socket.emit('join', emitData);
+            if (me.messages.length > 0) {//发送缓存消息;
+                for (let m of me.messages) {
+                    socket.emit(m.message, m.data);
+                }
+            }
+            if (typeof markReadProjectIDs !== 'undefined' && markReadProjectIDs.length) {
+                SHARE_TO.emitPermissionChange(commonConstants.SharePermissionChangeType.READ, userID, null, [], { markReadProjectIDs });
+            }
+            console.log('连接成功');
+        });
 
-      //=========================================================
-      //造价书页面接收消息部分
-      socket.on('feeRateChange', function (data) {
-          //data = JSON.parse(data);
+        //=========================================================
+        //造价书页面接收消息部分
+        socket.on('feeRateChange', function (data) {
+            //data = JSON.parse(data);
 
-          $("#message").html('费率文件已被修改,<a href="javascript:void(0);" id="load-data" onclick="window.location.reload()">点击加载并重新进行造价计算</a>');
-          $("#notify").show();
-          //alert('费率文件已经修改,请刷新页面');
-          //window.location.reload();
-      });
-      socket.on('unitFileChange', function (data) {
-          /*console.log(data);
-          if (data.newValue === undefined) {
-              return false;
-          }*/
-          $("#message").html('市场单价已被修改,<a href="javascript:void(0);" id="load-data" onclick="window.location.reload()">点击加载并重新进行造价计算</a>');
-          $("#notify").show();
-      });
-      socket.on('changeFileNotify', function (data) {//收到文件改变的消息
-          if (data.projectID == projectObj.project.ID()) {//如果是同个项目,则给出提示,否则忽略
-              let preString = "";
-              if (data.name == 'feeRate') {
-                  preString = "费率文件";
-              }
-              if (data.name == 'unitFile') {
-                  preString = "单价文件";
-              }
-              $("#message").html(preString + '已被修改,<a href="javascript:void(0);" id="load-data" onclick="window.location.reload()">点击加载并重新进行造价计算</a>');
-              $("#notify").show();
-          }
-      });
-      socket.on('handleAvatarList', function ({ editingUsers }) {
-          projectInfoObj.handleAvatarList(editingUsers);
-      });
-      SHARE_TO.permissionChangeListener();
+            $("#message").html('费率文件已被修改,<a href="javascript:void(0);" id="load-data" onclick="window.location.reload()">点击加载并重新进行造价计算</a>');
+            $("#notify").show();
+            //alert('费率文件已经修改,请刷新页面');
+            //window.location.reload();
+        });
+        socket.on('unitFileChange', function (data) {
+            /*console.log(data);
+            if (data.newValue === undefined) {
+                return false;
+            }*/
+            $("#message").html('市场单价已被修改,<a href="javascript:void(0);" id="load-data" onclick="window.location.reload()">点击加载并重新进行造价计算</a>');
+            $("#notify").show();
+        });
+        socket.on('changeFileNotify', function (data) {//收到文件改变的消息
+            if (data.projectID == projectObj.project.ID()) {//如果是同个项目,则给出提示,否则忽略
+                let preString = "";
+                if (data.name == 'feeRate') {
+                    preString = "费率文件";
+                }
+                if (data.name == 'unitFile') {
+                    preString = "单价文件";
+                }
+                $("#message").html(preString + '已被修改,<a href="javascript:void(0);" id="load-data" onclick="window.location.reload()">点击加载并重新进行造价计算</a>');
+                $("#notify").show();
+            }
+        });
+        socket.on('handleAvatarList', function ({ editingUsers }) {
+            projectInfoObj.handleAvatarList(editingUsers);
+        });
+        SHARE_TO.permissionChangeListener();
 
-      //=============================================================================================
-      //项目管理页面接收消息部分
+        //=============================================================================================
+        //项目管理页面接收消息部分
 
-      socket.on('refreshProjectIcon', function (data) {//收到刷新图标消息
-          if (data.projectID && typeof projTreeObj !== 'undefined') projTreeObj.refreshProjectIcon(data.projectID);
-      });
-      socket.on('fileDataChange', function (data) {//收到单价文件、费率文件内容修改、文件切换、另存(暂时能共用,以后有需要可分离)推送消息
-          if (data.projectID && typeof projTreeObj !== 'undefined') projTreeObj.refreshWhenFileDateChange(data.projectID);
-      });
-  },
-  getFeeRateRoomID: function () {
-      return projectObj.project.FeeRate.getActivateFeeRateFileID();
-  },
-  getUnitFileRoomID: function () {
-      return projectObj.project.projectGLJ.datas.constData.roomId ? projectObj.project.projectGLJ.datas.constData.roomId : roomId;
-  }
+        socket.on('refreshProjectIcon', function (data) {//收到刷新图标消息
+            if (data.projectID && typeof projTreeObj !== 'undefined') projTreeObj.refreshProjectIcon(data.projectID);
+        });
+        socket.on('fileDataChange', function (data) {//收到单价文件、费率文件内容修改、文件切换、另存(暂时能共用,以后有需要可分离)推送消息
+            if (data.projectID && typeof projTreeObj !== 'undefined') projTreeObj.refreshWhenFileDateChange(data.projectID);
+        });
+    },
+    getFeeRateRoomID: function () {
+        return projectObj.project.FeeRate.getActivateFeeRateFileID();
+    },
+    getUnitFileRoomID: function () {
+        return projectObj.project.projectGLJ.datas.constData.roomId ? projectObj.project.projectGLJ.datas.constData.roomId : roomId;
+    }
 }

+ 17 - 3
socket.js

@@ -6,6 +6,7 @@
  * @version
  */
 import socket from "socket.io";
+const moment = require('moment');
 const { PageTarget } = require('./public/common_constants');
 
 const socketIO = socket(3300);
@@ -102,11 +103,24 @@ socketIO.on('connection', function(socket) {
     });
 
     // 分享权限变更
-    socket.on('sharePermissionChange', function ({ permissionType, userID, compilationID, projectID }) {
+    socket.on('sharePermissionChange', async function ({ permissionType, userID, compilationID, projectID, emitTenders, payload }) {
+        const emitPayload = { projectID };
+        if (payload) {
+            if (payload.prop) {
+                payload.prop.updateDate = moment(Date.now()).format('YYYY-MM-DD HH:mm:ss');
+            }
+            Object.assign(emitPayload, payload);
+        }
         // 推送给项目管理页面
-        socket.broadcast.to(`${userID}@${compilationID}`).emit('sharePermissionChange', { permissionType, target: PageTarget.PM, payload: { projectID } });
+        socket.broadcast.to(`${userID}@${compilationID}`).emit('sharePermissionChange', { permissionType, target: PageTarget.PM, payload: emitPayload });
         // 推送给主页面
-        socket.broadcast.to(`${userID}@${projectID}`).emit('sharePermissionChange', { permissionType, target: PageTarget.MAIN });
+        for (const tender of emitTenders) {
+            const emitPayload = {};
+            if (typeof tender.allowCooperate !== 'undefined') {
+                emitPayload.allowCooperate = tender.allowCooperate;
+            }
+            socket.broadcast.to(`${userID}@${tender.ID}`).emit('sharePermissionChange', { permissionType, target: PageTarget.MAIN, payload: emitPayload });
+        }
     });
 
     socket.on('disconnect', function () {

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

@@ -45,6 +45,7 @@
         const overWriteUrl = '<%- overWriteUrl %>';
         console.log(projectCooperate);
         const G_SHOW_BLOCK_LIB = true;
+        const markReadProjectIDs = JSON.parse('<%- markReadProjectIDs %>');
 //        const G_SHOW_BLOCK_LIB = false;
     </script>
 </head>

+ 3 - 3
web/building_saas/pm/js/pm_newMain.js

@@ -903,9 +903,9 @@ const projTreeObj = {
             let newTab = window.open('about:blank');
             BeforeOpenProject(ID, {'fullFolder': GetFullFolder(parent)}, function () {
                 let mainUrl = `/main?project=${ID}`;
-                CommonAjax.get(mainUrl, [], function () {
-                    newTab.location.replace(mainUrl); //不能后退
-                });
+                newTab.location.replace(mainUrl); //不能后退
+                /* CommonAjax.get(mainUrl, [], function () {
+                }); */
             });
         }, timeoutTime);
     },

+ 87 - 5
web/building_saas/pm/js/pm_share.js

@@ -500,8 +500,37 @@ const pmShare = (function () {
         };
         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 cancelForeColor = 'red';
+    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();
+        //style.foreColor = foreColor;
+        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){
@@ -520,6 +549,12 @@ const pmShare = (function () {
                         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] : '');
                 }
@@ -527,6 +562,30 @@ const pmShare = (function () {
         };
         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
@@ -698,6 +757,7 @@ const pmShare = (function () {
         $.bootstrapLoading.start();
         //获取分享数据
         CommonAjax.post('/pm/api/receiveProjects', {user_id: userID}, function (rstData) {
+            actualIDShareInfo = {};
             // 排序 --分享的文件按照时间先后顺序排序,分享文件下的子文件,按照原本树结构显示,不需要排序
             sortByDate(rstData.grouped);
             sortByDate(rstData.ungrouped);
@@ -904,6 +964,26 @@ const pmShare = (function () {
             }
         }
     }
+    // 处理节点操作属性变更(是否可拷贝、是否可编辑)
+    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();
@@ -934,7 +1014,7 @@ const pmShare = (function () {
             showTreeData(tree.items, headers);
             $.bootstrapLoading.end();
             if (callback) {
-                callback();
+                callback(rstData);
             }
         }, function () {
             $.bootstrapLoading.end();
@@ -1014,11 +1094,11 @@ const pmShare = (function () {
             copyShareProject(tree.selected, parseInt(selProj), parseInt(selEng));
         });
         //清除分享
-        $('#cancelShareConfirm').click(function () {
+        $('#cancelShareConfirm').click(function (data) {
             const cancelProjID = tree.selected.data.actualTreeInfo.ID;
             handleCancelShare(cancelProjID, () => {
                 // 推送已打开的项目,通知已取消分享
-                SHARE_TO.emitPermissionChange(commonConstants.SharePermissionChangeType.CANCEL, userID, cancelProjID);
+                SHARE_TO.emitPermissionChange(commonConstants.SharePermissionChangeType.CANCEL, userID, cancelProjID, data.emitTenders);
                 // 清除已读
                 SHARE_TO.removeUnread(cancelProjID, unreadShareList);
             });
@@ -1031,7 +1111,9 @@ const pmShare = (function () {
         initView, 
         eventListener, 
         initShareTree, 
-        handleCancelShare
+        handlePropChange,
+        handleCancelShare,
+        handleMarkRead
     }
 })();
 

+ 35 - 16
web/common/components/share/index.js

@@ -238,16 +238,17 @@ const SHARE_TO = (() => {
             } else {
                 shareData = [{ userID: receiver, isCancel: true }];
             }
+            // 获取权限变更的类型
+            const permissionType = getPermissionType(shareType, curSharedUsers, shareData[0]);
             const postData = {
                 user_id: userID,
                 type,
+                permissionType,
                 projectID: curProjectID,
                 count: rencentCount,
                 shareData
             };
             const rst = await ajaxPost('/pm/api/share', postData);
-            // 获取权限变更的类型
-            const permissionType = getPermissionType(shareType, curSharedUsers, shareData[0]);
             // 请求成功后刷新视图
             if (shareType === ShareType.CREATE || shareType === ShareType.CANCEL) {
                 if (shareType === ShareType.CREATE) {
@@ -276,8 +277,10 @@ const SHARE_TO = (() => {
                 }
             }
             if (permissionType !== null) {
-                console.log(curProjectID);
-                emitPermissionChange(permissionType, receiver, curProjectID);
+                const payload = [PermissionType.UPDATE_COOPERATE, PermissionType.UPDATE_COPY].includes(permissionType)
+                    ? { prop: { allowCopy: shareData[0].allowCopy, allowCooperate: shareData[0].allowCooperate } }
+                    : null;
+                emitPermissionChange(permissionType, receiver, curProjectID, rst.emitTenders, payload);
             }
         } catch (err) {
             console.log(err);
@@ -306,13 +309,16 @@ const SHARE_TO = (() => {
         if (match.allowCooperate !== curShareData.allowCooperate) {
             return PermissionType.UPDATE_COOPERATE;
         }
+        if (match.allowCopy !== curShareData.allowCopy) {
+            return PermissionType.UPDATE_COPY;
+        }
         return null;
     }
 
     // 权限变更消息推送
-    function emitPermissionChange(permissionType, userID, projectID) {
+    function emitPermissionChange(permissionType, userID, projectID, emitTenders, payload) {
         const compilationID = typeof projectObj !== 'undefined' ? projectObj.project.projectInfo.compilation : compilationData._id;
-        socket.emit('sharePermissionChange', { permissionType, userID, compilationID, projectID });
+        socket.emit('sharePermissionChange', { permissionType, userID, compilationID, projectID, emitTenders, payload });
     }
 
     // 权限变更处理监听
@@ -320,11 +326,15 @@ const SHARE_TO = (() => {
         socket.on('sharePermissionChange', ({ permissionType, target, payload }) => {
             const type = `${permissionType}-${target}`;
             switch (type) {
+                case `${PermissionType.READ}-${PageTarget.PM}`:
+                    handleShareItemRead(payload);
+                    break;
                 case `${PermissionType.UPDATE_COOPERATE}-${PageTarget.PM}`:
-                    handlePMPropChange();
+                case `${PermissionType.UPDATE_COPY}-${PageTarget.PM}`:
+                    handlePMPropChange(payload);
                     break;
                 case `${PermissionType.UPDATE_COOPERATE}-${PageTarget.MAIN}`:
-                    handleMainCooperateChange();
+                    handleMainCooperateChange(payload);
                     break;
                 case `${PermissionType.CANCEL}-${PageTarget.PM}`:
                     handlePMCancelPermission(payload);
@@ -340,9 +350,19 @@ const SHARE_TO = (() => {
     }
 
     // 项目管理页面分享权限变更后相关处理函数
+
+    // 已读分享项目
+    function handleShareItemRead({ markReadProjectIDs }) {
+        pmShare.handleMarkRead(unreadShareList, markReadProjectIDs);
+    }
     // 分享条数属性变更(是否可拷贝、是否可编辑)
-    function handlePMPropChange(prop) {
-        
+    // @param {Object} prop - 属性变更对象 eg: { allowCopy: false }
+    function handlePMPropChange({ projectID, prop }) {
+        // 如果当前在项目管理的分享页面,需要刷新相关节点
+        const isActive = $('#tab_pm_share').hasClass('active');
+        if (isActive) {
+            pmShare.handlePropChange(projectID, prop);
+        }
     }
 
     // 已读某未读分享项目
@@ -394,17 +414,16 @@ const SHARE_TO = (() => {
 
     
     // 主页面的分享权限变更后相关处理函数
-    function handleMainCooperateChange() {
-        setLocalCache(commonConstants.StorageKey.ONCE_MAIN_LOADED, '分享设置已被修改,当前项目已自动刷新。');
-        window.location.reload();
+    function handleMainCooperateChange({ allowCooperate }) {
+        if (projectObj.project.projectInfo.shareState && projectObj.project.projectInfo.shareState.allowCooperate !== allowCooperate) {
+            setLocalCache(commonConstants.StorageKey.ONCE_MAIN_LOADED, '分享设置已被修改,当前项目已自动刷新。');
+            window.location.reload();
+        }
     }
     function handleMainCancelPermission() {
         // 定位到空白页
         window.location.replace(`/blank?type=${commonConstants.BlankType.SHARE_CANCEL}`);
     }
-    function handleShare(params) {
-        
-    }
 
     // 刷新项目管理树视图
     // 如果是在项目管理页面,需要刷新树(分享图标可能需要清除)