Browse Source

Merge branch 'master' of http://smartcost.f3322.net:3000/SmartCost/ConstructionCost

Chenshilong 7 years atrás
parent
commit
cc5da72e07
58 changed files with 1551 additions and 322 deletions
  1. 17 7
      modules/complementary_glj_lib/controllers/gljController.js
  2. 1 0
      modules/complementary_glj_lib/models/schemas.js
  3. 72 41
      modules/fee_rates/facade/fee_rates_facade.js
  4. 127 12
      modules/glj/controllers/glj_controller.js
  5. 3 3
      modules/glj/models/glj_list_model.js
  6. 48 0
      modules/glj/models/unit_price_model.js
  7. 2 0
      modules/glj/routes/glj_router.js
  8. 0 38
      modules/main/models/proj_counter.js
  9. 29 0
      modules/main/models/proj_counter_model.js
  10. 30 0
      modules/main/models/proj_setting_model.js
  11. 3 1
      modules/main/models/project.js
  12. 15 0
      modules/main/models/schemas/proj_counter.js
  13. 17 0
      modules/main/models/schemas/proj_setting.js
  14. 3 1
      modules/pm/controllers/copy_proj_controller.js
  15. 8 1
      modules/pm/controllers/new_proj_controller.js
  16. 19 1
      modules/pm/controllers/pm_controller.js
  17. 92 16
      modules/pm/models/project_model.js
  18. 1 0
      modules/pm/routes/pm_route.js
  19. 33 4
      modules/ration_glj/facade/ration_glj_facade.js
  20. 1 5
      modules/ration_glj/models/ration_glj.js
  21. 1 0
      modules/ration_repository/models/ration_item.js
  22. 2 1
      modules/ration_repository/models/ration_section_tree.js
  23. 18 2
      modules/reports/controllers/rpt_tpl_controller.js
  24. 77 0
      modules/reports/facade/rpt_tpl_tree_node_facade.js
  25. 1 1
      modules/reports/models/rpt_cfg.js
  26. 1 1
      modules/reports/models/rpt_mapping_field.js
  27. 1 1
      modules/reports/models/rpt_template.js
  28. 1 1
      modules/reports/models/rpt_tpl_data_demo.js
  29. 26 1
      modules/reports/models/tpl_tree_node.js
  30. 4 3
      modules/reports/routes/rpt_tpl_router_fe.js
  31. 5 7
      modules/reports/rpt_component/jpc_ex.js
  32. 48 2
      modules/users/models/log_model.js
  33. 9 5
      modules/users/models/schema/log.js
  34. 28 17
      public/web/sheet/sheet_data_helper.js
  35. 4 5
      public/web/tree_sheet/tree_sheet_helper.js
  36. 27 5
      public/web/ztree_common.js
  37. 46 5
      test/logs/testlog.js
  38. 152 0
      test/unit/reports/rpt_tpl_tree_test.js
  39. 6 6
      web/building_saas/complementary_glj_lib/html/tools-gongliaoji.html
  40. 3 11
      web/building_saas/complementary_glj_lib/js/components.js
  41. 2 4
      web/building_saas/complementary_glj_lib/js/gljComponent.js
  42. 11 2
      web/building_saas/complementary_glj_lib/js/sheetOpr.js
  43. 44 44
      web/building_saas/css/main.css
  44. 9 8
      web/building_saas/fee_rates/fee_rate.html
  45. 54 6
      web/building_saas/glj/html/glj_index.html
  46. 140 2
      web/building_saas/glj/js/project_glj.js
  47. 5 1
      web/building_saas/js/global.js
  48. 21 0
      web/building_saas/main/html/main.html
  49. 10 5
      web/building_saas/main/js/models/fee_rate.js
  50. 6 2
      web/building_saas/main/js/models/project.js
  51. 17 16
      web/building_saas/main/js/models/ration_glj.js
  52. 41 3
      web/building_saas/main/js/views/fee_rate_view.js
  53. 39 5
      web/building_saas/main/js/views/glj_view.js
  54. 51 0
      web/building_saas/main/js/views/main_tree_col.js
  55. 7 3
      web/building_saas/main/js/views/project_view.js
  56. 3 3
      web/building_saas/pm/html/project-management.html
  57. 109 13
      web/building_saas/pm/js/pm_main.js
  58. 1 1
      web/users/html/user-safe.html

+ 17 - 7
modules/complementary_glj_lib/controllers/gljController.js

@@ -4,6 +4,7 @@
 import BaseController from "../../common/base/base_controller";
 import stdgljutil  from "../../../public/cache/std_glj_type_util";
 import GljDao from "../models/gljModel";
+import EngineeringLibModel from "../../users/models/engineering_lib_model";
 
 let gljDao = new GljDao();
 let callback = function(req, res, err, message, data){
@@ -11,18 +12,27 @@ let callback = function(req, res, err, message, data){
 };
 
 class GljController extends BaseController{
-    redirectGlj(req, res){
-        let gljLibId;
-        if(typeof req.session.sessionCompilation.ration_valuation[0].glj_lib[0] !== 'undefined'){
-            gljLibId = req.session.sessionCompilation.ration_valuation[0].glj_lib[0].id;
+    async redirectGlj(req, res){
+        let gljLibId = null, engineeringId, sessionCompilation = req.session.sessionCompilation,
+            rationValuation = sessionCompilation.ration_valuation,
+            billValuation = sessionCompilation.bill_valuation,
+            engineeringLibModel = new EngineeringLibModel();
+        if(rationValuation[0]){
+            let engineeringList = rationValuation[0].engineering_list;
+            engineeringId = engineeringList.length > 0 ? engineeringList[0].engineering_id : null;
+            let engineeringInfo = await engineeringLibModel.getEngineering(engineeringId);
+            gljLibId = engineeringInfo.glj_lib.length > 0 && typeof engineeringInfo.glj_lib !== 'undefined' ? engineeringInfo.glj_lib[0].id : null;
         }
-        else if(typeof req.session.sessionCompilation.bill_valuation[0].glj_lib[0] !== 'undefined'){
-            gljLibId = req.session.sessionCompilation.bill_valuation[0].glj_lib[0].id;
+        else if(billValuation[0]){
+            let engineeringList = billValuation[0].engineering_list;
+            engineeringId = engineeringList.length > 0 ? engineeringList[0].engineering_id : null;
+            let engineeringInfo = await engineeringLibModel.getEngineering(engineeringId);
+            gljLibId = engineeringInfo.glj_lib.length > 0 && typeof engineeringInfo.glj_lib !== 'undefined' ? engineeringInfo.glj_lib[0].id : null;
         }
         res.render('building_saas/complementary_glj_lib/html/tools-gongliaoji.html',{
             userID: req.session.sessionUser.ssoId,
             gljLibId: gljLibId,
-            compilationId: req.session.sessionCompilation._id
+            compilationId: sessionCompilation._id
         });
     }
     getGljDistType (req, res) {

+ 1 - 0
modules/complementary_glj_lib/models/schemas.js

@@ -40,6 +40,7 @@ let stdGljSchema = new Schema({
     gljClass: Number,
     gljType: Number,
     shortName: String,
+    unit: String,
     component: [gjlComponentSchema]
 },{versionKey: false});
 

+ 72 - 41
modules/fee_rates/facade/fee_rates_facade.js

@@ -25,7 +25,8 @@ module.exports={
     getChangeInfo:getChangeInfo,
     changeFeeRateFileFromCurrent:changeFeeRateFileFromCurrent,
     changeFeeRateFileFromOthers:changeFeeRateFileFromOthers,
-    newFeeRateFile:newFeeRateFile
+    newFeeRateFile:newFeeRateFile,
+    getFeeRatesByProject:getFeeRatesByProject
 };
 let operationMap={
     'ut_create':create_fee_rate,
@@ -93,7 +94,11 @@ async function creatFeeRateFile(feeRateFile,feeRate,projectID) {//预留projectI
         err:null
     }
     try {
-        await project_feerate_temp.findOneAndUpdate({projectID:projectID},{feeRateFileID:feeRateFile.ID});
+        let feeFile={
+            id:feeRateFile.ID,
+            name:feeRateFile.name
+        }
+        await projectsModel.findOneAndUpdate({ID:projectID},{'property.feeFile':feeFile});
         await feeRateFileModel.create(feeRateFile);
         await  feeRateModel.create(feeRate);
     }catch (err){
@@ -182,7 +187,6 @@ function getData(projectID, callback) {
 }
 
 async function getFeeRateData(projectID) {
-    // to do 需根据projectID查找对应的费率文件
     let result={
         err:null
     }
@@ -190,7 +194,7 @@ async function getFeeRateData(projectID) {
         //
         let project =  await projectsModel.findOne({ID:projectID});
         if (project&&project.property&&project.property.feeFile){
-            let feeRateData = await feeRateFileModel.findOne({'ID':project.property.feeFile,deleteInfo:null});
+            let feeRateData = await feeRateFileModel.findOne({'ID':project.property.feeFile.id,deleteInfo:null});
             if(feeRateData===null){
                 result.datas=[];
             }else {
@@ -213,7 +217,7 @@ async function getFeeRateData(projectID) {
 }
 
 async function getUsageProjects(feeRateID){
-    let projects = await projectsModel.find({'property.feeFile':feeRateID,'deleteInfo':null});
+    let projects = await projectsModel.find({'property.feeFile.id':feeRateID,'deleteInfo':null});
     return projects;
 }
 
@@ -265,27 +269,42 @@ async function newFeeRateFile(updateData){
     if(updateData.property !== null){
         let property = updateData.property;
         logger.info("Create new feeRate file for project :"+updateData.ID);
-        let libID = property.feeFile;
+        let feeFile = property.feeFile;
         let rootProjectID = property.rootProjectID;
         let name = updateData.name;
-        let doc={
-            rootProjectID:rootProjectID,
-            name:name
-        };
-        if(libID!== ''){
-            let template = await std_fee_rate_lib_model.findOne({"ID":libID});
-            let newFeeRate = {};
-            newFeeRate.ID =uuidV1();
-            newFeeRate.rates=template.rates;
-            await feeRateModel.create(newFeeRate);
-            doc.libID = libID;
-            doc.libName = template.libName;
-            doc.feeRateID =  newFeeRate.ID;
+        let newFeeRate = {};
+        if(feeFile.id.indexOf("newFeeRate")!=-1){
+            let temFee = await feeRateFileModel.findOne({rootProjectID:rootProjectID,name:name,deleteInfo:null});
+            if(temFee){
+                newFeeRate.id=temFee.ID;
+                newFeeRate.name = temFee.name;
+                return newFeeRate;
+            }
+            let temA = feeFile.id.split("-");
+            let libID = temA[1];
+            let doc={
+                rootProjectID:rootProjectID,
+                name:name
+            };
+            if(libID!== ''){
+                let template = await std_fee_rate_lib_model.findOne({"ID":libID});
+                let newFeeRate = {};
+                newFeeRate.ID =uuidV1();
+                newFeeRate.rates=template.rates;
+                await feeRateModel.create(newFeeRate);
+                doc.libID = libID;
+                doc.libName = template.libName;
+                doc.feeRateID =  newFeeRate.ID;
+            }
+            doc.ID = uuidV1();
+            await feeRateFileModel.create(doc);
+            newFeeRate.id = doc.ID;
+            newFeeRate.name =doc.name;
+            return newFeeRate;
+        }else {
+            return feeFile
         }
 
-        doc.ID = uuidV1();
-        await feeRateFileModel.create(doc);
-        return doc.ID;
     }
     return null;
 }
@@ -303,33 +322,41 @@ async function checkFeeRateName(jdata) {
 
 async function getChangeInfo(jdata){
     let data = JSON.parse(jdata);
-    //{ projectID: 99, user_id: '76075' }
+    //{ rootProjectID: 99, user_id: '76075' }
     let result={};
-    let currentProject = {projectID:99,name:'建设项目1'};//dummy 数据
-    currentProject.currentOptions=await feeRateFileModel.find({rootProjectID:data.projectID,deleteInfo:null},['ID','name']);
+    let currentProject = await projectsModel.findOne({'ID':data.rootProjectID},['ID','name']); //{projectID:99,name:'建设项目1'};//dummy 数据
+    if(currentProject){
+        currentProject._doc.currentOptions=await getFeeRatesByProject(data.rootProjectID);
+    }
     //根据用户ID 找除了当前项目的其它建设项目;
-    let others = [
-        {projectID:100,name:'建设项目2',optionList:[
-            {ID:'590cf860-7d99-11e7-90b0-e3a3dfdb2116',name:'2-test另存'},
-            {ID:'c55718d0-7d98-11e7-b3b4-cfc9038d29b0',name:'2-费率B'},
-            {ID:'da059df1-7c18-11e7-9e2f-1390b52643b4',name:'2-费率A'}
-        ] },
-        {projectID:101,name:'建设项目3',optionList:currentProject.currentOptions },
-        {projectID:102,name:'建设项目4',optionList:currentProject.currentOptions },
-    ]
+    let others =await projectsModel.find({'$and': [
+            {'$or':[{'userID': data.user_id,'projType':'Project', 'deleteInfo': null}, {'userID': data.user_id,'projType':'Project', 'deleteInfo.deleted': {'$in': [null, false]}}]},
+            { 'ID':{'$nin':[data.rootProjectID]}}
+        ]},['ID','name']);
+    for(let o of others){
+        o._doc.optionList = await getFeeRatesByProject(o.ID);
+    }
     result.currentProject=currentProject;
     result.others = others;
     return result;
 }
 
+async function getFeeRatesByProject(rootProjectID) {
+       let feeRates = await feeRateFileModel.find({rootProjectID:rootProjectID,deleteInfo:null},['ID','name']);
+       return feeRates;
+}
+
 async function changeFeeRateFileFromCurrent(jdata){
     let data = JSON.parse(jdata);
-    let result = await  project_feerate_temp.findOneAndUpdate({projectID:data.projectID},{feeRateFileID:data.newFeeRateFileID});
-    let feeRateData = await feeRateFileModel.findOne({'ID':data.newFeeRateFileID});
-    let feeRate = await feeRateModel.findOne({ID:feeRateData.feeRateID});
-    feeRateData._doc.rates = feeRate.rates;
+    let newFeeRateFile=data.newFeeRateFile;
+    let result = await  projectsModel.findOneAndUpdate({ID:data.projectID},{'property.feeFile':newFeeRateFile});
+    let feeRateData = await feeRateFileModel.findOne({'ID':newFeeRateFile.id});
+    if(feeRateData!==null){
+        let feeRate = await feeRateModel.findOne({ID:feeRateData.feeRateID});
+        feeRateData._doc.rates = feeRate.rates;
+    }
     //
-    feeRateData._doc.usageProjects=getUsageProjects(feeRateData.ID);
+    feeRateData._doc.usageProjects=await getUsageProjects(feeRateData.ID);
     return feeRateData;
 }
 
@@ -350,8 +377,12 @@ async function changeFeeRateFileFromOthers(jdata) {
     newFeeRateFile.feeRateID =newFeeRate.ID;
     await feeRateModel.create(newFeeRate);
     await feeRateFileModel.create(newFeeRateFile);
-    await project_feerate_temp.findOneAndUpdate({projectID:data.projectID},{feeRateFileID:newFeeRateFile.ID});
+    let feeFile={
+        id:newFeeRateFile.ID,
+        name:data.name
+    }
+    await projectsModel.findOneAndUpdate({ID:data.projectID},{'property.feeFile':feeFile});
     newFeeRateFile.rates=newFeeRate.rates;
-    newFeeRateFile.usageProjects=getUsageProjects(newFeeRateFile.ID);
+    newFeeRateFile.usageProjects=await getUsageProjects(newFeeRateFile.ID);
     return newFeeRateFile;
 }

+ 127 - 12
modules/glj/controllers/glj_controller.js

@@ -9,9 +9,10 @@ import BaseController from "../../common/base/base_controller";
 import GLJTypeConst from "../../common/const/glj_type_const";
 import GLJListModel from "../models/glj_list_model";
 import UnitPriceModel from "../models/unit_price_model";
-import UnitPriceFileModel from "../models/unit_price_file_model";
 import MixRatioModel from "../models/mix_ratio_model";
+import UnitPriceFileModel from "../models/unit_price_file_model";
 
+const ProjectModel = require('../../pm/models/project_model').project;
 class GLJController extends BaseController {
 
     /**
@@ -46,13 +47,22 @@ class GLJController extends BaseController {
             }
 
             // 获取标段对应的单价文件id
-            let unitPriceFileModel = new UnitPriceFileModel();
-            let unitPriceFile = await unitPriceFileModel.getDataByProject(projectId);
-            if (!unitPriceFile) {
+            let unitPriceFileId = await ProjectModel.getUnitPriceFileId(projectId);
+            if (unitPriceFileId <= 0) {
                 throw '没有对应的单价文件';
             }
-            // 单价文件id作为同步的roomId
-            let unitPriceFileId = unitPriceFile.id;
+
+            // 获取使用该单价文件的项目数据
+            let tenderData = await ProjectModel.getTenderByUnitPriceFileId(unitPriceFileId);
+            let usedTenderList = [];
+            let usedUnitPriceInfo = {};
+            if (tenderData !== null) {
+                for (let tmp of tenderData) {
+                    usedTenderList.push(tmp.name);
+                    usedUnitPriceInfo.name = tmp.property.unitPriceFile.name;
+                    usedUnitPriceInfo.id = tmp.property.unitPriceFile.id;
+                }
+            }
 
             // 先获取对应标段的项目工料机数据
             let gljListModel = new GLJListModel();
@@ -60,12 +70,14 @@ class GLJController extends BaseController {
 
             responseData.data.gljList = gljList;
             responseData.data.mixRatioConnectData = mixRatioConnectData;
+            responseData.data.usedTenderList = usedTenderList;
             responseData.data.constData = {
                 materialIdList: gljListModel.materialIdList,
                 ownCompositionTypes: gljListModel.ownCompositionTypes,
                 hostname: request.hostname,
                 roomId: unitPriceFileId,
                 GLJTypeConst: JSON.stringify(GLJTypeConst),
+                usedUnitPriceInfo: usedUnitPriceInfo
             };
         } catch (error) {
             responseData.err = 1;
@@ -180,15 +192,11 @@ class GLJController extends BaseController {
         };
         try {
             // 获取标段对应的单价文件id
-            let unitPriceFileModel = new UnitPriceFileModel();
-            let unitPriceFile = await unitPriceFileModel.getDataByProject(projectId);
-            if (!unitPriceFile) {
+            let unitPriceFileId = await ProjectModel.getUnitPriceFileId(projectId);
+            if (unitPriceFileId <= 0) {
                 throw '没有对应的单价文件';
             }
 
-            // 单价文件id作为同步的roomId
-            let unitPriceFileId = unitPriceFile.id;
-
             let gljListModel = new GLJListModel();
             let result = await gljListModel.getCompositionList(projectGLJId, unitPriceFileId);
             if (result.length <= 0) {
@@ -237,6 +245,113 @@ class GLJController extends BaseController {
     }
 
     /**
+     * 获取项目与单价文件对应的数据
+     *
+     * @param {object} request
+     * @param {object} response
+     * @return {void}
+     */
+    async getProjectInfo(request, response) {
+        let projectId = request.body.project_id;
+        projectId = parseInt(projectId);
+        let responseData = {
+            err: 0,
+            data: null
+        };
+        try {
+            let sessionUserData = request.session.sessionUser;
+            // 获取对应用户所有的建设项目数据
+            let projectList = await ProjectModel.getUserProjectData(sessionUserData.ssoId);
+            if (projectList === null) {
+                throw '没有找到对应的项目数据';
+            }
+            // 转换mongoose数据
+            projectList = JSON.stringify(projectList);
+            projectList = JSON.parse(projectList);
+
+            let result = {
+                self: [],
+                other: []
+            };
+            for (let index in projectList) {
+                // 获取对应建设项目下所有的单位工程id
+                let idList = await ProjectModel.getTenderByProjectId(projectList[index].ID);
+                if (idList.length <= 0) {
+                    continue;
+                }
+
+                // 获取对应的单价文件
+                let unitPriceFileModel = new UnitPriceFileModel();
+                let unitPriceFileData = await unitPriceFileModel.getDataByTenderId(idList);
+                projectList[index].unitPriceList = unitPriceFileData;
+
+                // 归类
+                if (idList.indexOf(projectId) >= 0) {
+                    result.self = unitPriceFileData;
+                } else {
+                    result.other.push(projectList[index]);
+                }
+            }
+            responseData.data = result;
+            response.json(responseData);
+
+        } catch (error) {
+            responseData.err = 1;
+            response.json(responseData);
+        }
+    }
+
+    /**
+     * 更改单价文件
+     *
+     * @param {object} request
+     * @param {object} response
+     * @return {void}
+     */
+    async changeUnitPriceFile(request, response) {
+        let projectId = request.body.project_id;
+        let changeUnitPriceId = request.body.change_id;
+        let responseData = {
+            err: 0,
+            msg: ''
+        };
+        try {
+            let currentUnitPriceId = await ProjectModel.getUnitPriceFileId(projectId);
+
+            // 获取即将更改的单价文件信息
+            let unitPriceFileModel = new UnitPriceFileModel();
+            let targetUnitPriceFile = await unitPriceFileModel.findDataByCondition({id: changeUnitPriceId});
+            if (targetUnitPriceFile === null) {
+                throw '没有找到对应的单价文件';
+            }
+
+            // 查找对应单价文件的项目工料机数据
+            let unitPriceModel = new UnitPriceModel();
+            let copyResult = await unitPriceModel.copyNotExist(currentUnitPriceId, changeUnitPriceId);
+            // 复制成功后更改project数据
+            if (!copyResult) {
+                throw '复制数据失败';
+            }
+
+            let changeUnitPriceFileInfo = {
+                id: targetUnitPriceFile.id,
+                name: targetUnitPriceFile.name
+            };
+            let result = ProjectModel.changeUnitPriceFileInfo(projectId, changeUnitPriceFileInfo);
+            if (!result) {
+                throw '切换单价文件失败!';
+            }
+
+        } catch (error) {
+            console.log(error);
+            responseData.err = 1;
+            responseData.msg = error;
+        }
+
+        response.json(responseData);
+    }
+
+    /**
      * 模拟定额插入
      *
      * @param {object} request

+ 3 - 3
modules/glj/models/glj_list_model.js

@@ -20,12 +20,13 @@ import MixRatioModel from "./mix_ratio_model";
 class GLJListModel extends BaseModel {
 
     /**
-     * 材料类型id
+     * 材料、主材、设备类型id
      *
      * @var {Array}
      */
     materialIdList = [GLJTypeConst.GENERAL_MATERIAL, GLJTypeConst.CONCRETE, GLJTypeConst.MORTAR, GLJTypeConst.MIX_RATIO,
-        GLJTypeConst.COMMERCIAL_CONCRETE, GLJTypeConst.COMMERCIAL_MORTAR];
+        GLJTypeConst.COMMERCIAL_CONCRETE, GLJTypeConst.COMMERCIAL_MORTAR, GLJTypeConst.MAIN_MATERIAL,
+        GLJTypeConst.EQUIPMENT];
 
     /**
      * 拥有组成物的工料机类型id
@@ -137,7 +138,6 @@ class GLJListModel extends BaseModel {
                     }
                 }
             }
-
             // 组合单价数据
             this.combineData(gljData, unitPriceList, quantityList, mixRatioData, totalComposition);
 

+ 48 - 0
modules/glj/models/unit_price_model.js

@@ -213,6 +213,54 @@ class UnitPriceModel extends BaseModel {
         return result.ok !== undefined && result.ok === 1;
     }
 
+    /**
+     * 复制单价文件数据
+     *
+     * @param {Number} currentUnitPriceId
+     * @param {Number} changeUnitPriceId
+     * @return {Promise}
+     */
+    async copyNotExist(currentUnitPriceId, changeUnitPriceId) {
+        let result = false;
+        // 首先查找原单价文件id下的数据
+        let currentUnitList = await this.findDataByCondition({unit_price_file_id: currentUnitPriceId}, null, false);
+        if (currentUnitList === null) {
+            return result;
+        }
+        // 过滤mongoose格式
+        currentUnitList = JSON.stringify(currentUnitList);
+        currentUnitList = JSON.parse(currentUnitList);
+
+        let codeList = [];
+        for (let tmp of currentUnitList) {
+            if (codeList.indexOf(tmp.code) >= 0) {
+                continue;
+            }
+            codeList.push(tmp.code);
+        }
+
+        // 查找即将更替的单价文件是否存在对应的工料机数据
+        let condition = {unit_price_file_id: changeUnitPriceId, code: {"$in": codeList}};
+        let targetUnitList = await this.findDataByCondition(condition, null, false, 'code');
+
+        // 如果没有重叠的数据则原有的数据都复制一份
+        let insertData = [];
+        for (let tmp of currentUnitList) {
+            if (targetUnitList !== null && targetUnitList[tmp.code] !== undefined) {
+                continue;
+            }
+            // 删除原有id信息
+            delete tmp._id;
+            delete tmp.id;
+            tmp.unit_price_file_id = changeUnitPriceId;
+            insertData.push(tmp);
+        }
+
+        return insertData.length > 0 ? this.add(currentUnitList) : true;
+
+    }
+
+
 }
 
 export default UnitPriceModel;

+ 2 - 0
modules/glj/routes/glj_router.js

@@ -17,6 +17,8 @@ router.post('/getData', gljController.init, gljController.getGljList);
 router.post('/update', gljController.init, gljController.updateData);
 router.post('/get-ratio', gljController.init, gljController.getRatio);
 router.post('/delete-ratio', gljController.init, gljController.deleteMixRatio);
+router.post('/get-project-info', gljController.init, gljController.getProjectInfo);
+router.post('/change-file', gljController.init, gljController.changeUnitPriceFile);
 
 router.get('/test', gljController.init, gljController.test);
 router.get('/testModify', gljController.init, gljController.testModify);

+ 0 - 38
modules/main/models/proj_counter.js

@@ -1,38 +0,0 @@
-/**
- * Created by Mai on 2017/6/13.
- */
-
-let mongoose = require('mongoose');
-let baseModel = require('./base_model');
-
-class projCounter extends baseModel {
-    constructor (name) {
-        let db = require("../db/project_db");
-        let Schema = require("mongoose").Schema;
-        let projCounterSchema = new Schema({
-            projectID: Number,
-            bills: Number,
-            ration: Number,
-            volume_price: Number
-        });
-        let projCounterModel = db.model(name, projCounterSchema);
-        super(projCounterModel);
-        this.collectionName = name;
-    };
-
-    getData (projectID, callback) {
-        this.model.findOne({"projectID": projectID}, '-_id', function (err, result) {
-            if (!err) {
-                callback(0, '', result);
-            } else {
-                callback(1, '查询数据失败。', null);
-            }
-        });
-    };
-
-    save (user_id, data, callback) {
-        this.model.update({"projectID": data.projectID}, data, callback);
-    }
-};
-
-module.exports = new projCounter('projCounter');

+ 29 - 0
modules/main/models/proj_counter_model.js

@@ -0,0 +1,29 @@
+/**
+ * Created by Mai on 2017/6/13.
+ */
+
+let baseModel = require('./base_model');
+import {default as projCounterSchema, collectionName as collectionName} from "./schemas/proj_counter";
+
+class projCounter extends baseModel {
+    constructor() {
+        super(projCounterSchema);
+        this.collectionName = collectionName;
+    }
+
+    getData (projectID, callback) {
+        this.model.findOne({"projectID": projectID}, '-_id', function (err, result) {
+            if (!err) {
+                callback(0, collectionName, result);
+            } else {
+                callback(1, '查询数据失败。', null);
+            }
+        });
+    };
+
+    save (user_id, data, callback) {
+        this.model.update({"projectID": data.projectID}, data, callback);
+    }
+};
+
+module.exports = new projCounter();

+ 30 - 0
modules/main/models/proj_setting_model.js

@@ -0,0 +1,30 @@
+/**
+ * Created by Mai on 2017/9/14.
+ */
+
+let baseModel = require('./base_model');
+import {default as projSettingSchema, collectionName as collectionName} from "./schemas/proj_setting";
+
+class projSettingModel extends baseModel {
+
+    constructor() {
+        super(projSettingSchema);
+        this.collectionName = collectionName;
+    }
+
+    getData (projectID, callback) {
+        this.model.findOne({"projectID": projectID}, '-_id', function (err, result) {
+            if (!err) {
+                callback(0, collectionName, result);
+            } else {
+                callback(1, '查询数据失败。', null);
+            }
+        });
+    };
+
+    save (user_id, data, callback) {
+        this.model.update({"projectID": data.projectID}, data, callback);
+    };
+}
+
+module.exports = new projSettingModel();

+ 3 - 1
modules/main/models/project.js

@@ -9,7 +9,8 @@ var ration_coe_data = require('../../ration_glj/facade/ration_coe_facade');
 var ration_ass_data = require('../../ration_glj/facade/ration_ass_facade');
 var quantity_detail_data = require('../../ration_glj/facade/quantity_detail_facade');
 var fee_rate_data = require('../../fee_rates/facade/fee_rates_facade');
-let projCounter = require('./proj_counter');
+let projCounter = require('./proj_counter_model');
+let projSetting = require('./proj_setting_model');
 let volumePriceData = require('../../volume_price/models/volume_price_model');
 var consts = require('./project_consts');
 var projectConsts = consts.projectConst;
@@ -25,6 +26,7 @@ moduleMap[projectConsts.RATION_COE] = ration_coe_data;
 moduleMap[projectConsts.RATION_ASS] = ration_ass_data;
 moduleMap[projectConsts.QUANTITY_DETAIL] = quantity_detail_data;
 moduleMap[projCounter.collectionName] = projCounter;
+moduleMap[projSetting.collectionName] = projSetting;
 moduleMap[volumePriceData.collectionName] = volumePriceData;
 moduleMap[projectConsts.FEERATE] = fee_rate_data;
 

+ 15 - 0
modules/main/models/schemas/proj_counter.js

@@ -0,0 +1,15 @@
+/**
+ * Created by Mai on 2017/9/15.
+ */
+
+let mongoose = require("mongoose");
+let Schema = mongoose.Schema;
+let collectionName = 'projCounter';
+let projSettingSchema = {
+    projectID: Number,
+    bills: Number,
+    ration: Number,
+    volume_price: Number
+};
+let model = mongoose.model(collectionName, new Schema(projSettingSchema, {versionKey: false, collection: collectionName}));
+export {model as default, collectionName as collectionName};

+ 17 - 0
modules/main/models/schemas/proj_setting.js

@@ -0,0 +1,17 @@
+/**
+ * Created by Mai on 2017/9/14.
+ */
+
+let mongoose = require("mongoose");
+let Schema = mongoose.Schema;
+let collectionName = 'proj_setting';
+let projSettingSchema = {
+    projectID: Number,
+    // 列设置
+    main_tree_col: {
+        type: Schema.Types.Mixed,
+        default: {}
+    }
+};
+let model = mongoose.model(collectionName, new Schema(projSettingSchema, {versionKey: false, collection: collectionName}));
+export {model as default, collectionName as collectionName};

+ 3 - 1
modules/pm/controllers/copy_proj_controller.js

@@ -4,7 +4,8 @@
 
 let billsData = require('../../main/models/bills');
 let rationData = require('../../main/models/ration');
-let projCounter = require('../../main/models/proj_counter');
+let projCounter = require('../../main/models/proj_counter_model');
+let projSetting = require('../../main/models/proj_setting_model');
 let volumePriceData = require('../../volume_price/models/volume_price_model');
 let async = require('async');
 
@@ -30,6 +31,7 @@ module.exports = {
         fun.push(copyData(billsData));
         fun.push(copyData(rationData));
         fun.push(copyData(projCounter));
+        fun.push(copyData(projSetting));
         fun.push(copyData(volumePriceData));
         async.parallel(fun, (err) => callback(err));
     }

+ 8 - 1
modules/pm/controllers/new_proj_controller.js

@@ -3,10 +3,12 @@
  */
 
 let billsData = require('../../main/models/bills');
-let projCounter = require('../../main/models/proj_counter');
+let projCounter = require('../../main/models/proj_counter_model');
+let projSetting = require('../../main/models/proj_setting_model');
 let async = require('async');
 
 import BillsTemplateModel from "../models/templates/bills_template_model";
+import EngineeringLibModel from "../../users/models/engineering_lib_model";
 
 module.exports = {
     copyTemplateData: async function (property, newProjID, callback) {
@@ -23,6 +25,11 @@ module.exports = {
             },
             function (cb) {
                 projCounter.insertData({"projectID": newProjID}, cb);
+            },
+            async function (cb) {
+                let engineeringModel = new EngineeringLibModel();
+                let engineering = await engineeringModel.getEngineering(property.engineering_id);
+                projSetting.insertData({"projectID": newProjID, main_tree_col: engineering.main_tree_col}, cb);
             }
         ], (err) => callback(err));
     }

+ 19 - 1
modules/pm/controllers/pm_controller.js

@@ -6,6 +6,7 @@ let ProjectsData = require('../models/project_model').project;
 let projType = require('../models/project_model').projType;
 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");
 
 //统一回调函数
 let callback = function(req, res, err, message, data){
@@ -149,7 +150,7 @@ module.exports = {
             // 获取对应的单价文件
             let unitPriceFileModel = new UnitPriceFileModel();
             let unitPriceFileData = await unitPriceFileModel.getDataByTenderId(idList);
-            console.log(unitPriceFileData);
+
             if (unitPriceFileData === null) {
                 throw {msg: '不存在对应单价文件', err: 0};
             }
@@ -170,5 +171,22 @@ module.exports = {
             let responseData = error.err === 1 ? null : [];
             callback(request, response, error.err, error.msg, responseData);
         }
+    },
+    getFeeRateFileList:async function(request, response) {
+        let data = request.body.data;
+        try {
+            data = JSON.parse(data);
+            let projectId = data.parentID !== undefined ? data.parentID : 0;
+            if (isNaN(projectId) && projectId <= 0) {
+                throw {msg: 'id数据有误!', err: 1};
+            }
+            // 获取对应建设项目下所有的单位工程id
+            let feeRateFileList = await fee_rate_facade.getFeeRatesByProject(projectId);
+            callback(request, response, 0, '',feeRateFileList );
+        } catch (error) {
+            console.log(error);
+            let responseData = error.err === 1 ? null : [];
+            callback(request, response, error.err, error.msg, responseData);
+        }
     }
 };

+ 92 - 16
modules/pm/models/project_model.js

@@ -65,6 +65,23 @@ ProjectsDAO.prototype.updateUserProjects = async function(userId, datas, callbac
             } else if (data.updateType === 'new') {
                 data.updateData['userID'] = userId;
                 data.updateData['createDateTime'] = new Date();
+                // 如果没有选中单价文件则新增单价文件
+                if (data.updateData.projType === projectType.tender && data.updateData.property !== null &&
+                    Object.keys(data.updateData.property.unitPriceFile).length > 0 &&
+                    data.updateData.property.unitPriceFile.id === '') {
+                    let unitPriceFileModel = new UnitPriceFileModel();
+
+                    let insertData = {
+                        name: data.updateData.name,
+                        project_id: data.updateData.ID
+                    };
+                    let addResult = await unitPriceFileModel.add(insertData);
+                    if (!addResult) {
+                        callback(1, '新增单价文件失败.', null);
+                        return;
+                    }
+                    data.updateData.property.unitPriceFile.id = addResult.id + '';
+                }
                 newProject = new Projects(data.updateData);
                 // 查找同级是否存在同名数据
                 let exist = await this.isExist(data.updateData.name, data.updateData.ParentID);
@@ -72,25 +89,13 @@ ProjectsDAO.prototype.updateUserProjects = async function(userId, datas, callbac
                     callback(1, '同级目录已存在相同名称数据.', null);
                     return;
                 }
-                let  feeRateFileID = await feeRateFacade.newFeeRateFile(data.updateData);
-                newProject.property.feeFile = feeRateFileID?feeRateFileID:-1;
+                if(data.updateData.projType==='Tender'){
+                    let  feeRateFileID = await feeRateFacade.newFeeRateFile(data.updateData);
+                    newProject.property.feeFile = feeRateFileID?feeRateFileID:-1;
+                }
                 newProject.save(async function (err, result) {
                     if (!err && result._doc.projType === projectType.tender) {
                         newProjController.copyTemplateData(data.updateData.property, newProject.ID, updateAll);
-                        // 如果没有选中单价文件则新增单价文件
-                        if (data.updateData.property !== null && data.updateData.property.unitPriceFile === '') {
-                            let unitPriceFileModel = new UnitPriceFileModel();
-                            let insertData = {
-                                name: data.updateData.name,
-                                project_id: data.updateData.ID
-                            };
-                            let addResult = await unitPriceFileModel.add(insertData);
-                            if (!addResult) {
-                                callback(1, '新增单价文件失败.', null);
-                                return;
-                            }
-                        }
-
                     } else {
                         updateAll(err);
                     }
@@ -257,6 +262,77 @@ ProjectsDAO.prototype.getTenderByProjectId = async function(projectId) {
     return result;
 };
 
+/**
+ * 根据单价文件id获取对应的标段数据
+ *
+ * @param {Number} unitPriceFileId
+ * @return {Promise}
+ */
+ProjectsDAO.prototype.getTenderByUnitPriceFileId = async function(unitPriceFileId) {
+    let result = [];
+
+    unitPriceFileId = parseInt(unitPriceFileId);
+    if (isNaN(unitPriceFileId) && unitPriceFileId <= 0) {
+        return result;
+    }
+
+    let condition = {projType: 'Tender', "property.unitPriceFile.id": unitPriceFileId + ''};
+    result = await Projects.find(condition);
+
+    return result;
+};
+
+/**
+ * 根据项目id获取单价文件列表id
+ *
+ * @param {Number} projectId
+ * @return {Promise}
+ */
+ProjectsDAO.prototype.getUnitPriceFileId = async function(projectId) {
+    let result = 0;
+    let projectData = await Projects.findOne({ID: projectId});
+    if (projectData === null) {
+        return result;
+    }
+
+    result = projectData.property.unitPriceFile.id;
+    return result;
+};
+
+/**
+ * 获取当前用户的建设项目数据
+ *
+ * @param {Number} userId
+ * @return {Promise}
+ */
+ProjectsDAO.prototype.getUserProjectData = async function(userId) {
+    let projectList = await Projects.find({
+        '$or': [
+            {'userID': userId, 'deleteInfo': null, projType: 'Project'},
+            {'userID': userId, 'deleteInfo.deleted': {'$in': [null, false]}, projType: 'Project'}
+            ]
+    }, {_id: 0, name: 1, ID: 1});
+
+    return projectList;
+};
+
+/**
+ * 更改项目属性中的单价文件
+ *
+ * @param {Number} projectId
+ * @param {Object} changeInfo
+ * @return {Promise}
+ */
+ProjectsDAO.prototype.changeUnitPriceFileInfo = async function(projectId, changeInfo) {
+    projectId = parseInt(projectId);
+    if (isNaN(projectId) || projectId <= 0) {
+        return false;
+    }
+    let result = await Projects.update({ID: projectId}, {"property.unitPriceFile": changeInfo});
+
+    return result.ok === 1;
+};
+
 module.exports ={
     project: new ProjectsDAO(),
     projType: projectType

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

@@ -41,6 +41,7 @@ module.exports = function (app) {
     pmRouter.post('/getProject', pmController.getProject);
     pmRouter.post('/getNewProjectID', pmController.getNewProjectID);
     pmRouter.post('/getUnitFile', pmController.getUnitFileList);
+    pmRouter.post('/getFeeRateFile', pmController.getFeeRateFileList);
 
     app.use('/pm/api', pmRouter);
 };

+ 33 - 4
modules/ration_glj/facade/ration_glj_facade.js

@@ -98,7 +98,10 @@ function get_lib_glj_info(ration_glj) {
                 ration_glj.repositoryId = glj.ration_glj
                 getInfoFromProjectGLJ(ration_glj).then(function (info) {
                     if(info){
-                        result.datas.push(info);
+                        let tem={};
+                        tem.newRecode=createNewRecord(info);
+                        tem.showData=info;
+                        result.datas.push(tem);
                         cb(null,result);
                     }else {
                         cb(new Error('get project glj error'),null);
@@ -111,6 +114,26 @@ function get_lib_glj_info(ration_glj) {
     }
 }
 
+
+function createNewRecord(ration_glj) {
+    let newRecoed={};
+    newRecoed.ID=ration_glj.ID;
+    newRecoed.projectID=ration_glj.projectID;
+    newRecoed.GLJID=ration_glj.GLJID;
+    newRecoed.rationID=ration_glj.rationID;
+    newRecoed.rationItemQuantity=ration_glj.rationItemQuantity;
+    newRecoed.quantity=ration_glj.quantity;
+    newRecoed.name = ration_glj.name;
+    newRecoed.code = ration_glj.code;
+    newRecoed.unit = ration_glj.unit;
+    newRecoed.specs = ration_glj.specs;
+    newRecoed.shortName = ration_glj.shortName;
+    newRecoed.type = ration_glj.type;
+    newRecoed.repositoryId = ration_glj.repositoryId;
+    newRecoed.projectGLJID=ration_glj.projectGLJID;
+  return newRecoed
+}
+
 async function getInfoFromProjectGLJ(ration_glj) {
      let data = {
          glj_id: ration_glj.GLJID,
@@ -130,7 +153,8 @@ async function getInfoFromProjectGLJ(ration_glj) {
          let projectGljModel = new GLJListModel();
          let result = await projectGljModel.addList(data);
          ration_glj.marketPrice=result.unit_price.market_price;
-         ration_glj.adjustPrice=result.adjust_price;
+         ration_glj.adjustPrice=result.unit_price.base_price;
+         ration_glj.basePrice=result.unit_price.base_price;
          ration_glj.projectGLJID=result.id;
          ration_glj.isEstimate=result.is_evaluate;
          return ration_glj;
@@ -155,9 +179,11 @@ function create_ration_glj(user_id,datas) {
                 callback(err,results)
             }else {
                 let newRecords =[];
+                let showDatas=[];
                 for (let r of results.datas){
                     if(r){
-                        newRecords.push(r)
+                        newRecords.push(r.newRecode);
+                        showDatas.push(r.showData);
                     }
                 }
                 if(newRecords.length>0){
@@ -168,7 +194,10 @@ function create_ration_glj(user_id,datas) {
                             let returndata ={
                                 updateTpye:commonConsts.UT_CREATE,
                                 moduleName:'ration_glj',
-                                data:newRecords
+                                data:{
+                                    newRecords:newRecords,
+                                    showDatas:showDatas
+                                }
                             }
                             callback(null,returndata)
                         }

+ 1 - 5
modules/ration_glj/models/ration_glj.js

@@ -15,16 +15,12 @@ var ration_glj = new Schema({
     code:String,
     specs:String,
     unit:String,
-    basePrice:Number,
     shortName:String,
     type:Number,
     quantity:Number,
     customQuantity:Number,
     rationItemQuantity:Number,
-    marketPrice:Number,
-    adjustPrice:Number,
-    marketPriceAdjust:Number,
-    isEstimate:Number
+    marketPriceAdjust:Number
 },{versionKey:false});
 
 mongoose.model('ration_glj', ration_glj);

+ 1 - 0
modules/ration_repository/models/ration_item.js

@@ -35,6 +35,7 @@ var rationItemSchema = mongoose.Schema({
     rationRepId: Number,
     caption: String,
     feeType: Number,
+    jobContent: String,
     rationGljList: [rationGljItemSchema],
     rationCoeList: Array,
     rationAssList: [rationAssItemSchema]

+ 2 - 1
modules/ration_repository/models/ration_section_tree.js

@@ -15,7 +15,8 @@ var rationChapterTreeSchema = new Schema({//章节树  //生成唯一id改为sec
     NextSiblingID:Number,
     name: String,
     explanation: String,//说明
-    ruleText: String,//计算规则
+    ruleText: String,//计算规则,
+    jobContentSituation: String,//工作内容适用情况,ALL适用本项全部定额,PARTIAL适用本项部分定额
     isDeleted: Boolean
 });
 var rationChapterTreeModel = chapterTreeDb.model("std_ration_lib_ration_chapter_trees", rationChapterTreeSchema, "std_ration_lib_ration_chapter_trees");

+ 18 - 2
modules/reports/controllers/rpt_tpl_controller.js

@@ -15,6 +15,7 @@ let rptTplDef = rpttplDefObj.getUtil();
 
 //import stringUtil from "../../../public/stringUtil";
 import JV from "../rpt_component/jpc_value_define";
+import rttFacade from "../facade/rpt_tpl_tree_node_facade";
 
 //import test_glj_type_util from "../../../public/cache/std_glj_type_util");
 
@@ -23,7 +24,7 @@ let callback = function(req, res, err, message, data){
     res.json({error: err, message: message, data: data});
 };
 
-module.exports = {
+let mExport = {
     getDftTemplates(req, res) {
         let filter = {"userId": -100, "$or": [{"isDeleted": null}, {"isDeleted": false} ]};
         TreeNodeModel.find(filter, '-_id', function(err, data){
@@ -36,6 +37,19 @@ module.exports = {
     },
     getRptTplTree: function(req, res) {
         let params = JSON.parse(req.body.params),
+            compilationId = params.compilationId,
+            userId = params.userId,
+            engineerId = params.engineerId;
+        rttFacade.findTplTree(compilationId, engineerId, userId).then(function(result) {
+            if (result) {
+                callback(req,res,false,"", result);
+            } else {
+                callback(req,res, true,"no result", null);
+            }
+        });
+    },
+    getRptTplTree_org: function(req, res) {
+        let params = JSON.parse(req.body.params),
             grpType = params.grpType,
             userId = params.userId,
             tplType = params.tplType;
@@ -176,4 +190,6 @@ module.exports = {
             }
         });
     }
-};
+};
+
+export default mExport;

+ 77 - 0
modules/reports/facade/rpt_tpl_tree_node_facade.js

@@ -0,0 +1,77 @@
+/**
+ * Created by Tony on 2017/9/14.
+ */
+
+import mongoose from "mongoose";
+
+let rpt_tpl_tree_mdl = mongoose.model("rpt_tpl_tree");
+
+const SYSTEM_USER_ID = -100;
+
+function validate(doc) {
+    let rst = true;
+    if (doc) {
+        if (!(doc.hasOwnProperty("compilationId") && doc.hasOwnProperty("engineerId") && doc.hasOwnProperty("userId"))) {
+            rst = false;
+        }
+    } else {
+        rst = false;
+    }
+    return rst;
+}
+
+async function createNewTree(doc) {
+    if (validate(doc)) {
+        return await rpt_tpl_tree_mdl.create(doc)
+    } else {
+        return null;
+    }
+}
+
+async function updateTree(compilationId, engineerId, userId, doc) {
+    let filter = {"compilationId": compilationId, "engineerId": engineerId, "userId": userId};
+    return await rpt_tpl_tree_mdl.update(filter, doc);
+}
+
+async function removeTree(compilationId, engineerId, userId, cb) {
+    let filter = {"compilationId": compilationId, "engineerId": engineerId, "userId": userId};
+    return await rpt_tpl_tree_mdl.findAndModify(filter, [], { $set: { "isDeleted": true } }, {'new':true}, cb);
+}
+
+async function removeTreePhycically(compilationId, engineerId, userId) {
+    let filter = {"compilationId": compilationId, "engineerId": engineerId, "userId": userId};
+    return await rpt_tpl_tree_mdl.remove(filter);
+}
+
+async function findTplTree(compilationId, engineerIds, userIds) {
+    //let filter = {"compilationId": compilationId, "engineerId": engineerIds, "userId": userIds};
+    let filter = {"compilationId": compilationId, "engineerId": engineerIds, "userId": userIds, "$or": [{"isDeleted": null}, {"isDeleted": false}]};
+    if (engineerIds instanceof Array) {
+        filter.engineerId = {$in: engineerIds};
+    }
+    if (userIds instanceof Array) {
+        filter.userId = {$in: userIds};
+    }
+    return await rpt_tpl_tree_mdl.find(filter);
+}
+
+async function findTplTreeByOid(objectId) {
+    if (objectId) {
+        //let filter = {"_id": ObjectId(objectId)};
+        let id = mongoose.Types.ObjectId(objectId);
+        let filter = {_id: id};
+        return await rpt_tpl_tree_mdl.findOne(filter);
+    } else return null;
+}
+
+
+let expObj = {
+    createNewTree:  createNewTree,
+    updateTree:     updateTree,
+    removeTree:     removeTree,
+    removeTreePhycically: removeTreePhycically,
+    findTplTree:    findTplTree,
+    findTplTreeByOid: findTplTreeByOid
+};
+
+export {expObj as default};

+ 1 - 1
modules/reports/models/rpt_cfg.js

@@ -45,4 +45,4 @@ let RptCfgSchema = new Schema({
 
 let Rpt_Cfg_Mdl = mongoose.model("rpt_cfg", RptCfgSchema, "rpt_cfg");
 
-module.exports = Rpt_Cfg_Mdl;
+export {Rpt_Cfg_Mdl as default};

+ 1 - 1
modules/reports/models/rpt_mapping_field.js

@@ -19,4 +19,4 @@ let MapFieldSchema = new mongoose.Schema({
 
 let Rpt_Map_Field_Mdl = mongoose.model("rpt_mapping_field", MapFieldSchema, "rpt_mapping_field");
 
-module.exports = Rpt_Map_Field_Mdl;
+export {Rpt_Map_Field_Mdl as default};

+ 1 - 1
modules/reports/models/rpt_template.js

@@ -28,4 +28,4 @@ let RptTemplateSchema = new Schema({
 
 let Template = mongoose.model("rpt_templates", RptTemplateSchema, "rpt_templates");
 
-module.exports = Template;
+export {Template as default};

+ 1 - 1
modules/reports/models/rpt_tpl_data_demo.js

@@ -35,4 +35,4 @@ let TemplateData = mongoose.model("rpt_temp_tpl_data", RptTemplateDataSchema, "r
 //
 // module.exports = new RplTplDataDAO();
 
-module.exports = TemplateData;
+export {TemplateData as default};

+ 26 - 1
modules/reports/models/tpl_tree_node.js

@@ -18,6 +18,31 @@ let TreeNodeSchema = new Schema({
     isDeleted: Boolean
 });
 
+let TplNodeSchema = new Schema({
+    nodeType: Number,   //节点类型:树节点(枝) 或 模板节点(叶)
+    refId: Number,      //引用报表模板id (引用 collection: rpt_templates)
+    name: String,       //显示名称
+    items: []           //子节点
+});
+
+let RptTplTreeSchema = new Schema({
+    compilationId: String,  //编办的ObjectId
+    engineerId: Number,     //工程专业Id(参考 /modules/common/const/engineering.js)
+    userId: Number,         //userId,如果是标准模板,则为-100
+    properties: [],         //这是一个预留的属性,假定未来还会有不同的划分细节(如:招标/投标/清单 ... etc)
+    name: String,           //显示名称
+    released: Boolean,      //是否已发布
+    isDeleted: Boolean,     //删除标记
+    items: []               //TplNodeSchema entity
+});
+RptTplTreeSchema.statics.findAndModify = function (query, sort, doc, options, callback) {
+    return this.collection.findAndModify(query, sort, doc, options, callback);
+};
+
+/*
 let TreeNodeModel = mongoose.model("rpt_tpl_tree", TreeNodeSchema, "rpt_tpl_tree");
+/*/
+let TreeNodeModel = mongoose.model("rpt_tpl_tree", RptTplTreeSchema, "rpt_tpl_tree");
+//*/
 
-module.exports = TreeNodeModel;
+export {TreeNodeModel as default};

+ 4 - 3
modules/reports/routes/rpt_tpl_router_fe.js

@@ -2,10 +2,11 @@
  * Created by Tony on 2017/6/26.
  * 报表模板路由 - 前台专用(无任何update)
  */
-let express = require("express");
+import express from "express";
+let rptTplRouter = express.Router();
+import reportTplController from "./../controllers/rpt_tpl_controller";
+
 module.exports = function (app) {
-    let rptTplRouter = express.Router();
-    let reportTplController = require('./../controllers/rpt_tpl_controller');
     rptTplRouter.post('/getRptTplTree', reportTplController.getRptTplTree);
 
     app.use("/report_tpl_api", rptTplRouter);

+ 5 - 7
modules/reports/rpt_component/jpc_ex.js

@@ -25,7 +25,7 @@ JpcExSrv.prototype.createNew = function(){
             if (rptTpl && rptTpl[nodeName] && rptTpl[nodeName].length > 0) {
                 for (let i = 0; i < rptTpl[nodeName].length; i++) {
                     let rptDftItem = rptTpl[nodeName][i];
-                    if (rst[rptDftItem[JV.PROP_ID]] == undefined) {
+                    if (rst[rptDftItem[JV.PROP_ID]] === undefined) {
                         let item = {};
                         for (let j = 0; j < propArray.length; j++) {
                             item[propArray[j]] = rptDftItem[propArray[j]];
@@ -38,12 +38,10 @@ JpcExSrv.prototype.createNew = function(){
         return rst;
     }
     function private_buildDftControls(rptTpl, dftControlCollection) {
-        let rst = private_buildDftItems(rptTpl,dftControlCollection, JV.CONTROL_PROPS, JV.NODE_CONTROL_COLLECTION);
-        return rst;
+        return private_buildDftItems(rptTpl,dftControlCollection, JV.CONTROL_PROPS, JV.NODE_CONTROL_COLLECTION);
     }
     function private_buildDftFonts(rptTpl, dftFontCollection) {
-        let rst = private_buildDftItems(rptTpl,dftFontCollection, JV.FONT_PROPS, JV.NODE_FONT_COLLECTION);
-        return rst;
+        return private_buildDftItems(rptTpl,dftFontCollection, JV.FONT_PROPS, JV.NODE_FONT_COLLECTION);
     }
     function private_buildDftStyles(rptTpl, dftStyleCollection) {
         let rst = {};
@@ -64,7 +62,7 @@ JpcExSrv.prototype.createNew = function(){
             if (rptTpl && rptTpl[JV.NODE_STYLE_COLLECTION] && rptTpl[JV.NODE_STYLE_COLLECTION].length > 0) {
                 for (let i = 0; i < rptTpl[JV.NODE_STYLE_COLLECTION].length; i++) {
                     let rptDftItem = rptTpl[JV.NODE_STYLE_COLLECTION][i];
-                    if (rst[rptDftItem[JV.PROP_ID]] == undefined) {
+                    if (rst[rptDftItem[JV.PROP_ID]] === undefined) {
                         let item = {};
                         for (let j = 0; j < rptDftItem[JV.PROP_BORDER_STYLE].length; j++) {
                             let borderItem = {};
@@ -231,4 +229,4 @@ JpcExSrv.prototype.createNew = function(){
     return JpcResult;
 };
 
-module.exports = new JpcExSrv();
+export default new JpcExSrv();

+ 48 - 2
modules/users/models/log_model.js

@@ -9,6 +9,7 @@ import BaseModel from "../../common/base/base_model";
 import LogType from "../../common/const/log_type_const";
 import LogSchema from "./schema/log";
 import UAParser from "ua-parser-js";
+import Request from "request";
 
 class LogModel extends BaseModel {
 
@@ -57,11 +58,13 @@ class LogModel extends BaseModel {
      * @param {Object} request
      * @return {Promise}
      */
-    addLoginLog(userId, request) {
+    async addLoginLog(userId, request) {
         let ip = request.connection.remoteAddress;
         ip = ip.split(':');
         ip = ip[3] === undefined ? '' : ip[3];
 
+        let ipInfo = await this.getIpInfoFromApi(ip);
+
         let userAgentObject = new UAParser(request.headers['user-agent']);
         let osInfo = userAgentObject.getOS();
         let cpuInfo = userAgentObject.getCPU();
@@ -69,7 +72,8 @@ class LogModel extends BaseModel {
         let message = {
             os: osInfo.name + ' ' + osInfo.version + ' ' + cpuInfo.architecture,
             browser: browserInfo.name + ' ' + browserInfo.version,
-            ip: ip
+            ip: ip,
+            ip_info: ipInfo
         };
 
         return this.addLog(userId, LogType.LOGIN_LOG, message);
@@ -99,6 +103,48 @@ class LogModel extends BaseModel {
         return logList
     }
 
+    /**
+     * 获取ip信息
+     *
+     * @param {String} ip
+     * @return {Promise}
+     */
+    async getIpInfoFromApi(ip) {
+        let result = '';
+        if (ip === '') {
+            return result;
+        }
+
+        if (ip === '127.0.0.1') {
+            return '服务器本机访问';
+        }
+
+        let getData = {
+            url: 'http://ip.taobao.com/service/getIpInfo.php?ip=' + ip,
+            encoding: 'utf8'
+        };
+        return new Promise(function (resolve, reject) {
+            try {
+                // 请求接口
+                Request.get(getData, function (err, getResponse, body) {
+                    if (err) {
+                        throw '请求错误';
+                    }
+                    if (getResponse.statusCode !== 200) {
+                        throw '获取数据失败!';
+                    }
+                    let responseData = JSON.parse(body);
+                    let ipData = responseData.data !== undefined ? responseData.data : [];
+                    if (ipData.ip === undefined) {
+                        throw '接口数据有误';
+                    }
+                    resolve(ipData.region + ipData.city + ' ' + ipData.isp);
+                });
+            } catch (error) {
+                reject([]);
+            }
+        });
+    }
 }
 
 export default LogModel;

+ 9 - 5
modules/users/models/schema/log.js

@@ -9,18 +9,22 @@ import mongoose from "mongoose";
 
 let Schema = mongoose.Schema;
 let collectionName = 'log';
+let messageSchema = new Schema({
+    ip: String,
+    ip_info: String,
+    browser: String,
+    os: String
+}, {_id: false});
 let modelSchema = {
     // 日志类型
     type: {
-        type: Number,
-        index: true
+        type: Number
     },
     // 日志内容
-    message: Schema.Types.Mixed,
+    message: messageSchema,
     // 关联用户id
     user_id: {
-        type: String,
-        index: true
+        type: String
     },
     // 创建时间
     create_time: Number

+ 28 - 17
public/web/sheet/sheet_data_helper.js

@@ -61,23 +61,29 @@ var SheetDataHelper = {
         }
         sheet.setColumnCount(setting.cols.length);
         sheet.setRowCount(setting.headRows, GC.Spread.Sheets.SheetArea.colHeader);
-        setting.headRowHeight.forEach(function (rowHeight, index) {
-            sheet.setRowHeight(index, rowHeight, GC.Spread.Sheets.SheetArea.colHeader);
-        })
-        setting.cols.forEach(function (col, index) {
-            var i, iRow = 0, cell;
-            for (i = 0; i < col.head.spanCols.length; i++) {
-                if (col.head.spanCols[i] !== 0) {
-                    cell = sheet.getCell(iRow, index, GC.Spread.Sheets.SheetArea.colHeader);
-                    cell.value(col.head.titleNames[i]).font(col.head.font).hAlign(col.head.hAlign[i]).vAlign(col.head.vAlign[i]);
-                }
-                if (col.head.spanCols[i] > 1 || col.head.spanRows[i] > 1) {
-                    sheet.addSpan(iRow, index, col.head.spanRows[i], col.head.spanCols[i], GC.Spread.Sheets.SheetArea.colHeader);
-                }
-                iRow += col.head.spanRows[i];
-            };
-            sheet.setColumnWidth(index, col.width);
-        });
+        if (setting.headRowHeight) {
+            setting.headRowHeight.forEach(function (rowHeight, index) {
+                sheet.setRowHeight(index, rowHeight, GC.Spread.Sheets.SheetArea.colHeader);
+            });
+        }
+        if (setting.cols) {
+            sheet.setColumnCount(setting.cols.length);
+            setting.cols.forEach(function (col, index) {
+                var i, iRow = 0, cell;
+                for (i = 0; i < col.head.spanCols.length; i++) {
+                    if (col.head.spanCols[i] !== 0) {
+                        cell = sheet.getCell(iRow, index, GC.Spread.Sheets.SheetArea.colHeader);
+                        cell.value(col.head.titleNames[i]).font(col.head.font).hAlign(col.head.hAlign[i]).vAlign(col.head.vAlign[i]).wordWrap(true);
+                    }
+                    if (col.head.spanCols[i] > 1 || col.head.spanRows[i] > 1) {
+                        sheet.addSpan(iRow, index, col.head.spanRows[i], col.head.spanCols[i], GC.Spread.Sheets.SheetArea.colHeader);
+                    }
+                    iRow += col.head.spanRows[i];
+                };
+                sheet.setColumnWidth(index, col.width);
+                sheet.setColumnVisible(index, col.visible);
+            });
+        }
     },
     protectdSheet: function (sheet) {
         var option = {
@@ -191,6 +197,11 @@ var SheetDataHelper = {
         sheet.resumeEvent();
         sheet.resumePaint();
     },
+    refreshColumnVisible: function (setting, sheet) {
+        setting.cols.forEach(function (col, index) {
+            sheet.setColumnVisible(index, col.visible);
+        });
+    },
     bindSheetData: function (setting, sheet, datas) {     
         var getBindColInfo = function (setting) {
             var colInfo = {};

+ 4 - 5
public/web/tree_sheet/tree_sheet_helper.js

@@ -30,7 +30,6 @@ var TREE_SHEET_HELPER = {
         spread.options.cutCopyIndicatorVisible = false;
         spread.options.allowCopyPasteExcelStyle = false;
         spread.options.allowUserDragDrop = false;
-        spread.options.
         spread.getActiveSheet().setRowCount(3);
         return spread;
     },
@@ -61,7 +60,7 @@ var TREE_SHEET_HELPER = {
             for (i = 0; i < col.head.spanCols.length; i++) {
                 if (col.head.spanCols[i] !== 0) {
                     cell = sheet.getCell(iRow, index, GC.Spread.Sheets.SheetArea.colHeader);
-                    cell.value(col.head.titleNames[i]).font(col.head.font).hAlign(col.head.hAlign[i]).vAlign(col.head.vAlign[i]).wordWrap(col.head.wordWrap);
+                    cell.value(col.head.titleNames[i]).font(col.head.font).hAlign(col.head.hAlign[i]).vAlign(col.head.vAlign[i]).wordWrap(true);
                 }
                 if (col.head.spanCols[i] > 1 || col.head.spanRows[i] > 1) {
                     sheet.addSpan(iRow, index, col.head.spanRows[i], col.head.spanCols[i], GC.Spread.Sheets.SheetArea.colHeader);
@@ -69,6 +68,7 @@ var TREE_SHEET_HELPER = {
                 iRow += col.head.spanRows[i];
             };
             sheet.setColumnWidth(index, col.width);
+            sheet.setColumnVisible(index, col.visible && true);
         });
     },
     protectdSheet: function (sheet) {
@@ -131,12 +131,12 @@ var TREE_SHEET_HELPER = {
                     }
                     return data;
                 };
-                if (colSetting.data.getText) {
+                if (colSetting.data.getText && Object.prototype.toString.apply(colSetting.data.getText) === "[object Function]") {
                     cell.value(colSetting.data.getText(node));
                 } else {
                     cell.value(getFieldText2());
                 }
-                if (colSetting.data.cellType) {
+                if (colSetting.data.cellType && Object.prototype.toString.apply(colSetting.data.cellType) !== "[object String]") {
                     cell.cellType(colSetting.data.cellType);
                 }
                 if (colSetting.readOnly) {
@@ -164,7 +164,6 @@ var TREE_SHEET_HELPER = {
         };
         TreeNodeCellType.prototype = new GC.Spread.Sheets.CellTypes.Text();
         TreeNodeCellType.prototype.paint = function (ctx, value, x, y, w, h, style, options) {
-            console.log(style);
             if (style.backColor) {
                 ctx.save();
                 ctx.fillStyle = style.backColor;

+ 27 - 5
public/web/ztree_common.js

@@ -3,10 +3,32 @@
  */
 zTreeHelper = {
     createTree: function(sourceData, setting, containerId, caller){
-        var treeArr = tree_Data_Helper.buildTreeNodeDirectly(sourceData);
-        var private_build_parentNodeIds = function(pNodeId, nodesArr){
-            var rst = [];
-            for (var i = 0; i < nodesArr.length; i++) {
+        let me = this, treeArr = tree_Data_Helper.buildTreeNodeDirectly(sourceData);
+        // let private_build_parentNodeIds = function(pNodeId, nodesArr){
+        //     let rst = [];
+        //     for (let i = 0; i < nodesArr.length; i++) {
+        //         if (nodesArr[i].items.length > 0) {
+        //             rst = rst.concat(private_build_parentNodeIds(nodesArr[i].ID, nodesArr[i].items));
+        //         } else {
+        //             rst.push(nodesArr[i].ID);
+        //         }
+        //     }
+        //     if (pNodeId && rst.length > 0) {
+        //         caller.parentNodeIds["_pNodeId_" + pNodeId] = rst;
+        //     }
+        //     return rst;
+        // };
+        // if (caller.parentNodeIds) {
+        //     private_build_parentNodeIds(null, treeArr);
+        // }
+        // caller.treeObj = $.fn.zTree.init($("#" + containerId), setting, treeArr);
+        // caller.treeObj.expandAll(true);
+        me.createTreeDirectly(treeArr, setting, containerId, caller);
+    },
+    createTreeDirectly: function (treeArr, setting, containerId, caller) {
+        let private_build_parentNodeIds = function(pNodeId, nodesArr){
+            let rst = [];
+            for (let i = 0; i < nodesArr.length; i++) {
                 if (nodesArr[i].items.length > 0) {
                     rst = rst.concat(private_build_parentNodeIds(nodesArr[i].ID, nodesArr[i].items));
                 } else {
@@ -24,4 +46,4 @@ zTreeHelper = {
         caller.treeObj = $.fn.zTree.init($("#" + containerId), setting, treeArr);
         caller.treeObj.expandAll(true);
     }
-}
+};

+ 46 - 5
test/logs/testlog.js

@@ -1,9 +1,50 @@
 /**
  * Created by chen on 2017/9/13.
  */
-let logger = require("../../logs/log_helper").logger;
 
-logger.info("log info...");
-logger.debug("log debug...");
-logger.warn("log warn...");
-logger.err("log err...");
+console.log(["1", "2", "3"].map(parseInt))
+
+var val = 'smtg';
+console.log('Value is ' + (val === 'smtg') ? 'Something' : 'Nothing');
+
+function foo() { }
+var oldName = foo.name;
+foo.name = "bar";
+console.log([oldName, foo.name])
+
+
+var name = "The Window";
+var object = {
+    name : "My Object",
+    getNameFunc : function(){
+        return function(){
+            return this.name;
+        };
+    }
+};
+console.log(object.getNameFunc()());
+
+var name = "The Window";
+var object = {
+    name : "My Object",
+    getNameFunc : function(){
+        var that = this;
+        return function(){
+            return that.name;
+        };
+    }
+};
+console.log(object.getNameFunc()());
+
+var User = {
+    count: 1,
+    getCount: function() {
+        return this.count;
+    }
+};
+console.log(User.getCount());
+var func = User.getCount;
+console.log(func());
+
+
+

+ 152 - 0
test/unit/reports/rpt_tpl_tree_test.js

@@ -0,0 +1,152 @@
+/**
+ * Created by Tony on 2017/9/15.
+ */
+import test from "tape";
+import mongoose from "mongoose";
+let config = require("../../../config/config.js");
+//config.setupDb(process.env.NODE_ENV);
+config.setupDb('qa');
+import dbm from "../../../config/db/db_manager";
+import mdl from "../../../modules/reports/models/tpl_tree_node";
+import rttFacade from "../../../modules/reports/facade/rpt_tpl_tree_node_facade";
+
+dbm.connect();
+
+/*
+test('测试 - 创建dummy报表树: ', function (t) {
+    let tprTplTree = {};
+    tprTplTree.compilationId = "598d239605cdd825682925d1";
+    tprTplTree.engineerId = 1;
+    tprTplTree.userId = -100;
+    tprTplTree.properties = [{"isZhaoBiao": false}, {"isBills": true}];
+    tprTplTree.name = "重庆市建筑工程";
+    tprTplTree.released = true;
+    tprTplTree.isDeleted = false;
+    tprTplTree.items = [];
+
+    tprTplTree.items.push( {nodeType: 1, refId: -1, name: "【封-1】招标工程量清单", items: null} );
+    tprTplTree.items.push( {nodeType: 1, refId: -1, name: "【表-09】分部分项工程/施工技术措施项目清单计价表", items: null} );
+
+    let results = rttFacade.createNewTree(tprTplTree);
+    results.then(function(rst) {
+        console.log(rst);
+        t.pass('just pass!');
+        t.end();
+    });
+});
+ //*/
+
+/*
+test('测试 - 创建dummy报表树2: ', function (t) {
+    let tprTplTree = {};
+    tprTplTree.compilationId = "598d239605cdd825682925d1";
+    tprTplTree.engineerId = 2;
+    tprTplTree.userId = -100;
+    tprTplTree.properties = [{"isZhaoBiao": false}, {"isBills": true}];
+    tprTplTree.name = "重庆市装饰工程";
+    tprTplTree.released = true;
+    tprTplTree.isDeleted = false;
+    tprTplTree.items = [];
+
+    tprTplTree.items.push( {nodeType: 1, refId: -1, name: "【封-1】招标工程量清单", items: null} );
+    tprTplTree.items.push( {nodeType: 1, refId: -1, name: "【表-09】分部分项工程/施工技术措施项目清单计价表", items: null} );
+
+    let results = rttFacade.createNewTree(tprTplTree);
+    results.then(function(rst) {
+        console.log(rst);
+        t.pass('just pass!');
+        t.end();
+    });
+});
+//*/
+
+/*
+test('测试 - 更新 dummy报表树2: ', function (t) {
+    let tprTplTree = {};
+    tprTplTree.compilationId = "598d239605cdd825682925d1";
+    tprTplTree.engineerId = 2;
+    tprTplTree.userId = -100;
+    tprTplTree.properties = [{"isZhaoBiao": false}, {"isBills": true}];
+    tprTplTree.name = "重庆市装饰工程";
+    tprTplTree.released = false;
+    tprTplTree.isDeleted = false;
+    tprTplTree.items = [];
+
+    tprTplTree.items.push( {nodeType: 1, refId: -1, name: "【封-1】招标工程量清单", items: null} );
+    tprTplTree.items.push( {nodeType: 1, refId: -1, name: "【表-09】分部分项工程/施工技术措施项目清单计价表", items: null} );
+    tprTplTree.items.push( {nodeType: 1, refId: -1, name: "【表-09-1】分部分项工程/施工技术措施项目清单计价表(一)", items: null} );
+
+    let results = rttFacade.updateTree(tprTplTree.compilationId, tprTplTree.engineerId, tprTplTree.userId, tprTplTree);
+    results.then(function(rst) {
+        console.log(rst);
+        t.pass('just pass!');
+        t.end();
+    });
+});
+//*/
+
+/*
+test('测试 - 真正删除 dummy报表树2: ', function (t) {
+    let results = rttFacade.removeTreePhycically("598d239605cdd825682925d1", 2, -100);
+    results.then(function(rst) {
+        console.log(rst);
+        t.pass('just pass!');
+        t.end();
+    });
+});
+//*/
+
+/*
+test('测试 - 删除 dummy 报表树: ', function (t) {
+    let results = rttFacade.removeTree("598d239605cdd825682925d1", 2, -100, function(err, rst){
+        console.log(err);
+        console.log(rst);
+    });
+    results.then(function(err, rst) {
+        //mongoose.disconnect();
+        t.pass('just pass!');
+        t.end();
+    });
+});
+//*/
+
+/*
+test('测试 - find dummy 报表树 by ObjectId: ', function (t) {
+    let results = rttFacade.findTplTreeByOid("59bb7fbbbe61c629c0b2bea6");
+    results.then(function(rst) {
+        console.log(rst);
+        //mongoose.disconnect();
+        t.pass('just pass!');
+        t.end();
+    });
+});
+//*/
+
+//*
+test('测试 - find dummy 报表树 ', function (t) {
+    let results = rttFacade.findTplTree("598d239605cdd825682925d1", [1], [-101]);
+    results.then(function(rst) {
+        if (rst) {
+            console.log('no result');
+        } else {
+            console.log(rst);
+        }
+        //mongoose.disconnect();
+        t.pass('just pass!');
+        t.end();
+    });
+});
+//*/
+
+//*
+test('close the connection', function (t) {
+    setTimeout(function () {
+        mongoose.disconnect();
+        t.pass('closing db connection');
+        t.end();
+    }, 500);
+    // mongoose.disconnect();
+    // t.pass('closing db connection');
+    // t.end();
+});
+//*/

+ 6 - 6
web/building_saas/complementary_glj_lib/html/tools-gongliaoji.html

@@ -118,24 +118,24 @@
                   <div class="modal-body">
                     <div class="row">
                       <div class="col-4">
-                        <div  class="modal-auto-height">
-                            <div class="print-list">
-                                <div class="form-list" id="componentTreeDiv">
+                        <div  class="modal-auto-height" id="componentTreeDiv" style="overflow: hidden">
+                            <!--<div class="print-list">-->
+                                <div style="width: 100%; height: 100%; overflow: auto">
                                     <ul id="componentTree" class="ztree"></ul>
                                 </div>
-                            </div>
+                            <!--</div>-->
                         </div>
                       </div>
                       <div class="col-8">
                           <div class="row">
-                              <div class="modal-auto-height col-12" id="gljRadios">
+                              <div class="col-12" id="gljRadios">
                                   <input type="radio" class="glj-radio" name="glj" value="allGljs">所有工料机&nbsp;&nbsp;
                                   <input type="radio" class="glj-radio" name="glj" value="stdGljs">标准工料机&nbsp;&nbsp;
                                   <input type="radio" class="glj-radio" name="glj" value="complementaryGljs">补充工料机&nbsp;&nbsp;
                                   <input type="radio" class="glj-radio" name="glj" value="selectedGljs">已选工料机机&nbsp;&nbsp;
                                  <!-- <div class="form-group"><input id="searchGlj" type="text" class="form-control-sm" placeholder="查询工料机"></div>-->
                               </div>
-                              <div class="modal-auto-height col-12"  id="componentSheet">
+                              <div class="modal-auto-height col-12" style="overflow: hidden" id="componentSheet">
                                <!--   <table class="table table-sm table-bordered m-0">
                                       <thead>
                                       <tr><th></th><th>编码</th><th>名称</th><th>规格型号</th><th>计量单位</th><th>单价</th><th>类型</th></tr>

+ 3 - 11
web/building_saas/complementary_glj_lib/js/components.js

@@ -89,7 +89,7 @@ let componentOprObj = {
         let materialArr = [202, 203, 204];//混凝土、砂浆、配合比, 201普通材料
         let that = repositoryGljObj, me = componentOprObj;
             for(let i = 0; i < gljList.length; i++){
-                if(that.currentGlj.gljType === 3 && gljList[i].gljType === 302 ||
+                if(that.currentGlj.gljType === 301 && gljList[i].gljType === 302 ||
                     materialArr.indexOf(that.currentGlj.gljType) !== -1 && gljList[i].gljType === 201){
                     //去除与已添加的组成物重复的条目
                     let isExist = false;
@@ -248,6 +248,8 @@ let componentOprObj = {
             }
             sheetOpr.cleanSheet(me.workBook.getSheet(0), me.setting, -1);
             sheetOpr.showData(me.workBook.getSheet(0), me.setting, cacheSection, re.distTypeTree);
+            me.workBook.getSheet(0).options.isProtected = true;
+            me.workBook.getSheet(0).setRowCount(cacheSection);
             cacheSection = null;
         }
     },
@@ -280,17 +282,7 @@ let componentTypeTreeOprObj = {
             } else {
                 me.currentCache = me.getCache();
             }
-            //切换分类树时,记住当前分类的选择
-            //me.setComponentChecked(me.workBook.getSheet(0));
         }
         me.showGljItems(me.showGljList, gljTypeId);
-        /*sheetOpr.cleanSheet(that.workBook.getSheet(0), that.setting, 5);
-         that.workBook.getSheet(0).getRange(-1, 0 , -1, 1, GC.Spread.Sheets.SheetArea.viewport).locked(true);
-         that.workBook.getSheet(0).getRange(-1, 4 , -1, 1, GC.Spread.Sheets.SheetArea.viewport).locked(true);
-         re.workBook.getSheet(0).getRange(-1, 6 , -1, 1, GC.Spread.Sheets.SheetArea.viewport).locked(true);*/
-        //that.workBook.getSheet(0).options.isProtected = true;
-
-        //sheetOpr.lockCodeCells(re.workBook.getSheet(0), re.currentCache.length);
-        //re.workBook.getSheet(0).setRowCount(re.currentCache.length);
     }
 }

+ 2 - 4
web/building_saas/complementary_glj_lib/js/gljComponent.js

@@ -61,12 +61,10 @@ let gljComponentOprObj = {
             selector: '#gljComponentSheet',
             build: function($triggerElement, e){
                 //控制允许右键菜单在哪个位置出现
-                let clientX = e.originalEvent.clientX,
-                    clientY = e.originalEvent.clientY;
                 let sheet = me.workBook.getSheet(0);
                 let offset = $("#gljComponentSheet").offset(),
-                    x = clientX - offset.left,
-                    y = clientY - offset.top;
+                    x = e.pageX - offset.left,
+                    y = e.pageY - offset.top;
                 let target = sheet.hitTest(x, y);
                 if(target.hitTestType === 3 && typeof target.row !== 'undefined' && typeof target.col !== 'undefined'){//在表格内
                     sheet.setActiveCell(target.row, target.col);

+ 11 - 2
web/building_saas/complementary_glj_lib/js/sheetOpr.js

@@ -7,7 +7,8 @@ let sheetOpr = {
         var spreadBook = new GC.Spread.Sheets.Workbook(container, { sheetCount: SheetCount });
         spreadBook.options.allowCopyPasteExcelStyle = false;
         spreadBook.options.tabStripVisible = false;
-        spreadBook.options.showHorizontalScrollbar = false;
+        spreadBook.options.scrollbarMaxAlign = true;
+        //spreadBook.options.showHorizontalScrollbar = false;
         spreadBook.options.allowUserDragDrop = false;
         return spreadBook;
     },
@@ -21,6 +22,10 @@ let sheetOpr = {
         sheet.setColumnCount(setting.header.length, spreadNS.SheetArea.viewport);
         sheet.options.colHeaderAutoTextIndex = 1;
         sheet.options.colHeaderAutoText = spreadNS.HeaderAutoText.numbers;
+        sheet.options.protectionOptions = {
+            allowResizeRows: true,
+            allowResizeColumns: true
+        };
         sheet.showRowOutline(false);
         me.buildHeader(sheet, setting);
         if (rowCount > 0) sheet.setRowCount(rowCount);
@@ -32,7 +37,7 @@ let sheetOpr = {
         var me = this;
         var spreadBook = new GC.Spread.Sheets.Workbook(container, { sheetCount: 1 });
         spreadBook.options.tabStripVisible = false;
-        spreadBook.options.showHorizontalScrollbar = false;
+        //spreadBook.options.showHorizontalScrollbar = false;
         spreadBook.options.scrollbarMaxAlign = true;
         spreadBook.options.allowCopyPasteExcelStyle = false;
         spreadBook.options.allowExtendPasteRange = true;
@@ -46,6 +51,10 @@ let sheetOpr = {
         sheet.setColumnCount(setting.header.length, spreadNS.SheetArea.viewport);
         sheet.options.colHeaderAutoTextIndex = 1;
         sheet.options.colHeaderAutoText = spreadNS.HeaderAutoText.numbers;
+        sheet.options.protectionOptions = {
+            allowResizeRows: true,
+            allowResizeColumns: true
+        };
         sheet.showRowOutline(false);
         //setup column header
         me.buildHeader(sheet, setting);

+ 44 - 44
web/building_saas/css/main.css

@@ -8,7 +8,7 @@ body {
     font-size: 0.9rem
 }
 .btn.disabled, .btn:disabled {
-    color:#999
+  color:#999
 }
 /*自定义css*/
 .header {
@@ -25,10 +25,10 @@ body {
     line-height: inherit
 }
 .top-msg{
-    position: fixed;
-    top:0;
-    width:100%;
-    z-index: 999
+  position: fixed;
+  top:0;
+  width:100%;
+  z-index: 999
 }
 .in-1{padding-left:0px!important}
 .in-2{padding-left:21px!important}
@@ -67,7 +67,7 @@ body {
     color: #333
 }
 .main-nav .nav-tabs{
-    border-bottom: none
+  border-bottom: none
 }
 .content {
     border-left: 1px solid #ccc;
@@ -75,7 +75,7 @@ body {
     background: #fff
 }
 .toolsbar,.toolsbar-f {
-    border-bottom: 1px solid #ccc
+  border-bottom: 1px solid #ccc
 }
 .tools-btn {
     height: 30px;
@@ -89,23 +89,23 @@ body {
     overflow-y: hidden;
 }
 .main-data-top,.main-data-full{
-    overflow: hidden;
-    width:100%
+  overflow: hidden;
+  width:100%
 }
 .main-content.col-lg-8{
-    width:66.666667%
+  width:66.666667%
 }
 .main-content.col-lg-12{
-    width:100%
+  width:100%
 }
 .main-side.col-lg-4{
-    width: 33.333333%;
+  width: 33.333333%;
 }
 .main-side.col-lg-0{
-    width:0%;
+  width:0%;
 }
 .sidebar-bottom,.sidebar-bottom .col-lg-6,.sidebar-bottom .col-lg-12 {
-    height:200px
+  height:200px
 }
 .top-content, .fluid-content {
     overflow: auto;
@@ -121,7 +121,7 @@ body {
     padding: 0.2em 0.5em
 }
 .side-tabs .nav-tabs .nav-item {
-    z-index: 999
+  z-index: 999
 }
 .side-tabs .nav-tabs {
     border-bottom: none;
@@ -244,64 +244,64 @@ body {
     max-width: 500px;
     margin: 150px auto;
 }
-.poj-list, .side-content {
+.poj-list, .side-content ,.form-view{
     overflow: auto;
 }
 .poj-list span.poj-icon {
-    padding-right:7px;
-    color:#ccc
+  padding-right:7px;
+  color:#ccc
 }
 .poj-list a.tree-open,.poj-list a.tree-close{
-    width:15px;
-    display: inline-block;
+  width:15px;
+  display: inline-block;
 }
 .print-toolsbar{
-    padding:5px
+  padding:5px
 }
 .print-toolsbar .panel {
-    display:inline-block;
-    vertical-align:top;
-    background:#f7f7f9
+  display:inline-block;
+  vertical-align:top;
+  background:#f7f7f9
 }
 .print-toolsbar .panel .panel-foot{
-    text-align: center;
-    font-size: 12px
+  text-align: center;
+  font-size: 12px
 }
 .print-list {
-    border-right:1px solid #ccc
+  border-right:1px solid #ccc
 }
 .print-list .form-list {
-    overflow: auto
+  overflow: auto
 }
 .print-list .list-tools{
-    height:50px;
-    padding:10px 0;
-    border-bottom:1px solid #f2f2f2
+  height:50px;
+  padding:10px 0;
+  border-bottom:1px solid #f2f2f2
 }
 .pageContainer {
-    background: #ededed;
-    text-align: center
+  background: #ededed;
+  text-align: center
 }
 .pageContainer .page{
-    border:9px solid transparent;
-    display: inline-block;
+  border:9px solid transparent;
+  display: inline-block;
 }
 .pageContainer .page img{
-    width:inherit;
-    height: inherit;
+  width:inherit;
+  height: inherit;
 }
 .modal-auto-height {
-    height: 400px;
-    overflow-y: auto;
+  height: 400px;
+  overflow-y: auto;
 }
 .modal-fixed-height {
-    height: 400px;
-    overflow-y: hidden;
+  height: 400px;
+  overflow-y: hidden;
 }
 .sidebar-tools-bar {
-    background:#fff
+  background:#fff
 }
 .side-search-box{
-    background:#fff;
-    border-bottom:1px solid #ddd
+  background:#fff;
+  border-bottom:1px solid #ddd
 }

+ 9 - 8
web/building_saas/fee_rates/fee_rate.html

@@ -25,9 +25,9 @@
                 </div>
                 <div class=" grid  main-data-full-fl" id="divFee"></div>
             </div>
-            <div class="col-lg-4 p-0">
+            <div class="col-lg-4 py-1">
                 <div class="py-1"><input type="checkbox" id="cascadeSet" checked >统一设置相同参数</div>
-                <div class="grid  py-1" id="subRate"></div>
+                <div class="grid  main-data-full-fl" id="subRate"></div>
             </div>
         </div>
 </div>
@@ -56,17 +56,17 @@
                 </div>
                 <!--从本建设项目中选择-->
                 <div class="form-group" id="fromProject">
-                    <label id="currentProject">建设项目A</label>
-                    <select class="form-control" id="currentOptions"><option>费率1</option><option>费率2</option><option>费率3</option></select>
+                    <label id="currentProject"></label>
+                    <select class="form-control" id="currentOptions"></select>
                 </div>
                 <!--从其他建设项目中复制-->
                 <div id="fromOther" >
                     <div class="form-group">
                         <label>选择建设项目</label>
-                        <select class="form-control" id="otherProject"><option>建设项目B</option><option>建设项目C</option><option>建设项目D</option></select>
+                        <select class="form-control" id="otherProject"></select>
                     </div>
                     <div class="form-group">
-                        <select class="form-control" id="otherFeeRateOption"><option>费率1</option><option>费率2</option><option>费率3</option></select>
+                        <select class="form-control" id="otherFeeRateOption"></select>
                         <small class="form-text text-muted">你选择的费率文件将复制一份至新项目,不会影响原建设项目的费率文件。</small>
                     </div>
                 </div>
@@ -96,7 +96,7 @@
                     <small class="form-text text-danger">重新选择费率标准将重置当前费率文件的所有费率,正在使用当前费率文件的其他单位工程也将受影响。</small>
                 </div>
                 <div class="form-group">
-                    <label>正在使用 费率1 的单位工程</label>
+                    <label>正在使用 <span id="set-use-feeRateName">费率1</span> 的单位工程</label>
                     <ul class="list-unstyled" id="usageProjectList">
 
                     </ul>
@@ -123,6 +123,7 @@
             <div class="modal-body">
                 <div class="form-group">
                     <label>费率文件名称</label>
+                    <input id="valid_name" type="hidden">
                     <input class="form-control" id="copyFeeRateName" value="">
                     <!--默认为复制费率文件名字+副本 2字,用户修改后需判断是否在同项目下存在同名-->
                     <small class="form-text text-danger" id="nameError" style="display: none">已存在同名费率文件。</small>
@@ -130,7 +131,7 @@
             </div>
             <div class="modal-footer">
                 <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
-                <button type="button" class="btn btn-primary" data-dismiss="modal" id="saveAsConfirm">确定</button>
+                <button type="button" class="btn btn-primary" id="saveAsConfirm">确定</button>
             </div>
         </div>
     </div>

+ 54 - 6
web/building_saas/glj/html/glj_index.html

@@ -1,10 +1,13 @@
+<style type="text/css">
+    .copy{
+        display: none;
+    }
+</style>
 <div class="toolsbar px-1">
-    <div class="tools-btn btn-group align-top">
-        <a href="" class="btn btn-sm"><i class="fa fa-arrow-down" aria-hidden="true"></i>下移</a>
-        <a href="" class="btn btn-sm"><i class="fa fa-arrow-up" aria-hidden="true"></i>上移</a>
-        <a href="" class="btn btn-sm"><i class="fa fa-arrow-left" aria-hidden="true"></i></a>
-        <a href="" class="btn btn-sm"><i class="fa fa-arrow-right" aria-hidden="true"></i></a>
-        <a href="" class="btn btn-sm"><i class="fa fa-undo" aria-hidden="true"></i></a>
+    <div class="form-inline py-1">
+        <label class="mx-2">当前使用:<span id="used-name"></span>(<a href="#" id="pop-dj" data-original-title="" title=""><span id="used-count">0</span> 单位工程使用</a>)
+            <a class="btn btn-sm ml-1" href="#" data-toggle="modal" data-target="#change-dj"><i class="fa fa-exchange"></i> 选择其他</a>
+            <a class="btn btn-sm ml-1" href="#" data-toggle="modal" data-target="#copy-dj"><i class="fa fa-files-o"></i> 另存单独用</a></label>
     </div>
 </div>
 <div class="container-fluid">
@@ -47,6 +50,51 @@
         </div>
     </div>
 </div>
+<!--弹出更换-->
+<div class="modal fade" id="change-dj" 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">
+                <div class="form-group">
+                    <label class="custom-control custom-radio">
+                        <input name="change-type" type="radio" class="custom-control-input" checked="checked" value="0">
+                        <span class="custom-control-indicator"></span>
+                        <span class="custom-control-description">从本建设项目中选择</span>
+                    </label>
+                    <label class="custom-control custom-radio">
+                        <input name="change-type" type="radio" class="custom-control-input" value="1">
+                        <span class="custom-control-indicator"></span>
+                        <span class="custom-control-description">从其他建设项目中复制</span>
+                    </label>
+                </div>
+                <!--从本建设项目中选择-->
+                <div class="form-group select option">
+                    <label id="current-project-name"></label>
+                    <select class="form-control" id="self-file"></select>
+                </div>
+                <!--从其他建设项目中复制-->
+                <div class="form-group copy option">
+                    <label>选择建设项目</label>
+                    <select class="form-control" id="other-project"></select>
+                </div>
+                <div class="form-group copy option">
+                    <select class="form-control" id="other-file"></select>
+                    <small class="form-text text-muted">你选择的单价文件将复制一份至新项目,不会影响原建设项目的单价文件。</small>
+                </div>
+            </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="change-file-confirm">确定</a>
+            </div>
+        </div>
+    </div>
+</div>
 <script type="text/javascript" src="/web/building_saas/glj/js/project_glj.js"></script>
 <script type="text/javascript" src="/web/building_saas/glj/js/composition.js"></script>
 <script type="text/javascript" src="/web/building_saas/glj/js/socket.js"></script>

+ 140 - 2
web/building_saas/glj/js/project_glj.js

@@ -19,7 +19,9 @@ let GLJTypeConst = [];
 // spreadjs载入数据所需
 let jsonData = [];
 let mixRatioConnectData = [];
-
+// 单价文件相关
+let usedUnitPriceInfo = {};
+let otherFileData = {};
 let currentTag = '';
 let isChanging = false;
 $(document).ready(function () {
@@ -27,6 +29,118 @@ $(document).ready(function () {
         init();
     });
 
+    // 单价文件切换弹框
+    $('#change-dj').on('shown.bs.modal', function () {
+        // 获取当前建设项数据
+        let projectName = projectInfoObj.projectInfo.fullFolder !== undefined &&
+            projectInfoObj.projectInfo.fullFolder.length > 0 ? projectInfoObj.projectInfo.fullFolder[0] : '';
+        $("#current-project-name").text(projectName);
+
+        // 获取切换单价文件相关数据
+        $.ajax({
+            url: '/glj/get-project-info',
+            type: 'post',
+            data: {project_id: scUrlUtil.GetQueryString('project')},
+            dataType: 'json',
+            success: function(response) {
+                if (response.err === 1) {
+                    alert('数据传输错误!');
+                    return false;
+                }
+                let data = response.data;
+                // 本项目中的单价文件
+                if (data.self.length > 0) {
+                    let selfFileHtml = '';
+                    for(let tmp of data.self) {
+                        let select = usedUnitPriceInfo === tmp.id ? ' selected="selected"' : '';
+                        selfFileHtml += '<option'+ select +' value="'+ tmp.id +'">'+ tmp.name +'</option>';
+                    }
+                    $("#self-file").html(selfFileHtml);
+                }
+
+                // 其他建设项目数据
+                if (data.other.length > 0) {
+                    let otherProjectHtml = '';
+                    let otherFileHtml = '';
+                    for(let tmp of data.other) {
+                        otherProjectHtml += '<option value="'+ tmp.ID +'">'+ tmp.name +'</option>';
+                        otherFileData[tmp.ID] = tmp.unitPriceList;
+                        if (otherFileHtml !== '') {
+                            continue;
+                        }
+                        for(let unitPrice of tmp.unitPriceList) {
+                            otherFileHtml += '<option value="'+ unitPrice.id +'">'+ unitPrice.name +'</option>';
+                        }
+                    }
+                    $("#other-project").html(otherProjectHtml);
+                    $("#other-file").html(otherFileHtml);
+                }
+            }
+        });
+    });
+
+    // 从其他建设项目中复制 选择建设项目
+    $("#other-project").change(function() {
+        let projectId = $(this).val();
+        if (otherFileData[projectId] === undefined) {
+            return false;
+        }
+        let otherFileHtml = '';
+        for(let unitPrice of otherFileData[projectId]) {
+            otherFileHtml += '<option value="'+ unitPrice.id +'">'+ unitPrice.name +'</option>';
+        }
+        $("#other-file").html(otherFileHtml);
+    });
+
+    // 单价文件选项切换
+    $("input[name='change-type']").change(function() {
+        let type = $(this).val();
+        type = parseInt(type);
+        $("#change-dj .option").hide();
+        if (type === 0) {
+            $(".option.select").show();
+        } else {
+            $(".option.copy").show();
+        }
+    });
+
+    // 单价文件切换确认
+    $("#change-file-confirm").click(function() {
+        if (isChanging) {
+            return false;
+        }
+        let type = $("input[name='change-type']:checked").val();
+        type = parseInt(type);
+        let changeUnitPriceId = 0;
+        if (type === 0) {
+            // 从本项目中选择
+            changeUnitPriceId = $("#self-file").val();
+        } else {
+            // 从其他项目中复制
+            changeUnitPriceId = $("#other-file").val();
+        }
+        $.ajax({
+            url: '/glj/change-file',
+            type: 'post',
+            data: {project_id: scUrlUtil.GetQueryString('project'), change_id: changeUnitPriceId},
+            error: function() {
+                isChanging = false;
+            },
+            beforeSend: function() {
+                isChanging = true;
+            },
+            success: function(response) {
+                isChanging = false;
+                if (response.err === 1) {
+                    let msg = response.msg !== undefined ? response.msg : '未知错误';
+                    alert(msg);
+                    return false;
+                }
+                $('#change-dj').modal("hide");
+            }
+        });
+    });
+
     // 是否主动更改数据
     // $("#message").on('click', '#load-data', function() {
     //     $("#notify").slideUp('fast');
@@ -76,10 +190,14 @@ function init() {
                 data.constData.ownCompositionTypes : canNotChangeTypeId;
             GLJTypeConst = data.constData.GLJTypeConst !== undefined ? JSON.parse(data.constData.GLJTypeConst) : GLJTypeConst;
 
+            let usedTenderList = data.usedTenderList !== undefined ? data.usedTenderList : [];
+            usedUnitPriceInfo = data.constData.usedUnitPriceInfo !== undefined ?
+                data.constData.usedUnitPriceInfo : {};
             // 存入缓存
             projectObj.project.projectGLJ.datas = jsonData;
-            console.log(projectObj.project);
+
             spreadInit();
+            unitPriceFileInit(usedUnitPriceInfo.name, usedTenderList);
         }
     });
 
@@ -126,6 +244,26 @@ function spreadInit() {
 }
 
 /**
+ * 单价文件相关初始化
+ *
+ * @param {String} name
+ * @param {Array} data
+ * @return {void}
+ */
+function unitPriceFileInit(name, data) {
+    $("#used-name").text(name);
+    let usedCount = data.length <= 0 ? 1 : data.length;
+    $("#used-count").text(usedCount);
+    $('#pop-dj').popover({
+            placement:"bottom",
+            html:true,
+            trigger:"hover | focus",
+            content: data.join('<br>')
+        }
+    );
+}
+
+/**
  * 成功事件
  *
  * @param {string} field

+ 5 - 1
web/building_saas/js/global.js

@@ -14,7 +14,8 @@ function autoFlashHeight(){
     $(".main-data-not").height($(window).height()-headerHeight-1);
     $(".main-data-side-search").height($(window).height()-headerHeight-toolsbarHeight-64);
     $(".side-content").height($(window).height()-headerHeight );
-    $(".poj-list").height($(window).height()-headerHeight-ftoolsbarHeight);
+    $(".poj-list").height($(window).height()-headerHeight-toolsbarHeight);
+    $(".form-view").height($(window).height()-headerHeight-ftoolsbarHeight);
     $(".form-list").height($(window).height()-headerHeight-50 );
 };
 $(window).resize(autoFlashHeight);
@@ -44,4 +45,7 @@ $(function(){
         $('[data-toggle="tooltip"]').tooltip()
     });
     /*工具提示*/
+    $(function () {
+        $('[data-toggle="popover"]').popover()
+    });
 });

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

@@ -112,6 +112,9 @@
                     <a href="javascript:void(0)" class="btn btn-sm" id="downMove"><i class="fa fa-arrow-down" aria-hidden="true"></i> 下移</a>
                     <a href="javascript:void(0)" class="btn btn-sm" id="upMove"><i class="fa fa-arrow-up" aria-hidden="true"></i> 上移</a>
                   </div>
+                  <div>
+                      <a href="javacript:void(0);" data-toggle="modal" data-target="#column" class="btn btn-sm"><i class="fa fa-table" aria-hidden="true"></i> 列设置</a>
+                  </div>
                   <div class="side-tabs">
                       <ul class="nav nav-tabs" role="tablist">
                           <li class="nav-item">
@@ -406,6 +409,24 @@
 
         </div>
     </div>
+    <!--弹出列设置-->
+    <div class="modal fade" id="column" data-backdrop="static">
+        <div class="modal-dialog modal-lg" role="document">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <h5 class="modal-title"><i class="fa fa-table"></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 modal-auto-height" id="col_setting_spread" style="height: 130px; overflow: hidden;">
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
+                </div>
+            </div>
+        </div>
+    </div>
     <!-- JS. -->
     <script type="text/javascript">
         autoFlashHeight();

+ 10 - 5
web/building_saas/main/js/models/fee_rate.js

@@ -198,22 +198,27 @@ var FeeRate = {
             return  this.datas;
         };
         FeeRate.prototype.getChangeInfo = function (callback) {
-            var projectID = projectInfoObj.projectInfo.ID; //这里暂时用的是当前项目的ID,以后要改成顶层的建设项目ID
+           // var projectID = projectInfoObj.projectInfo.ID;
+            var feeRate = this.getActivateFeeRate();
+            var  rootProjectID= feeRate.rootProjectID;
+            if(!rootProjectID){
+                rootProjectID=projectInfoObj.projectInfo.property.rootProjectID;
+            }
             var data={
-                "projectID": projectID,
-                "user_id":userID
+                "user_id":userID,
+                "rootProjectID":rootProjectID,
             };
             CommonAjax.post('/feeRates/getChangeInfo', data, function (data) {
                 callback(data);
             });
         };
 
-        FeeRate.prototype.changeFeeRateFileFromCurrent = function (newFeeRateFileID,callback){
+        FeeRate.prototype.changeFeeRateFileFromCurrent = function (newFeeRateFile,callback){
             var me=this;
             var projectID = projectInfoObj.projectInfo.ID;
             var data={
                 "projectID": projectID,
-                "newFeeRateFileID":newFeeRateFileID
+                "newFeeRateFile":newFeeRateFile
             };
             CommonAjax.post('/feeRates/changeFeeRateFileFromCurrent', data, function (data) {
                 if (data) {

+ 6 - 2
web/building_saas/main/js/models/project.js

@@ -12,7 +12,8 @@ var PROJECT = {
             updateData: [],
             operation: '',
             modules: {},
-            projCounter: 'projCounter'
+            projCounter: 'projCounter',
+            projSetting: 'proj_setting'
         };
 
         var me = tools;
@@ -35,6 +36,9 @@ var PROJECT = {
                     me.modules[item.moduleName].loadData(item.data);
                 } else if (item.moduleName === me.projCounter) {
                     counter = item.data;
+                } else if (item.moduleName === me.projSetting) {
+                    me._project.projSetting = item.data;
+                    me._project.projSetting.moduleName = me.projSetting;
                 }
             });
             for (module in counter) {
@@ -274,7 +278,7 @@ var PROJECT = {
                 this.push(moduleName, data);
             }
             this.endUpdate();
-        }
+        };
 
         project.prototype.registerModule = function(moduleName, obj){
             if (!tools.modules.hasOwnProperty(moduleName)){

+ 17 - 16
web/building_saas/main/js/models/ration_glj.js

@@ -94,14 +94,19 @@ var ration_glj = {
             }
         };
         ration_glj.prototype.refreshAfterSave=function(data){
+            let neRecodes=[];
+            if(data){
+                neRecodes=data.newRecords;
+                gljOprObj.sheetData=data.showDatas;
+            }
             if(projectObj.project.ration_glj.datas&&Array.isArray(projectObj.project.ration_glj.datas)){
-                projectObj.project.ration_glj.datas = projectObj.project.ration_glj.datas.concat(data);
+                if(data){
+                    projectObj.project.ration_glj.datas = projectObj.project.ration_glj.datas.concat(neRecodes);
+                }
             }else {
-                projectObj.project.ration_glj.datas = data;
+                projectObj.project.ration_glj.datas = neRecodes;
             }
-            sheetCommonObj.showData(gljOprObj.sheet,gljOprObj.setting,data);
-            gljOprObj.sheetData=data;
-            // SheetDataHelper.loadSheetData(setting, rationLibObj.sectionRationsSpread.getActiveSheet(), datas);
+            gljOprObj.showRationGLJSheetData();
         };
         ration_glj.prototype.refreshAfterUpdate=function(data){
             var me = this;
@@ -112,23 +117,19 @@ var ration_glj = {
             }else {
                 me.refreshEachItme(data.doc,data.query);
             }
-            var selected = projectObj.project.mainTree.selected
-            if(selected==null){
-                return;
-            }
-            if(selected.sourceType==ModuleNames.ration){
-                var showList = _.filter(projectObj.project.ration_glj.datas,{'rationID':selected.data.ID});
-                gljOprObj.sheetData=showList;
-                sheetCommonObj.showData(gljOprObj.sheet,gljOprObj.setting,showList);
-            }
+            gljOprObj.showRationGLJSheetData();
         };
         ration_glj.prototype.refreshEachItme = function (doc,query) {
             var glj_list = projectObj.project.ration_glj.datas;
             var glj_index= _.findIndex(glj_list,(glj)=>{
-                return glj.ID==query.ID&&glj.projectID==query.projectID;
+                return glj.ID==query.ID;
+            })
+            var sheet_index= _.findIndex(gljOprObj.sheetData,(sd)=>{
+                return sd.ID==query.ID;
             })
             _.forEach(doc, function(n, key) {
                 glj_list[glj_index][key] = n;
+                gljOprObj.sheetData[sheet_index][key]=n;
             });
             return glj_list[glj_index].rationID;
         };
@@ -136,7 +137,7 @@ var ration_glj = {
             var glj_list = projectObj.project.ration_glj.datas;
             _.remove(glj_list,data.query);
             _.remove(gljOprObj.sheetData,data.query);
-            sheetCommonObj.showData(gljOprObj.sheet,gljOprObj.setting,gljOprObj.sheetData);
+            gljOprObj.showRationGLJSheetData();
         };
         // CSL,2017.05.09
         ration_glj.prototype.modifyQuantity = function (data, newQuantity) {

+ 41 - 3
web/building_saas/main/js/views/fee_rate_view.js

@@ -247,6 +247,7 @@ var feeRateObject={
             feeRateObject.createSpreadView();
             feeRateObject.loadPageContent();
             projectObj.project.FeeRate.synchronizeFeeRate();
+            subRateObject.destorySpreadView();
         };
         projectObj.project.FeeRate.changeFeeRateStandard(newVal,callback);
     },
@@ -260,7 +261,9 @@ var feeRateObject={
             if(data){
                 $('#saveAsConfirm').attr("disabled","disabled");
                 $('#nameError').text("已存在同名费率文件。").show();
+                $('#valid_name').val('');
             }else {
+                $('#valid_name').val(newVal);
                 $('#saveAsConfirm').removeAttr("disabled");
                 $('#nameError').hide();
             }
@@ -269,8 +272,31 @@ var feeRateObject={
         projectObj.project.FeeRate.checkFeeRateName(newVal,callback);
     },
     feeRateFileSaveAs:function (newName) {
+        if(!newName||newName==""){
+            $('#saveAsConfirm').attr("disabled","disabled");
+            $('#nameError').text("请输入文件名称。").show();
+            return;
+        }
+        var valideName = $('#valid_name').val();
+        if(valideName==''||valideName!==newName){
+            var callback=function (data) {
+                if(data){
+                    $('#saveAsConfirm').attr("disabled","disabled");
+                    $('#nameError').text("已存在同名费率文件。").show();
+                    $('#valid_name').val('');
+                }else {
+                    feeRateObject.submitSaveAs(newName);
+                }
+            }
+            projectObj.project.FeeRate.checkFeeRateName(newName,callback)
+        }else {
+            feeRateObject.submitSaveAs(newName);
+        }
+    },
+    submitSaveAs:function (newName) {
         this.activateFeeRate =  projectObj.project.FeeRate.feeRateFileSaveAs(newName);
         feeRateObject.loadPageContent();
+        $('#copy-lv').modal('hide');
     },
     getChangeInfo:function () {
         var me = this;
@@ -291,7 +317,7 @@ var feeRateObject={
         $('#currentOptions').val(projectObj.project.FeeRate.getActivateFeeRateID());
         $('#otherProject').empty();
         _.forEach(data.others,function (p) {
-            var option =  $("<option>").val(p.projectID).text(p.name);
+            var option =  $("<option>").val(p.ID).text(p.name);
             $('#otherProject').append(option);
         });
         $('#otherFeeRateOption').empty();
@@ -307,16 +333,25 @@ var feeRateObject={
         if($("#currentOptions").val()==this.activateFeeRate.ID){
             return;
         }
+        var name =$("#currentOptions").find("option:selected").text();
+        var newFeeRateFile = {
+            id:newVal,
+            name:name
+        }
         var callback=function () {
             feeRateObject.createSpreadView();
             feeRateObject.loadPageContent();
             projectObj.project.FeeRate.synchronizeFeeRate();
         }
-        projectObj.project.FeeRate.changeFeeRateFileFromCurrent(newVal,callback);
+        projectObj.project.FeeRate.changeFeeRateFileFromCurrent(newFeeRateFile,callback);
     },
     changeFeeRateFileFromOthers:function () {
         var feeRateFileID = $("#otherFeeRateOption").val();
         var name =$("#otherFeeRateOption").find("option:selected").text();
+        if(null===feeRateFileID){
+            alert("请选择一个费率文件!");
+            return;
+        }
         var currentOption = _.find(this.changeInfo.currentProject.currentOptions,{name:name})
         if(currentOption){
             $("#rename-lv").modal({show:true});
@@ -371,6 +406,7 @@ $('#setNewFeeRate').bind('click', function () {
     })
     $("#usageProjectList").html(listString);
     $("#set-lv-feeRateName").text(feeRateFile.name);
+    $("#set-use-feeRateName").text(feeRateFile.name);
 
     feeRateObject.getFeeRateStandards(function (data) {
         $('#standardSelect').empty();
@@ -392,6 +428,8 @@ $('#changeConfirm').bind('click', function (){
 $('#saveAs').bind('click', function (){
     var feeRateFile = projectObj.project.FeeRate.getActivateFeeRate();
     $('#copyFeeRateName').val(feeRateFile.name+'副本');
+    $('#valid_name').val(feeRateFile.name+'副本');
+    $('#nameError').hide();
 });
 
 $('#saveAsConfirm').bind('click',function () {
@@ -452,7 +490,7 @@ $('#changFeeRateFile').bind('click',function (){
 $('#otherProject').change(function(){
     var newVal = $(this).val();
     var projects = feeRateObject.changeInfo.others;
-    var selected = _.find(projects,{projectID:parseInt(newVal)});
+    var selected = _.find(projects,{ID:parseInt(newVal)});
     $('#otherFeeRateOption').empty();
     _.forEach(selected.optionList,function (f) {
         var option =  $("<option>").val(f.ID).text(f.name);

+ 39 - 5
web/building_saas/main/js/views/glj_view.js

@@ -454,15 +454,46 @@ var gljOprObj = {
      //   $('#dropdown').hide();
     },
     showRationGLJData:function (node) {
-        let gljList = [];
-        let ration_glj = projectObj.project.ration_glj;
-        let ration = node.data;
-        if(ration_glj.datas&&ration_glj.datas.length>0){
-            gljList = _.filter(ration_glj.datas,{'projectID':ration.projectID,'rationID':ration.ID})
+        var gljList = [];
+        var ration_glj = projectObj.project.ration_glj;
+        node=node?node:projectObj.project.mainTree.selected;
+        if(node.sourceType==ModuleNames.ration){
+            let ration = node.data;
+            gljList=this.filterGljByRation(ration,ration_glj.datas);
+            this.showInSheet(gljList);
+        }
+    },
+    showRationGLJSheetData:function () {
+        sheetCommonObj.showData(this.sheet,this.setting,this.sheetData);
+    },
+    filterGljByRation:function (ration,datas) {
+        var gljList=[];
+        if(datas&&datas.length>0){
+            gljList = _.filter(datas,{'rationID':ration.ID})
         }
+        return gljList;
+    },
+    showInSheet:function(gljList){
+        gljList=this.combineWithProjectGlj(gljList);
         sheetCommonObj.showData(this.sheet,this.setting,gljList);
         this.sheetData=gljList;
     },
+    combineWithProjectGlj:function (ration_gljs) {
+        var projectGljs = projectObj.project.projectGLJ.datas;
+        if(ration_gljs&&ration_gljs.length>0&&projectGljs&&projectGljs.length>0){
+            ration_gljs.forEach(function (a) {
+                var glj = _.find(projectGljs,{id:a.projectGLJID});
+                if(glj){
+                    a.basePrice=glj.unit_price.base_price;
+                    a.marketPrice=glj.unit_price.market_price;
+                    a.adjustPrice=glj.adjust_price;
+                    a.isEstimate=glj.is_evaluate;
+                }
+            })
+        }
+        return ration_gljs;
+    }
+    ,
     showRationCoeData:function (node) {
         var coeList = [];
         var ration_coe= projectObj.project.ration_coe;
@@ -596,6 +627,9 @@ var gljOprObj = {
             }
         }
         return true;
+    },
+    refreshView:function () {
+        this.showRationGLJData();
     }
 }
 

+ 51 - 0
web/building_saas/main/js/views/main_tree_col.js

@@ -86,3 +86,54 @@ let MainTreeCol = {
         }
     }
 };
+
+let colSettingObj = {
+    settingSpread: null,
+    checkBox: new GC.Spread.Sheets.CellTypes.CheckBox(),
+    loadSetting: function (sheet, setting) {
+        sheet.setColumnCount(setting.cols.length);
+        sheet.setRowCount(setting.headRows, GC.Spread.Sheets.SheetArea.colHeader);
+        sheet.setRowCount(1);
+        sheet.getRange(0, -1, 1, -1).cellType(this.checkBox).hAlign(GC.Spread.Sheets.HorizontalAlign.center);
+
+        setting.headRowHeight.forEach(function (rowHeight, index) {
+            sheet.setRowHeight(index, rowHeight, GC.Spread.Sheets.SheetArea.colHeader);
+        });
+        setting.cols.forEach(function (col, index) {
+            let i, iRow = 0, cell;
+            for (i = 0; i < col.head.spanCols.length; i++) {
+                if (col.head.spanCols[i] !== 0) {
+                    cell = sheet.getCell(iRow, index, GC.Spread.Sheets.SheetArea.colHeader);
+                    cell.value(col.head.titleNames[i]).font(col.head.font).hAlign(col.head.hAlign[i]).vAlign(col.head.vAlign[i]).wordWrap(true);
+                }
+                if (col.head.spanCols[i] > 1 || col.head.spanRows[i] > 1) {
+                    sheet.addSpan(iRow, index, col.head.spanRows[i], col.head.spanCols[i], GC.Spread.Sheets.SheetArea.colHeader);
+                }
+                iRow += col.head.spanRows[i];
+            };
+            sheet.setColumnWidth(index, col.width);
+            cell = sheet.getCell(0, index).value(col.visible);
+        });
+    },
+    initSettingSpread: function () {
+        this.settingSpread = SheetDataHelper.createNewSpread($('#col_setting_spread')[0], {sheetCount: 1});
+        this.settingSpread.options.showScrollTip = GC.Spread.Sheets.ShowScrollTip.horizontal;
+        this.loadSetting(this.settingSpread.getActiveSheet(), projectObj.project.projSetting.main_tree_col);
+    }
+};
+
+$('#column').on('shown.bs.modal', function () {
+    if (!colSettingObj.settingSpread) {
+        colSettingObj.initSettingSpread();
+    }
+});
+
+$('#column').on('hide.bs.modal', function () {
+    let sheet = colSettingObj.settingSpread.getActiveSheet();
+    for (let iCol = 0; iCol < sheet.getColumnCount(); iCol ++) {
+        projectObj.project.projSetting.main_tree_col.cols[iCol].visible = sheet.getValue(0, iCol);
+        projectObj.project.projSetting.mainGridSetting.cols[iCol].visible = sheet.getValue(0, iCol);
+    }
+    SheetDataHelper.refreshColumnVisible(projectObj.project.projSetting.mainGridSetting, projectObj.mainSpread.getActiveSheet());
+    projectObj.project.pushNow('editColSetting', projectObj.project.projSetting.moduleName, {projectID: projectObj.project.ID(), main_tree_col: projectObj.project.projSetting.main_tree_col});
+})

+ 7 - 3
web/building_saas/main/js/views/project_view.js

@@ -91,8 +91,11 @@ var projectObj = {
         this.project = PROJECT.createNew(scUrlUtil.GetQueryString('project'), userID);
         this.project.loadDatas(function (err) {
             if (!err) {
-                TREE_SHEET_HELPER.initSetting($('#billsSpread')[0], BillsGridSetting);
-                BillsGridSetting.cols.forEach(function (col) {
+                let str = JSON.stringify(that.project.projSetting.main_tree_col);
+                that.project.projSetting.mainGridSetting = JSON.parse(str);
+                that.project.projSetting.mainGridSetting.frozenCols = 4;
+                TREE_SHEET_HELPER.initSetting($('#billsSpread')[0], that.project.projSetting.mainGridSetting);
+                that.project.projSetting.mainGridSetting.cols.forEach(function (col) {
                     col.data.splitFields = col.data.field.split('.');
                     if (col.data.getText && Object.prototype.toString.apply(col.data.getText) === "[object String]") {
                         col.data.getText = MainTreeCol.getEvent(col.data.getText);
@@ -109,7 +112,7 @@ var projectObj = {
                         col.data.formatter = MainTreeCol.getNumberFormatter(col.data.decimal);
                     }
                 });
-                that.mainController = TREE_SHEET_CONTROLLER.createNew(that.project.mainTree, that.mainSpread.getActiveSheet(), BillsGridSetting);
+                that.mainController = TREE_SHEET_CONTROLLER.createNew(that.project.mainTree, that.mainSpread.getActiveSheet(), that.project.projSetting.mainGridSetting);
                 that.mainController.showTreeData();
                 that.mainController.bind('refreshBaseActn', function (tree) {
                     var setButtonValid = function (valid, btn) {
@@ -403,3 +406,4 @@ $('#downMove').click(function () {
         controller.downMove();
     }
 });
+

+ 3 - 3
web/building_saas/pm/html/project-management.html

@@ -183,7 +183,7 @@
                 <div class="row">
                     <div class="col-md-6">
                         <legend>单价文件</legend>
-                        <table class="table table-bordered table-hover table-sm">
+                        <table class="table table-bordered table-hover table-sm" id="summary-project-unit-price-table">
                             <thead><th></th><th>名称</th></thead>
                             <tbody>
                             <tr><td>1</td><td>A单价文件</td></tr>
@@ -194,7 +194,7 @@
                     </div>
                     <div class="col-md-6">
                         <legend>费率文件</legend>
-                        <table class="table table-bordered table-hover table-sm">
+                        <table class="table table-bordered table-hover table-sm" id="summary-project-fee-table">
                             <thead><th></th><th>名称</th></thead>
                             <tbody>
                             <tr><td>1</td><td>A费率文件</td></tr>
@@ -366,7 +366,7 @@
                     </div>
                     <div class="form-group hidden-area">
                         <label>费率文件</label>
-                        <select class="form-control" id="tender-fee-rate"><option value="">请选择费率文件</option></select>
+                        <select class="form-control" id="tender-fee-rate"><option value="">新建费率文件</option></select>
                     </div>
                     <div class="form-group">
                         <label>计价方式</label>

+ 109 - 13
web/building_saas/pm/js/pm_main.js

@@ -249,7 +249,8 @@ $(document).ready(function() {
 
         // 获取单价文件数据
         getUnitFile(projectInfo.data.ID);
-
+        // 获取费率文件数据
+        getFeeRateFile(projectInfo.data.ID);
     });
 
     // 新增单位工程
@@ -536,14 +537,9 @@ $(document).ready(function() {
             return false;
         }
         // 输出数据到页面
-        let feeHtml = '<option>请选择费率文件</option>';
         if (currentLib.fee_lib !== undefined && currentLib.fee_lib.length > 0) {
-            for (let fee of currentLib.fee_lib) {
-                feeHtml += '<option value="'+ fee.id +'">'+ fee.name +'</option>';
-            }
+            $("#tender-fee-rate").children("option").first().val("newFeeRate-"+currentLib.fee_lib[0].id);
         }
-        $("#tender-fee-rate").html(feeHtml);
-
         $(this).parent().siblings('.hidden-area').slideDown('fast');
     });
 });
@@ -554,6 +550,9 @@ $(document).ready(function() {
  * @return {void}
  */
 function init() {
+    billValuation = billValuation.replace(/\n/g, '\\n');
+    rationValuation = rationValuation.replace(/\n/g, '\\n');
+
     let table = $('#ProjTree');
     $('thead', table).remove();
     $('tbody', table).remove();
@@ -720,11 +719,13 @@ function AddTender() {
         }
 
         let unitPriceFile = $("#unit-price").val();
+        let unitPriceName = unitPriceFile !== '' ? $("#unit-price").children("option:selected").text() : name;
 
         let feeFile = $("#tender-fee-rate").val();
         if (feeFile === '') {
             throw '请选择费率文件';
         }
+        let feeFileName = $("#tender-fee-rate").children("option:selected").text();
 
         let valuation = $("#tender-valuation").val();
         let valuationName = $("#tender-valuation").children("option:selected").text();
@@ -762,8 +763,8 @@ function AddTender() {
             engineering: engineering,
             engineering_id: engineering_id,
             engineeringName: engineeringName,
-            unitPriceFile: unitPriceFile,
-            feeFile: feeFile
+            unitPriceFile: {name: unitPriceName, id: unitPriceFile},
+            feeFile: {name: feeFileName, id: feeFile}
         };
         // 如果选择的是单项工程则新增同级数据
         if (selectedItem !== null && selectedItem.data.projType === projectType.tender) {
@@ -820,9 +821,16 @@ function AddFolder() {
 function GetUpdateData(parent, next, name, property, newId, type) {
     let data = [];
     let updateData = {};
-    let rootProject = parent ? parent.parent : Tree._root;
-    let rootProjectID = rootProject ? rootProject.id() : -1;
-    property.rootProjectID=rootProjectID;
+
+    let rootProjectID = -1;
+    if(type.projectType === projectType.tender){
+        let rootProject = parent ? parent.parent : Tree._root;
+        rootProjectID = rootProject ? rootProject.id() : -1;
+        if(property){
+            property.rootProjectID=rootProjectID;
+        }
+    }
+
     updateData['updateType'] = type.updateType === undefined ? 'new' : type.updateType;
     updateData['updateData'] = {};
     if (newId !== '') {
@@ -833,7 +841,7 @@ function GetUpdateData(parent, next, name, property, newId, type) {
     if (name !== '') {
         updateData['updateData']['name'] = name;
     }
-    if (property !== undefined) {
+    if (property !== null && property !== undefined) {
         updateData['updateData']['property'] = property;
     }
     if (type !== null && type.projectType !== null) {
@@ -1092,6 +1100,7 @@ function getUnitFile(parentID) {
                 for(let tmp of response.data) {
                     unitFileHtml += '<option value="'+ tmp.id +'">'+ tmp.name +'</option>';
                 }
+                $("#unit-price").children("option:not(':first')").remove();
                 $("#unit-price").children("option").first().after(unitFileHtml);
             }
         }
@@ -1100,6 +1109,50 @@ function getUnitFile(parentID) {
 }
 
 /**
+ * 获取费率文件
+ *
+ * @param {Number} parentID
+ * @return {void}
+ */
+function getFeeRateFile(parentID) {
+    parentID = parseInt(parentID);
+    if (isNaN(parentID) && parentID <= 0) {
+        return;
+    }
+
+    $.ajax({
+        url: '/pm/api/getFeeRateFile',
+        type: 'post',
+        data: {'data': JSON.stringify({"user_id": userID, "parentID": parentID})},
+        dataType: 'json',
+        error: function() {
+            alert('数据传输错误!');
+        },
+        beforeSend: function() {
+
+        },
+        success: function(response) {
+            if (response.error === 1) {
+                alert('获取失败!');
+            } else {
+                if (response.data.length <= 0) {
+                    return false;
+                }
+                var first = $("#tender-fee-rate").children("option").first();
+                $("#tender-fee-rate").empty();
+                $("#tender-fee-rate").append(first);
+                for(let tmp of response.data) {
+                    var option =  $("<option>").val(tmp.ID).text(tmp.name);
+                    $("#tender-fee-rate").append(option);
+                }
+            }
+        }
+    });
+
+}
+
+
+/**
  * 加载数据到侧边栏
  *
  * @return {void}
@@ -1142,4 +1195,47 @@ function setDataToSideBar() {
         '</tr>';
     $(target + '-table tbody').html(html);
 
+    // 加载单价文件与费率文件
+    if (selectedItem.data.projType === projectType.project) {
+        let engineeringData = selectedItem.children !== null && selectedItem.children.children !== null ?
+            selectedItem.children : [];
+        if (engineeringData.length <= 0) {
+            return;
+        }
+        let unitPriceFileHtml = '';
+        let feeFileHtml = '';
+        let unitPriceFileCounter = 1;
+        let feeFileCounter = 1;
+        let unitPriceFileList = [];
+        let feeFileList = [];
+        for(let engineering of engineeringData) {
+            let tenderData = engineering.children !== null ? engineering.children : [];
+            if (tenderData.length <= 0) {
+                continue;
+            }
+            for(let tmp of tenderData) {
+                tmp = tmp.data.property !== null ? tmp.data.property : null;
+                if(tmp === null) {
+                    continue;
+                }
+
+                if (tmp.feeFile !== undefined && feeFileList.indexOf(tmp.feeFile.name) < 0) {
+                    feeFileHtml += '<tr><td>'+ feeFileCounter +'</td><td>'+ tmp.feeFile.name +'</td></tr>';
+                    feeFileCounter++;
+                    feeFileList.push(tmp.feeFile.name);
+                }
+
+                if (tmp.unitPriceFile !== undefined && unitPriceFileList.indexOf(tmp.unitPriceFile.name) < 0) {
+                    unitPriceFileHtml += '<tr><td>'+ unitPriceFileCounter +'</td><td>'+ tmp.unitPriceFile.name +'单价文件</td></tr>';
+                    unitPriceFileCounter++;
+                    unitPriceFileList.push(tmp.unitPriceFile.name);
+                }
+            }
+
+            $(target + '-unit-price-table tbody').html(unitPriceFileHtml);
+            $(target + '-fee-table tbody').html(feeFileHtml);
+        }
+
+    }
+
 }

+ 1 - 1
web/users/html/user-safe.html

@@ -103,7 +103,7 @@
                             <td><%= log.message.os %></td>
                             <td><%= log.message.browser %></td>
                             <td><%= moment(log.create_time).format('YYYY-MM-DD HH:mm:ss') %></td>
-                            <td>(<%= log.message.ip %>)</td>
+                            <td><%= log.message.ip_info %>(<%= log.message.ip %>)</td>
                         </tr>
                         <% }) %>
                         </tbody>