Browse Source

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

zhangweicheng 7 years ago
parent
commit
7749d0a77a

+ 7 - 7
modules/main/facade/labour_coe_facade.js

@@ -87,22 +87,22 @@ function getData(projectID, callback) {
 // needUpdateDatas: [{ID: 5, value: 2.87}, {ID: 13, value: 2.91}]
 function save (data, callback) {
     let updateArr = [];
-    let datas = JSON.parse(data);
+    // let datas = JSON.parse(data);
 
-    if (datas.libID){
+    if (data.libID){
         let ItemObj = {
             updateOne: {
-                filter: {projectID: datas.projectID},
-                update: { 'libID': datas.projectID, 'libName': datas.libName }
+                filter: {projectID: data.projectID},
+                update: { 'libID': data.projectID, 'libName': data.libName }
             }
         };
         updateArr.push(ItemObj);
     };
 
-    for (let Item of datas.newItemArr) {
+    for (let Item of data.newItemArr) {
          let ItemObj = {
              updateOne: {
-                 filter: {projectID: datas.projectID, 'coes.ID': Item.ID},
+                 filter: {projectID: data.projectID, 'coes.ID': Item.ID},
                  update: { 'coes.$.coe': Item.coe }
              }
          };
@@ -111,7 +111,7 @@ function save (data, callback) {
     // console.log(JSON.stringify(updateArr));
     projectLabourCoesModel.bulkWrite(updateArr)
         .then(function(){
-            logger.info(`Project LabourCoe saved successful : ${datas.projectID}`);
+            logger.info(`Project LabourCoe saved successful : ${data.projectID}`);
             callback(0, '', null);
         })
         .catch(function (err) {

+ 33 - 12
modules/pm/controllers/pm_controller.js

@@ -3,12 +3,15 @@
  */
 import UnitPriceFileModel from "../../glj/models/unit_price_file_model";
 let ProjectsData = require('../models/project_model').project;
-let projectM = require('../../main/models/project');
+let labourCoe = require('../../main/facade/labour_coe_facade');
 let projType = require('../models/project_model').projType;
 let fileType = require('../models/project_model').fileType;
 const engineering = require("../../common/const/engineering");
 let EngineeringLibModel = require("../../users/models/engineering_lib_model");
 let fee_rate_facade = require("../../fee_rates/facade/fee_rates_facade");
+let billsModel = require('../../main/models/bills').model;
+let rationsModel = require('../../main/models/ration').model;
+let projectModel = require("../models/project_schema");
 
 //统一回调函数
 let callback = function(req, res, err, message, data){
@@ -59,23 +62,41 @@ module.exports = {
             }
         });
     },
-    // 该方法主要用于项目属性位置提交保存混合型数据,这些数据来自不同的表,包括projects.property、ration、bills、labour_coes.
+    // CSL, 2017-12-14 该方法用于项目属性:提交保存混合型数据,这些数据来自不同的表,包括projects.property、ration、bills、labour_coes.
     updateMixDatas: function(req, res){
         let callBackInner = function (err, message, data) {
             if (err === 0) {
-                callback(req, res, err, message, data);
+                res.json({error: err, message: message, data: data});
             } else {
-                callback(req, res, err, message, null);
+                res.json({error: err, message: message, data: null});
             }
         };
-        let datas = JSON.parse(req.body.data);
-        for (let data of datas){
-              if (data.sourceType == 'properties'){
-                  ProjectsData.updateUserProjects(req.session.sessionUser.ssoId, data.updateData, callBackInner);
-              }
-              else{
-                projectM.save(data, callBackInner);
-              }
+
+        let datas = JSON.parse(req.body.data).mixDataArr;
+
+        // 项目属性
+        if (Object.keys(datas.properties).length > 0){
+            projectModel.update({ID: datas.projectID}, datas.properties, callBackInner);
+        };
+
+        // 人工系数
+        if (datas.labourCoes.updateData){
+            datas.labourCoes.updateData.projectID = datas.projectID;
+            labourCoe.save(datas.labourCoes.updateData, callBackInner);
+        };
+
+        // 清单:每文档doc只存储一条清单,每条清单都必须定位一次文档,无法合并处理
+        if (datas.bills.length > 0){
+            for (let bill of datas.bills){
+                billsModel.update({projectID: datas.projectID, ID: bill.ID, deleteInfo: null}, bill, callBackInner);
+            };
+        };
+
+        // 定额:每文档doc只存储一条定额,每条定额都必须定位一次文档,无法合并处理
+        if (datas.rations.length > 0){
+            for (let ration of datas.rations){
+                rationsModel.update({projectID: datas.projectID, ID: ration.ID, deleteInfo: null}, ration, callBackInner);
+            };
         };
     },
     updateFiles: async function(req, res){

+ 6 - 3
modules/pm/models/project_model.js

@@ -72,7 +72,8 @@ ProjectsDAO.prototype.updateUserProjects = async function(userId, compilationId,
             }
             if (data.updateType === 'update') {
                 Projects.update({userID: userId, ID: data.updateData.ID}, data.updateData, updateAll);
-            } else if (data.updateType === 'new') {
+            }
+            else if (data.updateType === 'new') {
                 data.updateData['userID'] = userId;
                 data.updateData['compilation'] = compilationId;
                 data.updateData['createDateTime'] = new Date();
@@ -136,7 +137,8 @@ ProjectsDAO.prototype.updateUserProjects = async function(userId, compilationId,
                         updateAll(err);
                     }
                 });
-            } else if (data.updateType === 'delete') {
+            }
+            else if (data.updateType === 'delete') {
                 deleteInfo = {};
                 deleteInfo['deleted'] = true;
                 deleteInfo['deleteDateTime'] = new Date();
@@ -190,7 +192,8 @@ ProjectsDAO.prototype.updateUserProjects = async function(userId, compilationId,
                 catch (error){
                     callback(1, error, null);
                 }
-            } else {
+            }
+            else {
                 hasError = true;
                 callback(1, '提交数据错误.', null);
             }

+ 10 - 0
modules/ration_repository/controllers/ration_controller.js

@@ -18,6 +18,16 @@ module.exports = {
             }
         });
     },
+    getRationGljItemsBySection: async function(req, res){
+        var sectionId = req.body.sectionID;
+        rationItem.getRationGljItemsBySection(sectionId, function(err, message, rst){
+            if (err) {
+                callback(req, res, err, message, null);
+            } else {
+                callback(req, res, err, message, rst);
+            }
+        });
+    },
     mixUpdateRationItems: function(req, res){
         var sectionId = req.body.sectionID,
             rationLibId = req.body.rationLibId,

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

@@ -43,6 +43,7 @@ var rationItemSchema = mongoose.Schema({
 });
 var rationItemModel = db.model("std_ration_lib_ration_items",rationItemSchema, "std_ration_lib_ration_items")
 var counter = require('../../../public/counter/counter');
+import stdGljListModel from '../../common/std/schemas/std_ration_lib_glj_list';
 
 var rationItemDAO = function(){};
 
@@ -52,6 +53,28 @@ rationItemDAO.prototype.getRationItemsBySection = function(sectionId,callback){
         else callback(false,"Get items successfully", data);
     })
 };
+rationItemDAO.prototype.getRationGljItemsBySection = async function(sectionId,callback){
+    try{
+        let rationItems = await rationItemModel.find({"sectionId": sectionId, "$or": [{"isDeleted": null}, {"isDeleted": false} ]}, null, {sort: {code: 1}});
+        for(let i = 0, len = rationItems.length; i < len; i++){
+            let hint = '';
+            let ration = rationItems[i];
+            for(let j = 0, jLen = ration.rationGljList.length; j < jLen; j++){
+                let rationGlj = ration.rationGljList[j];
+                let glj = await stdGljListModel.find({ID: rationGlj.gljId, $or: [{isDeleted: null}, {isDeleted: false} ]}, '-_id code name unit');
+                if(glj.length > 0){
+                    let unitHint = '' + glj[0].code + ' ' + glj[0].name + '' + glj[0].unit + ' ' + rationGlj.consumeAmt + '</br>';
+                    hint += unitHint;
+                }
+            }
+            ration._doc.hint = hint;
+        }
+        callback(false,"Get items successfully", rationItems);
+    }
+    catch (err){
+        callback(true, "Fail to get items", "")
+    }
+};
 rationItemDAO.prototype.mixUpdateRationItems = function(rationLibId, sectionId, updateItems, addItems, rIds, callback){
     var me = this;
     if (updateItems.length == 0 && rIds.length == 0) {

+ 1 - 0
modules/ration_repository/routes/ration_front_end_routes.js

@@ -21,6 +21,7 @@ module.exports = function (app) {
     apiRouter.post("/getRationTree",rationChapterTreeController.getRationChapterTree);
 
     apiRouter.post("/getRationItems",rationController.getRationItemsBySection);
+    apiRouter.post("/getRationGljItems",rationController.getRationGljItemsBySection);
 
     apiRouter.post("/getGljTree",repositoryGljController.getGljTree);
     apiRouter.post("/getGljItems",repositoryGljController.getGljItems);

+ 64 - 7
public/web/scMathUtil.js

@@ -1,5 +1,7 @@
 /**
  * Created by jimiz on 2017/3/28.
+ * 经验证:10000次四舍五入,用num.toFixed为15毫秒,用roundTo为47毫秒,速度低一些,但可以接受
+ * 另:经手工验证,用num.toString(2)将十进制浮点数转换为二进制浮点数时,最后一位有错误的情况出现,例子(10.0311)
  */
 
 let scMathUtil = {
@@ -31,8 +33,69 @@ let scMathUtil = {
         // 拼出完整结果
         return Number(sign + r1 + '.' + r2);
     },
+    // 原来直接用num.toString(2),如果小数段最后位数是0,会被舍掉,导致进位计算bug
+    // 改为自己计算二进制,固定为53位。
+    // 经验证速度没有差别
+    // 另:经手工验证,用num.toString(2)将十进制浮点数转换为二进制浮点数时,最后一位有错误的情况出现,例子(10.0311)
     floatToBin: function(num) {
-        return num.toString(2);
+        let sign = '';
+        let dNum = num;
+        // 符号位
+        if (num < 0) {
+            sign = '-';
+            dNum = -num;
+        };
+        // 解析整数段
+        let iNum = Math.floor(dNum);
+        let iFactor;
+        let sResult1 = '';
+        // 计算二进制整数段
+        while (iNum > 0){
+            iFactor = iNum % 2;
+            iNum = Math.floor(iNum / 2);
+            sResult1 = iFactor + sResult1;
+        }
+        // 判断是否有整数段
+        let bIntZero = sResult1 === '';
+        if (bIntZero){
+            sResult1 = '0';
+        }
+        // 解析小数段
+        let fNum = dNum - Math.floor(dNum);
+        let sResult2 = '';
+        if (fNum > 0){
+            // 双精度浮点数,尾数总长52位,因为第一位总是1,存储时已经被隐藏,所以有效位数为53位
+            const floatLength = 53;
+
+            let iLength;
+            // js的bug,浮点数直接取小数可能不能获得精确值,只有转成字符串,截取字符串中的小数段
+            let sNum = dNum.toString(10);
+            let iDot = sNum.indexOf('.');
+            sNum = '0' + sNum.substring(iDot, sNum.length);
+            fNum = Number(sNum);
+            // 有整数段,则小数位数为全部位数-整数位数
+            if (!bIntZero){
+                iLength = floatLength - sResult1.length;
+            }
+            else{
+                iLength = floatLength;
+            }
+            // 计算二进制小数段
+            while (iLength > 0){
+                fNum = fNum * 2;
+                iFactor = Math.floor(fNum);
+                fNum = fNum % 1;
+                sResult2 = sResult2 + iFactor;
+                if (iFactor > 0){
+                    bIntZero = false;
+                }
+                if (bIntZero && (iFactor === 0)){
+                    continue;
+                }
+                iLength--;
+            }
+        }
+        return sign + sResult1 + '.' + sResult2;
     },
     binToFloat: function(bin) {
         let result = 0;
@@ -74,13 +137,7 @@ let scMathUtil = {
         let result = bin;
         let iDot = bin.indexOf('.');
         if (iDot < 0){return result};
-        // 二进制浮点数带小数位数最大长度
-        let floatLength = 53;
         let iLength = bin.length;
-        // 长度小于53说明该二进制数尾数长度小于Double类型限制,未被截断,无需进位
-        if (iLength < floatLength) {
-            return result;
-        }
         iLength = bin.length;
         for (let i = iLength - 1; i > iDot; i--){
             let num = Number(bin[i]);

+ 5 - 1
public/web/sheet/sheet_data_helper.js

@@ -134,6 +134,10 @@ var SheetDataHelper = {
         };
         TipCellType.prototype.processMouseEnter = function (hitinfo) {
             let text = hitinfo.sheet.getText(hitinfo.row, hitinfo.col);
+            let tag = hitinfo.sheet.getTag(hitinfo.row, hitinfo.col);
+            if(tag !== undefined && tag){
+                text = tag;
+            }
             if (setting.pos && text && text !== '') {
                 if (!this._toolTipElement) {
                     let div = $('#autoTip')[0];
@@ -150,7 +154,7 @@ var SheetDataHelper = {
                         document.body.insertBefore(div, null);
                     }
                     this._toolTipElement = div;
-                    $(this._toolTipElement).text(text).css("top", setting.pos.y + hitinfo.y + 15).css("left", setting.pos.x + hitinfo.x + 15);
+                    $(this._toolTipElement).html(text).css("top", setting.pos.y + hitinfo.y + 15).css("left", setting.pos.x + hitinfo.x + 15);
                     $(this._toolTipElement).show("fast");
                 }
             }

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

@@ -223,7 +223,6 @@ var TREE_SHEET_HELPER = {
             }
             let node = tree.items[options.row];
             let showTreeLine = true;
-
             if (!node) { return; }
 
             let centerX = Math.floor(x) + node.depth() * indent + indent / 2;
@@ -317,6 +316,10 @@ var TREE_SHEET_HELPER = {
         };
         TipCellType.prototype.processMouseEnter = function (hitinfo) {
             let text = hitinfo.sheet.getText(hitinfo.row, hitinfo.col);
+            let tag = hitinfo.sheet.getTag(hitinfo.row, hitinfo.col);
+            if(tag !== undefined && tag) {
+                text = tag;
+            }
             if (setting.pos && text && text !== '') {
                 if (!this._toolTipElement) {
                     let div = $('#autoTip')[0];

+ 3 - 3
web/building_saas/complementary_glj_lib/js/glj.js

@@ -45,7 +45,7 @@ let repositoryGljObj = {
             {headerName:"名称",headerWidth:280,dataCode:"name", dataType: "String", hAlign: "left", vAlign: "center"},
             {headerName:"规格型号",headerWidth:180,dataCode:"specs", dataType: "String", hAlign: "left", vAlign: "center"},
             {headerName:"单位",headerWidth:120,dataCode:"unit", dataType: "String", hAlign: "center", vAlign: "center"},
-            {headerName:"基价单价",headerWidth:120,dataCode:"basePrice", dataType: "Number", formatter: "0.00", hAlign: "right", vAlign: "center"},
+            {headerName:"定额价",headerWidth:120,dataCode:"basePrice", dataType: "Number", formatter: "0.00", hAlign: "right", vAlign: "center"},
             {headerName:"类型",headerWidth:120,dataCode:"gljType", dataType: "String", hAlign: "center", vAlign: "center"},
             {headerName:"是否新增",headerWidth:80,dataCode:"isComplementary", hAlign: "center", vAlign: "center"}
         ],
@@ -147,8 +147,7 @@ let repositoryGljObj = {
             }
             sheetOpr.cleanData(me.workBook.getSheet(0), me.setting, -1);
             sheetOpr.showData(me.workBook.getSheet(0), me.setting, cacheSection, me.distTypeTree);
-            sheetCommonObj.setStaticCombo(me.workBook.getActiveSheet(), 0, 5, cacheSection.length, me.distTypeTree.comboDatas, false, 'text');
-            sheetCommonObj.setDynamicCombo(me.workBook.getActiveSheet(), cacheSection.length, 5, me.workBook.getActiveSheet().getRowCount() - cacheSection.length, me.distTypeTree.comboDatas, false, 'text');
+            sheetCommonObj.setDynamicCombo(me.workBook.getActiveSheet(), 0, 5, me.workBook.getActiveSheet().getRowCount(), me.distTypeTree.comboDatas, false, 'text');
 
             cacheSection = null;
         }
@@ -165,6 +164,7 @@ let repositoryGljObj = {
         me.workBook.getSheet(0).bind(GC.Spread.Sheets.Events.SelectionChanged, me.onSelectionChanged);
         me.workBook.bind(GC.Spread.Sheets.Events.ButtonClicked, me.onButtonClicked);//复选框点击事件
     },
+
     getCurrentComponent: function (gljComponent) {
         let me = repositoryGljObj, rst = [];
         for(let i = 0; i < gljComponent.length; i++){

+ 2 - 2
web/building_saas/main/html/main.html

@@ -124,7 +124,7 @@
                                           </div>
                                           <div class="main-data-bottom ovf-hidden" style="width: 33%; float: left;" id="itemSpread">
                                           </div>
-                                          <div id="add-rule" style="width: 33%;float: left;background: #EFEFEF; height: 100%;display: none;">
+                                          <div id="add-rule" style="width: 33%;float: left;background: #EFEFEF; height: 100%;display: none; padding-left: 8px;">
                                               <p style="text-align: center">添加规则</p>
                                               <p>
                                                   <label class="title">添加位置:</label>
@@ -170,7 +170,7 @@
                                               </p>
                                               <p>
                                                   <label class="title">序号格式:</label>
-                                                  <select id="serial-type" disabled="disabled">
+                                                  <select id="serial-type">
                                                       <option value="">无</option>
                                                       <option value="1" selected="selected">1.</option>
                                                       <option value="2">a.</option>

+ 3 - 8
web/building_saas/main/js/models/calc_base.js

@@ -52,7 +52,7 @@ let cbTools = {
         return this.isDef(v) && !isNaN(v) && v !== Infinity;
     },
     isFlag: function (v) {
-        return this.isDef(v.flagsIndex) && this.isDef(v.flagsIndex.fixed);
+        return this.isDef(v) && this.isDef(v.flagsIndex) && this.isDef(v.flagsIndex.fixed);
     },
     returnV: function (v, r) {
         if(this.isDef(v)){
@@ -500,11 +500,6 @@ let cbAnalyzer = {
             return null;
         }
         return null;
-    },
-
-    isCN: function(v){
-        let regex = /[\u4e00-\u9fa5]/g;
-        return (regex.test(v));
     }
 };
 
@@ -610,7 +605,7 @@ let calcBase = {
             me.project.calcProgram.saveNode(node);
         }
         catch (err){
-            alert(err);
+            alert('表达式不正确');
         }
-    },
+    }
 };

+ 5 - 4
web/building_saas/main/js/views/calc_base_view.js

@@ -14,7 +14,7 @@ let calcBaseView = {
     setting:{
         header: [
             {name: '计算基础名称', dataCode: 'base', width: 280, vAlign: 'center', hAlign: 'left'},
-            {name: '金额', dataCode: 'price', width: 120, vAlign: 'center', hAlign: 'left'}
+            {name: '金额', dataCode: 'price', width: 120, vAlign: 'center', hAlign: 'right'}
         ],
         options: {
             tabStripVisible:  false,
@@ -84,7 +84,7 @@ let calcBaseView = {
             sheet.setFormatter(-1, 1, '@');
             for(let col = 0, cLen = cols.length; col < cLen; col++){
                 sheet.getRange(-1, col, -1, 1).hAlign(GC.Spread.Sheets.HorizontalAlign[cols[col]['hAlign']]);
-                sheet.getRange(-1, col, -1, 1).hAlign(GC.Spread.Sheets.VerticalAlign[cols[col]['vAlign']]);
+                sheet.getRange(-1, col, -1, 1).vAlign(GC.Spread.Sheets.VerticalAlign[cols[col]['vAlign']]);
                 for(let row = 0, rLen = datas.length; row < rLen; row++){
                     sheet.setValue(row, col, datas[row][cols[col]['dataCode']]);
                 }
@@ -210,8 +210,9 @@ let calcBaseView = {
         CalcBaseCellType.prototype = new ns.CellTypes.Text();
         CalcBaseCellType.prototype.paint = function (ctx, value, x, y, w, h, style, options) {
             if(value!=null){
-                // ctx.fillText(value,x+3+ctx.measureText(value).width,y+h-3);
-                ctx.fillText(value,x+w,y+h-3);
+               // ctx.fillText(value,x+3+ctx.measureText(value).width,y+h-3);
+               // ctx.fillText(value,x+w-3,y+h-3);
+                GC.Spread.Sheets.CellTypes.Text.prototype.paint.apply(this, arguments);
             }
             if(calcBaseView.editingCell){
                 if(calcBaseView.editingCell.row==options.row&&calcBaseView.editingCell.col==options.col){

+ 70 - 18
web/building_saas/main/js/views/character_content_view.js

@@ -780,10 +780,10 @@ let pageCCOprObj = {
         }
         // 保存的条件数据
         const findSet = { ID: node.data.ID, projectID: node.data.projectID };
-
+        const baseData = { findSet, itemJob, itemCharacter };
         let characterArray = [];
         for (const tmp of itemCharacter) {
-            if (tmp.eigenvalue === undefined || tmp.eigenvalue.length <= 0) {
+            if (tmp.eigenvalue === undefined || tmp.eigenvalue.length <= 0 || !tmp.isChecked) {
                 continue;
             }
             // 获取选中的特征值
@@ -804,7 +804,7 @@ let pageCCOprObj = {
                     break;
                 case '2':
                     // 特征:特征值
-                    characterString = serialNo + tmp.character + ':' + selectedEigen;
+                    characterString = serialNo + tmp.character + ': ' + selectedEigen;
                     break;
             }
             characterArray.push(characterString);
@@ -813,6 +813,9 @@ let pageCCOprObj = {
         // 内容部分
         let jobArray = [];
         for (const tmp of itemJob) {
+            if (!tmp.isChecked) {
+                continue;
+            }
             // 匹配设置的序号格式
             const serialNo = this.formatSerialNumber(setting.serialType, tmp.serialNo);
             jobArray.push(serialNo + tmp.content)
@@ -820,7 +823,16 @@ let pageCCOprObj = {
 
         // 组合数据
         let content = '';
-        let defaultContentInfo = {};
+        const jobContent = jobArray.join("\r\n");
+        const characterContent = characterArray.join("\r\n");
+        let nodeNameList = node.data.name.split("\n");
+        const nameContent = nodeNameList[0] !== undefined ? nodeNameList[0] : '';
+        // 存入对象,生成数据时用
+        let defaultContentInfo = {
+            jobContent,
+            characterContent,
+            nameContent
+        };
         switch (setting.addContent) {
             case "1":
                 // 项目特征+工作内容
@@ -851,16 +863,6 @@ let pageCCOprObj = {
                 break;
             case "":
                 // 无
-                const jobContent = jobArray.join("\r\n");
-                const characterContent = characterArray.join("\r\n");
-                let nodeNameList = node.data.name.split("\n");
-                const nameContent = nodeNameList[0] !== undefined ? nodeNameList[0] : '';
-                // 存入对象,生成数据时用
-                defaultContentInfo = {
-                    jobContent,
-                    characterContent,
-                    nameContent
-                };
                 break;
         }
         // 显示格式
@@ -878,10 +880,13 @@ let pageCCOprObj = {
                 content = '(' + contentArray.join(',') + ')';
                 break;
         }
+        // 还原数据
+        this.restoreData(node, setting.position, baseData, defaultContentInfo);
         // 添加到对应位置
         let saveObj = {};
         switch (setting.position) {
             case "1":
+                // 添加到项目特征列
                 saveObj = {field: 'itemCharacterText', text: content};
                 // 更新到数据库
                 pageCCOprObj.updateCharacterContent(findSet, {field: 'itemCharacter', updateArr: itemCharacter},
@@ -937,15 +942,15 @@ let pageCCOprObj = {
         switch (type) {
             case '1':
                 // 数字
-                serialNo = serialNo + '.';
+                serialNo = serialNo + '. ';
                 break;
             case '2':
                 // 英文字母(小写)
-                serialNo = letter[serialNo - 1] !== undefined ? letter[serialNo - 1] + '.' : '';
+                serialNo = letter[serialNo - 1] !== undefined ? letter[serialNo - 1] + '. ' : '';
                 break;
             case '3':
                 // 英文字母(大写)
-                serialNo = letter[serialNo - 1] !== undefined ? letter[serialNo - 1].toUpperCase() + '.' : '';
+                serialNo = letter[serialNo - 1] !== undefined ? letter[serialNo - 1].toUpperCase() + '. ' : '';
                 break;
         }
         return serialNo;
@@ -969,10 +974,57 @@ let pageCCOprObj = {
                 continue;
             }
             const serialNo = this.formatSerialNumber(setting.serialType, count.toString());
-            result.push(serialNo + tmp.data.code + ':' + tmp.data.name);
+            result.push(serialNo +  tmp.data.code + ':' + tmp.data.name);
             count++;
         }
 
         return result;
     },
+
+    /**
+     * 还原数据
+     *
+     * @param {Object} node - 节点数据
+     * @param {String} setType - 当前设置的项
+     * @param {Object} baseData - 需要用到的基础数据
+     * @param {Object} defaultContentInfo - 默认数据
+     * @return {void}
+     */
+    restoreData: function(node, setType, baseData, defaultContentInfo) {
+        if (baseData.findSet === undefined ||
+        baseData.itemJob === undefined || baseData.itemCharacter === undefined) {
+            return;
+        }
+
+        switch (setType) {
+            case "1":
+                // 添加到项目特征列
+                // 把其他字段还原回原来数据
+                // 还原名称
+                projectObj.project.Bills.updateField(node.source, 'name', defaultContentInfo.nameContent, true);
+                projectObj.mainController.refreshTreeNode([node], false);
+                // 还原工作内容
+                pageCCOprObj.updateCharacterContent(baseData.findSet, {field: 'jobContent', updateArr: baseData.itemJob},
+                    {field: 'jobContentText', text: defaultContentInfo.jobContent}, node);
+                break;
+            case "2":
+                // 添加到清单名称
+                // 还原特征
+                pageCCOprObj.updateCharacterContent(baseData.findSet, {field: 'itemCharacter', updateArr: baseData.itemCharacter},
+                    {field: 'itemCharacterText', text: defaultContentInfo.characterContent}, node);
+                // 还原工作内容
+                pageCCOprObj.updateCharacterContent(baseData.findSet, {field: 'jobContent', updateArr: baseData.itemJob},
+                    {field: 'jobContentText', text: defaultContentInfo.jobContent}, node);
+                break;
+            case "3":
+                // 添加到工作内容列
+                // 还原名称
+                projectObj.project.Bills.updateField(node.source, 'name', defaultContentInfo.nameContent, true);
+                projectObj.mainController.refreshTreeNode([node], false);
+                // 还原特征
+                pageCCOprObj.updateCharacterContent(baseData.findSet, {field: 'itemCharacter', updateArr: baseData.itemCharacter},
+                    {field: 'jobContentText', text: defaultContentInfo.characterContent}, node);
+                break;
+        }
+    },
 }

+ 2 - 2
web/building_saas/main/js/views/project_property_basicInfo.js

@@ -265,12 +265,12 @@ let basicInfoView = {
             if(datas[i].hasOwnProperty('items')){
                 let collapsed = false;
                 if(init){
-                    datas[i].collapsed=true;
+                    datas[i].collapsed=false;
                     collapsed = true;
                 }else {
                     collapsed = datas[i].collapsed == undefined ? true : datas[i].collapsed;
                 }
-                sheet.getRange(i+1, -1, datas[i].items.length, -1).visible(!collapsed);
+                //sheet.getRange(i+1, -1, datas[i].items.length, -1).visible(!collapsed);
             }
         }
     },

+ 2 - 2
web/building_saas/main/js/views/project_property_display_view.js

@@ -27,8 +27,8 @@ let projDisplayView = {
         if(this.datas.autoHeight!==autoHeight||this.datas.disPlayMainMaterial!==disPlayMainMaterial){
             this.datas.autoHeight=autoHeight;
             this.datas.disPlayMainMaterial=disPlayMainMaterial;
-            let updateData = {sourceType: 'properties', updateType: 'update', updateData: {ID: projectID, 'property.displaySetting':this.datas}};
-            properties.push(updateData);
+            // let updateData = {sourceType: 'properties', updateType: 'update', updateData: {ID: projectID, 'property.displaySetting':this.datas}};
+            properties['property.displaySetting'] = this.datas;
         }
     }
 };

+ 11 - 6
web/building_saas/main/js/views/project_property_projFeature.js

@@ -48,10 +48,10 @@ let projFeatureView = {
     },
 
     setCombo: function (sheet, row, items) {
-        let combo = new GC.Spread.Sheets.CellTypes.ComboBox();
-        combo.items(items);
-        combo.editable(false);
-        sheet.getCell(row, 1).cellType(combo);
+        let dynamicCombo = sheetCommonObj.getDynamicCombo();
+        dynamicCombo.items(items);
+        dynamicCombo.editable(false);
+        sheet.getCell(row, 1).cellType(dynamicCombo);
     },
 
     getComboItemsByRow: function (row) {
@@ -91,6 +91,7 @@ let projFeatureView = {
         let sheet = workBook.getActiveSheet();
         sheet.bind(_events.EditStarting, this.onEditStarting);
         sheet.bind(_events.EditEnded, this.onEditEnded);
+        sheet.bind(_events.EnterCell, this.onEnterCell);
         sheet.bind(_events.ClipboardPasting, this.onClipboardPasting);
         sheet.bind(_events.ClipboardPasted, this.onClipboardPasted);
     },
@@ -142,6 +143,10 @@ let projFeatureView = {
         }
     },
 
+    onEnterCell: function (sender, args) {
+        args.sheet.repaint();
+    },
+
     onClipboardPasting: function (sender, args) {
         let me = projFeatureView;
         if(me.setting.locked.cols.indexOf(args.cellRange.col) !== -1){
@@ -260,12 +265,12 @@ let projFeatureView = {
             if(datas[i].hasOwnProperty('items')){
                 let collapsed = false;
                 if(init){
-                    datas[i].collapsed=true;
+                    datas[i].collapsed=false;
                     collapsed = true;
                 }else {
                     collapsed = datas[i].collapsed == undefined ? true : datas[i].collapsed;
                 }
-                sheet.getRange(i+1, -1, datas[i].items.length, -1).visible(!collapsed);
+                //sheet.getRange(i+1, -1, datas[i].items.length, -1).visible(!collapsed);
             }
         }
     },

+ 50 - 39
web/building_saas/main/js/views/project_view.js

@@ -435,8 +435,10 @@ var projectObj = {
                         col.data.field === 'jobContentText' || col.data.field === 'adjustState') {
                         if (!autoHeight) {
                             col.showHint = true;
+                            col.data.wordWrap = false;
                         } else {
                             col.showHint = false;
+                            col.data.wordWrap = true;
                         }
                     }
 
@@ -705,75 +707,75 @@ $('#poj-set').on('show.bs.modal', function () {
     }
 });
 $('#property_ok').click(function () {
-    let properties = [], projectID = parseInt(scUrlUtil.GetQueryString('project'));
-    let project = projectObj.project, reCalcBills= false, reCalcRations= false;
-    let b = parseInt($("input[name='calcFlag']:checked").val());
+    let project = projectObj.project,
+        projectID = project.ID(),
+
+        properties = {},
+        labourCoes = {},
+        rations = [],
+        bills = [],
+
+        mixDatas = {
+            projectID: projectID,
+            updateType: 'update',
+            properties: properties,
+            labourCoes: labourCoes,
+            rations: rations,
+            bills: bills
+        },
+
+        reCalcBills= false,
+        reCalcRations= false;
 
+    let b = parseInt($("input[name='calcFlag']:checked").val());
     if (b !== project.property.billsCalcMode) {
-        let bData = {sourceType: 'properties', updateType: 'update', updateData: {ID: projectID, 'property.billsCalcMode': b}};
-        properties.push(bData);
+        properties['property.billsCalcMode'] = b;
         project.property.billsCalcMode = b;
         reCalcBills = true;
     };
 
     let zg = parseInt($("input[name='zangu']:checked").val());
     if (zg !== project.property.zanguCalcMode) {
-        let zgData = {sourceType: 'properties', updateType: 'update', updateData: {ID: projectID, 'property.zanguCalcMode': zg}};
-        properties.push(zgData);
+        properties['property.zanguCalcMode'] = zg;
         project.property.zanguCalcMode = zg;
         reCalcBills = true;
     };
 
     //基本信息
     if(basicInfoView.toUpdate(basicInfoView.orgDatas, basicInfoView.datas)){
-        let updateData = {sourceType: 'properties', updateType: 'update', updateData: {ID: projectID, 'property.basicInformation': basicInfoView.toSaveDatas(basicInfoView.datas)}};
-        properties.push(updateData);
+        properties['property.basicInformation'] = basicInfoView.toSaveDatas(basicInfoView.datas);
     }
     //工程特征
     if(projFeatureView.toUpdate(projFeatureView.orgDatas, projFeatureView.datas)){
-        let updateData = {sourceType: 'properties', updateType: 'update', updateData: {ID: projectID, 'property.projectFeature': projFeatureView.toSaveDatas(projFeatureView.datas)}};
-        properties.push(updateData);
+        properties['property.projectFeature'] = projFeatureView.toSaveDatas(projFeatureView.datas);
     }
     //清单工程量精度
     let newBillsDecimalDatas = billsDecimalView.toBillsDecimalDatas(billsDecimalView.cache);
     if(billsDecimalView.toUpdate(billsQuanDecimal.datas, newBillsDecimalDatas)){
         reCalcBills = true;
-        let updateData = {sourceType: 'properties', updateType: 'update', updateData: {ID: projectID, 'property.billsQuantityDecimal': newBillsDecimalDatas}};
-        properties.push(updateData);
+        properties['property.billsQuantityDecimal'] = newBillsDecimalDatas;
     }
     //小数位数
-    //获取更新的数据
     let updateDecimal = m_getDecimalData($('input', '#poj-settings-decimal'));
     if(toUpdateDecimal(decimalObj, updateDecimal)){
         reCalcRations = true;
         reCalcBills = true;
-        let updateData = {sourceType: 'properties', updateType: 'update', updateData: {ID: projectID, 'property.decimal': updateDecimal}};
-        properties.push(updateData);
+        properties['property.decimal'] = updateDecimal;
     };
+    // 呈现选项
+    projDisplayView.updateChecking(projectID, properties);
 
     // 人工系数
-    let lcData;
     if (labourCoeView.needSave()){
         reCalcRations = true;
         reCalcBills = true;
         project.calcProgram.compileAllTemps();
 
-        let projectID = projectInfoObj.projectInfo.ID;
         let libID = $("#std_labour_coe_files").children("option:selected").val();
         let libName = $("#std_labour_coe_files").children("option:selected").text();
-        lcData = {sourceType: 'labourCoe', projectID: projectID, libID: libID, libName: libName, newItemArr: labourCoeView.needUpdateDatas};
-        properties.push(lcData);
-    };
 
-    // 呈现选项
-    projDisplayView.updateChecking(projectID,properties);
- /*   const autoHeight = $("#autoHeight:checked").length > 0;
-    const disPlayMainMaterial = $("#disPlayMainMaterial:checked").length > 0;*/
-/*    if (projDisplayView.needUpdate(autoHeight, disPlayMainMaterial)) {
-        const displaySetting = { autoHeight, disPlayMainMaterial };
-        let updateData = {sourceType: 'properties', updateType: 'update', updateData: {ID: projectID, 'property.displaySetting': displaySetting}};
-        properties.push(updateData);
-    }*/
+        labourCoes.updateData = {libID: libID, libName: libName, newItemArr: labourCoeView.needUpdateDatas};
+    };
 
     // 重新计算树节点
     let changedNodes = [];
@@ -784,7 +786,7 @@ $('#property_ok').click(function () {
     if (changedNodes.length > 0) {
         for (let node of changedNodes){
             let data = {
-                projectID: project.ID(),
+                // projectID: projectID,
                 ID: node.data.ID,
                 quantity: node.data.quantity,
                 calcBase: node.data.calcBase,
@@ -795,19 +797,28 @@ $('#property_ok').click(function () {
                 feeRate: node.data.feeRate,
                 feeRateID: node.data.feeRateID
             };
-            let dataObj = {sourceType: node.sourceType, updateType: 'ut_update', updateData: data};
-            properties.push(dataObj);
+            if (node.sourceType == 'ration'){
+                rations.push(data);
+            }
+            else if (node.sourceType == 'bills'){
+                bills.push(data);
+            };
         };
     };
 
-    console.log(properties);
-    if(properties.length > 0){
-        CommonAjax.post('/pm/api/updateMixDatas', {user_id: userID, updateData: properties}, function (rstData) {
-            if (changedNodes.length > 0) {
+    console.log(mixDatas);
+    function hasMixData() {
+        return Object.keys(mixDatas.properties).length > 0 ||
+            mixDatas.labourCoes.updateData || mixDatas.rations.length > 0 || mixDatas.bills.length > 0;
+    }
+
+    if(hasMixData){
+        CommonAjax.post('/pm/api/updateMixDatas', {user_id: userID, mixDataArr: mixDatas}, function (rstData) {
+/*            if (changedNodes.length > 0) {
                 for (let node of changedNodes){delete node.changed};
             };
-            if (lcData) labourCoeView.refresh(lcData);
-            window.location.href = '/main?project=' + projectID;
+            if (mixDatas.labourCoes.updateData) labourCoeView.refresh(mixDatas.labourCoes.updateData);*/
+            // window.location.href = '/main?project=' + projectID;
         });
     }
 });

+ 18 - 3
web/building_saas/main/js/views/std_bills_lib.js

@@ -46,6 +46,19 @@ var billsLibObj = {
             sheet.resumePaint();
         }
     },
+    setTagForHint: function (datas) {
+        let sheet = this.stdBillsSpread.getActiveSheet();
+        sheet.suspendPaint();
+        sheet.suspendEvent();
+        for(let i = 0, len = sheet.getRowCount(); i < len; i++){
+            sheet.setTag(i, 2, '');
+        }
+        for(let i = 0, len = datas.length; i < len; i++){
+            sheet.setTag(i, 2, datas[i].ruleText ? datas[i].ruleText : '');
+        }
+        sheet.resumePaint();
+        sheet.resumeEvent();
+    },
     loadStdBillsLib: function () {
         let i, select = $('#stdBillsLibSelect');
         select.empty();
@@ -153,6 +166,7 @@ var billsLibObj = {
             stdBills = datas;
             stdBillsTree.loadDatas(stdBills);
             stdBillsTreeController.showTreeData();
+            billsLibObj.setTagForHint(datas);
             showBillsRela(stdBillsTree.firstNode());
 
             stdBillsTreeController.bind(TREE_SHEET_CONTROLLER.eventName.treeSelectedChanged, showBillsRela);
@@ -249,7 +263,7 @@ var billsLibObj = {
                 "font":"Arial"
             }
         }, {
-            "width":150,
+            "width":220,
             "readOnly": true,
             "head":{
                 "titleNames":["项目名称"],
@@ -268,6 +282,7 @@ var billsLibObj = {
         }, {
             "width":50,
             "readOnly": true,
+            "showHint": true,
             "head":{
                 "titleNames":["计量单位"],
                 "spanCols":[1],
@@ -283,7 +298,7 @@ var billsLibObj = {
                 "hAlign":1,
                 "font":"Arial"
             }
-        }, {
+        }/*, {
             "width":100,
             "readOnly": true,
             "showHint": true,
@@ -301,7 +316,7 @@ var billsLibObj = {
                 "hAlign":0,
                 "font":"Arial"
             }
-        }]
+        }*/]
     },
     jobsSetting: {
         "emptyRows":0,

+ 22 - 1
web/building_saas/main/js/views/std_ration_lib.js

@@ -8,6 +8,9 @@ var rationLibObj = {
     rationChapterSpread: null,
     sectionRationsSpread: null,
     rationChapterTreeController: null,
+    refreshSettingForHint: function () {
+        TREE_SHEET_HELPER.initSetting($('#stdSectionRations')[0], rationLibObj.sectionRationsSetting);
+    },
     checkSpread: function () {
         if (!this.rationChapterSpread) {
             this.rationChapterSpread = SheetDataHelper.createNewSpread($('#stdRationChapter')[0]);
@@ -16,6 +19,7 @@ var rationLibObj = {
             this.sectionRationsSpread = SheetDataHelper.createNewSpread($('#stdSectionRations')[0]);
 
             this.sectionRationsSpread.bind(GC.Spread.Sheets.Events.CellDoubleClick, this.onRationSpreadCellDoubleClick);
+            this.refreshSettingForHint();
         }
     },
     refreshSpread: function () {
@@ -63,13 +67,27 @@ var rationLibObj = {
             showRationChapterTree([]);
         });
     },
+    setTagForHint: function (datas) {
+        let sheet = this.sectionRationsSpread.getActiveSheet();
+        sheet.suspendPaint();
+        sheet.suspendEvent();
+        for(let i = 0, len = sheet.getRowCount(); i < len; i++){
+            sheet.setTag(i, 1, '');
+        }
+        for(let i = 0, len = datas.length; i < len; i++){
+            sheet.setTag(i, 1, datas[i].hint ? datas[i].hint : '');
+        }
+        sheet.resumePaint();
+        sheet.resumeEvent();
+    },
     loadSectionRations: function (sectionID) {
         var showDatas = function (datas, setting) {
             SheetDataHelper.loadSheetHeader(setting, rationLibObj.sectionRationsSpread.getActiveSheet());
             SheetDataHelper.loadSheetData(setting, rationLibObj.sectionRationsSpread.getActiveSheet(), datas);
+            rationLibObj.setTagForHint(datas);
         };
         if (sectionID) {
-            CommonAjax.postRationLib('/rationRepository/api/getRationItems', {userId: userID, sectionID: sectionID}, function (datas) {
+            CommonAjax.postRationLib('/rationRepository/api/getRationGljItems', {userId: userID, sectionID: sectionID}, function (datas) {
                 showDatas(datas, rationLibObj.sectionRationsSetting);
             }, function () {
                 showDatas([], rationLibObj.sectionRationsSetting);
@@ -174,6 +192,7 @@ var rationLibObj = {
         }, {
             "width":220,
             "readOnly": true,
+            "showHint": true,
             "head":{
                 "titleNames":["名称"],
                 "spanCols":[1],
@@ -225,6 +244,8 @@ var rationLibObj = {
         }]
     }
 };
+
+addEventOnResize(rationLibObj.refreshSettingForHint);
 $('#stdRationTab').bind('click', function () {
     refreshSubSpread();//subSpread、jobSpread、itemSpread显示问题
     var select = $('#stdRationLibSelect');

+ 9 - 6
web/building_saas/main/js/views/sub_view.js

@@ -177,21 +177,24 @@ $("#add-content").change(function() {
     const selected = $(this).children(":selected").val();
     const characterFormatEle = $("#character-format");
     const childDisplayFormatEle = $("#child-display-format");
+    const serialTypeEle = $("#serial-type");
 
     switch (selected) {
-        case '4':
-            // 当“添加内容”是“定额子目”或“工作内容”,则“特征生成方式”灰显,不需选择;否则有效可选。
-            characterFormatEle.attr('disabled', 'disabled');
-            characterFormatEle.val(2);
-            break;
         case '5':
             // 当“添加内容”是“定额子目”或“工作内容”,则“特征生成方式”灰显,不需选择;否则有效可选。
             characterFormatEle.attr('disabled', 'disabled');
             characterFormatEle.val(2);
             // 当“添加内容”是“定额子目”,则“子目生成方式”有效可选;否则灰显,不需选择。
             childDisplayFormatEle.removeAttr('disabled');
+            serialTypeEle.val('');
+            serialTypeEle.attr('disabled', 'disabled');
             break;
+        case '4':
+            // 当“添加内容”是“定额子目”或“工作内容”,则“特征生成方式”灰显,不需选择;否则有效可选。
+            characterFormatEle.attr('disabled', 'disabled');
+            characterFormatEle.val(2);
         default:
+            serialTypeEle.removeAttr('disabled');
             childDisplayFormatEle.attr('disabled', 'disabled');
             break;
     }
@@ -204,7 +207,7 @@ $("#child-display-format").change(function() {
     // 如果是编号+定额名称则序号格式不能选择
     if (selected === '1') {
         // 默认选中数字显示模式
-        serialTypeEle.val(1);
+        serialTypeEle.val("");
         serialTypeEle.attr('disabled', 'disabled');
     } else {
         serialTypeEle.removeAttr('disabled');

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

@@ -80,7 +80,7 @@
                                     <div class="dropdown-menu" aria-labelledby="btnGroupDrop1">
                                         <a href="javascript:void(0);"  id="add-project-btn" class="dropdown-item"><i class="fa fa-cubes"></i>新建建设项目</a>
                                         <a href="javascript:void(0);"  id="add-engineering-btn" class="dropdown-item disabled"><i class="fa fa-cube"></i> 新建单项工程</a>
-                                        <a href="javascript:void(0);"  id="add-folder-btn" class="dropdown-item"><i class="fa fa-folder-o"></i>新建文件夹</a>
+                                        <a href="javascript:void(0);"  id="add-folder-btn" class="dropdown-item"><i class="fa fa-folder-o"></i> 新建文件夹</a>
                                     </div>
                                 </div>
                                 <a href="javascript:void(0);" class="btn btn-sm" id="rename-btn">重命名</a>
@@ -366,7 +366,7 @@
     <div class="modal-dialog" role="document">
         <div class="modal-content">
             <div class="modal-header">
-                <h5 class="modal-title">新建文件夹</h5>
+                <h5 class="modal-title"><i class="fa fa-folder-o"></i>新建文件夹</h5>
                 <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                     <span aria-hidden="true">&times;</span>
                 </button>

+ 14 - 15
web/building_saas/pm/js/pm_main.js

@@ -95,45 +95,44 @@ let ProjTreeSetting = {
             }
         },
         {
-            head: '计价方式',
+            head: '工程造价',
             data: 'valuationType',
             width: '10%',
             event: {
                 getText: function (html, node, text) {
                     if(node.data.projType === projectType.tender){
-                        let typeText = node.data.property.valuationType === 'bill'? '清单计价' : '定额计价';
-                        html.push(typeText);
+                        html.push('0');
                     }
                 }
             }
         },
         {
-            head: '计价规则',
-            data: 'valuationName',
-            width: '10%',
+            head: '单价文件',
+            data: 'unitPriceFile',
+            width: '15%',
             event: {
                 getText: function (html, node, text) {
                     if(node.data.projType === projectType.tender){
-                        let valuationText = node.data.property.valuationName;
-                        html.push(valuationText);
+                        let unitPriceText = node.data.property.unitPriceFile ? node.data.property.unitPriceFile.name : '';
+                        html.push(unitPriceText);
                     }
                 }
             }
         },
         {
-            head: '工程专业',
-            data: 'engineeringName',
-            width: '10%',
+            head: '费率文件',
+            data: 'feeFile',
+            width: '15%',
             event: {
                 getText: function (html, node, text) {
                     if(node.data.projType === projectType.tender){
-                        let engineeringText = node.data.property.engineeringName;
-                        html.push(engineeringText);
+                        let feeFileText = node.data.property.feeFile ? node.data.property.feeFile.name : '';
+                        html.push(feeFileText);
                     }
                 }
             }
         },
-        {
+        /*{
             head: '最近使用',
             data: 'lastDateTime',
             width: '10%',
@@ -144,7 +143,7 @@ let ProjTreeSetting = {
                     }
                 }
             }
-        },
+        },*/
         {
             head: '创建日期',
             data: 'createDateTime',