Просмотр исходного кода

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

chenshilong 7 лет назад
Родитель
Сommit
204c18450c
41 измененных файлов с 1354 добавлено и 353 удалено
  1. 1 0
      config/gulpConfig.js
  2. 2 2
      modules/all_models/std_glj.js
  3. 1 0
      modules/fee_rates/facade/fee_rates_facade.js
  4. 18 0
      modules/glj/controllers/glj_controller.js
  5. 21 3
      modules/main/controllers/bills_controller.js
  6. 10 2
      modules/main/facade/bill_facade.js
  7. 1 0
      modules/main/models/project_consts.js
  8. 1 0
      modules/main/routes/bills_route.js
  9. 4 2
      modules/pm/facade/pm_facade.js
  10. 2 2
      modules/pm/models/project_model.js
  11. 25 0
      modules/reports/controllers/rpt_tpl_controller.js
  12. 1 0
      modules/reports/routes/rpt_tpl_router.js
  13. 3 0
      modules/reports/rpt_component/helper/jpc_helper_discrete.js
  14. 34 0
      modules/reports/util/rpt_construct_data_util.js
  15. 4 1
      modules/users/controllers/user_controller.js
  16. 11 0
      modules/users/models/user_model.js
  17. 2 0
      public/web/sheet/sheet_common.js
  18. 1 0
      public/web/sheet/sheet_data_helper.js
  19. 4 0
      public/web/tree_sheet/tree_sheet_controller.js
  20. 8 0
      public/web/tree_sheet/tree_sheet_helper.js
  21. 81 106
      web/building_saas/complementary_glj_lib/js/glj.js
  22. 75 67
      web/building_saas/css/main.css
  23. 9 1
      web/building_saas/js/global.js
  24. 66 9
      web/building_saas/main/html/main.html
  25. 446 0
      web/building_saas/main/js/controllers/block_controller.js
  26. 3 0
      web/building_saas/main/js/models/cache_tree.js
  27. 1 0
      web/building_saas/main/js/models/fee_rate.js
  28. 16 0
      web/building_saas/main/js/models/main_consts.js
  29. 61 32
      web/building_saas/main/js/models/quantity_detail.js
  30. 4 0
      web/building_saas/main/js/models/ration_coe.js
  31. 4 0
      web/building_saas/main/js/models/ration_installation.js
  32. 217 68
      web/building_saas/main/js/views/character_content_view.js
  33. 3 3
      web/building_saas/main/js/views/fee_rate_view.js
  34. 80 19
      web/building_saas/main/js/views/glj_view.js
  35. 1 1
      web/building_saas/main/js/views/project_glj_view.js
  36. 62 12
      web/building_saas/main/js/views/project_view.js
  37. 4 7
      web/building_saas/main/js/views/side_tools.js
  38. 2 2
      web/building_saas/main/js/views/sub_fee_rate_views.js
  39. 8 1
      web/building_saas/main/js/views/sub_view.js
  40. 2 2
      web/building_saas/pm/js/pm_gc.js
  41. 55 11
      web/building_saas/pm/js/pm_newMain.js

+ 1 - 0
config/gulpConfig.js

@@ -109,6 +109,7 @@ module.exports = {
         'web/building_saas/main/js/main_ajax.js',
         'web/building_saas/main/js/main.js',
         'web/building_saas/main/js/controllers/project_controller.js',
+        'web/building_saas/main/js/controllers/block_controller.js',
         'web/building_saas/main/js/views/side_tools.js',
         'web/building_saas/main/js/views/std_bills_lib.js',
         'web/building_saas/main/js/views/std_ration_lib.js',

+ 2 - 2
modules/all_models/std_glj.js

@@ -27,8 +27,8 @@ const std_glj = new Schema({
     shortName: String,
     unit: String,
     adjCoe: Number,
-    materialType: String,
-    materialCoe: Number,
+    materialType: Number,   //三材类别
+    materialCoe: Number,    //三材系数
     component: [std_gljComponent]
 },{versionKey: false});
 

+ 1 - 0
modules/fee_rates/facade/fee_rates_facade.js

@@ -388,6 +388,7 @@ async function changeFeeRateFileFromOthers(jdata) {
     let newFeeRateFile = {};
     newFeeRateFile.ID = uuidV1();
     newFeeRateFile.name = data.name;
+    newFeeRateFile.userID = data.userID;
     newFeeRateFile.libName = feeRateFile.libName;
     newFeeRateFile.libID=feeRateFile.libID;
     newFeeRateFile.rootProjectID = data.rootProjectID;

+ 18 - 0
modules/glj/controllers/glj_controller.js

@@ -330,6 +330,24 @@ class GLJController extends BaseController {
 
             // 查找对应单价文件的项目工料机数据
             let unitPriceModel = new UnitPriceModel();
+            if(type ===1){//从其它项目复制,则先复制一份数据。
+                let needCopyList = await unitPriceModel.findDataByCondition({unit_price_file_id: changeUnitPriceId}, null, false);
+                if(needCopyList){
+                    // 过滤mongoose格式
+                    needCopyList = JSON.stringify(needCopyList);
+                    needCopyList = JSON.parse(needCopyList);
+                    let copyList = [];
+                    for(let n of needCopyList){
+                        delete n._id;  // 删除原有id信息
+                        delete n.id;
+                        n.unit_price_file_id = targetUnitPriceFile.id;
+                        copyList.push(n);
+                    }
+                    copyList.length>0 ? await unitPriceModel.add(copyList):'';
+                }
+            }
+
+
             let copyResult = await unitPriceModel.copyNotExist(currentUnitPriceId, targetUnitPriceFile.id,projectId);
             // 复制成功后更改project数据
             if (!copyResult) {

+ 21 - 3
modules/main/controllers/bills_controller.js

@@ -7,7 +7,7 @@ let ration_model = require('../models/ration');
 let ProjectsData = require('../../pm/models/project_model').project;
 let logger = require("../../../logs/log_helper").logger;
 let quantity_detail = require("../facade/quantity_detail_facade");
-let bill_detail = require("../facade/bill_facade");
+let bill_facade = require("../facade/bill_facade");
 let ration_glj = mongoose.model('ration_glj');
 let ration_coe = mongoose.model('ration_coe');
 let rationInstallationModel = mongoose.model('ration_installation');
@@ -140,7 +140,7 @@ module.exports = {
         try {
             let data = req.body.data;
             data = JSON.parse(data);
-            let sectionInfo= await bill_detail.getSectionInfo(data);
+            let sectionInfo= await bill_facade.getSectionInfo(data);
             result.data=sectionInfo;
         }catch (err){
             logger.err(err);
@@ -156,7 +156,7 @@ module.exports = {
         try {
             let data = req.body.data;
             data = JSON.parse(data);
-            let reorganizeResult= await bill_detail.reorganizeFBFX(data);
+            let reorganizeResult= await bill_facade.reorganizeFBFX(data);
             result.data=reorganizeResult;
         }catch (err){
             logger.err(err);
@@ -165,6 +165,24 @@ module.exports = {
         }
         res.json(result);
     },
+    pasteBlock:async function(req,res){
+        let result={
+            error:0
+        }
+        try {
+            let data = req.body.data;
+            data = JSON.parse(data);
+            let pasteResult = await bill_facade.pasteBlock(data);
+            result.data = pasteResult;
+        }catch (err){
+            logger.err(err);
+            result.error=1;
+            result.message = err.message;
+        }
+        res.json(result);
+    },
+
+
     upload: async function(req, res){
         let responseData = {
             err: 0,

+ 10 - 2
modules/main/facade/bill_facade.js

@@ -7,7 +7,7 @@ let Bills_Lib = mongoose.model('std_bills_lib_bills');
 let bill_Model = require('../models/bills').model;
 let _ = require("lodash");
 module.exports={
-   getSectionInfo : async function (data) {
+    getSectionInfo : async function (data) {
         let conditions=[];
         let fxList=[];
         let sectionInfo ={};
@@ -54,8 +54,16 @@ module.exports={
             result =await bill_Model.bulkWrite(tasks);
         }
         return result;
+    },
+    pasteBlock : async function(data){
+
+
+
+
+
+        console.log(data);
     }
-}
+};
 
 function generateBillTasks(data) {
     let tasks=[];

+ 1 - 0
modules/main/models/project_consts.js

@@ -45,4 +45,5 @@ let commonConst = {
     UT_DELETE: 'ut_delete'
 };
 
+
 module.exports = {projectConst: projectConst, commonConst: commonConst, projectConstList: projectConstList};

+ 1 - 0
modules/main/routes/bills_route.js

@@ -17,6 +17,7 @@ module.exports = function (app) {
     billsRouter.post('/multiDelete',billsController.multiDelete);
     billsRouter.post('/getSectionInfo', billsController.getSectionInfo);
     billsRouter.post('/reorganizeFBFX', billsController.reorganizeFBFX);
+    billsRouter.post('/pasteBlock', billsController.pasteBlock);
     billsRouter.post('/upload', billsController.upload);
     app.use('/bills', billsRouter);
 };

+ 4 - 2
modules/pm/facade/pm_facade.js

@@ -78,7 +78,7 @@ async function copyProject(userID, compilationID,data) {
         createProject(projectMap),
         copyProjectSetting(originalID,newProjectID),
         copyBills(newProjectID,billMap),
-        copyRations(newProjectID,billMap.uuidMaping,rationMap),
+        copyRations(newProjectID,billMap.uuidMaping,rationMap,projectGLJMap.IDMap),
         copyProjectGLJ(projectGLJMap.datas),
         commonCopy(newProjectID,originalProperty.calcProgramFile.ID,calcProgramFileID,calcProgramsModel),
         commonCopy(newProjectID,originalProperty.labourCoeFile.ID,labourCoeFileID,labourCoesModel),
@@ -153,7 +153,7 @@ async function copyBills(newProjectID,billMap) {
     return billMap.datas;
 }
 
-async function copyRations(newProjectID,billsIDMap,rationMap) {
+async function copyRations(newProjectID,billsIDMap,rationMap,projectGLJIDMap) {
     let uuidMaping = rationMap.uuidMaping;
     for(let doc of rationMap.datas){
         doc.projectID = newProjectID;
@@ -161,6 +161,8 @@ async function copyRations(newProjectID,billsIDMap,rationMap) {
         if(doc.billsItemID){
             doc.billsItemID = billsIDMap[doc.billsItemID]?billsIDMap[doc.billsItemID]:-1;
         }
+        //绑定定类型的工料机 项目工料机ID
+        doc.type==3&&doc.projectGLJID&&projectGLJIDMap[doc.projectGLJID]?doc.projectGLJID = projectGLJIDMap[doc.projectGLJID]:'';
     }
     if(rationMap.datas.length > 0){
         await insertMany(rationMap.datas,rationModel);

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

@@ -263,7 +263,7 @@ ProjectsDAO.prototype.udpateUserFiles = async function (userId, datas, callback)
                 }, {$set: {'property.unitPriceFile.name': data.updateData.name}});
             }
             else if (data.updateType === updateType.update && data.fileType === fileType.feeRateFile) {
-                await FeeRateFiles.update({userID: userId, ID: data.updateData.ID}, data.updateData);
+                await FeeRateFiles.update({ID: data.updateData.ID}, data.updateData);
                 await Projects.update({
                     userID: userId,
                     'property.feeFile.id': data.updateData.ID
@@ -279,7 +279,7 @@ ProjectsDAO.prototype.udpateUserFiles = async function (userId, datas, callback)
             }
             else if (data.updateType === updateType.delete && data.fileType === fileType.feeRateFile) {
                 data.updateData.deleteInfo = deleteInfo;
-                await FeeRateFiles.update({userID: userId, ID: data.updateData.ID}, data.updateData);
+                await FeeRateFiles.update({ID: data.updateData.ID}, data.updateData);
             }
             else throw '未知文件类型,删除失败'
         }

+ 25 - 0
modules/reports/controllers/rpt_tpl_controller.js

@@ -345,6 +345,31 @@ let mExport = {
                 callback(req, res, false, 'The report template was updated successfully!', true);
             }
         });
+    },
+    copyRptTpl: function (req, res) {
+        let params = JSON.parse(req.body.params),
+            orgRptTplId = params.orgRptTplId,
+            newID = params.newRptTplId;
+        let filter = {"ID": orgRptTplId};
+        RptTplModel.findOne(filter, '-_id').exec().then(function(baseTplRst) {
+            if (baseTplRst) {
+                let _doc = baseTplRst["_doc"];
+                _doc["ID"] = newID;
+                if (_doc["GROUP_KEY"].indexOf("(Copy)") < 0) {
+                    _doc["GROUP_KEY"] = _doc["GROUP_KEY"] + "(Copy)";
+                }
+                let rptTpl = new RptTplModel(_doc);
+                rptTpl.save(function (err, actTplRst) {
+                    if (err) {
+                        callback(req,res, "报表模板创建错误", "", null);
+                    } else {
+                        callback(req,res, false, "", newID);
+                    }
+                });
+            } else {
+                callback(req, res, 'Create report template failed!', null);
+            }
+        });
     }
 };
 

+ 1 - 0
modules/reports/routes/rpt_tpl_router.js

@@ -27,6 +27,7 @@ module.exports = function (app) {
     rptTplRouter.post('/createDftRptTpl', reportTplController.createDftRptTpl);
     rptTplRouter.post('/getRefRptTpl', reportTplController.getRefRptTpl);
     rptTplRouter.post('/updateRptTpl', reportTplController.updateRptTpl);
+    rptTplRouter.post('/copyRptTpl', reportTplController.copyRptTpl);
     rptTplRouter.post('/getCompilationList', reportTplController.getCompilationList);
     rptTplRouter.post('/getCustomizeCfg', reportTplController.getCustomerCfg);
     rptTplRouter.post('/saveCustomerCfg', reportTplController.saveCustomerCfg);

+ 3 - 0
modules/reports/rpt_component/helper/jpc_helper_discrete.js

@@ -71,6 +71,9 @@ let JpcDiscreteHelper = {
                     for (let j = 0; j < discreteArray[i][JV.PROP_DISCRETE_FIELDS].length; j++) {
                         let df = discreteArray[i][JV.PROP_DISCRETE_FIELDS][j];
                         let value = "";
+                        if (df[JV.PROP_DFT_VALUE]) {
+                            value = df[JV.PROP_DFT_VALUE];
+                        }
                         let item = JpcCommonOutputHelper.createCommonOutputWithoutDecorate(df, value, null);
                         //position
                         item[JV.PROP_AREA] = JpcAreaHelper.outputArea(df[JV.PROP_AREA], band, unitFactor, 1, 0, 1, 0, 1, 0, false, false);

+ 34 - 0
modules/reports/util/rpt_construct_data_util.js

@@ -803,6 +803,7 @@ function setupFunc(obj, prop, ownRawObj) {
     obj[prop].getProperty = ext_getPropety;
     obj[prop].getFee = ext_getFee;
     obj[prop].getPropertyByForeignId = ext_getPropertyByForeignId;
+    obj[prop].getArrayValues = ext_getArrayValues;
     obj[prop].getArrayItemByKey = ext_getArrayItemByKey;
     obj[prop].getPropertyByFlag = ext_getPropertyByFlag;
     obj[prop].getBlank = ext_getBlank;
@@ -1055,6 +1056,39 @@ function ext_getFeeRate(fee_Ids){
     return rst;
 }
 
+function ext_getArrayValues(itemKey) {
+    let rst = [], parentObj = this;
+    let dtObj = parentObj["myOwnRawDataObj"];
+    let keysArr = itemKey.split(".");
+    for (let dataItem of dtObj.data) {
+        let itemArr = [];
+        if (keysArr.length <= 2) {
+            if (dataItem[keysArr[0]] instanceof Array) {
+                if (keysArr.length === 2) {
+                    for (let item of dataItem[keysArr[0]]) {
+                        itemArr.push(item[keysArr[1]]);
+                    }
+                } else {
+                    itemArr = itemArr.concat(dataItem[keysArr[0]]);
+                }
+            } else {
+                if (keysArr.length === 2) {
+                    let subProperty = dataItem[keysArr[0]][keysArr[1]];
+                    if (subProperty instanceof Array) {
+                        itemArr = itemArr.concat(subProperty);
+                    } else {
+                        itemArr.push(subProperty);
+                    }
+                } else {
+                    itemArr.push(dataItem[keysArr[0]]);
+                }
+            }
+        }
+        rst.push(itemArr);
+    }
+    return rst;
+}
+
 function ext_getArrayItemByKey(arrayKey, itemKey, itemKeyValue, itemRstKey){
     let rst = [], parentObj = this;
     let dtObj = parentObj["myOwnRawDataObj"];

+ 4 - 1
modules/users/controllers/user_controller.js

@@ -62,7 +62,10 @@ class UserController extends BaseController {
             let condition = {ssoId: sessionUser.ssoId};
             userModel.setScene('saveInfo');
             let result = await userModel.updateUser(condition, updateData);
-
+            //更新session
+            for(let attr in sessionUser){
+                sessionUser[attr] = updateData[attr] ? updateData[attr] : sessionUser[attr];
+            }
             if (result.ok !== 1) {
                 throw '用户数据保存失败';
             }

+ 11 - 0
modules/users/models/user_model.js

@@ -151,6 +151,17 @@ class UserModel extends BaseModel {
     }
 
     /**
+     * 根据userId查找数据
+     *
+     * @param {string} ssoId
+     * @return {object}
+     */
+    async findDataById(id) {
+        let objId = mongoose.Types.ObjectId(id);
+        return await this.db.findOne({_id: objId});
+    }
+
+    /**
      * 新增用户
      *
      * @param {object} userData

+ 2 - 0
public/web/sheet/sheet_common.js

@@ -12,6 +12,7 @@ var sheetCommonObj = {
         spreadBook.options.showVerticalScrollbar = true;
         spreadBook.options.allowCopyPasteExcelStyle = false;
         spreadBook.options.allowUserDragDrop = true;
+        spreadBook.options. allowUserEditFormula = false;
         return spreadBook;
     },
 
@@ -192,6 +193,7 @@ var sheetCommonObj = {
             sheet.autoFitRow(row);
         }
     },
+    //todo
     analyzePasteData: function(setting, pastedInfo) {
         var rst = [], propId = pastedInfo.cellRange.col, preStrIdx = 0, itemObj = {};//propId = 0 to proId = pastedInfo.cellRange.col, update by zhong
         for (var i = 0; i < pastedInfo.pasteData.text.length; i++) {

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

@@ -53,6 +53,7 @@ var SheetDataHelper = {
         spread.options.allowCopyPasteExcelStyle = false;
         spread.options.allowUserDragDrop = false;
         spread.options.allowUndo = false;//that.mainSpread.commandManager().setShortcutKey(undefined, GC.Spread.Commands.Key.z, true, false, false, false); 屏蔽undo
+        spread.options. allowUserEditFormula = false;
         spread.getActiveSheet().setRowCount(3);
         return spread;
     },

+ 4 - 0
public/web/tree_sheet/tree_sheet_controller.js

@@ -144,6 +144,8 @@ var TREE_SHEET_CONTROLLER = {
                 if (this.tree.selected.upMove()) {
                     TREE_SHEET_HELPER.massOperationSheet(this.sheet, function () {
                         TREE_SHEET_HELPER.refreshTreeNodeData(that.setting, that.sheet, [that.tree.selected, that.tree.selected.nextSibling], true);
+                        TREE_SHEET_HELPER.refreshChildrenVisiable(that.sheet,that.tree,that.tree.selected,that.tree.selected.serialNo());
+                        TREE_SHEET_HELPER.refreshChildrenVisiable(that.sheet,that.tree,that.tree.selected.nextSibling,that.tree.selected.nextSibling.serialNo());
                         that.sheet.setSelection(that.tree.selected.serialNo(), sels[0].col, 1, 1);
                         if (that.event.refreshBaseActn) {
                             that.event.refreshBaseActn(that.tree);
@@ -158,6 +160,8 @@ var TREE_SHEET_CONTROLLER = {
                 if (this.tree.selected.downMove()) {
                     TREE_SHEET_HELPER.massOperationSheet(this.sheet, function () {
                         TREE_SHEET_HELPER.refreshTreeNodeData(that.setting, that.sheet, [that.tree.selected, that.tree.selected.preSibling], true);
+                        TREE_SHEET_HELPER.refreshChildrenVisiable(that.sheet,that.tree,that.tree.selected,that.tree.selected.serialNo());
+                        TREE_SHEET_HELPER.refreshChildrenVisiable(that.sheet,that.tree,that.tree.selected.preSibling,that.tree.selected.preSibling.serialNo());
                         that.sheet.setSelection(that.tree.selected.serialNo(), sels[0].col, 1, 1);
                         if (that.event.refreshBaseActn) {
                             that.event.refreshBaseActn(that.tree);

+ 8 - 0
public/web/tree_sheet/tree_sheet_helper.js

@@ -180,6 +180,14 @@ var TREE_SHEET_HELPER = {
             }
         });
     },
+    refreshChildrenVisiable:function(sheet,tree,node,row){
+        let iCount = node.posterityCount(), i, child;
+        for (i = 0; i < iCount; i++) {
+            child = tree.items[row + i + 1];
+            sheet.setRowVisible(row + i + 1, child.visible, GC.Spread.Sheets.SheetArea.viewport);
+        }
+       sheet.invalidateLayout();
+    },
     showTreeData: function (setting, sheet, tree) {
         let indent = 20;
         let levelIndent = -5;

+ 81 - 106
web/building_saas/complementary_glj_lib/js/glj.js

@@ -418,9 +418,9 @@ let repositoryGljObj = {
                                 if(me.currentGlj){
                                     me.currentGlj.component = [];
                                 }
-                                if(me.allowComponent.indexOf(rObj.gljType) !== -1){
+                               /* if(me.allowComponent.indexOf(rObj.gljType) !== -1){
                                     rObj.basePrice = 0;
-                                }
+                                }*/
                                 if(me.componentGljType.indexOf(me.currentEditingGlj.gljType) !== -1 &&
                                     !(me.currentEditingGlj.gljType === 302 && rObj.gljType === 303) && !(me.currentEditingGlj.gljType === 303 && rObj.gljType === 302)){//修改了原本是组成物的工料机
                                     //寻找所有引用了此组成物的工料机,并从组成物中删去此工料机,并重算单价
@@ -506,9 +506,9 @@ let repositoryGljObj = {
                     me.addGljObj = null;
                     rObj.component = [];
                     //如果类型为混凝土、砂浆、配合比、机械台班时,添加时填写的单价清空
-                    if(me.allowComponent.indexOf(rObj.gljType) !== -1){
+                   /* if(me.allowComponent.indexOf(rObj.gljType) !== -1){
                         rObj.basePrice = 0;
-                    }
+                    }*/
                     rObj.basePrice = !isNaN(parseFloat(rObj.basePrice)) && (rObj.basePrice && typeof rObj.basePrice !== 'undefined') ? parseFloat(rObj.basePrice) : 0;
                     addArr.push(rObj);
                 }
@@ -668,6 +668,7 @@ let repositoryGljObj = {
             let isExsit = false;
             for(let i = 0; i < me.distTypeTree.comboDatas.length; i++){
                 if(pasteObj.gljType === me.distTypeTree.comboDatas[i].text){
+                    pasteObj.gljType = me.distTypeTree.comboDatas[i].value;
                     isExsit = true;
                     reCalBasePrc = true;
                     //
@@ -685,9 +686,9 @@ let repositoryGljObj = {
                         }
                     }
                     tempObj.component = tempObj.gljType === me.distTypeTree.comboDatas[i].value ? tempObj.component : [];
-                    if(me.allowComponent.indexOf(tempObj.gljType) !== -1){
+                    /*if(me.allowComponent.indexOf(tempObj.gljType) !== -1){
                         tempObj.basePrice = tempObj.gljType === me.distTypeTree.comboDatas[i].value ? tempObj.basePrice : 0;
-                    }
+                    }*/
                     tempObj.gljType = me.distTypeTree.comboDatas[i].value;
                     tempObj.shortName = me.distTypeTree.distTypes[me.distTypeTree.prefix + tempObj.gljType].data.shortName;
                     break;
@@ -804,125 +805,99 @@ let repositoryGljObj = {
         }
     },
     onClipboardPasted: function(e, info) {
-      //  if(info.pasteData.text.trim().length > 0){
-            let me = repositoryGljObj;
-            let updateArr = [], addArr = [];
-            let items = sheetOpr.analyzePasteData(me.setting, info);
-            let beginRow = info.cellRange.row, endRow = info.cellRange.row + info.cellRange.rowCount - 1,//复制的起始行数和结束行数
-                maxRow = me.currentCache.length - 1,//当前数据最大行数
-                updateBasePrcArr = [] ,
-                updateCount, resumeArr = [];
-            if(endRow <= maxRow){
-                //updateItems = items;
-                for(let i = 0; i < items.length; i++){
-                    let updateObj = me.validUpdateObj(items[i], info.cellRange.row + i);
-                    if(updateObj && typeof updateObj.updateGlj !== 'undefined' && updateObj.updateGlj.length > 0){
-                        //updateArr = updateObj.updateGlj;
-                        updateArr = updateArr.concat(updateObj.updateGlj);
-                        if(typeof updateObj.updateBasePrcArr !== 'undefined'){
-                            updateBasePrcArr = updateBasePrcArr.concat(updateObj.updateBasePrcArr);
-                         }
-                    }
-                    else{
-                        resumeArr.push(info.cellRange.row + i);
+        //  if(info.pasteData.text.trim().length > 0){
+        let me = repositoryGljObj;
+        let updateArr = [], addArr = [];
+        let items = sheetOpr.analyzePasteData(me.setting, info);
+        let beginRow = info.cellRange.row, endRow = info.cellRange.row + info.cellRange.rowCount - 1,//复制的起始行数和结束行数
+            maxRow = me.currentCache.length - 1,//当前数据最大行数
+            updateBasePrcArr = [] ,
+            updateCount, resumeArr = [];
+        if(endRow <= maxRow){
+            //updateItems = items;
+            for(let i = 0; i < items.length; i++){
+                let updateObj = me.validUpdateObj(items[i], info.cellRange.row + i);
+                if(updateObj && typeof updateObj.updateGlj !== 'undefined' && updateObj.updateGlj.length > 0){
+                    //updateArr = updateObj.updateGlj;
+                    updateArr = updateArr.concat(updateObj.updateGlj);
+                    if(typeof updateObj.updateBasePrcArr !== 'undefined'){
+                        updateBasePrcArr = updateBasePrcArr.concat(updateObj.updateBasePrcArr);
                     }
                 }
             }
-            else if(beginRow <= maxRow && endRow > maxRow){
-                updateCount = maxRow - beginRow + 1;
-                for(let i = 0; i < updateCount; i++){
-                    let updateObj = me.validUpdateObj(items[i], info.cellRange.row + i);
-                    if(updateObj && typeof updateObj.updateGlj !== 'undefined'){
-                        //updateArr = updateObj.updateGlj;
-                        updateArr = updateArr.concat(updateObj.updateGlj);
-                        if(typeof updateObj.updateBasePrcArr !== 'undefined'){
-                            updateBasePrcArr = updateBasePrcArr.concat(updateObj.updateBasePrcArr);
-                        }
-                    }
-                    else{
-                        resumeArr.push(info.cellRange.row + i);
+        }
+        else if(beginRow <= maxRow && endRow > maxRow){
+            updateCount = maxRow - beginRow + 1;
+            for(let i = 0; i < updateCount; i++){
+                let updateObj = me.validUpdateObj(items[i], info.cellRange.row + i);
+                if(updateObj && typeof updateObj.updateGlj !== 'undefined'){
+                    //updateArr = updateObj.updateGlj;
+                    updateArr = updateArr.concat(updateObj.updateGlj);
+                    if(typeof updateObj.updateBasePrcArr !== 'undefined'){
+                        updateBasePrcArr = updateBasePrcArr.concat(updateObj.updateBasePrcArr);
                     }
                 }
-                if(info.cellRange.colCount === me.setting.header.length -1){
-                    for(let i = updateCount ; i < items.length; i++){
-                        if(me.isValidObj(items[i])){
-                            items[i].component = [];
-                            //类型为混凝土、砂浆、配合比、机械时,基价只能组成物计算
-                            if(me.allowComponent.indexOf(items[i].gljType) !== -1){
-                                items[i].basePrice = 0;
-                            }
-                            addArr.push(items[i]);
-                        }
-                        else{
-                            resumeArr.push(info.cellRange.row + i);
-                        }
+            }
+            if(info.cellRange.colCount === me.setting.header.length -1){
+                for(let i = updateCount ; i < items.length; i++){
+                    if(me.isValidObj(items[i])){
+                        items[i].component = [];
+                        //类型为混凝土、砂浆、配合比、机械时,基价只能组成物计算
+                        /* if(me.allowComponent.indexOf(items[i].gljType) !== -1){
+                         items[i].basePrice = 0;
+                         }*/
+                        addArr.push(items[i]);
                     }
                 }
-                else{
-                    for(let i = updateCount ; i < items.length; i++){
-                        resumeArr.push(info.cellRange.row + i);
+            }
+        }
+        else{
+            if(info.cellRange.colCount === me.setting.header.length -1){
+                for(let i = 0; i < items.length; i++){
+                    if(me.isValidObj(items[i])){
+                        items[i].component = [];
+                        /*if(me.allowComponent.indexOf(items[i].gljType) !== -1){
+                         items[i].basePrice = 0;
+                         }*/
+                        addArr.push(items[i]);
                     }
                 }
             }
-            else{
-                if(info.cellRange.colCount === me.setting.header.length -1){
-                    for(let i = 0; i < items.length; i++){
-                        if(me.isValidObj(items[i])){
-                            items[i].component = [];
-                            if(me.allowComponent.indexOf(items[i].gljType) !== -1){
-                                items[i].basePrice = 0;
-                            }
-                            addArr.push(items[i]);
+        }
+        //repaint
+        for(let i = 0; i < info.cellRange.rowCount; i++){
+            resumeArr.push(info.cellRange.row + i);
+        }
+        if(resumeArr.length > 0){
+            let sheet = me.workBook.getActiveSheet();
+            sheet.suspendPaint();
+            for(let i = 0; i < resumeArr.length ; i++){
+                if(resumeArr[i] < me.currentCache.length){
+                    for(let col = 0; col < me.setting.header.length -1; col++){
+                        if(me.setting.header[col].dataCode === 'gljType'){
+                            let gljType = me.currentCache[resumeArr[i]][me.setting.header[col].dataCode];
+                            sheet.setValue(resumeArr[i], col, me.distTypeTree.distTypes["gljType" + gljType].data.fullName);
                         }
                         else{
-                            resumeArr.push(info.cellRange.row + i);
+                            sheet.setValue(resumeArr[i], col, me.currentCache[resumeArr[i]][me.setting.header[col].dataCode]);
                         }
                     }
                 }
                 else{
-                    for(let i = 0; i < items.length; i++){
-                        resumeArr.push(info.cellRange.row + i);
+                    for(let col = 0; col < me.setting.header.length - 1; col++){
+                        sheet.setValue(resumeArr[i], col, '', GC.Spread.Sheets.SheetArea.viewport);
                     }
                 }
             }
-            //repaint
-            if(resumeArr.length > 0){
-                let sheet = me.workBook.getActiveSheet();
-                sheet.suspendPaint();
-                for(let i = 0; i < resumeArr.length ; i++){
-                    if(resumeArr[i] < me.currentCache.length){
-                        for(let col = 0; col < me.setting.header.length -1; col++){
-                            if(me.setting.header[col].dataCode === 'gljType'){
-                                let gljType = me.currentCache[resumeArr[i]][me.setting.header[col].dataCode];
-                                sheet.setValue(resumeArr[i], col, me.distTypeTree.distTypes["gljType" + gljType].data.fullName);
-                            }
-                            else{
-                                sheet.setValue(resumeArr[i], col, me.currentCache[resumeArr[i]][me.setting.header[col].dataCode]);
-                            }
-                        }
-                    }
-                    else{
-                        for(let col = 0; col < me.setting.header.length - 1; col++){
-                            sheet.setValue(resumeArr[i], col, '', GC.Spread.Sheets.SheetArea.viewport);
-                        }
-                    }
-                }
-                sheet.resumePaint();
-            }
-            if (updateArr.length > 0 || addArr.length > 0) {
-                me.mixUpdateRequest(updateArr, addArr, []);
-            }
-            if(updateBasePrcArr.length > 0 && me.rationLibs.length > 0){
-                me.updateRationBasePrcRq(updateBasePrcArr);
-            }
-       // }
-      /*  else{//解决bug: 从原本的sheet复制一行数据,会两次调用粘贴事件函数..,todo:找出原因
-            for(let i = 0, len = info.cellRange.rowCount; i < len; i++){
-                for(let col = 0; col < 6; col++){
-                    info.sheet.setValue(info.cellRange.row + i, col, '');
-                }
-            }
-        }*/
+            sheet.resumePaint();
+        }
+        if (updateArr.length > 0 || addArr.length > 0) {
+            me.mixUpdateRequest(updateArr, addArr, []);
+        }
+        if(updateBasePrcArr.length > 0 && me.rationLibs.length > 0){
+            me.updateRationBasePrcRq(updateBasePrcArr);
+        }
+        // }
     },
     updateRationBasePrcRq: function (basePrcArr) {
         CommonAjax.post('complementartGlj/api/updateRationBasePrc', {basePrcArr: basePrcArr}, function (rstData) {

+ 75 - 67
web/building_saas/css/main.css

@@ -8,10 +8,10 @@ body {
     font-size: 0.9rem
 }
 .btn.disabled, .btn:disabled {
-  color:#999
+    color:#999
 }
 .btn-link:focus, .btn-link:hover{
-  text-decoration: none
+    text-decoration: none
 }
 /*自定义css*/
 .header {
@@ -28,14 +28,14 @@ body {
     line-height: inherit
 }
 .header .header-logo sup{
-  font-size:10px;
-  top:-1.2em
+    font-size:10px;
+    top:-1.2em
 }
 .top-msg{
-  position: fixed;
-  top:0;
-  width:100%;
-  z-index: 999
+    position: fixed;
+    top:0;
+    width:100%;
+    z-index: 999
 }
 .main {
     position: relative;
@@ -61,38 +61,38 @@ body {
     text-decoration: none;
 }
 .main-nav .nav a.active {
-    border: 1px solid #ff6501;
+    border: 2px solid #ff6501;
     border-right: 1px solid #fff;
     background: #fff;
     color: #333
 }
 .main-nav .nav-tabs{
-  border-bottom: none
+    border-bottom: none
 }
 .poj-manage .col-auto{
-  background:#f7f7f9
+    background:#f7f7f9
 }
 .poj-cate {
-  width:58px
+    width:58px
 }
 .poj-cate .nav-pills .nav-link{
-  border-radius: 0;
-  font-size: 24px;
-  color: #007bff
+    border-radius: 0;
+    font-size: 24px;
+    color: #007bff
 }
 .poj-cate .nav-pills .nav-link:hover{
-  color:#0056b3
+    color:#0056b3
 }
 .poj-cate .nav-pills .nav-link.active, .nav-pills .show > .nav-link{
-  background-color: #6c757d;
-  color:#fff
+    background-color: #6c757d;
+    color:#fff
 }
 .pm-side{
-  position: fixed;
-  left:0
+    position: fixed;
+    left:0
 }
 .pm-content{
-  padding-left:58px
+    padding-left:58px
 }
 .content {
     border-left: 1px solid #ccc;
@@ -100,11 +100,12 @@ body {
     background: #fff
 }
 .toolsbar,.toolsbar-f {
-  border-bottom: 1px solid #ccc
+    border-bottom: 1px solid #ccc
 }
 .tools-btn {
     height: 30px;
     line-height: 30px;
+    background:#fff
 }
 .toolsbar .tools-btn.btn:hover,.toolsbar-f .tools-btn.btn:hover {
     background: #f7f7f9;
@@ -114,23 +115,23 @@ body {
     overflow-y: hidden;
 }
 .main-data-top,.main-data-full{
-  overflow: hidden;
-  width:100%
+    overflow: hidden;
+    width:100%
 }
 .main-content.col-lg-8{
-  width:66.666667%
+    width:66.666667%
 }
 .main-content.col-lg-12{
-  width:100%
+    width:100%
 }
 .main-side.col-lg-4{
-  width: 33.333333%;
+    width: 33.333333%;
 }
 .main-side.col-lg-0{
-  width:0%;
+    width:0%;
 }
 .sidebar-bottom,.sidebar-bottom .col-lg-6,.sidebar-bottom .col-lg-12 {
-  height:300px
+    height:300px
 }
 .top-content, .fluid-content {
     overflow: auto;
@@ -145,8 +146,15 @@ body {
     border-radius: 0;
     padding: 0.2em 0.5em
 }
+.bottom-tools {
+    height: 30px;
+    line-height: 30px;
+    background:#F1F1F1;
+    bottom:30px;
+    left:5px;
+}
 .side-tabs .nav-tabs .nav-item {
-  z-index: 999
+    z-index: 999
 }
 .side-tabs .nav-tabs {
     border-bottom: none;
@@ -159,7 +167,7 @@ body {
     z-index: 999
 }
 .bottom-content .nav-tabs .nav-link.active {
-    border:1px solid #ff6501;
+    border:2px solid #ff6501;
     border-bottom: 1px solid #fff
 }
 .side-tabs .nav-tabs .nav-link.active {
@@ -274,82 +282,82 @@ body {
     overflow: auto;
 }
 .print-toolsbar{
-  padding:5px
+    padding:5px
 }
 .print-toolsbar .panel {
-  display:inline-block;
-  vertical-align:top;
-  background:#f7f7f9
+    display:inline-block;
+    vertical-align:top;
+    background:#f7f7f9
 }
 .print-toolsbar .panel .panel-foot{
-  text-align: center;
-  font-size: 12px
+    text-align: center;
+    font-size: 12px
 }
 .print-list {
-  border-right:1px solid #ccc
+    border-right:1px solid #ccc
 }
 .print-list .form-list {
-  overflow: auto
+    overflow: auto
 }
 .print-list .list-tools{
-  height:50px;
-  padding:10px 0;
-  border-bottom:1px solid #f2f2f2
+    height:50px;
+    padding:10px 0;
+    border-bottom:1px solid #f2f2f2
 }
 .pageContainer {
-  background: #ededed;
-  text-align: center
+    background: #ededed;
+    text-align: center
 }
 .pageContainer .page{
-  border:9px solid transparent;
-  display: inline-block;
+    border:9px solid transparent;
+    display: inline-block;
 }
 .pageContainer .page img{
-  width:inherit;
-  height: inherit;
+    width:inherit;
+    height: inherit;
 }
 .modal-auto-height {
-  height: 400px;
-  overflow-y: auto;
+    height: 400px;
+    overflow-y: auto;
 }
 .modal-toolbar + .modal-auto-height{
-  height:369px
+    height:369px
 }
 .modal-fixed-height {
-  height: 400px;
-  overflow-y: hidden;
+    height: 400px;
+    overflow-y: hidden;
 }
 .sidebar-tools-bar {
-  background:#fff
+    background:#fff
 }
 .side-search-box{
-  background:#fff;
-  border-bottom:1px solid #ddd
+    background:#fff;
+    border-bottom:1px solid #ddd
 }
 .navbar-crumb span{
-  max-width: 200px
+    max-width: 200px
 }
 .dropdown-item{
-  color:#007bff
+    color:#007bff
 }
 .dropdown-item:hover{
-  color:#0056b3
+    color:#0056b3
 }
 .dropdown-item.disabled, .dropdown-item:disabled{
-  pointer-events:none
+    pointer-events:none
 }
 .tools-symbol{
-  width:450px
+    width:450px
 }
 .tools-symbol p{
-  margin: 0
+    margin: 0
 }
 .tools-symbol a.btn{
-  font-size: .95rem;
-  width:26px;
-  padding: 0;
-  height:26px;
+    font-size: .95rem;
+    width:26px;
+    padding: 0;
+    height:26px;
 }
 .custom-file-input:lang(zh) ~ .custom-file-label::after {
     content: "浏览";
-}
+}

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

@@ -85,4 +85,12 @@ function getLocalCache(key) {
     }
 
     return storage.getItem(key);
-}
+}
+
+function removeLocalCache(key) {
+    const storage = window.localStorage;
+    if (!storage || key === '') {
+        return null;
+    }
+    return storage.removeItem(key);
+}

+ 66 - 9
web/building_saas/main/html/main.html

@@ -56,9 +56,9 @@
               <!--造价书-->
               <div class="toolsbar px-1 d-flex justify-content-between">
                   <div class="tools-btn btn-group align-top">
-                    <a href="" class="btn btn-sm" title="复制"><i class="fa fa-files-o" aria-hidden="true"></i></a>
-                    <a href="" class="btn btn-sm" title="剪切"><i class="fa fa-scissors" aria-hidden="true"></i></a>
-                    <a href="" class="btn btn-sm" title="粘贴"><i class="fa fa-clipboard" aria-hidden="true"></i></a>
+                    <a href="javascript:void(0)" class="btn btn-sm" title="复制" ><i class="fa fa-files-o" aria-hidden="true"></i></a>
+                    <a href="javascript:void(0)" class="btn btn-sm" title="剪切"><i class="fa fa-scissors" aria-hidden="true"></i></a>
+                    <a href="javascript:void(0)" class="btn btn-sm" title="粘贴"><i class="fa fa-clipboard" aria-hidden="true"></i></a>
                  <!--   <a href="javascript:void(0)" class="btn btn-sm" id="insert" title="插入"><i class="fa fa-sign-in" aria-hidden="true"></i></a>-->
                     <a href="javascript:void(0)" class="btn btn-sm" id="delete" title="删除"><i class="fa fa-remove" aria-hidden="true"></i></a>
                     <a href="javascript:void(0)" class="btn btn-sm" id="upLevel" title="升级"><i class="fa fa-arrow-left" aria-hidden="true"></i></a>
@@ -66,7 +66,7 @@
                     <a href="javascript:void(0)" class="btn btn-sm" id="downMove" title="下移"><i class="fa fa-arrow-down" aria-hidden="true"></i></a>
                     <a href="javascript:void(0)" class="btn btn-sm" id="upMove" title="上移"><i class="fa fa-arrow-up" aria-hidden="true"></i></a>
                     <span>
-                      <a href="" class="btn btn-sm" data-toggle="dropdown"><b data-toggle="tooltip" data-placement="bottom">显示至...</b></a>
+                      <a href="" data-toggle="dropdown"><span data-toggle="tooltip" data-placement="bottom" title="显示至...">显示至...</span></a>
                       <div class="dropdown-menu dropdown-menu-left" style="min-width: 6.5rem">
                       <a class="dropdown-item" href="javascript:void(0);" style="padding: 0rem 1.5rem" id="displayDXFY">大项费用</a>
                       <a class="dropdown-item" href="javascript:void(0);" style="padding: 0rem 1.5rem" id="displayFB1">一级分部</a>
@@ -83,7 +83,6 @@
                       <% } else { %>
                       <a href="javascript:void(0)" class="btn btn-sm" name="lockBills"  title="锁定清单"> <i class="fa fa-lock" aria-hidden="true"></i> 锁定清单</a>
                       <% } %>
-
                   </div>
                   <div class="tools-btn">
                       <a href="javacript:void(0);" data-toggle="modal" data-target="#column" class="btn btn-sm"><i class="fa fa-table" aria-hidden="true"></i> 列设置</a>
@@ -142,12 +141,32 @@
                                       <div class="main-data-bottom ovf-hidden" style="display: none" id="comments">
                                           <textarea class="form-control" rows="8" readonly=""></textarea>
                                       </div>
-                                      <div id="tzjnrCon" class="main-data-bottom">
-                                          <div class="main-data-bottom ovf-hidden" style="width: 33%; float: left;" id="jobSpread">
+                                      <div id="tzjnrCon" class="main-data-bottom" style="background: #F1F1F1">
+                                          <div class="col-4" style="width: 33%; float: left; margin: 0; padding:0;">
+                                              <div class="main-data-bottom ovf-hidden" id="jobSpread">
+                                              </div>
+                                              <!--工具栏-->
+                                              <div class="bottom-tools btn-group position-absolute">
+                                                  <a href="javascript:void(0);" id="jobInsert" class="btn btn-sm disabled" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="插入"><i class="fa fa-sign-in" aria-hidden="true"></i></a>
+                                                  <a href="javascript:void(0);" id="jobAdd" class="btn btn-sm " data-toggle="tooltip" data-placement="bottom" title="" data-original-title="添加"><i class="fa fa-plus" aria-hidden="true"></i></a>
+                                                  <a href="javascript:void(0);" id="jobDel" class="btn btn-sm disabled" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="删除"><i class="fa fa-remove" aria-hidden="true"></i></a>
+                                                  <a href="javascript:void(0);" id="jobDown" class="btn btn-sm disabled" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="下移"><i class="fa fa-arrow-down" aria-hidden="true"></i></a>
+                                                  <a href="javascript:void(0);" id="jobUp" class="btn btn-sm disabled" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="上移"><i class="fa fa-arrow-up" aria-hidden="true"></i></a>
+                                              </div>
                                           </div>
-                                          <div class="main-data-bottom ovf-hidden" style="width: 33%; float: left;" id="itemSpread">
+                                          <div class="col-4" style="width: 33%; float: left; margin: 0; padding:0;">
+                                              <div class="main-data-bottom ovf-hidden"  id="itemSpread">
+                                              </div>
+                                              <!--工具栏-->
+                                              <div class="bottom-tools btn-group position-absolute">
+                                                  <a href="javascript:void(0);" id="itemInsert" class="btn btn-sm disabled" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="插入"><i class="fa fa-sign-in" aria-hidden="true"></i></a>
+                                                  <a href="javascript:void(0);" id="itemAdd" class="btn btn-sm " data-toggle="tooltip" data-placement="bottom" title="" data-original-title="添加"><i class="fa fa-plus" aria-hidden="true"></i></a>
+                                                  <a href="javascript:void(0);" id="itemDel" class="btn btn-sm disabled" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="删除"><i class="fa fa-remove" aria-hidden="true"></i></a>
+                                                  <a href="javascript:void(0);" id="itemDown" class="btn btn-sm disabled" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="下移"><i class="fa fa-arrow-down" aria-hidden="true"></i></a>
+                                                  <a href="javascript:void(0);" id="itemUp" class="btn btn-sm disabled" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="上移"><i class="fa fa-arrow-up" aria-hidden="true"></i></a>
+                                              </div>
                                           </div>
-                                          <div id="add-rule" style="width: 33%;float: left;background: #EFEFEF; height: 100%;display: none; padding-left: 8px;">
+                                          <div id="add-rule" style="width: 34%;float: left;background: #EFEFEF; height: 100%;display: none; padding-left: 8px;">
                                               <p style="text-align: center">添加规则</p>
                                               <p>
                                                   <label class="title">添加位置:</label>
@@ -1053,6 +1072,43 @@
             </div>
         </div>
     </div>
+
+    <!--弹出 粘帖位置选择-->
+    <div class="modal fade" id="pastePosition" data-backdrop="static">
+        <div class="modal-dialog" role="document">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <h5 class="modal-title">粘帖位置选择</h5>
+                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                        <span aria-hidden="true">&times;</span>
+                    </button>
+                </div>
+                <div class="modal-body">
+                    <div class="form-group">
+                        <label >插入为选定节点的:</label>
+                        <div>
+                            <div class="form-check form-check-inline">
+                                <input class="form-check-input" type="radio" name="pastePositionRadio" id="next_node" value="next">
+                                <label class="form-check-label" for="next_node">后项</label>
+                            </div>
+                            <div class="form-check form-check-inline">
+                                <input class="form-check-input" type="radio" name="pastePositionRadio" id="pre_node" value="pre">
+                                <label class="form-check-label" for="pre_node">前项</label>
+                            </div>
+                            <div class="form-check form-check-inline">
+                                <input class="form-check-input" type="radio" name="pastePositionRadio" id="sub_node" value="sub">
+                                <label class="form-check-label" for="sub_node">子项</label>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
+                    <button class="btn btn-primary" id="paste_confirm">确定</button>
+                </div>
+            </div>
+        </div>
+    </div>
         <!-- JS. -->
         <script type="text/javascript" src="/lib/spreadjs/sheets/gc.spread.sheets.all.10.0.1.min.js"></script>
 
@@ -1153,6 +1209,7 @@
         <script type="text/javascript" src="/web/building_saas/main/js/main_ajax.js"></script>
         <script type="text/javascript" src="/web/building_saas/main/js/main.js"></script>
         <script type="text/javascript" src="/web/building_saas/main/js/controllers/project_controller.js"></script>
+        <script type="text/javascript" src="/web/building_saas/main/js/controllers/block_controller.js"></script>
         <script type="text/javascript" src="/web/building_saas/main/js/views/side_tools.js"></script>
         <script type="text/javascript" src="/web/building_saas/main/js/views/std_bills_lib.js"></script>
         <script type="text/javascript" src="/web/building_saas/main/js/views/std_ration_lib.js"></script>

+ 446 - 0
web/building_saas/main/js/controllers/block_controller.js

@@ -0,0 +1,446 @@
+/**
+ * Created by zhang on 2018/5/10.
+ */
+let BlockController = {
+    datas:[],
+    copyBtnDisable:function (selected) {
+        if(this.isDXFYorMainEq(selected)){
+            return true;
+        }
+        if(selected.sourceType == ModuleNames.ration && selected.data.type == rationType.install){
+            return true;
+        }
+        return false;
+    },
+    pasteBtnDisable:function (selected) {
+        let blockData = this.getBlockData();
+        let Bills = projectObj.project.Bills;
+        if(this.isDXFYorMainEq(selected)){
+            return true;
+        }
+        if(blockData == null){
+            return true;
+        }
+        if(blockData.firstNodeType != blockType.RATION && blockData.isFBFX !=  Bills.isFBFX(selected)){//除了复制定额外,焦点行和复制的块不是来自同一个地方(分部分项工其它)
+            return true;
+        }
+        if(selected.sourceType == Bills.getSourceType() && selected.data.type == billType.FX && blockData.firstNodeType == blockType.FB){//焦点行是分项,复制块的第一层是分部,则无效。
+            return true;
+        }
+        if(blockData.firstNodeType == blockType.RATION && selected.sourceType == Bills.getSourceType()){ //复制的是定额/量价/工料机、焦点行是分部/清单父项则无效
+            if( selected.data.type == billType.FB ){
+                return true;
+            }
+            if(MainTreeCol.readOnly.billsParent(selected)){
+                return true;
+            }
+        }
+        if(blockData.firstNodeType != blockType.RATION && selected.sourceType == ModuleNames.ration){
+            return true;
+        }
+        return false;
+    },
+    isDXFYorMainEq:function (node) {//焦点行是大项费用或定额下的主材设备
+        if(node.sourceType == ModuleNames.bills && node.data.type == billType.DXFY){//焦点行是大项费用则无效;
+            return true;
+        }
+        if(node.sourceType == ModuleNames.ration_glj){// 焦点行是定额下的主材设备则无效;
+            return true;
+        }
+        return false;
+    },
+
+    getBlockData:function () {
+        let blockString =getLocalCache('project_block');
+        if(blockString !=null){
+            return JSON.parse(blockString);
+        }
+        return null;
+    },
+
+    copyBlock:function (selected) {
+        let startTime = +new Date();
+        let blockOjb = {
+            compilationID:projectInfoObj.projectInfo.compilation
+        };
+        if(selected.sourceType == projectObj.project.Bills.getSourceType()){
+            blockOjb.firstNodeType = selected.data.type;
+        }else if(selected.sourceType == projectObj.project.Ration.getSourceType()){
+            blockOjb.firstNodeType = blockType.RATION;
+        }
+        blockOjb.isFBFX = projectObj.project.Bills.isFBFX(selected);
+        let ration_glj_Map = _.groupBy(projectObj.project.ration_glj.datas, 'rationID');
+        blockOjb.data = this.getNodeDatas(selected,ration_glj_Map);
+        let getDataTime = +new Date();
+        console.log(`复制所用时间——${getDataTime - startTime}`);
+        blockOjb.copyTime = +new Date();//设置复制时间,可以用来做过期处理
+        setLocalCache('project_block',JSON.stringify(blockOjb));
+        let endTime = +new Date();
+        console.log(`复制所用时间——${endTime - startTime}`);
+    },
+    getNodeDatas : function (node,ration_glj_Map) {
+        let data = node.data;
+        data.sourceType =  node.sourceType;
+        if(node.sourceType == projectObj.project.Bills.getSourceType()){
+            data.quantity_details = projectObj.project.quantity_detail.getDetailByBillID(data.ID);
+        }
+        if(node.sourceType == projectObj.project.Ration.getSourceType()){
+            if(node.data.type == rationType.install){ //如果是生成的安装增加费,则跳过
+                return null;
+            }
+            let gljList = ration_glj_Map[data.ID]?ration_glj_Map[data.ID]:[];//gljOprObj.filterGljByRation(node.data, datas);
+            gljList = gljOprObj.combineWithProjectGlj(gljList,false);
+            data.ration_gljs = gljList;
+            data.ration_coes = projectObj.project.ration_coe.getCoeByRationID(data.ID);
+            data.ration_installations =  projectObj.project.ration_installation.getInstallationByRationID(data.ID);
+            data.quantity_details = projectObj.project.quantity_detail.getDetailByRationID(data.ID);
+        }else if(node.children.length>0){
+            let children = [];
+            for(let c of node.children){
+                let tem_data = this.getNodeDatas(c,ration_glj_Map);
+                tem_data?children.push(tem_data):'';
+            }
+            data.children = children;
+        }
+        return data;
+    },
+    pasteBlock:function (selected) {
+        let blockData = this.getBlockData();
+        let position = this.initOptionDiv(selected,blockData);
+        if(position == null){
+            return;
+        }
+        this.confirmPaste(blockData,selected,position);
+        //do paste
+    },
+
+    initOptionDiv:function (selected,blockData) {
+        let Bills = projectObj.project.Bills;
+        if( blockData.firstNodeType == blockType.RATION){//如果剪切板中是复制的定额块
+            if(selected.sourceType == ModuleNames.ration && selected.data.type != rationType.install ){//焦点行是定额/量价/工料机,则粘贴为后项
+                return "next";
+            }
+            if(isFXorBX(selected)||(selected.sourceType === Bills.getSourceType()&& selected.source.children.length == 0)){//焦点行是分项/叶子清单,且无基数计算,则粘贴到分项/叶子清单下
+                if(selected.data.calcBase ==null||selected.data.calcBase ==undefined|| selected.data.calcBase == ""){//无基数计算
+                    return "sub";
+                }
+            }
+        }
+
+        //设置选项的初始值
+        setRadioProp('next_node',{checked:true,disabled:false});
+        setRadioProp('pre_node',{checked:false,disabled:false});
+        if(Bills.isFBFX(selected)){//  (2.1)、焦点行属于“分部分项工程”:
+            //复制块的第一层、焦点行的类型都是“分部”
+            if(blockData.firstNodeType == blockType.FB && isFB(selected)){
+                //默认为当前行的后项,可选前项、子项。
+                setRadioProp('sub_node',{checked:false,disabled:false});
+            }
+            //复制块的第一层、焦点行的类型都是“分项”或补项
+            if(blockIsFXorBX(blockData.firstNodeType) && isFXorBX(selected)){
+                //默认为当前行的后项,可选前项,子项灰显不可选。
+                setRadioProp('sub_node',{checked:false,disabled:true});
+            }
+            //复制块的第一层是分项,焦点行是分部,且分部下无子项或者子项是分项
+            if(blockIsFXorBX(blockData.firstNodeType)&& isFB(selected)){
+                if(selected.children.length == 0 || isFXorBX(selected.children[0])){
+                    return 'sub';//不弹出选择窗口,直接粘贴为子项。
+                }
+            }
+        }else {//焦点行不属于“分部分项工程”
+            if(blockData.firstNodeType == blockType.BILL &&selected.sourceType == Bills.getSourceType()){//如果剪切板中是从“分部分项工程”以外复制的清单块
+                if(selected.children.length==0 || selected.children[0].sourceType == Bills.getSourceType()){//焦点行没有子项,或者子项是清单,判断是否有基数计算
+                    if(selected.data.calcBase && selected.data.calcBase!=""){//如果焦点行有基数计算,则子项灰显不可选。
+                        setRadioProp('sub_node',{checked:false,disabled:true});
+                    }else{//如果焦点行没有基数计算,则子项可选。
+                        setRadioProp('sub_node',{checked:false,disabled:false});
+                    }
+                }else {
+                    setRadioProp('sub_node',{checked:false,disabled:true});
+                }
+            }
+        }
+        $("#pastePosition").modal({show:true});
+        return null;
+
+       function setRadioProp(id,options) {
+           $("#"+id).prop("checked",options.checked);
+           $("#"+id).prop("disabled",options.disabled);
+       }
+
+       function isFB(selected) {
+           return selected.sourceType == Bills.getSourceType() && selected.data.type == billType.FB;
+       }
+
+       function isFXorBX(selected) {//是分项或者补项
+            if(selected.sourceType == Bills.getSourceType()){
+                return   selected.data.type == billType.FX || selected.data.type == billType.BX;
+            }
+            return false;
+       }
+       function blockIsFXorBX(type) {
+           return type == blockType.FX||blockType.BX;
+       }
+
+    },
+    /**
+     * @param blockData
+     * @param selected
+     * @param position next/pre/sub
+     */
+    confirmPaste:function (blockData,selected,position) {
+        let Bills = projectObj.project.Bills;
+        let parent = null,next = null,pre = null;
+        let updateData = [],billUpdate = null;
+        let billsIDMap = {};//用来做新旧ID映射
+        if(blockData.compilationID != projectInfoObj.projectInfo.compilation){//如果编办不一样,不能复制
+            alert("编办不一致,不能粘贴!");
+            return;
+        }
+        if(position == 'next'){ //插入为选中节点的后项,即选中节点为前项
+            parent = selected.parent;
+            next = selected.nextSibling;
+            pre = selected;
+        }
+        if(position == 'pre'){//插入为选中节点的前项,即选中节点为后项
+            parent = selected.parent;
+            next = selected;
+            pre = selected.preSibling;
+        }
+        if(position == 'sub'){//即选中节点为父项
+            parent = selected;
+            pre = selected.lastChild();
+        }
+        let parentID = parent?parent.getID():-1;
+        let nextID = next?next.getID():-1;
+        if(blockData.firstNodeType == blockType.RATION){ //复制的是定额,需根据新的父项信息和工程量明细计算工程量
+            blockData.data.billsItemID = parentID;
+            let billsQuantity = scMathUtil.roundForObj(parent.data.quantity,getDecimal("quantity",parent));
+            this.calcRationQuantityAndContain(billsQuantity,blockData.data);
+            //如果粘贴位置不属于分部分项工程,或者不是安装工程,则把安装增加费内容置空
+            if(!Bills.isFBFX(parent)|| projectInfoObj.projectInfo.property.engineering!=engineeringType.BUILD_IN){
+                blockData.data.ration_installations = [];
+            }
+            //计算序列号
+            this.calcRationSerialNo(parentID,blockData,updateData,pre,next);
+        }else {
+            blockData.data.ParentID = parentID;
+            blockData.data.NextSiblingID=nextID;
+            if(pre){
+                billUpdate = {type:blockData.data.sourceType,query:{ID:pre.getID()},doc:{NextSiblingID:blockData.data.ID}};
+            }
+        }
+        let dataMap = this.preparePasteData(blockData.data,billsIDMap);
+        if(billUpdate){
+            billUpdate.doc.NextSiblingID = billsIDMap[billUpdate.doc.NextSiblingID];
+            updateData.push(billUpdate);
+        }
+        dataMap.updateData = updateData;
+        console.log(dataMap);
+        $.bootstrapLoading.start();
+        CommonAjax.post('/bills/pasteBlock',dataMap,function (data) {
+             $.bootstrapLoading.end();
+
+
+        })
+
+        //  delete fees / feesIndex /__v
+    },
+
+    preparePasteData : function (data,billsIDMap) {
+        let me = this;
+        me.datas = _.cloneDeep(projectObj.project.Bills.datas);
+        let bills = [],rations=[],ration_gljs = [],ration_coes = [],quantity_details = [],ration_installations = [];
+
+        eachData(data);
+        for(let b of bills){//更新ID
+            billsIDMap[b.ParentID]?b.ParentID = billsIDMap[b.ParentID]:'';
+            billsIDMap[b.NextSiblingID]?b.NextSiblingID = billsIDMap[b.NextSiblingID]:'';
+        }
+
+
+        return {bills:bills,rations:rations,ration_gljs:ration_gljs,ration_coes:ration_coes,quantity_details:quantity_details,ration_installations:ration_installations};
+
+        function eachData(data) {
+            if(data.sourceType == 'bills'){
+                let tem_b = createBillsData(data);
+                bills.push(tem_b);
+                for(let d of data.quantity_details){
+                    quantity_details.push(createQuantityDetails(d,tem_b,'bills'));
+                }
+                if(data.children && data.children.length>0){
+                    for(let c of data.children){
+                        eachData(c);
+                    }
+                }
+            }
+
+            if( data.sourceType == 'ration'){
+                let tem_r = createRationData(data);
+                rations.push(tem_r);
+                for(let d of data.quantity_details){
+                    quantity_details.push(createQuantityDetails(d,tem_r, 'ration'));
+                }
+                for(let g of data.ration_gljs){
+                    let tem_rg = createSubList(g,tem_r);
+                    tem_rg.billsItemID = tem_r.billsItemID;
+                    ration_gljs.push(tem_rg);
+                }
+                for(let o of data.ration_coes){
+                    ration_coes.push(createSubList(o,tem_r));
+                }
+                for(let ri of data.ration_installations){
+                    ration_installations.push(createSubList(ri,tem_r));
+                }
+            }
+
+        }
+
+        function createSubList(subData,rationData) {
+            let tem_sub = _.cloneDeep(subData);
+            delete tem_sub._id;
+            tem_sub.ID = uuid.v1();
+            tem_sub.projectID = projectObj.project.ID();
+            tem_sub.rationID = rationData.ID;
+            return tem_sub;
+        }
+
+        function createQuantityDetails(detailData,pdata,type) {
+            let tem_detail = _.cloneDeep(detailData);
+            tem_detail.ID = uuid.v1();
+            tem_detail.projectID = projectObj.project.ID();
+            if(type == 'bills'){
+                tem_detail.billID = pdata.ID;
+            }
+            if(type == 'ration'){
+                tem_detail.rationID = pdata.ID;
+            }
+            return tem_detail;
+        }
+
+        function createRationData(rationData) {
+            let tem_ration = _.cloneDeep(rationData);
+            //删除旧数据
+            delete tem_ration.fees;
+            delete tem_ration.feesIndex;
+            delete tem_ration.ration_gljs;
+            delete tem_ration.ration_coes;
+            delete tem_ration.ration_installations;
+            delete tem_ration.quantity_details;
+            delete tem_ration.__v;
+            delete tem_ration.sourceType;
+
+            tem_ration.projectID = projectObj.project.ID();
+            tem_ration.ID = uuid.v1();
+            billsIDMap[tem_ration.billsItemID]?tem_ration.billsItemID = billsIDMap[tem_ration.billsItemID]:'';
+
+            let firstLibID = rationLibObj.getFirstStdRationLibID();
+            if(firstLibID){
+                tem_ration.prefix = projectObj.project.Ration.getRationPrefix(firstLibID,tem_ration);
+            }
+            return tem_ration;
+
+        }
+
+        function createBillsData(billsData) { //ID、重新生成code
+            let temData = _.cloneDeep(billsData);
+            //删除旧数据
+            delete  temData.fees;
+            delete  temData.feesIndex;
+            delete  temData.children;
+            delete  temData.quantity_details;
+            delete  temData.__v;
+            delete  temData.sourceType;
+
+            temData.projectID = projectObj.project.ID();
+            let newID = uuid.v1(); //新的清单ID
+            billsIDMap[temData.ID] = newID;
+            temData.ID = newID; //新的清单ID
+            if(temData.billsLibId && temData.billsLibId!="" && temData.code.length == 12){//是从清单库来的
+                let value = temData.code.substr(0,9);
+                if (value&&value.length === 9 && /^[\d]+$/.test(value)) {
+                    temData.code = projectObj.project.Bills.newFormatCode(value);
+                }
+            }
+
+            me.datas.push(temData);//为了下一个清单的std code 一样
+            return temData;
+        }
+    },
+
+    calcRationSerialNo:function (billsItemID,blockData,updateData,pre,next) {
+        let br = projectObj.project.Ration.getBillsSortRation(billsItemID);
+        if(next == null){ //没有下一树节点,即为最后节点
+            blockData.data.serialNo = br.length > 0 ? br[br.length - 1].serialNo + 1 : 1;
+        }else {//有下一节点
+            let startIndex =0;
+            if(pre){
+                startIndex = br.indexOf(pre.data)+1;
+            }
+            blockData.data.serialNo = br[startIndex].serialNo;
+            for(let i = startIndex;i < br.length; i++){
+                let br_serialNo =  i < br.length - 1 ? br [i + 1].serialNo : br[i].serialNo + 1;
+                updateData.push({type:blockData.data.sourceType,query:{ID:br[i].ID},doc:{serialNo:br_serialNo}});//更新兄弟节点序列号
+            }
+        }
+
+    },
+
+    calcRationQuantityAndContain : function (billsQuantity,ration) {//计算定额工程量和含量
+        let EXPString = ration.quantityEXP+"";
+        if(EXPString.indexOf("QDL") != -1){
+            if(EXPString=="QDL"){//定额的工程量是直接通过清单量填进来的;
+                let times = parseInt(ration.unit);
+                if(isNaN(times)){
+                    times = 1;
+                }
+                ration.quantity = scMathUtil.roundForObj(billsQuantity / times,getDecimal("ration.quantity"));
+                billsQuantity?ration.contain = scMathUtil.roundForObj(ration.quantity/billsQuantity,getDecimal("process")):ration.contain = 0;
+            } else {//如果定额的工程量是通过计算出来的,则应该重新计算。
+                let tem_contain = scMathUtil.roundForObj(ration.contain,getDecimal("process"));
+                let tem_quantity = scMathUtil.roundForObj(billsQuantity*tem_contain,getDecimal("ration.quantity")); //this.autoTransformQuantity(tem_quantity,rationNode);
+                ration.quantity = tem_quantity;
+            }
+        }else {//GCLMXHJ
+            let tem_contain=0;
+            if(billsQuantity&&billsQuantity!=0){
+                let children_quantity = scMathUtil.roundForObj(ration.quantity,getDecimal("ration.quantity"));
+                // children_quantity = scMathUtil.roundForObj(this.reverseQuantity(children_quantity,rationNode),getDecimal("quantity",rationNode));  原先是要反算的,现在改成不用反算了
+                tem_contain =scMathUtil.roundForObj(children_quantity/billsQuantity,getDecimal("process"));
+            }
+            ration.contain = tem_contain;
+        }
+    },
+
+   newFormatCode : function (stdCode, filterCode) {
+        let matchs = this.sameStdCode(stdCode, filterCode);
+        let format = function (Number) {
+            let s = Number + '';
+            while (s.length < 3) {
+                s = '0' + s;
+            }
+            return s;
+        };
+        for (let i = 0; i <= matchs.length; i++) {
+            let formatCode = stdCode + format(i+1);
+            if (matchs.indexOf(formatCode) === -1) {
+                return formatCode;
+            }
+        }
+    },
+    sameStdCode : function (stdCode, filterCode) {
+        let reg = new RegExp('^' + stdCode), matchs= [];
+        for (let data of this.datas) {
+            if (data.code && data.code.length === 12 && reg.test(data.code) && data.code !== filterCode) {
+                matchs.push(data.code);
+            }
+        }
+        return matchs;
+    },
+
+
+    removeBlock:function () {
+        removeLocalCache('project_block');
+    }
+
+};

+ 3 - 0
web/building_saas/main/js/models/cache_tree.js

@@ -143,6 +143,9 @@ var cacheTree = {
         Node.prototype.firstChild = function () {
             return this.children.length === 0 ? null : this.children[0];
         };
+        Node.prototype.lastChild = function () {
+            return this.children.length === 0 ? null : this.children[this.children.length - 1];
+        };
         Node.prototype.depth = function () {
             return this.parent ? this.parent.depth() + 1 : 0;
         };

+ 1 - 0
web/building_saas/main/js/models/fee_rate.js

@@ -546,6 +546,7 @@ var FeeRate = {
                 "projectID": projectID,
                 "feeRateFileID":feeRateFileID,
                 "name":name,
+                "userID":userID,
                 "rootProjectID":me.getActivateFeeRate().rootProjectID
             };
             CommonAjax.post('/feeRates/changeFeeRateFileFromOthers', data, function (data) {

+ 16 - 0
web/building_saas/main/js/models/main_consts.js

@@ -201,6 +201,15 @@ const supplyText = {
     JDYG: '甲定乙供'
 };
 
+//三材类别
+const materialType = {
+    1: '钢材',
+    2: '钢筋',
+    3: '木材',
+    4: '水泥',
+    5: '标准砖'
+};
+
 //清单固定行
 const fixedFlag = {
     // 分部分项工程
@@ -320,6 +329,13 @@ const engineeringType = {
     // 安装修缮工程
     BUILD_IN_REPAIR: 14
 };
+const blockType ={
+    RATION:1,//定额
+    FB:2,//分部
+    FX:3,//分项
+    BILL:4,//清单
+    BX:5//补项
+};
 
 const installFeeType = ['子目费用','分项费用','措施费用'];
 const installSectionBase = ['分别按人材机乘系数','人工','材料','机械'];

+ 61 - 32
web/building_saas/main/js/models/quantity_detail.js

@@ -40,18 +40,25 @@ var quantity_detail = {
                 this.refreshSheetData();
             }
         };
-        quantity_detail.prototype.refreshAfterSave=function(data){
+        quantity_detail.prototype.refreshAfterSave=function(data,batchCallback){
             var me = this;
+            let newData = null;
             if(data.hasOwnProperty('resort')){
                 this.resortData(data.doc,1);
                 _.forEach(data.update_task,function (item) {
                     me.refreshEachItme(item.query,item.doc);
                 })
-                this.datas.push(data.doc);
+                newData = data.doc;
             }else {
-                this.datas.push(data);
+                newData = data;
             }
-            this.refreshSheetData();
+            this.datas.push(newData);
+            if(batchCallback){
+                gljOprObj.detailData.push(newData);
+            }else {
+                this.refreshSheetData();
+            }
+
         };
         quantity_detail.prototype.resortData=function(data,req){
 
@@ -62,7 +69,7 @@ var quantity_detail = {
                 }
             }
         };
-        quantity_detail.prototype.refreshAfterUpdate=function(data){
+        quantity_detail.prototype.refreshAfterUpdate=function(data,batchCallback){
             var me = this;
             var filter_object;
             if(data.hasOwnProperty('refreshList')){
@@ -75,7 +82,11 @@ var quantity_detail = {
             var showList = _.filter(this.datas,filter_object);
             gljOprObj.detailData=showList;
             gljOprObj.detailData=_.sortBy(gljOprObj.detailData,'seq');
-            this.refreshSheetData();
+            console.log(batchCallback);
+            if(batchCallback == undefined){
+                this.refreshSheetData();
+            }
+
         };
         quantity_detail.prototype.refreshEachItme = function(query,doc){
             var detail_list = this.datas;
@@ -107,7 +118,7 @@ var quantity_detail = {
         quantity_detail.prototype.refreshSheetData=function () {
             gljOprObj.showQuantityDetailData();
         };
-        quantity_detail.prototype.saveQuantityDetail=function (args,dataCode,selected) {
+        quantity_detail.prototype.saveQuantityDetail=function (args,dataCode,selected,batchCallback) {
             var me = this;
             var doc={};
             var selected = selected?selected:projectObj.project.mainTree.selected;
@@ -127,9 +138,13 @@ var quantity_detail = {
                 }
                 doc.refreshQuantity=true;
                 if(!selected.data.hasOwnProperty('isFromDetail')||selected.data.isFromDetail==0){
-                    var c = confirm("确定要使用工程量明细替换原工程量吗?");
-                    if(!c){
-                        doc.refreshQuantity=false;
+                    if(!args.replace){//为了批量粘贴时不重复提示,普通编辑时不受影响
+                        var c = confirm("确定要使用工程量明细替换原工程量吗?");
+                        if(c){
+                            args.replace = true;
+                        }else {
+                            doc.refreshQuantity=false;
+                        }
                     }
                 }
 
@@ -142,17 +157,19 @@ var quantity_detail = {
                 url = "/quantity_detail/save";
             }
             var callback = function (data) {
+                $.bootstrapLoading.end();
                 if(doc.refreshQuantity==false){//清空数据
                     me.cleanQuantityDetail();
                 }else {
-                    data.newRecord?me.refreshAfterSave(data.newRecord):me.refreshAfterSave(data);
-                    if(data.node){
+                    data.newRecord?me.refreshAfterSave(data.newRecord,batchCallback):me.refreshAfterSave(data,batchCallback);
+                    if(batchCallback){
+                        batchCallback(args)
+                    }else if(data.node){
                       me.refreshRationOrBillNodes(data.node);
                     }
                     //gljOprObj.detailSheet.setActiveCell(0,0);
                     //gljOprObj.detailSheet.clearSelection();
                 }
-                $.bootstrapLoading.end();
             }
             CommonAjax.post(url,doc,callback,function () {
                 $.bootstrapLoading.end();
@@ -166,7 +183,7 @@ var quantity_detail = {
                     console.log(newNode.data.quantity);
                     this.updateBillQuantity(newNode.data.quantity,newNode,newNode.data.quantityEXP);
                 }else {//更新定额所使用的值要用还没转换前的
-                    this.updateRationQuantity(node.data.r_quantity,newNode,newNode.data.quantityEXP);//to do 加上工程量表达式和含量更新
+                    this.updateRationQuantity(node.data.r_quantity,newNode,newNode.data.quantityEXP);
                 }
             }
         };
@@ -257,7 +274,7 @@ var quantity_detail = {
             let regExp = new RegExp(FindText, "g");
             return str.replace(regExp, RepText);
         };
-        quantity_detail.prototype.updateQuantityDetail=function (args,dataCode,recode,selected) {
+        quantity_detail.prototype.updateQuantityDetail=function (args,dataCode,recode,selected,batchCallback) {
             var doc ={};
             var query={
                 ID:recode.ID,
@@ -273,20 +290,23 @@ var quantity_detail = {
                 }
                 query.refreshQuantity=true;
                 if(!selected.data.hasOwnProperty('isFromDetail')||selected.data.isFromDetail==0){
-                    var c = confirm("确定要使用工程量明细替换原工程量吗?");
-                    if(!c){
-                        //query.refreshQuantity=false;
-                        this.cleanQuantityDetail(selected,true);
-                        return;
+                    if(!args.replace){//为了批量粘贴时不重复提示,普通编辑时不受影响
+                        var c = confirm("确定要使用工程量明细替换原工程量吗?");
+                        if(c){
+                            args.replace = true;
+                        }else {
+                            this.cleanQuantityDetail(selected,true);
+                            return;
+                        }
                     }
                 }
                 query.index = args.row;
-                this.updateQuantityRegex(query,doc,args)
+                this.updateQuantityRegex(query,doc,args,batchCallback)
             }else {
-                this.normalUpdate(query,doc);
+                this.normalUpdate(query,doc,args,batchCallback);
             }
         };
-        quantity_detail.prototype.updateQuantityRegex=function(query,doc,args){
+        quantity_detail.prototype.updateQuantityRegex=function(query,doc,args,batchCallback){
             var needupdate = false;
             if(args.editingText==null){
                 needupdate =true;
@@ -297,7 +317,7 @@ var quantity_detail = {
                 }
             }
             if(needupdate){
-                this.commonUpdate("/quantity_detail/updateRegex",{query:query,doc:doc});
+                this.commonUpdate("/quantity_detail/updateRegex",{query:query,doc:doc},args,batchCallback);
             }else {
                 var sheet = subSpread.getActiveSheet();
                 sheet.getCell(args.row,args.col).value(gljOprObj.detailData[args.row].regex);
@@ -327,23 +347,25 @@ var quantity_detail = {
             };
             this.normalUpdate(query,doc);
         };
-        quantity_detail.prototype.commonUpdate = function (url,postData) {
+        quantity_detail.prototype.commonUpdate = function (url,postData,args,batchCallback) {
             var me = this;
             $.bootstrapLoading.start();
             var callback = function (data) {
-                me.refreshAfterUpdate(data);
-                if(data.node){
-                  me.refreshRationOrBillNodes(data.node);
-                }
                 $.bootstrapLoading.end();
+                me.refreshAfterUpdate(data,batchCallback);
+                if(batchCallback){
+                    batchCallback(args)
+                }else if(data.node){
+                    me.refreshRationOrBillNodes(data.node);
+                }
             }
             CommonAjax.post(url,postData,callback,function () {
                 $.bootstrapLoading.end();
             });
         };
-        quantity_detail.prototype.normalUpdate=function(query,doc){
+        quantity_detail.prototype.normalUpdate=function(query,doc,args,batchCallback){
             var url = "/quantity_detail/update";
-            this.commonUpdate(url,{query:query,doc:doc});
+            this.commonUpdate(url,{query:query,doc:doc},args,batchCallback);
         };
         quantity_detail.prototype.regexChecking=function(text){
             var regex=/^[0-9Cc\+\-\*\^/\(\)\.]*$/g;
@@ -452,6 +474,13 @@ var quantity_detail = {
             });
             return temp;
         };
+        quantity_detail.prototype.getDetailByRationID = function (rationID) {
+          return _.filter(this.datas,{'rationID':rationID});
+        };
+        quantity_detail.prototype.getDetailByBillID = function (billID) {
+            return _.filter(this.datas,{'billID':billID});
+        };
+
         quantity_detail.prototype.deleteByRation = function(ration){
             var detail_list = this.datas;
             _.remove(detail_list,{'rationID':ration.ID});
@@ -595,7 +624,7 @@ var quantity_detail = {
                     }else {
                         let tem_contain=0;
                         if(value&&value!=0){
-                           let children_quantity = scMathUtil.roundForObj(rationNode.data.quantity,getDecimal("quantity"),rationNode);
+                           let children_quantity = scMathUtil.roundForObj(rationNode.data.quantity,getDecimal("quantity",rationNode));
                             // children_quantity = scMathUtil.roundForObj(this.reverseQuantity(children_quantity,rationNode),getDecimal("quantity",rationNode));  原先是要反算的,现在改成不用反算了
                             tem_contain =scMathUtil.roundForObj(children_quantity/value,getDecimal("process"));
                         }

+ 4 - 0
web/building_saas/main/js/models/ration_coe.js

@@ -53,6 +53,10 @@ var ration_coe = {
                 }
             }
         };
+        ration_coe.prototype.getCoeByRationID = function (rationID) {
+           let coeList = _.filter(this.datas, {'rationID': rationID});
+           return coeList;
+        };
         ration_coe.prototype.refreshAfterUpdate=function(data){
             var coe_list = projectObj.project.ration_coe.datas;
             var coe_index= _.findIndex(coe_list,function(coe){

+ 4 - 0
web/building_saas/main/js/models/ration_installation.js

@@ -32,6 +32,10 @@ let ration_installation = {
                 }
             }
         };
+        ration_installation.prototype.getInstallationByRationID = function (rationID) {
+            let insList = _.filter(this.datas, {'rationID': rationID});
+            return insList;
+        };
         ration_installation.prototype.getBySectionID = function(sectionID){
             var ri_list = this.datas;
             return _.filter(ri_list,{'sectionId':sectionID});

+ 217 - 68
web/building_saas/main/js/views/character_content_view.js

@@ -27,6 +27,32 @@ let contentOprObj = {
         sheet.bind(EVENTS.EditEnded, me.onEditEnded);
         sheet.bind(EVENTS.ClipboardPasting, me.onClipboardPasting);
         sheet.bind(EVENTS.ClipboardPasted, me.onClipboardPasted);
+        sheet.bind(EVENTS.SelectionChanged, me.onSelectionChanged);
+        me.bindTools();
+    },
+    bindTools: function () {
+        let me = contentOprObj;
+        let sheet = me.workBook.getActiveSheet();
+        $('#jobAdd').click(function () {
+            me.insertContent(sheet, me.currentCache.length, '');
+            me.workBook.focus();
+        });
+        $('#jobInsert').click(function(){
+            me.insertContent(sheet, sheet.getActiveRowIndex(), '');
+            me.workBook.focus();
+        });
+        $('#jobDel').click(function(){
+            me.deleteContent(sheet.getActiveRowIndex());
+            me.workBook.focus();
+        });
+        $('#jobUp').click(function(){
+            me.upMove({row: sheet.getActiveRowIndex(), col: sheet.getActiveColumnIndex()});
+            me.workBook.focus();
+        });
+        $('#jobDown').click(function(){
+            me.downMove({row: sheet.getActiveRowIndex(), col: sheet.getActiveColumnIndex()});
+            me.workBook.focus();
+        });
     },
     //将从清单库中添加的清单,把标准清单的工作内容转化成清单的工作内容
     buildJobContent: function (jobs) {
@@ -72,11 +98,11 @@ let contentOprObj = {
         return null;
     },
     //新增行
-    addRow: function (sheet) {
+    addRow: function (idx, sheet) {
         let checkBox = new GC.Spread.Sheets.CellTypes.CheckBox();
         checkBox.isThreeState = false;
-        sheet.addRows(sheet.getRowCount(), 1);
-        sheet.getCell(sheet.getRowCount() - 1, 1).cellType(checkBox);
+        sheet.addRows(idx, 1);
+        sheet.getCell(idx - 1, 1).cellType(checkBox);
     },
     upMove: function (cell) {
         let me = contentOprObj;
@@ -88,6 +114,7 @@ let contentOprObj = {
         preObj.serialNo = temp;
         me.sortCache(me.currentCache);
         me.save(function () {
+            me.workBook.focus();
             me.workBook.getSheet(0).setActiveCell(cell.row - 1, cell.col);
         });
     },
@@ -101,6 +128,7 @@ let contentOprObj = {
         nextObj.serialNo = temp;
         me.sortCache(me.currentCache);
         me.save(function () {
+            me.workBook.focus();
             me.workBook.getSheet(0).setActiveCell(cell.row + 1, cell.col);
         });
     },
@@ -108,18 +136,24 @@ let contentOprObj = {
         let me = contentOprObj;
         me.currentCache.splice(rowIdx, 1);
         me.save();
+        me.workBook.focus();
     },
     //更新
     updateContent: function (job, newContent) {
+        let me = contentOprObj;
         job.content = newContent;
+        me.save();
     },
     //新增
-    insertContent: function (content) {
+    insertContent: function (sheet, idx, content) {
         let me = contentOprObj;
-        let preObj = me.currentCache.length > 0 ?  me.currentCache[me.currentCache.length - 1] : null;
-        let newObj = {content: content, isCheceked: false, serialNo: preObj ? preObj.serialNo + 1 : 1};
-        me.currentCache.push(newObj);
-
+        me.addRow(idx, sheet);
+        let newObj = {content: content, isChecked: true};
+        me.currentCache.splice(idx, 0, newObj);
+        //重新排序赋值
+        pageCCOprObj.resortNo(me.currentCache);
+        me.save();
+        me.workBook.focus();
     },
     save: function (callback) {
         let selectedNode = projectObj.mainController.tree.selected;
@@ -128,24 +162,15 @@ let contentOprObj = {
     },
     onEditEnded: function (sender, args) {
         let me = contentOprObj;
-        let preObj = me.currentCache.length > 0 ?  me.currentCache[me.currentCache.length - 1] : null;
-        let contentTxt;
-        if(args.editingText && args.editingText.toString().trim().length > 0){
-            //更新
-            if(args.row < me.currentCache.length ){
-                me.updateContent(me.currentCache[args.row], args.editingText);
-            }
-            //新增
-            else{
-                me.insertContent(args.editingText);
-            }
-            //保存
-            me.save();
+        if(me.setting.header[args.col].dataCode === 'isChecked'){
+            return;
         }
-        else{
-            //恢复
-            args.sheet.setValue(args.row, args.col, me.currentCache.length > args.row ? me.currentCache[args.row].content + '' : '');
+        args.editingText = args.editingText ? args.editingText : '';
+        //更新
+        if(args.row < me.currentCache.length ){
+            me.updateContent(me.currentCache[args.row], args.editingText);
         }
+
     },
     //复选框控制输出
     onButtonClicked: function (sender, args) {
@@ -179,12 +204,42 @@ let contentOprObj = {
             if(rowIdx < me.currentCache.length){
                 me.updateContent(me.currentCache[rowIdx], items[i].content);
             }
-            //新增
-            else{
-                me.insertContent(items[i].content);
+        }
+    },
+    onSelectionChanged: function (sender, args) {
+        let me = contentOprObj;
+        if(args.newSelections && args.newSelections.length > 0){
+            me.initSelection(args.newSelections[0].row);
+        }
+        me.initSelection(args.newSelections[0].row);
+    },
+    initSelection: function (row) {
+        let me = contentOprObj;
+        let disObj = {jobAdd: false, jobInsert: true, jobDel: true, jobUp: true, jobDown: true};
+        if(row !== -1){
+            //在表内
+            if(row < me.currentCache.length){
+                disObj.jobDel = false;
+                disObj.jobInsert = false;
+                if(row !== 0){
+                    disObj.jobUp = false;
+                }
+                if(row !== me.currentCache.length - 1){
+                    disObj.jobDown = false;
+                }
+            }
+        }
+        me.refreshTools(disObj);
+    },
+    //刷新工具条
+    refreshTools: function (disObj) {
+        for(let o in disObj){
+            let jqSel = $(`#${o}`);
+            jqSel.removeClass('disabled');
+            if(disObj[o]){
+                jqSel.addClass('disabled');
             }
         }
-        me.save();
     },
     sortCache: function (cacheArr) {
         cacheArr.sort(function (a, b) {
@@ -206,18 +261,20 @@ let contentOprObj = {
                 //控制允许右键菜单在哪个位置出现
                 let target = SheetDataHelper.safeRightClickSelection($triggerElement, e, me.workBook);
                 let sheet = me.workBook.getSheet(0);
+                let addDis = pageCCOprObj.isBillsType() ? false : true,  insertDis = false, delDis = false, upDis = false, downDis = false;
                 if(target.hitTestType === 3){//在表格内&& typeof target.row !== 'undefined' && typeof target.col !== 'undefined'
-                    let insertDis = pageCCOprObj.isBillsType() ? false : true, delDis = false, upDis = false, downDis = false;
                     if(typeof target.row !== 'undefined'){
                         //控制按钮是否可用
                         sheet.setActiveCell(target.row, target.col);
                         if(!me.currentCache ||target.row >= me.currentCache.length){//右键定位在有数据的行,删除键才显示可用
+                            insertDis = true;
                             delDis = true;
                             downDis = true;
                             upDis = true;
                         }
                         else{//有数据
                             if(typeof target.col === 'undefined'){//定位不在表格内
+                                insertDis = true;
                                 downDis = true;
                                 upDis = true;
                                 delDis = true;
@@ -233,16 +290,20 @@ let contentOprObj = {
                         }
                     }
                     else{
+                        insertDis = true;
                         delDis = true;
                         downDis = true;
                         upDis = true;
                     }
+                    me.refreshTools({jobAdd: addDis, jobInsert: insertDis, jobDel: delDis, jobUp: upDis, jobDown: downDis});
                     return {
                         callback: function(){},
                         items: {
-                            "insert": {name: "添加", disabled: insertDis, icon: "fa-sign-in", callback: function (key, opt) {
-                                //插入空行
-                                me.addRow(sheet);
+                            "insert": {name: "插入", disabled: insertDis, icon: "context-menu-icon context-menu-icon-add", callback: function (key, opt) {
+                                me.insertContent(sheet, sheet.getActiveRowIndex(), '');
+                            }},
+                            "add": {name: "添加", disabled: addDis, icon: "fa-sign-in", callback: function (key, opt) {
+                                me.insertContent(sheet, me.currentCache.length, '');
                             }},
                             "delete": {name: "删除", disabled: delDis, icon: "fa-remove", callback: function (key, opt) {
                                 me.deleteContent(target.row);
@@ -258,6 +319,7 @@ let contentOprObj = {
                     };
                 }
                 else{
+                    me.refreshTools({jobAdd: addDis, jobInsert: insertDis, jobDel: delDis, jobUp: upDis, jobDown: downDis});
                     return false;
                 }
             }
@@ -293,7 +355,33 @@ let characterOprObj = {
         sheet.bind(EVENTS.EditStarting, me.onEditStart);
         sheet.bind(EVENTS.ClipboardPasting, me.onClipboardPasting);
         sheet.bind(EVENTS.ClipboardPasted, me.onClipboardPasted);
+        sheet.bind(EVENTS.SelectionChanged, me.onSelectionChanged);
         workBook.bind(EVENTS.RangeChanged, me.onRangeChanged);
+        me.bindTools();
+    },
+    bindTools: function () {
+        let me = characterOprObj;
+        let sheet = me.workBook.getActiveSheet();
+        $('#itemAdd').click(function () {
+            me.insertCharacter(sheet, me.currentCache.length, '');
+            me.workBook.focus();
+        });
+        $('#itemInsert').click(function(){
+            me.insertCharacter(sheet, sheet.getActiveRowIndex(), '');
+            me.workBook.focus();
+        });
+        $('#itemDel').click(function(){
+            me.deleteCharacter(sheet.getActiveRowIndex());
+            me.workBook.focus();
+        });
+        $('#itemUp').click(function(){
+            me.upMove({row: sheet.getActiveRowIndex(), col: sheet.getActiveColumnIndex()});
+            me.workBook.focus();
+        });
+        $('#itemDown').click(function(){
+            me.downMove({row: sheet.getActiveRowIndex(), col: sheet.getActiveColumnIndex()});
+            me.workBook.focus();
+        });
     },
     //将从清单库中添加的清单,把标准清单的项目特征转化成清单的项目特征
     buildItemCharactet: function (items) {//从清单库过来的默认不输出
@@ -382,15 +470,14 @@ let characterOprObj = {
         }
         return null;
     },
-    addRow: function (sheet) {
+    addRow: function (idx, sheet) {
         let checkBox = new GC.Spread.Sheets.CellTypes.CheckBox(),
             combo = new GC.Spread.Sheets.CellTypes.ComboBox();
         checkBox.isThreeState = false;
         combo.editable(true);
-        let rowIdx = sheet.getRowCount();
-        sheet.addRows(rowIdx, 1);
-        sheet.getCell(rowIdx, 1).cellType(combo);
-        sheet.getCell(rowIdx, 2).cellType(checkBox);
+        sheet.addRows(idx, 1);
+        sheet.getCell(idx, 1).cellType(combo);
+        sheet.getCell(idx, 2).cellType(checkBox);
     },
     upMove: function (cell) {
         let me = characterOprObj;
@@ -403,6 +490,7 @@ let characterOprObj = {
         contentOprObj.sortCache(me.currentCache);
         me.save(function () {
             me.workBook.getSheet(0).setActiveCell(cell.row - 1, cell.col);
+            me.workBook.focus();
         });
     },
     downMove: function (cell) {
@@ -416,12 +504,14 @@ let characterOprObj = {
         contentOprObj.sortCache(me.currentCache);
         me.save(function () {
             me.workBook.getSheet(0).setActiveCell(cell.row + 1, cell.col);
+            me.workBook.focus();
         });
     },
     deleteCharacter: function (rowIdx) {
         let me = characterOprObj;
         me.currentCache.splice(rowIdx, 1);
         me.save();
+        me.workBook.focus();
     },
     //取消选择的特征值
     unsetSelected: function (item) {
@@ -477,24 +567,16 @@ let characterOprObj = {
                 item.isChecked = true;
             }
         }
+        me.save();
     },
-    insertCharacter: function (character, value) {
+    insertCharacter: function (sheet, idx, character) {
         let me = characterOprObj;
-        let preObj = me.currentCache.length > 0 ?  me.currentCache[me.currentCache.length - 1] : null;
-        if(character && !value){
-            let newCharacter = {character: character, eigenvalue: [], isChecked: false, serialNo: preObj ? preObj.serialNo + 1 : 1};
-            me.currentCache.push(newCharacter);
-        }
-        else if(!character && value){
-            let newValue = {value: value, isSelected: true};
-            let newCharacter = {character: '', eigenvalue: [newValue], isChecked: false, serialNo: preObj? preObj.serialNo + 1 : 1};
-            me.currentCache.push(newCharacter);
-        }
-        else if(character && value){//有了特征值自动打勾输出
-            let newValue = {value: value, isSelected: true};
-            let newCharacter = {character:character , eigenvalue: [newValue], isChecked: true, serialNo: preObj? preObj.serialNo + 1 : 1};
-            me.currentCache.push(newCharacter);
-        }
+        me.addRow(idx, sheet);
+        let newObj = {character: character, eigenvalue: [], isChecked: false};
+        me.currentCache.splice(idx, 0, newObj);
+        pageCCOprObj.resortNo(me.currentCache);
+        me.save();
+        me.workBook.focus();
     },
     save: function (callback) {
         let selectedNode = projectObj.mainController.tree.selected;
@@ -521,7 +603,7 @@ let characterOprObj = {
                     me.updateCharacter(thisCha, null, args.editingText);
                 }
             }
-            //新增
+            /*//新增
             else{
                 if(args.col === 0){//特征
                     me.insertCharacter(args.editingText, null);
@@ -529,9 +611,7 @@ let characterOprObj = {
                 else if(args.col === 1){//特征值
                     me.insertCharacter(null, args.editingText);
                 }
-            }
-            //保存
-            me.save();
+            }*/
         }
         else{//恢复
             if(args.col === 0){
@@ -556,12 +636,11 @@ let characterOprObj = {
             if(me.currentCache.length > rowIdx){
                me.updateCharacter(me.currentCache[rowIdx], items[i].character, items[i].eigenvalue);
             }
-            //新增
+           /* //新增
             else{
                 me.insertCharacter(items[i].character, items[i].eigenvalue);
-            }
+            }*/
         }
-        me.save();
     },
     onRangeChanged: function (sender, args) {
         let me = characterOprObj;
@@ -597,6 +676,40 @@ let characterOprObj = {
             args.sheet.setValue(args.row, args.col, 0);
         }
     },
+    onSelectionChanged: function (sender, args) {
+        let me = characterOprObj;
+        if(args.newSelections && args.newSelections.length > 0){
+            me.initSelection(args.newSelections[0].row);
+        }
+    },
+    initSelection: function (row) {
+        let me = characterOprObj;
+        let disObj = {itemAdd: false, itemInsert: true, itemDel: true, itemUp: true, itemDown: true};
+        if(row !== -1){
+            //在表内
+            if(row < me.currentCache.length){
+                disObj.itemDel = false;
+                disObj.itemInsert = false;
+                if(row !== 0){
+                    disObj.itemUp = false;
+                }
+                if(row !== me.currentCache.length - 1){
+                    disObj.itemDown = false;
+                }
+            }
+        }
+        me.refreshTools(disObj);
+    },
+    //刷新工具条
+    refreshTools: function (disObj) {
+        for(let o in disObj){
+            let jqSel = $(`#${o}`);
+            jqSel.removeClass('disabled');
+            if(disObj[o]){
+                jqSel.addClass('disabled');
+            }
+        }
+    },
     onContextmenuOpr: function () {//右键菜单
         let me = characterOprObj;
         $.contextMenu({
@@ -605,18 +718,20 @@ let characterOprObj = {
                 //控制允许右键菜单在哪个位置出现
                 let target = SheetDataHelper.safeRightClickSelection($triggerElement, e, me.workBook);
                 let sheet = me.workBook.getSheet(0);
+                let addDis = pageCCOprObj.isBillsType() ? false : true, insertDis = false, delDis = false, upDis = false, downDis = false;
                 if(target.hitTestType === 3){//在表格内 && typeof target.row !== 'undefined' && typeof target.col !== 'undefined'
-                    let insertDis = pageCCOprObj.isBillsType() ? false : true, delDis = false, upDis = false, downDis = false;
                     if(typeof target.row !== 'undefined'){
                         //控制按钮是否可用
                         sheet.setActiveCell(target.row, target.col);
                         if(!me.currentCache ||target.row >= me.currentCache.length){//右键定位在有数据的行,删除键才显示可用
+                            insertDis = true;
                             delDis = true;
                             downDis = true;
                             upDis = true;
                         }
                         else{//有数据
                             if(typeof target.col === 'undefined'){//定位在表格外
+                                insertDis = true;
                                 downDis = true;
                                 upDis = true;
                                 delDis = true;
@@ -632,15 +747,20 @@ let characterOprObj = {
                         }
                     }
                     else{
+                        insertDis = true;
                         delDis = true;
                         downDis = true;
                         upDis = true;
                     }
+                    me.refreshTools({itemAdd: addDis, itemInsert: insertDis, itemDel: delDis, itemUp: upDis, itemDown: downDis});
                     return {
                         callback: function(){},
                         items: {
-                            "insert": {name: "添加", disabled: insertDis, icon: "fa-sign-in", callback: function (key, opt) {
-                                me.addRow(sheet);
+                            "insert": {name: "插入", disabled: insertDis, icon: "fa-sign-in", callback: function (key, opt) {
+                                me.insertCharacter(sheet, sheet.getActiveRowIndex(), '');
+                            }},
+                            "add": {name: "添加", disabled: addDis, icon: "context-menu-icon context-menu-icon-add", callback: function (key, opt) {
+                                me.insertCharacter(sheet, me.currentCache.length, '');
                             }},
                             "delete": {name: "删除", disabled: delDis, icon: "fa-remove", callback: function (key, opt) {
                                 me.deleteCharacter(target.row);
@@ -655,6 +775,7 @@ let characterOprObj = {
                     };
                 }
                 else{
+                    me.refreshTools({jobAdd: addDis, jobInsert: insertDis, jobDel: delDis, jobUp: upDis, jobDown: downDis});
                     return false;
                 }
             }
@@ -666,6 +787,13 @@ let pageCCOprObj = {
     currentFindSet: null,
     mainActiveCell: null,//mainSpread焦点单元格
     nameCache: '',
+    //重新赋serialNo
+    resortNo: function (items) {
+        let count = 1;
+        for(let item of items){
+            item.serialNo = count++;
+        }
+    },
     //获得造价书当前焦点行的类型:清单、定额
     isBillsType: function () {
         let rst = false;
@@ -699,8 +827,10 @@ let pageCCOprObj = {
     //设置特征及内容currentCache
     setCacheAndShow: function (node) {
         let theCont = contentOprObj, theCha = characterOprObj;
-        theCont.currentCache = node && typeof node.data.jobContent !== 'undefined' ? node.data.jobContent : [];
-        theCha.currentCache = node && typeof node.data.itemCharacter !== 'undefined' ? node.data.itemCharacter : [];
+        node.data.jobContent = node && typeof node.data.jobContent !== 'undefined' ? node.data.jobContent : [];
+        node.data.itemCharacter = node && typeof node.data.itemCharacter !== 'undefined' ? node.data.itemCharacter : [];
+        theCont.currentCache =  node.data.jobContent;
+        theCha.currentCache = node.data.itemCharacter;
         this.currentFindSet = node && typeof node.data.ID !== 'undefined' && typeof node.data.projectID ? {ID: node.data.ID, projectID: node.data.projectID} : null;
         this.showData(theCont.workBook.getSheet(0), theCont.setting, theCont.currentCache);
         this.showData(theCha.workBook.getSheet(0), theCha.setting, theCha.currentCache);
@@ -744,6 +874,8 @@ let pageCCOprObj = {
                 sheet.autoFitRow(row);
             }
         }
+        contentOprObj.initSelection(0);
+        characterOprObj.initSelection(0);
         sheet.resumeEvent();
         sheet.resumePaint();
     },
@@ -842,6 +974,9 @@ let pageCCOprObj = {
      * @return {void}
      */
     setCharacterBySetting: function(node, setting, callback = null, oprObj = null) {
+        if(!node){
+            return;
+        }
         let self = this;
         // 保存的条件数据
         const findSet = { ID: node.data.ID, projectID: node.data.projectID };
@@ -941,7 +1076,10 @@ let pageCCOprObj = {
             }
             const itemCharacter = node.data.itemCharacter;
             const itemJob = node.data.jobContent;
-            if (itemCharacter === undefined || itemCharacter.length <= 0 || itemJob === undefined || itemJob.length <= 0) {
+         /*   if (itemCharacter === undefined || itemCharacter.length <= 0 || itemJob === undefined || itemJob.length <= 0) {
+                throw '内部数据错误';
+            }*/
+            if (itemCharacter === undefined || itemJob === undefined) {
                 throw '内部数据错误';
             }
             // 默认名称
@@ -1011,9 +1149,20 @@ let pageCCOprObj = {
         let updateData = {
             itemCharacterText: '',
             jobContentText: '',
-            name: '',
+            name: node.data.name ? node.data.name : '',
         };
-        if (node.data.name === undefined || node.data.itemCharacter.length <= 0 || node.data.jobContent.length <= 0) {
+        /* let updateData = {
+            itemCharacterText: '',
+            jobContentText: '',
+            name: '',
+        };*/
+        if(!node.data.itemCharacter){
+            node.data.itemCharacter = [];
+        }
+        if(!node.data.jobContent){
+            node.data.jobContent = [];
+        }
+        if (node.data.name === undefined || (node.data.itemCharacter.length <= 0 && node.data.jobContent.length <= 0)) {
             return updateData;
         }
         // 获取原名称

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

@@ -10,9 +10,9 @@ var feeRateObject={
     mainFeeRateData:null,
     mainFeeRateSetting:{
         header: [
-            {headerName: "专业名称", headerWidth: 550, dataCode: "name", dataType: "String"},
-            {headerName: "值%", headerWidth: 250, dataCode: "rate", dataType: "Number",hAlign: "right",decimalField:"feeRate"},
-            {headerName: "备注", dataCode: "memo", dataType: "String"}
+            {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"}
         ],
         view: {
             lockColumns: [0]

+ 80 - 19
web/building_saas/main/js/views/glj_view.js

@@ -357,7 +357,7 @@ var gljOprObj = {
 
     onClipboardPasting: function (sender, args) {
         var me = gljOprObj;
-        if(args.cellRange.rowCount!=1||args.cellRange.colCount!=1){
+        if(args.sheetName!="quantity_detail"&&(args.cellRange.rowCount!=1||args.cellRange.colCount!=1)){//工程量明细做特殊处理
             args.cancel = true;
         }
     },
@@ -397,7 +397,7 @@ var gljOprObj = {
             me.onEditDetailSheet(args);
         }
     },
-    onEditDetailSheet: function (args) {
+    onEditDetailSheet: function (args,callback) {
         var me = gljOprObj;
         if (args.row > me.detailData.length) {
             return;
@@ -407,14 +407,16 @@ var gljOprObj = {
         }
         var selected = projectObj.project.mainTree.selected;//因为使用了延时方法,所以要先取得选中行;
         var detailList = me.detailData;
-        args.editingText = args.editingText.replace(/(/g, "(");//替换中文左右括号;
-        args.editingText = args.editingText.replace(/)/g, ")");
+        if(args.editingText){
+            args.editingText = args.editingText.replace(/(/g, "(");//替换中文左右括号;
+            args.editingText = args.editingText.replace(/)/g, ")");
+        }
         setTimeout(function () {//这里须用延时执行的办法,不然的弹窗确认窗口会和spreadjs 的事件有冲突,造成定额工料机数据不会根据树结点更新的问题
             if (args.row == detailList.length) {
-                projectObj.project.quantity_detail.saveQuantityDetail(args, me.detailSetting.header[args.col].dataCode, selected);
+                projectObj.project.quantity_detail.saveQuantityDetail(args, me.detailSetting.header[args.col].dataCode, selected,callback);
             }
             if (args.row < detailList.length) {
-                projectObj.project.quantity_detail.updateQuantityDetail(args, me.detailSetting.header[args.col].dataCode, detailList[args.row], selected);
+                projectObj.project.quantity_detail.updateQuantityDetail(args, me.detailSetting.header[args.col].dataCode, detailList[args.row], selected,callback);
             }
         }, 100);
 
@@ -481,7 +483,9 @@ var gljOprObj = {
         } else if (args.sheetName == 'quantity_detail') {
             projectObj.project.quantity_detail.isSummationUpdate(args, gljOprObj.detailData, newval);
         } else if (args.sheetName == 'glj_lib') {
-            gljOprObj.setGLJSelection(args, newval);
+            if(gljOprObj.gljLibSheetSetting.header[args.col].dataCode === 'select'){
+                gljOprObj.setGLJSelection(args, newval);
+            }
         }else if(args.sheetName == 'rationInstallSheet'){
             args.newValue = newval;
             installationFeeObj.onRationInstallValueChange(sender,args);
@@ -723,21 +727,78 @@ var gljOprObj = {
     },
     onRangeChanged: function (sender, args) {
         var me = gljOprObj;
-        if (args.action == GC.Spread.Sheets.RangeChangedAction.clear) {
-            args.editingText = null;
-        }else if(args.action == GC.Spread.Sheets.RangeChangedAction.paste){
-            args.editingText = args.sheet.getCell(args.row,args.col).value();
+        if(args.sheetName == 'quantity_detail'){
+            me.batchUpdateQuantityDetail(args);
         }else {
-            return;
+            if (args.action == GC.Spread.Sheets.RangeChangedAction.clear) {
+                args.editingText = null;
+            }else if(args.action == GC.Spread.Sheets.RangeChangedAction.paste){
+                args.editingText = args.sheet.getCell(args.row,args.col).value();
+            }else {
+                return;
+            }
+            if (args.sheetName == 'ration_glj') {
+                me.onEditGLJSheet(args);
+            }
+            if (args.sheetName == 'ration_ass') {
+                me.updateRationAss(args);
+            }
         }
-        if (args.sheetName == 'ration_glj') {
-            me.onEditGLJSheet(args);
+    },
+
+    batchUpdateQuantityDetail:function (args) {
+        let me = gljOprObj;
+        let updateArray = [];
+        for(let i =0;i<args.changedCells.length;i++){
+            let c = args.changedCells[i];
+            let tem = {
+                row:c.row,
+                col:c.col,
+                editingText:args.sheet.getCell(c.row,c.col).text(),
+                sheet:args.sheet,
+                sheetName:args.sheetName,
+                index:i
+            };
+            updateArray.push(tem);
         }
-        if (args.sheetName == 'ration_ass') {
-            me.updateRationAss(args);
+        if(updateArray.length>0){
+            updateArray.length == 1?me.onEditDetailSheet(updateArray[0]):me.onEditDetailSheet(updateArray[0],updateCallback);
+        }
+
+        function updateCallback(i_args) {
+            let index = i_args.index;
+            if(index < updateArray.length-1){
+                let nextIndex = index+1;
+                updateArray[nextIndex].replace = i_args.replace;
+                if(nextIndex == updateArray.length-1){//是最后一个,则不用调callback了
+                    me.onEditDetailSheet(updateArray[nextIndex]);
+                }else {
+                    me.onEditDetailSheet(updateArray[nextIndex],updateCallback);
+                }
+
+            }
         }
 
     },
+
+    testBatchUpdate:function () {
+        let me=gljOprObj;
+        let temA = [1,2,3];
+        me.b(1,a);
+
+
+        function a(v) {
+            let index = temA.indexOf(v);
+            if(index < temA.length-1){
+               me.b(temA[index+1],a)
+            }
+        }
+
+    },
+    b:function (g,callback) {
+        console.log(g);
+        callback(g);
+    },
     generateHtmlString: function () {
 //        return "<div id='edit'><div>";
 
@@ -943,7 +1004,7 @@ var gljOprObj = {
         }
         this.sheetData = newList;
     },
-    combineWithProjectGlj: function (ration_gljs) {
+    combineWithProjectGlj: function (ration_gljs,needRatio=true) {
         var projectGLJData = projectObj.project.projectGLJ.datas;
         var projectGljs = projectGLJData.gljList;
         var mixRatioMap = projectGLJData.mixRatioMap;
@@ -958,7 +1019,7 @@ var gljOprObj = {
                     ration_gljs[i].isAdd = glj.unit_price.is_add;
                     ration_gljs[i]=this.setGLJPrice(ration_gljs[i],glj);//设置工料机价格
                     var connect_index = this.getIndex(glj, gljKeyArray);
-                    if (mixRatioMap.hasOwnProperty(connect_index)) {
+                    if (needRatio==true&&mixRatioMap.hasOwnProperty(connect_index)) {
                         var mixRatios = this.getMixRationShowDatas(mixRatioMap[connect_index], projectGljs);
                         ration_gljs[i].subList = mixRatios;
                     }
@@ -1863,4 +1924,4 @@ function compareRationGLJ(a, b) {
         }
     }
     return false;
-}
+}

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

@@ -632,7 +632,7 @@ $(function () {
 
     $("#unitFile-save-as").on('shown.bs.modal', function () {
         // 获取当前建设项数据
-        $("#save-as-name").val(projectGljObject.usedUnitPriceInfo.name + '(复件)');
+        $("#save-as-name").val(projectGljObject.usedUnitPriceInfo.name + '副本');
     });
 
     // 从其他建设项目中复制 选择建设项目

+ 62 - 12
web/building_saas/main/js/views/project_view.js

@@ -40,7 +40,7 @@ var projectObj = {
         //zhong 2017-9-1 特征及内容
         if(pageCCOprObj.active){
             pageCCOprObj.mainActiveCell = projectObj.mainSpread.getActiveSheet().getSelections()[0];//mainSpread焦点单元格
-            if(node.sourceType === project.Bills.getSourceType()){
+            if(node && node.sourceType === project.Bills.getSourceType()){
                 pageCCOprObj.setCacheAndShow(node);
             }
             else{
@@ -484,6 +484,9 @@ var projectObj = {
         let colSetting = projectObj.mainController.setting.cols[info.col];
         if(colSetting.data.field === 'unit' || (projectObj.lastCol&&projectObj.lastCol.data.field === 'unit')||colSetting.data.field ==='subType'
             || (projectObj.lastCol&&projectObj.lastCol.data.field === 'subType') || colSetting.data.field === 'programID' ||(projectObj.lastCol&&projectObj.lastCol.data.field === 'programID')){
+            /*let hideRowFilter =new GC.Spread.Sheets.Filter.HideRowFilter(info.sheet.getRange(-1, info.col, -1, 1));
+            info.sheet.rowFilter(hideRowFilter);
+            info.sheet.resumePaint();*/
             info.sheet.repaint();
         }
     },
@@ -924,20 +927,13 @@ var projectObj = {
                     callback: function () {
                         project.calcProgram.calcAllNodesAndSave();
                     }
-                }/*,
+                },
                 "spr2":'--------',
                 "copyBlock": {
                     name: '复制整块',
                     icon: 'fa-copy',
                     disabled: function () {
-                        let selected = project.mainTree.selected;
-                        if(selected.sourceType == project.Bills.getSourceType() && selected.data.type == billType.DXFY){//焦点行是大项费用则无效;
-                            return true;
-                        }
-                        if(selected.sourceType == project.ration_glj.getSourceType()){// 焦点行是定额下的主材设备则无效;
-                            return true;
-                        }
-                        return false;
+                        return BlockController.copyBtnDisable(project.mainTree.selected);
                     },
                     callback: function () {
                         $.bootstrapLoading.start();
@@ -953,10 +949,13 @@ var projectObj = {
                 "pasteBlock": {
                     name: '粘贴整块',
                     icon: 'fa-paste',
+                    disabled: function (){
+                        return BlockController.pasteBtnDisable(project.mainTree.selected);
+                    },
                     callback: function () {
-
+                        BlockController.pasteBlock(project.mainTree.selected);
                     }
-                }*/
+                }
             }
         });
     },
@@ -1579,6 +1578,42 @@ $('#property_ok').click(function () {
     }
 });
 
+function testShow() {
+    var controller = projectObj.mainController, project = projectObj.project;
+    var selected = controller.tree.selected, parent = selected.parent;
+    var showinfo = "<label>确认要删除当前选中行吗?</label>";
+    var showN = false;
+    var cancelText = "否";
+    if(selected.sourceType == project.Bills.getSourceType()&&selected.data.type==billType.FB&&selected.children.length>0){//选中的是分部,并且有子项
+        if(isSingleSelect()||selectionChecking()){
+            showinfo = "<label>是否删除其下的子项?</label><br><label>【是】则删除分部行及其下的所有子项,</label><br><label>【否】则仅删除当前分部行,子项保留,</label><br><label>【取消】则取消删除</label>";
+            showN = true;
+            cancelText = "取消";
+        }
+    }
+    $('#delete_showinfo').html(showinfo);
+    showN==true? $('#deleteN').show():$('#deleteN').hide();
+    $('#deleteCancel').text(cancelText);
+
+    function selectionChecking() {
+        let selection = projectObj.mainSpread.getActiveSheet().getSelections()[0];
+        let mainTreeMap = {};
+        for(let i =0;i<selection.rowCount;i++){
+            let tem_node = controller.tree.items[selection.row+i];
+            if(i==0){//第一个直接添加;
+                mainTreeMap[tem_node.getID()] = tem_node;
+            }else {
+                project.Bills.setNodeToMap(tem_node,mainTreeMap);
+            }
+        }
+        let nodes = changeMapToArray(mainTreeMap);
+        if(nodes.length==1){
+            return true
+        }
+        return false;
+    }
+}
+
 $('#delete_row').on('shown.bs.modal', function (e) {
     var controller = projectObj.mainController, project = projectObj.project;
     var selected = controller.tree.selected, parent = selected.parent;
@@ -1849,6 +1884,11 @@ function doAfterImport(resData){
 
 
 $(function () {
+    //清空导入清单选择文件
+    $('#import').on('show.bs.modal', function(){
+        $('#customFile').val('');
+        $('#uploadAlert').hide();
+    });
 
     $("#billsSpread").mouseover(function(){
         spreadAutoFocus(projectObj.mainSpread,subSpread);
@@ -1858,6 +1898,16 @@ $(function () {
         spreadAutoFocus(subSpread,projectObj.mainSpread);
     });
 
+    $("#paste_confirm").click(function (){
+        let selected = projectObj.project.mainTree.selected;
+        let blockData = BlockController.getBlockData();
+        let position = $("input[name='pastePositionRadio']:checked").val();
+        BlockController.confirmPaste(blockData,selected,position);
+        $("#pastePosition").modal("hide");
+
+    });
+
+
     function spreadAutoFocus(spread,relateSpread) {
         if(relateSpread&&relateSpread.getActiveSheet().isEditing()){//关联的spread不在编辑状态的情况下,才自动获得焦点;
             return;

+ 4 - 7
web/building_saas/main/js/views/side_tools.js

@@ -59,18 +59,12 @@ var sideToolsObj = {
             $('.main-side .tab-pane').hide();
             tabPanel.show();
             loadSize(sideResizeEles, 'width', function(){
-                refreshSubSpread();
                 if(id === 'stdRationTab'){//定额库
-                    //autoFlashHeight();
                     loadSize(rationLibResizeEles, 'height', function(){
-                        rationLibObj.refreshSpread();;//subSpread、jobSpread、itemSpread显示问题
                     });
                 }
                 else{//清单库
                     loadSize(billsLibResizeEles, 'height', function(){
-                        //autoFlashHeight();
-                        billsLibObj.refreshBillsSpread();
-                        billsLibObj.refreshBillsRelaSpread();
                     });
                 }
             });
@@ -79,9 +73,12 @@ var sideToolsObj = {
             sideResizeEles.nearElement.css('width', '100%');
             sideResizeEles.farElement.css('width', '0%');
             tabPanel.hide();
-            refreshSubSpread();
         }
         autoFlashHeight();
+        billsLibObj.refreshBillsSpread();
+        refreshSubSpread();
+        billsLibObj.refreshBillsRelaSpread();
+        rationLibObj.refreshSpread();;//subSpread、jobSpread、itemSpread显示问题
     }
 };
 

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

@@ -11,8 +11,8 @@ var subRateObject={
     subRateSheet:null,
     subRateSetting:{
         header: [
-            {headerName: "参数名称", headerWidth: 250, dataCode: "name", dataType: "String"},
-            {headerName: "参数值", headerWidth: 200, dataCode: "optionValue", dataType: "String",getText:'forOption'}
+            {headerName: "参数名称", headerWidth: 110, dataCode: "name", dataType: "String"},
+            {headerName: "参数值", headerWidth: 150, dataCode: "optionValue", dataType: "String",getText:'forOption'}
         ],
         view: {
             lockColumns: [0]

+ 8 - 1
web/building_saas/main/js/views/sub_view.js

@@ -132,8 +132,15 @@ $("#use-to-current").click(function() {
     const self = $(this);
     self.attr('disabled', 'disabled');
     let selectedNode = projectObj.mainController.tree.selected;
+    function findBill(node){
+        while(node && node.sourceType !== projectObj.project.Bills.getSourceType()){
+            node = node.parent;
+        }
+        return node;
+    }
+    let billsNode = findBill(selectedNode);
     // 操作内容
-    pageCCOprObj.setCharacterBySetting(selectedNode, setting);
+    pageCCOprObj.setCharacterBySetting(billsNode, setting);
 
     // 防止连续点击1秒后才能再次发起请求
     setTimeout(function() {

+ 2 - 2
web/building_saas/pm/js/pm_gc.js

@@ -21,7 +21,7 @@ const gcTreeObj = {
             {name: '删除日期', dataCode: 'deleteDateTime', width: 170, vAlign: 'center', hAlign: 'left'},
             {name: '创建日期', dataCode: 'createDateTime', width: 170, vAlign: 'center', hAlign: 'left'},
             {name: '恢复', dataCode: 'recovery', width: 100, vAlign: 'center', hAlign: 'left'},
-            {name: '除', dataCode: 'delete', width: 100, vAlign: 'center', hAlign: 'left'},
+            {name: '彻底删除', dataCode: 'delete', width: 100, vAlign: 'center', hAlign: 'left'},
             {name: '单价文件', dataCode: 'unitPriceFile', width: 100, vAlign: 'center', hAlign: 'left'},
             {name: '单价文件-清除', dataCode: 'unitPriceFile_delete', width: 100, vAlign: 'center', hAlign: 'left'},
             {name: '费率文件', dataCode: 'feeRateFile', width: 100, vAlign: 'center', hAlign: 'left'},
@@ -633,7 +633,7 @@ function v_getMoBody(type, oprNode, nodes){
         html += ('<p>点“确定”按钮,确认从回收站中恢复</p>');
     }
     else{
-        html += ('<p>点“确定”按钮,确认除数据</p>');
+        html += ('<p>点“确定”按钮,确认彻底删除数据</p>');
     }
     return html;
 }

+ 55 - 11
web/building_saas/pm/js/pm_newMain.js

@@ -214,7 +214,10 @@ const projTreeObj = {
         if(args.sheet.name()=="copyToSheet"){ //如果是复制到表,不用做后面的操作
             return;
         }
-        if(selected.preSibling()!=null&&selected.preSibling() == targetNode){
+        if(selected.preSibling()!=null&&selected.preSibling() == targetNode&&selected.data.projType == targetNode.data.projType){//如果目标节点与选中节点的前一节点一样,并且选中节点与目标节点项目类型也一样的话,不用移动
+            return;
+        }
+        if(selected == targetNode){
             return;
         }
 
@@ -247,7 +250,6 @@ const projTreeObj = {
                 }
                 if(selected.pid() != rootProjectID){//跨了建设项目,更新子项目,同时要检查是否移动或复制子项的单价文件和费率文件。
                     //检查费率文件和单价文件
-                    //todo
                     for(let c of selected.children){
                         projectMap[c.id()] = {query:{'ID':c.id()},update:{'property.rootProjectID':rootProjectID}};
                         moveOrCopy(c,rootProjectID,feeRateMap,unitPriceMap,true);
@@ -300,7 +302,9 @@ const projTreeObj = {
                 projectMap[sel.preSibling().id()] = {query:{'ID':sel.preSibling().id()},update:{'NextSiblingID':sel.data.NextSiblingID}};
             }
             if(sel.parent.id() == tem_parent.id()){//移动前移动后的父项相同,只改变next
-                projectMap[selected.id()] = {query:{'ID':selected.id()},update:{'NextSiblingID':nextID}};
+                if(selected.id() != nextID){//父项相同的情况下, 下一节点ID如果等于选中的ID即项目没有移动,不用做处理
+                    projectMap[selected.id()] = {query:{'ID':selected.id()},update:{'NextSiblingID':nextID}};
+                }
             }else {//
                 let temData = {query:{'ID':selected.id()},update:{'ParentID':tem_parent.id(),'NextSiblingID':nextID}};
                 let reName = projTreeObj.projectNameChecking(tem_parent,selected);//重名检查
@@ -866,6 +870,9 @@ $(document).ready(function() {
     $('#add-project-btn').click(function () {
         let selectedItem = projTreeObj.tree.selected;
         $('#add-project-dialog').modal('show');
+        setTimeout(function () {
+            $('#project-name')[0].focus();
+        }, 300);
     });
 
     // 新增建设项目操作
@@ -902,6 +909,9 @@ $(document).ready(function() {
         try {
             if(selectedItem !== null  && selectedItem.data.projType !== projectType.folder){
                 $("#add-engineering-dialog").modal("show");
+                setTimeout(function () {
+                    $('#engineering-name')[0].focus();
+                }, 300);
             }
 
         } catch (error) {
@@ -1003,6 +1013,9 @@ $(document).ready(function() {
         let projs = getProjs(selected);
         setProjOptions(projs, selected);
         $($("input[name='valuation_type']")[0]).click();
+        setTimeout(function () {
+            $('#tender-name')[0].focus();
+        }, 300);
     });
 
     // 新增单位工程
@@ -1013,6 +1026,9 @@ $(document).ready(function() {
     // 新增文件夹按钮点击
     $("#add-folder-btn").click(function() {
         $("#add-folder-dialog").modal("show");
+        setTimeout(function () {
+            $('#folder-name')[0].focus();
+        }, 300);
     });
 
     // 新增文件夹操作
@@ -1097,6 +1113,9 @@ $(document).ready(function() {
         }
         $('#rename-name').val(projTreeObj.tree.selected.data.name ? projTreeObj.tree.selected.data.name : '');
         $('#rename-dialog').modal('show');
+        setTimeout(function () {
+            $('#rename-name')[0].focus();
+        }, 300);
     });
 
     // 重命名操作
@@ -1339,7 +1358,7 @@ function getChangedFunc(input, nameInfo){
             nameInfo.show();
         }
         else {
-            nameInfo.text('');
+            nameInfo.text('');N
             nameInfo.hide();
         }
     }
@@ -1825,11 +1844,8 @@ function AddTender() {
             return false;
         }
 
-        let unitPriceFile = $("#unit-price").val();
-        let unitPriceName = unitPriceFile !== '' ? $("#unit-price").children("option:selected").text() : tenderName;
-
-        let feeFile = $("#tender-fee-rate").val();
-        let feeFileName = $("#tender-fee-rate").children("option:selected").text();
+        let unitPriceFileObj = getAddTenderFile(tenderName, $('#unit-price'), $("#unit-price").children());
+        let feeFileObj = getAddTenderFile(tenderName, $('#tender-fee-rate'), $("#tender-fee-rate").children());
 
         let valuation = $("#valuation").val();
         if(valuation === ''){
@@ -1888,8 +1904,8 @@ function AddTender() {
             engineering: engineering,
             engineering_id: engineering_id,
             engineeringName: engineeringName,
-            unitPriceFile: {name: unitPriceName, id: unitPriceFile},
-            feeFile: {name: feeFileName, id: feeFile}
+            unitPriceFile: {name: unitPriceFileObj.name, id: unitPriceFileObj.id},
+            feeFile: {name: feeFileObj.name, id: feeFileObj.id}
         };
         AddTenderItems(selectedItem, projName, engName, tenderName, tenderInfo, callback);
 
@@ -1897,6 +1913,34 @@ function AddTender() {
         alert(error);
     }
 }
+/*
+* 新增单位工程时选择的文件
+* @tenderName {String}
+* @selValue {String}
+* @options {Array}
+* */
+function getAddTenderFile(tenderName, selected, options){
+    let rst = {name: '', id: ''};
+    let selValue = selected.val();
+    //选择的是新建单价/费率文件
+    if(selValue === ''){
+        //若新建的单位工程名称与建设项目下文件重名,则引用该文件
+        for(let option of options){
+            if($(option).text() === tenderName){
+                rst.id = $(option).val();
+                break;
+            }
+        }
+        rst.name = tenderName;
+    }
+    //非新建
+    else{
+        rst.id = selected.val();
+        rst.name =  selected.text();
+    }
+    return rst;
+}
+
 
 /**
  * 新增文件夹