Browse Source

1.分享推送到项目管理相关
2.导入测评项目刷新问题

vian 5 years ago
parent
commit
7be557631e

+ 1 - 1
modules/all_models/import_logs.js

@@ -18,7 +18,7 @@ let modelSchema = {
     // 状态
     status:String,
     // 建设项目ID
-    projectID: Number,
+    projectID: Array,
     // 创建时间
     create_time: Number,
     errorMsg:""

+ 4 - 0
modules/all_models/share_list.js

@@ -9,6 +9,10 @@ const Schema = mongoose.Schema;
 const shareSchema = new Schema({
     ID: String,
     projectID: Number,
+    isRead: {
+        type: Boolean,
+        default: false
+    },
     owner: String, // 项目拥有者ID
     receiver: String, // 接收者ID
     allowCopy: {

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

@@ -76,13 +76,9 @@ module.exports = {
         });
     },
     getProjects: async function (req, res) {
-        await ProjectsData.getUserProjects(req.session.sessionUser.id, req.session.sessionCompilation._id, function (err, message, projects) {
+        await ProjectsData.getUserProjects(req.session.sessionUser.id, req.session.sessionCompilation._id, function (err, message, data) {
             console.log(err);
-            if (projects) {
-                callback(req, res, err, message, projects);
-            } else {
-                callback(req, res, err, message, null);
-            }
+            callback(req, res, err, message, data);
         });
     },
     updateProjects: async function (req, res) {
@@ -317,8 +313,7 @@ module.exports = {
     },
     // 项目管理首页
     index: async function (request, response) {
-        // TODO 上线后删除,处理旧的分享数据
-        await pm_facade.prepareShareList();
+        //await pm_facade.prepareShareList();
         // 获取编办信息
         let sessionCompilation = request.session.sessionCompilation;
         if (sessionCompilation === undefined || sessionCompilation === null) {
@@ -347,7 +342,10 @@ module.exports = {
         let overWriteUrl = fs.existsSync(absoluteUrl) && fs.statSync(absoluteUrl).isFile() ? compilationData.overWriteUrl : null;
         //欢迎页显示控制
         let [isShow, context] = await pm_facade.getWelcomeInfo(sessionCompilation._id, request.session.sessionUser, request.session.compilationVersion.includes('免费'));
+        // 未读的分享项目数量
+        const unreadShareList = await pm_facade.getUnreadShareListByCompilation(request.session.sessionUser.id, sessionCompilation._id);
         let renderData = {
+            unreadShareList: JSON.stringify(unreadShareList),
             isFirst: isFirst,
             isShow: isShow,
             context: context,

+ 39 - 7
modules/pm/facade/pm_facade.js

@@ -17,6 +17,7 @@ module.exports={
     getShareInfoMap,
     getRecentShareList,
     getProjectShareList,
+    getUnreadShareListByCompilation,
     getShareTip,
     getShareState,
     moveProject:moveProject,
@@ -295,6 +296,23 @@ async function getProjectShareList(projectID, limit = null) {
     return users;
 }
 
+// 获取某用户某费用定额的未读的被分享记录
+async function getUnreadShareListByCompilation(userID, compilationID, isGetCount) {
+    const fields = isGetCount ? '-_id projectID ' : '-_id';
+    const list = await shareListModel.find({ receiver: userID, isRead: false }, fields);
+    const idList = list.reduce((acc, cur) => {
+        acc.push(cur.projectID);
+        return acc;
+    }, []);
+    const notDeleted = [{ deleteInfo: null }, { 'deleteInfo.deleted': false }];
+    const query = { ID: { $in: idList }, compilation: compilationID, $or: notDeleted };
+    if (isGetCount) {
+        return await projectModel.count(query)
+    }
+    const items = await projectModel.find(query, '-_id ID').lean();
+    return items.map(item => item.ID);
+}
+
 // 获取分享的提示(造价书分享按钮tooltip使用)
 async function getShareTip(projectID, limit) {
     const task = [
@@ -368,9 +386,14 @@ async function copyExample(userID, compilation, projIDs){
     let newDate = new Date(),
         parentBulks = [];
     const projectMaps = [];
+    // 传入项目ID的新ID
+    const newProjIDs = [];
     for (let data of allProjs) {
         let orgID = data.ID;
         data.ID = IDMapping[data.ID];
+        if (projIDs.indexOf(orgID) >= 0) {
+            newProjIDs.push(data.ID);
+        }
         data.ParentID = IDMapping[data.ParentID] ? IDMapping[data.ParentID] : -1;
         data.NextSiblingID = IDMapping[data.NextSiblingID] ? IDMapping[data.NextSiblingID] : -1;
         data.createDateTime = newDate;
@@ -403,7 +426,7 @@ async function copyExample(userID, compilation, projIDs){
     // 处理项目数据
     const projectTasks = [projectModel.bulkWrite(parentBulks), createProject(projectMaps)];
     await Promise.all(projectTasks);
-    return true;
+    return newProjIDs;
 }
 
 async function accessToCopyProject(userID, compilationID, data, newProjectID) {
@@ -424,7 +447,7 @@ async function handleCopyProject(key, userID, compilationID, data, newProjectID)
     const doc = { status: 'finish' };
     try {
         const projectMap = await copyProject(userID, compilationID, data, newProjectID);
-        doc.projectID = projectMap.copy.document.ID;
+        doc.projectID = [projectMap.copy.document.ID];
     } catch (err) {
         doc.status = 'error';
         doc.errorMsg = String(err);
@@ -1554,7 +1577,6 @@ async function importChongqingProject(data) {
     doImport(data.user_id,data.session.sessionCompilation._id,data.session.sessionCompilation.adProjects,data.key);
 
      return "start importing";
-
     async function doImport(user_id,compilationId,projectIDs,key) {
         let doc = {status:"finish"};
         try {
@@ -1562,6 +1584,8 @@ async function importChongqingProject(data) {
            if(r == false){
                doc.errorMsg = "导入失败,请检查项目是否存在!";
                doc.status = "error";
+           } else {
+               doc.projectID = r;
            }
         }catch (error){
             console.log(error);
@@ -2253,7 +2277,7 @@ async function doDownLoadAndImport(privateDownloadUrl,info) {
                 doc.errorMsg = result.msg;
                 doc.status = "error";
             } else {
-                doc.projectID = result.constructionProjectID;
+                doc.projectID = [result.constructionProjectID];
             }
         }catch (error){
             console.log(error);
@@ -2275,14 +2299,22 @@ async function importProcessChecking(data){
             result.status = "complete";
             await importLogsModel.remove(query);
             // 获取导入的项目数据
-            if (log.projectID) {
+            if (log.projectID && log.projectID.length > 0) {
+                const projects = await getPosterityProjects(log.projectID, true);
+                if (!(projects.length === 1 && projects[0].projType === projectType.tender)) { // 处理的是建设项目数据
+                    const summaryInfo = await getSummaryInfo(log.projectID);
+                    setupSummaryFields(summaryInfo, projects);
+                }
+                result.data = projects;
+            }
+            /* if (log.projectID && log.projectID.length > 0) {
                 const projects = await getPosterityProjects([log.projectID], true);
                 if (!(projects.length === 1 && projects[0].projType === projectType.tender)) { // 处理的是建设项目数据
                     const summaryInfo = await getSummaryInfo([log.projectID]);
                     setupSummaryFields(summaryInfo, projects);
                 }
                 result.data = projects;
-            }
+            } */
         }else if(log.status == "start"){
             result.status = "processing";
             result.content = log.content;
@@ -2359,7 +2391,7 @@ async function handleImportInterface(key, session) {
             throw '您创建的项目个数超限,请联系我们的客服人员,或者导出建设项目保存到本地备份,删除云上数据。';
         }
         const projectID = await importProject(importData, userID, compilationID);
-        doc.projectID = projectID;
+        doc.projectID = [projectID];
     } catch (err) {
         doc.errorMsg = typeof err === 'string' ? err : '导入接口失败,请检查接口文件!';
         doc.status = 'error';

+ 2 - 0
modules/pm/models/project_model.js

@@ -81,6 +81,8 @@ ProjectsDAO.prototype.getUserProjects = async function (userId, compilation, cal
         projects.forEach(project => {
             project.shareInfo = shareMap[project.ID] || [];
         });
+        // 当前费用定额未读的分享的条目数量
+        
         // 设置汇总字段
         let summaryInfo = await pmFacade.getSummaryInfo(projIDs);
         pmFacade.setupSummaryFields(summaryInfo, projects);

+ 10 - 1
public/common_constants.js

@@ -152,10 +152,18 @@
         // 主界面一旦出现这个缓存,马上提示
         ONCE_MAIN_LOADED: 'onceMainLoaded'
     };
-
+    
+    // 分享权限变更的类型
     const SharePermissionChangeType = {
         UPDATE_COOPERATE: 1,
         CANCEL: 2,
+        SHARE: 3
+    };
+
+    // 页面目标
+    const PageTarget = {
+        PM: 1, // 项目管理
+        MAIN: 2 // 造价书
     };
 
     const BlankType = {
@@ -177,6 +185,7 @@
         COMPLEMENTARY_LIB,
         StorageKey,
         SharePermissionChangeType,
+        PageTarget,
         BlankType
     };
 });

+ 1 - 0
public/web/socket/connection.js

@@ -13,6 +13,7 @@ socketObject = {
       socket.on('connect', function () {
           if (from == 'pm') {
               me.roomInfo = {
+                  compilationUser: `${userID}@${compilationData._id}`,
                   userID: userID
               };
         }else if(from == 'unitPrice'){

+ 6 - 3
socket.js

@@ -6,7 +6,7 @@
  * @version
  */
 import socket from "socket.io";
-const { SharePermissionType } = require('./public/common_constants');
+const { PageTarget } = require('./public/common_constants');
 
 const socketIO = socket(3300);
 
@@ -102,8 +102,11 @@ socketIO.on('connection', function(socket) {
     });
 
     // 分享权限变更
-    socket.on('sharePermissionChange', function ({ permissionType, roomID }) {
-        socket.broadcast.to(roomID).emit('sharePermissionChange', { permissionType });
+    socket.on('sharePermissionChange', function ({ permissionType, userID, compilationID, projectID }) {
+        // 推送给项目管理页面
+        socket.broadcast.to(`${userID}@${compilationID}`).emit('sharePermissionChange', { permissionType, target: PageTarget.PM, payload: { projectID } });
+        // 推送给主页面
+        socket.broadcast.to(`${userID}@${projectID}`).emit('sharePermissionChange', { permissionType, target: PageTarget.MAIN });
     });
 
     socket.on('disconnect', function () {

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

@@ -58,14 +58,6 @@
 <input type="hidden" id="fileKind" value="<%= fileKind %>">
 <img src="/web/dest/css/img/question.png" id="question_pic" style="display: none">
     <div class="header">
-         <div class="top-msg clearfix">
-            <div class="alert alert-warning alert-dismissible" role="alert" id="notify" style="display: none">
-                <button type="button" class="close" aria-label="Close" onclick="$('#notify').hide();">
-                  <span aria-hidden="true">&times;</span>
-                </button>
-                <strong id="message"></strong>-
-            </div>
-        </div>
         <%include ../../../common/html/header.html %>
     </div>
     <div class="main">

+ 6 - 0
web/building_saas/pm/html/project-management.html

@@ -23,6 +23,7 @@
         var userID = '<%- userID %>';
         let isFirst = JSON.parse('<%- isFirst %>');
         let isShow = JSON.parse('<%- isShow %>');
+        let unreadShareList = JSON.parse('<%- unreadShareList %>');
 
     </script>
     <style type="text/css">
@@ -86,6 +87,11 @@
                         </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>
+                            <% if (JSON.parse(unreadShareList).length > 0) { %>
+                                <span class="badge badge-danger" id="unread-share-count"><%- JSON.parse(unreadShareList).length %></span>
+                            <% } else {%>
+                                <span class="badge badge-danger hide-area" id="unread-share-count"><%- JSON.parse(unreadShareList).length %></span>
+                            <% } %>
                         </li>
                         <!--<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-users"></i></a>

+ 58 - 38
web/building_saas/pm/js/pm_share.js

@@ -894,6 +894,52 @@ const pmShare = (function () {
         }
         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 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();
+            }
+        }, function () {
+            $.bootstrapLoading.end();
+        });
+    }
     //事件监听器
     //@return void
     function eventListener(){
@@ -968,51 +1014,25 @@ 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();
-            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();
+            const cancelProjID = tree.selected.data.actualTreeInfo.ID;
+            handleCancelShare(cancelProjID, () => {
                 // 推送已打开的项目,通知已取消分享
                 SHARE_TO.emitPermissionChange(commonConstants.SharePermissionChangeType.CANCEL, userID, cancelProjID);
-            }, function () {
-                $.bootstrapLoading.end();
+                // 清除已读
+                SHARE_TO.removeUnread(cancelProjID, unreadShareList);
             });
         });
     }
 
-    return {spreadObj, headers, initView, eventListener}
+    return {
+        spreadObj, 
+        headers, 
+        initView, 
+        eventListener, 
+        initShareTree, 
+        handleCancelShare
+    }
 })();
 
 $(document).ready(function () {

+ 89 - 11
web/common/components/share/index.js

@@ -1,3 +1,4 @@
+
 const SHARE_TO = (() => {
 
     const ShareType = {
@@ -6,7 +7,7 @@ const SHARE_TO = (() => {
         CANCEL: 'cancel',
     };
 
-    const PermissionType = commonConstants.SharePermissionChangeType;
+    const { SharePermissionChangeType: PermissionType, PageTarget } = commonConstants;
 
     // 当前分享的项目ID
     let curProjectID;
@@ -275,6 +276,7 @@ const SHARE_TO = (() => {
                 }
             }
             if (permissionType !== null) {
+                console.log(curProjectID);
                 emitPermissionChange(permissionType, receiver, curProjectID);
             }
         } catch (err) {
@@ -291,6 +293,9 @@ const SHARE_TO = (() => {
         if (shareType === ShareType.CANCEL) {
             return PermissionType.CANCEL;
         }
+        if (shareType === ShareType.CREATE) {
+            return PermissionType.SHARE;
+        }
         if (!cache) {
             return null;
         }
@@ -306,29 +311,100 @@ const SHARE_TO = (() => {
 
     // 权限变更消息推送
     function emitPermissionChange(permissionType, userID, projectID) {
-        socket.emit('sharePermissionChange', { permissionType, roomID: `${userID}@${projectID}` });
+        const compilationID = typeof projectObj !== 'undefined' ? projectObj.project.projectInfo.compilation : compilationData._id;
+        socket.emit('sharePermissionChange', { permissionType, userID, compilationID, projectID });
     }
 
     // 权限变更处理监听
     function permissionChangeListener() {
-        socket.on('sharePermissionChange', ({ permissionType }) => {
-            if (permissionType === PermissionType.CANCEL) {
-                handleCancelPermission();
-            } else if (permissionType === PermissionType.UPDATE_COOPERATE) {
-                handleCooperateChange();
+        socket.on('sharePermissionChange', ({ permissionType, target, payload }) => {
+            const type = `${permissionType}-${target}`;
+            switch (type) {
+                case `${PermissionType.UPDATE_COOPERATE}-${PageTarget.PM}`:
+                    handlePMPropChange();
+                    break;
+                case `${PermissionType.UPDATE_COOPERATE}-${PageTarget.MAIN}`:
+                    handleMainCooperateChange();
+                    break;
+                case `${PermissionType.CANCEL}-${PageTarget.PM}`:
+                    handlePMCancelPermission(payload);
+                    break;
+                case `${PermissionType.CANCEL}-${PageTarget.MAIN}`:
+                    handleMainCancelPermission();
+                    break;
+                case `${PermissionType.SHARE}-${PageTarget.PM}`:
+                    handlePMSharePermission(payload);
+                    break;
             }
         });
     }
 
-    function handleCancelPermission() {
-        // 定位到空白页
-        window.location.replace(`/blank?type=${commonConstants.BlankType.SHARE_CANCEL}`);
+    // 项目管理页面分享权限变更后相关处理函数
+    // 分享条数属性变更(是否可拷贝、是否可编辑)
+    function handlePMPropChange(prop) {
+        
+    }
+
+    // 已读某未读分享项目
+    function removeUnread(projectID, list) {
+        const idx = list.indexOf(projectID);
+        if (idx >= 0) {
+            list.splice(idx, 1);
+            refreshUnreadCount(list.length);
+        }
+    }
+
+    // 取消分享后项目管理页面接收到推送后到操作
+    function handlePMCancelPermission({ projectID }) {
+        removeUnread(projectID, unreadShareList);
+        // 如果当前停留在分享标签界面,清楚分享项目
+        const isActive = $('#tab_pm_share').hasClass('active');
+        if (isActive) {
+            pmShare.handleCancelShare(projectID);
+        }
+    }
+    // 通知信息点击事件
+    function notify() {
+        pmShare.initShareTree();
+        $("#notify").hide();
+    }
+    // 新增分享后项目管理页面接收到推送后的操作
+    function handlePMSharePermission({ projectID }) {
+        unreadShareList.push(projectID);
+        unreadShareList = [...new Set(unreadShareList)];
+        refreshUnreadCount(unreadShareList.length);
+        // 如果当前停留在分享标签界面,需要弹出提示
+        const isActive = $('#tab_pm_share').hasClass('active');
+        if (isActive) {
+            $("#message").html('您有新的分享项目,<a href="javascript:void(0);" id="load-data" onclick="SHARE_TO.notify()">点击刷新列表</a>');
+            $("#notify").show();
+        }
+    }
+
+    // 刷新未读分享标记
+    function refreshUnreadCount(count) {
+        if (count) {
+            $('#unread-share-count').text(count);
+            $('#unread-share-count').show();
+        } else {
+            $('#unread-share-count').hide();
+        }
     }
 
-    function handleCooperateChange() {
+
+    
+    // 主页面的分享权限变更后相关处理函数
+    function handleMainCooperateChange() {
         setLocalCache(commonConstants.StorageKey.ONCE_MAIN_LOADED, '分享设置已被修改,当前项目已自动刷新。');
         window.location.reload();
     }
+    function handleMainCancelPermission() {
+        // 定位到空白页
+        window.location.replace(`/blank?type=${commonConstants.BlankType.SHARE_CANCEL}`);
+    }
+    function handleShare(params) {
+        
+    }
 
     // 刷新项目管理树视图
     // 如果是在项目管理页面,需要刷新树(分享图标可能需要清除)
@@ -498,5 +574,7 @@ const SHARE_TO = (() => {
         permissionChangeListener,
         emitPermissionChange,
         getAvatarHTML,
+        notify,
+        removeUnread,
     }
 })();

+ 8 - 0
web/common/html/header.html

@@ -1,5 +1,13 @@
 <img id="f_btn" src="/web/dest/css/img/feeRate_btn.jpg" alt="" style="display: none" />
 <!-- <nav class="navbar p-0 "> -->
+<div class="top-msg clearfix">
+    <div class="alert alert-warning alert-dismissible" role="alert" id="notify" style="display: none">
+        <button type="button" class="close" aria-label="Close" onclick="$('#notify').hide();">
+            <span aria-hidden="true">&times;</span>
+        </button>
+        <strong id="message"></strong>-
+    </div>
+</div>
 <nav class="navbar navbar-expand-lg p-0 d-flex <%= versionName.includes('免费') ? 'free-version' : 'pro-version' %>">
     <% if(controller === 'boot' || controller === 'pm'){ %>
     <!--<a style="text-decoration: none" href="javascript:void(0);" class="header-logo">-->