Переглянути джерело

Merge branch 'master' of http://192.168.1.41:3000/SmartCost/YangHuCost

TonyKang 5 роки тому
батько
коміт
113803c81e
47 змінених файлів з 1146 додано та 284 видалено
  1. 2 0
      modules/all_models/material_calc.js
  2. 2 0
      modules/all_models/unit_price.js
  3. 4 1
      modules/all_models/unit_price_file.js
  4. 28 19
      modules/complementary_glj_lib/models/gljModel.js
  5. 1 1
      modules/glj/models/unit_price_model.js
  6. 1 1
      modules/main/controllers/project_controller.js
  7. 2 2
      modules/main/models/project.js
  8. 5 0
      modules/pm/controllers/new_proj_controller.js
  9. 9 1
      modules/pm/controllers/pm_controller.js
  10. 44 3
      modules/pm/facade/pm_facade.js
  11. 2 2
      modules/pm/models/project_model.js
  12. 52 1
      modules/ration_glj/controllers/ration_glj_controller.js
  13. 64 0
      modules/ration_glj/facade/ration_glj_facade.js
  14. 1 1
      modules/ration_glj/routes/ration_glj_route.js
  15. 50 0
      modules/unit_price_file/controllers/unit_price_controller.js
  16. 14 0
      modules/unit_price_file/routes/unit_price_router.js
  17. 1 1
      modules/users/models/user_model.js
  18. 34 1
      public/common_constants.js
  19. 6 8
      public/web/gljUtil.js
  20. 6 5
      public/web/sheet/sheet_common.js
  21. 9 6
      public/web/tree_sheet/tree_sheet_helper.js
  22. 10 2
      web/building_saas/complementary_ration_lib/html/dinge.html
  23. 73 87
      web/building_saas/complementary_ration_lib/js/gljSelect.js
  24. 1 0
      web/building_saas/complementary_ration_lib/js/init.js
  25. 1 6
      web/building_saas/complementary_ration_lib/js/ration_glj.js
  26. 0 2
      web/building_saas/complementary_ration_lib/js/section_tree.js
  27. 9 0
      web/building_saas/css/custom.css
  28. 4 0
      web/building_saas/css/main.css
  29. 1 0
      web/building_saas/glj/html/project_glj.html
  30. 7 6
      web/building_saas/main/html/main.html
  31. 6 0
      web/building_saas/main/js/models/bills.js
  32. 27 8
      web/building_saas/main/js/models/project_glj.js
  33. 3 3
      web/building_saas/main/js/models/ration_glj.js
  34. 1 1
      web/building_saas/main/js/views/calc_base_view.js
  35. 5 2
      web/building_saas/main/js/views/fee_rate_view.js
  36. 13 76
      web/building_saas/main/js/views/glj_view.js
  37. 115 18
      web/building_saas/main/js/views/glj_view_contextMenu.js
  38. 11 1
      web/building_saas/main/js/views/importBills.js
  39. 8 5
      web/building_saas/main/js/views/project_glj_view.js
  40. 18 8
      web/building_saas/main/js/views/project_info.js
  41. 3 3
      web/building_saas/main/js/views/project_view.js
  42. 3 0
      web/building_saas/main/js/views/std_billsGuidance_lib.js
  43. 169 0
      web/building_saas/unit_price_file/index.html
  44. 293 0
      web/building_saas/unit_price_file/index.js
  45. 25 0
      web/common/components/share/index.js
  46. 1 1
      web/common/html/header.html
  47. 2 2
      web/over_write/js/nongcun_2020.js

+ 2 - 0
modules/all_models/material_calc.js

@@ -81,6 +81,7 @@ let freightSchema = {
     loadingTimes:String,//装卸次数
     otherFee:String,//其它费用
     freightIncreaseRate:String,//运价增加率
+    heightFee:String,//高原增加费
     weightCoe:String,//加权系数
     rations:[ration_schema],
     ration_gljs:[ration_glj],
@@ -97,6 +98,7 @@ let originalSchema = {
     supplyLocation:String,//供应地点
     supplyPrice:String,//供应价
     coe:String,//加权系数
+    heightFee:String,//高原增加费
     rations:[ration_schema],
     ration_gljs:[ration_glj]
 };

+ 2 - 0
modules/all_models/unit_price.js

@@ -53,7 +53,9 @@ let modelSchema = {
     },
     supplyLocation:String,//供应地点
     originalPrice:String,//原价
+    priceHeightFee:String,//自采高原增加费
     unitFreight:String,//单价运费
+    freightHeightFee:String,//自办运输高原增加费
     totalLoadingTimes:String,//装卸总次数
     offSiteTransportLoss:String,//场外运输损耗
     purchaseStorage:String,//采购及保管费

+ 4 - 1
modules/all_models/unit_price_file.js

@@ -11,7 +11,10 @@ let Schema = mongoose.Schema;
 let collectionName = 'unit_price_file';
 let modelSchema = {
     // 自增id
-    id: Number,
+    id: {
+      type: Number,
+      index: true
+    },
     // 标段id
     project_id: {
         type: Number,

+ 28 - 19
modules/complementary_glj_lib/models/gljModel.js

@@ -51,29 +51,34 @@ class GljDao {
     }
 
     //获得用户的补充工料机和用户当前所在编办的标准工料机
-    async getGljItems (stdGljLibId, userId, compilationId, projection, callback){
+    async getGljItems(stdGljLibId, userId, compilationId, projection, callback) {
         let me = this;
-        let rst = {stdGljs: [], complementaryGljs: []};
+        let rst = { stdGljs: [], complementaryGljs: [] };
         //批量获取异步
         async.parallel([
-           async function (cb) {
-               try{
-                   let stdGljs = await stdGljModel.find({repositoryId: stdGljLibId}, projection).lean();
-                   me.sortToNumber(stdGljs);
-                   rst.stdGljs = stdGljs;
-                   cb(null);
-               }
-               catch (err){
-                   cb(err);
-               }
+            async function (cb) {
+                try {
+                    let stdGljs = stdGljLibId ? await stdGljModel.find({ repositoryId: stdGljLibId }, projection).lean() : [];
+                    me.sortToNumber(stdGljs);
+                    rst.stdGljs = stdGljs;
+                    cb(null);
+                }
+                catch (err) {
+                    cb(err);
+                }
 
             },
             function (cb) {
-                complementaryGljModel.find({userId: userId, compilationId: compilationId}, '-_id', {lean: true}, function (err, complementaryGljs) {
-                    if(err){
+                if (!userId || !compilationId) {
+                    rst.complementaryGljs = [];
+                    cb(null);
+                    return;
+                }
+                complementaryGljModel.find({ userId: userId, compilationId: compilationId }, '-_id', { lean: true }, function (err, complementaryGljs) {
+                    if (err) {
                         cb(err);
                     }
-                    else{
+                    else {
                         me.sortToNumber(complementaryGljs);
                         rst.complementaryGljs = complementaryGljs;
                         cb(null);
@@ -81,10 +86,10 @@ class GljDao {
                 });
             }
         ], function (err) {
-            if(err){
+            if (err) {
                 callback(err, null);
             }
-            else{
+            else {
                 callback(0, rst);
             }
         })
@@ -313,8 +318,12 @@ class GljDao {
 
     async getMixedTree(gljLibId, userId, compilationId){
         let rst = {std: [], comple: []};
-        rst.std = await gljClassModel.find({repositoryId: gljLibId}).lean();
-        rst.comple = await compleClassModel.find({userId: userId, compilationId: compilationId}).lean();
+        if (gljLibId) {
+            rst.std = await gljClassModel.find({repositoryId: gljLibId}).lean();
+        }
+        if (userId && compilationId) {
+            rst.comple = await compleClassModel.find({userId: userId, compilationId: compilationId}).lean();
+        }
         return rst;
     }
 }

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

@@ -346,7 +346,7 @@ class UnitPriceModel extends BaseModel {
     }
 
     async updateParentUnitPrice(mixRatio,fieid,project_id,newValueMap,batchUpdate){//batchUpdate 批量更新标记,如果true,只生成task
-        let  decimalObject =await decimal_facade.getProjectDecimal(project_id);
+        let  decimalObject =project_id?await decimal_facade.getProjectDecimal(project_id):null;
         let quantity_decimal = (decimalObject&&decimalObject.glj&&decimalObject.glj.quantity)?decimalObject.glj.quantity:3;
         let price_decimal = (decimalObject&&decimalObject.glj&&decimalObject.glj.unitPrice)?decimalObject.glj.unitPrice:2;
         //查找该工料机所有组成物

+ 1 - 1
modules/main/controllers/project_controller.js

@@ -46,7 +46,7 @@ module.exports = {
             } else {
                 callback(req, res, err, message, null);
             }
-        });
+        }, req.session.sessionUser.id);
     },
     markUpdateProject:async function (req,res) {
         let result={

+ 2 - 2
modules/main/models/project.js

@@ -96,7 +96,7 @@ Project.prototype.save = function(datas, callback){
     me.datas = [];
 };
 
-Project.prototype.getData = function(projectID, callback){
+Project.prototype.getData = function(projectID, callback, userID){
     var functions = [];
     var itemName;
     let firstTime = +new Date();
@@ -105,7 +105,7 @@ Project.prototype.getData = function(projectID, callback){
             return function (cb) {
                 moduleMap[itemName].getData(projectID, function(err, moduleName, data){
                     cb(err, {moduleName: moduleName, data: data})
-                })
+                }, userID)
             }
         })(itemName))
     }

+ 5 - 0
modules/pm/controllers/new_proj_controller.js

@@ -9,6 +9,7 @@ let async = require('async');
 const uuidV1 = require('uuid/v1');
 const mongoose = require('mongoose');
 let mainColLibModel = mongoose.model('std_main_col_lib');
+const { ValuationType } = require('../../../public/common_constants');
 
 import BillsTemplateModel from "../models/templates/bills_template_model";
 import EngineeringLibModel from "../../users/models/engineering_lib_model";
@@ -44,6 +45,10 @@ module.exports = {
                 }
                 const reg = /@\d+/;
                 billsDatas.forEach(function (template) {
+                    // 工程量清单单价分析默认勾选
+                    if (property.valuationType === ValuationType.BOQ) {
+                        template.unitPriceAnalysis = 1;
+                    }
                     template.projectID = newProjID;
                     template.ID = uuidMaping[template.ID] ? uuidMaping[template.ID] : -1;
                     template.ParentID = uuidMaping[template.ParentID] ? uuidMaping[template.ParentID] : -1;

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

@@ -201,7 +201,7 @@ module.exports = {
         });
     },
     //project getData接口
-    getData: function(projectID, callback) {
+    getData: function(projectID, callback, userID) {
         projectModel.findOne({$or: [{deleteInfo: null}, {'deleteInfo.deleted': false}], ID: projectID}, '-_id').then(async function (project) {
             if (!project) {
                 callback('', consts.projectConst.PROJECT_INFO, {});
@@ -229,6 +229,14 @@ module.exports = {
             //获取单位工程完整目录结构
             let fullPath = await pm_facade.getFullPath(projectID);
             projInfo.fullPath = fullPath;
+            // 获取分享的tip
+            projInfo.shareTip = await pm_facade.getShareTip(projectID, 2);
+            // 获取分享状态
+            if (typeof userID === 'string') {
+                projInfo.shareState = await pm_facade.getShareState(projectID, userID);
+            }
+            // 获取项目所属用户
+            projInfo.owner = await userModel.findOne({_id: mongoose.Types.ObjectId(project.userID)}, 'real_name');
             callback('', consts.projectConst.PROJECT_INFO, project);
         }, function (err) {
             callback(err, consts.projectConst.PROJECT_INFO, {});

+ 44 - 3
modules/pm/facade/pm_facade.js

@@ -17,6 +17,8 @@ module.exports={
     getShareInfoMap,
     getRecentShareList,
     getProjectShareList,
+    getShareTip,
+    getShareState,
     moveProject:moveProject,
     accessToCopyProject,
     copyProject:copyProject,
@@ -244,26 +246,65 @@ async function getRecentShareList(userID, count) {
 }
 
 // 获取某项目的分享记录
-async function getProjectShareList(projectID) {
-    const sharedList = await shareListModel.find({ projectID }).lean();
+async function getProjectShareList(projectID, limit = null) {
+    const sharedList = limit 
+        ? await shareListModel.find({ projectID }).lean().sort({ shareDate: -1 }).limit(limit)
+        : await shareListModel.find({ projectID }).lean().sort({ shareDate: -1 });
     const userIDs = [];
     const userMap = {};
-    sharedList.forEach(item => {
+    sharedList.forEach((item, index) => {
         userIDs.push(item.receiver);
         userMap[item.receiver] = item;
+        userMap[item.receiver].index = index;
     });
     const userObjectIDs = userIDs.map(userID => mongoose.Types.ObjectId(userID));
     const users = await userModel.find({_id: {$in: userObjectIDs}}, 'real_name mobile company').lean();
     users.forEach(user => {
         const matched = userMap[user._id];
         if (matched) {
+            user.index = matched.index;
             user.allowCopy = matched.allowCopy;
             user.allowCooperate = matched.allowCooperate;
         }
     });
+    users.sort((a, b) => a.index - b.index);
     return users;
 }
 
+// 获取分享的提示(造价书分享按钮tooltip使用)
+async function getShareTip(projectID, limit) {
+    const task = [
+        getProjectShareList(projectID, limit),
+        shareListModel.count({ projectID })
+    ];
+    const [users, count] = await Promise.all(task);
+    return users.reduce((acc, user, index) => {
+        if (index === 0) {
+            acc += '已分享给';
+            acc += user.real_name;
+        } else {
+            acc += ` ${user.real_name}`;
+        }
+        if (index === users.length - 1 && count > limit) {
+            acc += `等${count}人`;
+        }
+        return acc;
+    }, '');
+}
+
+// 获取项目的分享状态
+// 分享项目的拷贝和编辑性,需要参考父项
+// 以项目链上最新更新的分享数据为准
+async function getShareState(projectID, receiver) {
+    const projectIDs = await getUpChainIDs(projectID);
+    const shareList = await shareListModel.find({ projectID: { $in: projectIDs }, receiver }).lean();
+    shareList.sort((a, b) => Date.parse(b.updateDate) - Date.parse(a.updateDate));
+    return {
+        allowCopy: shareList[0] && shareList[0].allowCopy || false,
+        allowCooperate: shareList[0] && shareList[0].allowCooperate || false
+    };
+}
+
 //拷贝例题项目
 //@param {String}userID {Array}projIDs拷贝的例题项目ID(建设项目、文件夹)@return {Boolean}
 async function copyExample(userID, compilation, projIDs){

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

@@ -32,7 +32,7 @@ import {
     bookmarkSetting
 } from './project_property_template';
 import optionSetting from '../../options/models/optionTypes';
-const { fixedFlag } = require('../../../public/common_constants');
+const { fixedFlag, ValuationType } = require('../../../public/common_constants');
 let FeeRateFiles = mongoose.model('fee_rate_file');
 let counter = require("../../../public/counter/counter.js");
 
@@ -184,7 +184,7 @@ ProjectsDAO.prototype.updateUserProjects = async function (userId, compilationId
                     if(data.updateData.property.featureLibID){
                         //项目类别(valuationType)、养护类别(engineering)、费用标准(feeStandard)根据新建分选的选项去赋值
                         let assign = {
-                            valuationType: data.updateData.property.valuationType === 'bill' ? '预算' : '工程量清单',
+                            valuationType: data.updateData.property.valuationType === ValuationType.BUDGET ? '预算' : '工程量清单',
                             engineering: data.updateData.property.engineeringName,
                             feeStandard: data.updateData.property.feeStandardName
                         };

+ 52 - 1
modules/ration_glj/controllers/ration_glj_controller.js

@@ -5,6 +5,7 @@ let mongoose = require("mongoose")
 let ration_glj_facade = require('../facade/ration_glj_facade')
 import EngineeringLibModel from "../../users/models/engineering_lib_model";
 let logger = require("../../../logs/log_helper").logger;
+const { COMPLEMENTARY_LIB, COMPILATION } = require ('../../../public/common_constants');
 
 module.exports={
     createRationGLJ:createRationGLJ,
@@ -64,7 +65,32 @@ async function getGLJData(req, res) {
         error:0
     }
     try {
-        let info = await ration_glj_facade.getLibInfo(req);
+        let libData = null;
+        let { engineerID, gljLibId, isInitial } = req.params;
+        if (gljLibId !== COMPLEMENTARY_LIB) {
+            gljLibId = +gljLibId;
+        }
+        isInitial = JSON.parse(isInitial);
+        if (!gljLibId || isInitial) { // 替换人材机的话,可能存在gljLibID,但是是初始化的操作
+            libData = engineerID === COMPILATION 
+            ? await ration_glj_facade.getLibOptionsForCompilation(req.session.sessionCompilation._id)
+            : await ration_glj_facade.getLibOptions(engineerID);
+            libData.push({ name: '补充工料机', gljLibId: COMPLEMENTARY_LIB });
+            if (gljLibId) { // 替换人材机初始化会触发此条件
+                const orgDefalutLib = libData.find(lib => lib.isDefault);
+                const newDefaultLib = libData.find(lib => lib.gljLibId === +gljLibId);
+                if (orgDefalutLib && newDefaultLib) {
+                    orgDefalutLib.isDefault = false;
+                    newDefaultLib.isDefault = true;
+                }
+            }
+        }
+        if (!gljLibId && libData) {
+            gljLibId = (libData.find(lib => lib.isDefault) || {}).gljLibId;
+        }
+        const info = gljLibId === COMPLEMENTARY_LIB 
+            ? { gljLibId: null, userID: req.session.sessionUser.id, compilationId: req.session.sessionCompilation._id }
+            : { gljLibId, userID: null, compilationId: null };
         ration_glj_facade.getGLJData(info,function (err,datas) {
             if(err){
                 result.error=1;
@@ -73,6 +99,7 @@ async function getGLJData(req, res) {
                 //多单价字段
                 if(req.session.sessionCompilation.priceProperties) datas.priceProperties = req.session.sessionCompilation.priceProperties;
                 result.datas = datas;
+                result.datas.libData = libData;
             }
             res.json(result);
         });
@@ -83,6 +110,30 @@ async function getGLJData(req, res) {
         res.json(result);
     }
 }
+/* async function getGLJData(req, res) {
+    let result={
+        error:0
+    }
+    try {
+        let info = await ration_glj_facade.getLibInfo(req);
+        ration_glj_facade.getGLJData(info,function (err,datas) {
+            if(err){
+                result.error=1;
+                result.message = err.message;
+            }else {
+                //多单价字段
+                if(req.session.sessionCompilation.priceProperties) datas.priceProperties = req.session.sessionCompilation.priceProperties;
+                result.datas = datas;
+            }
+            res.json(result);
+        });
+    }catch (err){
+        logger.err(err);
+        result.error=1;
+        result.message = err.message;
+        res.json(result);
+    }
+} */
 
 async function addGLJ(req, res){
     let result={

+ 64 - 0
modules/ration_glj/facade/ration_glj_facade.js

@@ -8,6 +8,8 @@ module.exports = {//先 exports再require 防止循环引用
     deleteByRation: deleteByRation,
     getQuantityByProjectGLJ: getQuantityByProjectGLJ,
     getLibInfo: getLibInfo,
+    getLibOptions,
+    getLibOptionsForCompilation,
     getGLJData: getGLJData,
     getGLJDataByCodes:getGLJDataByCodes,
     addGLJ: addGLJ,
@@ -57,6 +59,9 @@ const stdGljModel = mongoose.model('std_glj_lib_gljList');
 const gljClassModel = mongoose.model('std_glj_lib_gljClass');
 const projectDao = require('../../pm/models/project_model').project;
 const compleClassModel = mongoose.model('complementary_glj_section');
+const stdRationLibModel = mongoose.model('std_ration_lib_map');
+const compilationModel = mongoose.model('compilation');
+const engineeringModel = mongoose.model('engineering_lib');
 let gljUtil = require('../../../public/gljUtil');
 
 
@@ -548,6 +553,65 @@ async function getGLJLibByEngineerID  (engineerID) {
     return gljLibId
 }
 
+// 获取人材机选择页面,可选的定额库-人材机库映射选项
+async function getLibOptions(engineerID) {
+    // 找到工程专业绑定的定额库,再获取这些定额库引用的人材机库
+    const engineeringLibModel = new EngineeringLibModel();
+    const engineeringInfo = await engineeringLibModel.findDataByCondition({ _id: engineerID });
+    const rationLibs = engineeringInfo.ration_lib;
+    const rationLibIDs = rationLibs.map(lib => lib.id);
+    const rationLibData = await stdRationLibModel.find({ ID: { $in: rationLibIDs } }, 'ID gljLib').lean();
+    const rst = [];
+    rationLibs.forEach(lib => {
+        rationLibData.forEach(stdLib => {
+            if (+lib.id === +stdLib.ID) {
+                lib.gljLibId = stdLib.gljLib;
+                rst.push(lib);
+            }
+        });
+    });
+    return rst;
+}
+
+// 获取人材机选择库页面,可选的定额库为费用定额下,所有工程专业的定额库(需要去重)
+async function getLibOptionsForCompilation(compilationId) {
+    const compilation = await compilationModel.findOne({ _id: mongoose.Types.ObjectId(compilationId) }, 'ration_valuation bill_valuation');
+    const valuationIDs = [];
+    if (compilation.ration_valuation[0] && compilation.ration_valuation[0].enable) {
+        valuationIDs.push(compilation.ration_valuation[0].id);
+    }
+    if (compilation.bill_valuation[0] && compilation.bill_valuation[0].enable) {
+        valuationIDs.push(compilation.bill_valuation[0].id);
+    }
+    const engineeringLibs = await engineeringModel.find({ valuationID: { $in: valuationIDs }, visible: true }, 'ration_lib');
+    const rationLibs = [];
+    const rationLibIDs = [];
+    let hasDefalut = false;
+    engineeringLibs.forEach(lib => {
+        lib.ration_lib.forEach(rLib => {
+            if (!rationLibIDs.includes(rLib.id)) {
+                rationLibIDs.push(rLib.id);
+                rationLibs.push({
+                    isDefault: hasDefalut ? false: rLib.isDefault,
+                    name: rLib.name,
+                    id: rLib.id
+                });
+                if (rLib.isDefault) {
+                    hasDefalut = true;
+                }
+            }
+        });
+    });
+    const stdRationLibs = await stdRationLibModel.find({ ID: { $in: rationLibIDs } }, 'ID gljLib').lean();
+    rationLibs.forEach(lib => {
+        stdRationLibs.forEach(stdLib => {
+            if (+lib.id === +stdLib.ID) {
+                lib.gljLibId = stdLib.gljLib;
+            }
+        });
+    });
+    return rationLibs;
+}
 
 function getGLJData(info, callback) {
     let gljDao = new GljDao();

+ 1 - 1
modules/ration_glj/routes/ration_glj_route.js

@@ -8,7 +8,7 @@ let rgController = require('../controllers/ration_glj_controller');
 module.exports = function (app) {
 
     var rgRouter = express.Router();
-    rgRouter.get('/getGLJData/:engineerID', rgController.getGLJData);
+    rgRouter.get('/getGLJData/:engineerID/:gljLibId/:isInitial', rgController.getGLJData);
     rgRouter.post('/getGLJDataByCodes',rgController.getGLJDataByCodes);
     rgRouter.post('/addGLJ',rgController.addGLJ);
     rgRouter.post('/replaceGLJ',rgController.replaceGLJ);

+ 50 - 0
modules/unit_price_file/controllers/unit_price_controller.js

@@ -0,0 +1,50 @@
+
+let mongoose = require("mongoose")
+let logger = require("../../../logs/log_helper").logger;
+let config = require("../../../config/config.js");
+let unitPriceFileModel = mongoose.model('unit_price_file');
+let projectModel = mongoose.model('projects');
+const ProjectDao = require('../../pm/models/project_model').project;
+let unitPriceModel = mongoose.model('unit_price');
+let mixRatioModel = mongoose.model('mix_ratio');
+let glj_type_util = require('../../../public/cache/std_glj_type_util');
+let _ = require("lodash");
+
+module.exports={
+    index:async function(req,res){
+      let unitPriceFileID = req.params.unitPriceFileID;
+      let unitPriceFile = await unitPriceFileModel.findOne({id:unitPriceFileID}).lean();
+      let project = await projectModel.findOne({ID:unitPriceFile.root_project_id}).lean();
+      let tenderData = await ProjectDao.getTenderByUnitPriceFileId(unitPriceFileID);
+      let unitpriceList = await unitPriceModel.find({unit_price_file_id:unitPriceFileID},{supplyLocation:0}).lean();
+      let mixRatioList = await mixRatioModel.find({unit_price_file_id:unitPriceFileID}).lean();
+      let mixRatioMap = _.groupBy(mixRatioList,"connect_key");
+
+
+
+      let gljTypeMap = glj_type_util.getStdGljTypeCacheObj().innerGljTypeObj;
+      let usedTenderList = [];
+      if (tenderData !== null) {
+          for (let tmp of tenderData) {
+              usedTenderList.push(tmp.name);
+          }
+      }
+      let usedTenderString = "人材机单价的变化,将自动影响以下单位工程造价:<br>"+usedTenderList.join("<br>");
+      res.render('building_saas/unit_price_file/index.html',
+        {
+          userAccount: req.session.userAccount,
+          userID: req.session.sessionUser.id,
+          versionName: req.session.compilationVersion,
+          unitFileName:unitPriceFile.name,
+          rootProjectName:project.name,
+          usedTenderList:usedTenderList,
+          usedTenderString:usedTenderString,
+          unitpriceList:JSON.stringify(unitpriceList),
+          gljTypeMap:JSON.stringify(gljTypeMap),
+          mixRatioMap:JSON.stringify(mixRatioMap),
+          LicenseKey:config.getLicenseKey(process.env.NODE_ENV)
+        });
+    }
+}
+
+// engineerID = req.params.engineerID;

+ 14 - 0
modules/unit_price_file/routes/unit_price_router.js

@@ -0,0 +1,14 @@
+let express = require('express');
+let unitPirceController = require('../controllers/unit_price_controller');
+
+module.exports = function (app) {
+
+    var Router = express.Router();
+    Router.get('/index/:unitPriceFileID', unitPirceController.index);
+    // Router.post('/getGLJDataByCodes',unitPirceController.getGLJDataByCodes);
+    // Router.post('/addGLJ',unitPirceController.addGLJ);
+    // Router.post('/replaceGLJ',unitPirceController.replaceGLJ);
+    
+
+    app.use('/unitPrice',Router);
+}

+ 1 - 1
modules/users/models/user_model.js

@@ -452,7 +452,7 @@ class UserModel extends BaseModel {
 
         let keyword = request.query.keyword;
         if (keyword !== '' && keyword !== undefined) {
-            condition.$or = [{real_name : {$regex: keyword}},{email : {$regex: keyword}},{mobile : {$regex: keyword}},{company : {$regex: keyword}}];
+            condition.$or = [{real_name : {$regex: keyword}},{email : {$regex: keyword}},{mobile : {$regex: keyword}},{qq : {$regex: keyword}},{company : {$regex: keyword}}];
         }
 
         return condition;

+ 34 - 1
public/common_constants.js

@@ -75,9 +75,42 @@
         PREVENTIVE_MAINTENANCE_FEE: 32,
         // 修复养护费
         REPAIR_MAINTENANCE_FEE: 33,
+        // 日常养护费
+        DAILY_MAINTENANCE_FEE: 34,
+        // 日常巡查费
+        DAILY_PATROL_FEE: 35,
+        // 日常保养费
+        DAILY_UPKEEP_FEE: 36,
+        // 信息化系统养护费
+        INFORMATIZATION_MAINTENANCE_FEE: 37,
+        // 技术状况评定费
+        TECH_ASSESSMENT_FEE: 38,
+        // 系统维护费
+        SYSTEM_MAINTENANCE_FEE: 39,
+        // 养护机械设备购置费
+        MAINTENANCE_MACHINE_ACQUISITION_FEE: 40,
+        // 养护工程费
+        MAINTENANCE_FEE: 41,
+        // 应急养护费
+        EMERGENCY_FEE: 42
+    };
+
+    // 补充人材机库
+    const COMPLEMENTARY_LIB = 'complementaryLib';
+
+    // 费用定额
+    const COMPILATION = 'compilation';
+
+    // 项目类别,叫bill和ratoin,是建筑的计价类型为清单、定额计价,延用。
+    const ValuationType = {
+        BUDGET: 'bill',
+        BOQ: 'ration'
     };
 
     return {
-        fixedFlag
+        fixedFlag,
+        COMPLEMENTARY_LIB,
+        COMPILATION,
+        ValuationType,
     };
 })

+ 6 - 8
public/web/gljUtil.js

@@ -265,12 +265,9 @@ let gljUtil = {
         if (!this.isConcreteType(glj.unit_price.type)&& this.notEditType.indexOf(glj.unit_price.type)!=-1&&glj.ratio_data.length>0) {//对于机械台班等有组成物的材料,价格需根据组成物计算得出(排除混凝土、配合比、砂浆这几个类型直接为0)。
             let p =0;
             for(let ratio of glj.ratio_data){
-                let tem =  _.find(projectGLJDatas.gljList,{
-                    'code': ratio.code,
-                    'name': ratio.name,
-                    'specs':ratio.specs,
-                    'type': ratio.type,
-                    'unit': ratio.unit
+                let rIndex = gljUtil.getIndex(ratio);
+                let tem =  _.find(projectGLJDatas.gljList,function(item){
+                  return rIndex == gljUtil.getIndex(item);
                 });
                 if(tem){
                     let priceData=this.getGLJPrice(tem,projectGLJDatas,calcOptions,labourCoeDatas,decimalObj,true,_,scMathUtil);
@@ -399,8 +396,9 @@ let gljUtil = {
         let lo = lodash?lodash:_;
         let specialMap = {1:-1,303:0,202:9,203:10,204:11};//,人工、机械工排在最前,混凝土、砂浆、配合比 排到最后
         list = lo.sortByAll(list, [function (item) {
-            if(specialMap[item.unit_price.type] != undefined) return specialMap[item.unit_price.type];
-            return gljUtil.getMainType(item.unit_price.type);
+            let unit_price = item.unit_price?item.unit_price:item;
+            if(specialMap[unit_price.type] != undefined) return specialMap[unit_price.type];
+            return gljUtil.getMainType(unit_price.type);
         }, gljUtil.getCodeSortMath()]);
         return list;
     },

+ 6 - 5
public/web/sheet/sheet_common.js

@@ -132,13 +132,14 @@ var sheetCommonObj = {
             if (setting.header[col].formatter) {
                 sheet.setFormatter(-1, col, setting.header[col].formatter, GC.Spread.Sheets.SheetArea.viewport);
             }
-            if (setting.header[col].cellType === "checkBox" || setting.header[col].cellType === "button") {//clear and reset
+           /*  直接在showrowdata时当val为null时返回一个text类型的单元格 
+              if (setting.header[col].cellType === "checkBox" || setting.header[col].cellType === "button") {//clear and reset
                 var me = this, header = GC.Spread.Sheets.SheetArea.colHeader;
                 sheet.deleteColumns(col, 1);
                 sheet.addColumns(col, 1);
                 sheet.setValue(0, col, setting.header[col].headerName, header);
                 sheet.setColumnWidth(col, setting.header[col].headerWidth ? setting.header[col].headerWidth : 100);
-            }
+            } */
             if (setting.header[col].visible !== null && setting.header[col].visible !== undefined) {
                 sheet.setColumnVisible(col, setting.header[col].visible);
             }
@@ -177,7 +178,7 @@ var sheetCommonObj = {
                     val = val + '';
                 }
             }
-            if (val != null && setting.header[col].cellType === "checkBox") {
+            if (setting.header[col].cellType === "checkBox") {
                 this.setCheckBoxCell(row, col, sheet, val)
             }
             if (setting.header[col].cellType === "comboBox") {
@@ -301,8 +302,8 @@ var sheetCommonObj = {
         }
     },
     setCheckBoxCell(row, col, sheet, val) {
-        var c = new GC.Spread.Sheets.CellTypes.CheckBox();
-        c.isThreeState(false);
+        var c = val==null?new GC.Spread.Sheets.CellTypes.Text():new GC.Spread.Sheets.CellTypes.CheckBox();
+        if(val != null) c.isThreeState(false);
         sheet.setCellType(row, col, c, GC.Spread.Sheets.SheetArea.viewport);
         sheet.getCell(row, col).value(val);
         sheet.getCell(row, col).hAlign(GC.Spread.Sheets.HorizontalAlign.center);

+ 9 - 6
public/web/tree_sheet/tree_sheet_helper.js

@@ -224,7 +224,7 @@ var TREE_SHEET_HELPER = {
         }
        sheet.invalidateLayout();
     },
-    showTreeData: function (setting, sheet, tree) {
+    getTipCellType: function (setting) {
         let TipCellType = function () {};
         TipCellType.prototype = new GC.Spread.Sheets.CellTypes.Text();
         TipCellType.prototype.getHitInfo = function (x, y, cellStyle, cellRect, context) {
@@ -247,7 +247,7 @@ var TREE_SHEET_HELPER = {
                 zoom = hitinfo.sheet.zoom();
             let textLength = this.getAutoFitWidth(value, text, acStyle, zoom, {sheet: hitinfo.sheet, row: hitinfo.row, col: hitinfo.col, sheetArea: GC.Spread.Sheets.SheetArea.viewport});
             let cellWidth = hitinfo.sheet.getCell(-1, hitinfo.col).width();
-            let dataField = setting.cols[hitinfo.col].data.field;
+            let dataField = setting.cols && setting.cols[hitinfo.col].data.field || setting.header[hitinfo.col].dataCode;
 
             if((tag==undefined||tag=='')&&hitinfo.sheet.getCell(hitinfo.row,hitinfo.col).wordWrap()==true){//显示其它列的标记为空并且设置了自动换行
                 return;
@@ -280,8 +280,10 @@ var TREE_SHEET_HELPER = {
         };
         TipCellType.prototype.processMouseLeave = function (hitinfo) {
             TREE_SHEET_HELPER.hideTipsDiv();
-        }
-
+        };
+        return new TipCellType();
+    },
+    showTreeData: function (setting, sheet, tree) {
         TREE_SHEET_HELPER.protectdSheet(sheet);
         TREE_SHEET_HELPER.massOperationSheet(sheet, function () {
             sheet.rowOutlines.direction(GC.Spread.Sheets.Outlines.OutlineDirection.backward);
@@ -294,7 +296,7 @@ var TREE_SHEET_HELPER = {
             setting.cols.forEach(function (colSetting, iCol) {
                 sheet.setStyle(-1, iCol, TREE_SHEET_HELPER.getSheetCellStyle(colSetting));
                 if (colSetting.showHint) {
-                    sheet.getRange(-1, iCol, -1, 1).cellType(new TipCellType());
+                    sheet.getRange(-1, iCol, -1, 1).cellType(TREE_SHEET_HELPER.getTipCellType(setting));
                 }
                 if(colSetting.formatter){
                     sheet.setFormatter(-1, iCol, colSetting.formatter, GC.Spread.Sheets.SheetArea.viewport);
@@ -616,7 +618,7 @@ var TREE_SHEET_HELPER = {
 
     },
     showTipsDiv:function (text,setting,hitinfo) {
-        if (setting.pos && text && text !== '') {
+        if (text && text !== '') {
             if(text) text = replaceAll(/[\n]/,'<br>',text);
             if(!this._fixedTipElement){
                 let div = $('#fixedTip')[0];
@@ -669,6 +671,7 @@ var TREE_SHEET_HELPER = {
                     let left =  setting.pos.x + hitinfo.cellRect.x;
                     $(this._toolTipElement).css("top", top).css("left", left).css("max-width","500px");
                 }
+                $(this._toolTipElement).css('z-index', 9999);
                 $(this._toolTipElement).show("fast");
                 TREE_SHEET_HELPER.tipDiv = 'show';//做个标记
             }

+ 10 - 2
web/building_saas/complementary_ration_lib/html/dinge.html

@@ -18,6 +18,10 @@
     <link rel="shortcut icon" href="/web/building_saas/css/favicon.ico">
     <link rel="icon" type="image/gif" href="/web/building_saas/css/animated_favicon1.gif">
     <style type="text/css">
+        .form-control-inline {
+            display: inline-block !important;
+            width: 80% !important;
+        }
         div.resize-y{
             height: 5px;
             background: #efefef;
@@ -520,8 +524,12 @@
             <div class="modal-body" style="padding-left: 0; padding-right: 3px; margin-left: 0;">
                 <div style="width: 36%; float: left;">
                     &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;
+                    <select class="form-control  form-control-sm form-control-inline" id="glj-lib-select">
+                        <option value="1">1</option>
+                        <option value="2">2</option>
+                    </select>
+<!--                     <input type="radio" class="glj-radio" name="glj" value="stdGljs">标准&nbsp;&nbsp;
+                    <input type="radio" class="glj-radio" name="glj" value="complementaryGljs">补充&nbsp;&nbsp; -->
                     <div  class="modal-auto-height" id="gljSelTreeDiv" style="overflow: hidden">
                         <div style="width: 100%; height: 100%; overflow: auto">
                             <ul id="selGljTree" class="ztree"></ul>

+ 73 - 87
web/building_saas/complementary_ration_lib/js/gljSelect.js

@@ -3,10 +3,10 @@
  */
 
 let gljSelOprObj = {
+    distTypeTree: null,
     parentNodeIds: {},
     treeObj:null,
     rootNode: null,//分类树根节点
-    radiosSelected: null,//allGljs, stdGljs, complementaryGljs
     workBook: null,
     selectedList: [],//选中的工料机
     setting: {
@@ -39,23 +39,6 @@ let gljSelOprObj = {
             delete glj.ID;
         }
     },
-    getSelGljItems: function(gljData) {
-        this.stdGljList = gljData.stdGljs;
-        //兼容多单价,计算补充定额价格时,套多单价人材机的时候,默认取第一个价格
-        for(let sGlj of this.stdGljList){
-            if(sGlj.priceProperty && typeof sGlj.priceProperty.price1 !== 'undefined'){
-                sGlj.basePrice = sGlj.priceProperty.price1;
-            }
-        }
-        this.complementaryGljList = gljData.complementaryGljs;
-        this.switchToGljId(this.stdGljList);
-        this.switchToGljId(this.complementaryGljList);
-        this.setProp('type', 'std', this.stdGljList);
-        this.setProp('type', 'complementary', this.complementaryGljList);
-        this.sortGlj(this.stdGljList);
-        this.sortGlj(this.complementaryGljList);
-        gljAdjOprObj.gljList = this.stdGljList.concat(this.complementaryGljList);
-    },
     initClassTree: function (type, treeData) {
         let me = this;
         if (me.treeObj) {
@@ -75,28 +58,6 @@ let gljSelOprObj = {
             }
         }
     },
-    getGljClassTree: function (gljLibId, callback) {
-        let me = this;
-        let url = '/complementartGlj/api/getMixedTree';
-        let postData = {gljLibId: gljLibId};
-        let sucFunc = function (rstData) {
-            me.treeData = rstData;
-            me.initClassTree('std', me.treeData.std);
-            gljSelOprObj.buildSheet($('#gljSelSheet')[0]);
-            if(callback){
-                callback();
-            }
-        };
-        let errFunc = function () {
-
-        };
-        CommonAjax.post(url, postData, sucFunc, errFunc);
-    },
-    getGljClassTree: function (mixedTreeData) {
-        this.treeData = mixedTreeData;
-        this.initClassTree('std', this.treeData.std);
-        gljSelOprObj.buildSheet($('#gljSelSheet')[0]);
-    },
     buildSheet: function (container) {
         let me = gljSelOprObj;
         me.workBook = sheetCommonObj.buildSheet(container, me.setting, 30);
@@ -107,7 +68,64 @@ let gljSelOprObj = {
         me.workBook.getSheet(0).bind(GC.Spread.Sheets.Events.ClipboardPasting, me.onClipboardPasting);
         me.workBook.bind(GC.Spread.Sheets.Events.ButtonClicked, me.onButtonClicked);//复选框点击事件
         me.bindBtnOpr($('#gljSelY'));
-        me.radiosChange();
+    },
+    setGLJItems: function(stdGLJs, complementaryGLJs) {
+        this.stdGljList = stdGLJs;
+        //兼容多单价,计算补充定额价格时,套多单价人材机的时候,默认取第一个价格
+        for(let sGlj of this.stdGljList){
+            if(sGlj.priceProperty && typeof sGlj.priceProperty.price1 !== 'undefined'){
+                sGlj.basePrice = sGlj.priceProperty.price1;
+            }
+        }
+        this.complementaryGljList = complementaryGLJs;
+        this.switchToGljId(this.stdGljList);
+        this.switchToGljId(this.complementaryGljList);
+        this.setProp('type', 'std', this.stdGljList);
+        this.setProp('type', 'complementary', this.complementaryGljList);
+        this.sortGlj(this.stdGljList);
+        this.sortGlj(this.complementaryGljList);
+    },
+    initLibOptions: function (libData) {
+        const html = libData.reduce((acc, lib) => acc += `<option ${lib.isDefault ? 'selected="selected"' : ''} value="${lib.gljLibId}">${lib.name}</option>`, '');
+        $('#glj-lib-select').html(html);
+    },
+    // 初始化选择页面
+    initView: async function (gljLibId, isInitial) {
+        try {
+            $.bootstrapLoading.start();
+            const { libData, treeData, distTypeTree, stdGLJ, complementaryGLJs } = await this.getViewData(gljLibId);
+            if (isInitial) {
+                this.initLibOptions(libData);
+                $('#gljSearchKeyword').val('');
+                setTimeout(() => $('#selGlj').modal('show'), 200);
+            }
+            if (!this.workBook) {
+                this.buildSheet($('#gljSelSheet')[0]);
+            }
+            this.distTypeTree = distTypeTree;
+            this.setGLJItems(stdGLJ, complementaryGLJs);
+            this.selectedList = [].concat(rationGLJOprObj.cache['_GLJ_' + rationGLJOprObj.currentRationItem.ID]);
+            this.showGljList = [];
+            this.setShowGljList(this.stdGljList, true);
+            if (treeData.std.length) {
+                this.initClassTree('std', treeData.std);
+            } else if (treeData.comple.length) {
+                this.initClassTree('comple', treeData.comple);
+            } else {
+                throw '没有有效的分类树。';
+            }
+            this.filterDatasAndShow();
+        } catch (err) {
+            console.log(err);
+            alert(err);
+        } finally {
+            $.bootstrapLoading.end();
+        }
+    },
+    getViewData: async function (gljLibId) {
+        const url = `/rationGlj/getGLJData/${commonConstants.COMPILATION}/${gljLibId}/true`;
+        const data = await ajaxGet(url);
+        return data.datas;
     },
     onClipboardPasting: function (sender, args) {
         args.cancel = true;
@@ -172,41 +190,16 @@ let gljSelOprObj = {
             me.showGljList.push(gljList[i]);
         }
     },
-    //初始默认radio
-    initRadio: function () {
-        let me = gljSelOprObj;
-        $('#gljSearchKeyword').val('');//恢复搜索文本
-        me.selectedList = [].concat(rationGLJOprObj.cache['_GLJ_' + rationGLJOprObj.currentRationItem.ID]);
-        //默认radio所有工料机
-        if(typeof $("input[name='glj']:checked")[0] !== 'undefined'){
-            $("input[name='glj']:checked")[0].checked = false;
-        }
-        $("input[value = 'stdGljs']")[0].checked = true;
-        me.radiosSelected = 'stdGljs';
-        //初始为标准工料机
-        me.showGljList = [];
-        if(me.radiosSelected === 'stdGljs'){
-            me.setShowGljList(me.stdGljList, true);
-            //me.setShowGljList(me.complementaryGljList, true);
-            me.sortGlj(me.showGljList);
-        }
-    },
     filterDatasAndShow: function () {
+        const gljLib = $('#glj-lib-select').val();
         let me = gljSelOprObj;
-        let val = $("input[name='glj']:checked").val();
-        me.radiosSelected = val;
         //选择改变,数据重新筛选显示
         me.showGljList = [];
-        if(me.radiosSelected === 'allGljs'){
-            me.setShowGljList(me.stdGljList);
+        if (gljLib === commonConstants.COMPLEMENTARY_LIB) {
             me.setShowGljList(me.complementaryGljList);
-        }
-        else if(me.radiosSelected === 'stdGljs'){
+        } else {
             me.setShowGljList(me.stdGljList);
         }
-        else if(me.radiosSelected === 'complementaryGljs'){
-            me.setShowGljList(me.complementaryGljList);
-        }
         //搜索匹配
         let searchStr = $('#gljSearchKeyword').val();
         if(searchStr && searchStr.trim() != ''){
@@ -215,10 +208,9 @@ let gljSelOprObj = {
                 return reg.test(data.code) || reg.test(data.name);
             });
         }
-        me.sortGlj(me.showGljList);
+        //me.sortGlj(me.showGljList);
         //重新显示
         me.showGljItems(me.showGljList, me.gljCurTypeId);
-        //切换radio后更新cache
         if (me.currentOprParent = 1) {
             if(me.parentNodeIds["_pNodeId_" + me.gljCurTypeId]){
                 me.currentCache = me.getParentCache(me.parentNodeIds["_pNodeId_" + me.gljCurTypeId]);
@@ -230,19 +222,6 @@ let gljSelOprObj = {
             me.currentCache = me.getCache();
         }
     },
-    //监听radios选择事件
-    radiosChange: function () {
-        let me = gljSelOprObj;
-        $('.glj-radio').change(function () {
-            if($(this).val() === 'stdGljs') {
-                me.initClassTree('std', me.treeData.std);
-            } else {
-                me.initClassTree('comple', me.treeData.comple);
-            }
-            me.filterDatasAndShow();
-        });
-    },
-
     getParentCache: function (nodes) {
         let me = gljSelOprObj, rst = [];
         for(let i = 0; i < me.showGljList.length; i++){
@@ -279,7 +258,7 @@ let gljSelOprObj = {
                     cacheSection.push(data[i]);
                 }
             }
-            sheetCommonObj.cleanSheet(me.workBook.getSheet(0), me.setting, -1);
+            //sheetCommonObj.cleanSheet(me.workBook.getSheet(0), me.setting, -1);
             sheetsOprObj.showDataForGljSel(me.workBook.getSheet(0), me.setting, cacheSection, rationGLJOprObj.distTypeTree);
             me.workBook.getSheet(0).setRowCount(cacheSection.length);
             cacheSection = null;
@@ -349,7 +328,11 @@ let gljSelTreeOprObj = {
 };
 
 $(document).ready(function () {
-    $('#gljSearchKeyword').change(function () {
+    $('#glj-lib-select').change(function () {
+        const gljLibId = $(this).val();
+        gljSelOprObj.initView(gljLibId, false);
+    });
+    /* $('#gljSearchKeyword').change(function () {
         gljSelOprObj.filterDatasAndShow();
     });
     $('#gljSearchKeyword').bind('keypress', function (e) {
@@ -357,7 +340,10 @@ $(document).ready(function () {
             $(this).blur();
             return false;
         }
-    });
+    }); */
+    $('#gljSearchKeyword').on('keyup', _.debounce(function () {
+        gljSelOprObj.filterDatasAndShow();  
+    }, 300));
     $('#selGlj').on('shown.bs.modal', function () {
         if (gljSelOprObj.workBook) {
             gljSelOprObj.workBook.refresh();

+ 1 - 0
web/building_saas/complementary_ration_lib/js/init.js

@@ -40,6 +40,7 @@ const initialization = (() => {
                 rdSpreadEscSheets.push({sheet: rdSpread.getSheet(2), editStarting: rationCoeOprObj.onEditStarting, editEnded: rationCoeOprObj.onEditEnded});
                 rdSpreadEscSheets.push({sheet: rdSpread.getSheet(3), editStarting: rationInstObj.onEditStarting, editEnded: rationInstObj.onEditEnded});
                 sheetCommonObj.bindEscKey(rdSpread, rdSpreadEscSheets);
+                gljAdjOprObj.gljList = data.mixedGLJData.stdGljs.concat(data.mixedGLJData.complementaryGljs);
                 pageOprObj.initPage();
 
                 $("#linkGLJ").click(function(){

+ 1 - 6
web/building_saas/complementary_ration_lib/js/ration_glj.js

@@ -113,12 +113,7 @@ var rationGLJOprObj = {
                         items: {
                             "add": {
                                 name: "添加工料机", disabled: addDis, icon: "fa-plus", callback: function (key, opt) {
-                                    //默认radio所有工料机
-                                    gljSelOprObj.initRadio();
-                                    gljSelOprObj.gljCurTypeId = null;
-                                    gljSelOprObj.initClassTree('std', gljSelOprObj.treeData.std);
-                                    //弹出窗口
-                                    $('#selGlj').modal('show');
+                                    gljSelOprObj.initView(0, true);
                                 }
                             },
                             "delete": {

+ 0 - 2
web/building_saas/complementary_ration_lib/js/section_tree.js

@@ -20,8 +20,6 @@ let pageOprObj = {
         $('#fzAddConBtn').click(annotationOprObj.bindAddConBtn());
         $('#fzUpdateConBtn').click(annotationOprObj.bindUpdateConBtn());
         annotationOprObj.bindAllEvents($('#fzTxtareaAll'));
-        gljSelOprObj.getGljClassTree(this.mixedTreeData);
-        gljSelOprObj.getSelGljItems(this.mixedGLJData);
     },
     getRationLibInfo: function (rationLibId, callback) {
         CommonAjax.post('api/getRationLib', {rationRepId: rationLibId}, callback);

+ 9 - 0
web/building_saas/css/custom.css

@@ -431,4 +431,13 @@ input.text-right{
 .poj-list {
     height: 1000px; 
     background: #f7f7f9;
+}
+.form-control-inline {
+  display: inline-block !important;
+  width: 80% !important;
+}
+.unit_price_header{
+  padding-top:6px;
+  margin-left: 50px;
+  margin-right: 100px !important;
 }

+ 4 - 0
web/building_saas/css/main.css

@@ -56,6 +56,10 @@ font-size: .875rem;
 height: calc(1.5em + .5rem + 2px);
 font-size: .875rem;
 }
+.btn-xs{
+  padding:0rem .5rem;
+  font-size:.875rem;
+}
 /*自定义css*/
 .login-body,.login-html{
 height:100%;

+ 1 - 0
web/building_saas/glj/html/project_glj.html

@@ -14,6 +14,7 @@
                 <option>福建车船税标准(2012)</option>
             </select>
         </div>
+        <a class="btn btn-sm ml-1" id="editUnitFile" href="/unitPrice/index/123" target="_"> 编辑单价文件</a>
     </div>
 
 </div>

+ 7 - 6
web/building_saas/main/html/main.html

@@ -42,7 +42,7 @@
         let projectReadOnly = JSON.parse('<%- projectReadOnly %>');
         let projectCooperate = JSON.parse('<%- projectCooperate %>');
         let projectOptins =  JSON.parse('<%- options %>');
-        const G_SHOW_BLOCK_LIB = false;
+        const G_SHOW_BLOCK_LIB = true;
 //        const G_SHOW_BLOCK_LIB = false;
     </script>
 </head>
@@ -1069,8 +1069,10 @@
                 <div class="modal-body" style="padding-left: 0; padding-right: 3px; margin-left: 0;">
                         <div style="width: 32%; float: left;">
                             &nbsp;
-                            <input type="radio" class="glj-radio" name="glj" value="stdGLJ">标准&nbsp;&nbsp;
-                            <input type="radio" class="glj-radio" name="glj" value="complementaryGLJs">补充&nbsp;&nbsp;
+                            <select class="form-control  form-control-sm form-control-inline" id="glj-lib-select">
+                            </select>
+ <!--                            <input type="radio" class="glj-radio" name="glj" value="stdGLJ">标准&nbsp;&nbsp;
+                            <input type="radio" class="glj-radio" name="glj" value="complementaryGLJs">补充&nbsp;&nbsp; -->
                             <div  class="modal-auto-height" id="componentTreeDiv" style=" height: 435px; overflow: hidden;">
                                 <!--<div class="print-list">-->
                                 <div style="width: 100%; height: 100%; overflow: auto">
@@ -1210,7 +1212,7 @@
                         <span aria-hidden="true">&times;</span>
                     </button>
                 </div>
-                <div class="modal-body">
+                <div class="modal-body pb-0">
                     <div class="tab-content">
                         <div class="tab-pane active" id="m-js" role="tabpanel">
                             <div class="form-group" id="expArea">
@@ -1258,7 +1260,7 @@
                                         </li>
                                     </ul>
                                 </div>
-                                <div class=" modal-auto-height col-9" style="overflow: hidden; padding: 0; margin: 0;" id="billsBaseSpread">
+                                <div class=" modal-auto-height col-9" style="overflow: hidden; padding: 0; margin: 0; height: 360px;" id="billsBaseSpread">
                                 </div>
                             </div>
                         </div>
@@ -1955,7 +1957,6 @@
     <script type="text/javascript" src="/public/web/common_ajax.js"></script>
     <script type="text/javascript" src="/public/web/url_util.js"></script>
     <script type="text/javascript" src="/public/web/number_util.js"></script>
-    <script type="text/javascript" src="/public/web/sheet/sheet_common.js"></script>
     <script type="text/javascript" src="/public/web/slideResize.js"></script>
     <!-- JS. -->
     <!--<script src="/lib/popper/popper.min.js"></script>

+ 6 - 0
web/building_saas/main/js/models/bills.js

@@ -182,6 +182,9 @@ var Bills = {
             insertData.forEach(function (data) {
                 if (data.type === idTree.updateType.new) {
                     data.data.type = billType.BILL;
+                    if (projectObj.project.property.valuationType === commonConstants.ValuationType.BOQ) {
+                        data.data.unitPriceAnalysis = 1;
+                    }
                     newData = data.data;
                 }
             });
@@ -197,6 +200,9 @@ var Bills = {
             var newData = null, that = this;
             insertData.forEach(function (data) {
                 if (data.type === idTree.updateType.new) {
+                    if (projectObj.project.property.valuationType === commonConstants.ValuationType.BOQ) {
+                        data.data.unitPriceAnalysis = 1;
+                    }
                     data.data.code = that.newFormatCode(stdBillsData.code);
                     data.data.name = stdBillsData.name;
                     data.data.unit = stdBillsData.unit;

+ 27 - 8
web/building_saas/main/js/models/project_glj.js

@@ -431,14 +431,16 @@ ProjectGLJ.prototype.materialCal = function (id,dataMap,tglj,tfreightList,tprice
     if(!glj) return;
     let unitPrice = {projectGLJID:glj.id,id:glj.unit_price.id,'unit_price_file_id':glj.unit_price.unit_price_file_id,doc:{}};
     //先计算原价
-    let [originalPrice,supplyLocation] = this.priceCalc(glj,dataMap,tpriceList);
+    let [originalPrice,supplyLocation,priceHeightFee] = this.priceCalc(glj,dataMap,tpriceList);
     doc['originalPrice'] = originalPrice+'';
     doc['supplyLocation'] = supplyLocation;
+    doc['priceHeightFee'] = priceHeightFee;
     //再计算运费
     let grossWeightCoe_n = doc['grossWeightCoe_n']?doc['grossWeightCoe_n']:glj.unit_price.grossWeightCoe_n;
     grossWeightCoe_n = scMathUtil.roundForObj(grossWeightCoe_n,process);
-    let unitFreight = this.freightCalc(glj,grossWeightCoe_n,dataMap,tfreightList);
+    let [unitFreight,freightHeightFee] = this.freightCalc(glj,grossWeightCoe_n,dataMap,tfreightList);
     doc['unitFreight'] = unitFreight+'';
+    doc['freightHeightFee'] = freightHeightFee+'';
     //计算场外运输损耗
     let sum_o_f = scMathUtil.roundForObj(originalPrice+unitFreight,process);//(原价+单位运费)
     let totalLoadingTimes = doc["totalLoadingTimes"]?doc["totalLoadingTimes"]:glj.unit_price.totalLoadingTimes;//装卸总次数
@@ -478,10 +480,12 @@ ProjectGLJ.prototype.freightCalc= function (glj,grossWeightCoe_n,dataMap,tfreigh
     let unitPirce = getDecimal("glj.unitPrice");
     let unitPriceHasMix = getDecimal("glj.unitPriceHasMix");//这里暂时没用到
     let sum = 0;
+    let height_sum=0;
     let freightList = tfreightList?tfreightList:_.filter(this.datas.freightList,{"connect_key":gljUtil.getIndex(glj)});
     if(dataMap["freight"] && dataMap["freight"]["add"])  freightList = freightList.concat(dataMap["freight"]["add"]); //把添加的加进去
     for(let f of freightList){
         let unitFreight = f.unitFreight,kmDistance = f.kmDistance,freightIncreaseRate = f.freightIncreaseRate,unitLoadingFee= f.unitLoadingFee,loadingTimes = f.loadingTimes,otherFee = f.otherFee,weightCoe = f.weightCoe,conveyance = f.conveyance,calcType=f.calcType,materialType=f.materialType;
+        let heightFee= f.heightFee?f.heightFee:0;  
         if(dataMap["freight"] && dataMap["freight"]["update"]){//覆盖更新的数据
             let t = dataMap["freight"]["update"][f.ID];
             if(t){
@@ -495,6 +499,7 @@ ProjectGLJ.prototype.freightCalc= function (glj,grossWeightCoe_n,dataMap,tfreigh
                 if(t['conveyance']) conveyance = t['conveyance'];
                 if(t['calcType']) calcType = t['calcType'];
                 if(t['materialType']) materialType = t['materialType'];
+                if(t['heightFee']) heightFee = t['heightFee'];
             }
         }
         if(dataMap["freight"] && dataMap["freight"]["delete"]){//忽略删除的数据
@@ -505,6 +510,7 @@ ProjectGLJ.prototype.freightCalc= function (glj,grossWeightCoe_n,dataMap,tfreigh
         freightIncreaseRate = scMathUtil.roundForObj(1+freightIncreaseRate/100,process);//(1+运距增加率%)
         unitFreight = scMathUtil.roundForObj(unitFreight,unitPirce);
         kmDistance = scMathUtil.roundForObj(kmDistance,unitPirce);
+        heightFee = scMathUtil.roundForObj(heightFee,unitPirce);
 
         let t = getPrice(unitFreight,kmDistance,conveyance,calcType,materialType,process);//单位运价×km运距
         t = scMathUtil.roundForObj(t*freightIncreaseRate,process);//单位运价×km运距×(1+运距增加率%)
@@ -519,12 +525,14 @@ ProjectGLJ.prototype.freightCalc= function (glj,grossWeightCoe_n,dataMap,tfreigh
         weightCoe = scMathUtil.roundForObj(weightCoe,unitPirce);
         t = scMathUtil.roundForObj(t*weightCoe,process);//(单位运价×km运距×(1+运距增加率%)+装卸费单价×装卸次数+其它费用)×单位毛重×加权系数
         sum = scMathUtil.roundForObj(sum + t,process);
+        heightFee = scMathUtil.roundForObj(heightFee*weightCoe,process);
+        height_sum = scMathUtil.roundForObj(height_sum + heightFee,process);
     }
     if(freightList.length == 0){//如果运费计算表没有数据,则读取输入的或单价文件的值
         let doc = dataMap['material']&&dataMap['material']['update']?dataMap['material']['update']:{};
         sum = doc['unitFreight']?doc['unitFreight']:glj.unit_price.unitFreight;
     }
-    return scMathUtil.roundForObj(sum,unitPirce);
+    return [scMathUtil.roundForObj(sum,unitPirce),scMathUtil.roundForObj(height_sum,unitPirce)];
 
 
     function getPrice(unitFreight,kmDistance,conveyance,calcType,materialType,process){
@@ -542,25 +550,31 @@ ProjectGLJ.prototype.priceCalc = function (glj,dataMap,tpriceList) {
     let unitPirce = getDecimal("glj.unitPrice");
     let unitPriceHasMix = getDecimal("glj.unitPriceHasMix");
     let original_price = 0;
+    let sumFeightFee = 0;
     let supplyList = [];
     let supplyLocation = "";
     let priceList = tpriceList?tpriceList:_.filter(this.datas.originalList,{"connect_key":gljUtil.getIndex(glj)});
     if(dataMap["price"] && dataMap["price"]["add"])  priceList = priceList.concat(dataMap["price"]["add"]); //把添加的加进去
     for(let p of priceList){
         let supplyPrice = p.supplyPrice ,coe = p.coe,supplyLocation=p.supplyLocation;
+        let heightFee = p.heightFee?p.heightFee:0;
         if(dataMap["price"] && dataMap["price"]["update"]){//覆盖更新的数据
             let t = dataMap["price"]["update"][p.ID];
             if(t && t["supplyPrice"]) supplyPrice =t["supplyPrice"];
             if(t && t["coe"]) coe =t["coe"];
             if(t && t["supplyLocation"]) supplyLocation = t["supplyLocation"];
+            if(t && t["heightFee"]) heightFee = t["heightFee"];
         }
         if(dataMap["price"] && dataMap["price"]["delete"]){//忽略删除的数据
             if(dataMap["price"]["delete"][p.ID]) continue;
         }
         supplyPrice = scMathUtil.roundForObj(supplyPrice,unitPirce);
         coe = scMathUtil.roundForObj(coe,unitPirce);
+        heightFee = scMathUtil.roundForObj(heightFee,unitPirce);
         let t_p = scMathUtil.roundForObj(supplyPrice *  coe,process);
+        let t_h = scMathUtil.roundForObj(heightFee *  coe,process);
         original_price=scMathUtil.roundForObj(original_price+t_p,process);
+        sumFeightFee = scMathUtil.roundForObj(sumFeightFee+t_h,process);
         supplyList.push(supplyLocation);
     }
     supplyLocation = supplyList.join(',');
@@ -569,7 +583,7 @@ ProjectGLJ.prototype.priceCalc = function (glj,dataMap,tpriceList) {
         original_price = doc['originalPrice']!==undefined?doc['originalPrice']:glj.unit_price.originalPrice;
         supplyLocation = doc['supplyLocation']!==undefined?doc['supplyLocation']:glj.unit_price.supplyLocation;
     }
-    return [scMathUtil.roundForObj(original_price,unitPriceHasMix),supplyLocation];
+    return [scMathUtil.roundForObj(original_price,unitPriceHasMix),supplyLocation,scMathUtil.roundForObj(sumFeightFee,unitPirce)];
 };
 
 
@@ -912,6 +926,7 @@ ProjectGLJ.prototype.calcEachFreightOrPrice = function (temp,type,priceMap) {//
     if(temp){
          if(type == "freight" && temp.conveyance !="自办运输") return null;
         let sum =0;
+        let heightFee = 0;
         let gljMap = {};
         let decimal = type == "freight"?getDecimal("glj.unitPrice"):getDecimal("glj.unitPriceHasMix");
         //因为材料计算的数据是保存在单价文件里的,有可能存在共享的情况,这样的话就不能用单价文件里的项目工料机ID来匹配,要用5大项匹配
@@ -926,18 +941,21 @@ ProjectGLJ.prototype.calcEachFreightOrPrice = function (temp,type,priceMap) {//
         }
         if(temp.rations) {
             for(let r of temp.rations){
-                sum = scMathUtil.roundForObj(sum + calcRation(r,gljMap[r.ID],pgljMap,priceMap),6);
+                let [tsum,thei] = calcRation(r,gljMap[r.ID],pgljMap,priceMap);
+                heightFee = scMathUtil.roundForObj(heightFee+thei,6);
+                sum = scMathUtil.roundForObj(sum + tsum,6);
             }
         }
         sum = scMathUtil.roundForObj(sum,decimal)+"";
-        if(type == "freight" && temp.unitFreight!= sum) return {ID:temp.ID,doc:{unitFreight:sum}};
-        if(type == "price" && temp.supplyPrice !=sum) return {ID:temp.ID,doc:{supplyPrice:sum}};
+        if(type == "freight" && temp.unitFreight!= sum) return {ID:temp.ID,doc:{unitFreight:sum,heightFee:heightFee}};
+        if(type == "price" && temp.supplyPrice !=sum) return {ID:temp.ID,doc:{supplyPrice:sum,heightFee:heightFee}}
     }
     return null;
 
 
     function calcRation(ration,gljs,pMap,priceMap){
         let result = 0;
+        let heightFee = 0;
         if(gljs){
             let processDecimal = getDecimal("process");
             let hightFeeRate = projectObj.project.projectGLJ.getHighlandFee(ration.feeType);//高原取费类别费率
@@ -960,8 +978,9 @@ ProjectGLJ.prototype.calcEachFreightOrPrice = function (temp,type,priceMap) {//
             let hs = scMathUtil.roundForObj(tt*hightFeeRate,processDecimal);//(人工定额消耗量*定额价*定额工程量+机械定额消耗量*定额价*定额工程量)*高原取费类别费率
             result = scMathUtil.roundForObj(as + result,processDecimal);
             result = scMathUtil.roundForObj(hs + result,processDecimal);
+            heightFee = hs;
         }
-        return  result;
+        return  [result,heightFee];
     }
 
 

+ 3 - 3
web/building_saas/main/js/models/ration_glj.js

@@ -538,10 +538,10 @@ let ration_glj = {
             }
             return node
         };
-        ration_glj.prototype.getGLJData = function (cb) {
+        ration_glj.prototype.getGLJData = function (url, cb) {
             let property = projectObj.project.projectInfo.property;
-            let engineerID = property.engineering_id;
-            CommonAjax.get('/rationGlj/getGLJData/'+engineerID, function (data) {
+            //let engineerID = property.engineering_id;
+            CommonAjax.get(url, function (data) {
                 //编办中有多单价设置
                 if(data.datas.priceProperties && data.datas.priceProperties.length > 0){
                     let tem = _.find(data.datas.priceProperties,{region:property.region,taxModel:parseInt(property.taxType)});

+ 1 - 1
web/building_saas/main/js/views/calc_base_view.js

@@ -58,7 +58,7 @@ let calcBaseView = {
                 allowResizeColumns: true
             };
             sheet.setColumnCount(headers.length);
-            sheet.setRowHeight(0, 40, GC.Spread.Sheets.SheetArea.colHeader);
+            sheet.setRowHeight(0, 20, GC.Spread.Sheets.SheetArea.colHeader);
             sheet.setColumnWidth(0, 20, GC.Spread.Sheets.SheetArea.rowHeader);
             for(let i = 0, len = headers.length; i < len; i++){
                 sheet.setValue(0, i, headers[i].name, GC.Spread.Sheets.SheetArea.colHeader);

+ 5 - 2
web/building_saas/main/js/views/fee_rate_view.js

@@ -12,7 +12,7 @@ var feeRateObject={
         header: [
             {headerName: "专业名称", headerWidth: 250, dataCode: "name", dataType: "String"},
             {headerName: "值%", headerWidth: 80, dataCode: "rate", dataType: "Number",hAlign: "right",decimalField:"feeRate"},
-            {headerName: "备注", headerWidth: 150, dataCode: "memo", dataType: "String"}
+            {headerName: "备注", headerWidth: 150, dataCode: "memo", dataType: "String", showHint: true}
         ],
         view: {
             lockColumns: [0]
@@ -33,7 +33,7 @@ var feeRateObject={
         header: [
             {headerName: "专业名称", headerWidth: 200, dataCode: "name", dataType: "String"},
             {headerName: "值%", headerWidth: 120, dataCode: "rate", dataType: "Number",hAlign: "right",decimalField:"feeRate"},
-            {headerName: "备注", dataCode: "memo", dataType: "String"}
+            {headerName: "备注", dataCode: "memo", dataType: "String", showHint: true}
         ],
         view: {
             comboBox: [],
@@ -158,6 +158,9 @@ var feeRateObject={
             if (setting.header[col].formatter) {
                 sheet.setFormatter(-1, col, setting.header[col].formatter, GC.Spread.Sheets.SheetArea.viewport);
             }
+            if (setting.header[col].showHint) {
+                sheet.getRange(-1, col, -1, 1).cellType(TREE_SHEET_HELPER.getTipCellType(setting));
+            }
             for (let row = 0; row < data.length; row++) {
                 let val = data[row][setting.header[col].dataCode];
                 if(val&&setting.header[col].dataType === "Number"){

+ 13 - 76
web/building_saas/main/js/views/glj_view.js

@@ -998,12 +998,10 @@ var gljOprObj = {
     },
     filterLibGLJSheetData: function () {
         let me = this;
-        let val = $("input[name='glj']:checked").val();
-        if (val == 'allGljs') {
-            me.gljLibSheetData = me.stdGLJ.concat(me.complementaryGLJs);
-        } else {
-            me.gljLibSheetData = me[val];
-        }
+        const selectLibID = $('#glj-lib-select').val();
+        me.gljLibSheetData = selectLibID === commonConstants.COMPLEMENTARY_LIB
+            ? me.complementaryGLJs
+            : me.stdGLJ;
         if ($('#actionType').val() == 'replace' || $('#actionType').val() == 'm_replace') {
             me.filterLibGLJByType();
         }else if($('#actionType').val() == 'addMix'){
@@ -1432,7 +1430,10 @@ var gljOprObj = {
         let zTree = $.fn.zTree.getZTreeObj("gljTree");
         let node = null;
         if (ID) node = zTree.getNodesByParam('ID', ID, null)[0];
-        if (!node) node = zTree.getNodeByTId('gljTree_1');
+        if (!node) {
+            node = zTree.getNodeByTId('gljTree_1');
+            ID = node.ID;
+        }
         zTree.selectNode(node);
         gljOprObj.gljCurTypeId = ID;
         gljOprObj.filterLibGLJSheetData();
@@ -1537,72 +1538,7 @@ var gljOprObj = {
 
 $(function () {
     $('#glj_tree_div').on('shown.bs.modal', function (e) {
-        if (gljOprObj.gljLibSpresd == undefined) {
-            gljOprObj.gljLibSpresd = sheetCommonObj.buildSheet($('#gljLibSheet')[0], gljOprObj.gljLibSheetSetting, gljOprObj.stdGLJ.length + gljOprObj.complementaryGLJs.length);
-            sheetCommonObj.spreadDefaultStyle(gljOprObj.gljLibSpresd);
-            gljOprObj.gljLibSpresd.bind(GC.Spread.Sheets.Events.ButtonClicked, gljOprObj.onButtonClick);
-            gljOprObj.gljLibSheet = gljOprObj.gljLibSpresd.getSheet(0);
-            gljOprObj.gljLibSheet.bind(GC.Spread.Sheets.Events.SelectionChanged, gljOprObj.onSelectionChanged);
-            gljOprObj.gljLibSheet.setColumnWidth(0, 20, GC.Spread.Sheets.SheetArea.rowHeader);
-            gljOprObj.gljLibSheet.options.isProtected = true;
-            gljOprObj.gljLibSheet.name('glj_lib');
-        }
-        gljOprObj.gljLibSheetData = gljOprObj.AllRecode;
-        let gljClass = 0, selectMap = {};
-        if ($('#actionType').val() == 'add' || $('#actionType').val() == 'insert' || $('#actionType').val() == 'insertEquipment') {//插入,添加
-            gljOprObj.GLJSelection = [];
-        } else if($('#actionType').val() =='m_replace' || $('#actionType').val() == 'replace'){//替换、批量替换
-            let selected = gljOprObj.sheetData[gljContextMenu.selectedRow];
-            let connect_key = gljOprObj.getIndex(selected, gljKeyArray);
-            gljOprObj.GLJSelection = [connect_key];
-            selectMap[connect_key] = true;
-            gljOprObj.filterLibGLJByType();
-        }else if($('#actionType').val() =='addMix'){//添加组成物
-            gljOprObj.GLJSelection = [];
-            projectGljObject.filterLibGLJForMixRatio();
-            /*selections = projectGljObject.mixRatioData;  添加组成物的时候先不选中
-             gljOprObj.GLJSelection = [];
-             for(let s of selections){
-             let s_key = gljOprObj.getIndex(s, gljKeyArray);
-             selectMap[s_key] = true;
-             gljOprObj.GLJSelection.push(s_key);
-             }*/
-        }
-        for(let item of gljOprObj.gljLibSheetData){
-            let item_key = gljOprObj.getIndex(item, gljLibKeyArray);
-            if(selectMap[item_key]){
-                item.select = 1 ;
-                gljClass = item.gljClass;
-            }
-        }
-        //替换,焦点定位至当前选中人材机
-        if($('#actionType').val() =='m_replace' || $('#actionType').val() == 'replace'){
-            gljOprObj.locateZTree(gljClass);
-            let selected = gljOprObj.sheetData[gljContextMenu.selectedRow];
-            let index = _.findIndex(gljOprObj.gljLibSheetData, {code: selected.code});
-            gljOprObj.gljLibSheet.showRow(index, GC.Spread.Sheets.VerticalPosition.center);
-            gljOprObj.gljLibSheet.setActiveCell(index, 0);
-            gljOprObj.initSelection({row: index});
-            gljOprObj.gljLibSpresd.focus(true);
-        } else if ($('#actionType').val() === 'insertEquipment') {//右键插入设备,人材机选择窗口,应默认固定到分类"养护管理设备"。
-            let locateClass = gljOprObj.treeData.std.find(function (stdClass) {
-                return stdClass.Name === '养护管理设备';
-            });
-            if (locateClass) {
-                gljClass = locateClass.ID;
-                gljOprObj.locateZTree(gljClass);
-                gljOprObj.gljLibSheet.showRow(0, GC.Spread.Sheets.VerticalPosition.top);
-                gljOprObj.gljLibSheet.setActiveCell(0, 0);
-                gljOprObj.initSelection({row: 0});
-            }
-        } else if ($('#actionType').val() === 'add') {
-            gljOprObj.locateZTree(null);
-            gljOprObj.gljLibSheet.showRow(0, GC.Spread.Sheets.VerticalPosition.top);
-            gljOprObj.gljLibSheet.setActiveCell(0, 0);
-            gljOprObj.initSelection({row: 0});
-        } else {
-            gljOprObj.showLibGLJSheetData();
-        }
+        gljContextMenu.initGLJSelectView();
     });
 
     $('#mreplace_next_div').on('shown.bs.modal', function (e) {
@@ -1629,11 +1565,12 @@ $(function () {
                 gljOprObj.initClassTree('comple', gljOprObj.treeData.comple, true);
             }
             gljOprObj.initSelection({row: 0});
-            //gljOprObj.gljLibSheetData = gljOprObj[val];
-            /*gljOprObj.filterLibGLJSheetData();
-             gljOprObj.showLibGLJSheetData();*/
         }
     });
+    // 更改选择库
+    $('#glj-lib-select').change(function () {
+        getGLJData('change', false);
+    })
     /*    //工料机搜索
      $('#gljSearchKeyword').change(function () {
      gljOprObj.filterLibGLJSheetData();

+ 115 - 18
web/building_saas/main/js/views/glj_view_contextMenu.js

@@ -370,13 +370,103 @@ var gljContextMenu = {
         }
         //controller.setTreeSelected(controller.tree.items[target.row]);
         return target.hitTestType === GC.Spread.Sheets.SheetArea.viewport || target.hitTestType === GC.Spread.Sheets.SheetArea.rowHeader;
+    },
+    initGLJSelectView: function () {
+        if (gljOprObj.gljLibSpresd == undefined) {
+            gljOprObj.gljLibSpresd = sheetCommonObj.buildSheet($('#gljLibSheet')[0], gljOprObj.gljLibSheetSetting, gljOprObj.stdGLJ.length + gljOprObj.complementaryGLJs.length);
+            sheetCommonObj.spreadDefaultStyle(gljOprObj.gljLibSpresd);
+            gljOprObj.gljLibSpresd.bind(GC.Spread.Sheets.Events.ButtonClicked, gljOprObj.onButtonClick);
+            gljOprObj.gljLibSheet = gljOprObj.gljLibSpresd.getSheet(0);
+            gljOprObj.gljLibSheet.bind(GC.Spread.Sheets.Events.SelectionChanged, gljOprObj.onSelectionChanged);
+            gljOprObj.gljLibSheet.setColumnWidth(0, 20, GC.Spread.Sheets.SheetArea.rowHeader);
+            gljOprObj.gljLibSheet.options.isProtected = true;
+            gljOprObj.gljLibSheet.name('glj_lib');
+        }
+        gljOprObj.gljLibSheetData = gljOprObj.AllRecode;
+        let gljClass = 0, selectMap = {};
+        if ($('#actionType').val() == 'add' || $('#actionType').val() == 'insert' || $('#actionType').val() == 'insertEquipment') {//插入,添加
+            gljOprObj.GLJSelection = [];
+        } else if($('#actionType').val() =='m_replace' || $('#actionType').val() == 'replace'){//替换、批量替换
+            let selected = gljOprObj.sheetData[gljContextMenu.selectedRow];
+            let connect_key = gljOprObj.getIndex(selected, gljKeyArray);
+            gljOprObj.GLJSelection = [connect_key];
+            selectMap[connect_key] = true;
+            gljOprObj.filterLibGLJByType();
+        }else if($('#actionType').val() =='addMix'){//添加组成物
+            gljOprObj.GLJSelection = [];
+            projectGljObject.filterLibGLJForMixRatio();
+        }
+        for(let item of gljOprObj.gljLibSheetData){
+            let item_key = gljOprObj.getIndex(item, gljLibKeyArray);
+            if(selectMap[item_key]){
+                item.select = 1 ;
+                gljClass = item.gljClass;
+            } else {
+                item.select = 0;
+            }
+        }
+        //替换,焦点定位至当前选中人材机
+        if($('#actionType').val() =='m_replace' || $('#actionType').val() == 'replace'){
+            gljOprObj.locateZTree(gljClass);
+            let selected = gljOprObj.sheetData[gljContextMenu.selectedRow];
+            let index = _.findIndex(gljOprObj.gljLibSheetData, {code: selected.code});
+            gljOprObj.gljLibSheet.showRow(index, GC.Spread.Sheets.VerticalPosition.center);
+            gljOprObj.gljLibSheet.setActiveCell(index, 0);
+            gljOprObj.initSelection({row: index});
+            gljOprObj.gljLibSpresd.focus(true);
+        } else if ($('#actionType').val() === 'insertEquipment') {//右键插入设备,人材机选择窗口,应默认固定到分类"养护管理设备"。
+            let locateClass = gljOprObj.treeData.std.find(function (stdClass) {
+                return stdClass.Name === '养护管理设备';
+            });
+            if (locateClass) {
+                gljClass = locateClass.ID;
+                gljOprObj.locateZTree(gljClass);
+                gljOprObj.gljLibSheet.showRow(0, GC.Spread.Sheets.VerticalPosition.top);
+                gljOprObj.gljLibSheet.setActiveCell(0, 0);
+                gljOprObj.initSelection({row: 0});
+            }
+        } else if ($('#actionType').val() === 'add') {
+            gljOprObj.locateZTree(null);
+            gljOprObj.gljLibSheet.showRow(0, GC.Spread.Sheets.VerticalPosition.top);
+            gljOprObj.gljLibSheet.setActiveCell(0, 0);
+            gljOprObj.initSelection({row: 0});
+        } else {
+            gljOprObj.showLibGLJSheetData();
+        }
+    }
+}
+
+function initLibOptions(libData) {
+    const html = libData.reduce((acc, lib) => acc += `<option ${lib.isDefault ? 'selected="selected"' : ''} value="${lib.gljLibId}">${lib.name}</option>`, '');
+    $('#glj-lib-select').html(html);
+}
+
+function getActionUrl(actionType) {
+    const rootUrl = `/rationGlj/getGLJData/${commonConstants.COMPILATION}`
+    switch (actionType) {
+        case 'add':
+        case 'addMix':
+        case 'insertEquipment':
+            return `${rootUrl}/0/true`;
+        case 'replace':
+        case 'm_replace':
+            const selected = gljOprObj.sheetData[gljContextMenu.selectedRow];
+            const gljLibId = selected.repositoryId || commonConstants.COMPLEMENTARY_LIB;
+            return `${rootUrl}/${gljLibId}/true`;
+        case 'change': // 更改选择库
+            const selectGLJLibID = $('#glj-lib-select').val();
+            return `${rootUrl}/${selectGLJLibID}/false`;
     }
 }
 
-function getGLJData(actionType) {
+function getGLJData(actionType, isInitial = true) {
+    const url = getActionUrl(actionType);
+    if (actionType === 'change') {
+        actionType = $('#actionType').val();
+    }
     $('#actionType').val(actionType);
     $.bootstrapLoading.start();
-    projectObj.project.ration_glj.getGLJData(function (result) {
+    projectObj.project.ration_glj.getGLJData(url, function (result) {
         // 目前只有浙江2015需要特殊处理处理
         if (gljOprObj.sortSelectViewGLJ) {
             gljOprObj.sortSelectViewGLJ(result.datas.stdGLJ);
@@ -385,9 +475,6 @@ function getGLJData(actionType) {
             result.datas.stdGLJ = _.sortBy(result.datas.stdGLJ, 'code');
             result.datas.complementaryGLJs = _.sortBy(result.datas.complementaryGLJs, 'code');
         }
-        gljOprObj.treeData = result.datas.treeData;
-        //zTreeHelper.createTree(result.datas.treeData, gljOprObj.gljTreeSetting, "gljTree", gljOprObj);
-        gljOprObj.initClassTree('std', gljOprObj.treeData.std);
         gljOprObj.stdGLJ=result.datas.stdGLJ;
         gljOprObj.complementaryGLJs=result.datas.complementaryGLJs;
         for(let compleGlj of gljOprObj.complementaryGLJs){
@@ -397,20 +484,30 @@ function getGLJData(actionType) {
         gljOprObj.AllRecode=gljOprObj.stdGLJ.concat(gljOprObj.complementaryGLJs);
         //gljOprObj.AllRecode=gljOprObj.stdGLJ;
         gljOprObj.distTypeTree=gljOprObj.getComboData(result.datas.distTypeTree);
-        $('#modalCon').width($(window).width()*0.5);
-        $("input[name='glj']").get(0).checked=true;
-        $.bootstrapLoading.end();
-        if(actionType == "m_replace"){
-            $('#glj_selected_conf').hide();
-            $('#replace_next_btn').show();
-        }else {
-            $('#glj_selected_conf').show();
-            $('#replace_next_btn').hide();
+        gljOprObj.treeData = result.datas.treeData;
+        if (gljOprObj.treeData.std.length) {
+            gljOprObj.initClassTree('std', gljOprObj.treeData.std, !isInitial);
+        } else if (gljOprObj.treeData.comple.length) {
+            gljOprObj.initClassTree('comple', gljOprObj.treeData.comple, !isInitial);
         }
-        $("#glj_tree_div").modal({show:true});
-        setTimeout(function(){
-            gljOprObj.gljLibSpresd?gljOprObj.gljLibSpresd.refresh():'';
-        }, 200);
+        if (isInitial) {
+            initLibOptions(result.datas.libData);
+            $('#modalCon').width($(window).width()*0.5);
+            if(actionType == "m_replace"){
+                $('#glj_selected_conf').hide();
+                $('#replace_next_btn').show();
+            }else {
+                $('#glj_selected_conf').show();
+                $('#replace_next_btn').hide();
+            }
+            $("#glj_tree_div").modal({show:true});
+            setTimeout(function(){
+                gljOprObj.gljLibSpresd?gljOprObj.gljLibSpresd.refresh():'';
+            }, 200);
+        } else {
+            gljContextMenu.initGLJSelectView();
+        }
+        $.bootstrapLoading.end();
     })
 }
 

+ 11 - 1
web/building_saas/main/js/views/importBills.js

@@ -94,7 +94,17 @@ const importBills = (function(){
             }
             //表格内的数据
             let depth = getDepth(code);
-            let data = {ID: uuid.v1(), NextSiblingID: -1, ParentID: -1, code: code, name: name, unit: unit, quantity: quantity, depth: depth};
+            let data = {
+                ID: uuid.v1(), 
+                NextSiblingID: -1, 
+                ParentID: -1, 
+                code: code, 
+                name: name, 
+                unit: unit, 
+                quantity: quantity, 
+                depth: depth,
+                unitPriceAnalysis: 1,
+            };
             let lastData = rst[rst.length - 1];
             //获取data的父节点链,成为兄弟节点,只能在父链里找前兄弟(不能跨父链)
             let parents = getParents(lastData);

+ 8 - 5
web/building_saas/main/js/views/project_glj_view.js

@@ -132,6 +132,7 @@ projectGljObject={
         $("#current-name").text(me.usedUnitPriceInfo.name);
         let usedCount = me.usedTenderList.length <= 0 ? 1 : me.usedTenderList.length;
         $("#used-project-count").text(usedCount);
+        $("#editUnitFile").attr("href",`/unitPrice/index/${me.usedUnitPriceInfo.id}`)
     },
     getUsedTenderInfo:function() {
         return "人材机单价的变化,将自动影响以下单位工程造价:<br>"+projectGljObject.usedTenderList.join("<br>");
@@ -315,9 +316,11 @@ projectGljObject={
             let style = gljOprObj.getSelStyle(true,{});
             me.projectGljSheet.setStyle(newSel.row, -1, style);
             let orow = oldSel.row==''||oldSel.row==-1?0:oldSel.row;
-            let tstyle = gljOprObj.getSelStyle(false,{},me.projectGljSheetData[orow].bgColour);
-            me.projectGljSheet.setStyle(orow, -1, tstyle);
-            me.projectGljRowChang();
+            if(me.projectGljSheetData[orow]){
+              let tstyle = gljOprObj.getSelStyle(false,{},me.projectGljSheetData[orow].bgColour);
+              me.projectGljSheet.setStyle(orow, -1, tstyle);
+              me.projectGljRowChang();
+            }
         }else{
           me.projectGljSheet.repaint();
         }
@@ -881,10 +884,10 @@ projectGljObject={
         if(info.newValue === undefined ){
             return;
         }
-        if (value&&!me.checkData(col,setting,value)) {
+        if(value && !me.checkData(col,setting,value)) {
             alert('输入的数据类型不对,请重新输入!');
             info.sheetName =="materialTreeSheet"?me.materialTreeController.refreshTreeNode([me.materialTree.selected]):me.refreshProjectGljRow(row);
-            return ;
+            return;
         }
         let callback=function (impactList) {
             info.sheet.suspendPaint();

+ 18 - 8
web/building_saas/main/js/views/project_info.js

@@ -3,26 +3,36 @@
  */
 
 var projectInfoObj = {
+    getSubShareInfo: function (proj) {
+        const { allowCopy, allowCooperate } = proj.shareState;
+        let str = '(';
+        if (allowCopy) {
+            str += '可拷贝 ';
+        }
+        if (allowCooperate) {
+            if (allowCopy) {
+                str += ' ';
+            }
+            str += '可编辑';
+        }
+        str += ')';
+        return str === '()' ? '' : str;
+    },
     getFullPathHtml: function (proj) {
         let fullPath = [], i, pm = '<span class="text-truncate"><a href="/pm">项目管理</a></span>', angleRight = '<span class="text-truncate"><i class="fa fa-angle-right fa-fw"></i></span>';
         if (proj) {
             let pathArr = proj.fullPath;
             let projectName = pathArr[pathArr.length -2] || '',
                 folderName = pathArr[pathArr.length -3] || '';
+            const subShareInfo = projectInfoObj.getSubShareInfo(proj);
+            const receiveTip = `<span class="alert alert-success py-0 px-2 m-0" id="share-info"><i class="fa fa-share-alt"></i>来自 ${proj.owner && proj.owner.real_name || ''} 的分享${subShareInfo}</span>`;
             let newHtml = `   <span data-toggle="tooltip" data-placement="bottom" data-original-title="${folderName}"><i class="fa fa-folder-open-o"></i>...</span>
                 <span class="text-muted px-1">\</span>
                 <span data-toggle="tooltip" data-placement="bottom" data-original-title="${projectName}"><i class="fa fa-cubes"></i>...</span>
                 <span class="text-muted px-1">\</span>
                  <span><i class="fa fa-sticky-note-o"></i></span>
                 <span class="text-truncate"  data-toggle="tooltip" data-placement="bottom" data-original-title="${proj.name}">&nbsp;${proj.name}</span>
-                ${projectReadOnly ?
-                '<span data-toggle="tooltip" data-placement="bottom" data-original-title="当前的工程状态为“只读”,如果要进行编辑,请在项目管理-分享界面,使用“拷贝工程”功能。">(只读)</span>' 
-                : ''}
-                ${projectCooperate ? 
-                '<span data-toggle="tooltip" data-placement="bottom" data-original-title="当前的工程状态为“协作”,可直接编辑分享人的原始数据。">(协作)</span>'
-                : ''}
-                ${projectReadOnly || projectCooperate ? '' : '<span><a id="init-share" class="pl-2" href="javascript:;"><i class="fa fa-share-alt" aria-hidden="true"></i> 分享</a></span>'}
-                `;
+                ${projectReadOnly || projectCooperate ? receiveTip : `<span id="share-tip" class="ml-2" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="${proj.shareTip}"><a id="init-share" href="javascript:;" class="btn btn-xs btn-primary"><i class="fa fa-share-alt"></i> 分享</a></span>`}`;
             fullPath.push(newHtml);
 
         }

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

@@ -1168,7 +1168,7 @@ var projectObj = {
 
     loadMainSpreadContextMenu: function () {
         var project = this.project, spread = this.mainSpread, controller = this.mainController;
-        let insertBillsName = project.projectInfo.property && project.projectInfo.property.valuationType == "bill"?"插入项目节":"插入清单";//右键“插入清单”改文字为“插入项目节”,工程量清单中保持不变。
+        let insertBillsName = project.projectInfo.property && project.projectInfo.property.valuationType == commonConstants.ValuationType.BUDGET?"插入项目节":"插入清单";//右键“插入清单”改文字为“插入项目节”,工程量清单中保持不变。
             $.contextMenu({
             selector: '#billsSpread',
             selectableSubMenu: true,
@@ -3295,7 +3295,7 @@ function changeCalcBaseFeeRate(toggle) {
         $('#normalHeader').show();
         $('#calcBaseFeeRate').find('.modal-title').text('计算基数选择').show();
         $('#calcBaseExp').remove();
-        let $textarea = $('<textarea>').attr('id', 'calcBaseExp').prop('rows', 3).addClass('form-control').css('resize', 'none');
+        let $textarea = $('<textarea>').attr('id', 'calcBaseExp').prop('rows', 2).addClass('form-control').css('resize', 'none');
         $('#expArea').prepend($textarea);
     }
     else if(toggle === 'feeRate'){
@@ -3311,7 +3311,7 @@ function changeCalcBaseFeeRate(toggle) {
         $('#calcBaseFeeRate').find('.modal-body').find('button:first').show();
         $('#calcBaseFeeRate').find('.modal-body').find('ul:first').show();
         $('#calcBaseExp').remove();
-        let $textarea = $('<textarea>').attr('id', 'calcBaseExp').prop('rows', 3).addClass('form-control').css('resize', 'none');
+        let $textarea = $('<textarea>').attr('id', 'calcBaseExp').prop('rows', 2).addClass('form-control').css('resize', 'none');
         $('#expArea').prepend($textarea);
     }
 }

+ 3 - 0
web/building_saas/main/js/views/std_billsGuidance_lib.js

@@ -367,6 +367,9 @@ const billsGuidance = (function () {
                 stdData.flags = [{flag : stdNode.data.fixedFlag, fieldName : 'fixed'}];
                 stdData.flagsIndex = {fixed: {fieldName: 'fixed', flag: stdNode.data.fixedFlag}};   //前端用
             }
+            if (projectObj.project.property.valuationType === commonConstants.ValuationType.BOQ) {
+                stdData.unitPriceAnalysis = 1;
+            }
             return stdData;
         }
         //从同层节点中获取更新数据

+ 169 - 0
web/building_saas/unit_price_file/index.html

@@ -0,0 +1,169 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+    <meta http-equiv="x-ua-compatible" content="ie=edge">
+    <title>纵横公路养护云造价</title>
+
+
+    <link rel="stylesheet" href="/lib/jquery-ui/jquery-ui.css" type="text/css">
+    <link rel="stylesheet" href="/lib/bootstrap/css/bootstrap.min.css">
+    <link rel="stylesheet" href="/lib/bootstrap/css/bootstrap-submenu.css">
+    <link rel="stylesheet" href="/lib/spreadjs/sheets/css/gc.spread.sheets.sc.css" type="text/css">
+    <link rel="stylesheet" href="/web/building_saas/css/main.css">
+    <link rel="stylesheet" href="/web/building_saas/css/custom.css">
+    <link rel="stylesheet" href="/lib/font-awesome/font-awesome.min.css">
+    <link rel="stylesheet" href="/lib/jquery-contextmenu/jquery.contextMenu.css" type="text/css">
+    <link rel="stylesheet" href="/lib/jquery-editable-select/jquery.editable-select.min.css" type="text/css">
+    <!--zTree-->
+    <link rel="stylesheet" href="/lib/ztree/css/zTreeStyle.css" type="text/css">
+    <!--SpreadJs-->
+   <!-- <link rel="stylesheet" href="/lib/jquery-ui/jquery-ui.css" type="text/css">
+    <link rel="stylesheet" href="/lib/spreadjs/sheets/css/gc.spread.sheets.sc.css" type="text/css">-->
+    <link rel="stylesheet" href="/lib/spreadjs/views/gc.spread.views.dataview.10.0.0.css">
+    <!-- jquery.contextmenu -->
+   <!-- <link rel="stylesheet" href="/lib/jquery-contextmenu/jquery.contextMenu.css" type="text/css">-->
+
+    <link rel="shortcut icon" href="/web/building_saas/css/favicon.ico">
+    <link rel="icon" type="image/gif" href="/web/building_saas/css/animated_favicon1.gif">
+    <style type="text/css">
+        .ztree * {
+            font-family: Calibri;
+            font-size: 0.9rem;
+        }
+    </style>
+
+</head>
+<script type="text/javascript">
+  let unitPriceList = JSON.parse(`<%- unitpriceList %>`);
+  let gljTypeMap = JSON.parse(`<%- gljTypeMap %>`);
+  let mixRatioMap = JSON.parse(`<%- mixRatioMap %>`);
+</script>
+<body oncontextmenu="return false;">  <!--屏蔽input鼠标右键-->
+<!--<div id="toolToastWrap" style="left: 20px; right: 30px; position: fixed; z-index: 10001; top: 100px;">
+    <div id="toolToast" class="toolToast">
+        <span id="tool-toast-content">右键不支持粘贴外部内容,请使用Ctrl+V粘贴。<span id="toolToastBtn">我知道了</span></span>
+    </div>
+</div>-->
+
+    <div class="header">
+         <div class="top-msg clearfix">
+            <div class="alert alert-warning alert-dismissible" role="alert" id="notify" style="display: none">
+                <button type="button" class="close" aria-label="Close" onclick="$('#notify').hide();">
+                  <span aria-hidden="true">&times;</span>
+                </button>
+                <strong id="message"></strong>-
+            </div>
+        </div>
+        <nav class="navbar navbar-expand-lg p-0 d-flex <%= versionName.includes('免费') ? 'free-version' : 'pro-version' %>">
+          <div class="unit_price_header header-logo ">
+            <h5>单价文件编辑器</h5>
+          </div>
+          <div class="navbar-text navbar-crumb px-1 mr-auto" id="fullpath">   
+            <span class="text-muted px-1"></span>
+            <span data-toggle="tooltip" data-placement="bottom" data-original-title="<%= rootProjectName%>"><i class="fa fa-cubes"></i>...</span>
+            <span class="text-muted px-1"></span>
+             <span><i class="fa fa-puzzle-piece"></i></span>
+            <span class="text-truncate" data-toggle="tooltip" data-placement="bottom" data-original-title="<%= unitFileName%>">&nbsp;<%= unitFileName%></span>
+            &nbsp;(<span class="a_color" data-toggle="tooltip" id="pop-used-list"  style="float: none;" data-original-title="" title="<%= usedTenderString%>">与<span id="used-project-count" style="float: none;">1</span>个单位工程同步</span>)
+          </div>
+        </nav>
+    </div>
+    <div class="main">
+        <div class="content" style="margin-left: 0px;">
+          <div class="tab-content">
+              <!--造价书-->
+              <div class="container-fluid">
+                  <div class="row" id="mainRow">
+                      <!--col-lg-12 p-0-->
+                      <div class="main-content" style="width: 100%; display: inline-block" id="main">
+                          <div class="top-content" id="top_div" style="overflow:hidden;">
+                              <div class="main-data-top" id="mainSpread"></div>
+                          </div>
+                          <div class="resize-y" id="mainVerticalResize"></div>
+                          <div class="bottom-content" id="bottom_div">
+                              <ul class="nav nav-tabs" role="tablist" id="bottom_div_ul">  
+                                  <li class="nav-item" id="GLJ_div">
+                                      <a class="nav-link sub-item active" id="linkGLJ" data-toggle="tab" href="#subSpread" role="tab">组成物计算</a>
+                                  </li>                                
+                              </ul>
+                              <!-- Tab panes -->
+                              <div class="tab-content" id="tabCon">
+                                  <div class="tab-pane active" id="subItems" role="tabpanel">
+                                     <div class="main-data-bottom ovf-hidden" id="subSpread" tabindex="0"></div>
+                                  </div>
+                              </div>
+                          </div>
+                      </div>
+                      </div>
+                  </div>
+              </div>
+            </div>
+
+
+        </div>
+    </div>
+   
+
+   
+ 
+   
+    <img src="/web/dest/css/img/folder_open.png" id="folder_open_pic" style="display: none">
+    <img src="/web/dest/css/img/folder_close.png" id="folder_close_pic" style="display: none">
+    <img src="/web/dest/css/img/project.png" id="proj_pic" style="display: none">
+    <img src="/web/dest/css/img/engineering.png" id="eng_pic" style="display: none">
+    <img src="/web/dest/css/img/tender.png" id="tender_pic" style="display: none">
+
+    <img src="/web/dest/css/img/blockLib.png" id="blockLib_pic" style="display: none">
+    <img src="/web/dest/css/img/folder_open.png" id="folder_pic" style="display: none">
+    <img src="/web/dest/css/img/tender.png" id="block_pic" style="display: none">
+
+        <!-- JS. -->
+    <script src="/lib/jquery/jquery-3.2.1.min.js"></script>
+    <script type="text/javascript" src="/lib/jquery-ui/jquery-ui.min.js"></script>
+    <script src = "/lib/spreadjs/sheets/gc.spread.sheets.all.11.1.2.min.js"></script>
+    <script src="/lib/spreadjs/sheets/interop/gc.spread.excelio.11.1.2.min.js"></script>
+    <script>GC.Spread.Sheets.LicenseKey =  '<%- LicenseKey %>';</script>
+    <script type="text/javascript" src="/lib/jquery-ui/jquery-ui-datepickerCN.js"></script>
+    <script type="text/javascript" src="/lib/jquery-contextmenu/jquery.contextMenu.js"></script>
+    <script type="text/javascript" src="/lib/jquery-contextmenu/jquery.ui.position.js"></script>
+    <script src="/lib/spreadjs/views/gc.spread.views.dataview.10.0.0.min.js" type="text/javascript"></script>
+    <script type="text/javascript" src="/lib/ztree/jquery.ztree.core.js"></script>
+    <script type="text/javascript" src="/lib/ztree/jquery.ztree.excheck.js"></script>
+    <!--<script src="/lib/spreadjs/views/common/gc.spread.common.10.0.0.min.js" type="text/javascript"></script>-->
+    <script src="/lib/spreadjs/views/plugins/gc.spread.views.gridlayout.10.0.0.min.js" type="text/javascript"></script>
+    <script src="/lib/js-xlsx/xlsx.core.min.js"></script>
+    <script src="/lib/lz-string/lz-string.min.js"></script>
+    <script type="text/javascript" src="/lib/jspdf/jspdf.min.js"></script>
+    <!-- inject:js -->
+    <script src="/lib/popper/popper.min.js"></script>
+    <script src="/lib/bootstrap/bootstrap.min.js"></script>
+    <script src="/lib/bootstrap/bootstrap-submenu.js"></script>
+    <script type="text/javascript" src="/web/building_saas/js/moment.min.js"></script>
+    <script type="text/javascript" src="/web/building_saas/js/message.js"></script>
+    <script type="text/javascript" src="/public/web/scMathUtil.js"></script>
+    <script type="text/javascript" src="/public/web/gljUtil.js"></script>
+    <script type="text/javascript" src="/public/web/PerfectLoad.js"></script>
+    <script type="text/javascript" src="/lib/lodash/lodash.js"></script>
+    <script type="text/javascript" src="/public/web/commonAlert.js"></script>
+    <script type="text/javascript" src="/public/web/headerOpr.js"></script>
+    <script type="text/javascript" src="/public/web/common_ajax.js"></script>
+    <script type="text/javascript" src="/public/common_util.js"></script>
+    <script src="/public/common_constants.js"></script>
+    <script type="text/javascript" src="/lib/jquery-editable-select/jquery.editable-select.min.js"></script>
+    <script type="text/javascript" src="/public/web/tree_sheet/tree_sheet_helper.js"></script>
+    <script type="text/javascript" src="/public/web/sheet/sheet_data_helper.js"></script>
+    <script type="text/javascript" src="/public/web/sheet/sheet_common.js"></script>
+
+
+
+    <script type="text/javascript" src="/web/building_saas/unit_price_file/index.js"></script>
+    <!-- endinject -->
+
+
+        
+   
+</body>
+</html>

+ 293 - 0
web/building_saas/unit_price_file/index.js

@@ -0,0 +1,293 @@
+
+let unitPriceObj = {
+  unitPriceMap:{},
+  setUntiPriceMap:function(){
+    for(let u of unitPriceList){
+      this.unitPriceMap[gljUtil.getIndex(u)] = u;
+    }
+  },
+  mainSpread:null,
+  mainSetting:{
+    header: [
+        {headerName: "编号", headerWidth: 80, dataCode: "code", dataType: "String"},
+        {headerName: "名称", headerWidth: 160, dataCode: "name", dataType: "String"},
+        {headerName: "单位", headerWidth: 45, dataCode: "unit", hAlign: "center", dataType: "String"},
+        {headerName: "规格", headerWidth: 120, dataCode: "specs", hAlign: "left", dataType: "String"},
+        {headerName: "类型", headerWidth: 45, dataCode: "short_name", hAlign: "center", dataType: "String"},
+        {headerName: "定额价", headerWidth: 70, dataCode: "basePrice", hAlign: "right", dataType: "Number",validator:"number"},//decimalField:'glj.unitPrice',
+        {headerName: "预算价", headerWidth: 70, dataCode: "marketPrice", hAlign: "right", dataType: "Number",validator:"number"},//,decimalField:"glj.unitPrice"
+        {headerName: "是否新增", headerWidth: 50, dataCode: "is_add", hAlign: "center", dataType: "String",cellType:'checkBox'}
+    ],
+    view: {
+        lockColumns: ["code","name","specs","unit","short_name","basePrice","is_add"],
+        colHeaderHeight:36
+    },
+    getStyle:function (data,row,activeRow) {
+      if(row == activeRow){//选中黄色显示
+          return {backColor:"#FFFACD"};
+      }
+      return null;
+    }
+  },
+  subSpread:null,
+  subSetting:{
+    header:[
+        {headerName: "编号", headerWidth: 80, dataCode: "code", dataType: "String"},
+        {headerName: "名称", headerWidth: 240, dataCode: "name", dataType: "String"},
+        {headerName: "规格", headerWidth: 190, dataCode: "specs", dataType: "String"},
+        {headerName: "单位", headerWidth: 45, dataCode: "unit", hAlign: "center", dataType: "String"},
+        {headerName: "类型", headerWidth: 45, dataCode: "short_name", hAlign: "center", dataType: "String"},
+        {headerName: "定额价", headerWidth: 80, dataCode: "basePrice", hAlign: "right", dataType: "Number",validator:"number"},//,decimalField:'glj.unitPrice'
+        {headerName: "预算价", headerWidth: 80, dataCode: "marketPrice", hAlign: "right", dataType: "Number",validator:"number"},//,decimalField:"glj.unitPrice"
+        {headerName: "消耗量", headerWidth: 80, dataCode: "consumption", hAlign: "right", dataType: "Number",validator:"number",tofix:3}
+    ],
+    view: {
+        lockColumns: [0,1,2,3,4,5,6,7],
+        rowHeaderWidth: 25
+    }
+  },
+  initMainSpread:function () {
+    if(this.mainSpread) return this.mainSpread.refresh();
+    this.mainSpread = SheetDataHelper.createNewSpread($("#mainSpread")[0]);
+    sheetCommonObj.spreadDefaultStyle(this.mainSpread);
+    this.mainSheet = this.mainSpread.getSheet(0);
+    sheetCommonObj.initSheet(this.mainSheet, this.mainSetting, 30);
+    this.mainSheet.bind(GC.Spread.Sheets.Events.SelectionChanged,this.onMainSelectionChange);
+    this.mainSpread.bind(GC.Spread.Sheets.Events.RangeChanged, this.onMainRangeChange);
+    this.mainSheet.bind(GC.Spread.Sheets.Events.ValueChanged, this.onMainValueChange);
+    // this.sheet.bind(GC.Spread.Sheets.Events.EditStarting,this.onElectrovalenceEditStarting);
+
+    /* if(projectReadOnly){
+        disableSpread(this.spread);
+    } */
+  },
+  showMainDatas:function(){
+    unitPriceList = gljUtil.sortProjectGLJ(unitPriceList);
+    this.setData(unitPriceList);
+    let sel = this.mainSheet.getSelections()[0];
+    let oldData = sel.row<unitPriceList.length?unitPriceList[sel.row]:"";
+    sheetCommonObj.showData(this.mainSheet, this.mainSetting,unitPriceList);
+    this.mainSheet.setRowCount(unitPriceList.length);
+    sel.row =  oldData?_.findIndex(unitPriceList,{'id':oldData.id}):sel.row ;
+    this.mainSheet.setSelection(sel.row==-1?0:sel.row,sel.col,sel.rowCount,sel.colCount);
+  
+  },
+  getShortNameByType : function (type) {
+    return gljTypeMap["typeId" + type]?gljTypeMap["typeId" + type].shortName:'';
+  },
+  setData:function(list){
+    for(let l of list){
+      l.bgColour = "white";
+      l.basePrice = this.getPrice('base_price',l);
+      l.marketPrice = this.getPrice('market_price',l);
+      l.short_name = this.getShortNameByType(l.type);
+      if(l.base_price == l.market_price){//如果定额价等于市场价时,改底色。 优先度低于有组成物时的底色
+        l.bgColour = "#C4CAFB";
+      }
+      let lindex = gljUtil.getIndex(l);
+      if (gljUtil.notEditType.indexOf(l.type) >= 0 && mixRatioMap[lindex] && mixRatioMap[lindex].length>0) {//有组成物时
+        l.bgColour = "#E0E0E0";
+      }
+      if(gljUtil.isConcreteType(l.type)) l.bgColour = "#E0E0E0";//混凝土、砂浆、配合比的底色显示为 灰色#E0E0E0,灰色底色提醒用户不可修改。
+
+    }
+  },
+  getSelectedUnitPrice:function () {
+    let me = this,data = null;
+    let sheet = me.mainSpread.getActiveSheet();
+    let sel = sheet.getSelections()[0];
+        let srow = sel.row == -1||sel.row == ""?0:sel.row;
+        if(unitPriceList.length>srow){
+            data = unitPriceList[srow];
+        }
+    return data;
+  },
+  onMainSelectionChange:function(sender,args){
+    let me = unitPriceObj;
+    let newSel = args.newSelections[0];
+    let oldSel = args.oldSelections?args.oldSelections[0]:{};
+    args.sheet.suspendPaint();
+    args.sheet.suspendEvent();
+    if(newSel.row != oldSel.row){
+      let style = me.getSelStyle(true,{});
+      args.sheet.setStyle(newSel.row, -1, style);
+      let orow = oldSel.row==''||oldSel.row==-1?0:oldSel.row;
+      if(unitPriceList[orow]){
+        let tstyle = me.getSelStyle(false,{},unitPriceList[orow].bgColour);
+        args.sheet.setStyle(orow, -1, tstyle);
+        me.showSubDatas();
+      }
+    }else{
+      args.sheet.repaint();
+    }
+    args.sheet.resumeEvent();
+    args.sheet.resumePaint();
+
+  },
+  onMainValueChange:function(e,info){
+    let me = unitPriceObj;
+    let value = info.newValue;
+    if(info.newValue === undefined){
+      return;
+    }
+    if(value && !sheetCommonObj.checkData(info.col,me.mainSetting,value)) {
+      alert('输入的数据类型不对,请重新输入!');
+      return me.showMainDatas();
+    }
+    me.batchUpdateUnitPrice([{row:info.row,col:info.col,value:value}]);
+
+  },
+  onMainRangeChange:function(sender,info){
+    let me = unitPriceObj;
+    let canChange = true;
+    for(let c of info.changedCells){
+      let value=  info.sheet.getCell(c.row, c.col).text();
+      changeInfo.push({row:c.row,col:c.col,value:value});
+      if (!sheetCommonObj.checkData(c.col,me.mainSetting,value)) {
+          alert('输入的数据类型不对,请重新输入!');
+          canChange = false;
+          break;
+      }
+    }
+    if(canChange == false) return me.showMainDatas();
+    me.batchUpdateUnitPrice(changeInfo);
+  },
+  batchUpdateUnitPrice:async function(changeInfo){
+    let me = unitPriceObj;
+    let updateData = [];
+    let newValueMap = {};
+    let refreshList = [];
+    try {
+      for(let ci of changeInfo){
+        let dataCode = me.mainSetting.header[ci.col].dataCode;
+        let recode = unitPriceList[ci.row];
+        if(dataCode=='basePrice'||dataCode=='marketPrice'){
+            let editField = dataCode === 'basePrice'?"base_price":"market_price";
+            let newValue = ci.value;
+            if(recode && recode[editField]!=newValue){
+                newValue= scMathUtil.roundForObj(ci.value,3);
+                updateData.push({unit_price: recode, field: editField, newval: newValue});
+                newValueMap[recode.id]={field:editField,value:newValue};
+                refreshList.push(recode);
+            }
+        }
+      }
+      if(updateData.length > 0){
+        $.bootstrapLoading.start();
+        let result = await ajaxPost("/glj/batchUpdatePrices",updateData);
+        for(let r of refreshList){
+           r[newValueMap[r.id].field] = newValueMap[r.id].value;
+        }
+        for(let r of result){
+          let pdata = r.updateOne.filter;
+          let set = r.updateOne.update.$set;
+          for(let skey in set){
+              let pindex = gljUtil.getIndex(pdata);
+              me.unitPriceMap[pindex][skey] = set[skey];
+          }
+        }
+      }
+    } catch (error) {
+        alert(error);
+    }
+    $.bootstrapLoading.end();
+    me.showMainDatas();
+
+  },
+
+  initSubSpread:function () {
+    if(this.subSpread) return this.subSpread.refresh();
+    this.subSpread = SheetDataHelper.createNewSpread($("#subSpread")[0]);
+    sheetCommonObj.spreadDefaultStyle(this.subSpread);
+    this.subSheet = this.subSpread.getSheet(0);
+    sheetCommonObj.initSheet(this.subSheet, this.subSetting, 30);
+    // this.sheet.bind(GC.Spread.Sheets.Events.SelectionChanged,this.onElectrovalenceSelectionChange);
+    // this.sheet.bind(GC.Spread.Sheets.Events.ValueChanged, this.onElectrovalenceValueChange);
+    // this.sheet.bind(GC.Spread.Sheets.Events.EditStarting,this.onElectrovalenceEditStarting);
+
+    /* if(projectReadOnly){
+        disableSpread(this.spread);
+    } */
+  },
+  showSubDatas:function(){
+    let parentData = this.getSelectedUnitPrice();
+    this.mixRatioList = mixRatioMap[gljUtil.getIndex(parentData)];
+    this.mixRatioList = this.mixRatioList?this.mixRatioList:[];
+    this.setMixRatioData(this.mixRatioList);
+    let sel = this.subSheet.getSelections()[0];
+    this.subSheet.setRowCount(0);
+    sheetCommonObj.showData(this.subSheet, this.subSetting,this.mixRatioList);
+    this.subSheet.setRowCount(this.mixRatioList.length);
+    this.subSheet.setSelection(sel.row==-1?0:sel.row,sel.col,sel.rowCount,sel.colCount);
+  },
+  setMixRatioData:function(mixRatioList){
+    for(let m of mixRatioList){
+      m.short_name = this.getShortNameByType(m.type);
+      let mu = this.unitPriceMap[gljUtil.getIndex(m)];
+      if(mu){
+        m.basePrice = this.getPrice("base_price",mu);
+        m.marketPrice = this.getPrice("market_price",mu);
+      }else{
+        console.log("组成物的单价信息未找到---"+m.code);
+      }
+    }
+  },
+  getPrice:function(pricefield,unitprice){
+    let quantity = 3;
+    let unitPriceHasMix = 2;
+    let unitPrice = 3;
+    let process_decimal = 6;
+    let uIndex = gljUtil.getIndex(unitprice);
+    if(mixRatioMap[uIndex] && mixRatioMap[uIndex].length > 0){
+      let total = unitprice[pricefield];
+      if(pricefield == "market_price"){
+        total = 0;
+        for(let m of mixRatioMap[uIndex]){
+          let mu = unitPriceObj.unitPriceMap[gljUtil.getIndex(m)];
+          let price_m =  unitPriceObj.getPrice(pricefield,mu);
+          let temP = scMathUtil.roundForObj(price_m * scMathUtil.roundForObj(m.consumption,quantity),process_decimal);
+          total = scMathUtil.roundForObj(temP+total,process_decimal);
+        }
+      }
+      return scMathUtil.roundForObj(unitprice[pricefield],unitPriceHasMix);
+    }else{
+      return scMathUtil.roundForObj(unitprice[pricefield],unitPrice);
+    }
+  },
+  getSelStyle: function (selected,settingStyle,rcolor) {
+    let style = new GC.Spread.Sheets.Style();
+    if(settingStyle){
+        for(let key in settingStyle){
+            style[key] = settingStyle[key];
+        }
+    }
+    style.borderLeft = new GC.Spread.Sheets.LineBorder("#D4D4D4", GC.Spread.Sheets.LineStyle.thin);
+    style.borderTop = new GC.Spread.Sheets.LineBorder("#D4D4D4", GC.Spread.Sheets.LineStyle.thin);
+    style.borderRight = new GC.Spread.Sheets.LineBorder("#D4D4D4", GC.Spread.Sheets.LineStyle.thin);
+    style.borderBottom = new GC.Spread.Sheets.LineBorder("#D4D4D4", GC.Spread.Sheets.LineStyle.thin);
+    let selectedColor = "#FFFACD",
+        recColor = rcolor?rcolor:'White';
+    style.backColor = selected ? selectedColor : recColor;
+    return style;
+  },
+}
+
+
+
+function initPageHeight(){
+  let headerHeight = $(".header").height();
+  $(".main-data-top").height($(window).height()*0.6-headerHeight);
+  $(".main-data-bottom").height($(window).height()-headerHeight-$(".main-data-top").height()-$(".nav-item").height());
+}
+function initPage(){
+  $('[data-toggle="tooltip"]').tooltip({html: true});
+  initPageHeight();
+  unitPriceObj.initMainSpread();
+  unitPriceObj.initSubSpread();
+  unitPriceObj.showMainDatas();
+}
+
+unitPriceObj.setUntiPriceMap();
+initPage();
+$(window).resize(initPage);
+

+ 25 - 0
web/common/components/share/index.js

@@ -261,6 +261,7 @@ const SHARE_TO = (() => {
                     initContactsView(rst.contacts)
                 }
                 initSharedView(curSharedUsers);
+                refreshShareTip(curSharedUsers);
                 refreshTreeView();
             }
         } catch (err) {
@@ -285,6 +286,30 @@ const SHARE_TO = (() => {
         }
     }
 
+    // 刷新造价书的分享按钮tooltip提示
+    function refreshShareTip(sharedUsers) {
+        const $shareTip = $('#share-tip');
+        if (!$shareTip) {
+            return;
+        }
+        const limit = 2;
+        const count = sharedUsers.length;
+        const users = sharedUsers.slice(0, 2);
+        const tip = users.reduce((acc, user, index) => {
+            if (index === 0) {
+                acc += '已分享给';
+                acc += user.real_name;
+            } else {
+                acc += ` ${user.real_name}`;
+            }
+            if (index === users.length - 1 && count > limit) {
+                acc += `等${count}人`;
+            }
+            return acc;
+        }, '');
+        $shareTip.attr('data-original-title', tip);
+    }
+
     // 初始化分享给的页面
     async function initModal(projectID) {
         try {

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

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

+ 2 - 2
web/over_write/js/nongcun_2020.js

@@ -7,7 +7,7 @@
          * 获取操作<<农村公路养护预算费用库>>时的节点片段
          * 片段为主树根节点(与其他费用定额的添加逻辑一致)
          */
-        budeget() {
+        budget() {
             return { parent: null, mainTreeFragment: projectObj.project.Bills.tree.roots };
         },
         /**
@@ -67,7 +67,7 @@
     function getFragmentFunction() {
         const selLibText = $('#stdBillsGuidanceLibSelect').text();
         if (/农村公路养护预算费用/.test(selLibText)) {
-            return functionMap.budeget;
+            return functionMap.budget;
         } else if (/农村公路小修工程量清单/.test(selLibText)) {
             return functionMap.minorRepair;
         } else if (/农村公路养护工程工程量清单/.test(selLibText)) {