Browse Source

project gc

zhongzewei 7 years ago
parent
commit
03851d9028

+ 1 - 1
modules/glj/models/unit_price_file_model.js

@@ -133,7 +133,7 @@ class UnitPriceFileModel extends BaseModel {
      * @return {Promise}
      */
     async getGCUnitPriceFiles(userID){
-        let condition = {userID: userID, 'deleteInfo.deleted': true};
+        let condition = {user_id: userID, 'deleteInfo.deleted': true};
         let result = await this.findDataByCondition(condition, null, false);
         return result;
     }

+ 54 - 43
modules/pm/controllers/pm_controller.js

@@ -4,6 +4,7 @@
 import UnitPriceFileModel from "../../glj/models/unit_price_file_model";
 let ProjectsData = require('../models/project_model').project;
 let projType = require('../models/project_model').projType;
+let fileType = require('../models/project_model').fileType;
 const engineering = require("../../common/const/engineering");
 let EngineeringLibModel = require("../../users/models/engineering_lib_model");
 let fee_rate_facade = require("../../fee_rates/facade/fee_rates_facade");
@@ -191,61 +192,71 @@ module.exports = {
             callback(request, response, error.err, error.msg, responseData);
         }
     },
-    //拼接获取回收站数据
+
     getGCDatas: async function(request, response) {
         let userID = req.session.sessionUser.ssoId;
-        let engIdsSet = new Set(), rootIdsSet = new Set(), rst = [];
+        let rst = [];
+        let _projs = Object.create(null), _engs = Object.create(null), prefix = 'ID_';
         try{
-            let gc_unitPriceFiles = await ProjectsData.getGCFiles('UnitPriceFile', userID);
-            let gc_feeRateFiles = await ProjectsData.getGCFiles('FeeRateFile', userID);
+            let gc_unitPriceFiles = await ProjectsData.getGCFiles(fileType.unitPriceFile, userID);
+            let gc_feeRateFiles = await ProjectsData.getGCFiles(fileType.feeRateFile, userID);
             let gc_tenderFiles = await ProjectsData.getGCFiles(projType.tender, userID);
-            if(gc_unitPriceFiles.length > 0){
-                gc_unitPriceFiles.forEach(function (obj) {
-                    rootIdsSet.add(obj.rootProjectID);
-                });
-            }
-            if(gc_feeRateFiles.length > 0){
-                gc_feeRateFiles.forEach(function (obj) {
-                    rootIdsSet.add(obj.rootProjectID);
-                });
-            }
+                for(let i = 0, len = gc_unitPriceFiles.length; i < len; i++){
+                    let gc_uf = gc_unitPriceFiles[i];
+                    let theProj = _projs[prefix + gc_uf.root_project_id] || null;
+                    if(!theProj){
+                        theProj = _projs[prefix + gc_uf.root_project_id] = await ProjectsData.getProjectsByIds([gc_uf.root_project_id]);
+                        buildProj(theProj);
+                    }
+                    theProj.unitPriceFiles.push(gc_uf);
+                }
+                for(let i = 0, len = gc_feeRateFiles.length; i < len; i++){
+                    let gc_ff = gc_feeRateFiles[i];
+                    let theProj = _projs[prefix + gc_ff.rootProjectID] || null;
+                    if(!theProj){
+                        theProj = _projs[prefix + gc_ff.rootProjectID] = await ProjectsData.getProjectsByIds([gc_ff.rootProjectID]);
+                        buildProj(theProj);
+                    }
+                    theProj.feeRateFiles.push(gc_ff);
+                }
             if(gc_tenderFiles.length > 0){
-                rst = rst.concat(gc_tenderFiles);
-                gc_tenderFiles.forEach(function (obj) {
-                    engIdsSet.add(obj.ParentID);
-                });
-            }
-            if(engIdsSet.size > 0){
-                let engineerings = await ProjectsData.getProjectsByIds(Array.from(engIdsSet));
-                engineerings.forEach(function (obj) {
-                    rst.push(obj);
-                    rootIdsSet.add(obj.ParentID);
-                });
-            }
-            if(rootIdsSet.size > 0){
-                let projects = await ProjectsData.getProjectsByIds(Array.from(rootIdsSet));
-                for(let i = 0, len = projects.length; i < len; i++){
-                    projects[i].unitPriceFiles = [];
-                    projects[i].feeRateFiles = [];
-                    for(let j = 0, jLen = gc_unitPriceFiles.length; j < jLen; j++){
-                        if(gc_unitPriceFiles[j].rootProjectID === projects[i].ID){
-                            projects[i].unitPriceFiles.push(gc_unitPriceFiles);
-                            break;
-                        }
+                for(let i = 0, len = gc_tenderFiles.length; i < len; i++){
+                    let gc_t = gc_tenderFiles[i];
+                    let theEng = _engs[prefix + gc_t.ParentID] || null;
+                    if(!theEng){
+                        theEng = _engs[prefix + gc_t.ParentID] = await ProjectsData.getProjectsByIds([gc_t.ParentID]);
+                        theEng.children = [];
                     }
-                    for(let j = 0, jLen = gc_feeRateFiles.length; j < jLen; j++){
-                        if(gc_feeRateFiles[j].rootProjectID === projects[i].ID){
-                            projects[i].feeRateFiles.push(gc_feeRateFiles[j]);
-                            break;
-                        }
+                    theEng.children.push(gc_t);
+                    let theProj = _projs[prefix + theEng.ParentID] || null;
+                    if(!theProj){
+                        theProj = _projs[prefix + theEng.ParentID] = await ProjectsData.getProjectsByIds([theEng.ParentID]);
+                        buildProj(theProj);
                     }
+                    theProj.children.push(theEng);
                 }
-                rst = rst.concat(projects);
+            }
+            for(let i of _projs){
+                rst.push(i);
+            }
+            function buildProj(proj){
+                proj.children = [];
+                proj.unitPriceFiles = [];
+                proj.feeRateFiles = [];
             }
             callback(request, response, null, 'success', rst);
         }
         catch (error){
-            callback(request, response, true, 'fail', null);
+            callback(request, response, true, error, null);
         }
+    },
+
+    recGC: function(request, response){
+        let userID = request.session.sessionUser.ssoId;
+        let nodes = JSON.parse(request.body.nodes);
+        ProjectsData.recGC(userID, nodes, function (err, msg, data) {
+            callback(request, response, err, msg, data);
+        });
     }
+
 };

+ 84 - 1
modules/pm/models/project_model.js

@@ -2,6 +2,10 @@
  * Created by Mai on 2017/1/18.
  */
 import UnitPriceFileModel from "../../glj/models/unit_price_file_model";
+import async_c from 'async';
+import UnitPriceFiles from '../../glj/models/schemas/unit_price_file';
+import mongoose from 'mongoose';
+let FeeRateFiles = mongoose.model('fee_rate_file');
 let counter = require("../../../public/counter/counter.js");
 
 let newProjController = require('../controllers/new_proj_controller');
@@ -18,6 +22,11 @@ let projectType = {
     project: 'Project',
     engineering: 'Engineering',
 };
+//回收站恢复级别
+let fileType = {
+    unitPriceFile: 'UnitPriceFile',
+    feeRateFile: 'FeeRateFile'
+};
 
 let ProjectsDAO = function(){};
 
@@ -240,11 +249,84 @@ ProjectsDAO.prototype.getGCFiles = async function (fileType, userID){
         rst = await feeRateFacade.getGCFeeRateFiles(userID);
     }
     else {
+        let isExist = false;
+        for(let type of projectType){
+            if(type === fileType) isExist = true;
+            break;
+        }
+        if(!isExist) throw '不存在此项目类型!';
         rst = await Projects.find({projType: fileType, 'deleteInfo.deleted': true});
     }
     return rst;
 };
 
+ProjectsDAO.prototype.getFirstNodeID = async function (userID, projType) {
+    if(projType !== projectType.project) throw '只能为建设项目层';
+    let nodes = await Projects.find({userID: userID, projType: projType, deleteInfo: null});
+    if(nodes.length === 0){
+        return -1;
+    }
+    else {
+        let chain = Object.create(null);
+        for(let i = 0, len = nodes.length; i < len; i++){
+            let node = Object.create(null);
+            node.ID = nodes[i].ID;
+            node.NextSiblingID = nodes[i].NextSiblingID;
+            chain[node.ID] = node;
+        }
+        for(let i =0, len = nodes.length; i < len; i++){
+            let next = nodes[i].NextSiblingID > 0 ? chain[nodes[i].NextSiblingID] : null;
+            chain[nodes[i].ID].next = next;
+            if(next){
+                next.pre = chain[nodes[i].ID]
+            }
+        }
+        for(let node of chain){
+            let pre = node.pre || null;
+            if(!pre){
+                return node.ID;
+            }
+        }
+    }
+};
+
+ProjectsDAO.prototype.recGC = async function(userID, datas, callback){
+    let functions = [];
+    for(let i = 0, len = datas.length; i < len; i++){
+        if(datas[i].updateType === projectType.project && datas[i].updateData.NextSiblingID === undefined){//则为待查询NextSiblingID,前端无法查询
+            let firstNodeID = await this.getFirstNodeID(userID, projectType.project);
+            datas[i].updateData.NextSiblingID = firstNodeID;
+        }
+        functions.push((function(data){
+                return function (cb) {
+                    if(data.updateType === fileType.unitPriceFile){
+                        UnitPriceFiles.update(data.findData, data.updateData, function (err) {
+                            if(err) cb(err);
+                            else cb(false);
+                        })
+                    }
+                    else if(data.updateType === fileType.feeRateFile){
+                        FeeRateFiles.update(data.findData, data.updateData, function (err) {
+                            if(err) cb(err);
+                            else cb(false);
+                        });
+                    }
+                    else{
+                        Projects.update(data.findData, data.updateData, function (err) {
+                            if(err)cb(err);
+                            else cb(false);
+                        });
+                    }
+                }
+            }
+        )(datas[i]));
+    }
+    async_c.parallel(functions, function (err, results) {
+        if(err) callback(err, 'fail', null);
+        else callback(false, 'success', null);
+    });
+};
+
 /**
  * 整理工程专业对应标准库数据
  *
@@ -367,5 +449,6 @@ ProjectsDAO.prototype.changeUnitPriceFileInfo = async function(projectId, change
 
 module.exports ={
     project: new ProjectsDAO(),
-    projType: projectType
+    projType: projectType,
+    fileType: fileType
 };

+ 7 - 0
modules/pm/routes/pm_route.js

@@ -11,6 +11,10 @@ module.exports = function (app) {
 
     app.get('/pm', baseController.init, pmController.index);
 
+    app.get('/pm/gc',baseController.init, function (req, res) {
+        res.render('building_saas/pm/html/project-management-Recycle.html');
+    });
+
     let pmRouter = express.Router();
 
     pmRouter.use(function (req, res, next) {
@@ -43,6 +47,9 @@ module.exports = function (app) {
     pmRouter.post('/getNewProjectID', pmController.getNewProjectID);
     pmRouter.post('/getUnitFile', pmController.getUnitFileList);
     pmRouter.post('/getFeeRateFile', pmController.getFeeRateFileList);
+    //GC
+    pmRouter.post('/getGCDatas', pmController.getGCDatas);
+    pmRouter.post('/recGC', pmController.recGC);
 
     app.use('/pm/api', pmRouter);
 };

+ 1 - 1
public/web/tree_table/tree_table.js

@@ -270,7 +270,7 @@
  					} else {
  						parent.children.splice(parent.childIndex(next), 0, node);
  					}
- 				} else if (parent.childIndex(node) !== parent.childIndex(node.next) - 1) {
+ 				} else if (node.nextSibling && parent.childIndex(node) !== parent.childIndex(node.nextSibling) - 1) {
 					parent.children.splice(parent.childIndex(node), 1);
 					parent.children.splice(parent.childIndex(next), 0, node);
 				};

+ 67 - 0
web/building_saas/pm/html/project-management-Recycle.html

@@ -0,0 +1,67 @@
+<div class="toolsbar">
+    <legend class="m-0 pb-1">全部</legend>
+</div>
+<div class="poj-list">
+    <table class="table table-hover table-sm mb-5" id="gcTree">
+        <thead>
+        <tr>
+            <th width="50%">工程列表</th>
+            <th width="10%">删除日期</th>
+            <th width="10%">创建日期</th>
+            <th width="10%">恢复</th>
+            <th width="10%">单价文件</th>
+            <th width="10%">费率文件</th>
+        </tr>
+        </thead>
+        <tbody>
+        </tbody>
+    </table>
+</div>
+<!--弹出恢复项目-->
+<div class="modal fade" id="rePoj" data-backdrop="static">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">恢复 <i class="fa fa-cubes"></i> 建设项目</h5>
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                    <span aria-hidden="true">&times;</span>
+                </button>
+            </div>
+            <div class="modal-body">
+                <p><i class="fa fa-cubes"></i> 汽车生产车间 下的单位工程都将恢复都将恢复,恢复后将重命名为</p>
+                <p><b>建筑工程2(10-25 14:33:15恢复)</b>、<b>建筑工程3(10-25 14:33:15恢复)</b></p>
+                <p> 点“确定”按钮,确认从回收站中恢复。</p>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                <a href="javascript:void(0);" class="btn btn-primary" data-dismiss="modal" id="rePojBtn">确定</a>
+            </div>
+        </div>
+    </div>
+</div>
+<!--弹出恢复文件-->
+<div class="modal fade" id="reFile" data-backdrop="static">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">恢复单价文件</h5>
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                    <span aria-hidden="true">&times;</span>
+                </button>
+            </div>
+            <div class="modal-body modal-fixed-height">
+                <p>勾选需要恢复的文件,点“确定”按钮,确认从回收站中恢复。</p>
+                <table class="table table-hover table-sm mb-5">
+                    <thead><tr><th>名称</th><th>删除时间</th><th>勾选</th></tr></thead>
+                    <tbody>
+                    <tr><td>XX单价文件</td><td>2017-11-01<br>12:11:43</td><td><input type="checkbox"></td></tr>
+                    </tbody>
+                </table>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                <a href="javascript:void(0);" class="btn btn-primary" id="reFileBtn" data-dismiss="modal">确定</a>
+            </div>
+        </div>
+    </div>
+</div>

+ 38 - 30
web/building_saas/pm/html/project-management.html

@@ -91,7 +91,7 @@
                         <input type="text" class="my-2 form-control form-control-sm" placeholder="搜索所有工程">
                         <ul class="nav nav-pills flex-column">
                             <li class="nav-item">
-                                <a class="nav-link active" href="#">全部</a>
+                                <a class="nav-link active" data-toggle="tab" href="#pm_all" role="tab" id="tab_pm_all">全部</a>
                             </li>
                             <li class="nav-item">
                                 <a class="nav-link" href="#">最近使用</a>
@@ -106,42 +106,49 @@
                                 <a class="nav-link" href="#">归档</a>
                             </li>
                             <li class="nav-item">
-                                <a class="nav-link" href="#">回收站</a>
+                                <a class="nav-link" data-toggle="tab" role="tab" href="#pm_gc" id="tab_pm_gc">回收站</a>
                             </li>
                         </ul>
                     </div>
                 </div>
                 <div class="col-lg-10">
-                <div class="toolsbar">
-                    <div class="tools-btn btn-group align-top">
-                        <a href="javascript:void(0);" class="btn btn-sm" id="add-project-btn"><i class="fa fa-cubes"></i>&nbsp;新建建设项目</a>
-                        <a href="javascript:void(0);" class="btn btn-sm" id="add-engineering-btn"><i class="fa fa-cube"></i>&nbsp;新建单项工程</a>
-                        <a href="javascript:void(0);" class="btn btn-sm" id="add-tender-btn"><i class="fa fa-sticky-note-o"></i>&nbsp;新建单位工程</a>
-                        <a href="javascript:void(0);" class="btn btn-sm" id="add-folder-btn"><i class="fa fa-folder-o"></i>&nbsp;新建文件夹</a>
-                        <a href="javascript:void(0);" class="btn btn-sm" id="rename-btn">重命名</a>
-                        <a href="javascript:void(0);" class="btn btn-sm" id="del-btn">删除</a>
-                        <a href="javascript:void(0);" class="btn btn-sm" id="move-to-btn">移动到...</a>
-                        <a href="javascript:void(0);" class="btn btn-sm" id="copy-to-btn">复制到...</a>
-                        <a href="" class="btn btn-sm" id="share-btn">共享</a>
-                        <a href="" class="btn btn-sm" id="cooperate-btn">协同</a>
+                    <div class="tab-content">
+                        <div class="tab-pane active" id="pm_all" role="tabpanel">
+                        <div class="toolsbar">
+                            <div class="tools-btn btn-group align-top">
+                                <a href="javascript:void(0);" class="btn btn-sm" id="add-project-btn"><i class="fa fa-cubes"></i>&nbsp;新建建设项目</a>
+                                <a href="javascript:void(0);" class="btn btn-sm" id="add-engineering-btn"><i class="fa fa-cube"></i>&nbsp;新建单项工程</a>
+                                <a href="javascript:void(0);" class="btn btn-sm" id="add-tender-btn"><i class="fa fa-sticky-note-o"></i>&nbsp;新建单位工程</a>
+                                <a href="javascript:void(0);" class="btn btn-sm" id="add-folder-btn"><i class="fa fa-folder-o"></i>&nbsp;新建文件夹</a>
+                                <a href="javascript:void(0);" class="btn btn-sm" id="rename-btn">重命名</a>
+                                <a href="javascript:void(0);" class="btn btn-sm" id="del-btn">删除</a>
+                                <a href="javascript:void(0);" class="btn btn-sm" id="move-to-btn">移动到...</a>
+                                <a href="javascript:void(0);" class="btn btn-sm" id="copy-to-btn">复制到...</a>
+                                <a href="" class="btn btn-sm" id="share-btn">共享</a>
+                                <a href="" class="btn btn-sm" id="cooperate-btn">协同</a>
+                            </div>
+                        </div>
+                        <div class="poj-list">
+                            <legend>全部</legend>
+                            <table class="table table-hover table-sm" id="ProjTree">
+                                <thead>
+                                <tr>
+                                    <th width="40"></th>
+                                    <th width="78%">工程列表</th>
+                                    <th width="10%">最近使用</th>
+                                    <th width="10%">创建日期</th>
+                                </tr>
+                                </thead>
+                                <tbody>
+                                </tbody>
+                            </table>
+                        </div>
+                        </div>
+                        <div class="tab-pane" role="tabpanel" id="pm_gc">
+                            <%include project-management-Recycle.html %>
+                        </div>
                     </div>
                 </div>
-                <div class="poj-list">
-                    <legend>全部</legend>
-                    <table class="table table-hover table-sm" id="ProjTree">
-                        <thead>
-                        <tr>
-                            <th width="40"></th>
-                            <th width="78%">工程列表</th>
-                            <th width="10%">最近使用</th>
-                            <th width="10%">创建日期</th>
-                        </tr>
-                        </thead>
-                        <tbody>
-                        </tbody>
-                    </table>
-                </div>
-            </div>
         </div>
     </div>
     <div class="slide-sidebar">
@@ -505,6 +512,7 @@
 <script type="text/javascript" src="/public/web/common_ajax.js"></script>
 <script src="/web/building_saas/pm/js/pm_ajax.js"></script>
 <script src="/web/building_saas/pm/js/pm_main.js" charset="UTF-8"></script>
+<script src="/web/building_saas/pm/js/pm_gc.js"></script>
 <!-- zTree -->
 <script type="text/javascript" src="/lib/ztree/jquery.ztree.core.js"></script>
 <script type="text/javascript" src="/lib/ztree/jquery.ztree.excheck.js"></script>

+ 656 - 0
web/building_saas/pm/js/pm_gc.js

@@ -0,0 +1,656 @@
+/**
+ * Created by Zhong on 2017/10/30.
+ */
+//测试数据
+let deleteInfo = {deleteBy: 76075, deleteDateTime: '2017-10-31', deleted: true};
+let temp_gc_datas = [
+    {ID: 1, ParentID: -1, NextSiblingID: 7, name: 'testTreeA', projType: 'Project', userID: 76075, createDateTime: '2017-10-30', deleteInfo: deleteInfo,
+        unitPriceFiles: [{name: 'uA', id: 100, root_project_id: 1, user_id: 76075, deleteInfo: deleteInfo}, {name: 'uB', id: 101, root_project_id: 1, user_id: 76075, deleteInfo: deleteInfo}],
+        feeRateFiles: [{name: 'fA', ID: 'fr-1', rootProjectID: 1, userID: 76075, deleteInfo: deleteInfo}, {name: 'fB', ID: 'fr-2', rootProjectID: 1, userID: 76075, deleteInfo: deleteInfo}]},
+    {ID: 2, ParentID: 1, NextSiblingID: 3, name: 'enA', projType: 'Engineering', userID: 76075, createDateTime: '2017-10-30', deleteInfo: deleteInfo},
+    {ID: 3, ParentID: 1, NextSiblingID: -1, name: 'enB', projType: 'Engineering', userID: 76075, createDateTime: '2017-10-30', deleteInfo: deleteInfo},
+    {ID: 4, ParentID: 3, NextSiblingID: 5, name: 'tenderA', projType: 'Tender', userID: 76075, createDateTime: '2017-10-30', deleteInfo: deleteInfo, property: {feeFile: {id: 'fr-1', name: 'fA'}, unitPriceFile: {id: 100, name: 'uA'}}},
+    {ID: 5, ParentID: 3, NextSiblingID: 6, name: 'tenderB', projType: 'Tender', userID: 76075, createDateTime: '2017-10-30', deleteInfo: deleteInfo, property: {feeFile: {id: 'unD-1', name: 'unDF'}, unitPriceFile: {id: 100, name: 'uA'}}},
+    {ID: 6, ParentID: 3, NextSiblingID: -1, name: 'tenderC', projType: 'Tender', userID: 76075, createDateTime: '2017-10-30', deleteInfo: deleteInfo, property: {feeFile: {id: 'fr-2', name: 'fB'}, unitPriceFile: {id: 101, name: 'uB'}}},
+    {ID: 7, ParentID: -1, NextSiblingID: 10, name: 'testTreeB', projType: 'Project', userID: 76075, createDateTime: '2017-10-30', deleteInfo: deleteInfo,
+        unitPriceFiles: [{name: 'uC', id: 102, root_project_id: 7, user_id: 76075, deleteInfo: deleteInfo}, {name: 'uD', id: 103, root_project_id: 7, user_id: 76075, deleteInfo: deleteInfo}],
+        feeRateFiles: [{name: 'fC', ID: 'fr-3', rootProjectID: 7, userID: 76075, deleteInfo: deleteInfo}]},
+    {ID: 8, ParentID: 7, NextSiblingID: -1, name: 'enC', projType: 'Engineering', userID: 76075, createDateTime: '2017-10-30', deleteInfo: deleteInfo},
+    {ID: 9, ParentID: 8, NextSiblingID: -1, name: 'tenderD', projType: 'Tender', userID: 76075, createDateTime: '2017-10-30', deleteInfo: deleteInfo, property: {feeFile: {id: 'fr-3', name: 'fC'}, unitPriceFile: {id: 102, name: 'uC'}}},
+    {ID: 10, ParentID: -1, NextSiblingID: -1, name: 'testTreeC', projType: 'Project', userID: 76075, createDateTime: '2017-10-30', unitPriceFiles: [], feeRateFiles: [{name: 'fC', ID: 'fr-3', rootProjectID: 7, userID: 76075, deleteInfo: deleteInfo}]},
+    {ID: 11, ParentID: 10, NextSiblingID: -1, name: 'enD', projType: 'Engineering', userID: 76075, createDateTime: '2017-10-30'},
+    {ID: 12, ParentID: 11, NextSiblingID: -1, name: 'tenderE', projType: 'Tender', userID: 76075, createDateTime: '2017-10-30', deleteInfo: deleteInfo, property: {feeFile: {id: 'fr-3', name: 'fC'}, unitPriceFile: {id: 103, name: 'uD'}}},
+    {ID: 13, ParentID: 2, NextSiblingID: 14, name: 'tenderF', projType: 'Tender', userID: 76075, createDateTime: '2017-10-30', deleteInfo: deleteInfo, property: {feeFile: {id: 'unD-2', name: 'unDF2'}, unitPriceFile: {id: 102, name: 'uC'}}},
+    {ID: 14, ParentID: 2, NextSiblingID: 15, name: 'tenderG', projType: 'Tender', userID: 76075, createDateTime: '2017-10-30', deleteInfo: deleteInfo, property: {feeFile: {id: 'fr-3', name: 'fC'}, unitPriceFile: {id: 102, name: 'uC'}}},
+    {ID: 15, ParentID: 2, NextSiblingID: -1, name: 'tenderH', projType: 'Tender', userID: 76075, createDateTime: '2017-10-30', deleteInfo: deleteInfo, property: {feeFile: {id: 'qwqw', name: 'qweq'}, unitPriceFile: {id: 300, name: 'u30'}}}
+
+];
+
+/*function getTestDatas(){
+    let rst = [];
+    for(let i = 0; i < 1000; i ++){
+        let nid = i + 1 < 1000 ? i + 1 : -1;
+        let obj = {ID: i, ParentID: -1, NextSiblingID: nid, name : 'test' + i, projType: 'Project', userID: 76075, createDateTime: '2017-11-3', deleteInfo: deleteInfo,
+            unitPriceFiles: [{name: 'up' + i, id: i + 10000, deleteInfo: deleteInfo}], feeRateFiles: [{name: 'ff' + i, id: 'fr-' + i, deleteInfo: deleteInfo}]};
+        rst.push(obj);
+    }
+    return rst;
+}*/
+let gcTree = null;
+let decDate = null;//恢复后的名称后缀(时间+恢复)
+/*let projectType = {
+    folder: 'Folder',
+    tender: 'Tender',
+    project: 'Project',
+    engineering: 'Engineering'
+};*/
+let fileType = {
+    unitPriceFile: 'UnitPriceFile',
+    feeRateFile: 'FeeRateFile'
+};
+//恢复路径t = tender, e = engineering, p = project
+let recPath = {t: 'T', t_e: 'T_E', t_e_p: 'T_E_P', e: 'E', e_p: 'E_P', p: 'P'};
+let gcTreeSetting = {
+    tree: {
+        id: 'ID',
+        pid: 'ParentID',
+        nid: 'NextSiblingID',
+        btnColumn: 1,
+        nullId: -1
+    },
+    columns: [
+        {
+            head: '',
+            data: '',
+            width: '40',
+            event: {}
+        },
+        {
+            head: '工程列表',
+            data: 'name',
+            width: '50%',
+            event: {
+                getText: function (html, node, text) {
+                    let className = '';
+                    switch (node.data.projType) {
+                        case projectType.folder:
+                            className = "fa fa-folder-open-o";
+                            break;
+                        case projectType.tender:
+                            className = "fa fa-sticky-note-o";
+                            break;
+                        case projectType.project:
+                            className = "fa fa-cubes";
+                            break;
+                        case projectType.engineering:
+                            className = "fa fa-cube";
+                            break;
+                    }
+                    let icon = '<i class ="tree-icon '+ className +'"></i>';
+                    html.push(icon, '&nbsp;', text);
+                },
+                getIcon: function (html, node) {
+                    if (node.data.projType === projectType.tender) {
+                        html.push('<span class="poj-icon">└</span>');
+                    }
+                }
+            }
+        },
+        {
+            head: '删除日期',
+            data: 'deleteDateTime',
+            width: '10%',
+            event: {
+                getText: function (html, node, text) {
+                    if (node.data.projType === projectType.tender) {
+                        html.push(deleted(node) ?
+                            node.data.deleteInfo.deleteDateTime : '');
+                     //   html.push(text ? new Date(text).Format('yyyy-MM-dd') : '');
+                    }
+                }
+            }
+        },
+        {
+            head: '创建日期',
+            data: 'createDateTime',
+            width: '10%',
+            event: {
+                getText: function (html, node, text) {
+                    if (node.data.projType === projectType.tender) {
+                      html.push(text ? text : '');
+                    }
+                }
+            }
+        },
+        {
+            head: '恢复',
+            data: 'recovery',
+            width: '10%',
+            event: {
+                getText: function (html, node, text) {
+                    if(node.data.projType === projectType.project && deleted(node)){
+                        html.push('<a href="javascript:void(0);" data-toggle="modal" data-target="#rePoj">恢复</a>');
+                    }
+                    else if(node.data.projType === projectType.engineering && deleted(node)){
+                        html.push('<a href="javascript:void(0);" data-toggle="modal" data-target="#rePoj">恢复</a>');
+                    }
+                    else if(node.data.projType === projectType.tender && deleted(node)){
+                        html.push('<a href="javascript:void(0);" data-toggle="modal" data-target="#rePoj">恢复</a>');
+                    }
+                    else {
+                        html.push('');
+                    }
+                },
+                tdBindEvent: function(td, node){
+                    $('a:eq(0)' ,td).bind('click', function () {
+                        let tenderNodes = m_getTenders(node);
+                        $('#rePoj .modal-header').empty();
+                        $('p', '#rePoj .modal-body').remove();
+                        $('#rePoj .modal-header').html(v_getTitle(node));
+                        $('#rePoj .modal-body').html(v_getMoBody(node, tenderNodes));
+                        console.log(node);
+                        console.log(node.preSibling());
+                        //test 获取更新的数据
+                        /*let updateDatas = m_getRecDatas(node);
+                        console.log(updateDatas);*/
+                    });
+                }
+            }
+        },
+        {
+            head: '单价文件',
+            data: 'unitPriceFiles',
+            width: '10%',
+            event: {
+                getText: function (html, node, text) {
+                    if(node.data.projType === projectType.project && node.data.unitPriceFiles !== undefined && node.data.unitPriceFiles.length > 0){
+                        html.push('<a href="javascript:void(0);" data-toggle="modal" data-target="#reFile">恢复</a>');
+                    }
+                },
+                tdBindEvent: function (td, node) {
+                    $('a:eq(0)', td).bind('click', function () {
+                        let unitPriceFiles = node.data.unitPriceFiles;
+                        $('#reFile h5').text('恢复单价文件');
+                        $('tr', '#reFile tbody').remove();
+                        $('#reFile tbody').html(v_getFiles(fileType.unitPriceFile, unitPriceFiles));
+                    });
+                }
+            }
+        },
+        {
+            head: '费率文件',
+            data: 'feeRateFiles',
+            width: '10%',
+            event: {
+                getText: function (html, node, text) {
+                    if(node.data.projType === projectType.project && node.data.feeRateFiles !== undefined && node.data.feeRateFiles.length > 0){
+                        html.push('<a href="javascript:void(0);" data-toggle="modal" data-target="#reFile">恢复</a>');
+                    }
+                },
+                tdBindEvent: function (td, node) {
+                    $('a:eq(0)', td).bind('click', function () {
+                        let feeRateFiles = node.data.feeRateFiles;
+                       $('#reFile h5').text('恢复费率文件');
+                        $('tr', '#reFile tbody').remove();
+                        $('#reFile tbody').html(v_getFiles(fileType.feeRateFile, feeRateFiles));
+                    });
+                }
+            }
+        }
+    ]
+};
+
+$(document).ready(function () {
+    $('#tab_pm_gc').on('show.bs.tab', function () {
+        gc_init();
+        Tree = null;
+    });
+    e_recFiles($('#reFileBtn'));
+    e_recProj($('#rePojBtn'));
+});
+
+function gc_init(){
+    let table = $('#gcTree');
+    $('thead', table).remove();
+    $('tbody', table).remove();
+    m_buildVirtualTree(temp_gc_datas);
+    gcTree = $.fn.treeTable.init(table, gcTreeSetting, temp_gc_datas);
+    //gcTree = $.fn.treeTable.init(table, gcTreeSetting, getTestDatas());
+}
+
+//项目恢复模态框标题
+function v_getTitle(node){
+    let html = '';
+    html += '<h5 class="modal-title">恢复 ';
+    if(node.data.projType === projectType.project){
+        html += '<i class="fa fa-cubes"></i>建设项目</h5>';
+    }
+    else if(node.data.projType === projectType.engineering){
+        html += '<i class="fa fa-cube"></i>单项工程</h5>';
+    }
+    else if(node.data.projType === projectType.tender){
+        html += '<i class="fa fa-sticky-note-o"></i>单位工程</h5>';
+    }
+    html += '<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>';
+    return html;
+}
+
+//项目恢复模态框主体
+function v_getMoBody(oprNode, nodes){
+    let html = '';
+    if(oprNode.data.projType === projectType.tender){
+        decDate = '(' + new Date().Format('MM-dd hh:mm:ss') + '恢复)';
+        let recName = oprNode.data.name + decDate;
+        html += '<p>恢复后将重命名为 <b>' + recName + '</b></p>';
+    }
+    else {
+        if(oprNode.data.projType === projectType.project){
+            html += '<p><i class="fa fa-cubes"></i> ' + oprNode.data.name + '下的单位工程都将恢复都将恢复,恢复后将重命名为</p>';
+        }
+        else if(oprNode.data.projType === projectType.engineering){
+            html += '<p><i class="fa fa-cube"></i> ' + oprNode.data.name + '下的单位工程都将恢复都将恢复,恢复后将重命名为</p>';
+        }
+        html += ('<p>');
+        for(let i = 0, len = nodes.length; i < len; i++){
+            let recName = nodes[i].data.name + '(' + new Date().Format('MM-dd hh:mm:ss') +'恢复)';
+            html += '<b>' + recName + '</b>、';
+        }
+        html = html.slice(0, html.length - 1);
+        html += ('</p>');
+    }
+
+    html += ('<p>点“确定”按钮,确认从回收站中恢复</p>');
+    return html;
+}
+
+//单价、费率文件恢复弹出框数据
+function v_getFiles(type, files){
+    let html = '';
+    for(let i = 0, len = files.length; i < len; i ++){
+        let recName = type === fileType.unitPriceFile ?  files[i].name + '单价文件' : files[i].name + '费率文件';
+        let fileId = type === fileType.unitPriceFile ? files[i].id : files[i].ID;
+        let recTime = new Date();
+        let recTimeA = recTime.Format('yyyy-MM-dd');
+        let recTimeB = recTime.Format('hh:mm:ss');
+        html += '<tr><td>'+ recName +'</td><td>' + recTimeA + '<br>' + recTimeB + '</td><td><input name="fileItems" type="checkbox" fileId = "' + fileId + '" fileType = "' + type + '"></td></tr>';
+    }
+    return html;
+}
+
+//恢复单价、费率文件后前端显示变化
+function v_recFiles(project, fileIds, type){
+    let projFiles;
+    if(type === fileType.unitPriceFile){
+        projFiles = project.data.unitPriceFiles;
+    }
+    else if(type === fileType.feeRateFile){
+        projFiles = project.data.feeRateFiles;
+    }
+    if(projFiles && projFiles.length > 0){
+        let tempFiles = [];
+        for(let i = 0, len = projFiles.length; i < len; i++){
+            let isExist = false;
+            for(let j = 0, jLen = fileIds.length; j < jLen; j++){
+                let id = projFiles[i].id || projFiles[i].ID || null;
+                if(id && id === fileIds[j]){
+                    isExist = true;
+                }
+            }
+            if(!isExist){
+                tempFiles.push(projFiles[i]);
+            }
+        }
+        if(type === fileType.unitPriceFile){
+            project.data.unitPriceFiles = tempFiles;
+        }
+        else if(type === fileType.feeRateFile){
+           project.data.feeRateFiles = tempFiles;
+        }
+    }
+}
+
+function v_removeNode(node){
+    gcTree.removeNode(node);
+    let parent = node.parent || null;
+    if(parent && parent.children.length === 0 && parent.data !== undefined){
+        v_removeNode(parent);
+    }
+}
+
+function v_refreshNode(node){
+    if(deleted(node)){
+        delete node.data.deleteInfo;
+    }
+    gcTree.refreshNodesDom([node]);
+    let parent = node.parent || null;
+    if(parent && parent.data !== undefined){
+        v_refreshNode(parent);
+    }
+}
+
+//将获取的回收站中的数据建虚拟树
+function m_buildVirtualTree(datas){
+    for(let i = 0, len = datas.length; i < len; i++){
+        let children = datas[i].children || null;
+        if(children){
+            m_buildVirtualTree(children);
+        }
+        let next = datas[i+1] || null;
+        if(next){
+            datas[i].NextSiblingID = next.ID;
+        }
+        else {
+            datas[i].NextSiblingID = -1;
+        }
+    }
+}
+
+//获得当前节点的tenders数据,模态提示框用
+function m_getTenders(node){
+    if(node.data.projType === projectType.tender) return [node];
+    else {
+        let rst = [];
+        if(node.children.length > 0){
+            node.children.forEach(function (cNode) {
+                if(cNode.children.length > 0){
+                    cNode.children.forEach(function (ccNode) {
+                       if(ccNode.data.projType === projectType.tender) rst.push(ccNode);
+                    });
+                }
+                else if(cNode.children.length === 0 && cNode.data.projType === projectType.tender){
+                    rst.push(cNode);
+                }
+            });
+        }
+        return rst;
+    }
+}
+
+//获得要更新的数据(包含恢复的数据,维护项目管理树的数据)
+function m_getRecDatas(oprNode){
+    let rst = Object.create(null);
+    let rstProj = [], rstFile = [];
+    let path;
+    if(oprNode.data.projType === projectType.tender){
+        path = recPath.t;
+        let engineering = oprNode.parent || null;
+        if(!engineering) return null;
+        let project = engineering.parent || null;
+        if(!project) return null;
+        if(engineering && deleted(engineering)){
+            path = recPath.t_e;
+        }
+        //恢复建设项目
+        if(project && deleted(project)){
+            path = recPath.t_e_p;
+        }
+        //恢复单价、费率文件
+        rstFile = rstFile.concat(getUpdateFiles([oprNode], project));
+        if(path === recPath.t){
+            rstProj = rstProj.concat(getUpdateDatas(projectType.tender, oprNode, true, true));
+        }
+        else if(path === recPath.t_e){
+            rstProj = rstProj.concat(getUpdateDatas(projectType.tender, oprNode, true, false));
+            rstProj = rstProj.concat(getUpdateDatas(projectType.engineering, engineering, true, true));
+        }
+        else if(path === recPath.t_e_p){
+            rstProj = rstProj.concat(getUpdateDatas(projectType.tender, oprNode, true, false));
+            rstProj = rstProj.concat(getUpdateDatas(projectType.engineering, engineering, true, false));
+            rstProj = rstProj.concat(getUpdateDatas(projectType.project, project, true, false));
+        }
+    }
+    else if(oprNode.data.projType === projectType.engineering){
+        path = recPath.e;
+        let project = oprNode.parent || null;
+        if(!project) return null;
+        //恢复建设项目
+        if(project && deleted(project)){
+            path = recPath.e_p;
+        }
+        let tenders = oprNode.children;
+        if(tenders.length > 0){
+            for(let i = 0, len = tenders.length; i < len; i++){
+                rstProj = rstProj.concat(getUpdateDatas(projectType.tender, tenders[i], true, false));
+            }
+            //恢复单价、费率文件
+            rstFile = rstFile.concat(getUpdateFiles(tenders, project));
+        }
+        if(path === recPath.e){
+            rstProj= rstProj.concat(getUpdateDatas(projectType.engineering, oprNode, true, true));
+        }
+        else if(path === recPath.e_p){
+            rstProj= rstProj.concat(getUpdateDatas(projectType.engineering, oprNode, true, false));
+            rstProj= rstProj.concat(getUpdateDatas(projectType.project, project, true, false));
+        }
+    }
+    else if(oprNode.data.projType === projectType.project){
+        path = recPath.p;
+        let engineerings = oprNode.children;
+        if(engineerings.length > 0){
+            let allTenders = [];
+            for(let i = 0, len = engineerings.length; i < len; i++){
+                //恢复单项工程
+                rstProj = rstProj.concat(getUpdateDatas(projectType.engineering, engineerings[i], false, false));
+                let tenders = engineerings[i].children;
+                allTenders = allTenders.concat(tenders);
+                for(let j = 0, jLen = tenders.length; j < jLen; j++){
+                    //恢复单位工程
+                    rstProj = rstProj.concat(getUpdateDatas(projectType.tender, tenders[j], false, false));
+                }
+            }
+            //恢复单价、费率文件
+            rstFile = rstFile.concat(getUpdateFiles(allTenders, oprNode));
+        }
+        //恢复建设项目
+        rstProj = rstProj.concat(getUpdateDatas(projectType.project, oprNode, false, false));
+    }
+    console.log(path);
+    rst.proj = rstProj;
+    rst.file = rstFile;
+    return rst;
+}
+
+//获得勾选的单价、费率文件的id
+function m_getFilesIds(nodes){
+    let rstSet = new Set();
+    for(let i = 0, len = nodes.length; i < len; i++){
+        let fileId = $(nodes[i]).attr('fileId') || null;
+        if(fileId){
+            if($(nodes[i]).attr('fileType') === fileType.unitPriceFile){
+                fileId = parseInt(fileId);
+            }
+            rstSet.add(fileId);
+        }
+    }
+    return Array.from(rstSet);
+}
+
+function m_project(node){
+    if(node && node.data.projType === projectType.project) return node;
+    if(!node) return null;
+    let parent = node.parent || null;
+    if(!parent) return null;
+    if(parent && parent.data.projType === projectType.project) return parent;
+
+    let gParent = parent.parent || null;
+    if(!gParent) return null;
+    if(gParent && gParent.data.projType === projectType.project) return gParent;
+    return null;
+}
+
+//点击单价文件、费率文件下的恢复操作(确认)
+function e_recFiles(btn){
+    btn.bind('click', function () {
+        let recIds = m_getFilesIds($('[name = "fileItems"]:checked'));
+        let fileType = $('[name = "fileItems"]:checked').attr('fileType');
+        let selected = gcTree.selected();
+        //backend
+        let updateDatas = [];
+        for(let i = 0, len = recIds.length; i < len; i++){
+            updateDatas.push(getUpdateObj(fileType, {id: recIds[i]}, {deleteInfo: null}));
+        }
+        //front
+        if(recIds.length > 0){
+            v_recFiles(selected, recIds, fileType);
+            if(deleted(selected)){
+                delete selected.data.deleteInfo;
+            }
+            gcTree.refreshNodesDom([selected]);
+        }
+    });
+}
+
+//点击项目下的恢复操作(确认
+function e_recProj(btn){
+    btn.bind('click', function () {
+        let selected = gcTree.selected();
+        //backend
+        let updateObj = m_getRecDatas(selected);
+        let updateDatas = updateObj.proj.concat(updateObj.file);
+        let fileObj = getRecFileObj(updateObj.file);
+        console.log(updateObj);
+        //保存成功后回调front
+        //front
+        let project = m_project(selected);
+        if(project){
+            if(fileObj[fileType.unitPriceFile].length > 0){
+                v_recFiles(project, fileObj[fileType.unitPriceFile], fileType.unitPriceFile);
+            }
+            if(fileObj[fileType.feeRateFile].length > 0){
+                v_recFiles(project, fileObj[fileType.feeRateFile], fileType.feeRateFile);
+            }
+        }
+        v_removeNode(selected);
+        v_refreshNode(selected);
+    });
+}
+
+function a_getGC(callback){
+    $.ajax({
+        type: 'post',
+        url: '/pm/api/getGCDatas',
+        dataType: 'json',
+        timeout: 5000,
+        success: function (result) {
+            if(!result.error){
+                if(callback){
+                    callback(result.data);
+                }
+            }
+        }
+    })
+}
+
+function a_rec(nodes, callback){
+    $.ajax({
+        type: 'post',
+        url: '/pm/api/recGC',
+        data: {nodes: JSON.stringify(nodes)},
+        dataType: 'json',
+        timeout: 5000,
+        success: function (result) {
+            if(!result.error){
+                if(callback){
+                    callback();
+                }
+            }
+        }
+    })
+}
+
+function deleted(node){
+    return node.data.deleteInfo !== undefined && node.data.deleteInfo.deleted;
+}
+
+function fIsExist(files, id, type){
+    let isExist = false;
+    for(let i = 0, len = files.length; i < len; i++){
+        if((type === fileType.unitPriceFile && files[i].id === id) || (type === fileType.feeRateFile && files[i].ID === id)){
+            isExist = true;
+            break;
+        }
+    }
+    return isExist;
+}
+
+function getRecFileObj(files){
+    let rst = Object.create(null);
+    let rst_UF = [], rst_FF = [];
+    for(let i = 0, len = files.length; i < len; i++){
+        if(files[i].findData !== undefined && files[i].findData.id !== undefined){
+            if(files[i].updateType === fileType.unitPriceFile){
+                rst_UF.push(files[i].findData.id);
+            }
+            else if(files[i].updateType === fileType.feeRateFile){
+                rst_FF.push(files[i].findData.id);
+            }
+        }
+    }
+    rst[fileType.unitPriceFile] = rst_UF;
+    rst[fileType.feeRateFile] = rst_FF;
+    return rst;
+}
+
+function getUpdateObj(updateType, findData, updateData){
+    let obj = Object.create(null);
+    obj.updateType = updateType;
+    obj.findData = findData;
+    obj.updateData = updateData;
+    return obj;
+}
+
+function getUpdateDatas(updateType, node, mtNID, mtPM){
+    let rst = [];
+    if(!decDate){
+        decDate = '(' + new Date().Format('MM-dd hh:mm:ss') + '恢复)';
+    }
+    if(updateType === projectType.tender || updateType === projectType.engineering){
+        //维护回收站树
+     /*   if(mtGC){
+            rst.push(getUpdateObj(updateType, {NextSiblingID: node.data.ID, 'deleteInfo.deleted': true}, {NextSiblingID: node.data.NextSiblingID}));
+        }*/
+        //维护项目管理树
+        if(mtPM){
+            rst.push(getUpdateObj(updateType, {ParentID: node.data.ParentID, NextSiblingID: -1, deleteInfo: null}, {NextSiblingID: node.data.ID}));
+        }
+        //恢复
+        if(mtNID){
+            rst.push(getUpdateObj(updateType, {ID: node.data.ID, name: node.data.name + decDate}, {deleteInfo: null, NextSiblingID: -1}));
+        }
+        else {
+            rst.push(getUpdateObj(updateType, {ID: node.data.ID, name: node.data.name + decDate}, {deleteInfo: null}));
+        }
+    }
+    else if(updateType === projectType.project){
+       /* //维护回收站树
+        if(mtGC){
+            rst.push(getUpdateObj(updateType, {NextSiblingID: node.data.ID, 'deleteInfo.deleted': true}, {NextSiblingID: node.data.NextSiblingID}));
+        }*/
+        //恢复
+        rst.push(getUpdateObj(updateType, {ID: node.data.ID, name: node.data.name + decDate}, {deleteInfo: null}));//NextSibling为undefined,后端处理
+    }
+    return rst;
+}
+//unitPriceFile or feeRateFile
+function getUpdateFiles(tenders, project){
+    let unitFiles = [], feeFiles = [], rst = [];
+    for(let i = 0, len = tenders.length; i < len; i++){
+        //恢复单价文件
+        if(project && project.data.unitPriceFiles.length > 0 && fIsExist(project.data.unitPriceFiles, tenders[i].data.property.unitPriceFile.id, fileType.unitPriceFile)){
+            unitFiles.push(tenders[i].data.property.unitPriceFile.id);
+        }
+        //恢复费率文件
+        if(project && project.data.feeRateFiles.length > 0 && fIsExist(project.data.feeRateFiles, tenders[i].data.property.feeFile.id, fileType.feeRateFile)){
+            feeFiles.push(tenders[i].data.property.feeFile.id);
+        }
+    }
+    let ufIds = Array.from(new Set(unitFiles));
+    let ffIds = Array.from(new Set(feeFiles));
+    for(let i = 0, len = ufIds.length; i < len; i++){
+        rst.push(getUpdateObj(fileType.unitPriceFile, {id: ufIds[i]}, {deleteInfo: null}));
+    }
+    for(let i = 0, len = ffIds.length; i < len; i++){
+        rst.push(getUpdateObj(fileType.feeRateFile, {id: ffIds[i]}, {deleteInfo: null}));
+    }
+    return rst;
+}

+ 5 - 0
web/building_saas/pm/js/pm_main.js

@@ -149,6 +149,11 @@ let ProjTreeSetting = {
 
 $(document).ready(function() {
     init();
+    Tree = null;
+    $('#tab_pm_all').on('show.bs.tab', function () {
+        gcTree = null;
+        init();
+    });
 
     // 侧滑数据
     $(".poj-list").on('click', ".open-sidebar", function() {