浏览代码

Merge branch 'master' of http://192.168.1.12:3000/SmartCost/ConstructionCost

TonyKang 7 年之前
父节点
当前提交
b9fe9665dd
共有 85 个文件被更改,包括 8212 次插入676 次删除
  1. 75 1
      config/gulpConfig.js
  2. 141 1
      gulpfile.js
  3. 0 1
      modules/complementary_glj_lib/controllers/gljController.js
  4. 4 1
      modules/complementary_glj_lib/routes/routes.js
  5. 103 0
      modules/complementary_ration_lib/controllers/compleRationController.js
  6. 36 0
      modules/complementary_ration_lib/controllers/compleSectionTreeController.js
  7. 53 0
      modules/complementary_ration_lib/controllers/compleViewController.js
  8. 390 0
      modules/complementary_ration_lib/models/compleRationModel.js
  9. 29 0
      modules/complementary_ration_lib/models/compleViewModel.js
  10. 76 0
      modules/complementary_ration_lib/models/schemas.js
  11. 88 0
      modules/complementary_ration_lib/models/sectionTreeModel.js
  12. 46 0
      modules/complementary_ration_lib/routes/routes.js
  13. 16 5
      modules/glj/models/glj_list_model.js
  14. 18 16
      modules/main/facade/quantity_detail_facade.js
  15. 2 0
      modules/main/models/bills.js
  16. 1 0
      modules/main/models/ration.js
  17. 1 1
      modules/pm/models/templates/bills_template_model.js
  18. 2 1
      modules/pm/models/templates/schemas/bills_template.js
  19. 13 2
      modules/ration_glj/facade/ration_glj_facade.js
  20. 3 0
      modules/ration_glj/models/ration_glj_temp.js
  21. 1 1
      modules/ration_repository/controllers/ration_controller.js
  22. 1 1
      modules/ration_repository/controllers/ration_repository_controller.js
  23. 1 1
      modules/ration_repository/controllers/ration_section_tree_controller.js
  24. 2 2
      modules/ration_repository/controllers/search_controller.js
  25. 14 3
      modules/ration_repository/models/coe.js
  26. 1 1
      modules/ration_repository/models/glj_repository.js
  27. 5 1
      modules/ration_repository/models/ration_item.js
  28. 5 1
      modules/ration_repository/models/ration_section_tree.js
  29. 5 1
      modules/ration_repository/models/repository_map.js
  30. 9 0
      public/web/common_util.js
  31. 13 4
      public/web/sheet/sheet_common.js
  32. 8 1
      public/web/tree_sheet/tree_sheet_helper.js
  33. 8 4
      web/building_saas/complementary_glj_lib/html/tools-gongliaoji.html
  34. 2 1
      web/building_saas/complementary_glj_lib/js/components.js
  35. 46 38
      web/building_saas/complementary_glj_lib/js/glj.js
  36. 4 3
      web/building_saas/complementary_glj_lib/js/gljComponent.js
  37. 1 0
      web/building_saas/complementary_glj_lib/js/sheetOpr.js
  38. 504 0
      web/building_saas/complementary_ration_lib/html/dinge.html
  39. 88 0
      web/building_saas/complementary_ration_lib/html/fuzhu.html
  40. 288 0
      web/building_saas/complementary_ration_lib/html/gongliao.html
  41. 54 0
      web/building_saas/complementary_ration_lib/html/main.html
  42. 407 0
      web/building_saas/complementary_ration_lib/js/annotation.js
  43. 215 0
      web/building_saas/complementary_ration_lib/js/coe.js
  44. 95 0
      web/building_saas/complementary_ration_lib/js/explanatory.js
  45. 43 0
      web/building_saas/complementary_ration_lib/js/global.js
  46. 414 0
      web/building_saas/complementary_ration_lib/js/jobContent.js
  47. 33 0
      web/building_saas/complementary_ration_lib/js/main.js
  48. 662 0
      web/building_saas/complementary_ration_lib/js/ration.js
  49. 49 0
      web/building_saas/complementary_ration_lib/js/rationUnits.js
  50. 198 0
      web/building_saas/complementary_ration_lib/js/ration_assist.js
  51. 300 0
      web/building_saas/complementary_ration_lib/js/ration_coe.js
  52. 559 0
      web/building_saas/complementary_ration_lib/js/ration_glj.js
  53. 1012 0
      web/building_saas/complementary_ration_lib/js/repository_glj.js
  54. 442 0
      web/building_saas/complementary_ration_lib/js/section_tree.js
  55. 202 0
      web/building_saas/complementary_ration_lib/js/sheetsOpr.js
  56. 1 1
      web/building_saas/glj/js/composition.js
  57. 2 2
      web/building_saas/glj/js/composition_spread.js
  58. 1 0
      web/building_saas/glj/js/project_glj.js
  59. 7 1
      web/building_saas/glj/js/project_glj_spread.js
  60. 70 7
      web/building_saas/main/html/main.html
  61. 0 49
      web/building_saas/main/js/calc/calc_fees.js
  62. 46 4
      web/building_saas/main/js/controllers/project_controller.js
  63. 88 4
      web/building_saas/main/js/models/bills.js
  64. 0 1
      web/building_saas/main/js/models/cache_tree.js
  65. 216 104
      web/building_saas/main/js/models/calc_base.js
  66. 284 166
      web/building_saas/main/js/models/calc_program.js
  67. 12 1
      web/building_saas/main/js/models/composition.js
  68. 1 2
      web/building_saas/main/js/models/fee_rate.js
  69. 58 4
      web/building_saas/main/js/models/main_consts.js
  70. 97 5
      web/building_saas/main/js/models/project_glj.js
  71. 113 5
      web/building_saas/main/js/models/quantity_detail.js
  72. 36 4
      web/building_saas/main/js/models/ration.js
  73. 21 19
      web/building_saas/main/js/models/ration_glj.js
  74. 9 8
      web/building_saas/main/js/views/calc_base_view.js
  75. 1 2
      web/building_saas/main/js/views/calc_program_view.js
  76. 54 42
      web/building_saas/main/js/views/character_content_view.js
  77. 2 3
      web/building_saas/main/js/views/fee_rate_view.js
  78. 136 55
      web/building_saas/main/js/views/glj_view.js
  79. 1 1
      web/building_saas/main/js/views/glj_view_contextMenu.js
  80. 27 22
      web/building_saas/main/js/views/main_tree_col.js
  81. 1 1
      web/building_saas/main/js/views/project_property_decimal_view.js
  82. 130 38
      web/building_saas/main/js/views/project_view.js
  83. 1 1
      web/building_saas/main/js/views/std_bills_lib.js
  84. 7 31
      web/building_saas/main/js/views/sub_view.js
  85. 2 1
      web/common/html/header.html

+ 75 - 1
config/gulpConfig.js

@@ -120,7 +120,81 @@ module.exports = {
         'web/building_saas/main/js/views/fee_rate_view.js',
         'web/building_saas/main/js/views/sub_fee_rate_views.js',
         'web/building_saas/main/js/views/calc_base_view.js',
-        'web/building_saas/main/js/views/project_property_labour_coe_view.js'
+        'web/building_saas/main/js/views/project_property_labour_coe_view.js',
+        'web/building_saas/complementary_ration_lib/js/main.js',
+        'public/web/storageUtil.js'
+    ],
+    compleGlj_css: [
+        'lib/jquery-contextmenu/jquery.contextMenu.css',
+        'lib/ztree/css/zTreeStyle.css',
+        'lib/spreadjs/sheets/css/gc.spread.sheets.excel2013lightGray.10.0.1.css'
+    ],
+    compleGlj_jspaths: [
+        'public/web/common_ajax.js',
+        'public/web/treeDataHelper.js',
+        'public/web/QueryParam.js',
+        'web/building_saas/complementary_glj_lib/js/glj.js',
+        'web/building_saas/complementary_glj_lib/js/gljComponent.js',
+        'web/building_saas/complementary_glj_lib/js/components.js',
+        'public/web/ztree_common.js',
+        'public/web/sheet/sheet_common.js',
+        'web/building_saas/complementary_glj_lib/js/sheetOpr.js',
+        'public/web/storageUtil.js'
+    ],
+    compleRation_ration_css: [
+        'lib/jquery-contextmenu/jquery.contextMenu.css',
+        'lib/spreadjs/sheets/css/gc.spread.sheets.excel2013lightGray.10.0.1.css'
+    ],
+    compleRation_ration_jspaths:[
+        'web/building_saas/complementary_ration_lib/js/global.js',
+        'public/web/id_tree.js',
+        'public/web/tree_sheet/tree_sheet_controller.js',
+        'public/web/tree_sheet/tree_sheet_helper.js',
+        'public/web/treeDataHelper.js',
+        'public/web/sheet/sheet_common.js',
+        'web/building_saas/complementary_ration_lib/js/sheetsOpr.js',
+        'public/web/QueryParam.js',
+        'public/web/storageUtil.js',
+        'web/building_saas/complementary_ration_lib/js/section_tree.js',
+        'web/building_saas/complementary_ration_lib/js/explanatory.js',
+        'web/building_saas/complementary_ration_lib/js/jobContent.js',
+        'web/building_saas/complementary_ration_lib/js/annotation.js',
+        'public/web/scMathUtil.js',
+        'public/web/common_ajax.js',
+        'public/web/ztree_common.js',
+        'web/building_saas/complementary_ration_lib/js/rationUnits.js',
+        'web/building_saas/complementary_ration_lib/js/ration.js',
+        'web/building_saas/complementary_ration_lib/js/ration_glj.js',
+        'web/building_saas/complementary_ration_lib/js/ration_coe.js',
+        'web/building_saas/complementary_ration_lib/js/ration_assist.js'
+    ],
+    compleRation_glj_css: [
+        'lib/spreadjs/sheets/css/gc.spread.sheets.excel2013lightGray.10.0.1.css'
+    ],
+    compleRation_glj_jspaths: [
+        'web/building_saas/complementary_ration_lib/js/global.js',
+        'public/web/common_ajax.js',
+        'public/web/treeDataHelper.js',
+        'public/web/QueryParam.js',
+        'web/building_saas/complementary_ration_lib/js/repository_glj.js',
+        'public/web/ztree_common.js',
+        'public/web/sheet/sheet_common.js',
+        'web/building_saas/complementary_ration_lib/js/sheetsOpr.js',
+        'public/web/storageUtil.js'
+    ],
+    compleRation_coe_css: [
+        'lib/spreadjs/sheets/css/gc.spread.sheets.excel2013lightGray.10.0.1.css'
+    ],
+    compleRation_coe_jspaths: [
+        'web/building_saas/complementary_ration_lib/js/global.js',
+        'public/web/common_ajax.js',
+        'public/web/treeDataHelper.js',
+        'public/web/QueryParam.js',
+        'public/web/common_util.js',
+        'public/web/sheet/sheet_common.js',
+        'web/building_saas/complementary_ration_lib/js/sheetsOpr.js',
+        'public/web/storageUtil.js',
+        'web/building_saas/complementary_ration_lib/js/coe.js'
     ]
 }
 

+ 141 - 1
gulpfile.js

@@ -16,6 +16,14 @@ let pm_csspaths=config.pm_css;
 let login_jspaths=config.login_jspaths;
 let main_jspaths=config.main_jspaths;
 let main_csspaths=config.main_css;
+let compleGlj_jspaths = config.compleGlj_jspaths;
+let compleGlj_csspaths = config.compleGlj_css;
+let compleRation_ration_jspaths = config.compleRation_ration_jspaths;
+let compleRation_ration_csspaths = config.compleRation_ration_css;
+let compleRation_glj_jspaths = config.compleRation_glj_jspaths;
+let compleRation_glj_csspaths = config.compleRation_glj_css;
+let compleRation_coe_jspaths = config.compleRation_coe_jspaths;
+let compleRation_coe_csspaths = config.compleRation_coe_css;
 let version=config.version;
 let cssDest='web/dest/css';
 let scriptsDest='web/dest/scripts';
@@ -77,6 +85,73 @@ let mainOptions={
         'web/dest/css/main.all.min.'+version+'.css']
 }
 
+let compleGljOptions = {
+    version: version,
+    scriptsDest: 'web/dest/scripts',
+    jspaths: compleGlj_jspaths,
+    csspaths: compleGlj_csspaths,
+    concatName: 'compleGlj.all.min',
+    srcHtml: 'web/src/html/complementary_glj_lib/tools-gongliaoji.html',
+    htmlDest: 'web/building_saas/complementary_glj_lib/html/tools-gongliaoji.html',
+    htmlName: 'tools-gongliaoji.html',
+    injectList: [
+        'web/dest/scripts/compleGlj.all.min' + version + '.js',
+        'web/dest/css/compleGlj.all.min' + version + '.css',
+        'web/dest/css/common.all.min.' + version + '.css'
+    ]
+};
+
+let compleRation_rationOptions = {
+    version: version,
+    scriptsDest: 'web/dest/scripts',
+    jspaths: compleRation_ration_jspaths,
+    csspaths: compleRation_ration_csspaths,
+    concatName: 'compleRation_ration.all.min',
+    srcHtml: 'web/src/html/complementary_ration_lib/dinge.html',
+    htmlDest: 'web/building_saas/complementary_ration_lib/html/dinge.html',
+    htmlName: 'dinge.html',
+    injectList: [
+        'web/dest/scripts/compleRation_ration.all.min' + version + '.js',
+        'web/dest/css/compleRation_ration.all.min' + version + '.css',
+        'web/dest/scripts/common.all.min.'+version+'.js',
+        'web/dest/css/common.all.min.' + version + '.css'
+    ]
+};
+
+let compleRation_gljOptions = {
+    version: version,
+    scriptsDest: 'web/dest/scripts',
+    jspaths: compleRation_glj_jspaths,
+    csspaths: compleRation_glj_csspaths,
+    concatName: 'compleRation_glj.all.min',
+    srcHtml: 'web/src/html/complementary_ration_lib/gongliao.html',
+    htmlDest: 'web/building_saas/complementary_ration_lib/html/gongliao.html',
+    htmlName: 'gongliao.html',
+    injectList: [
+        'web/dest/scripts/compleRation_glj.all.min' + version + '.js',
+        'web/dest/scripts/compleRation_glj.all.min' + version + '.css',
+        'web/dest/scripts/common.all.min.'+version+'.js',
+        'web/dest/css/common.all.min.' + version + '.css'
+    ]
+};
+
+let compleRation_coeOptions = {
+    version: version,
+    scriptsDest: 'web/dest/scripts',
+    jspaths: compleRation_coe_jspaths,
+    csspaths: compleRation_coe_csspaths,
+    concatName: 'compleRation_coe.all.min',
+    srcHtml: 'web/src/html/complementary_ration_lib/fuzhu.html',
+    htmlDest: 'web/building_saas/complementary_ration_lib/html/fuzhu.html',
+    htmlName: 'fuzhu.html',
+    injectList: [
+        'web/dest/scripts/compleRation_coe.all.min' + version + '.js',
+        'web/dest/scripts/compleRation_coe.all.min' + version + '.css',
+        'web/dest/scripts/common.all.min.'+version+'.js',
+        'web/dest/css/common.all.min.' + version + '.css'
+    ]
+};
+
 function minify(options) {
     if(options.jspaths){
         return gulp.src(options.jspaths)
@@ -190,5 +265,70 @@ gulp.task('main',['main_inject'], function (){
     return htmlmin(mainOptions);
 });
 
+gulp.task('compleGlj_minify', ['common'], function () {
+    return minify(compleGljOptions);
+});
+
+gulp.task('compleGlj_css', function () {
+    return css(compleGljOptions);
+});
+
+gulp.task('compleGlj_inject', ['compleGlj_minify', 'compleGlj_css'], function () {
+    return inject(compleGljOptions);
+});
+
+gulp.task('compleGlj', ['compleGlj_inject'], function () {
+    return htmlmin(compleGljOptions);
+});
+
+gulp.task('compleRation_ration_minify', ['common'], function () {
+    return minify(compleRation_rationOptions);
+});
+
+gulp.task('compleRation_ration_css', function () {
+    return css(compleRation_rationOptions);
+});
+
+gulp.task('compleRation_ration_inject', ['compleRation_ration_minify', 'compleRation_ration_css'], function () {
+    return inject(compleRation_rationOptions);
+});
+
+gulp.task('compleRation_ration', ['compleRation_ration_inject'], function () {
+    return htmlmin(compleRation_rationOptions);
+});
+
+gulp.task('compleRation_glj_minify', ['common'], function () {
+    return minify(compleRation_gljOptions);
+});
+
+gulp.task('compleRation_glj_css', function () {
+    return css(compleRation_gljOptions);
+});
+
+gulp.task('compleRation_glj_inject', ['compleRation_glj_minify', 'compleRation_glj_css'], function () {
+    return inject(compleRation_gljOptions);
+});
+
+gulp.task('compleRation_glj', ['compleRation_glj_inject'], function () {
+    return htmlmin(compleRation_gljOptions);
+});
+
+gulp.task('compleRation_coe_minify', ['common'], function () {
+    return minify(compleRation_coeOptions);
+});
+
+gulp.task('compleRation_coe_css', function () {
+    return css(compleRation_coeOptions);
+});
+
+gulp.task('compleRation_coe_inject', ['compleRation_coe_minify', 'compleRation_coe_css'], function () {
+    return inject(compleRation_coeOptions);
+});
+
+gulp.task('compleRation_coe', ['compleRation_coe_inject'], function () {
+    return htmlmin(compleRation_coeOptions);
+});
+
+
 
-gulp.task('build',['header','login','pm','main']);
+gulp.task('build',['header','login','pm','main', 'compleGlj', 'compleRation_ration', 'compleRation_glj', 'compleRation_coe']);

+ 0 - 1
modules/complementary_glj_lib/controllers/gljController.js

@@ -13,7 +13,6 @@ let callback = function(req, res, err, message, data){
 
 class GljController extends BaseController{
     async redirectGlj(req, res){
-        console.log(req.s)
         let gljLibId = null, engineeringId, sessionCompilation = req.session.sessionCompilation,
             rationValuation = sessionCompilation.ration_valuation,
             billValuation = sessionCompilation.bill_valuation,

+ 4 - 1
modules/complementary_glj_lib/routes/routes.js

@@ -3,10 +3,12 @@
  */
 
 import express from "express";
-import GljController from "../controllers/gljController"
+import GljController from "../controllers/gljController";
+import CompleRationController from '../../complementary_ration_lib/controllers/compleRationController';
 
 let router = express.Router();
 let gljController = new GljController();
+let compleRationController = new CompleRationController();
 
 module.exports = function (app) {
     app.get('/complementaryGlj', gljController.init, gljController.redirectGlj);
@@ -21,6 +23,7 @@ module.exports = function (app) {
     router.post("/getGljItems", gljController.init, gljController.getGljItems);
     router.post("/updateComponent", gljController.init, gljController.updateComponent);
     router.post("/mixUpdateGljItems", gljController.init, gljController.mixUpdateGljItems);
+    router.post("/updateRationBasePrc",compleRationController.init, compleRationController.updateRationBasePrc);//更新定额单价
     //router.post("/getGljItemsByIds", gljController.init, gljController.getGljItemsByIds);
     //router.post("/getGljItemsByCodes", gljController.init, gljController.getGljItemsByCodes);
 

+ 103 - 0
modules/complementary_ration_lib/controllers/compleRationController.js

@@ -0,0 +1,103 @@
+/**
+ * Created by Zhong on 2017/12/21.
+ */
+
+import BaseController from '../../common/base/base_controller';
+import CompleRationDao from '../models/compleRationModel';
+
+let compleRationDao = new CompleRationDao();
+let coeListDAO = require('../../ration_repository/models/coe');
+let callback = function (req, res, err, msg, data) {
+    res.json({error: err, message: msg, data: data})
+}
+
+class CompleRationController extends BaseController{
+    getRationItems(req, res){
+        let data = JSON.parse(req.body.data);
+        compleRationDao.getRationItems(req.session.sessionUser.ssoId, data.rationRepId, data.sectionId, function (err, data) {
+            callback(req, res, err, '', data);
+        });
+    }
+
+    updateRations(req, res){
+        let data = JSON.parse(req.body.data);
+        compleRationDao.updateRation(req.session.sessionUser.ssoId, req.session.sessionCompilation._id, data.updateData, function (err, data) {
+            callback(req, res, err, '', data);
+        });
+    }
+
+    //更新补充定额价格
+    updateRationBasePrc(req, res){
+        let data = JSON.parse(req.body.data);
+        compleRationDao.updateRationBasePrc(req.session.sessionUser.ssoId, data.basePrcArr, function (err, data) {
+            callback(req, res, err, '', data);
+        });
+    }
+
+    mixUpdateRationItems(req, res){
+        let data = JSON.parse(req.body.data);
+        compleRationDao.mixUpdateRationItems(req.session.sessionUser.ssoId, req.session.sessionCompilation._id,
+            data.rationRepId, data.sectionId, data.updateItems, data.addItems, data.removeIds, function (err, data) {
+            callback(req, res, err, '', data);
+        });
+    }
+
+    //获取所有定额的编号
+    getRationsCodes(req, res){
+        let data = JSON.parse(req.body.data);
+        compleRationDao.getRationsCodes(req.session.sessionUser.ssoId, data.rationRepId, function (err, data) {
+            callback(req, res, err, '', data);
+        });
+    }
+
+    getGljItems(req, res){
+        let data = JSON.parse(req.body.data);
+        compleRationDao.getGljItems(data.gljLibId, function (err, data) {
+            callback(req, res, err, '', data);
+        })
+    }
+
+    getGljItemsOccupied(req, res){
+        let data = JSON.parse(req.body.data);
+        compleRationDao.getGljItemsOccupied(data.gljLibId, data.occupation, function (err, data) {
+            callback(req, res, err, '', data);
+        })
+    }
+
+    getGljItemsByIds(req, res){
+        let data = JSON.parse(req.body.data);
+        compleRationDao.getGljItemsByIds(req.session.sessionUser.ssoId, data.ids, function (err, data) {
+            callback(req, res, err, '', data);
+        });
+    }
+
+    getGljItemsByCodes(req, res){
+        let data = JSON.parse(req.body.data);
+        compleRationDao.getGljItemsByCodes(req.session.sessionUser.ssoId, req.session.sessionCompilation._id, data.rationRepId, data.gljCodes, function (err, data) {
+            callback(req, res, err, '', data);
+        });
+    }
+
+    getCoeList(req, res){
+        let data = JSON.parse(req.body.data);
+        coeListDAO.getCoesByLibID(data.libID, function (err, data) {
+            callback(req, res, err, '', data);
+        });
+    }
+
+    getCoeItemsByIDs(req, res){
+        let data = JSON.parse(req.body.data);
+        coeListDAO.getCoeItemsByIDs(data, function (err, data) {
+            callback(req, res, err, '', data);
+        });
+    }
+
+    getCoeItemsByNos(req, res){
+        let data = JSON.parse(req.body.data);
+        coeListDAO.getCoeItemsByNos(data, function (err, data) {
+            callback(req, res, err, '', data);
+        });
+    }
+}
+
+export default CompleRationController;

+ 36 - 0
modules/complementary_ration_lib/controllers/compleSectionTreeController.js

@@ -0,0 +1,36 @@
+/**
+ * Created by Zhong on 2017/12/21.
+ */
+
+import BaseController from '../../common/base/base_controller';
+import SectionTreeDao from '../models/sectionTreeModel';
+
+let sectionTreeDao = new SectionTreeDao();
+let callback = function (req, res, err, msg, data) {
+    res.json({error: err, message: msg, data: data});
+};
+
+class CompleSectionTreeController extends BaseController{
+    //保证章节树ID唯一,标准树与补充树才可进行拼接
+    getNewTreeID(req, res){
+        sectionTreeDao.getNewTreeID(function (err, data) {
+            callback(req, res, err, '', data);
+        });
+    }
+
+    getRationTree(req, res){
+        let data = JSON.parse(req.body.data);
+        sectionTreeDao.getRationTree(req.session.sessionUser.ssoId, data.rationRepId, function (err, data) {
+            callback(req, res, err, '', data);
+        });
+    }
+
+    updateRationSection(req, res){
+        let data = JSON.parse(req.body.data);
+        sectionTreeDao.updateSection(req.session.sessionUser.ssoId, req.session.sessionCompilation._id, data.updateData, function (err, data) {
+            callback(req, res, err, '', data);
+        });
+    }
+}
+
+export default CompleSectionTreeController;

+ 53 - 0
modules/complementary_ration_lib/controllers/compleViewController.js

@@ -0,0 +1,53 @@
+/**
+ * Created by Zhong on 2017/12/22.
+ */
+
+import BaseController from '../../common/base/base_controller';
+import CompleViewModel from '../models/compleViewModel';
+
+let compleViewModel = new CompleViewModel();
+let callback = function (req, res, err, msg, data) {
+    res.json({error: err, message: msg, data: data});
+};
+
+class CompleViewController extends BaseController{
+    redirectMain(req, res){
+        res.render('building_saas/complementary_ration_lib/html/main.html', {
+            userID: req.session.sessionUser.ssoId,
+            compilationId: req.session.sessionCompilation._id
+        });
+    }
+
+    redirectRation(req, res){
+        res.render('building_saas/complementary_ration_lib/html/dinge.html', {
+            userID: req.session.sessionUser.ssoId
+        });
+    }
+
+    redirectGljList(req, res){
+        res.render('building_saas/complementary_ration_lib/html/gongliao.html', {
+            userID: req.session.sessionUser.ssoId
+        });
+    }
+
+    redirectCoeList(req, res){
+        res.render('building_saas/complementary_ration_lib/html/fuzhu.html', {
+            userID: req.session.sessionUser.ssoId
+        });
+    }
+
+    getRationLib(req, res){
+        let data = JSON.parse(req.body.data);
+        compleViewModel.getRationLib(data.rationRepId, function (err, data) {
+            callback(req, res, err, '', data);
+        });
+    }
+
+    getRationLibs(req, res){
+        compleViewModel.getRationLibs(req.session.sessionCompilation._id, function (err, data) {
+            callback(req, res, err, '', data);
+        });
+    }
+}
+
+export default CompleViewController;

+ 390 - 0
modules/complementary_ration_lib/models/compleRationModel.js

@@ -0,0 +1,390 @@
+/**
+ * Created by Zhong on 2017/12/21.
+ */
+
+import {compleRationModel} from './schemas';
+import {complementaryGljModel, stdGljModel} from '../../complementary_glj_lib/models/schemas';
+import async from 'async';
+let stdRationModel = require ('../../ration_repository/models/ration_item').Model;
+let counter = require('../../../public/counter/counter');
+const scMathUtil = require('../../../public/scMathUtil').getUtil();
+
+class CompleRatoinDao {
+    async updateRation(userID, compilationId, updateData, callback){
+        try{
+            for(let i = 0, len = updateData.length; i < len; i++){
+                let updateObj = updateData[i];
+                if(updateObj.updateType === 'new'){
+                    updateObj.updateData.userID = userID;
+                    updateObj.updateData.compilationId = compilationId;
+                    await compleRationModel.create(updateObj.updateData);
+                }
+                else if(updateObj.updateType === 'update'){
+                    await compleRationModel.update({userID: userID, rationRepId: updateObj.updateData.rationRepId}, updateObj.updateData);
+                }
+            }
+            callback(0, '');
+        }
+        catch(err){
+            callback(err, null);
+        }
+    }
+
+    async getRationItems(userID, rationRepId, sectionId, callback){
+        try{
+            let stdRations = await stdRationModel.find({rationRepId: rationRepId, sectionId: sectionId, $or: [{isDeleted: null}, {isDeleted: false}]});
+            //mark std
+            for(let i = 0, len = stdRations.length; i < len; i++){
+                stdRations[i]._doc.type = 'std';
+            }
+            let compleRations = await compleRationModel.find({userId: userID, rationRepId: rationRepId, sectionId: sectionId, deleteInfo: null});
+            //mark complementary
+            for(let i = 0, len = compleRations.length; i < len; i++){
+                compleRations[i]._doc.type = 'complementary';
+            }
+            callback(0, stdRations.concat(compleRations));
+        }
+        catch(err){
+            callback(err, null);
+        }
+    }
+
+    async getRationsCodes(userID, rationRepId, callback){
+        try{
+            let stdRationCodes = await stdRationModel.find({rationRepId: rationRepId, $or: [{isDeleted: null}, {isDeleted: false}]}, '-_id code');
+            let compleRationCodes = await compleRationModel.find({userId: userID, rationRepId: rationRepId, deleteInfo: null}, '-_id code');
+            let rstCodes = [];
+            stdRationCodes.concat(compleRationCodes).forEach(function (rationItem) {
+                rstCodes.push(rationItem.code);
+            });
+            callback(0, rstCodes);
+        }
+        catch(err){
+            callback(err, null);
+        }
+    }
+
+    async getGljItems(gljLibId, callback){
+        try{
+            let stdGljs = await stdGljModel.find({repositoryId: gljLibId, $or: [{deleted: null}, {deleted: false}]});
+            callback(0, stdGljs);
+        }
+        catch(err){
+            callback(err, null);
+        }
+    }
+
+    async getGljItemsOccupied(gljLibId, occupation, callback){
+        try{
+            let stdGls = await stdGljModel.find({repositoryId: gljLibId, $or: [{deleted: null}, {deleted: false}]}, occupation);
+            callback(0, stdGls);
+        }
+        catch (err){
+            callback(err, null);
+        }
+    }
+
+
+    async getGljItemsByIds(userID, ids, callback){
+        try{
+            let rst = [];
+            for(let i = 0, len = ids.length; i < len; i++){
+                if(ids[i].type === 'std'){
+                    let stdGlj = await stdGljModel.find({ID: ids[i].id, deleteInfo: null});
+                    if(stdGlj.length > 0){
+                        stdGlj[0]._doc.type = 'std';
+                        rst.push(stdGlj[0]);
+                    }
+                }
+                else if(ids[i].type === 'complementary'){
+                    let compleGlj = await complementaryGljModel.find({userId: userID, ID: ids[i].id, deleteInfo: null});
+                    if(compleGlj.length > 0){
+                        compleGlj[0]._doc.type = 'complementary';
+                        rst.push(compleGlj[0]);
+                    }
+                }
+            }
+            callback(0, rst);
+        }
+        catch(err){
+            callback(err, null);
+        }
+    }
+
+    async getGljItemsByCodes(userID, compilationId, rationRepId, codes, callback){
+        try{
+            let rst = [];
+            for(let i = 0, len = codes.length; i < len; i++){
+                let stdGlj = await stdGljModel.find({repositoryId: rationRepId, code: codes[i]});
+                if(stdGlj.length > 0){
+                    stdGlj[0]._doc.type = 'std';
+                    rst.push(stdGlj[0]);
+                }
+                else {
+                    let compleGlj = await complementaryGljModel.find({userId: userID, compilationId: compilationId, code: codes[i]});
+                    if(compleGlj.length > 0){
+                        compleGlj[0]._doc.type = 'complementary';
+                        rst.push(compleGlj[0]);
+                    }
+                }
+            }
+            callback(0, rst);
+        }
+        catch(err){
+            callback(err, null);
+        }
+    }
+
+    updateRationBasePrc(userID, basePrcArr, callback){
+        let me  = this;
+        async.each(basePrcArr, function (basePrcObj, finalCb) {
+            let adjGljId = basePrcObj.gljId, adjBasePrice = basePrcObj.basePrice, adjGljType = basePrcObj.gljType;
+            async.waterfall([
+                function (cb) {
+                    if(typeof basePrcObj.delete !== 'undefined' && basePrcObj.delete === 1){
+                        //补充定额
+                        compleRationModel.find({'rationGljList.gljId': adjGljId},{ID: 1, rationGljList: 1}, function (err, compleRst) {
+                            if(err){
+                                cb(err);
+                            }
+                            else {
+                                compleRationModel.update({'rationGljList.gljId': adjGljId}, {$pull: {rationGljList: {gljId: adjGljId}}}, {multi: true}, function (err) {
+                                    if(err){
+                                        cb(err);
+                                    }
+                                    else {
+                                        cb(null, compleRst);
+                                    }
+                                });
+                            }
+                        });
+
+                    }
+                    else{
+                        compleRationModel.find({'rationGljList.gljId': adjGljId}, function (err, compleRst) {
+                            if(err){
+                                cb(err);
+                            }
+                            else {
+                                cb(null, compleRst);
+                            }
+                        });
+                    }
+                },
+                function (result, cb) {
+                    async.each(result, function (rationItem, ecb) {
+                        let rationGljList = rationItem.rationGljList,
+                            gljIds = [];
+                        rationGljList.forEach(function (rationGlj) {
+                            let idObj = Object.create(null);
+                            idObj.id = rationGlj.gljId;
+                            idObj.type = rationGlj.type;
+                            gljIds.push(idObj);
+                        });
+                        me.getGljItemsByIds(userID, gljIds, function(err, gljItems){
+                            if(err){
+                                ecb(err);
+                            }
+                            else{
+                                let gljArr = [];
+                                for(let i=0; i<gljItems.length; i++){
+                                    let gljParentType = -1;
+                                    if(gljItems[i].ID === adjGljId){
+                                        gljItems[i].gljType = adjGljType;
+                                    }
+                                    if(gljItems[i].gljType <= 3){
+                                        gljParentType = gljItems[i].gljType;
+                                    }
+                                    if(gljItems[i].gljType > 200 && gljItems[i].gljType < 300){
+                                        gljParentType = 2;
+                                    }
+                                    if(gljItems[i].gljType > 300 && gljItems[i].gljType < 400){
+                                        gljParentType = 3;
+                                    }
+                                    if(gljItems[i].ID === adjGljId){
+                                        gljArr.push({gljId: gljItems[i].ID, basePrice: adjBasePrice, gljParentType: gljParentType});
+                                    }
+                                    else {
+                                        gljArr.push({gljId: gljItems[i].ID, basePrice: parseFloat(gljItems[i].basePrice), gljParentType: gljParentType});
+                                    }
+                                }
+                                gljArr.forEach(function (gljItem) {
+                                    rationGljList.forEach(function (rationGlj) {
+                                        if(gljItem.gljId === rationGlj.gljId){
+                                            gljItem.consumeAmt = parseFloat(rationGlj.consumeAmt);
+                                        }
+                                    })
+                                });
+                                //recalculate the price of ration
+                                let labourPrc = [], materialPrc = [], machinePrc = [], singlePrc, updatePrc = {labourPrice: 0, materialPrice: 0, machinePrice: 0, basePrice: 0};
+                                gljArr.forEach(function (gljItem) {
+                                    if(gljItem.gljParentType !== -1){
+                                        singlePrc = scMathUtil.roundTo(gljItem.basePrice * gljItem.consumeAmt, -3);
+                                        if(gljItem.gljParentType === 1){
+                                            labourPrc.push(singlePrc);
+                                        }
+                                        else if(gljItem.gljParentType ===2){
+                                            materialPrc.push(singlePrc);
+                                        }
+                                        else{
+                                            machinePrc.push(singlePrc);
+                                        }
+                                    }
+                                });
+                                if(labourPrc.length > 0){
+                                    let sumLaP = 0;
+                                    for(let i=0; i<labourPrc.length; i++){
+                                        sumLaP += labourPrc[i];
+                                    }
+                                    updatePrc.labourPrice = scMathUtil.roundTo(sumLaP, -2);
+                                }
+                                if(materialPrc.length > 0){
+                                    let sumMtP = 0;
+                                    for(let i= 0; i<materialPrc.length; i++){
+                                        sumMtP += materialPrc[i];
+                                    }
+                                    updatePrc.materialPrice = scMathUtil.roundTo(sumMtP, -2);
+                                }
+                                if(machinePrc.length > 0){
+                                    let sumMaP = 0;
+                                    for(let i =0; i< machinePrc.length; i++){
+                                        sumMaP += machinePrc[i];
+                                    }
+                                    updatePrc.machinePrice = scMathUtil.roundTo(sumMaP, -2);
+                                }
+                                updatePrc.basePrice = scMathUtil.roundTo(updatePrc.labourPrice + updatePrc.materialPrice + updatePrc.machinePrice, -2);
+                                //updateDataBase
+                                compleRationModel.update({ID: rationItem.ID}, {$set: {labourPrice: updatePrc.labourPrice.toString(), materialPrice: updatePrc.materialPrice.toString(),
+                                        machinePrice: updatePrc.machinePrice.toString(), basePrice: updatePrc.basePrice.toString()}},
+                                    function (err, result) {
+                                        if(err){
+                                            ecb(err);
+                                        }
+                                        else {
+                                            ecb(null);
+                                        }
+                                    });
+                            }
+                        });
+                    }, function(err){
+                        if(err){
+                            cb(err);
+                        }
+                        else {
+                            cb(null);
+                        }
+                    });
+                },
+            ], function (err) {
+                if(err){
+                    finalCb(err);
+                }
+                else{
+                    finalCb(null);
+                }
+            });
+        }, function (err) {
+            if(err){
+                callback(err, 'Error');
+            }
+            else{
+                callback(0, '');
+            }
+        });
+    }
+
+    mixUpdateRationItems (userID, compilationId, rationLibId, sectionId, updateItems, addItems, rIds, callback){
+        let me = this;
+        if (updateItems.length == 0 && rIds.length == 0) {
+            me.addRationItems(userID, compilationId, rationLibId, sectionId, addItems, callback);
+        } else {
+            me.removeRationItems(rationLibId, rIds, function(err, message, docs) {
+                if (err) {
+                    callback(true, false);
+                } else {
+                    me.updateRationItems(userID, rationLibId, sectionId, updateItems, function(err, results){
+                        if (err) {
+                            callback(true, false);
+                        } else {
+                            if (addItems && addItems.length > 0) {
+                                me.addRationItems(rationLibId, sectionId, addItems, callback);
+                            } else {
+                                callback(0, results);
+                            }
+                        }
+                    });
+                }
+            })
+        }
+    }
+
+     removeRationItems(rationRepId, rIds,callback){
+        if (rIds.length > 0) {
+            compleRationModel.remove({rationRepId: rationRepId, ID: {$in: rIds}}, function(err, docs){
+                if (err) {
+                    callback(true, false);
+                } else {
+                    callback(0, docs);
+                }
+            })
+        } else {
+            callback(0,  null);
+        }
+    }
+
+
+     addRationItems(userID, compilationId, rationLibId, sectionId, items,callback){
+        if (items && items.length > 0) {
+            counter.counterDAO.getIDAfterCount(counter.moduleName.rations, items.length, function(err, result){
+                let maxId = result.value.sequence_value;
+                let arr = [];
+                for (let i = 0; i < items.length; i++) {
+                    let obj = new compleRationModel(items[i]);
+                    obj.ID = (maxId - (items.length - 1) + i);
+                    obj.sectionId = sectionId;
+                    obj.rationRepId = rationLibId;
+                    obj.userId = userID;
+                    obj.compilationId = compilationId;
+                    arr.push(obj);
+                }
+                compleRationModel.collection.insert(arr, null, function(err, docs){
+                    if (err) {
+                        callback(true, false);
+                    } else {
+                        callback(0, docs);
+                    }
+                })
+            });
+        } else {
+            callback(true, "Source error!", false);
+        }
+    }
+
+     updateRationItems(userID, rationLibId, sectionId, items,callback){
+        let functions = [];
+        for (let i=0; i < items.length; i++) {
+            functions.push((function(doc) {
+                return function(cb) {
+                    var filter = {};
+                    if (doc.ID) {
+                        filter.ID = doc.ID;
+                    } else {
+                        filter.sectionId = sectionId;
+                        filter.userId = userID;
+                        if (rationLibId) filter.rationRepId = rationLibId;
+                        filter.code = doc.code;
+                    }
+                    compleRationModel.update(filter, doc, cb);
+                };
+            })(items[i]));
+        }
+        async.parallel(functions, function(err, results) {
+            if(!err){
+                err = 0;
+            }
+            callback(err, results);
+        });
+    }
+}
+
+export default CompleRatoinDao;

+ 29 - 0
modules/complementary_ration_lib/models/compleViewModel.js

@@ -0,0 +1,29 @@
+/**
+ * Created by Zhong on 2017/12/22.
+ */
+
+let rationRepositoryModel = require('../../ration_repository/models/repository_map').Model;
+
+class CompleViewModel {
+    async getRationLib(rationRepId, callback){
+        try{
+            let rationLib = await rationRepositoryModel.find({ID: rationRepId, $or: [{deleted: null}, {deleted: false}]});
+            callback(0, rationLib);
+        }
+        catch(err) {
+            callback(err, null);
+        }
+    }
+
+    async getRationLibs(compilationId, callback){
+        try{
+            let rationLibs = await rationRepositoryModel.find({compilationId: compilationId, $or: [{deleted: null}, {deleted: false}]});
+            callback(0, rationLibs);
+        }
+        catch(err) {
+            callback(err, null);
+        }
+    }
+}
+
+export default CompleViewModel;

+ 76 - 0
modules/complementary_ration_lib/models/schemas.js

@@ -0,0 +1,76 @@
+/**
+ * Created by Zhong on 2017/12/21.
+ */
+
+import mongoose from 'mongoose';
+
+let deleteSchema = require('../../../public/models/delete_schema');
+let Schema = mongoose.Schema;
+
+//补充定额章节树
+let compleRationSectionTreeSchema = new Schema({
+    //用户名
+    userId: Number,
+    //编办
+    compilationId: String,
+    //标准定额库
+    rationRepId: Number,
+    //名称
+    name: String,
+    //是否是同层第一个节点
+    isFirst: Boolean,
+    ID: Number,
+    NextSiblingID: Number,
+    ParentID: Number,
+    deleteInfo: deleteSchema
+}, {versionKey: false});
+
+//定额工料机
+let compleRationGljItemSchema = new Schema({
+    gljId: Number,
+    consumeAmt: String,
+    type: String    //std or complementary
+
+}, { _id: false });
+
+//辅助定额调整
+let compleRationAssItemSchema = new Schema({
+    name: String,
+    assistID: Number,
+    assistCode: String,
+    stdValue: String,
+    stepValue: String,
+    decimal: Number,
+    carryBit: String,
+    minValue: String,
+    maxValue: String
+}, { _id: false });
+
+//补充定额
+let compleRationSchema = new Schema({
+    userId: Number,
+    compilationId: String,
+    rationRepId: Number,
+    ID:Number,
+    code: String,
+    name: String,
+    unit: String,
+    labourPrice: String,
+    materialPrice: String,
+    machinePrice: String,
+    basePrice: String,
+    sectionId: Number,
+    caption: String,
+    feeType: Number,
+    jobContent: String,
+    annotation: String,
+    rationGljList: [compleRationGljItemSchema],
+    rationCoeList: Array,
+    rationAssList: [compleRationAssItemSchema],
+    deleteInfo: deleteSchema
+}, {versionKey: false});
+
+let compleRationSectionTreeModel = mongoose.model('complementary_ration_section_tree', compleRationSectionTreeSchema, 'complementary_ration_section_tree');
+let compleRationModel = mongoose.model('complementary_ration_items', compleRationSchema, 'complementary_ration_items');
+
+export {compleRationSectionTreeModel, compleRationModel};

+ 88 - 0
modules/complementary_ration_lib/models/sectionTreeModel.js

@@ -0,0 +1,88 @@
+/**
+ * Created by Zhong on 2017/12/21.
+ */
+
+import {compleRationSectionTreeModel} from './schemas';
+
+let counter = require('../../../public/counter/counter');
+let stdSectionTreeModel = require ('../../ration_repository/models/ration_section_tree').Model;
+
+class SectionTreeDao {
+    getNewTreeID(callback){
+        counter.counterDAO.getIDAfterCount(counter.moduleName.rationTree, 1, function (err, result) {
+            if(err){
+                callback(err, null);
+            }
+            else {
+                callback(0, result.value.sequence_value);
+            }
+        });
+
+    }
+
+    //获取补充定额拼接章节树
+    async getRationTree(userID, rationRepId, callback){
+        try{
+            let stdSectionTree = await stdSectionTreeModel.find({rationRepId: rationRepId, $or: [{isDeleted: null}, {isDeleted: false}]});
+            let compleSectionTree = await compleRationSectionTreeModel.find({userId: userID, rationRepId: rationRepId, deleteInfo: null});
+            let dropPids = [], rstCompleSectionTree = [];
+            //mark std
+            for(let i = 0, len = stdSectionTree.length; i < len; i++){
+                stdSectionTree[i]._doc.type = 'std';
+            }
+            for(let i = 0, len = compleSectionTree.length; i < len; i++){
+                //mark complementary
+                compleSectionTree[i]._doc.type = 'complementary';
+                if(compleSectionTree[i]['isFirst']){
+                    let updateSection = getUpdateSection(compleSectionTree[i]['ParentID'], stdSectionTree);
+                    if(updateSection) {
+                        updateSection._doc.NextSiblingID = compleSectionTree[i]['ID'];
+                    }
+                    else if(!updateSection && compleSectionTree[i]['ParentID'] !== -1){
+                        dropPids.push(compleSectionTree[i]['ParentID']);
+                    }
+                }
+            }
+            function getUpdateSection(pid, datas){
+                for(let i = 0, len = datas.length; i < len; i++){
+                    if(datas[i]['ParentID'] === pid && datas[i]['NextSiblingID'] === -1){
+                        return datas[i];
+                    }
+                }
+                return null;
+            }
+            //返回父节点未被删除的
+            for(let i = 0, len = compleSectionTree.length; i < len; i++){
+                if(dropPids.indexOf(compleSectionTree[i]['ParentID']) === -1){
+                    rstCompleSectionTree.push(compleSectionTree[i]);
+                }
+            }
+            callback(0, stdSectionTree.concat(rstCompleSectionTree));
+        }
+        catch (err){
+            callback(err, null);
+        }
+    }
+
+    async updateSection(userID, compilationId, updateData, callback){
+        try{
+            for(let i = 0, len = updateData.length; i < len; i++){
+                let updateObj = updateData[i];
+                if(updateObj.updateType === 'new'){
+                    updateObj.updateData.userId = userID;
+                    updateObj.updateData.compilationId = compilationId;
+                    await compleRationSectionTreeModel.create(updateObj.updateData);
+                }
+                else if(updateObj.updateType === 'update'){
+                    await compleRationSectionTreeModel.update({userId: userID, rationRepId: updateObj.updateData.rationRepId, ID: updateObj.updateData.ID}, updateObj.updateData);
+                }
+            }
+            callback(0, 'success');
+        }
+        catch(err){
+            callback(err, null);
+        }
+    }
+}
+
+export default SectionTreeDao;

+ 46 - 0
modules/complementary_ration_lib/routes/routes.js

@@ -0,0 +1,46 @@
+/**
+ * Created by Zhong on 2017/12/21.
+ */
+
+import express from 'express';
+import CompleViewController from '../controllers/compleViewController';
+import CompleSectionTreeController from '../controllers/compleSectionTreeController';
+import CompleRationController from '../controllers/compleRationController';
+import GljController from '../../complementary_glj_lib/controllers/gljController';
+
+let router = express.Router();
+let compleViewController = new CompleViewController();
+let compleSectionTreeController = new CompleSectionTreeController();
+let compleRationController = new CompleRationController();
+let gljController = new GljController();
+
+module.exports = function (app) {
+    //app.get('/complementaryRation/main', compleViewController.init, compleViewController.redirectMain);
+    app.get('/complementaryRation/ration', compleViewController.init, compleViewController.redirectRation);
+    app.get('/complementaryRation/glj', compleViewController.init, compleViewController.redirectGljList);
+    app.get('/complementaryRation/coe', compleViewController.init, compleViewController.redirectCoeList);
+
+    router.post('/getRationLib', compleViewController.init, compleViewController.getRationLib);
+    router.post('/getRationLibs', compleViewController.init, compleViewController.getRationLibs);
+
+    router.post('/getNewTreeID', compleSectionTreeController.init, compleSectionTreeController.getNewTreeID);
+    router.post('/getRationTree', compleSectionTreeController.init, compleSectionTreeController.getRationTree);
+    router.post('/updateRationSection', compleSectionTreeController.init, compleSectionTreeController.updateRationSection);
+
+    router.post('/getRationItems', compleRationController.init, compleRationController.getRationItems);
+    router.post('/mixUpdateRationItems', compleRationController.init, compleRationController.mixUpdateRationItems);
+
+    router.post('/getGljDistType', gljController.init, gljController.getGljDistType);
+    router.post('/getGljTree', gljController.init, gljController.getGljTree);
+    router.post('/getGljItems', compleRationController.init, compleRationController.getGljItems);
+    router.post('/getGljItemsOccupied', compleRationController.init, compleRationController.getGljItemsOccupied);
+    router.post('/getRationsCodes', compleRationController.init, compleRationController.getRationsCodes);
+    router.post('/getGljItemsByIds', compleRationController.init, compleRationController.getGljItemsByIds);
+    router.post('/getGljItemsByCodes', compleRationController.init, compleRationController.getGljItemsByCodes);
+
+    router.post('/getCoeList', compleRationController.init, compleRationController.getCoeList);
+    router.post('/getCoeItemsByIDs', compleRationController.init, compleRationController.getCoeItemsByIDs);
+    router.post('/getCoeItemsByNos', compleRationController.init, compleRationController.getCoeItemsByNos);
+
+    app.use('/complementaryRation/api', router);
+};

+ 16 - 5
modules/glj/models/glj_list_model.js

@@ -36,7 +36,7 @@ class GLJListModel extends BaseModel {
      * @var {Array}
      */
     ownCompositionTypes = [GLJTypeConst.CONCRETE, GLJTypeConst.MORTAR, GLJTypeConst.MIX_RATIO,
-        GLJTypeConst.COMMERCIAL_CONCRETE, GLJTypeConst.COMMERCIAL_MORTAR, GLJTypeConst.GENERAL_MACHINE];
+        GLJTypeConst.COMMERCIAL_CONCRETE, GLJTypeConst.COMMERCIAL_MORTAR, GLJTypeConst.GENERAL_MACHINE,GLJTypeConst.MAIN_MATERIAL];
 
     /**
      * 构造函数
@@ -109,6 +109,7 @@ class GLJListModel extends BaseModel {
                 projectGLJIDList: gljIdList
             };
             let quantityData = await RationGLJFacade.getQuantityByProjectGLJ(condition);
+            let rationTypeQuantity = await RationGLJFacade.getRationTypeGLJQuantity(projectId);
             let quantityList = {};
             // 整理数据 得到总定额消耗量
             for (let tmp of quantityData) {
@@ -122,13 +123,23 @@ class GLJListModel extends BaseModel {
                     quantityList[tmp_con_key] = scMathUtil.roundTo(quantityList[tmp_con_key]+tmp.quantity * tmpNum,-quantity_decimal);
                 }
             }
+            //计算定额类型工料机的消耗量
+            for(let rq of rationTypeQuantity){
+                let rq_key = keyMap[rq.projectGLJID];
+                let rq_quantity= scMathUtil.roundForObj(rq.quantity,quantity_decimal);
+                if(quantityList[rq_key] === undefined){
+                    quantityList[rq_key] =  scMathUtil.roundTo(rq_quantity,-quantity_decimal);
+                }else {
+                    quantityList[rq_key] = scMathUtil.roundTo(quantityList[rq_key]+rq_quantity,-quantity_decimal);
+                }
+            }
             // 整理获取有组成物的项目工料机的数据
             let connect_keys = [];
             for(let tmp of gljData) {
                 // 有组成物的类型才查找
                 let key = keyMap[tmp.id];
                 if (quantityList[key]!=undefined&&(tmp.type === GLJTypeConst.CONCRETE || tmp.type === GLJTypeConst.MORTAR ||
-                    tmp.type === GLJTypeConst.MIX_RATIO || tmp.type === GLJTypeConst.GENERAL_MACHINE)){
+                    tmp.type === GLJTypeConst.MIX_RATIO || tmp.type === GLJTypeConst.GENERAL_MACHINE|| tmp.type === GLJTypeConst.MAIN_MATERIAL)){
                     connect_keys.push(key);
                 }
             }
@@ -298,9 +309,9 @@ class GLJListModel extends BaseModel {
             }
             let CompositionGLJ=[];
             let unitPriceModel = new UnitPriceModel();
-            // 判断类型,如果是混凝土、砂浆或者配合比则查找对应的组成物(前提是没有对应的项目工料机数据)
+            // 判断类型,如果是混凝土、砂浆、配合比或者主材则查找对应的组成物(前提是没有对应的项目工料机数据)
             if (data.type === GLJTypeConst.CONCRETE || data.type === GLJTypeConst.MORTAR ||
-                data.type === GLJTypeConst.MIX_RATIO || data.type === GLJTypeConst.GENERAL_MACHINE) {
+                data.type === GLJTypeConst.MIX_RATIO || data.type === GLJTypeConst.GENERAL_MACHINE||data.type === GLJTypeConst.MAIN_MATERIAL) {
                 //如果是新增
                 if(isAddProjectGLJ ){
                     await this.compositionInit(data, unitPriceFileId);
@@ -676,7 +687,7 @@ class GLJListModel extends BaseModel {
             let projectGLJData = await this.getDataById(projectGLJId,unitPriceFileId);
 
             let allowType = [GLJTypeConst.MIX_RATIO, GLJTypeConst.CONCRETE, GLJTypeConst.MORTAR,
-                GLJTypeConst.GENERAL_MACHINE];
+                GLJTypeConst.GENERAL_MACHINE,GLJTypeConst.MAIN_MATERIAL];
 
             if (projectGLJData.unit_price === null || allowType.indexOf(projectGLJData.unit_price.type) < 0) {
                 throw '找不到相关项目工料机';

+ 18 - 16
modules/main/facade/quantity_detail_facade.js

@@ -112,9 +112,7 @@ async function updateRegex(datas) {
     await quantity_detail_model.bulkWrite(generateUpdateTaks(updateTasks));
     resultObjec.refreshList=updateTasks;
     if(datas.query.refreshQuantity==true){
-        let data = {};
-        data.quantity = await summateResults(datas.query,detailList,decimal);
-        data.isFromDetail = 1;
+        let data = await summateResults(datas.query,detailList,decimal);
         node.data = data;
         resultObjec.node = node;
     }
@@ -259,9 +257,7 @@ async function insertRecodeWithReg (doc) {
         let newRecord = await quantity_detail_model.create(doc) ;
         detailList.push(newRecord);
         if(refreshQuantity==true){
-            let data = {};
-            data.quantity = await summateResults(doc,detailList,decimal);
-            data.isFromDetail = 1;
+            let data = await summateResults(doc,detailList,decimal);
             returnObjec.node.data = data;
         }
         returnObjec.newRecord = newRecord;
@@ -283,9 +279,7 @@ async function doIsSummationUpdate(query,doc) {
     await quantity_detail_model.update(query,doc);
     let detailList = await getDatailList(query,returnObjec);
     if(refreshQuantity==true){
-        let data = {};
-        data.quantity = await summateResults(query,detailList,decimal);
-        data.isFromDetail = 1;
+        let data = await summateResults(query,detailList,decimal);
         returnObjec.node.data = data;
     }
     return returnObjec;
@@ -331,6 +325,7 @@ function updateReferenceRecode(index,detailList,updateTasks) {
 
 async function summateResults (query,detailList,decimal) {
     let quantity = 0;
+    let doc = {};
      decimal = decimal?decimal:await decimal_facade.getProjectDecimal(query.projectID);
     for(let d of detailList){
         if(d.isSummation==1){
@@ -340,17 +335,25 @@ async function summateResults (query,detailList,decimal) {
     }
     if(query.hasOwnProperty('rationID')){
         let ration = await  ration_model.findOne({'ID':query.rationID,'projectID':query.projectID,deleteInfo: null});
+        let bill = await bill_model.findOne({'projectID':query.projectID,deleteInfo: null,"ID":ration.billsItemID});
+        let bill_decimal = await decimal_facade.getBillsQuantityDecimal(query.projectID,bill.unit);
+        let bill_quantity = scMathUtil.roundForObj(bill.quantity,bill_decimal);
+        let contain = bill_quantity==0?0:scMathUtil.roundForObj(quantity/bill_quantity,decimal.process);
+        let r_quantity = quantity;
         quantity = getQuantityByUnit(quantity,ration.unit);
         quantity = scMathUtil.roundTo(quantity, -decimal.ration.quantity);
-        await ration_model.update({'ID':query.rationID,'projectID':query.projectID,deleteInfo: null},{quantity:quantity,isFromDetail:1});
+        doc={quantity:quantity,isFromDetail:1,quantityEXP:'GCLMXHJ',contain:contain};
+        await ration_model.update({'ID':query.rationID,'projectID':query.projectID,deleteInfo: null},doc);
+        doc.r_quantity = r_quantity;
     }else {
         let bill = await bill_model.findOne({'ID':query.billID,'projectID':query.projectID,deleteInfo: null});
         decimal = await decimal_facade.getBillsQuantityDecimal(query.projectID,bill.unit);
-        quantity = getQuantityByUnit(quantity,bill.unit);
+       // quantity = getQuantityByUnit(quantity,bill.unit);
         quantity = scMathUtil.roundTo(quantity, -decimal);
-        await bill_model.update({'ID':query.billID,'projectID':query.projectID,deleteInfo: null},{quantity:quantity,isFromDetail:1});
+        doc = {quantity:quantity,isFromDetail:1};
+        await bill_model.update({'ID':query.billID,'projectID':query.projectID,deleteInfo: null},doc);
     }
-    return quantity
+    return doc
 }
 
 function getQuantityByUnit(quantity,unit) {
@@ -476,9 +479,8 @@ async function deleteRecode(doc) {
     await quantity_detail_model.deleteOne({ID:doc.ID,projectID:doc.projectID});
     _.remove(quantity_detail_List,{ID:doc.ID,projectID:doc.projectID});
 
-    let n_data = {};//更新节点信息
-    n_data.quantity = await summateResults(query,quantity_detail_List,decimal);
-    n_data.isFromDetail = 1;
+    //更新节点信息
+    let n_data = await summateResults(query,quantity_detail_List,decimal);
     resultObject.node.data = n_data;
 
     let r_data ={

+ 2 - 0
modules/main/models/bills.js

@@ -23,6 +23,8 @@ let billsSchema = new Schema({
     chapterID: Number,
     code: String,
     fullCode: String,
+    type:{type: Number,default:4},//1 :大项费用 2:分部 3分项 4清单
+    isAdd:{type: Number,default:0},//1 true 0 false是否新增
     name: String,
     unit: String,
     quantity: String, // Decimal

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

@@ -38,6 +38,7 @@ let rationSchema = new Schema({
     unit: String,
     quantity: String,
     contain:String,//含量
+    quantityEXP:String,//工程量表达式
     programID: Number,
     marketUnitFee: String,
     marketTotalFee: String,

+ 1 - 1
modules/pm/models/templates/bills_template_model.js

@@ -39,7 +39,7 @@ class BillsTemplateModel extends BaseModel {
      */
     async getTemplateDataForNewProj (valuationId, engineering) {
         // 筛选字段
-        let field = {_id: 0, ID: 1, ParentID: 1, NextSiblingID: 1, code: 1, name: 1, unit: 1, flags: 1};
+        let field = {_id: 0, ID: 1, ParentID: 1, NextSiblingID: 1, code: 1, name: 1, unit: 1, flags: 1,type:1};
         let data = await this.findDataByCondition({valuationId: valuationId, engineering: engineering}, field, false);
 
         return data === null ? [] : data;

+ 2 - 1
modules/pm/models/templates/schemas/bills_template.js

@@ -30,7 +30,8 @@ let BillsTemplateSchema = {
     // 所属计价ID
     valuationId: String,
     // 工程专业
-    engineering: Number
+    engineering: Number,
+    type:Number
 };
 
 let model = mongoose.model(collectionName, new Schema(BillsTemplateSchema, {versionKey: false, collection: collectionName}));

+ 13 - 2
modules/ration_glj/facade/ration_glj_facade.js

@@ -16,6 +16,7 @@ let ration_coe_facade = require('./ration_coe_facade');
 let ration_coe = mongoose.model('ration_coe');
 let std_ration_lib_ration_items = mongoose.model('std_ration_lib_ration_items');
 let glj_calculate_facade = require('./glj_calculate_facade');
+let glj_type_util = require('../../../public/cache/std_glj_type_util');
 let quantity_detail_facade = require('../../main/facade/quantity_detail_facade');
 let logger = require("../../../logs/log_helper").logger;
 import stdgljutil  from "../../../public/cache/std_glj_type_util";
@@ -37,7 +38,8 @@ module.exports = {
     mReplaceGLJ: mReplaceGLJ,
     updateRationGLJByEdit: updateRationGLJByEdit,
     getGLJClass: getGLJClass,
-    insertGLJAsRation: insertGLJAsRation
+    insertGLJAsRation: insertGLJAsRation,
+    getRationTypeGLJQuantity:getRationTypeGLJQuantity
 }
 
 let operationMap = {
@@ -562,7 +564,7 @@ function getGLJSearchInfo(ration_glj) {
         code: ration_glj.code,
         original_code: ration_glj.original_code,
         name: ration_glj.name,
-        shortName: ration_glj.shortName,
+        //shortName: ration_glj.shortName,
         specs: ration_glj.specs,
         unit: ration_glj.unit,
         type: ration_glj.subType ? ration_glj.subType : ration_glj.type,//如果有subType,则是通过插入定额级的工料机进来的
@@ -573,6 +575,10 @@ function getGLJSearchInfo(ration_glj) {
         adjCoe: ration_glj.adjCoe,
         from: ration_glj.from ? ration_glj.from : 'std'//std:标准工料机库, cpt:补充工料机库
     };
+    let glj_type_object = glj_type_util.getStdGljTypeCacheObj();
+    let type = glj_type_object.getItemById(data.type);
+    data.shortName = type.shortName;
+
     if (data.from == 'cpt') {//从补充工料机来的数据即为新增数据
         data.is_add = 1;
     }
@@ -765,6 +771,11 @@ async function insertGLJAsRation(data) {
     return gljList;
 }
 
+async function  getRationTypeGLJQuantity(projectID) {
+    let rations = await ration.find({'projectID': projectID,'type':3,'deleteInfo': null}, ['ID', 'projectGLJID','quantity']);
+    return rations;
+}
+
 async function changAdjustState(data, rationList) {
     let stateList = [];
     for (let r of rationList) {

+ 3 - 0
modules/ration_glj/models/ration_glj_temp.js

@@ -50,6 +50,7 @@ let rationSchema = new Schema({
     unit: String,
     quantity: String,
     contain:String,//含量
+    quantityEXP:String,//工程量表达式
     programID: Number,
     marketUnitFee: String,
     marketTotalFee: String,
@@ -146,6 +147,8 @@ let billsSchema = new Schema({
     chapterID: Number,
     code: String,
     fullCode: String,
+    type:Number,
+    isAdd:{type: Number,default:0},//1 true 0 false是否新增
     name: String,
     unit: String,
     quantity: String, // Decimal

+ 1 - 1
modules/ration_repository/controllers/ration_controller.js

@@ -2,7 +2,7 @@
  * Created by Tony on 2017/5/2.
  */
 
-var rationItem = require('../models/ration_item');
+var rationItem = require('../models/ration_item').Dao;
 var callback = function(req, res, err, message, data){
     res.json({error: err, message: message, data: data});
 };

+ 1 - 1
modules/ration_repository/controllers/ration_repository_controller.js

@@ -1,7 +1,7 @@
 /**
  * Created by Tony on 2017/4/20.
  */
-var rationRepository = require("../models/repository_map");
+var rationRepository = require("../models/repository_map").Dao;
 
 var callback = function(req, res, err, message, data){
     res.json({error: err, message: message, data: data});

+ 1 - 1
modules/ration_repository/controllers/ration_section_tree_controller.js

@@ -2,7 +2,7 @@
  * Created by Tony on 2017/4/21.
  */
 
-var rationChapterTreeData = require('../models/ration_section_tree');
+var rationChapterTreeData = require('../models/ration_section_tree').Dao;
 var callback = function(req,res,err,message, data){
     res.json({error: err, message: message, data: data});
 }

+ 2 - 2
modules/ration_repository/controllers/search_controller.js

@@ -1,8 +1,8 @@
 /**
  * Created by Mai on 2017/6/5.
  */
-var rationItem = require('../models/ration_item');
-let rationChapter = require('../models/ration_section_tree');
+var rationItem = require('../models/ration_item').Dao;;
+let rationChapter = require('../models/ration_section_tree').Dao;
 let asyncTool = require('async');
 var callback = function(req, res, err, message, data){
     res.json({error: err, message: message, data: data});

+ 14 - 3
modules/ration_repository/models/coe.js

@@ -46,10 +46,21 @@ coeListDAO.prototype.getCoeItemsByIDs = function (data, callback) {
     coeListModel.find({
             "libID": data.libID,
             "ID": {"$in":data.coeIDs}
-        }, ["libID","ID","name","content","-_id"],
+        }, ["libID","ID", "serialNo","name","content","-_id"],
         function (err, doc) {
             if (err) callback("批量获取系数明细错误!", null)
-            else callback(null, doc);
+            else callback(0, doc);
+        })
+};
+
+coeListDAO.prototype.getCoeItemsByNos = function (data, callback) {
+    coeListModel.find({
+            "libID": data.libID,
+            "serialNo": {"$in":data.coeNos}
+        }, ["libID","ID","serialNo","name","content","-_id"],
+        function (err, doc) {
+            if (err) callback("批量获取系数明细错误!", null)
+            else callback(0, doc);
         })
 };
 
@@ -57,7 +68,7 @@ coeListDAO.prototype.getCoesByLibID = function (libID, callback) {
     coeListModel.find({ "libID": libID },
         function (err, doc) {
             if (err) callback("获取定额库系数表错误", null)
-            else callback(null, doc);
+            else callback(0, doc);
         })
 };
 

+ 1 - 1
modules/ration_repository/models/glj_repository.js

@@ -33,7 +33,7 @@ var gljSchema = mongoose.Schema({
 });
 var gljTypeModel = db.model("std_ration_lib_glj_type",gljTypeSchema, "std_ration_lib_glj_type");
 var gljItemModel = mongoose.model("std_glj_lib_gljList");
-var repositoryMap = require('./repository_map');
+var repositoryMap = require('./repository_map').Dao;
 var counter = require('../../../public/counter/counter');
 
 var gljItemDAO = function(){};

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

@@ -213,5 +213,9 @@ rationItemDAO.prototype.updateRationItems = function(rationLibId, sectionId, ite
     });
 };
 
-module.exports = new rationItemDAO()
+module.exports = {
+    Dao: new rationItemDAO(),
+    Model: rationItemModel
+};
+//module.exports = new rationItemDAO()
 

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

@@ -117,4 +117,8 @@ rationChapterTreeDAO.prototype.getRationChapter = function (repId, chapterID, ca
     }
 }
 
-module.exports = new rationChapterTreeDAO()
+module.exports = {
+    Model: rationChapterTreeModel,
+    Dao: new rationChapterTreeDAO()
+};
+//module.exports = new rationChapterTreeDAO()

+ 5 - 1
modules/ration_repository/models/repository_map.js

@@ -117,4 +117,8 @@ rationRepositoryDao.prototype.deleteRationLib = function(rationName,callback){
     });
 }
 
-module.exports = new rationRepositoryDao();
+module.exports = {
+    Dao: new rationRepositoryDao(),
+    Model: rationRepository
+}
+//module.exports = new rationRepositoryDao();

+ 9 - 0
public/web/common_util.js

@@ -18,3 +18,12 @@ function parseFloatPlus(value){
     let rst = parseFloat(value);
     return  isNaN(rst) ? 0 : rst;
 };
+
+// 将arr2合并到arr1,并去重复。
+function mergeArr(arr1, arr2){
+    if (arr2.length > 0){
+        for (let cNode of arr2){
+            if (!arr1.includes(cNode)) arr1.push(cNode);
+        };
+    }
+};

+ 13 - 4
public/web/sheet/sheet_common.js

@@ -70,6 +70,14 @@ var sheetCommonObj = {
         sheet.resumeEvent();
         sheet.resumePaint();
     },
+    cleanData: function (sheet, setting, rowCount) {
+        sheet.suspendPaint();
+        sheet.suspendEvent();
+        sheet.clear(-1, 0, -1, setting.header.length, GC.Spread.Sheets.SheetArea.viewport, GC.Spread.Sheets.StorageType.data);
+        if (rowCount > 0) sheet.setRowCount(rowCount);
+        sheet.resumeEvent();
+        sheet.resumePaint();
+    },
     setAreaAlign: function(area, hAlign, vAlign){
         if (!(hAlign) || hAlign === "left") {
             area.hAlign(GC.Spread.Sheets.HorizontalAlign.left);
@@ -220,7 +228,7 @@ var sheetCommonObj = {
         var rst = true;
         if (rObj) {
             for (var i = 0; i < setting.header.length; i++) {
-                if (rObj[setting.header[i]]) {
+                if (rObj[setting.header[i].dataCode]) {
                     rst = false;
                     break;
                 }
@@ -230,12 +238,13 @@ var sheetCommonObj = {
     },
     //add by zhong 2017-10-10
     //动态下拉框,配合EnterCell, args.sheet.repaint();
-    getDynamicCombo: function () {
+    getDynamicCombo: function (forLocked) {
         let ComboCellForActiveCell = function () { };
         ComboCellForActiveCell.prototype = new GC.Spread.Sheets.CellTypes.ComboBox();
         ComboCellForActiveCell.prototype.paintValue = function (ctx, value, x, y, w, h, style, options) {
             let sheet = options.sheet;
-            if (options.row === sheet.getActiveRowIndex() && options.col === sheet.getActiveColumnIndex() && !sheet.getCell(options.row, options.col).locked()) {
+            if (options.row === sheet.getActiveRowIndex() && options.col === sheet.getActiveColumnIndex() && (!forLocked || forLocked && !sheet.getCell(options.row, options.col).locked())) {
+
                 GC.Spread.Sheets.CellTypes.ComboBox.prototype.paintValue.apply(this, arguments);
 
             } else {
@@ -244,7 +253,7 @@ var sheetCommonObj = {
         };
         ComboCellForActiveCell.prototype.getHitInfo = function (x, y, cellStyle, cellRect, options) {
             let sheet = options.sheet;
-            if (options.row === sheet.getActiveRowIndex() && options.col === sheet.getActiveColumnIndex() && !sheet.getCell(options.row, options.col).locked()) {
+            if (options.row === sheet.getActiveRowIndex() && options.col === sheet.getActiveColumnIndex() && (!forLocked || forLocked && !sheet.getCell(options.row, options.col).locked())) {
                 return GC.Spread.Sheets.CellTypes.ComboBox.prototype.getHitInfo.apply(this, arguments);
 
             } else {

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

@@ -131,6 +131,10 @@ var TREE_SHEET_HELPER = {
                     }
                     return data;
                 };
+                if(colSetting.data.field=="quantity"){
+                    let tag = node.data.quantityEXP?node.data.quantityEXP:'';
+                    sheet.setTag(iRow, iCol,tag);
+                }
                 if (colSetting.data.getText && Object.prototype.toString.apply(colSetting.data.getText) === "[object Function]") {
                     cell.value(colSetting.data.getText(node));
                 } else {
@@ -317,7 +321,9 @@ var TREE_SHEET_HELPER = {
         TipCellType.prototype.processMouseEnter = function (hitinfo) {
             let text = hitinfo.sheet.getText(hitinfo.row, hitinfo.col);
             let tag = hitinfo.sheet.getTag(hitinfo.row, hitinfo.col);
-            if(tag !== undefined && tag) {
+            if(setting.cols[hitinfo.col].data.field=="quantity"){
+                text = tag;
+            }else if(tag !== undefined && tag) {
                 text = tag;
             }
             if (setting.pos && text && text !== '') {
@@ -356,6 +362,7 @@ var TREE_SHEET_HELPER = {
                 sheet.defaults.rowHeight = setting.defaultRowHeight;
             }
             sheet.setRowCount(tree.count() + setting.emptyRows, GC.Spread.Sheets.SheetArea.viewport);
+            sheet.getRange(tree.count(), -1, setting.emptyRows, -1).locked(true);
             setting.cols.forEach(function (colSetting, iCol) {
                 sheet.setStyle(-1, iCol, TREE_SHEET_HELPER.getSheetCellStyle(colSetting));
                 if (colSetting.showHint) {

+ 8 - 4
web/building_saas/complementary_glj_lib/html/tools-gongliaoji.html

@@ -6,6 +6,7 @@
     <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
     <meta http-equiv="x-ua-compatible" content="ie=edge">
     <title>工料机库编辑-Smartcost</title>
+    <!--inject:css-->
     <link rel="stylesheet" href="/lib/bootstrap/css/bootstrap.min.css" type="text/css">
     <link rel="stylesheet" href="/web/building_saas/css/main.css" type="text/css">
     <link rel="stylesheet" href="/lib/font-awesome/font-awesome.min.css" type="text/css">
@@ -13,6 +14,7 @@
     <!--zTree-->
   	<link rel="stylesheet" href="/lib/ztree/css/zTreeStyle.css" type="text/css">
     <link rel="stylesheet" href="/lib/spreadjs/sheets/css/gc.spread.sheets.excel2013lightGray.10.0.1.css" type="text/css">
+    <!--endinject-->
     <style type="text/css">
         .modal-lg{max-width: 1000px}
     </style>
@@ -179,15 +181,16 @@
     <script src="/lib/jquery/jquery-3.2.1.min.js"></script>
     <script src="/lib/jquery-contextmenu/jquery.contextMenu.min.js"></script>
     <script src="/lib/jquery-contextmenu/jquery.ui.position.js"></script>
+    <script src = "/lib/spreadjs/sheets/gc.spread.sheets.all.10.0.1.min.js"></script>
+    <script type="text/javascript" src="/lib/ztree/jquery.ztree.core.js"></script>
+    <script type="text/javascript" src="/lib/ztree/jquery.ztree.excheck.js"></script>
+    <script type="text/javascript" src="/lib/ztree/jquery.ztree.exedit.js"></script>
+    <!--inject:js-->
     <script src="/lib/popper/popper.min.js"></script>
     <script src="/lib/bootstrap/bootstrap.min.js"></script>
     <script src="/web/building_saas/js/global.js"></script>
     <!-- zTree -->
-    <script src = "/lib/spreadjs/sheets/gc.spread.sheets.all.10.0.1.min.js"></script>
     <script>GC.Spread.Sheets.LicenseKey = "559432293813965#A0y3iTOzEDOzkjMyMDN9UTNiojIklkI1pjIEJCLi4TPB9mM5AFNTd4cvZ7SaJUVy3CWKtWYXx4VVhjMpp7dYNGdx2ia9sEVlZGOTh7NRlTUwkWR9wEV4gmbjBDZ4ElR8N7cGdHVvEWVBtCOwIGW0ZmeYVWVr3mI0IyUiwCMzETN8kzNzYTM0IicfJye&Qf35VfiEzRwEkI0IyQiwiIwEjL6ByUKBCZhVmcwNlI0IiTis7W0ICZyBlIsIyNyMzM5ADI5ADNwcTMwIjI0ICdyNkIsIibj9SbvNmL4N7bjRnch56ciojIz5GRiwiI8+Y9sWY9QmZ0Jyp96uL9v6L0wap9biY9qiq95q197Wr9g+89iojIh94Wiqi";</script>
-    <script type="text/javascript" src="/lib/ztree/jquery.ztree.core.js"></script>
-    <script type="text/javascript" src="/lib/ztree/jquery.ztree.excheck.js"></script>
-    <script type="text/javascript" src="/lib/ztree/jquery.ztree.exedit.js"></script>
     <script type="text/javascript" src="/public/web/common_ajax.js"></script>
     <script type="text/javascript" src="/public/web/treeDataHelper.js"></script>
     <script type="text/javascript" src="/public/web/QueryParam.js"></script>
@@ -198,6 +201,7 @@
     <script type="text/javascript" src="/public/web/sheet/sheet_common.js"></script>
     <script type="text/javascript" src="/web/building_saas/complementary_glj_lib/js/sheetOpr.js"></script>
     <script type="text/javascript" src="/public/web/storageUtil.js"></script>
+    <!--endinject-->
     <SCRIPT type="text/javascript">
         let userId = "<%= userID%>";
         let compilationId = "<%= compilationId%>";

+ 2 - 1
web/building_saas/complementary_glj_lib/js/components.js

@@ -78,7 +78,8 @@ let componentOprObj = {
         let that = repositoryGljObj, me = componentOprObj;
             for(let i = 0; i < gljList.length; i++){
                 if(that.currentGlj.gljType === 301 && machineArr.indexOf(gljList[i].gljType) !== -1 ||
-                    materialArr.indexOf(that.currentGlj.gljType) !== -1 && gljList[i].gljType === 201){
+                    materialArr.indexOf(that.currentGlj.gljType) !== -1 && gljList[i].gljType === 201 ||
+                    that.currentGlj.gljType === 4 && gljList[i].gljType === 4 && (!gljList[i].component || gljList[i].component.length === 0) && gljList[i].ID !== that.currentGlj.ID){
                     //去除与已添加的组成物重复的条目
                     let isExist = false;
                     for(let j = 0; j < that.currentComponent.length; j++){

+ 46 - 38
web/building_saas/complementary_glj_lib/js/glj.js

@@ -35,8 +35,8 @@ let repositoryGljObj = {
     gljList: [],
     stdGljList:[],
     complementaryGljList: [],
-    allowComponent: [202, 203, 204, 301],//可带组成物类型:混凝土、砂浆、配合比、机械台班
-    componentGljType: [201, 302, 303],//可成为组成物的工料机类型: 普通材料、 机械组成物、 机上人工
+    allowComponent: [202, 203, 204, 301, 4],//可带组成物类型:混凝土、砂浆、配合比、机械台班、主材
+    componentGljType: [201, 302, 303, 4],//可成为组成物的工料机类型: 普通材料、 机械组成物、 机上人工、主材
     distTypeTree: null,//add
     setting: {
 
@@ -165,6 +165,25 @@ let repositoryGljObj = {
         me.workBook.bind(GC.Spread.Sheets.Events.ButtonClicked, me.onButtonClicked);//复选框点击事件
     },
 
+    isDef: function (v) {
+        return v !== undefined && v !== null;
+    },
+
+    //成为了组成物,暂时只需要判断主材的
+    isComponent: function (gljId, gljList) {
+        for(let i = 0, len = gljList.length; i < len; i++){
+            let gljComponent = gljList[i].component;
+            if(gljList[i].gljType === 4 && this.isDef(gljComponent) && gljComponent.length > 0){
+                for(let j = 0, jLen = gljComponent.length; j < jLen; j++){
+                    if(gljComponent[j].ID === gljId){
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    },
+
     getCurrentComponent: function (gljComponent) {
         let me = repositoryGljObj, rst = [];
         for(let i = 0; i < gljComponent.length; i++){
@@ -359,7 +378,7 @@ let repositoryGljObj = {
         me.orgCode = me.workBook.getSheet(0).getValue(args.row, 0);
         if(args.row < me.currentCache.length){
             me.currentGlj = me.currentCache[args.row];
-            if(args.col === 0 || (args.col === 4 && me.allowComponent.indexOf(me.currentGlj.gljType) !== -1)
+            if(args.col === 0 || (args.col === 4 && me.allowComponent.indexOf(me.currentGlj.gljType) !== -1 && me.currentGlj.component.length > 0)
                 || args.col === 6){
                 args.cancel = true;
             }
@@ -447,7 +466,7 @@ let repositoryGljObj = {
             //--------------------------------------
             if(me.currentEditingGlj.basePrice !== rObj.basePrice){
                 //update basePrice of ration when editting basePrice of glj
-               /* let gljType = -1;
+                let gljType = -1;
                 let gljTypeParent = me.distTypeTree.distTypes[me.distTypeTree.prefix + me.currentEditingGlj.gljType].parent;
                 if(gljTypeParent && gljTypeParent.data.ID <=3){
                     gljType = gljTypeParent.data.ID;
@@ -458,18 +477,14 @@ let repositoryGljObj = {
                 let gljBasePrcObj = {gljId: me.currentEditingGlj.ID, gljType: gljType, basePrice: rObj.basePrice};
                 if(gljBasePrcObj.gljType !== -1){
                     updateBasePrcArr.push(gljBasePrcObj);
-                    if(me.rationLibs.length > 0){//重算定额单价
-                        me.updateRationBasePrcRq(updateBasePrcArr);
-                    }
-                }*/
+                    me.updateRationBasePrcRq(updateBasePrcArr);
+                }
             }
             //update basePrice of ration when editting gljType of glj
             if(me.currentEditingGlj.gljType !== rObj.gljType){
-                /*let gljTypeObj = {gljId: me.currentEditingGlj.ID, gljType: rObj.gljType, basePrice: rObj.basePrice};
+                let gljTypeObj = {gljId: me.currentEditingGlj.ID, gljType: rObj.gljType, basePrice: rObj.basePrice};
                 updateBasePrcArr.push(gljTypeObj);
-                if(me.rationLibs.length > 0){
-                    me.updateRationBasePrcRq(updateBasePrcArr);
-                }*/
+                me.updateRationBasePrcRq(updateBasePrcArr);
             }
             //-----------------------------------------------------------
         }
@@ -783,7 +798,7 @@ let repositoryGljObj = {
         }
     },
     onClipboardPasted: function(e, info) {
-        if(info.pasteData.text.trim().length > 0){
+      //  if(info.pasteData.text.trim().length > 0){
             let me = repositoryGljObj;
             let updateArr = [], addArr = [];
             let items = sheetOpr.analyzePasteData(me.setting, info);
@@ -795,11 +810,12 @@ let repositoryGljObj = {
                 //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'){
-                        updateArr = updateObj.updateGlj;
-                        /*if(typeof updateObj.updateBasePrcArr !== 'undefined'){
-                         updateBasePrcArr = updateObj.updateBasePrcArr;
-                         }*/
+                    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);
@@ -811,10 +827,11 @@ let repositoryGljObj = {
                 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;
-                        /* if(typeof updateObj.updateBasePrcArr !== 'undefined'){
-                         updateBasePrcArr = updateObj.updateBasePrcArr;
-                         }*/
+                        //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);
@@ -889,29 +906,20 @@ let repositoryGljObj = {
             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:找出原因
+            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, '');
                 }
             }
-        }
+        }*/
     },
     updateRationBasePrcRq: function (basePrcArr) {
-        $.ajax({
-            type: 'post',
-            url: 'complementartGlj/api/updateRationBasePrc',
-            data:{basePrcArr: JSON.stringify(basePrcArr)},
-            dataType: 'json',
-            success: function (result) {
-                if(result.error){
-                    alert("计算定额基价失败");
-                }
-            }
+        CommonAjax.post('complementartGlj/api/updateRationBasePrc', {basePrcArr: basePrcArr}, function (rstData) {
         });
     },
   /*  getRationGljIds: function (repId) {

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

@@ -69,7 +69,7 @@ let gljComponentOprObj = {
                     //控制按钮是否可用
                     let insertDis = false,
                         delDis = false;
-                    if(!(that.currentGlj && that.allowComponent.indexOf(that.currentGlj.gljType) !== -1)){
+                    if(!(that.currentGlj && that.allowComponent.indexOf(that.currentGlj.gljType) !== -1) || (that.currentGlj.gljType === 4 && that.isComponent(that.currentGlj.ID, that.stdGljList.concat(that.complementaryGljList)))){
                         insertDis = true;
                     }
                     if(!that.currentGlj || typeof that.currentComponent === 'undefined' || (typeof that.currentComponent !== 'undefined' && target.row >= that.currentComponent.length)){//右键定位在有组成物的行,删除键才显示可用
@@ -210,6 +210,7 @@ let gljComponentOprObj = {
         if(thatRow < that.currentCache.length){
             that.currentGlj = that.currentCache[thatRow];
             if(me.setting.view.lockedCols.indexOf(args.col) !== -1 || that.allowComponent.indexOf(that.currentGlj.gljType) === -1 ||
+                (that.currentGlj.gljType === 4 && that.isComponent(that.currentGlj.ID, that.stdGljList.concat(that.complementaryGljList))) ||
                 (args.col === 4 && (!that.currentComponent|| args.row >= that.currentComponent.length))){
                 args.cancel = true;
             }
@@ -345,10 +346,10 @@ let gljComponentOprObj = {
         }
     },
     onClipboardPasting: function (sender, info) {
-        let me = gljComponentOprObj;
+        let me = gljComponentOprObj, that = repositoryGljObj;
         let maxCol = info.cellRange.col + info.cellRange.colCount - 1;
         //复制的列数超过正确的列数,不可复制
-        if(info.cellRange.col !== 4 && info.cellRange.colCount > 1){
+        if(info.cellRange.col !== 4 && info.cellRange.colCount > 1 || (that.currentGlj.gljType === 4 && that.isComponent(that.currentGlj.ID, that.stdGljList.concat(that.complementaryGljList)))){
             args.cancel = true;
         }
     },

+ 1 - 0
web/building_saas/complementary_glj_lib/js/sheetOpr.js

@@ -49,6 +49,7 @@ let sheetOpr = {
         //Set rowHeader count and columnHeader count.
         sheet.setRowCount(1, spreadNS.SheetArea.colHeader);
         sheet.setColumnCount(setting.header.length, spreadNS.SheetArea.viewport);
+        sheet.options.clipBoardOptions = GC.Spread.Sheets.ClipboardPasteOptions.values;
         sheet.options.colHeaderAutoTextIndex = 1;
         sheet.options.colHeaderAutoText = spreadNS.HeaderAutoText.numbers;
         sheet.options.protectionOptions = {

+ 504 - 0
web/building_saas/complementary_ration_lib/html/dinge.html

@@ -0,0 +1,504 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+    <meta http-equiv="x-ua-compatible" content="ie=edge">
+    <title>定额库编辑器</title>'
+    <!--inject:css-->
+    <link rel="stylesheet" href="/lib/bootstrap/css/bootstrap.min.css">
+   <!-- <link rel="stylesheet" href="/lib/css/bootstrap/themes.css">-->
+    <link rel="stylesheet" href="/web/building_saas/css/main.css">
+    <link rel="stylesheet" href="/lib/font-awesome/font-awesome.min.css">
+    <link rel="stylesheet" href="/lib/jquery-contextmenu/jquery.contextMenu.css">
+    <link rel="stylesheet" href="/lib/spreadjs/sheets/css/gc.spread.sheets.excel2013lightGray.10.0.1.css" type="text/css">
+    <!--endinject-->
+</head>
+
+<body>
+    <div class="header">
+        <nav class="navbar navbar-toggleable-lg navbar-light bg-faded p-0 ">
+            <span class="header-logo px-2">Smartcost</span>
+            <div id="rationname" class="navbar-text"><a href="main">定额库</a><i class="fa fa-angle-right fa-fw"></i>XXX定额库</div>
+        </nav>
+        <nav class="navbar navbar-toggleable-lg justify-content-between navbar-light p-0">
+              <ul class="nav nav-tabs" role="tablist">
+                  <li class="nav-item">
+                      <a class="nav-link active px-3" id ="dinge" >定额</a>
+                  </li>
+                  <li class="nav-item">
+                      <a class="nav-link px-3" id="gongliao" href="#">工料机</a>
+                  </li>
+                  <li class="nav-item">
+                      <a class="nav-link px-3" id="fuzhu" href="#">附注条件</a>
+                  </li>
+                  <li class="nav-item">
+                      <a class="nav-link px-3" href="#">安装增加费</a>
+                  </li>
+              </ul>
+        </nav>
+    </div>
+    <div class="main" style="overflow: hidden">
+        <div class="content">
+            <div class="container-fluid">
+                <div class="row">
+                  <div class="main-side col-lg-3 p-0" style="width: 100%; height: 100%; overflow: hidden">
+                      <div class="tab-bar">
+                          <a href="javascript:void(0);" id="tree_Insert" 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="tree_remove" class="btn btn-sm" 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="tree_upLevel" class="btn btn-sm disabled" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="升级"><i class="fa fa-arrow-left" aria-hidden="true"></i></a>
+                          <a href="javascript:void(0);" id="tree_downLevel" class="btn btn-sm disabled" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="降级"><i class="fa fa-arrow-right" aria-hidden="true"></i></a>
+                          <a href="javascript:void(0);" id="tree_downMove" 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="tree_upMove" 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 class="tab-content" id="sectionSpread" style="overflow: hidden">
+                      <!--<ul id="rationChapterTree" class="ztree"></ul>-->
+                    </div>
+                  </div>
+                  <div class="main-content col-lg-9 p-0">
+                      <!-- 右标签 -->
+                      <ul class="nav nav-tabs tools-bar" role="tablist">
+                          <li class="nav-item">
+                              <a class="nav-link active" data-toggle="tab" href="#tde" role="tab">定额</a>
+                          </li>
+                          <li class="nav-item">
+                              <a class="nav-link" data-toggle="tab" href="#tsm" role="tab" id="explanationLink">说明</a>
+                          </li>
+                          <li class="nav-item">
+                              <a class="nav-link" data-toggle="tab" href="#tjs" role="tab">计算规则</a>
+                          </li>
+                          <li class="nav-item">
+                              <a class="nav-link" data-toggle="tab" href="#tgz" role="tab">工作内容</a>
+                          </li>
+                          <li class="nav-item">
+                              <a class="nav-link" data-toggle="tab" href="#tfz" role="tab">附注</a>
+                          </li>
+                      </ul>
+                      <div class="tab-content">
+                          <!--定额-->
+                          <div class="tab-pane active" id="tde" role="tabpanel">
+                              <!--定额top-->
+                              <div id="rationItemsSheet" class="main-data-top"></div>
+                              <!--定额bottom-->
+                              <div class="bottom-content">
+                                  <!-- 标签 -->
+                                  <ul class="nav nav-tabs" role="tablist">
+                                      <li class="nav-item">
+                                          <a class="nav-link active" id="linkGLJ" data-toggle="tab" href="#rDetail" role="tab">工料机</a>
+                                      </li>
+                                      <li class="nav-item">
+                                          <a class="nav-link" id="linkFZDE" data-toggle="tab" href="#rDetail" role="tab">辅助定额调整</a>
+                                      </li>
+                                      <li class="nav-item">
+                                          <a class="nav-link" id="linkFZTJ" data-toggle="tab" href="#rDetail" role="tab">附注条件调整</a>
+                                      </li>
+                                      <li class="nav-item">
+                                          <!--<a class="nav-link" id="linkAZZJ" data-toggle="tab" href="#" role="tab">安装增加费</a>-->
+                                          <a class="nav-link" href="#">安装增加费</a>
+                                      </li>
+                                  </ul>
+                                  <!-- 内容 -->
+                                  <div class="tab-content">
+                                      <div class="tab-pane active" id="rDetail" role="tabpanel">
+                                          <div id="rdSpread" class="main-data-bottom" style="overflow: hidden"></div>
+                                      </div>
+                                  </div>
+                              </div>
+                          </div>
+                          <!--说明-->
+                          <div class="tab-pane" id="tsm" role="tabpanel">
+                              <div class="main-data">
+                                  <div class="main-content m-2">
+                                      <h5>说明</h5>
+                                      <textarea id="explanationShow" class="form-control" disabled="disabled" rows="35" style="background: white;"></textarea>
+                                  </div>
+                              </div>
+                          </div>
+                          <!--计算规则-->
+                          <div class="tab-pane" id="tjs" role="tabpanel">
+                              <div class="main-data">
+                                  <div class="main-content m-2">
+                                      <h5>计算规则</h5>
+                                      <textarea id="ruleTextShow" class="form-control" disabled="disabled"  rows="35" style="background: white;"></textarea>
+                                  </div>
+                              </div>
+                          </div>
+                          <!--工作内容-->
+                          <div class="tab-pane" id="tgz" role="tabpanel">
+                              <div class="main-data">
+                                  <div class="form-check m-2"><label class="form-check-label"><input type="radio"  class="form-check-input" name="optionsRadios" value="ALL" disabled="true"> 适合本项所有定额</label>&nbsp;&nbsp;<label class="form-check-label"><input type="radio" class="form-check-input disabled" name="optionsRadios" value="PARTIAL" disabled="true"> 适合本项部分定额</label></div>
+                                  <!-- <p class="m-2">适合本项所有定额</p> -->
+                                  <table class="table table-sm table-bordered m-0" id="tableAll">
+                                      <tr>
+                                          <td><textarea class="form-control" rows="30" id="txtareaAll" disabled="disabled" style="background: white;"></textarea></td>
+                                      </tr>
+                                  </table>
+                                  <table class="table table-sm table-bordered m-0" id="tablePartial">
+                                  </table>
+                              </div>
+                          </div>
+                          <!--附注-->
+                          <div class="tab-pane" id="tfz" role="tabpanel">
+                              <div class="main-data">
+                                  <div class="form-check m-2"><label class="form-check-label"><input type="radio" class="form-check-input" name="fzRadios" value="ALL" disabled=""> 适合本项所有定额</label>&nbsp;&nbsp;<label class="form-check-label"><input type="radio" class="form-check-input" name="fzRadios" value="PARTIAL" disabled> 适合本项部分定额</label></div>
+                                  <!-- <p class="m-2">适合本项所有定额</p> -->
+                                  <table class="table table-sm table-bordered m-0" id="fzTableAll">
+                                      <tr>
+                                          <td><textarea class="form-control" rows="30" id="fzTxtareaAll" disabled="disabled" style="background: white;"></textarea></td>
+                                      </tr>
+                                  </table>
+                                  <table class="table table-sm table-bordered m-0" id="fzTablePartial">
+                                  </table>
+                              </div>
+                          </div>
+                  </div>
+                </div>
+            </div>
+        </div>
+    </div>
+        <!--弹出添加-->
+        <button id="gznrBtn" class="btn btn-primary btn-lg" data-toggle="modal" data-target="#addNewgznr" style="display: none"></button>
+        <div class="modal fade" id="addNewgznr" data-backdrop="static" style="display: none;" aria-hidden="true">
+            <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">×</span>
+                        </button>
+                    </div>
+                    <div class="modal-body">
+                        <form>
+                            <div class="form-group">
+                                <label>内容</label>
+                                <textarea class="form-control" rows="5"></textarea>
+                            </div>
+                        </form>
+                        <form>
+                            <div class="form-group">
+                                <label>编码</label>
+                                <div class="form-control">
+                                    <div class="row code">
+                                        <div class="col">
+                                            <label class="form-check-label">
+                                                <input class="form-check-input" type="checkbox" value="option1" checked> AA0017
+                                            </label>
+                                        </div>
+                                        <div class="col">
+                                            <label class="form-check-label">
+                                                <input class="form-check-input" type="checkbox" value="option1" checked> AA0018
+                                            </label>
+                                        </div>
+                                        <div class="col">
+                                            <label class="form-check-label">
+                                                <input class="form-check-input" type="checkbox" value="option1" checked> AA0019
+                                            </label>
+                                        </div>
+                                        <div class="w-100"></div>
+                                        <div class="col">
+                                            <label class="form-check-label">
+                                                <input class="form-check-input" type="checkbox" value="option1"> AA0020
+                                            </label>
+                                        </div>
+                                        <div class="col">
+                                            <label class="form-check-label">
+                                                <input class="form-check-input" type="checkbox" value="option1"> AA0021
+                                            </label>
+                                        </div>
+                                        <div class="col">
+                                            <label class="form-check-label">
+                                                <input class="form-check-input" type="checkbox" value="option1"> AA0022
+                                            </label>
+                                        </div>
+                                    </div>
+                                </div>
+                            </div>
+
+                            <div class="form-group">
+                                <label>内容</label>
+                                <textarea class="form-control" rows="5"></textarea>
+                            </div>
+                        </form>
+                    </div>
+                    <div class="modal-footer">
+                        <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                        <a href="" class="btn btn-primary">确定</a>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <!--弹出编辑-->
+        <div class="modal fade" id="editTsm" data-backdrop="static" style="display: none;" aria-hidden="true">
+            <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">×</span>
+                        </button>
+                    </div>
+                    <div class="modal-body">
+                        <form>
+                            <div class="form-group">
+                                <label>内容</label>
+                                <textarea class="form-control" rows="5" id="explanationAdd"></textarea>
+                            </div>
+                        </form>
+                    </div>
+                    <div class="modal-footer">
+                        <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                        <a href="javascript:void(0);" class="btn btn-primary" id="explanationBtn" data-dismiss="modal">确定</a>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <div class="modal fade" id="editTjs" data-backdrop="static" style="display: none;" aria-hidden="true">
+            <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">×</span>
+                        </button>
+                    </div>
+                    <div class="modal-body">
+                        <form>
+                            <div class="form-group">
+                                <label>内容</label>
+                                <textarea class="form-control" rows="5"></textarea>
+                            </div>
+                        </form>
+                    </div>
+                    <div class="modal-footer">
+                        <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                        <a href="javascript:void(0);" class="btn btn-primary" data-dismiss="modal" id="ruleTextAdd">确定</a>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <div class="modal fade" id="editBianmaQ" data-backdrop="static" style="display: none;" aria-hidden="true">
+            <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">×</span>
+                        </button>
+                    </div>
+                    <div class="modal-body">
+                        <form>
+                            <div class="form-group">
+                                <label>编码</label>
+                                <div class="form-control">
+                                    <div class="row code" id="updateCon">
+                                    </div>
+                                </div>
+                            </div>
+                        </form>
+                    </div>
+                    <div class="modal-footer">
+                        <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                        <a href="javascript: void(0);" class="btn btn-primary" data-dismiss="modal" id="updateConBtn">确定</a>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <div class="modal fade" id="editBianma" data-backdrop="static" style="display: none;" aria-hidden="true">
+            <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">×</span>
+                        </button>
+                    </div>
+                    <div class="modal-body">
+                        <form>
+                            <div class="form-group">
+                                <label>编码</label>
+                                <div class="form-control">
+                                    <div class="row code" id="addCon">
+                                    </div>
+                                </div>
+                            </div>
+                        </form>
+                    </div>
+                    <div class="modal-footer">
+                        <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                        <a href="javascript: void(0);" class="btn btn-primary" data-dismiss="modal" id="addConBtn">确定</a>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <!--弹出附注-->
+        <div class="modal fade" id="fzEditBianmaQ" data-backdrop="static" style="display: none;" aria-hidden="true">
+            <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">×</span>
+                        </button>
+                    </div>
+                    <div class="modal-body">
+                        <form>
+                            <div class="form-group">
+                                <label>编码</label>
+                                <div class="form-control">
+                                    <div class="row code" id="fzUpdateCon">
+                                    </div>
+                                </div>
+                            </div>
+                        </form>
+                    </div>
+                    <div class="modal-footer">
+                        <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                        <a href="javascript: void(0);" class="btn btn-primary" data-dismiss="modal" id="fzUpdateConBtn">确定</a>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <div class="modal fade" id="fzEditBianma" data-backdrop="static" style="display: none;" aria-hidden="true">
+            <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">×</span>
+                        </button>
+                    </div>
+                    <div class="modal-body">
+                        <form>
+                            <div class="form-group">
+                                <label>编码</label>
+                                <div class="form-control">
+                                    <div class="row code" id="fzAddCon">
+                                    </div>
+                                </div>
+                            </div>
+                        </form>
+                    </div>
+                    <div class="modal-footer">
+                        <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                        <a href="javascript: void(0);" class="btn btn-primary" data-dismiss="modal" id="fzAddConBtn">确定</a>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <!--弹出警告窗-->
+        <button id="rationAlertBtn" class="btn btn-primary btn-lg" data-toggle="modal" data-target="#rationAlert" style="display: none"></button>
+        <div class="modal fade" id="rationAlert" data-backdrop="static" style="display: none;" aria-hidden="true">
+            <input type="hidden" id="gdid" value="123">
+            <div class="modal-dialog" role="document">
+                <div class="modal-content">
+                    <div class="modal-header">
+                        <h5 class="modal-title">取消确认</h5>
+                        <button type="button" id="rationAlertCls" class="close" data-dismiss="modal" aria-label="Close">
+                            <span aria-hidden="true">×</span>
+                        </button>
+                    </div>
+                    <div class="modal-body">
+                        <h5 class="text-danger" id="alertRationTxt">编码不可为空,继续新增定额?</h5>
+                    </div>
+                    <div class="modal-footer">
+                        <button type="button" class="btn btn-secondary" id="rationAlertCac" data-dismiss="modal">取消</button>
+                        <a href="javascript: void(0);" id="rationAlertCof" class="btn btn-danger" data-dismiss="modal">确认</a>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <button id="alertModalBtn" class="btn btn-primary btn-lg" data-toggle="modal" data-target="#alertModal" style="display: none"></button>
+        <div class="modal fade" id="alertModal" data-backdrop="static" style="display: none;" aria-hidden="true">
+            <input type="hidden" id="codedid" value="123">
+            <div class="modal-dialog" role="document">
+                <div class="modal-content">
+                    <div class="modal-header">
+                        <h5 class="modal-title">警告</h5>
+                        <button type="button" id="alertModalCls" class="close" data-dismiss="modal" aria-label="Close">
+                            <span aria-hidden="true">×</span>
+                        </button>
+                    </div>
+                    <div class="modal-body">
+                        <h5 class="text-danger" id="alertText">输入的编号已存在,请重新输入!</h5>
+                    </div>
+                    <div class="modal-footer">
+                        <button type="button" class="btn btn-danger" id="alertModalCof" data-dismiss="modal">确认</button>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <!-- JS. -->
+        <script type="text/javascript" src = "/lib/spreadjs/sheets/gc.spread.sheets.all.10.0.1.min.js"></script>
+        <script type="text/javascript" src="/lib/jquery-contextmenu/jquery.contextMenu.min.js"></script>
+        <script type="text/javascript" src="/lib/jquery-contextmenu/jquery.ui.position.js"></script>
+        <!--inject:js-->
+        <script>GC.Spread.Sheets.LicenseKey = "559432293813965#A0y3iTOzEDOzkjMyMDN9UTNiojIklkI1pjIEJCLi4TPB9mM5AFNTd4cvZ7SaJUVy3CWKtWYXx4VVhjMpp7dYNGdx2ia9sEVlZGOTh7NRlTUwkWR9wEV4gmbjBDZ4ElR8N7cGdHVvEWVBtCOwIGW0ZmeYVWVr3mI0IyUiwCMzETN8kzNzYTM0IicfJye&Qf35VfiEzRwEkI0IyQiwiIwEjL6ByUKBCZhVmcwNlI0IiTis7W0ICZyBlIsIyNyMzM5ADI5ADNwcTMwIjI0ICdyNkIsIibj9SbvNmL4N7bjRnch56ciojIz5GRiwiI8+Y9sWY9QmZ0Jyp96uL9v6L0wap9biY9qiq95q197Wr9g+89iojIh94Wiqi";</script>
+        <script type="text/javascript" src="/lib/jquery/jquery-3.2.1.min.js"></script>
+        <script type="text/javascript" src="/lib/popper/popper.min.js"></script>
+        <script type="text/javascript" src="/lib/bootstrap/bootstrap.min.js"></script>
+        <script type="text/javascript" src="/web/building_saas/complementary_ration_lib/js/global.js"></script>
+        <script type="text/javascript" src="/public/web/id_tree.js"></script>
+        <script type="text/javascript" src="/public/web/tree_sheet/tree_sheet_controller.js"></script>
+        <script type="text/javascript" src="/public/web/tree_sheet/tree_sheet_helper.js"></script>
+        <script type="text/javascript" src="/public/web/treeDataHelper.js"></script>
+        <script type="text/javascript" src="/public/web/sheet/sheet_common.js"></script>
+        <script type="text/javascript" src="/web/building_saas/complementary_ration_lib/js/sheetsOpr.js"></script>
+        <script type="text/javascript" src="/public/web/QueryParam.js"></script>
+        <script type="text/javascript" src="/public/web/storageUtil.js"></script>
+
+        <script type="text/javascript" src="/web/building_saas/complementary_ration_lib/js/section_tree.js"></script>
+        <script type="text/javascript" src="/web/building_saas/complementary_ration_lib/js/explanatory.js"></script>
+        <script type="text/javascript" src="/web/building_saas/complementary_ration_lib/js/jobContent.js"></script>
+        <script type="text/javascript" src="/web/building_saas/complementary_ration_lib/js/annotation.js"></script>
+        <script type="text/javascript" src="/public/web/scMathUtil.js"></script>
+        <script type="text/javascript" src="/public/web/common_ajax.js"></script>
+        <script type="text/javascript" src="/public/web/ztree_common.js"></script>
+        <script type="text/javascript" src="/web/building_saas/complementary_ration_lib/js/rationUnits.js"></script>
+        <script type="text/javascript" src="/web/building_saas/complementary_ration_lib/js/ration.js"></script>
+        <script type="text/javascript" src="/web/building_saas/complementary_ration_lib/js/ration_glj.js"></script>
+   <!--     <script type="text/javascript" src="/public/web/sheet/sheet_creater.js"></script>-->
+        <script type="text/javascript" src="/web/building_saas/complementary_ration_lib/js/ration_coe.js"></script>
+        <script type="text/javascript" src="/web/building_saas/complementary_ration_lib/js/ration_assist.js"></script>
+        <!--endinject-->
+        <script type="text/javascript">
+            let userID = '<%=userID %>';
+            $(document).ready(function(){
+                pageOprObj.initPage();
+                rationOprObj.buildSheet($("#rationItemsSheet")[0]);
+               // sheetCommonObj.shieldAllCells(rationOprObj.workBook.getSheet(0), rationOprObj.setting);
+
+               // tabPanel 下有多个Spread时,相互之间不能正确显示。改成一个Spread下多个Sheet。
+                var rdSpread = sheetCommonObj.createSpread($("#rdSpread")[0], 3);
+                rationGLJOprObj.buildSheet(rdSpread.getSheet(0));
+               // sheetCommonObj.shieldAllCells(rdSpread.getSheet(0), rationGLJOprObj.setting);
+
+                rationAssistOprObj.buildSheet(rdSpread.getSheet(1));
+             //   sheetCommonObj.shieldAllCells(rdSpread.getSheet(1), rationAssistOprObj.setting);
+
+                rationCoeOprObj.buildSheet(rdSpread.getSheet(2));
+              //  sheetCommonObj.shieldAllCells(rdSpread.getSheet(2), rationCoeOprObj.setting);
+
+                $("#linkGLJ").click(function(){
+                    rationGLJOprObj.bindRationGljDelOpr();
+                    rdSpread.setActiveSheetIndex(0);
+                });
+
+                $("#linkFZDE").click(function(){
+                    rationAssistOprObj.bindRationAssDel();
+                    rdSpread.setActiveSheetIndex(1);
+                });
+
+                $("#linkFZTJ").click(function(){
+                    rationCoeOprObj.bindRationCoeDel();
+                    rdSpread.setActiveSheetIndex(2);
+                });
+            });
+        </script>
+    </div>
+</body>
+<script type="text/javascript">
+    autoFlashHeight();
+</script>
+
+</html>

+ 88 - 0
web/building_saas/complementary_ration_lib/html/fuzhu.html

@@ -0,0 +1,88 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+    <meta http-equiv="x-ua-compatible" content="ie=edge">
+    <title>定额库编辑器</title>
+    <!--inject:css-->
+    <link rel="stylesheet" href="/lib/bootstrap/css/bootstrap.min.css">
+    <link rel="stylesheet" href="/web/building_saas/css/main.css">
+    <link rel="stylesheet" href="/lib/font-awesome/font-awesome.min.css">
+    <link rel="stylesheet" href="/lib/spreadjs/sheets/css/gc.spread.sheets.excel2013lightGray.10.0.1.css" type="text/css">
+    <!--endinject-->
+</head>
+
+<body>
+    <div class="header">
+        <nav class="navbar navbar-toggleable-lg navbar-light bg-faded p-0 ">
+            <span class="header-logo px-2">Smartcost</span>
+            <div class="navbar-text" id="rationname"><a href="main">定额库</a><i class="fa fa-angle-right fa-fw"></i>XXX定额库</div>
+        </nav>
+        <nav class="navbar navbar-toggleable-lg justify-content-between navbar-light p-0">
+              <ul class="nav nav-tabs" role="tablist">
+                  <li class="nav-item">
+                      <a class="nav-link px-3" id="drirect-dinge" href="javascript:void(0);">定额</a>
+                  </li>
+                  <li class="nav-item">
+                      <a class="nav-link px-3" id="gongliao" href="javascript:void(0);">工料机</a>
+                  </li>
+                  <li class="nav-item">
+                      <a class="nav-link active px-3">附注条件</a>
+                  </li>
+                  <li class="nav-item">
+                      <a class="nav-link px-3" href="#maz">安装增加费</a>
+                  </li>
+
+                  <li class="nav-item">
+                  </li>
+              </ul>
+        </nav>
+    </div>
+    <div class="main">
+        <div class="content">
+            <div class="container-fluid">
+                <div class="row">
+                    <div class="main-content col-lg-7 p-0">
+                        <div class="main-data" id="mainSpread">
+                        </div>
+                    </div>
+                    <div class="main-side col-lg-5 p-0">
+                        <div class="main-data" id="contentSpread" >
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <!-- JS. -->
+    <script src = "/lib/spreadjs/sheets/gc.spread.sheets.all.10.0.1.min.js"></script>
+    <!--inject:js-->
+    <script src="/lib/jquery/jquery-3.2.1.min.js"></script>
+    <script src="/lib/popper/popper.min.js"></script>
+    <script src="/lib/bootstrap/bootstrap.min.js"></script>
+    <script type="text/javascript" src="/web/building_saas/complementary_ration_lib/js/global.js"></script>
+    <!-- zTree -->
+    <script>GC.Spread.Sheets.LicenseKey = "559432293813965#A0y3iTOzEDOzkjMyMDN9UTNiojIklkI1pjIEJCLi4TPB9mM5AFNTd4cvZ7SaJUVy3CWKtWYXx4VVhjMpp7dYNGdx2ia9sEVlZGOTh7NRlTUwkWR9wEV4gmbjBDZ4ElR8N7cGdHVvEWVBtCOwIGW0ZmeYVWVr3mI0IyUiwCMzETN8kzNzYTM0IicfJye&Qf35VfiEzRwEkI0IyQiwiIwEjL6ByUKBCZhVmcwNlI0IiTis7W0ICZyBlIsIyNyMzM5ADI5ADNwcTMwIjI0ICdyNkIsIibj9SbvNmL4N7bjRnch56ciojIz5GRiwiI8+Y9sWY9QmZ0Jyp96uL9v6L0wap9biY9qiq95q197Wr9g+89iojIh94Wiqi";</script>
+    <script type="text/javascript" src="/public/web/common_ajax.js"></script>
+    <script type="text/javascript" src="/public/web/treeDataHelper.js"></script>
+    <script type="text/javascript" src="/public/web/QueryParam.js"></script>
+    <script src="/public/web/common_util.js"></script>
+    <script type="text/javascript" src="/public/web/sheet/sheet_common.js"></script>
+    <script type="text/javascript" src="/web/building_saas/complementary_ration_lib/js/sheetsOpr.js"></script>
+    <script type="text/javascript" src="/public/web/storageUtil.js"></script>
+    <script type="text/javascript" src="/web/building_saas/complementary_ration_lib/js/coe.js"></script>
+    <!--endinject-->
+    <script type="text/javascript">
+        $(document).ready(function () {
+            pageObj.initPage();
+        });
+    </script>
+</body>
+<script type="text/javascript">
+    autoFlashHeight();
+</script>
+
+</html>

+ 288 - 0
web/building_saas/complementary_ration_lib/html/gongliao.html

@@ -0,0 +1,288 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+    <meta http-equiv="x-ua-compatible" content="ie=edge">
+    <title>定额库编辑器</title>
+    <!--inject:css-->
+    <link rel="stylesheet" href="/lib/bootstrap/css/bootstrap.min.css">
+    <link rel="stylesheet" href="/web/building_saas/css/main.css">
+    <link rel="stylesheet" href="/lib/font-awesome/font-awesome.min.css">
+    <link rel="stylesheet" href="/lib/spreadjs/sheets/css/gc.spread.sheets.excel2013lightGray.10.0.1.css" type="text/css">
+    <!--zTree-->
+  	<link rel="stylesheet" href="/lib/ztree/css/zTreeStyle.css" type="text/css">
+    <!--endinject-->
+    <style type="text/css">
+        .ztree li span.button.add{margin-right:2px;background-position:-144px 0;vertical-align:top;*vertical-align:middle}
+    </style>
+</head>
+
+<body>
+    <div class="header">
+        <nav class="navbar navbar-toggleable-lg navbar-light bg-faded p-0 ">
+            <span class="header-logo px-2">Smartcost</span>
+            <div id="rationname" class="navbar-text"><a href="main">定额库</a><i class="fa fa-angle-right fa-fw"></i>XXX定额库</div>
+        </nav>
+        <nav class="navbar navbar-toggleable-lg justify-content-between navbar-light p-0">
+              <ul class="nav nav-tabs" role="tablist">
+                  <li class="nav-item">
+                      <a class="nav-link px-3" id="drirect-dinge" href="/complementaryRation/ration">定额</a>
+                  </li>
+                  <li class="nav-item">
+                      <a class="nav-link active px-3">工料机</a>
+                  </li>
+                  <li class="nav-item">
+                      <a class="nav-link px-3" id="fuzhu" href="javascript:void(0);">附注条件</a>
+                  </li>
+                  <li class="nav-item">
+                      <a class="nav-link px-3" href="#maz">安装增加费</a>
+                  </li>
+              </ul>
+        </nav>
+    </div>
+    <div class="main">
+        <div class="content">
+            <div class="container-fluid">
+                <div class="row">
+                    <div class="main-side col-lg-3 p-0" style="width: 100%; height: 100%; overflow-y: auto">
+                        <ul id="repositoryTree" class="ztree"></ul>
+                    </div>
+                    <div class="main-content col-lg-9 p-0">
+                        <div id="GLJListSheet" class="main-data"></div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <!--弹出添加-->
+    <div class="modal fade" id="add" data-backdrop="static" style="display: none;" aria-hidden="true">
+        <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">×</span>
+                  </button>
+                </div>
+                <div class="modal-body">
+                  <form>
+                    <div class="form-group">
+                      <label>编码</label>
+                      <input class="form-control" id="gljcode" placeholder="输入编码" type="text">
+                    </div>
+                    <div class="form-group">
+                      <label>名称</label>
+                      <input class="form-control" id="gljname" placeholder="输入名称" type="text">
+                    </div>
+                    <div class="form-group">
+                      <label>规格</label>
+                      <input class="form-control" id="gljgg" placeholder="输入规格" type="text">
+                    </div>
+                    <div class="form-group">
+                      <label>单位</label>
+                      <select class="form-control" id = "gljdw"><option>选择单位</option><option>工日</option><option>t</option><option>m3</option></select>
+                    </div>
+                    <div class="form-group">
+                      <label>基价单价</label>
+                      <input class="form-control" id="gljjj" placeholder="输入基价" type="number">
+                    </div>
+                    <div class="form-group">
+                      <label>类型</label>
+                      <select class="form-control" id="gljlx"><option>人工</option><option>材料</option></select>
+                    </div>
+                  </form>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-secondary" id="btadd" data-dismiss="modal">添加</button>
+                    <a   class="btn btn-primary">取消</a>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <!--弹出编辑-->
+    <div class="modal fade" id="edit" data-backdrop="static" style="display: none;" aria-hidden="true">
+        <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">×</span>
+                  </button>
+                </div>
+                <div class="modal-body">
+                  <form>
+                    <div class="form-group">
+                      <label>编码</label>
+                      <input class="form-control" placeholder="输入编码" id="Ecode" type="text" value="">
+                    </div>
+                    <div class="form-group">
+                      <label>名称</label>
+                      <input class="form-control" placeholder="输入名称" id ="Ename" type="text" vaule="">
+                    </div>
+                    <div class="form-group">
+                      <label>规格</label>
+                      <input class="form-control" placeholder="输入规格" id="Eguige" type="text">
+                    </div>
+                    <div class="form-group">
+                      <label>单位</label>
+                      <select class="form-control" id="Edanwei"><option>工日</option></select>
+                    </div>
+                    <div class="form-group">
+                      <label>基价单价</label>
+                      <input class="form-control" id="Ejijia" placeholder="输入基价" type="number" value="">
+                    </div>
+                    <div class="form-group">
+                      <label>类型</label>
+                      <select class="form-control" id="Eleixing"><option>人工</option></select>
+                    </div>
+                  </form>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                    <button type="button" class="btn btn-secondary" id="edtglj" data-dismiss="modal">确定</button>
+
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <!--弹出删除-->
+    <div class="modal fade" id="del" data-backdrop="static" style="display: none;" aria-hidden="true">
+        <input type="hidden" id="did" value="">
+        <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">×</span>
+                  </button>
+                </div>
+                <div class="modal-body">
+                    <h5 class="text-danger">删除后无法恢复,确认是否删除?</h5>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-secondary"   data-dismiss="modal">取消</button>
+                    <button type="button" class="btn btn-secondary" id="deleteGLJ"  data-dismiss="modal">删除</button>
+                   <!-- <a href="" class="btn btn-danger" >删除</a>-->
+                </div>
+            </div>
+        </div>
+    </div>
+    <button id="gljAlertBtn" class="btn btn-primary btn-lg" data-toggle="modal" data-target="#gljAlert" style="display: none"></button>
+    <button id="codeAlertBtn" class="btn btn-primary btn-lg" data-toggle="modal" data-target="#codeAlert" style="display: none"></button>
+    <div class="modal fade" id="gljAlert" data-backdrop="static" style="display: none;" aria-hidden="true">
+        <input type="hidden" id="gdid" value="123">
+        <div class="modal-dialog" role="document">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <h5 class="modal-title">取消确认</h5>
+                    <button type="button" id="gljAleClose" class="close" data-dismiss="modal" aria-label="Close">
+                        <span aria-hidden="true">×</span>
+                    </button>
+                </div>
+                <div class="modal-body">
+                    <h5 class="text-danger" id="alertGljTxt">编号和类型不可为空!是否取消操作?</h5>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-secondary" id="aleCanceBtn" data-dismiss="modal">取消</button>
+                    <a href="javascript: void(0);" id="aleConfBtn" class="btn btn-danger" data-dismiss="modal">确认</a>
+                </div>
+            </div>
+        </div>
+    </div>
+    <div class="modal" id="codeAlert" data-backdrop="static" style="display: none;" aria-hidden="true">
+        <input type="hidden" id="codedid" value="123">
+        <div class="modal-dialog" role="document">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <h5 class="modal-title">警告</h5>
+                    <button type="button" id="codAleClose" class="close" data-dismiss="modal" aria-label="Close">
+                        <span aria-hidden="true">×</span>
+                    </button>
+                </div>
+                <div class="modal-body">
+                    <h5 class="text-danger" id="alertText">输入的编号已存在,请重新输入!</h5>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-danger" id="codAleConfBtn" data-dismiss="modal">确认</button>
+                </div>
+            </div>
+        </div>
+    </div>
+    <!-- JS. -->
+    <script src = "/lib/spreadjs/sheets/gc.spread.sheets.all.10.0.1.min.js"></script>
+    <script type="text/javascript" src="/lib/ztree/jquery.ztree.core.js"></script>
+    <script type="text/javascript" src="/lib/ztree/jquery.ztree.excheck.js"></script>
+    <script type="text/javascript" src="/lib/ztree/jquery.ztree.exedit.js"></script>
+    <!--inject:js-->
+    <script src="/lib/jquery/jquery-3.2.1.min.js"></script>
+    <script type="text/javascript" src="/lib/popper/popper.min.js"></script>
+    <script src="/lib/bootstrap/bootstrap.min.js"></script>
+    <script type="text/javascript" src="/web/building_saas/complementary_ration_lib/js/global.js"></script>
+    <!-- zTree -->
+    <script>GC.Spread.Sheets.LicenseKey = "559432293813965#A0y3iTOzEDOzkjMyMDN9UTNiojIklkI1pjIEJCLi4TPB9mM5AFNTd4cvZ7SaJUVy3CWKtWYXx4VVhjMpp7dYNGdx2ia9sEVlZGOTh7NRlTUwkWR9wEV4gmbjBDZ4ElR8N7cGdHVvEWVBtCOwIGW0ZmeYVWVr3mI0IyUiwCMzETN8kzNzYTM0IicfJye&Qf35VfiEzRwEkI0IyQiwiIwEjL6ByUKBCZhVmcwNlI0IiTis7W0ICZyBlIsIyNyMzM5ADI5ADNwcTMwIjI0ICdyNkIsIibj9SbvNmL4N7bjRnch56ciojIz5GRiwiI8+Y9sWY9QmZ0Jyp96uL9v6L0wap9biY9qiq95q197Wr9g+89iojIh94Wiqi";</script>
+    <script type="text/javascript" src="/public/web/common_ajax.js"></script>
+    <script type="text/javascript" src="/public/web/treeDataHelper.js"></script>
+    <script type="text/javascript" src="/public/web/QueryParam.js"></script>
+    <script type="text/javascript" src="/web/building_saas/complementary_ration_lib/js/repository_glj.js"></script>
+    <script type="text/javascript" src="/public/web/ztree_common.js"></script>
+    <script type="text/javascript" src="/public/web/sheet/sheet_common.js"></script>
+    <script type="text/javascript" src="/web/building_saas/complementary_ration_lib/js/sheetsOpr.js"></script>
+    <script type="text/javascript" src="/public/web/storageUtil.js"></script>
+    <!--endinject-->
+    <script type="text/javascript">
+        let userID = '<%=userID %>';
+        var gljSetting = {
+            view: {
+               // addHoverDom: gljTypeTreeOprObj.addHoverDom,
+               // removeHoverDom: gljTypeTreeOprObj.removeHoverDom,
+                expandSpeed: "",
+                selectedMulti: false
+            },
+            edit: {
+                enable: false,
+                editNameSelectAll: true,
+                showRemoveBtn: true,
+                showRenameBtn: true,
+                removeTitle: "删除节点",
+                renameTitle: "更改名称"
+            },
+            data: {
+                keep: {
+                    parent:true,
+                    leaf:true
+                },
+                key: {
+                    children: "items",
+                    name: "Name"
+                },
+                simpleData: {
+                    enable: false,
+                    idKey: "ID",
+                    pIdKey: "ParentID",
+                    rootPId: -1
+                }
+            },
+            callback:{
+               // beforeRename: gljTypeTreeOprObj.beforeRename,
+                //onRename: gljTypeTreeOprObj.onRename,
+               // beforeRemove: gljTypeTreeOprObj.onBeforeRemove,
+                //onRemove: gljTypeTreeOprObj.onRemove,
+                onClick: gljTypeTreeOprObj.onClick
+            }
+        };
+        $(document).ready(function(){
+            pageOprObj.initPage($("#GLJListSheet")[0]);
+            //repositoryGljObj.buildSheet($("#GLJListSheet")[0]);
+        });
+  	</script>
+</body>
+<script type="text/javascript">
+    autoFlashHeight();
+</script>
+
+</html>

+ 54 - 0
web/building_saas/complementary_ration_lib/html/main.html

@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+    <meta http-equiv="x-ua-compatible" content="ie=edge">
+    <title>定额库编辑器</title>
+    <link rel="stylesheet" href="/lib/bootstrap/css/bootstrap.min.css">
+   <!-- <link rel="stylesheet" href="css/bootstrap/themes.css">-->
+    <link rel="stylesheet" href="/web/building_saas/css/main.css">
+    <link rel="stylesheet" href="/lib/font-awesome/font-awesome.min.css">
+</head>
+
+<body>
+    <div class="header">
+        <nav class="navbar navbar-toggleable-lg navbar-light bg-faded p-0 ">
+            <span class="header-logo px-2">Smartcost</span>
+            <div class="navbar-text"></div>
+        </nav>
+    </div>
+    <div class="main">
+        <div class="content">
+            <div class="container-fluid">
+                <div class="row">
+                  <div class="col-md-8">
+                    <div class="warp-p2 mt-3">
+                      <table class="table table-hover table-bordered">
+                        <thead><tr><th>定额库名称</th></tr></thead>
+                        <tbody id="showArea">
+                        </tbody>
+                      </table>
+                    </div>
+                  </div>
+                </div>
+            </div>
+        </div>
+    </div>
+    <!-- JS. -->
+    <script src="/lib/popper/popper.min.js"></script>
+    <script src="/lib/jquery/jquery-3.2.1.min.js"></script>
+    <script src="/lib/bootstrap/bootstrap.min.js"></script>
+    <script src="/web/building_saas/js/global.js"></script>
+    <!-- zTree -->
+    <script type="text/javascript" src="/public/web/date_util.js"></script>
+    <script type="text/javascript" src="/public/web/common_ajax.js"></script>
+    <script type="text/javascript" src="/web/building_saas/complementary_ration_lib/js/main.js"></script>
+    <script type="text/javascript" src="/public/web/storageUtil.js"></script>
+</body>
+<script type="text/javascript">
+    let userID = '<%=userID %>';
+</script>
+
+</html>

+ 407 - 0
web/building_saas/complementary_ration_lib/js/annotation.js

@@ -0,0 +1,407 @@
+/**
+ * Created by Zhong on 2017/12/20.
+ */
+//附注
+let annotationOprObj = {
+    situations: {ALL: 'ALL', PARTIAL: 'PARTIAL', NONE: 'NONE'},
+    currentSituation: null,//本项适用情况
+    radios: $("input[name = 'fzRadios']"),
+    fzTableAll: $('#fzTableAll'),
+    fzTablePartial: $('#fzTablePartial'),
+    currentOprTr: null,
+    currentAnnotation: null,
+    addCon: $('#fzAddCon'),//勾选编码模态框
+    updateCon: $('#fzUpdateCon'),//编辑编码模态框
+    clickUpdate: function (txtarea) {//解决编辑完后在未失去焦点的时候直接定额章节树
+        let me = annotationOprObj;
+        if(txtarea.is(':focus')){
+            let annotation = txtarea.val();
+            if(annotation !== me.currentAnnotation){
+                jobContentOprObj.preTreeNode.data.annotation = annotation;
+                me.unbindEvents(txtarea);
+                txtarea.blur();
+                let updateCodes = [];
+                for(let i = 0, len = jobContentOprObj.currentRationItems.length; i < len; i++){
+                    updateCodes.push(jobContentOprObj.currentRationItems[i].code);
+                    jobContentOprObj.currentRationItems[i].annotation = annotation;
+                }
+                me.updateAnnotation(pageOprObj.rationLibId, me.getUpdateArr(updateCodes, annotation), function () {
+                    me.bindAllEvents(txtarea);
+                });
+            }
+            else {
+                txtarea.blur();
+            }
+        }
+    },
+    getGroup: function (rationItems) {
+        let rst = [];//rst = [{jobContent: String, items: Array}]
+        for(let i = 0, len = rationItems.length; i < len; i++){
+            if(typeof rationItems[i].annotation !== 'undefined' && rationItems[i].annotation.toString().trim().length > 0){
+                let isExist = false;
+                for(let j = 0, jLen = rst.length; j < jLen; j++){
+                    if(rst[j].annotation === rationItems[i].annotation){
+                        isExist = true;
+                        rst[j].items.push(rationItems[i].code);
+                        break;
+                    }
+                }
+                if(!isExist){
+                    rst.push({annotation: rationItems[i].annotation, items: [rationItems[i].code]});
+                }
+            }
+        }
+        return rst;
+    },
+    hideTable: function (tableAll, tablePartial) {
+        if(tableAll){
+            tableAll.hide();
+        }
+        if(tablePartial){
+            tablePartial.hide();
+        }
+    },
+    //建table
+    buildTablePartial: function (table, group) {
+        let me = annotationOprObj;
+        table.empty();
+        let $thead = $("<thead><tr><th></th><th>编码</th><th>附注</th>/tr></thead>");
+        let $tbody = $("<tbody></tbody>");
+        let count = 1;
+        for(let i = 0, len = group.length; i < len; i++){
+            let $newTr = me.getNewTr($tbody, group[i].items, group[i].annotation);
+            $tbody.append($newTr);
+            count++;
+        }
+        let $trEnd = $("<tr><td>"+ count +"</td><td></td><td><textarea class='form-control' disabled='disabled' style='background: white'></textarea></td></tr>");//勾选行
+        /*$($trEnd.children().children()[0]).bind('click', function () {
+            me.onclickFuncAdd($(this));
+            me.currentOprTr = $trEnd;
+            me.currentAnnotation = $(me.currentOprTr.children()[2]).children().val();
+        });*/
+        $tbody.append($trEnd);
+        table.append($thead);
+        table.append($tbody);
+    },
+    //新增一行tr
+    getNewTr: function (tbody, codes, jobContent) {
+        let me = annotationOprObj;
+        let count = tbody.children().length > 0 ? tbody.children().length : 1;
+        let $textTd = $("<td></td>");
+        let $textarea = $("<textarea class='form-control' disabled='disabled' style='background: white'></textarea>");
+        $textarea.val(jobContent);
+        $textTd.append($textarea);
+        let $tr = $("<tr><td>" + count + "</td><td><a href data-toggle='modal' data-target='#fzEditBianmaQ' class='m-0'>编辑编码</a></td></tr>");
+        /*$tr.children().children().bind('click', function () {
+            me.currentOprTr = $tr;
+            me.currentAnnotation = $(me.currentOprTr.children()[2]).children().val();
+            me.onclickFuncEdit($(this));
+        });*/
+        //文本变化;
+       /* $textarea.bind('change', function () {
+            let codes = me.getUpdateCodes($($(this).parent().parent().children()[1]).children());
+            let annotation = $(this).val();
+            me.updateAnnotation(pageOprObj.rationLibId, me.getUpdateArr(codes, annotation), function () {
+                if(annotation.trim().length === 0){
+                    me.buildTablePartial(me.fzTablePartial, me.getGroup(jobContentOprObj.currentRationItems));
+                }
+            });
+        });*/
+        $tr.append($textTd);
+        for(let i = 0, len = codes.length; i < len; i ++){
+            let $p = $("<p class='m-0'>" + codes[i] + "</p>");
+            $tr.children()[1].append($p[0]);
+        }
+        me.setTextareaHeight($textarea, codes.length + 1);
+        return $tr[0];
+    },
+    onclickFuncAdd: function (obj) {
+        let me = annotationOprObj;
+        let txtarea = $(obj.parent().parent().children().children()[1]);
+        let annotation = txtarea.val();
+        if(annotation.trim().length > 0){
+            let codesObj = me.getAddCodes(jobContentOprObj.currentRationItems);
+            me.buildCheckCodesCon(me.addCon, codesObj.checkedCodes, codesObj.disabledCodes)
+            obj.attr('data-target', '#fzEditBianma');
+        }
+        else{
+            obj.attr('data-target', '');
+            alert("附注不能为空!");
+        }
+    },
+    onclickFuncEdit: function (obj) {
+        let me = annotationOprObj;
+        me.buildEditableCodesCon(jobContentOprObj.currentRationItems, me.updateCon, me.getUpdateCodes(obj));
+    },
+    //获取编码td中的编码
+    getUpdateCodes: function (jq) {
+        let rst = [];
+        let nodes = jq.parent().children();
+        for(let i = 1, len = nodes.length; i < len; i++){
+            rst.push(nodes[i].textContent);
+        }
+        return rst;
+    },
+    //建一个编码checkbox Div
+    buildCodeOption: function (code, attr) {
+        let $div = $("<div class='col'><label class='form-check-label'><input class='form-check-input' type='checkbox' value= "+ code +"> "+ code +"</label></div>");
+        let $checkBox = $div.children().children();
+        if(attr){
+            $checkBox.attr(attr, true);
+        }
+        return $div;
+    },
+    //建修改编码弹窗
+    buildEditableCodesCon: function (rationItems, container, codes) {
+        let me = annotationOprObj;
+        let codeDivs = [];
+        container.empty();
+        for(let i = 0, len = codes.length; i < len; i++){
+            codeDivs.push({code: codes[i], attr: 'checked'});
+        }
+        for(let i = 0, len = rationItems.length; i < len; i++){
+            if(codes.indexOf(rationItems[i].code) === -1){
+                if(typeof rationItems[i].annotation !== 'undefined' && rationItems[i].annotation.toString().trim().length > 0){
+                    codeDivs.push({code: rationItems[i].code, attr: 'disabled'});
+                }
+                else{
+                    codeDivs.push({code: rationItems[i].code, attr: ''});
+                }
+            }
+        }
+        //排序
+        codeDivs.sort(function (a, b) {
+            let rst = 0;
+            if(a.code > b.code) rst = 1;
+            else if(a.code < b.code) rst = -1;
+            return rst;
+        });
+        for(let i = 0, len = codeDivs.length; i < len; i++){
+            container.append(me.buildCodeOption(codeDivs[i].code, codeDivs[i].attr));
+        }
+    },
+    //建勾选编码弹窗
+    buildCheckCodesCon: function (container, checkedCodes, disabledCodes) {
+        let me = annotationOprObj;
+        container.empty();
+        for(let i = 0, len = checkedCodes.length; i < len; i++){
+            let $codeDiv = me.buildCodeOption(checkedCodes[i], 'checked');
+            container.append($codeDiv);
+        }
+        for(let i = 0, len = disabledCodes.length; i < len; i++){
+            let $codeDiv = me.buildCodeOption(disabledCodes[i], 'disabled');
+            container.append($codeDiv);
+        }
+    },
+    getAddCodes: function (rationItems) {
+        let me = annotationOprObj;
+        let rst = {checkedCodes: [], disabledCodes: []};
+        for(let i = 0, len = rationItems.length; i < len; i++){
+            if(typeof rationItems[i].annotation !== 'undefined' && rationItems[i].annotation.toString().trim().length > 0){
+                rst.disabledCodes.push(rationItems[i].code);
+            }
+            else{
+                rst.checkedCodes.push(rationItems[i].code);
+            }
+        }
+        return rst;
+    },
+    //获取选择后的编码窗口的编码及状态
+    getCodesAfterS: function (checkNodes) {
+        let rst = {checked: [], unchecked: []};
+        for(let i = 0, len = checkNodes.length; i < len; i++){
+            if(checkNodes[i].checked){
+                rst.checked.push(checkNodes[i].value);
+            }
+            else if(!checkNodes[i].checked && !checkNodes[i].disabled){
+                rst.unchecked.push(checkNodes[i].value);
+            }
+        }
+        return rst;
+    },
+    setRadiosChecked: function (situation, radios) {
+        let me = annotationOprObj;
+        if(situation === me.situations.ALL){
+            radios[0].checked = true;
+            radios[1].checked = false;
+            $('#fzTxtareaAll').val(jobContentOprObj.currentRationItems.length > 0 ? jobContentOprObj.currentRationItems[0].annotation : '');
+            me.currentAnnotation = jobContentOprObj.currentRationItems.length > 0 ? jobContentOprObj.currentRationItems[0].annotation : '';
+            me.fzTableAll.show();
+            me.fzTablePartial.hide();
+        }
+        else if(situation === me.situations.PARTIAL){
+            radios[0].checked = false;
+            radios[1].checked = true;
+            me.fzTableAll.hide();
+            me.fzTablePartial.show();
+        }
+        else if(situation === me.situations.NONE){
+            radios[0].checked = false;
+            radios[1].checked = false;
+            me.fzTableAll.hide();
+            me.fzTablePartial.hide();
+        }
+    },
+    //radios是否可用,只有在定额章节树的底层节点才可用
+    setRadiosDisabled: function (val, radios) {
+        let me =annotationOprObj;
+        if(val){
+            radios[0].checked = false;
+            radios[1].checked = false;
+            me.currentSituation = me.situations.NONE;
+        }
+        radios.attr('disabled', val);
+    },
+    radiosChange: function (radios, tableAll, tablePartial) {
+        let me = annotationOprObj;
+        radios.change(function () {
+            let val = $("input[name = 'fzRadios']:checked").val();
+            let selectedNode = sectionTreeObj.tree.selected;
+            me.updateAnnoSituation(pageOprObj.rationLibId, selectedNode.getID(), val, function () {
+                selectedNode.data.annotationSituation = val;
+                me.currentSituation = val;
+                if(val === me.situations.ALL){
+                    let updateCodes = [];
+                    for(let i = 0, len = jobContentOprObj.currentRationItems.length; i < len; i++){
+                        updateCodes.push(jobContentOprObj.currentRationItems[i].code);
+                    }
+                    me.updateAnnotation(pageOprObj.rationLibId, me.getUpdateArr(updateCodes, ''), function () {
+                        me.currentAnnotation = '';
+                        $('#fzTxtareaAll').val('');
+                        tableAll.show();
+                        tablePartial.hide();
+                    });
+                }
+                else{
+                    me.buildTablePartial(me.fzTablePartial, me.getGroup(jobContentOprObj.currentRationItems));
+                    tableAll.hide();
+                    tablePartial.show();
+                }
+            });
+        });
+    },
+    setTextareaHeight: function (textarea, nodesCount) {
+        const perHeight = 21.6;
+        textarea.height(nodesCount * 21.6);
+    },
+    bindEvents: function (txtarea) {
+        let me = annotationOprObj;
+        txtarea.bind('change', function () {
+            let annotation = txtarea.val();
+            let jqNodes = txtarea.parent().parent().children()[1].children;
+            let updateCodes = me.getUpdateCodes(jqNodes);
+            txtarea.attr('disabled', true);
+            me.updateAnnotation(pageOprObj.rationLibId, me.getUpdateArr(updateCodes, annotation), function () {
+                txtarea.attr('disabled', false);
+            });
+        });
+    },
+    bindAllEvents: function (txtarea) {
+        let me = annotationOprObj;
+        txtarea.bind('change', function () {
+            let met = this;
+            let annotation = $(met).val();
+            $(met).attr('disabled', true);
+            let updateCodes = [];
+            for(let i = 0, len = jobContentOprObj.currentRationItems.length; i < len; i++){
+                updateCodes.push(jobContentOprObj.currentRationItems[i].code);
+                jobContentOprObj.currentRationItems[i].annotation = annotation;
+            }
+            me.currentAnnotation = annotation;
+            me.updateAnnotation(pageOprObj.rationLibId, me.getUpdateArr(updateCodes, annotation), function () {
+                $(met).attr('disabled', false);
+            });
+        });
+    },
+    unbindEvents: function (txtarea) {
+        txtarea.unbind();
+    },
+    //定额工作内容相关操作
+    rationAnnotationOpr: function (rationItems) {
+        let me = annotationOprObj;
+     //   me.setRadiosDisabled(rationItems.length > 0 ? false : true, me.radios);
+        me.setRadiosChecked(me.currentSituation, me.radios);
+        me.buildTablePartial(me.fzTablePartial, me.getGroup(rationItems));
+    },
+    getUpdateArr: function (updateCodes, annotation) {
+        let rst = [];
+        for(let i = 0, len = updateCodes.length; i < len; i++){
+            rst.push({code: updateCodes[i], annotation: annotation});
+        }
+        return rst;
+    },
+    bindAddConBtn: function () {
+        let me = annotationOprObj;
+        return function () {
+            let codesObj = me.getCodesAfterS(me.addCon.children().children().children());
+            let $tbody = $('#fzTablePartial tbody');
+            let lastEle = $tbody[0].lastElementChild;
+            let txtare = lastEle.lastElementChild.children[0];
+            if(me.currentAnnotation.trim().length > 0){//工作内容不为空才可添加编码
+                let updateArr = me.getUpdateArr(codesObj.checked, me.currentAnnotation);
+                me.updateAnnotation(pageOprObj.rationLibId, updateArr, function () {
+                    me.buildTablePartial(me.fzTablePartial, me.getGroup(jobContentOprObj.currentRationItems));
+                    $(txtare).val('');
+                });
+            }
+            else{
+                alert("附注不能为空!");
+            }
+        }
+    },
+    bindUpdateConBtn: function () {
+        let me = annotationOprObj;
+        return function () {
+            let codesObj = me.getCodesAfterS(me.updateCon.children().children().children());
+            let updateC = me.getUpdateArr(codesObj.checked, me.currentAnnotation),
+                updateUnC = me.getUpdateArr(codesObj.unchecked, ''),
+                updateArr = updateC.concat(updateUnC);
+            me.updateAnnotation(pageOprObj.rationLibId, updateArr, function () {
+                me.buildTablePartial(me.fzTablePartial, me.getGroup(jobContentOprObj.currentRationItems));
+            });
+        }
+    },
+    //更新缓存的定额
+    updateRationItem: function (rationItems, updateArr) {
+        for(let i = 0, len = rationItems.length; i < len; i++){
+            for(let j = 0, jLen = updateArr.length; j < jLen; j++){
+                if(rationItems[i].code === updateArr[j].code){
+                    rationItems[i].annotation = updateArr[j].annotation;
+                    break;
+                }
+            }
+        }
+    },
+    updateAnnotation: function (repId, updateArr, callback){
+        let me = annotationOprObj;
+        $.ajax({
+            type: 'post',
+            url: 'api/updateAnnotation',
+            data: {lastOpr: userAccount, repId: repId, updateArr: JSON.stringify(updateArr)},
+            dataType: 'json',
+            success: function (result) {
+                if(!result.error){
+                    me.updateRationItem(jobContentOprObj.currentRationItems, updateArr);
+                    callback();
+                }
+            }
+        });
+    },
+    updateAnnoSituation: function (repId, nodeId, situation, callback) {
+        let me = annotationOprObj;
+        $.ajax({
+            type: 'post',
+            url: 'api/updateAnnoSituation',
+            data: {lastOpr: userAccount, repId: repId, nodeId: nodeId, situation: situation},
+            dataType: 'json',
+            success: function (result) {
+                if(!result.error){
+                    if(callback){
+                        callback();
+                    }
+                }
+            }
+        })
+    }
+
+};

+ 215 - 0
web/building_saas/complementary_ration_lib/js/coe.js

@@ -0,0 +1,215 @@
+/**
+ * Created by CSL on 2017-05-18.
+ */
+//modiyied by zhong on 2017/9/21
+
+
+var pageObj = {
+    libID: null,
+    gljLibID: null,
+    initPage: function (){
+        $("#drirect-dinge").click(function(){
+            $(this).attr('href', "/complementaryRation/ration" + "?repository=" + getQueryString("repository"))
+        });
+
+        $("#gongliao").click(function(){
+            $(this).attr('href', "/complementaryRation/glj" + "?repository=" + getQueryString("repository"))
+        });
+
+        var libID = getQueryString("repository");
+        var libName = storageUtil.getSessionCache("RationGrp","repositoryID_" + libID);
+        if (libName) {
+            var html = $("#rationname")[0].outerHTML;
+            html = html.replace("XXX定额库", libName);
+            $("#rationname")[0].outerHTML = html;
+        };
+        this.gljLibID = storageUtil.getSessionCache("gljLib", "repositoryID_" + libID);
+        this.libID = libID;
+        coeOprObj.buildSheet($('#mainSpread')[0]);
+        gljAdjOprObj.buildSheet($('#contentSpread')[0]);
+        coeOprObj.getCoeList();
+        gljAdjOprObj.getGljItemsOcc();
+
+    },
+    showData: function(sheet, setting, data) {
+        let me = pageObj, ch = GC.Spread.Sheets.SheetArea.viewport;
+        sheet.suspendPaint();
+        sheet.suspendEvent();
+        sheet.clear(0, 0, sheet.getRowCount(), sheet.getColumnCount(), GC.Spread.Sheets.SheetArea.viewport, GC.Spread.Sheets.StorageType.data);
+        sheet.setRowCount(data.length + 3);
+        for (let col = 0; col < setting.header.length; col++) {
+            var hAlign = "left", vAlign = "center";
+            if (setting.header[col].hAlign) {
+                hAlign = setting.header[col].hAlign;
+            } else if (setting.header[col].dataType !== "String"){
+                hAlign = "right";
+            }
+            if(setting.header[col].readOnly){
+                sheet.getRange(-1, col, -1, 1).locked(true);
+            }
+            else{
+                sheet.getRange(-1, col, -1, 1).locked(false);
+            }
+            vAlign = setting.header[col].vAlign?setting.header[col].vAlign:vAlign;
+            sheetCommonObj.setAreaAlign(sheet.getRange(-1, col, -1, 1), hAlign, vAlign);
+            if (setting.header[col].formatter) {
+                sheet.setFormatter(-1, col, setting.header[col].formatter, GC.Spread.Sheets.SheetArea.viewport);
+            }
+            for (let row = 0; row < data.length; row++) {
+                let val = data[row][setting.header[col].dataCode];
+                sheet.setValue(row, col, val, ch);
+            }
+        }
+        sheet.resumeEvent();
+        sheet.resumePaint();
+    }
+};
+
+let coeOprObj = {
+    workBook: null,
+    workSheet: null,
+    currentCoeList: [],
+    currentCoe: null,
+    currentMaxNo: null,
+    setting: {
+        header: [
+            {headerName:"编号", headerWidth:60, dataCode:"serialNo", dataType: "String", hAlign: "center", vAlign: "center", readOnly: false},
+            {headerName:"名称", headerWidth:280, dataCode:"name", dataType: "String", hAlign: "left", vAlign: "center", readOnly: false},
+            {headerName:"内容", headerWidth:250, dataCode:"content", dataType: "String", hAlign: "left", vAlign: "center", readOnly: false},
+        ]
+    },
+    buildSheet: function (container) {
+        let me = coeOprObj;
+        me.workBook = sheetCommonObj.buildSheet(container, me.setting, 30);
+        me.workSheet = me.workBook.getSheet(0);
+        me.workSheet.options.isProtected = true;
+        me.workSheet.bind(GC.Spread.Sheets.Events.SelectionChanged, me.onSelectionChanged);
+        me.workSheet.bind(GC.Spread.Sheets.Events.EditStarting, me.onEditStarting);
+        me.workBook.bind(GC.Spread.Sheets.Events.ClipboardPasting, me.onClipboardPasting);
+    },
+    onSelectionChanged: function (sender, info) {
+        let me = coeOprObj, that = gljAdjOprObj;
+        if(info.oldSelections.length === 0 && info.newSelections.length > 0 || info.oldSelections[0].row !== info.newSelections[0].row){
+            let row = info.newSelections[0].row;
+            if(row < me.currentCoeList.length){
+                me.currentCoe = me.currentCoeList[row];
+                that.currentGljAdjList = me.currentCoe.coes;
+                that.buildDynamicComboBox(that.workSheet);
+            }
+            else{
+                me.currentCoe = null;
+                that.currentGljAdjList = [];
+                that.buildBaseCell(that.workSheet);
+            }
+            //refresh & show coes
+            sheetCommonObj.cleanSheet(that.workSheet, that.setting, -1);
+            me.workBook.focus(true);
+            that.show(that.currentGljAdjList);
+        }
+    },
+    onEditStarting: function (sender, args) {
+        args.cancel = true;
+    },
+    onClipboardPasting: function (sender, info) {
+        info.cancel = true;
+    },
+    isInt: function (num) {
+        return !isNaN(num) && num % 1 === 0;
+    },
+    sortCoeList: function (coeList) {
+        coeList.sort(function (a, b) {
+            let rst = 0;
+            if(a.serialNo > b.serialNo) rst = 1;
+            else if(a.serialNo < b.serialNo) rst = -1;
+            return rst;
+        });
+    },
+    getCoeList: function () {
+        let me = coeOprObj;
+        CommonAjax.post('api/getCoeList', {libID: pageObj.libID}, function (rstData) {
+            me.currentCoeList = rstData;
+            me.sortCoeList(me.currentCoeList);
+            me.currentMaxNo =  me.currentCoeList.length > 0 ? me.currentCoeList[me.currentCoeList.length - 1].serialNo : 0;
+            pageObj.showData(me.workSheet, me.setting, me.currentCoeList);
+            me.workSheet.clearSelection();
+        });
+    }
+};
+
+let gljAdjOprObj = {
+    workBook: null,
+    workSheet: null,
+    currentGljAdjList: [],
+    gljList: [],//只含编号和名称的总工料机列表
+    setting: {
+        header: [
+            {headerName:"调整类型", headerWidth:100, dataCode:"coeType", dataType: "String", hAlign: "center", vAlign: "center", readOnly: false},
+            {headerName:"工料机编码", headerWidth:100, dataCode:"gljCode", dataType: "String", formatter: '@', hAlign: "center", vAlign: "center", readOnly: false},
+            {headerName:"名称", headerWidth:100, dataCode:"gljName", dataType: "String", hAlign: "center", vAlign: "center", readOnly: true},
+            {headerName:"操作符", headerWidth:60, dataCode:"operator", dataType: "String", hAlign: "center", vAlign: "center", readOnly: false},
+            {headerName:"数量", headerWidth:80, dataCode:"amount", dataType: "String", hAlign: "center", vAlign: "center" , readOnly: false},
+        ],
+        comboItems: {
+            //调整类型下拉菜单
+            coeType: ['定额子目', '人工类', '材料类', '机械类', '主材类', '设备类', '单个工料机'],
+            //操作符下拉菜单
+            operator: ['+', '-', '*', '/', '=']
+        }
+    },
+    buildSheet: function (container) {
+        let me = gljAdjOprObj;
+        me.workBook = sheetCommonObj.buildSheet(container, me.setting, 3);
+        me.workSheet = me.workBook.getSheet(0);
+        me.workSheet.options.isProtected = true;
+        me.workSheet.clearSelection();
+        me.workSheet.bind(GC.Spread.Sheets.Events.EditStarting, me.onEditStart);
+        me.workSheet.bind(GC.Spread.Sheets.Events.EnterCell, me.onEnterCell);
+        me.workSheet.bind(GC.Spread.Sheets.Events.ClipboardPasting, me.onClipboardPasting);
+    },
+    buildBaseCell: function (sheet) {
+        let me = gljAdjOprObj;
+        sheet.suspendPaint();
+        sheet.suspendEvent();
+        let baseCell = GC.Spread.Sheets.CellTypes.Base();
+        sheet.getCell(-1, 0).cellType(baseCell);
+        sheet.getCell(-1, 3).cellType(baseCell);
+        sheet.resumePaint();
+        sheet.resumeEvent();
+    },
+    buildDynamicComboBox: function (sheet) {
+        let me = gljAdjOprObj;
+        sheet.suspendPaint();
+        sheet.suspendEvent();
+        let dynamicCombo = sheetCommonObj.getDynamicCombo();
+        dynamicCombo.items(me.setting.comboItems.coeType);
+        let dynamicOprCombo = sheetCommonObj.getDynamicCombo();
+        dynamicOprCombo.items(me.setting.comboItems.operator);
+        sheet.getCell(-1, 0).cellType(dynamicCombo);
+        sheet.getCell(-1, 3).cellType(dynamicOprCombo);
+        sheet.resumePaint();
+        sheet.resumeEvent();
+    },
+    onEnterCell: function (sender, args) {
+        args.sheet.repaint();
+    },
+    onEditStart: function (sender, args) {
+        let me = gljAdjOprObj;
+        args.cancel = true;
+    },
+    onClipboardPasting: function (sender, info) {
+        info.cancel = true;
+    },
+    show: function (coes) {
+        let me = gljAdjOprObj;
+        pageObj.showData(me.workSheet, me.setting, coes)
+    },
+    getGljItemsOcc: function () {
+        let me = gljAdjOprObj;
+        CommonAjax.post('api/getGljItemsOccupied', {gljLibId: pageObj.gljLibID, occupation: '-_id code name'}, function (rstData) {
+            me.gljList = rstData;
+        });
+
+    }
+};
+
+

+ 95 - 0
web/building_saas/complementary_ration_lib/js/explanatory.js

@@ -0,0 +1,95 @@
+/**
+ * Created by Zhong on 2017/12/20.
+ */
+//定额章节节点说明、计算规则
+let explanatoryOprObj = {
+    preTreeNode: null,
+    currentTreeNode: null,//定额章节树节点
+    currentExplanation: null,
+    currentRuleText: null,
+    setAttribute: function (preNode, currentNode, explanation, ruleText) {
+        let me = explanatoryOprObj;
+        me.preTreeNode = preNode;
+        me.currentTreeNode = currentNode;
+        me.currentExplanation = explanation;
+        me.currentRuleText = ruleText;
+    },
+    clickUpdate: function (exarea, ruarea) {//解决编辑完后在未失去焦点的时候直接定额章节树
+        let me = explanatoryOprObj;
+        if(exarea.is(':focus')){
+            let explanation = exarea.val();
+            if(explanation !== me.currentExplanation){
+                me.preTreeNode.data.explanation = explanation;
+                me.unbindEvents(exarea, ruarea);
+                exarea.blur();
+                me.updateExplanation(pageOprObj.rationLibId, me.preTreeNode.getID(), explanation, function () {
+                    me.bindEvents(exarea, ruarea);
+                });
+            }
+        }
+        if(ruarea.is(':focus')){
+            let ruleText = ruarea.val();
+            if(ruleText !== me.currentRuleText){
+                me.preTreeNode.data.ruleText = ruleText;
+                me.unbindEvents(exarea, ruarea);
+                ruarea.blur();
+                me.updateRuleText(pageOprObj.rationLibId, me.preTreeNode.getID(), ruleText, function () {
+                    me.bindEvents(exarea, ruarea);
+                });
+            }
+        }
+    },
+    unbindEvents: function (exarea, ruarea) {
+        exarea.unbind();
+        ruarea.unbind();
+    },
+    bindEvents: function (exarea, ruarea) {
+        let me = explanatoryOprObj;
+        exarea.bind('change', function () {
+            let explanation = exarea.val();
+            let node = me.currentTreeNode;
+            exarea.attr('disabled', true);
+            me.updateExplanation(pageOprObj.rationLibId, node.getID(), explanation, function () {
+                node.data.explanation = explanation;
+                exarea.attr('disabled', false);
+            });
+        });
+        ruarea.bind('change', function () {
+            let ruleText = ruarea.val();
+            let node = me.currentTreeNode;
+            ruarea.attr('disabled', true);
+            me.updateRuleText(pageOprObj.rationLibId, node.getID(), ruleText, function () {
+                node.data.ruleText = ruleText;
+                ruarea.attr('disabled', false);
+            });
+        });
+    },
+    showText: function (exarea, ruarea, explanation, ruleText) {
+        exarea.val(explanation && explanation !== 'undefined' ? explanation : '');
+        ruarea.val(ruleText && ruleText !== 'undefined' ? ruleText : '');
+    },
+    //更新说明
+    updateExplanation: function (repId, nodeId, explanation, callback) {
+        $.ajax({
+            type: 'post',
+            url: 'api/updateExplanation',
+            data: {lastOpr: userAccount, repId: pageOprObj.rationLibId, nodeId: nodeId, explanation: explanation},
+            dataType: 'json',
+            success: function () {
+                callback();
+            }
+        });
+    },
+    //更新计算规则
+    updateRuleText: function (repId, nodeId, explanation, callback) {
+        $.ajax({
+            type: 'post',
+            url: 'api/updateRuleText',
+            data: {lastOpr: userAccount, repId: pageOprObj.rationLibId, nodeId: nodeId, ruleText: explanation},
+            dataType: 'json',
+            success: function () {
+                callback();
+            }
+        });
+    }
+};

+ 43 - 0
web/building_saas/complementary_ration_lib/js/global.js

@@ -0,0 +1,43 @@
+/*全局自适应高度*/
+function autoFlashHeight(){
+    var headerHeight = $(".header").height();
+    var bottomContentHeight = $(".bottom-content").height();
+    var toolsBar = $(".tools-bar").height();
+    $(".content").height($(window).height()-headerHeight);
+    $(".main-side").height($(window).height()-headerHeight-2);
+    $(".fluid-content").height($(window).height()-headerHeight-1);
+    $(".side-content").height($(window).height()-headerHeight );
+    $(".poj-list").height($(window).height()-headerHeight);
+    $(".form-list").height($(window).height()-headerHeight-50 );
+    $(".main-data-top").height($(window).height()-headerHeight-toolsBar-bottomContentHeight-2);
+    $(".main-data").height($(window).height()-headerHeight);
+    $(".main-side .tab-content").height($(window).height()-headerHeight-38);
+};
+$(window).resize(autoFlashHeight);
+/*全局自适应高度结束*/
+$(function(){
+/*侧滑*/
+$(".open-sidebar").click(function(){
+    $(".slide-sidebar").animate({width:"800"}).addClass("open");
+});
+$("body").click(function(event){
+        var e = event || window.event; //浏览器兼容性
+        if(!$(event.target).is('a')) {
+            var elem = event.target || e.srcElement;
+            while (elem) { //循环判断至跟节点,防止点击的是div子元素
+                if (elem.className == "open-sidebar" || elem.className == 'slide-sidebar open') {
+                    return false;
+                }
+                elem = elem.parentNode;
+            }
+            $(".slide-sidebar").animate({width:"0"}).removeClass("open")// 关闭处理
+        }
+
+    });
+/*侧滑*/
+/*工具提示*/
+$('*[data-toggle=tooltip]').mouseover(function() {
+ $(this).tooltip('show');
+  });
+/*工具提示*/
+});

+ 414 - 0
web/building_saas/complementary_ration_lib/js/jobContent.js

@@ -0,0 +1,414 @@
+/**
+ * Created by Zhong on 2017/12/20.
+ */
+//工作内容
+let jobContentOprObj = {
+    situations: {ALL: 'ALL', PARTIAL: 'PARTIAL', NONE: 'NONE'},//所有ALL(包括未定义本项工作内容)、部分PARTIA,不可用NONE(无定额时)
+    currentSituation: null,//本项适用情况
+    currentTreeNode: null,
+    preTreeNode: null,
+    radios: $("input[name = 'optionsRadios']"),
+    tableAll: $('#tableAll'),
+    tablePartial: $('#tablePartial'),
+    currentOprTr: null,
+    currentJobContent: null,
+    currentRationItems: null,
+    addCon: $('#addCon'),//勾选编码模态框
+    updateCon: $('#updateCon'),//编辑编码模态框
+    setAttribute: function (preNode, currentNode) {
+        let me = jobContentOprObj;
+        me.preTreeNode = preNode;
+        me.currentTreeNode = currentNode;
+    },
+    clickUpdate: function (txtarea) {//解决编辑完后在未失去焦点的时候直接定额章节树
+        let me = jobContentOprObj;
+        if(txtarea.is(':focus')){
+            let jobContent = txtarea.val();
+            if(jobContent !== me.currentJobContent){
+                me.preTreeNode.data.jobContent = jobContent;
+                me.unbindEvents(txtarea);
+                txtarea.blur();
+                let updateCodes = [];
+                for(let i = 0, len = me.currentRationItems.length; i < len; i++){
+                    updateCodes.push(me.currentRationItems[i].code);
+                    me.currentRationItems[i].jobContent = jobContent;
+                }
+                me.updateJobContent(pageOprObj.rationLibId, me.getUpdateArr(updateCodes, jobContent), function () {
+                    me.bindAllEvents(txtarea);
+                })
+            }
+            else {
+                txtarea.blur();
+            }
+        }
+    },
+    getGroup: function (rationItems) {
+        let rst = [];//rst = [{jobContent: String, items: Array}]
+        for(let i = 0, len = rationItems.length; i < len; i++){
+            if(typeof rationItems[i].jobContent !== 'undefined' && rationItems[i].jobContent.toString().trim().length > 0){
+                let isExist = false;
+                for(let j = 0, jLen = rst.length; j < jLen; j++){
+                    if(rst[j].jobContent === rationItems[i].jobContent){
+                        isExist = true;
+                        rst[j].items.push(rationItems[i].code);
+                        break;
+                    }
+                }
+                if(!isExist){
+                    rst.push({jobContent: rationItems[i].jobContent, items: [rationItems[i].code]});
+                }
+            }
+        }
+        return rst;
+    },
+    hideTable: function (tableAll, tablePartial) {
+        if(tableAll){
+            tableAll.hide();
+        }
+        if(tablePartial){
+            tablePartial.hide();
+        }
+    },
+    //建table
+    buildTablePartial: function (table, group) {
+        let me = jobContentOprObj;
+        table.empty();
+        let $thead = $("<thead><tr><th></th><th>编码</th><th>工作内容</th>/tr></thead>");
+        let $tbody = $("<tbody></tbody>");
+        let count = 1;
+        for(let i = 0, len = group.length; i < len; i++){
+            let $newTr = me.getNewTr($tbody, group[i].items, group[i].jobContent);
+            $tbody.append($newTr);
+            count++;
+        }
+        let $trEnd = $("<tr><td>"+ count +"</td><td></td><td><textarea class='form-control' disabled='disabled' style='background: white'></textarea></td></tr>");//勾选行
+      /*  $($trEnd.children().children()[0]).bind('click', function () {
+            me.onclickFuncAdd($(this));
+            me.currentOprTr = $trEnd;
+            me.currentJobContent = $(me.currentOprTr.children()[2]).children().val();
+        });*/
+        $tbody.append($trEnd);
+        table.append($thead);
+        table.append($tbody);
+    },
+    //新增一行tr
+    getNewTr: function (tbody, codes, jobContent) {
+        let me = jobContentOprObj;
+        let count = tbody.children().length > 0 ? tbody.children().length : 1;
+        let $textTd = $("<td></td>");
+        let $textarea = $("<textarea class='form-control' disabled='disabled' style='background: white;'></textarea>");
+        $textarea.val(jobContent);
+        $textTd.append($textarea);
+        let $tr = $("<tr><td>" + count + "</td><td><a href data-toggle='modal' data-target='#editBianmaQ' class='m-0'>编辑编码</a></td></tr>");
+        /*$tr.children().children().bind('click', function () {
+            me.currentOprTr = $tr;
+            me.currentJobContent = $(me.currentOprTr.children()[2]).children().val();
+            me.onclickFuncEdit($(this));
+        });*/
+        //文本变化;
+        $textarea.bind('change', function () {
+            let codes = me.getUpdateCodes($($(this).parent().parent().children()[1]).children());
+            let jobContent = $(this).val();
+            me.updateJobContent(pageOprObj.rationLibId, me.getUpdateArr(codes, jobContent), function () {
+                if(jobContent.trim().length === 0){
+                    me.buildTablePartial(me.tablePartial, me.getGroup(me.currentRationItems));
+                }
+            });
+        });
+        $tr.append($textTd);
+        for(let i = 0, len = codes.length; i < len; i ++){
+            let $p = $("<p class='m-0'>" + codes[i] + "</p>");
+            $tr.children()[1].append($p[0]);
+        }
+        me.setTextareaHeight($textarea, codes.length + 1);
+        return $tr[0];
+    },
+    onclickFuncAdd: function (obj) {
+        let me = jobContentOprObj;
+        let txtarea = $(obj.parent().parent().children().children()[1]);
+        let jobContent = txtarea.val();
+        if(jobContent.trim().length > 0){//工作内容不为空才可添加编码
+            let codesObj = me.getAddCodes(me.currentRationItems);
+            me.buildCheckCodesCon(me.addCon, codesObj.checkedCodes, codesObj.disabledCodes)
+            obj.attr('data-target', '#editBianma');
+        }
+        else{
+            obj.attr('data-target', '');
+            alert("工作内容不能为空!");
+        }
+    },
+    onclickFuncEdit: function (obj) {
+        let me = jobContentOprObj;
+        me.buildEditableCodesCon(me.currentRationItems, me.updateCon, me.getUpdateCodes(obj));
+    },
+    //获取编码td中的编码
+    getUpdateCodes: function (jq) {
+        let rst = [];
+        let nodes = jq.parent().children();
+        for(let i = 1, len = nodes.length; i < len; i++){
+            rst.push(nodes[i].textContent);
+        }
+        return rst;
+    },
+    //建一个编码checkbox Div
+    buildCodeOption: function (code, attr) {
+        let $div = $("<div class='col'><label class='form-check-label'><input class='form-check-input' type='checkbox' value= "+ code +"> "+ code +"</label></div>");
+        let $checkBox = $div.children().children();
+        if(attr){
+            $checkBox.attr(attr, true);
+        }
+        return $div;
+    },
+    //建修改编码弹窗
+    buildEditableCodesCon: function (rationItems, container,codes) {
+        let me = jobContentOprObj;
+        let codeDivs = [];
+        container.empty();
+        for(let i = 0, len = codes.length; i < len; i++){
+            codeDivs.push({code: codes[i], attr: 'checked'});
+        }
+        for(let i = 0, len = rationItems.length; i < len; i++){
+            if(codes.indexOf(rationItems[i].code) === -1){
+                if(typeof rationItems[i].jobContent !== 'undefined' && rationItems[i].jobContent.toString().trim().length > 0){
+                    codeDivs.push({code: rationItems[i].code, attr: 'disabled'});
+                }
+                else{
+                    codeDivs.push({code: rationItems[i].code, attr: ''});
+                }
+            }
+        }
+        //排序
+        codeDivs.sort(function (a, b) {
+            let rst = 0;
+            if(a.code > b.code) rst = 1;
+            else if(a.code < b.code) rst = -1;
+            return rst;
+        });
+        for(let i = 0, len = codeDivs.length; i < len; i++){
+            container.append(me.buildCodeOption(codeDivs[i].code, codeDivs[i].attr));
+        }
+    },
+    //建勾选编码弹窗
+    buildCheckCodesCon: function (container, checkedCodes, disabledCodes) {
+        let me = jobContentOprObj;
+        container.empty();
+        for(let i = 0, len = checkedCodes.length; i < len; i++){
+            let $codeDiv = me.buildCodeOption(checkedCodes[i], 'checked');
+            container.append($codeDiv);
+        }
+        for(let i = 0, len = disabledCodes.length; i < len; i++){
+            let $codeDiv = me.buildCodeOption(disabledCodes[i], 'disabled');
+            container.append($codeDiv);
+        }
+    },
+    getAddCodes: function (rationItems) {
+        let me = jobContentOprObj;
+        let rst = {checkedCodes: [], disabledCodes: []};
+        for(let i = 0, len = rationItems.length; i < len; i++){
+            if(typeof rationItems[i].jobContent !== 'undefined' && rationItems[i].jobContent.toString().trim().length > 0){
+                rst.disabledCodes.push(rationItems[i].code);
+            }
+            else{
+                rst.checkedCodes.push(rationItems[i].code);
+            }
+        }
+        return rst;
+    },
+    //获取选择后的编码窗口的编码及状态
+    getCodesAfterS: function (checkNodes) {
+        let rst = {checked: [], unchecked: []};
+        for(let i = 0, len = checkNodes.length; i < len; i++){
+            if(checkNodes[i].checked){
+                rst.checked.push(checkNodes[i].value);
+            }
+            else if(!checkNodes[i].checked && !checkNodes[i].disabled){
+                rst.unchecked.push(checkNodes[i].value);
+            }
+        }
+        return rst;
+    },
+    setRadiosChecked: function (situation, radios) {
+        let me = jobContentOprObj;
+        if(situation === me.situations.ALL){
+            radios[0].checked = true;
+            radios[1].checked = false;
+            $('#txtareaAll').val(me.currentRationItems.length > 0 ? me.currentRationItems[0].jobContent : '');
+            me.currentJobContent = me.currentRationItems.length > 0 ? me.currentRationItems[0].jobContent : '';
+            me.tableAll.show();
+            me.tablePartial.hide();
+        }
+        else if(situation === me.situations.PARTIAL){
+            radios[0].checked = false;
+            radios[1].checked = true;
+            me.tableAll.hide();
+            me.tablePartial.show();
+        }
+        else if(situation === me.situations.NONE){
+            radios[0].checked = false;
+            radios[1].checked = false;
+            me.tableAll.hide();
+            me.tablePartial.hide();
+        }
+    },
+    //radios是否可用,只有在定额章节树的底层节点才可用
+    setRadiosDisabled: function (val, radios) {
+        let me =jobContentOprObj;
+        if(val){
+            radios[0].checked = false;
+            radios[1].checked = false;
+            me.currentSituation = me.situations.NONE;
+        }
+        radios.attr('disabled', val);
+    },
+    radiosChange: function (radios, tableAll, tablePartial) {
+        let me = jobContentOprObj;
+        radios.change(function () {
+            let val = $("input[name = 'optionsRadios']:checked").val();
+            let selectedNode = sectionTreeObj.tree.selected;
+            me.updateSituation(pageOprObj.rationLibId, selectedNode.getID(), val, function () {
+                selectedNode.data.jobContentSituation = val;
+                me.currentSituation = val;
+                if(val === me.situations.ALL){
+                    let updateCodes = [];
+                    for(let i = 0, len = me.currentRationItems.length; i < len; i++){
+                        updateCodes.push(me.currentRationItems[i].code);
+                    }
+                    me.updateJobContent(pageOprObj.rationLibId, me.getUpdateArr(updateCodes, ''), function () {
+                        me.currentJobContent = '';
+                        $('#txtareaAll').val('');
+                        tableAll.show();
+                        tablePartial.hide();
+                    });
+                }
+                else{
+                    me.buildTablePartial(me.tablePartial, me.getGroup(me.currentRationItems));
+                    tableAll.hide();
+                    tablePartial.show();
+                }
+            });
+        });
+    },
+    setTextareaHeight: function (textarea, nodesCount) {
+        const perHeight = 21.6;
+        textarea.height(nodesCount * 21.6);
+    },
+    bindEvents: function (txtarea) {
+        let me = jobContentOprObj;
+        txtarea.bind('change', function () {
+            let jobContent = txtarea.val();
+            let jqNodes = txtarea.parent().parent().children()[1].children;
+            let updateCodes = me.getUpdateCodes(jqNodes);
+            txtarea.attr('disabled', true);
+            me.updateJobContent(pageOprObj.rationLibId, me.getUpdateArr(updateCodes, jobContent), function () {
+                txtarea.attr('disabled', false);
+            });
+        });
+    },
+    bindAllEvents: function (txtarea) {
+        let me = jobContentOprObj;
+        txtarea.bind('change', function () {
+            let met = this;
+            let jobContent = $(met).val();
+            $(met).attr('disabled', true);
+            let updateCodes = [];
+            for(let i = 0, len = me.currentRationItems.length; i < len; i++){
+                updateCodes.push(me.currentRationItems[i].code);
+                me.currentRationItems[i].jobContent = jobContent;
+            }
+            me.currentJobContent = jobContent;
+            me.updateJobContent(pageOprObj.rationLibId, me.getUpdateArr(updateCodes, jobContent), function () {
+                $(met).attr('disabled', false);
+            });
+        });
+    },
+    unbindEvents: function (txtarea) {
+        txtarea.unbind();
+    },
+    //定额工作内容相关操作
+    rationJobContentOpr: function (rationItems) {
+        let me = jobContentOprObj;
+        //me.setRadiosDisabled(me.currentRationItems.length > 0 ? false : true, me.radios);
+        me.setRadiosChecked(me.currentSituation, me.radios);
+        me.buildTablePartial(me.tablePartial, me.getGroup(rationItems));
+    },
+    getUpdateArr: function (updateCodes, jobContent) {
+        let rst = [];
+        for(let i = 0, len = updateCodes.length; i < len; i++){
+            rst.push({code: updateCodes[i], jobContent: jobContent});
+        }
+        return rst;
+    },
+    bindAddConBtn: function () {
+        let me = jobContentOprObj;
+        return function () {
+            let codesObj = me.getCodesAfterS(me.addCon.children().children().children());
+            let $tbody = $('#tablePartial tbody');
+            let lastEle = $tbody[0].lastElementChild;
+            let txtare = lastEle.lastElementChild.children[0];
+            if(me.currentJobContent.trim().length > 0){//工作内容不为空才可添加编码
+                let updateArr = me.getUpdateArr(codesObj.checked, me.currentJobContent);
+                me.updateJobContent(pageOprObj.rationLibId, updateArr, function () {
+                    me.buildTablePartial(me.tablePartial, me.getGroup(me.currentRationItems));
+                    $(txtare).val('');
+                });
+            }
+            else{
+                alert("工作内容不能为空!");
+            }
+        }
+    },
+    bindUpdateConBtn: function () {
+        let me = jobContentOprObj;
+        return function () {
+            let codesObj = me.getCodesAfterS(me.updateCon.children().children().children());
+            let updateC = me.getUpdateArr(codesObj.checked, me.currentJobContent),
+                updateUnC = me.getUpdateArr(codesObj.unchecked, ''),
+                updateArr = updateC.concat(updateUnC);
+            me.updateJobContent(pageOprObj.rationLibId, updateArr, function () {
+                me.buildTablePartial(me.tablePartial, me.getGroup(me.currentRationItems));
+            });
+        }
+    },
+    //更新缓存的定额
+    updateRationItem: function (rationItems, updateArr) {
+        for(let i = 0, len = rationItems.length; i < len; i++){
+            for(let j = 0, jLen = updateArr.length; j < jLen; j++){
+                if(rationItems[i].code === updateArr[j].code){
+                    rationItems[i].jobContent = updateArr[j].jobContent;
+                    break;
+                }
+            }
+        }
+    },
+    updateJobContent: function (repId, updateArr, callback){
+        let me = jobContentOprObj;
+        $.ajax({
+            type: 'post',
+            url: 'api/updateJobContent',
+            data: {lastOpr: userAccount, repId: pageOprObj.rationLibId, updateArr: JSON.stringify(updateArr)},
+            dataType: 'json',
+            success: function (result) {
+                if(!result.error){
+                    me.updateRationItem(jobContentOprObj.currentRationItems, updateArr);
+                    callback();
+                }
+            }
+        });
+    },
+    updateSituation: function (repId, nodeId, situation, callback) {
+        let me = jobContentOprObj;
+        $.ajax({
+            type: 'post',
+            url: 'api/updateSituation',
+            data: {lastOpr: userAccount, repId: pageOprObj.rationLibId, nodeId: nodeId, situation: situation},
+            dataType: 'json',
+            success: function (result) {
+                if(!result.error){
+                    if(callback){
+                        callback();
+                    }
+                }
+            }
+        })
+    }
+};

+ 33 - 0
web/building_saas/complementary_ration_lib/js/main.js

@@ -0,0 +1,33 @@
+/**
+ * Created by Zhong on 2017/12/22.
+ */
+
+let compleRationMain = {
+    getRationLibs: function () {
+        let scFunc = function (rstData) {
+            $("#comple_ration_table").empty();
+            for(let i = 0; i < rstData.length; i++){
+                storageUtil.setSessionCache("RationGrp","repositoryID_" + rstData[i].ID, rstData[i].dispName);
+                if(rstData[i].gljLib !== undefined && rstData[i].gljLib && rstData[i].gljLib != -1){
+                    storageUtil.setSessionCache("gljLib","repositoryID_" + rstData[i].ID, rstData[i].gljLib);
+                    let id = rstData[i].ID;
+                    let libName = rstData[i].dispName;
+                    $("#comple_ration_table").append(
+                        "<tr id='tempId'>" +
+                        "<td><a href='/stdGljRepository/glj'>"+libName+"</a></td></tr>"
+                    );
+                    var newHref = "/complementaryRation/ration?repository="+id;
+                    $("#tempId td:first a").attr("href", newHref);
+                    $("#tempId").attr("id", id);
+                }
+            }
+        };
+        CommonAjax.post('/complementaryRation/api/getRationLibs', {user_id: userID}, scFunc);
+    }
+};
+
+$(document).ready(function () {
+    $('#comple-ration').on('shown.bs.modal', function () {
+        compleRationMain.getRationLibs();
+    });
+});

+ 662 - 0
web/building_saas/complementary_ration_lib/js/ration.js

@@ -0,0 +1,662 @@
+/**
+ * Created by Tony on 2017/4/28.
+ */
+
+$("#gongliao").click(function(){
+    $(this).attr('href', "/complementaryRation/glj" + "?repository=" + getQueryString("repository"))
+});
+
+$("#fuzhu").click(function(){
+    $(this).attr('href', "/complementaryRation/coe" + "?repository=" + getQueryString("repository"))
+});
+const digital = {
+    gljPrc: -3,//计算定额基价时单个工料机价格取三位
+    rationBasePrc: -2,
+    consumeAmt: -3
+};
+let rationOprObj = {
+    workBook: null,
+    currentRations: {},
+    currentEditingRation: null,
+    currentSectionId: -1,
+    rationsCodes: [],
+    type: {std: 'std', complementary: 'complementary'},
+    setting: {
+        header:[
+            {headerName:"编码",headerWidth:120,dataCode:"code", dataType: "String", formatter: "@"},
+            {headerName:"名称",headerWidth:280,dataCode:"name", dataType: "String"},
+            {headerName:"计量单位",headerWidth:120,dataCode:"unit", dataType: "String", hAlign: "center"},
+            {headerName:"人工费",headerWidth:120,dataCode:"labourPrice", dataType: "Number", formatter: "0.00", hAlign: "right"},
+            {headerName:"材料费",headerWidth:120,dataCode:"materialPrice", dataType: "Number", formatter: "0.00",  hAlign: "right"},
+            {headerName:"机械费",headerWidth:120,dataCode:"machinePrice", dataType: "Number", formatter: "0.00", hAlign: "right"},
+            {headerName:"基价",headerWidth:120,dataCode:"basePrice", dataType: "Number", formatter: "0.00", hAlign: "right"},
+            {headerName:"显示名称(以%s表示参数)",headerWidth:280,dataCode:"caption", dataType: "String"},
+            {headerName:"取费专业",headerWidth:100,dataCode:"feeType", dataType: "Number", hAlign: "center"}
+        ],
+        view:{
+            comboBox:[
+                {row:-1,col:2,rowCount:-1,colCount:1}
+            ],
+            lockedCells:[
+                {row:-1,col:3,rowCount:-1, colCount:1}
+            ],
+            lockColumns: [
+                3, 4, 5, 6
+            ]
+        }
+    },
+    buildSheet: function(container) {
+        let rationRepId = getQueryString("repository");
+        let me = rationOprObj;
+        me.workBook = sheetCommonObj.buildSheet(container, me.setting, 30);
+        me.getRationsCodes(rationRepId);
+        me.rationDelOpr();
+        me.setCombo(me.workBook.getSheet(0), 'dynamic');
+        me.workBook.getSheet(0).bind(GC.Spread.Sheets.Events.ClipboardPasting, me.onClipboardPasting);
+        me.workBook.getSheet(0).bind(GC.Spread.Sheets.Events.ClipboardPasted, me.onClipboardPasted);
+        me.workBook.getSheet(0).bind(GC.Spread.Sheets.Events.LeaveCell, me.onLeaveCell);
+        me.workBook.getSheet(0).bind(GC.Spread.Sheets.Events.EnterCell, me.onEnterCell);
+        me.workBook.getSheet(0).bind(GC.Spread.Sheets.Events.EditStarting, me.onCellEditStart);
+        me.workBook.getSheet(0).bind(GC.Spread.Sheets.Events.EditEnded, me.onCellEditEnd);
+        me.workBook.getSheet(0).bind(GC.Spread.Sheets.Events.SelectionChanged, me.onSelectionChanged);
+    },
+    setCombo: function (sheet, combo) {
+        let me = rationOprObj;
+        sheet.suspendPaint();
+        sheet.suspendEvent();
+        if(combo){
+            combo = sheetCommonObj.getDynamicCombo();
+            combo.items(rationUnits).itemHeight(10).editable(true);
+        }
+        sheet.getRange(-1, me.setting.view.comboBox[0].col, -1, 1).cellType(combo);
+        sheet.resumePaint();
+        sheet.resumeEvent();
+    },
+    onSelectionChanged: function (sender, info) {
+        if(info.oldSelections.length === 0 && info.newSelections.length > 0 || info.oldSelections[0].row !== info.newSelections[0].row){
+            let row = info.newSelections[0].row;
+            let me = rationOprObj,
+                sheetGLJ = rationGLJOprObj.sheet, settingGLJ = rationGLJOprObj.setting,
+                sheetCoe = rationCoeOprObj.sheet, settingCoe = rationCoeOprObj.setting,
+                sheetAss = rationAssistOprObj.sheet, settingAss = rationAssistOprObj.setting;
+            sheetCommonObj.cleanSheet(sheetGLJ, settingGLJ, -1);
+            sheetCommonObj.cleanSheet(sheetCoe, settingCoe, -1);
+            sheetCommonObj.cleanSheet(sheetAss, settingAss, -1);
+            let cacheSection = me.getCache();
+            if (cacheSection && row < cacheSection.length) {
+                rationGLJOprObj.getGljItems(cacheSection[row], function () {
+                    me.workBook.focus(true);
+                });
+                rationCoeOprObj.getCoeItems(cacheSection[row], function () {
+                    me.workBook.focus(true);
+                });
+                rationAssistOprObj.getAssItems(cacheSection[row]);
+            }
+            else {
+                rationGLJOprObj.currentRationItem = null;
+            }
+            me.workBook.focus(true);
+        }
+    },
+    isDef: function (v) {
+        return v !== undefined && v !== null;
+    },
+    isInt: function (num) {
+        return !isNaN(num) && num % 1 === 0;
+    },
+    getCache: function() {
+        let me = this, rst = me.currentRations["_SEC_ID_" + me.currentSectionId];
+        if (!(rst)) {
+            me.currentRations["_SEC_ID_" + me.currentSectionId] = [];
+            rst = me.currentRations["_SEC_ID_" + me.currentSectionId];
+        }
+        return rst;
+    },
+    updateCache: function(addArr, updateArr, removeIds, rstData) {
+        let me = this, cacheSection = me.getCache();
+        if (addArr.length > 0) {
+            me.currentRations["_SEC_ID_" + me.currentSectionId] = cacheSection.concat(addArr);
+            cacheSection = me.currentRations["_SEC_ID_" + me.currentSectionId];
+        }
+        for (let i = removeIds.length - 1; i >= 0; i--) {
+            for (let j = cacheSection.length - 1; j >= 0 ; j--) {
+                if (cacheSection[j]["ID"] == removeIds[i]) {
+                    cacheSection.splice(j,1);
+                }
+            }
+        }
+        if (rstData && rstData.ops && rstData.ops.length > 0) {
+            for (let i = 0; i < rstData.ops.length; i++) {
+                for (let j = 0; j < cacheSection.length; j++) {
+                    if (cacheSection[j][me.setting.header[0].dataCode] == rstData.ops[i][me.setting.header[0].dataCode]) {
+                        cacheSection[j]["ID"] = rstData.ops[i]["ID"];
+                        cacheSection[j]["rationGljList"] = rstData.ops[i]["rationGljList"];
+                        cacheSection[j]["rationCoeList"] = rstData.ops[i]["rationCoeList"];
+                        cacheSection[j]["rationAssList"] = rstData.ops[i]["rationAssList"];
+                    }
+                }
+            }
+        }
+        for (let i = 0; i < updateArr.length; i++) {
+            for (let j = 0; j < cacheSection.length; j++) {
+                if (updateArr[i]["ID"] && cacheSection[j]["ID"]) {
+                    if (cacheSection[j]["ID"] == updateArr[i]["ID"]) {
+                        cacheSection[j] = updateArr[i];
+                        cacheSection[j].type = me.type.complementary;
+                    }
+                } else {
+                    if (cacheSection[j][me.setting.header[0].dataCode] == updateArr[i][me.setting.header[0].dataCode]) {
+                        cacheSection[j] = updateArr[i];
+                        cacheSection[j].type = me.type.complementary;
+                    }
+                }
+            }
+        }
+        return cacheSection;
+    },
+    rationDelOpr: function () {
+        let me = rationOprObj;
+        me.workBook.commandManager().register('rationDelete', function () {
+            let rationSheet = me.workBook.getActiveSheet();
+            let sels = rationSheet.getSelections(), updateArr = [], removeArr = [], lockCols = me.setting.view.lockColumns;
+            let cacheSection = me.getCache();
+            if(sels.length > 0){
+                for(let sel = 0; sel < sels.length; sel++){
+                    if(sels[sel].colCount === me.setting.header.length){
+                        if(cacheSection){
+                            for(let i = 0; i < sels[sel].rowCount; i++){
+                                if(sels[sel].row + i < cacheSection.length && cacheSection[sels[sel].row + i].type !== me.type.std){
+                                    removeArr.push(cacheSection[sels[sel].row + i].ID);
+                                    me.rationsCodes.splice(me.rationsCodes.indexOf(cacheSection[sels[sel].row + i].code), 1);
+                                }
+                            }
+                        }
+                    }
+                    else{
+                        if(sels[sel].col === 0 && me.isDef(cacheSection[sels[sel].row]) && cacheSection[sels[sel].row].type !== me.type.std){
+                            $('#alertText').text("编号不能为空,修改失败!");
+                            $('#alertModalBtn').click();
+                            $('#alertModalCls').click(function () {
+                            });
+                            $('#alertModalCof').click(function () {
+                            })
+                        }
+                        else if(sels[sel].col !== 0 && !(sels[sel].col === 3 && sels.col + sels[sel].colCount -1 === 6)){
+                            if(cacheSection){
+                                for(let i = sels[sel].row === -1 ? 1 : 0; i < sels[sel].rowCount; i++){
+                                    if(sels[sel].row + i < cacheSection.length){
+                                        for(let col = sels[sel].col; col <= sels[sel].col + sels[sel].colCount - 1; col++){
+                                            if(lockCols.indexOf(col) === -1 && cacheSection[sels[sel].row + i].type !== me.type.std){
+                                                cacheSection[sels[sel].row + i][me.setting.header[col].dataCode] = '';
+                                            }
+                                        }
+                                    }
+                                    if(me.isDef(cacheSection[sels[sel].row + i]) && cacheSection[sels[sel].row + i].type !== me.type.std){
+                                        updateArr.push(cacheSection[sels[sel].row + i]);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            if(updateArr.length > 0 || removeArr.length > 0){
+                me.mixUpdate = 1;
+                me.mixDel = removeArr.length > 0 ? 1 : 0;
+                me.mixUpdateRequest(updateArr, [], removeArr);
+            }
+
+        });
+        me.workBook.commandManager().setShortcutKey(null, GC.Spread.Commands.Key.del, false, false, false, false);
+        me.workBook.commandManager().setShortcutKey('rationDelete', GC.Spread.Commands.Key.del, false, false, false, false);
+    },
+    onLeaveCell: function (sender, args) {
+        let me = rationOprObj;
+        me.lastCol = me.setting.header[args.col];
+    },
+    onEnterCell: function (sender, args) {
+        let me = rationOprObj;
+        if(me.setting.header[args.col]['dataCode'] === 'unit' || me.lastCol.dataCode === 'unit'){
+            args.sheet.repaint();
+        }
+        me.cellRowIdx = args.row;
+        let isHasData = false;
+        if(me.addRationItem){
+            for(let i=0; i<me.setting.header.length; i++){
+                if(me.addRationItem[me.setting.header[i].dataCode]){
+                    isHasData = true;
+                    break;
+                }
+            }
+        }
+        if(isHasData){
+            if(me.editingRowIdx !== me.cellRowIdx) {
+                let focusToCol = !me.addRationItem.code ? 0 : -1;
+                if(focusToCol !== -1){
+                    $('#rationAlertBtn').click();
+                    $('#rationAlertCac').click(function () {
+                        me.addRationItem = null;
+                        for(let col=0; col<me.setting.header.length; col++){
+                            me.workBook.getSheet(0).getCell(me.editingRowIdx, col).value('');
+                        }
+                    });
+                    $('#rationAlertCls').click(function () {
+                        me.workBook.getSheet(0).setActiveCell(me.editingRowIdx, focusToCol);
+                    });
+                    $('#rationAlertCof').click(function () {
+                        me.workBook.getSheet(0).setActiveCell(me.editingRowIdx, focusToCol);
+                    });
+                }
+            }
+        }
+    },
+    onCellEditStart: function(sender, args) {
+        let me = rationOprObj;
+        let cacheSection = me.getCache();
+        if(!me.canRations || me.setting.view.lockColumns.indexOf(args.col) !== -1
+        || (me.isDef(cacheSection[args.row]) && cacheSection[args.row].type === me.type.std)){
+            args.cancel = true;
+        }
+        else{
+            let rObj = sheetsOprObj.combineRationRowData(me.workBook.getSheet(0), me.setting, args.row);
+            me.currentEditingRation = rObj;
+            if (cacheSection) {
+                for (let j = 0; j < cacheSection.length; j++) {
+                    if (cacheSection[j][me.setting.header[0].dataCode] == rObj[me.setting.header[0].dataCode]) {
+                        rObj["ID"] = cacheSection[j]["ID"];
+                        break;
+                    }
+                }
+            }
+        }
+    },
+    onCellEditEnd: function(sender, args) {
+        let me = rationOprObj, rObj = sheetsOprObj.combineRationRowData(me.workBook.getSheet(0), me.setting, args.row),
+            updateArr = [], addArr = [];
+        let dataCode = me.setting.header[args.col].dataCode;
+        me.editingRowIdx = args.row;
+        if (me.currentEditingRation["ID"]) {
+            if((!args.editingText || args.editingText.toString().trim().length === 0) && args.col === 0){
+                args.sheet.setValue(args.row, args.col, me.currentEditingRation[dataCode] + '');
+            }
+            else {
+                rObj["ID"] = me.currentEditingRation["ID"];
+                if(me.currentEditingRation[dataCode] !== rObj[dataCode]){
+                    me.addRationItem = rObj;
+                    if(dataCode === 'code'){
+                        if(me.rationsCodes.indexOf(rObj.code) === -1){
+                            me.rationsCodes.splice(me.rationsCodes.indexOf(rObj.code), 1);
+                            me.rationsCodes.push(rObj.code);
+                            updateArr.push(rObj);
+                        }
+                        else{
+                            alert("编码已存在!");
+                            args.sheet.setValue(args.row, args.col, me.currentEditingRation[dataCode]);
+
+                        }
+                    }
+                    else if(dataCode === 'feeType'){//取费专业控制为整数
+                        if(me.isInt(rObj[dataCode])){
+                            updateArr.push(rObj);
+                        }
+                        else {
+                            rObj[dataCode] = '';
+                            args.sheet.setValue(args.row, args.col, typeof me.currentEditingRation[dataCode] !== 'undefined' && me.currentEditingRation[dataCode] ? me.currentEditingRation[dataCode] : '');
+                        }
+                    }
+                    else{
+                        updateArr.push(rObj);
+                    }
+                }
+            }
+        }
+        else if(!me.currentEditingRation["ID"]) {
+            if (!sheetCommonObj.chkIfEmpty(rObj, me.setting)) {
+                //addArr.push(rObj);
+                me.addRationItem = rObj;
+                if(rObj.code && rObj.code.toString().trim().length > 0){
+                    if(me.rationsCodes.indexOf(rObj.code) === -1){
+                        //jobContent
+                        if(jobContentOprObj && jobContentOprObj.currentSituation === jobContentOprObj.situations.ALL){
+                            rObj.jobContent = jobContentOprObj.currentJobContent ? jobContentOprObj.currentJobContent : '';
+                        }
+                        if(annotationOprObj && annotationOprObj.currentSituation === annotationOprObj.situations.ALL){
+                            rObj.annotation = annotationOprObj.currentAnnotation ? annotationOprObj.currentAnnotation : '';
+                        }
+                        me.setInitPrc(rObj);
+                        addArr.push(rObj);
+                        me.rationsCodes.push(rObj.code);
+                        me.addRationItem = null;
+                    }
+                    else{
+                        alert('编码已存在!');
+                        me.workBook.getSheet(0).setValue(args.row, args.col, '');
+                    }
+                }
+                else if(rObj.code && rObj.code.toString.trim().length === 0){
+                    me.workBook.getSheet(0).setValue(args.row, args.col, '');
+                }
+            }
+        }
+        if (updateArr.length > 0 || addArr.length > 0) {
+            me.currentEditingRation = null;
+            me.mixUpdate = 1;
+            me.mixUpdateRequest(updateArr, addArr, []);
+        }
+    },
+    canPasted: function (beginCol, maxCol) {
+        let rst = false;
+        if(maxCol < 3 || beginCol > 6){
+            rst = true;
+        }
+        return rst;
+    },
+    onClipboardPasting: function(sender, args) {
+        let me = rationOprObj;
+        let cacheSection = me.getCache();
+        let maxCol = args.cellRange.col + args.cellRange.colCount -1;
+        if(!me.canRations || !me.canPasted(args.cellRange.col, maxCol) || maxCol > me.setting.header.length - 1){
+            args.cancel = true;
+            return;
+        }
+        let hasStd = false;
+        for(let row = args.cellRange.row, len = args.cellRange.row + args.cellRange.rowCount - 1; row < len; row++){
+            if(me.isDef(cacheSection[row]) && me.isDef(cacheSection[row].type) && cacheSection[row].type === me.type.std){
+                hasStd = true;
+            }
+        }
+        if(hasStd){
+            args.cancel = true;
+        }
+    },
+    onClipboardPasted: function(e, info) {
+        let me = rationOprObj;
+        let cacheSection = me.getCache();
+        let updateArr = [], addArr = [];
+        let items = sheetCommonObj.analyzePasteData(me.setting, info);
+        for (let i = 0; i < items.length; i++) {
+            let rowIdx = info.cellRange.row + i;
+            if (cacheSection) {
+                if(!me.isValidUnit(items[i], rationUnits)){//无效单位
+                    items[i].unit = rowIdx < cacheSection.length  && typeof cacheSection[rowIdx].unit !== 'undefined' ? cacheSection[rowIdx].unit : '';
+                }
+                if(!cacheSection[rowIdx] && info.cellRange.col === 0 ){
+                    if(me.rationsCodes.indexOf(items[i].code) === -1){
+                        //jobConten
+                        if(jobContentOprObj && jobContentOprObj.currentSituation === jobContentOprObj.situations.ALL){
+                            items[i].jobContent = jobContentOprObj.currentJobContent ? jobContentOprObj.currentJobContent : '';
+                        }
+                        if(annotationOprObj && annotationOprObj.currentSituation === annotationOprObj.situations.ALL){
+                            items[i].annotation = annotationOprObj.currentAnnotation ? annotationOprObj.currentAnnotation : '';
+                        }
+                        me.setInitPrc(items[i]);
+                        addArr.push(items[i]);
+                        me.rationsCodes.push(items[i].code);
+                    }
+                    else{
+                        me.workBook.getSheet(0).setValue(rowIdx, 0, '');
+                    }
+                }
+                else if(cacheSection[rowIdx]){
+                    for(let col = 0; col < me.setting.header.length; col++){
+                        if(!items[i][me.setting.header[col].dataCode] && typeof cacheSection[rowIdx][me.setting.header[col].dataCode] !== 'undefined'){
+                            items[i][me.setting.header[col].dataCode] = cacheSection[rowIdx][me.setting.header[col].dataCode];
+                        }
+                    }
+                    if(items[i].feeType && !me.isInt(items[i].feeType)){
+                        items[i].feeType = '';
+                        me.workBook.getSheet(0).setValue(rowIdx, 8, '');
+                    }
+                    if(info.cellRange.col === 0){
+                        if(me.rationsCodes.indexOf(items[i].code) === -1){
+                            items[i].ID = cacheSection[rowIdx].ID;
+                            updateArr.push(items[i]);
+                        }
+                        else{
+                            me.workBook.getSheet(0).setValue(rowIdx, 0, cacheSection[rowIdx].code);
+                        }
+                    }
+                    else{
+                        items[i].ID = cacheSection[rowIdx].ID;
+                        updateArr.push(items[i]);
+                    }
+                }
+
+            } else {
+                if(!me.isValidUnit(items[i], rationUnits)){//无效单位
+                    items[i].unit = '';
+                }
+                //add
+                if(info.cellRange.col === 0){
+                    //是否含有已存在的编号
+                        if(me.rationsCodes.indexOf(items[i].code) === -1){
+                            //jobConten
+                            if(jobContentOprObj && jobContentOprObj.currentSituation === jobContentOprObj.situations.ALL){
+                                items[i].jobContent = jobContentOprObj.currentJobContent ? jobContentOprObj.currentJobContent : '';
+                            }
+                            if(annotationOprObj && annotationOprObj.currentSituation === annotationOprObj.situations.ALL){
+                                items[i].annotation = annotationOprObj.currentAnnotation ? annotationOprObj.currentAnnotation : '';
+                            }
+                            me.setInitPrc(items[i]);
+                            addArr.push(items[i]);
+                        }
+                }
+            }
+        };
+         if (updateArr.length > 0 || addArr.length > 0) {
+             me.mixUpdate = 1;
+            me.mixUpdateRequest(updateArr, addArr, []);
+        }
+        else{
+             me.getRationItems(me.currentSectionId);
+         }
+    },
+    setInitPrc: function (obj) {
+        obj.labourPrice = 0;
+        obj.materialPrice = 0;
+        obj.machinePrice = 0;
+        obj.basePrice = 0;
+    },
+    isValidUnit: function (rationObj, validUnits) {
+        let rst = true;
+        if(typeof rationObj.unit !== 'undefined' && rationObj.unit && validUnits.indexOf(rationObj.unit) === -1){//无效
+            rst = false;
+        }
+        return rst;
+    },
+    getRationsCodes: function (repId) {
+        let me = rationOprObj;
+        CommonAjax.post('api/getRationsCodes', {rationRepId: repId}, function (rstData) {
+            me.rationsCodes = rstData;
+        });
+    },
+    mixUpdateRequest: function(updateArr, addArr, removeIds, callback) {
+        let me = rationOprObj;
+        me.saveInString(updateArr);
+        CommonAjax.post('api/mixUpdateRationItems',
+            {rationRepId: getQueryString("repository"),  sectionId: me.currentSectionId, updateItems: updateArr, addItems: addArr, removeIds: removeIds},
+            function (rstData) {
+                //mark complementary
+                for(let i = 0, len = addArr.length; i < len; i++){
+                    addArr[i].type = me.type.complementary;
+                }
+                let cacheSection = me.updateCache(addArr, updateArr, removeIds, rstData);
+                cacheSection.sort(function(a, b){
+                    let rst = 0;
+                    if (a.code > b.code) rst = 1
+                    else if (a.code < b.code) rst = -1;
+                    return rst;
+                });
+                //jobContent
+                if(jobContentOprObj ){
+                    jobContentOprObj.currentRationItems = cacheSection;
+                    jobContentOprObj.setRadiosDisabled(cacheSection.length > 0 ? false : true, jobContentOprObj.radios);
+                    if(cacheSection.length === 0){
+                        jobContentOprObj.updateSituation(pageOprObj.rationLibId, me.currentSectionId, 'NONE');
+                    }
+                    jobContentOprObj.setRadiosChecked(jobContentOprObj.currentSituation, jobContentOprObj.radios);
+                    if(jobContentOprObj.currentSituation === jobContentOprObj.situations.PARTIAL){
+                        jobContentOprObj.buildTablePartial(jobContentOprObj.tablePartial, jobContentOprObj.getGroup(cacheSection));
+                    }
+                }
+                if(annotationOprObj ){
+                    annotationOprObj.setRadiosDisabled(cacheSection.length > 0 ? false : true, annotationOprObj.radios);
+                    if(cacheSection.length === 0){
+                        annotationOprObj.updateAnnoSituation(pageOprObj.rationLibId, me.currentSectionId, 'NONE');
+                    }
+                    annotationOprObj.setRadiosChecked(annotationOprObj.currentSituation, annotationOprObj.radios);
+                    if(annotationOprObj.currentSituation === annotationOprObj.situations.PARTIAL){
+                        annotationOprObj.buildTablePartial(annotationOprObj.fzTablePartial, annotationOprObj.getGroup(cacheSection));
+                    }
+                }
+                me.showRationItems(me.currentSectionId);
+                me.mixUpdate = 0;
+                me.mixDel = 0;
+                if(callback) callback();
+            }, function () {
+                me.getRationItems(me.currentSectionId);
+            });
+    },
+    getRationItems: function(sectionID){
+        if (sectionID != -1) {
+            let me = rationOprObj;
+            me.mixUpdate = 0;
+            me.currentSectionId = sectionID;
+            if (me.currentRations["_SEC_ID_" + sectionID]) {
+                //jobContent--
+                jobContentOprObj.currentRationItems = me.currentRations["_SEC_ID_" + sectionID];
+                jobContentOprObj.rationJobContentOpr(me.currentRations["_SEC_ID_" + sectionID]);
+                //annotation
+                annotationOprObj.rationAnnotationOpr(me.currentRations["_SEC_ID_" + sectionID]);
+                me.showRationItems(sectionID);
+            } else {
+                CommonAjax.post('/complementaryRation/api/getRationItems', {rationRepId: pageOprObj.rationLibId, sectionId: sectionID}, function (rstData) {
+                    me.currentRations["_SEC_ID_" + sectionID] = rstData;
+                    me.currentRations["_SEC_ID_" + sectionID] = me.sortByCode(me.currentRations["_SEC_ID_" + sectionID]);
+                    //job--
+                    jobContentOprObj.currentRationItems = me.currentRations["_SEC_ID_" + sectionID];
+                    jobContentOprObj.rationJobContentOpr(me.currentRations["_SEC_ID_" + sectionID]);
+                    //annotation
+                    annotationOprObj.rationAnnotationOpr(me.currentRations["_SEC_ID_" + sectionID]);
+                    me.showRationItems(sectionID);
+                });
+            }
+        }
+    },
+    setColor: function (cache) {
+        let me = this;
+        let sheet = me.workBook.getSheet(0);
+        sheet.suspendPaint();
+        for(let i = 0, len = cache.length; i < len; i++){
+            if(cache[i].type === me.type.complementary){
+                sheet.getRange(i, -1, 1, -1).foreColor('gray');
+            }
+            else {
+                sheet.getRange(i, -1, 1, -1).foreColor('');
+            }
+        }
+        sheet.resumePaint();
+    },
+    showRationItems: function(sectionID){
+        let me = rationOprObj,
+            sheetGLJ = rationGLJOprObj.sheet, settingGLJ = rationGLJOprObj.setting,
+            sheetCoe = rationCoeOprObj.sheet, settingCoe = rationCoeOprObj.setting,
+            sheetAss = rationAssistOprObj.sheet, settingAss = rationAssistOprObj.setting;
+        if (me.workBook) {
+            if (me.currentRations && me.currentRations["_SEC_ID_" + sectionID] && me.currentRations["_SEC_ID_" + sectionID].length > 0) {
+                let cacheSection = me.currentRations["_SEC_ID_" + sectionID];
+                sheetCommonObj.cleanData(me.workBook.getSheet(0), me.setting, -1);
+                sheetsOprObj.showData(me.workBook.getSheet(0), me.setting, cacheSection);
+                console.log(cacheSection);
+                me.setColor(cacheSection);
+                //combo
+                //sheetCommonObj.setStaticCombo(me.workBook.getActiveSheet(), 0, 2, cacheSection.length, rationUnits, 10, false);
+                //--sheetCommonObj.setDynamicCombo(me.workBook.getActiveSheet(), 0, 2, me.workBook.getActiveSheet().getRowCount(), rationUnits, 10, false);
+                if(me.mixDel === 1){
+                    let row = me.workBook.getSheet(0).getSelections()[0].row;
+                    if (cacheSection && row < cacheSection.length) {
+                        sheetCommonObj.cleanData(sheetGLJ, settingGLJ, -1);
+                        sheetCommonObj.cleanData(sheetCoe, settingCoe, -1);
+                        sheetCommonObj.cleanData(sheetAss, settingAss, -1);
+                        rationGLJOprObj.getGljItems(cacheSection[row]);
+                        rationCoeOprObj.getCoeItems(cacheSection[row]);
+                        rationAssistOprObj.getAssItems(cacheSection[row]);
+                    }
+                    else {
+                        rationGLJOprObj.currentRationItem = null;
+                        sheetCommonObj.cleanData(sheetGLJ, settingGLJ, -1);
+                        sheetCommonObj.cleanData(sheetCoe, settingCoe, -1);
+                        sheetCommonObj.cleanData(sheetAss, settingAss, -1);
+                        sheetCommonObj.setDynamicCombo(sheetAss, 0, 5, sheetAss.getRowCount(), rationAssistOprObj.setting.comboItems, false, false);
+                    }
+                }
+
+            } else {
+                sheetCommonObj.setDynamicCombo(sheetAss, 0, 5, sheetAss.getRowCount(), rationAssistOprObj.setting.comboItems, false, false);
+                //--sheetCommonObj.setDynamicCombo(me.workBook.getActiveSheet(), 0, 2, me.workBook.getActiveSheet().getRowCount(), rationUnits, 10, false);
+                //清除ration数据及工料机数据
+                rationGLJOprObj.currentRationItem = null;
+                sheetCommonObj.cleanSheet(me.workBook.getSheet(0), me.setting, -1);
+                sheetCommonObj.cleanSheet(sheetGLJ, settingGLJ, -1);
+                sheetCommonObj.cleanSheet(sheetCoe, settingCoe, -1);
+                sheetCommonObj.cleanSheet(sheetAss, settingAss, -1);
+            }
+           //--- me.workBook.focus(true);
+        }
+        sectionTreeObj.workBook.focus(true);
+    },
+    sortByCode: function(arr){
+        let me = rationOprObj;
+        //std complementary
+        let stdArr = [], compleArr = [];
+        for(let i = 0, len = arr.length; i < len; i++){
+            if(arr[i].type === me.type.std){
+                stdArr.push(arr[i]);
+            }
+            else if(arr[i].type === me.type.complementary){
+                compleArr.push(arr[i]);
+            }
+        }
+        stdArr.sort(compare());
+        compleArr.sort(compare());
+        return stdArr.concat(compleArr);
+        function compare(){
+            return function (a, b) {
+                let rst = 0;
+                if (a.code > b.code) {
+                    rst = 1;
+                }
+                else if (a.code < b.code) {
+                    rst = -1;
+                }
+                return rst;
+            }
+        }
+       // arr.sort(compare());
+    },
+    saveInString(datas){
+        for(let i = 0, len = datas.length; i < len; i++){
+            let data = datas[i];
+            if(data.labourPrice !== undefined && data.labourPrice){
+                data.labourPrice = data.labourPrice.toString();
+            }
+            if(data.materialPrice !== undefined && data.materialPrice){
+                data.materialPrice = data.materialPrice.toString();
+            }
+            if(data.machinePrice !== undefined && data.machinePrice){
+                data.machinePrice = data.machinePrice.toString();
+            }
+            if(data.basePrice !== undefined && data.basePrice){
+                data.basePrice = data.basePrice.toString();
+            }
+            if(data.rationGljList !== undefined && data.rationGljList && data.rationGljList.length > 0){
+                for(let j = 0, jLen = data.rationGljList.length; j < jLen; j++){
+                    let raGljObj = data.rationGljList[j];
+                    if(raGljObj.consumeAmt !== undefined && raGljObj.consumeAmt){
+                        raGljObj.consumeAmt = raGljObj.consumeAmt.toString();
+                    }
+                }
+            }
+        }
+    }
+}

+ 49 - 0
web/building_saas/complementary_ration_lib/js/rationUnits.js

@@ -0,0 +1,49 @@
+/**
+ * Created by Zhong on 2017/9/8.
+ * 定额列表单位下拉表
+ */
+let rationUnits =[
+    'm',
+    'km',
+    'm2',
+    'm3',
+    'kg',
+    't',
+    '10m',
+    '10m2',
+    '10m3',
+    '100m',
+    '100m2',
+    '100m3',
+    '1000m2',
+    '1000m3',
+    'à·km',
+    '总额',
+    '月',
+    '项',
+    '处',
+    '个',
+    '根',
+    '棵',
+    '块',
+    '每一试桩',
+    '桥长米',
+    '公路公里',
+    '株',
+    '组',
+    '座',
+    '元',
+    '工日',
+    '套',
+    '台班',
+    '艘班',
+    'm/处',
+    'm/道',
+    'm/座',
+    'm2/m',
+    'm3/m',
+    'm3/处',
+    '根/米',
+    '亩',
+    'm3/m2'
+];

+ 198 - 0
web/building_saas/complementary_ration_lib/js/ration_assist.js

@@ -0,0 +1,198 @@
+/**
+ * Created by CSL on 2017-06-14.
+ */
+var rationAssistOprObj = {
+    sheet: null,
+    libID: null,
+    ration: null,
+    setting: {
+        header:[
+            {headerName:"调整名称",headerWidth:200,dataCode:"name", dataType: "String", hAlign: "left"},
+            {headerName:"辅助定额号",headerWidth:120,dataCode:"assistCode", dataType: "String", hAlign: "center"},
+            {headerName:"标准值",headerWidth:100,dataCode:"stdValue", dataType: "String", hAlign: "right"},
+            {headerName:"步距",headerWidth:100,dataCode:"stepValue", dataType: "String", hAlign: "right"},
+            {headerName:"精度",headerWidth:80,dataCode:"decimal",  dataType: "String", hAlign: "right"},
+            {headerName:"进位方式",headerWidth:100,dataCode:"carryBit", dataType: "String", hAlign: "center"},
+            {headerName:"最小值",headerWidth:100,dataCode:"minValue", dataType: "String", hAlign: "right"},
+            {headerName:"最大值",headerWidth:100,dataCode:"maxValue", dataType: "String", hAlign: "right"}
+        ],
+        view:{},
+        comboItems: ["四舍五入", "进一"]
+    },
+
+    buildSheet: function(sheet) {
+        var me = this;
+        me.sheet = sheet;
+        //me.libID = storageUtil.getSessionCache("RationGrp","repositoryID"); // 不可靠,有时取不到
+        me.libID = pageOprObj.rationLibId;
+        if (me.libID == undefined){me.libID = getQueryString('repository')};
+
+        sheetCommonObj.initSheet(me.sheet, me.setting, 30);
+
+        me.sheet.bind(GC.Spread.Sheets.Events.ClipboardPasting, me.onClipboardPasting);
+        me.sheet.bind(GC.Spread.Sheets.Events.ClipboardPasted, me.onClipboardPasted);
+        me.sheet.bind(GC.Spread.Sheets.Events.EditStarting, me.onEditStarting);
+        me.sheet.bind(GC.Spread.Sheets.Events.EditEnded, me.onEditEnded);
+        me.sheet.bind(GC.Spread.Sheets.Events.EnterCell, me.onEnterCell);
+    },
+
+    onEnterCell: function (sender, args) {
+        let me = rationAssistOprObj;
+        args.sheet.repaint();
+        let cellType = args.sheet.getCellType(args.row, 5);
+        if(cellType.typeName !== 'undefined' && cellType.typeName === '1'){
+          //  sheetCommonObj.setStaticCombo(args.sheet, 0, 5, 0, me.setting.comboItems, false);
+            sheetCommonObj.setDynamicCombo(args.sheet, 0, 5, me.sheet.getRowCount(), me.setting.comboItems, false, false);
+        }
+    },
+
+    onClipboardPasting: function(sender, args) {
+        let me = rationAssistOprObj;
+        let rationSection = rationOprObj.getCache();
+        let rationRow = rationOprObj.workBook.getSheet(0).getSelections()[0].row;
+        me.ration = rationRow < rationSection.length ? rationSection[rationRow] : null;
+        if (!me.ration || (me.ration && me.ration.type === rationOprObj.type.std)) {
+            args.cancel = true;
+        }
+    },
+
+    onClipboardPasted: function(e, info) {
+        var me = rationAssistOprObj;
+        if (!me.ration) {return;};
+        var tempArr = sheetCommonObj.analyzePasteData(me.setting, info);
+        var assList = me.ration.rationAssList;
+        if (assList == undefined) {
+            me.ration.rationAssList = tempArr;
+        }else{
+            assList = assList.concat(tempArr);
+            me.ration.rationAssList = assList;
+        };
+
+        rationOprObj.mixUpdateRequest([me.ration], [], [], function () {
+            me.sheet.getParent().focus(true);
+        });
+        sheetCommonObj.cleanData(me.sheet, me.setting, -1);
+        //sheetCommonObj.setStaticCombo(me.sheet, 0, 5, me.ration.rationAssList.length, me.setting.comboItems, false, false);
+        sheetCommonObj.setDynamicCombo(me.sheet, 0, 5, me.sheet.getRowCount(), me.setting.comboItems, false, false);
+        sheetCommonObj.showData(me.sheet, me.setting, me.ration.rationAssList);
+    },
+
+    onEditStarting: function (sender, args) {
+        let me = rationAssistOprObj;
+        let rationSection = rationOprObj.getCache();
+        let rationRow = rationOprObj.workBook.getSheet(0).getSelections()[0].row;
+        me.ration = rationRow < rationSection.length ? rationSection[rationRow] : null;
+        if(!me.ration || (me.ration && me.ration.type === rationOprObj.type.std)){
+            args.cancel = true;
+        }
+    },
+
+    onEditEnded: function(sender, args){
+        var me = rationAssistOprObj;
+        if (!me.ration) {return;};
+        if(typeof me.ration.rationAssList === 'undefined'){
+            me.ration.rationAssList = [];
+        }
+        var assList = me.ration.rationAssList;
+        var assObj = sheetsOprObj.combineRationRowData(me.sheet, me.setting, args.row);
+        let dataCode = me.setting.header[args.col].dataCode;
+        if((args.col === 2 || args.col === 3 || args.col === 6 || args.col === 7)
+            && args.editingText && args.editingText.toString().trim().length > 0 && isNaN(args.editingText)){
+            args.sheet.setValue(args.row, args.col, args.row < assList.length ? assList[args.row][dataCode] : '');
+            alert(me.setting.header[args.col].headerName + '只能为数值!');
+            return;
+        }
+        else if(args.col === 4 && args.editingText && (args.editingText.toString().trim().length === 0 ||
+                isNaN(args.editingText) || args.editingText % 1 !== 0)){
+            args.sheet.setValue(args.row, args.col, args.row < assList.length ? assList[args.row][dataCode] : 0);
+            alert(me.setting.header[args.col].headerName + '只能为整数!');
+            return;
+        }
+        // 新增
+        if (args.row >= assList.length) {
+            if (assObj.decimal == undefined || assObj.decimal == null){assObj.decimal = '0';};
+            if (assObj.carryBit == undefined || assObj.carryBit == null){assObj.carryBit = '四舍五入';};
+            assList.push(assObj);
+        }
+        // 修改
+        else{ assList[args.row] = assObj; };
+        rationOprObj.mixUpdateRequest([me.ration], [], [], function () {
+            me.sheet.getParent().focus(true);
+        });
+        sheetCommonObj.cleanData(me.sheet, me.setting, -1);
+        //sheetCommonObj.setStaticCombo(me.sheet, 0, 5, assList.length, me.setting.comboItems, false, false);
+        sheetCommonObj.setDynamicCombo(me.sheet, 0, 5, me.sheet.getRowCount(), me.setting.comboItems, false, false);
+        sheetCommonObj.showData(me.sheet, me.setting, assList);
+    },
+
+    onRangeChanged: function(sender, args) {
+        if (args.action == GC.Spread.Sheets.RangeChangedAction.clear) {
+            if (!confirm(`确定要删除选中的 ${args.rowCount} 条辅助定额吗?`)){return; }
+
+            var me = rationAssistOprObj;
+            if (!me.ration) {return;};
+            var assList = me.ration.rationAssList;
+            for (var i = args.rowCount - 1; i >= 0; i--) {
+                if (args.row + i < assList.length) {
+                    assList.splice(args.row + i, 1);
+                };
+            };
+
+            rationOprObj.mixUpdateRequest([me.ration], [], []);
+            sheetCommonObj.cleanSheet(me.sheet, me.setting, -1);
+            sheetCommonObj.showData(me.sheet, me.setting, assList);
+        };
+    },
+    bindRationAssDel: function () {
+        let me = rationAssistOprObj;
+        let workBook = me.sheet.getParent();
+        workBook.commandManager().register('rationAssDel', function () {
+            if(!me.ration || me.ration.type === rationOprObj.type.std){
+                return;
+            }
+            let sels = me.sheet.getSelections(), isUpdate = false;
+            if(me.ration){
+                let curCahe = me.ration.rationAssList;
+                for(let i = 0, len = sels.length; i < len; i ++ ){
+                    if(sels[i].colCount === me.setting.header.length){
+                        if(sels[i].row < curCahe.length){
+                            isUpdate = true;
+                            curCahe.splice(sels[i].row, sels[i].rowCount);
+                        }
+                    }
+                }
+                if(isUpdate){
+                    rationOprObj.mixUpdateRequest([me.ration], [], [], function () {
+                        workBook.focus(true);
+                    });
+                    sheetCommonObj.cleanData(me.sheet, me.setting, -1);
+                    //sheetCommonObj.setStaticCombo(me.sheet, 0, 5, curCahe.length, me.setting.comboItems, false);
+                    sheetCommonObj.setDynamicCombo(me.sheet, 0, 5, me.sheet.getRowCount(), me.setting.comboItems, false);
+                    sheetCommonObj.showData(me.sheet, me.setting, curCahe);
+                }
+            }
+        });
+        workBook.commandManager().setShortcutKey(null, GC.Spread.Commands.Key.del, false, false, false, false);
+        workBook.commandManager().setShortcutKey('rationAssDel', GC.Spread.Commands.Key.del, false, false, false, false);
+    },
+
+    getAssItems: function(ration) {
+        var me = this;
+        me.ration = ration;
+
+        sheetCommonObj.cleanSheet(me.sheet, me.setting, -1);
+        sheetCommonObj.unShieldAllCells(me.sheet);
+
+        if (ration == undefined || ration.rationAssList == undefined ||
+            ration.rationAssList.length == 0){
+            //sheetCommonObj.setStaticCombo(me.sheet, 0, 5, 0, me.setting.comboItems, false);
+            sheetCommonObj.setDynamicCombo(me.sheet, 0, 5, me.sheet.getRowCount(), me.setting.comboItems, false, false);
+            return;
+        }
+        else {
+            //sheetCommonObj.setStaticCombo(me.sheet, 0, 5, ration.rationAssList.length, me.setting.comboItems, false);
+            sheetCommonObj.setDynamicCombo(me.sheet, 0, 5, me.sheet.getRowCount(), me.setting.comboItems, false, false);
+        }
+        sheetCommonObj.showData(me.sheet, me.setting, ration.rationAssList);
+    }
+}

+ 300 - 0
web/building_saas/complementary_ration_lib/js/ration_coe.js

@@ -0,0 +1,300 @@
+/**
+ * Created by CSL on 2017-06-08.
+ */
+ //modified by zhong on 2017-09-25
+var rationCoeOprObj = {
+    sheet: null,
+    libID: null,
+    curRation: null,
+    tempDelArr: [],
+    cache: {},
+    setting: {
+        header:[
+            {headerName:"编号",headerWidth:120,dataCode:"serialNo", dataType: "Number", hAlign: 'left'},
+            {headerName:"名称",headerWidth:400,dataCode:"name", dataType: "String", hAlign: 'left'},
+            {headerName:"内容",headerWidth:300,dataCode:"content", dataType: "String", hAlign: 'left'}
+        ],
+        view:{
+            comboBox:[],
+            lockColumns:[1,2]
+        }
+    },
+
+    buildSheet: function(sheet) {
+        var me = this;
+        me.sheet = sheet;
+        //me.libID = storageUtil.getSessionCache("RationGrp","repositoryID"); // 不可靠,有时取不到
+        me.libID = pageOprObj.rationLibId;
+        if (me.libID == undefined){me.libID = getQueryString('repository')};
+        sheetCommonObj.initSheet(me.sheet, me.setting, 30);
+        me.sheet.bind(GC.Spread.Sheets.Events.ClipboardPasting, me.onClipboardPasting);
+        me.sheet.bind(GC.Spread.Sheets.Events.ClipboardPasted, me.onClipboardPasted);
+        me.sheet.bind(GC.Spread.Sheets.Events.EditStarting, me.onEditStarting);
+        me.sheet.bind(GC.Spread.Sheets.Events.EditEnded, me.onEditEnded);
+       // me.sheet.bind(GC.Spread.Sheets.Events.RangeChanged, me.onRangeChanged);
+    },
+
+    onClipboardPasting: function(sender, args) {
+        var me = rationCoeOprObj;
+        let rationSection = rationOprObj.getCache();
+        let rationRow = rationOprObj.workBook.getSheet(0).getSelections()[0].row;
+        me.curRation = rationRow < rationSection.length ? rationSection[rationRow] : null;
+        if (args.cellRange.colCount != 1 || args.cellRange.col != 0 || !(me.curRation) || (me.curRation && me.curRation.type === rationOprObj.type.std)) {
+            args.cancel = true;
+        }
+    },
+
+    onClipboardPasted: function(e, info) {
+        var me = rationCoeOprObj;
+        if (me.libID) {
+            // 修改第一列(编号)
+            if (info.cellRange.col == 0) {
+                me.tempDelArr = [];
+                var coeNos = [];
+                var items = sheetCommonObj.analyzePasteData({header:[{dataCode: "serialNo"}] }, info);
+                let curCache = typeof me.cache["_Coe_" + me.curRation.ID] !== 'undefined' ? me.cache["_Coe_" + me.curRation.ID] : [];
+                let isRefresh = false;
+                for(let i = 0, len = items.length; i < len; i++){
+                    if(!isNaN(items[i].serialNo)){
+                        let row = i + info.cellRange.row;
+                        //update
+                        if(row < curCache.length){
+                            let isExist = false;
+                            for(let j = 0, jLen = curCache.length; j < jLen; j++){
+                                if(items[i].serialNo === curCache[j].serialNo && j !== row){
+                                    isExist = true;
+                                    break;
+                                }
+                            }
+                            if(!isExist){
+                                me.tempDelArr.push({org: curCache[row], newNo: items[i].serialNo});
+                                coeNos.push(items[i].serialNo);
+                            }
+                            else{
+                                isRefresh = true;
+                            }
+                        }
+                        else{
+                            coeNos.push(items[i].serialNo);
+                        }
+                    }
+                }
+                //delete in front
+                if(me.tempDelArr.length > 0){
+                   for(let i = 0, len = me.tempDelArr.length; i < len; i++){
+                       for(let j = 0; j < curCache.length; j++){
+                           if(me.tempDelArr[i].org.serialNo === curCache[j].serialNo){
+                               curCache.splice(j, 1);
+                               break;
+                           }
+                       }
+                   }
+                }
+                me.addCoeItems(coeNos);
+                if(isRefresh){
+                    me.showCoeItems(me.curRation.ID);
+                }
+            } else {
+                //修改其它列。
+            }
+        }
+    },
+    onEditStarting: function (sender, args) {
+        let me = rationCoeOprObj;
+        let rationSection = rationOprObj.getCache();
+        let rationRow = rationOprObj.workBook.getSheet(0).getSelections()[0].row;
+        me.curRation = rationRow < rationSection.length ? rationSection[rationRow] : null;
+        if(!me.curRation || args.col !== 0 || (me.curRation && me.curRation.type === rationOprObj.type.std)){
+            args.cancel = true;
+        }
+
+    },
+    onEditEnded: function(sender, args){
+        var me = rationCoeOprObj;
+        if (args.col == 0 && args.editingText && args.editingText.toString().trim().length > 0 && !isNaN(args.editingText)) {   // 编号列
+            let curCahe = typeof me.cache["_Coe_" + me.curRation.ID] !== 'undefined' ? me.cache["_Coe_" + me.curRation.ID] : [];
+            me.tempDelArr = [];
+            //update
+            if(args.row < curCahe.length && args.editingText != curCahe[args.row].serialNo){
+                let isExist = false;
+                for(let i = 0, len = curCahe.length; i < len; i++){
+                    if(args.editingText == curCahe[i].serialNo){
+                        isExist = true;
+                        break;
+                    }
+                }
+                if(!isExist){
+                    me.tempDelArr.push({org: curCahe[args.row], newNo: args.editingText});
+                    curCahe.splice(args.row, 1);
+                    me.addCoeItems([args.editingText]);
+                }
+                else{
+                    me.showCoeItems(me.curRation.ID);
+                }
+            }
+            //insert
+            else{
+                me.addCoeItems([args.editingText]);
+            }
+        }
+        else{
+            sheetCommonObj.cleanData(me.sheet, me.setting, -1);
+            me.showCoeItems(me.curRation.ID);
+        }
+    },
+
+    bindRationCoeDel: function () {
+        let me = rationCoeOprObj;
+        let workBook = me.sheet.getParent();
+        workBook.commandManager().register('rationCoeDel', function () {
+            if(!me.curRation || me.curRation.type === rationOprObj.type.std){
+                return;
+            }
+            let sels = me.sheet.getSelections(), isUpdate = false;
+            let curCahe = me.cache["_Coe_" + me.curRation.ID];
+            for(let i = 0, len = sels.length; i < len; i ++ ){
+                if(sels[i].colCount === me.setting.header.length){
+                    if(sels[i].row < curCahe.length){
+                        isUpdate = true;
+                        curCahe.splice(sels[i].row, sels[i].rowCount);
+                    }
+                }
+            }
+            if(isUpdate){
+                me.updateCurRation(function () {
+                    me.sheet.getParent().focus(true);
+                });
+                sheetCommonObj.cleanData(me.sheet, me.setting, -1);
+                me.showCoeItems(me.curRation.ID);
+            }
+        });
+        workBook.commandManager().setShortcutKey(null, GC.Spread.Commands.Key.del, false, false, false, false);
+        workBook.commandManager().setShortcutKey('rationCoeDel', GC.Spread.Commands.Key.del, false, false, false, false);
+    },
+    getRecoveryArr: function (tempDelArr, newArr) {//获得更新的coe不存在,恢复删除的被更新数据
+        let rst = [];
+        for(let i = 0, len = tempDelArr.length; i < len; i++){
+            let isExist = false;
+            for(let j = 0, jLen = newArr.length; j < jLen; j++){
+                if(tempDelArr[i].newNo == newArr[j].serialNo){
+                    isExist = true;
+                    break;
+                }
+            }
+            if(!isExist){
+                rst.push(tempDelArr[i].org);
+            }
+        }
+        return rst;
+    },
+    addCoeItems: function(coeNos) {
+        var me = this;
+        sheetCommonObj.cleanData(me.sheet, me.setting, -1);
+
+        var curCache = me.cache["_Coe_" + me.curRation.ID];
+        var temp = [];
+        if (curCache) {
+            for (var i = 0; i < coeNos.length; i++) {
+                var isExist = false;
+                for (let obj of curCache) {
+                    if (obj.serialNo == coeNos[i]) {
+                        isExist = true;
+                        break;
+                    };
+                };
+                if (!isExist) {
+                    temp.push(coeNos[i]);
+                };
+            };
+        }else{
+            for (let obj of coeNos){temp.push(obj)};
+        };
+
+        if(temp.length == 0){
+            me.showCoeItems(me.curRation.ID);
+            //sheetCommonObj.lockCells(me.sheet, me.setting);
+        }else{
+            CommonAjax.post('api/getCoeItemsByNos', {libID: me.libID, coeNos: temp}, function (rstData) {
+                var rstArr = [];
+                for (let obj of rstData){rstArr.push(obj)};
+                if (curCache) {
+                    curCache = curCache.concat(rstArr);
+                }else{
+                    curCache = rstArr;
+                }
+                let recoveryArr = me.getRecoveryArr(me.tempDelArr, rstData);
+                if(recoveryArr.length > 0){
+                    curCache = curCache.concat(recoveryArr);
+                }
+                me.cache["_Coe_" + me.curRation.ID] = curCache;
+                me.updateCurRation(function () {
+                    me.sheet.getParent().focus(true);
+                });
+                me.showCoeItems(me.curRation.ID);
+            });
+        };
+    },
+
+    getCoeItems: function(ration, callback) {
+        var me = this;
+        me.curRation = ration;
+
+        /*if (ration == undefined || ration.rationCoeList == undefined ||
+            ration.rationCoeList.length == 0){return;};*/
+
+        var coeList = ration.rationCoeList;
+        var curCache = me.cache["_Coe_" + ration.ID];
+        if (curCache) {
+            me.showCoeItems(ration.ID);
+            //sheetCommonObj.lockCells(me.sheet, me.setting);
+        } else if(!curCache && typeof coeList !== 'undefined' && coeList.length > 0) {
+            var data = {"libID": me.libID, "coeIDs": coeList};
+            CommonAjax.post('api/getCoeItemsByIDs', data, function (rstData) {
+                sheetCommonObj.cleanData(me.sheet, me.setting, -1);
+                var tempResult = [];
+                for (let obj of rstData) {
+                    tempResult.push(obj);
+                };
+                me.cache["_Coe_" + ration.ID] = tempResult;
+
+                me.showCoeItems(ration.ID);
+                //sheetCommonObj.lockCells(me.sheet, me.setting);
+                if(callback) callback();
+            });
+        };
+    },
+
+    showCoeItems: function(rationID) {
+        var me = this;
+        var curCache = me.cache["_Coe_" + rationID];
+        if (curCache) {
+            curCache.sort(function(a, b) {
+                var rst = 0;
+                if (a.serialNo > b.serialNo) rst = 1
+                else if (a.serialNo < b.serialNo) rst = -1;
+                return rst;
+            });
+            sheetsOprObj.showData(me.sheet, me.setting, curCache);
+        }
+    },
+
+    updateCurRation: function(callback) {
+        var me = this, updateArr = [];
+        if (me.curRation) {
+            var rst = [];
+            var curCache = me.cache["_Coe_" + me.curRation.ID];
+            if (curCache) {
+                for (let obj of curCache) {
+                    rst.push(obj.ID);
+                };
+                me.curRation.rationCoeList = rst;
+                updateArr.push(me.curRation);
+                rationOprObj.mixUpdateRequest(updateArr, [], [], function () {
+                    if(callback) callback();
+                });
+            };
+        };
+    }
+}
+
+

+ 559 - 0
web/building_saas/complementary_ration_lib/js/ration_glj.js

@@ -0,0 +1,559 @@
+/**
+ * Created by Tony on 2017/4/28.
+ */
+var rationGLJOprObj = {
+    sheet: null,
+    currentRationItem: null,
+    distTypeTree: null,
+    activeCell: null,
+    tempCacheArr: [],//被更新的工料机,若更新的工料机不存在,则恢复
+    cache: {},
+    setting: {
+        header:[
+            {headerName:"编码",headerWidth:120,dataCode:"code", dataType: "String", formatter: "@"},
+            {headerName:"名称",headerWidth:400,dataCode:"name", dataType: "String"},
+            {headerName:"规格型号",headerWidth:120,dataCode:"specs", dataType: "String"},
+            {headerName:"单位",headerWidth:160,dataCode:"unit", dataType: "String", hAlign: "center", vAlign: "center"},
+            {headerName:"基价单价",headerWidth:160, dataCode:"basePrice", dataType: "Number", formatter:"0.00",  precision: 2},
+            {headerName:"定额消耗",headerWidth:160, dataCode:"consumeAmt", dataType: "Number", formatter: "0.000", precision: 3},
+            {headerName:"类型",headerWidth:160,dataCode:"gljType", dataType: "String", hAlign: "center", vAlign: "center"}
+        ],
+        view:{
+            comboBox:[],
+            lockColumns:[1,2,3,4,6]
+        }
+    },
+    getDistTypeTree: function (gljDistType) {
+        let me = this;
+        let distType;
+        let distTypeTree = {
+            prefix : 'gljDistType',
+            distTypes: {},
+            comboDatas: [],
+            distTypesArr: []
+        };
+        gljDistType.forEach(function (typeData) {
+            let typeObj = {
+                data: typeData,
+                children: [],
+                parent: null
+            }
+            distTypeTree.distTypes[distTypeTree.prefix + typeData.ID] = typeObj;
+            distTypeTree.distTypesArr.push(typeObj);
+        });
+        gljDistType.forEach(function (typeData) {
+            distType = distTypeTree.distTypes[distTypeTree.prefix + typeData.ID];
+            let parent = distTypeTree.distTypes[distTypeTree.prefix + typeData.ParentID];
+            if(parent){
+                distType.parent = parent;
+                parent.children.push(distType);
+            }
+        });
+        distTypeTree.distTypesArr.forEach(function (distTypeObj) {
+            if(distTypeObj.children.length === 0 && distTypeObj.data.fullName !== '普通机械' &&distTypeObj.data.fullName !== '机械组成物'
+                && distTypeObj.data.fullName !== '机上人工'){
+                distTypeTree.comboDatas.push({text: distTypeObj.data.fullName, value: distTypeObj.data.ID});
+            }
+            if(distTypeObj.data.fullName === '机械'){
+                distTypeTree.comboDatas.push({text: distTypeObj.data.fullName, value: distTypeObj.data.ID});
+            }
+        });
+        return distTypeTree;
+    },
+    getGljDistType: function (callback) {
+        let me = this;
+        $.ajax({
+            type: 'post',
+            url: "api/getGljDistType",
+            dataType: 'json',
+            success: function (result) {
+                if(!result.error && callback){
+                    me.distTypeTree = me.getDistTypeTree(result.data);
+                    callback();
+                }
+            }
+        })
+    },
+    buildSheet: function(sheet) {
+        var me = this;
+        me.sheet = sheet;
+        me.getGljDistType(function () {
+           // me.onContextmenuOpr();
+            sheetCommonObj.initSheet(me.sheet, me.setting, 30);
+            me.bindRationGljDelOpr();
+            me.sheet.bind(GC.Spread.Sheets.Events.ClipboardPasting, me.onClipboardPasting);
+            me.sheet.bind(GC.Spread.Sheets.Events.ClipboardPasted, me.onClipboardPasted);
+            me.sheet.bind(GC.Spread.Sheets.Events.EditStarting, me.onEditStarting);
+            me.sheet.bind(GC.Spread.Sheets.Events.EditEnded, me.onCellEditEnd);
+        });
+    },
+    bindRationGljDelOpr: function () {
+        let me = rationGLJOprObj, spreadBook = me.sheet.getParent();
+        spreadBook.commandManager().register('rationGljDelete', function () {
+            if(!me.currentRationItem || me.currentRationItem.type === rationOprObj.type.std){
+                return;
+            }
+            let sels = me.sheet.getSelections(), lockCols = me.setting.view.lockColumns;
+            let cacheSection = me.cache["_GLJ_" + me.currentRationItem.ID], isUpdate = false;
+            if(sels.length > 0){
+                for(let sel = 0; sel < sels.length; sel++){
+                    if(sels[sel].colCount === me.setting.header.length){
+                        if(cacheSection && sels[sel].row < cacheSection.length){
+                            isUpdate = true;
+                            cacheSection.splice(sels[sel].row, sels[sel].rowCount);
+                        }
+                    }
+                    else{
+                         if(sels[sel].col !== 0 && sels[sel].col !== 5 && !(sels[sel].col === 1 && sels.col + sels[sel].colCount -1 === 3)){
+                            if(cacheSection){
+                                for(let i = sels[sel].row === -1 ? 1 : 0; i < sels[sel].rowCount; i++){
+                                    if(sels[sel].row + i < cacheSection.length){
+                                        for(let col = sels[sel].col; col <= sels[sel].col + sels[sel].colCount - 1; col++){
+                                            if(lockCols.indexOf(col) === -1){
+                                                isUpdate = true;
+                                                cacheSection[sels[sel].row + i][me.setting.header[col].dataCode] = 0;
+                                                me.sheet.setValue(sels[sel].row + i, col, 0.00);
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            if(isUpdate){
+                me.updateRationItem(function () {
+                    me.sheet.getParent().focus(true);
+                });
+                sheetCommonObj.cleanData(me.sheet, me.setting, -1);
+                me.showGljItems(me.currentRationItem.ID);
+            }
+        });
+        spreadBook.commandManager().setShortcutKey(null, GC.Spread.Commands.Key.del, false, false, false, false);
+        spreadBook.commandManager().setShortcutKey('rationGljDelete', GC.Spread.Commands.Key.del, false, false, false, false);
+    },
+    onClipboardPasting: function(sender, args) {
+        var me = rationGLJOprObj;
+        let rationSection = rationOprObj.getCache();
+        let rationRow = rationOprObj.workBook.getSheet(0).getSelections()[0].row;
+        me.currentRationItem = rationRow < rationSection.length ? rationSection[rationRow] : null;
+        if(me.currentRationItem && typeof me.cache["_GLJ_" + me.currentRationItem.ID] === 'undefined'){
+            me.cache["_GLJ_" + me.currentRationItem.ID] = [];
+        }
+        if (!(args.cellRange.col === 0 || args.cellRange.col === 5) || !(me.currentRationItem) || (me.currentRationItem && me.currentRationItem.type === rationOprObj.type.std)) {
+            args.cancel = true;
+        }
+    },
+    onClipboardPasted: function(e, info) {
+        var me = rationGLJOprObj, repId = pageOprObj.rationLibId;
+        me.tempCacheArr = [];
+        if (repId) {
+            let gljLibId = pageOprObj.gljLibId;
+            console.log(gljLibId);
+            if(gljLibId){
+                if (info.cellRange.col == 0) {
+                    let cacheArr = me.cache["_GLJ_" + me.currentRationItem.ID];
+                    var tmpCodes = sheetCommonObj.analyzePasteData({header:[{dataCode: "code"}] }, info);
+                    var codes = [];
+                    for (var i = 0; i < tmpCodes.length; i++) {
+                        let rowIdx = info.cellRange.row + i;
+                        if(rowIdx < cacheArr.length){//更新
+                            me.tempCacheArr.push({org: cacheArr[rowIdx], newCode: tmpCodes[i].code});
+                            cacheArr.splice(rowIdx--, 1);
+                        }
+                        codes.push(tmpCodes[i].code);
+                    }
+                    me.addGljItems(codes, gljLibId, info.cellRange);
+                } else {
+                    //修改用量
+                    if(me.cache["_GLJ_" + me.currentRationItem.ID] && info.cellRange.row < me.cache["_GLJ_" + me.currentRationItem.ID].length){
+                        let tempConsumes = sheetCommonObj.analyzePasteData(me.setting, info);
+                        let maxCount = info.cellRange.row + info.cellRange.rowCount -1 > me.cache["_GLJ_" + me.currentRationItem.ID].length -1 ?
+                        me.cache["_GLJ_" + me.currentRationItem.ID].length - info.cellRange.row : info.cellRange.rowCount;
+                        for(let i = 0; i < maxCount; i++){
+                            let roundCons = scMathUtil.roundTo(tempConsumes[i].consumeAmt, -3);
+                            me.cache["_GLJ_" + me.currentRationItem.ID][info.cellRange.row + i].consumeAmt = roundCons;
+                        }
+                        me.updateRationItem(function () {
+                            me.sheet.getParent().focus(true);
+                        });
+                        if(info.cellRange.row + info.cellRange.rowCount -1 >= me.cache["_GLJ_" + me.currentRationItem.ID].length -1){
+                            me.sheet.suspendPaint();
+                            for(let rowIdx = me.cache["_GLJ_" + me.currentRationItem.ID].length; rowIdx <= info.cellRange.row + info.cellRange.rowCount -1; rowIdx++){
+                                me.sheet.setValue(rowIdx, info.cellRange.col, '');
+                            }
+                            me.sheet.resumePaint();
+                        }
+                    }
+                    else if(info.cellRange.row >= me.cache["_GLJ_" + me.currentRationItem.ID].length){
+                        me.sheet.suspendPaint();
+                        for(let rowIdx = info.cellRange.row; rowIdx <= info.cellRange.row + info.cellRange.rowCount -1; rowIdx ++){
+                            me.sheet.setValue(rowIdx, info.cellRange.col, '');
+                        }
+                        me.sheet.resumePaint();
+                    }
+                }
+            }
+        }
+    },
+    onEditStarting: function (sender, args) {
+        let me = rationGLJOprObj;
+        let rationSection = rationOprObj.getCache();
+        let rationRow = rationOprObj.workBook.getSheet(0).getSelections()[0].row;
+        me.currentRationItem = rationRow < rationSection.length ? rationSection[rationRow] : null;
+        if(me.currentRationItem && typeof me.cache["_GLJ_" + me.currentRationItem.ID] === 'undefined'){
+            me.cache["_GLJ_" + me.currentRationItem.ID] = [];
+        }
+        if(!me.currentRationItem){
+            args.cancel = true;
+        }
+        else {
+            if(args.col !== 0 && args.col !== 5 || args.col === 5 && args.row >= me.cache["_GLJ_" + me.currentRationItem.ID].length
+            || me.currentRationItem.type === rationOprObj.type.std){
+                args.cancel = true;
+            }
+        }
+    },
+    onCellEditEnd: function(sender, args){
+        var me = rationGLJOprObj;
+        if(me.currentRationItem) {
+            var cacheArr = me.cache["_GLJ_" + me.currentRationItem.ID];
+            me.tempCacheArr = [];
+            if (args.col != 0) {
+                if (args.row < cacheArr.length) {
+                    var editGlj = cacheArr[args.row];
+                    if (editGlj["consumeAmt"] != args.editingText) {
+                        let parseNum = parseFloat(args.editingText);
+                        if (isNaN(parseFloat(args.editingText))) {
+                            $('#alertModalBtn').click();
+                            $('#alertText').text("定额消耗只能输入数值!");
+                            $('#alertModalCls').click(function () {
+                                args.sheet.setValue(args.row, args.col, editGlj['consumeAmt']);
+                            });
+                            $('#alertModalCof').click(function () {
+                                args.sheet.setValue(args.row, args.col, editGlj['consumeAmt']);
+                            })
+                        }
+                        else {
+                            args.sheet.setValue(args.row, args.col, parseNum);
+                            let roundNum = scMathUtil.roundTo(parseNum, -3);
+                            editGlj["consumeAmt"] = roundNum;
+                            me.updateRationItem(function () {
+                                me.sheet.getParent().focus(true);
+                            });
+                        }
+                    }
+                }
+            } else {
+                if (args.editingText && args.editingText.toString().trim().length !== 0) {
+                    let isExist = false;
+                    for (let i = 0, len = cacheArr.length; i < len; i++) {
+                        if (cacheArr[i].code === args.editingText && i !== args.row) {
+                            isExist = true;
+                            break;
+                        }
+                    }
+                    if (isExist) {
+                        alert("该工料机已存在!");
+                        args.sheet.setValue(args.row, args.col, typeof cacheArr[args.row] !== 'undefined' ? cacheArr[args.row].code + '' : '');
+                    }
+                    else {
+                        if (args.row < cacheArr.length && args.editingText !== cacheArr[args.row].code) {//更新
+                            me.tempCacheArr.push({org: cacheArr[args.row], newCode: args.editingText.toString().trim()});
+                            cacheArr.splice(args.row, 1);
+                            let gljLibID = pageOprObj.gljLibId;
+                            let codes = [];
+                            codes.push(args.editingText.toString().trim());
+                            me.addGljItems(codes, gljLibID, args);
+                        }
+                        else if (args.row >= cacheArr.length) {//新增
+                            let gljLibID = pageOprObj.gljLibId;
+                            if (gljLibID) {
+                                var codes = [];
+                                codes.push(args.editingText.toString().trim());
+                                me.addGljItems(codes, gljLibID, args);
+                            }
+                        }
+                    }
+                }
+                else {
+                    args.sheet.setValue(args.row, args.col, args.row < cacheArr.length ? cacheArr[args.row].code : '');
+                }
+            }
+        }
+        else {
+            args.sheet.setValue(args.row, args.col, '');
+        }
+    },
+    onContextmenuOpr: function () {
+        let me = rationGLJOprObj;
+        $.contextMenu({
+            selector: '#rdSpread',
+            build: function ($triggerElement, e) {
+                //控制允许右键菜单在哪个位置出现
+                let sheet = me.sheet;
+                let offset = $triggerElement.offset(),
+                    x = e.pageX - offset.left,
+                    y = e.pageY - offset.top;
+                let target = sheet.hitTest(x, y);
+                if(sheet.parent.getActiveSheetIndex() === 0 && target.hitTestType === 3 && typeof target.row !== 'undefined' && typeof target.col !== 'undefined'){
+                    let delDis = true, cacheSection;
+                    sheet.setActiveCell(target.row, target.col);
+                    if(me.currentRationItem){
+                        let cacheSection = me.cache["_GLJ_" + me.currentRationItem.ID];
+                        if(target.row < cacheSection.length){
+                            delDis = false;
+                        }
+                    }
+                    return {
+                        callback: function(key, options) {
+                        },
+                        items: {
+                            "delete": {name: "删除", icon: 'fa-remove', disabled: delDis, callback: function (key, opt) {
+                                cacheSection.splice(target.row, 1);
+                                me.updateRationItem(function () {
+                                    me.sheet.getParent().focus(true);
+                                });
+                                sheetCommonObj.cleanData(me.sheet, me.setting, -1);
+                                me.showGljItems(me.currentRationItem.ID);
+                            }}
+                        }
+                    };
+                }
+                else{
+                    return false;
+                }
+            }
+        });
+    },
+    getRecoveryArr: function (tempDelArr, newArr) {//获得更新的code不存在,恢复删除的被更新数据
+        let rst = [];
+        for(let i = 0, len = tempDelArr.length; i < len; i++){
+            let isExist = false;
+            for(let j = 0, jLen = newArr.length; j < jLen; j++){
+                if(tempDelArr[i].newCode == newArr[j].code){
+                    isExist = true;
+                    break;
+                }
+            }
+            if(!isExist){
+                rst.push(tempDelArr[i].org);
+            }
+        }
+        return rst;
+    },
+    addGljItems: function(codes, repId, args) {
+        let me = this;
+        CommonAjax.post('api/getGljItemsByCodes', {gljCodes: codes, rationRepId: repId}, function (rstData) {
+            if(rstData.length > 0){
+                sheetCommonObj.cleanData(me.sheet, me.setting, -1);
+                let rstArr = [], dummyR = {gljId: 0, consumeAmt:0}, newAddArr = [];
+                for (let i = 0; i < rstData.length; i++) {
+                    dummyR.gljId = rstData[i].ID;
+                    dummyR.type = rstData[i].type;
+                    rstArr.push(me.createRationGljDisplayItem(dummyR, rstData[i]));
+                }
+                if (me.cache["_GLJ_" + me.currentRationItem.ID]) {
+                    var cacheArr = me.cache["_GLJ_" + me.currentRationItem.ID];
+                    for (var i = 0; i < rstArr.length; i++) {
+                        var hasDup = false;
+                        for (var j = 0; j < cacheArr.length; j++) {
+                            if (cacheArr[j].gljId == rstArr[i].gljId) {
+                                hasDup = true;
+                                break;
+                            }
+                        }
+                        if (!hasDup) {
+                            newAddArr.push(rstArr[i]);
+                        }
+                    }
+                    me.cache["_GLJ_" + me.currentRationItem.ID] = cacheArr.concat(newAddArr);
+                    let recoveryArr = me.getRecoveryArr(me.tempCacheArr, rstData);
+                    if(recoveryArr.length > 0){
+                        me.cache["_GLJ_" + me.currentRationItem.ID] = me.cache["_GLJ_" + me.currentRationItem.ID].concat(recoveryArr);
+                    }
+                    me.cache["_GLJ_" + me.currentRationItem.ID].sort(function(a, b) {
+                        var rst = 0;
+                        if (a.code > b.code) rst = 1
+                        else if (a.code < b.code) rst = -1;
+                        return rst;
+                    });
+                }
+                me.showGljItems(me.currentRationItem.ID);
+                if (newAddArr.length > 0) {
+                    me.updateRationItem(function () {
+                        me.sheet.getParent().focus(true);
+                    });
+                }
+            }
+            else{
+                let cacheArr = me.cache["_GLJ_" + me.currentRationItem.ID]?  me.cache["_GLJ_" + me.currentRationItem.ID] : [];
+                let recoveryArr = me.getRecoveryArr(me.tempCacheArr, []);
+                if(recoveryArr.length > 0){
+                    me.cache["_GLJ_" + me.currentRationItem.ID] = cacheArr.concat(recoveryArr);
+                }
+                //更新的工料机不存在
+                me.cache["_GLJ_" + me.currentRationItem.ID].sort(function(a, b) {
+                    var rst = 0;
+                    if (a.code > b.code) rst = 1
+                    else if (a.code < b.code) rst = -1;
+                    return rst;
+                });
+                $('#alertModalBtn').click();
+                $('#alertText').text("工料机"+ codes + "不存在,请查找你所需要的工料机,或新增工料机");
+                $('#alertModalCls').click(function () {
+                    me.showGljItems(me.currentRationItem.ID);
+                });
+                $('#alertModalCof').click(function () {
+                    me.showGljItems(me.currentRationItem.ID);
+                })
+            }
+        });
+    },
+    round(v, e){
+        var t=1;
+        for(;e>0;t*=10,e--);
+        for(;e<0;t/=10,e++);
+        return Math.round(v*t)/t;
+    },
+    rationCal: function () {
+        let me = rationGLJOprObj;
+        let price = {gljType1: [], gljType2: [], gljType3: []}, rst = {labourPrice: 0, materialPrice: 0, machinePrice: 0}, rationBasePrc = 0;
+        if(me.currentRationItem && me.cache['_GLJ_' + me.currentRationItem.ID]){
+            let cacheArr = me.cache['_GLJ_' + me.currentRationItem.ID];
+            cacheArr.forEach(function (gljData) {
+                if(gljData.gljType && gljData.basePrice && gljData.consumeAmt){
+                    let parent = me.distTypeTree.distTypes[me.distTypeTree.prefix + gljData.gljType].parent;
+                    if(parent && parent.data.ID <= 3){
+                        price['gljType' + parent.data.ID].push(scMathUtil.roundTo( gljData.basePrice * gljData.consumeAmt, -3));//取三位
+                    }
+                    if(!parent && gljData.gljType <= 3){
+                        price['gljType' + gljData.gljType].push(scMathUtil.roundTo( gljData.basePrice * gljData.consumeAmt, -3));//取三位
+                    }
+                }
+            });
+            if(price.gljType1.length > 0){
+                let labourPrice = 0;
+                price.gljType1.forEach(function (singlePrc) {
+                    labourPrice += singlePrc;
+                });
+                let roundPrice = scMathUtil.roundTo(labourPrice, -2);
+                rst.labourPrice = roundPrice;
+                rationBasePrc += roundPrice;
+            }
+            if(price.gljType2.length > 0){
+                let materialPrice = 0;
+                price.gljType2.forEach(function (singlePrc) {
+                    materialPrice += singlePrc;
+                });
+                let roundPrice = scMathUtil.roundTo(materialPrice, -2);
+                rst.materialPrice = roundPrice;
+                rationBasePrc += roundPrice;
+            }
+            if(price.gljType3.length > 0){
+                let machinePrice = 0;
+                price.gljType3.forEach(function (singlePrc) {
+                    machinePrice += singlePrc;
+                });
+                let roundPrice = scMathUtil.roundTo(machinePrice, -2);
+                rst.machinePrice = roundPrice;
+                rationBasePrc += roundPrice;
+            }
+            rst.rationBasePrc = rationBasePrc;
+        }
+        return rst;
+    },
+    updateRationItem: function(callback) {
+        var me = this, updateArr = [];
+        if (me.currentRationItem) {
+            me.currentRationItem.rationGljList = me.buildRationItemGlj();
+            //recalculate ration basePrice
+            let price = me.rationCal();
+            me.currentRationItem.labourPrice = price.labourPrice;
+            me.currentRationItem.materialPrice = price.materialPrice;
+            me.currentRationItem.machinePrice = price.machinePrice;
+            me.currentRationItem.basePrice = price.rationBasePrc;
+            updateArr.push(me.currentRationItem);
+            rationOprObj.mixUpdateRequest(updateArr, [], [], function () {
+                if(callback) callback();
+            });
+        }
+    },
+
+    buildRationItemGlj: function(){
+        var me = this, rst = [];
+        console.log(me.currentRationItem && me.cache["_GLJ_" + me.currentRationItem.ID]);
+        if (me.currentRationItem && me.cache["_GLJ_" + me.currentRationItem.ID]) {
+            var cacheArr = me.cache["_GLJ_" + me.currentRationItem.ID];
+            for (var i = 0; i < cacheArr.length; i++) {
+                rst.push({gljId: cacheArr[i].gljId, consumeAmt: cacheArr[i].consumeAmt, type: cacheArr[i].type});
+            }
+        }
+        return rst;
+    },
+
+    createRationGljDisplayItem: function(rItem, repGlj) {
+        var rst = {};
+        rst.gljId = rItem.gljId;
+        rst.type = rItem.type;
+        rst.consumeAmt = rItem.consumeAmt;
+        rst.code = repGlj.code;
+        rst.name = repGlj.name;
+        rst.specs = repGlj.specs;
+        rst.unit = repGlj.unit;
+        rst.basePrice = repGlj.basePrice;
+        rst.gljType = repGlj.gljType;
+        return rst;
+    },
+    getGljItems: function(rationItem, callback) {
+        let me = this, rationID = rationItem.ID, rationGljList = rationItem.rationGljList, rationType = rationItem.type;
+        me.currentRationItem = rationItem;
+        if (me.cache["_GLJ_" + rationID]) {
+            me.showGljItems(rationID);
+        } else {
+            let gljIds = [];
+            for (let i = 0; i < rationGljList.length; i++) {
+                let idObj = Object.create(null);
+                idObj.type = rationType === rationOprObj.type.std ? rationOprObj.type.std : rationGljList[i].type;
+                idObj.id = rationGljList[i].gljId;
+                gljIds.push(idObj);
+            }
+            CommonAjax.post('api/getGljItemsByIds', {ids: gljIds}, function (rstData) {
+                sheetCommonObj.cleanSheet(me.sheet, me.setting, -1);
+                var cacheArr = [];
+                for (let i = 0; i < rstData.length; i++) {
+                    for (let j = 0; j < rationGljList.length; j++) {
+                        if (rationGljList[j].gljId == rstData[i].ID) {
+                            cacheArr.push(me.createRationGljDisplayItem(rationGljList[j], rstData[i]));
+                            break;
+                        }
+                    }
+                }
+                function compare(){
+                    return function (a, b) {
+                        let rst = 0;
+                        if (a.code > b.code) {
+                            rst = 1;
+                        }
+                        else if (a.code < b.code) {
+                            rst = -1;
+                        }
+                        return rst;
+                    }
+                }
+                cacheArr.sort(compare());
+                me.cache["_GLJ_" + rationID] = cacheArr;
+                me.showGljItems(rationID);
+                if(callback) callback();
+            });
+        }
+    },
+    showGljItems: function(rationID) {
+        var me = this;
+        if (me.cache["_GLJ_" + rationID]) {
+            sheetCommonObj.cleanData(me.sheet, me.setting, -1);
+            sheetsOprObj.showData(me.sheet, me.setting, me.cache["_GLJ_" + rationID], me.distTypeTree);
+        }
+    }
+}

文件差异内容过多而无法显示
+ 1012 - 0
web/building_saas/complementary_ration_lib/js/repository_glj.js


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

@@ -0,0 +1,442 @@
+/**
+ * Created by Zhong on 2017/12/18.
+ */
+let pageOprObj = {
+    rationLibName : null,
+    rationLibId : null,
+    gljLibId: null,
+    initPage : function() {
+        let me = this, rationLibId = getQueryString("repository");
+        me.getRationLibInfo(rationLibId, function (rstData) {
+            if(rstData.length > 0){
+                me.rationLibName = rstData[0].dispName;
+                me.gljLibId = rstData[0].gljLib;
+                let html = $("#rationname")[0].outerHTML;
+                html = html.replace("XXX定额库", me.rationLibName);
+                $("#rationname")[0].outerHTML = html;
+                me.rationLibId = rationLibId;
+                sectionTreeObj.getSectionTree(rationLibId);
+                //job
+                jobContentOprObj.radiosChange(jobContentOprObj.radios, jobContentOprObj.tableAll, jobContentOprObj.tablePartial);
+                $('#addConBtn').click(jobContentOprObj.bindAddConBtn());
+                $('#updateConBtn').click(jobContentOprObj.bindUpdateConBtn());
+                jobContentOprObj.bindAllEvents($('#txtareaAll'));
+                //fz
+                annotationOprObj.radiosChange(annotationOprObj.radios, annotationOprObj.fzTableAll, annotationOprObj.fzTablePartial);
+                $('#fzAddConBtn').click(annotationOprObj.bindAddConBtn());
+                $('#fzUpdateConBtn').click(annotationOprObj.bindUpdateConBtn());
+                annotationOprObj.bindAllEvents($('#fzTxtareaAll'));
+            }
+        });
+    },
+    getRationLibInfo: function (rationLibId, callback) {
+        CommonAjax.post('api/getRationLib', {rationRepId: rationLibId}, callback);
+    }
+};
+
+let sectionTreeObj = {
+    cache: null,//ref to tree.items
+    tree: null,
+    controller: null,
+    workBook: null,
+    sheet: null,
+    updateType: {new: 'new', update: 'update'},
+    insertBtn: $('#tree_Insert'),
+    removeBtn: $('#tree_remove'),
+    type: {std: 'std', complementary: 'complementary'},
+    setting: {
+        sheet: {
+            cols:[
+                {
+                    head: {
+                        titleNames: ['名称'],
+                        spanCols: [1],
+                        spanRows: [2],
+                        vAlign: [1, 1],
+                        hAlign: [1, 1],
+                        font: 'Arial'
+                    },
+                    data: {
+                        field: 'name',
+                        vAlign: 1,
+                        hAlign: 0,
+                        font: 'Arial'
+                    },
+                    width: 400
+                }
+            ],
+            headRows: 1,
+            headRowHeight: [47],
+            emptyRows: 0,
+            treeCol: 0
+        },
+        tree: {
+            id: 'ID',
+            pid: 'ParentID',
+            nid: 'NextSiblingID',
+            rootId: -1
+        },
+        options: {
+            tabStripVisible:  false,
+            allowCopyPasteExcelStyle : false,
+            allowExtendPasteRange: false,
+            allowUserDragDrop : false,
+            allowUserDragFill: false,
+            scrollbarMaxAlign : true
+        }
+    },
+
+    isDef: function (v) {
+        return v !== undefined && v !== null;
+    },
+    isFunc: function (v) {
+        return this.isDef(v) && typeof v === 'function';
+    },
+    //sheet things
+    setOptions: function (workbook, opts) {
+        for(let opt in opts){
+            workbook.options[opt] = opts[opt];
+        }
+    },
+
+    renderFunc: function (sheet, func) {
+        sheet.suspendPaint();
+        sheet.suspendEvent();
+        if(this.isFunc(func)){
+            func();
+        }
+        sheet.resumePaint();
+        sheet.resumeEvent();
+    },
+
+    buildSheet: function () {
+        if(!this.isDef(this.workBook)){
+            this.workBook = new GC.Spread.Sheets.Workbook($('#sectionSpread')[0], {sheetCount: 1});
+            this.sheet = this.workBook.getSheet(0);
+            this.bindEvents(this.sheet);
+            this.setOptions(this.workBook, this.setting.options);
+            this.sheet.options.clipBoardOptions = GC.Spread.Sheets.ClipboardPasteOptions.values;
+        }
+    },
+
+    bindEvents: function (sheet) {
+        let me = sectionTreeObj;
+        const Events = GC.Spread.Sheets.Events;
+        sheet.bind(Events.SelectionChanging, me.onSelectionChanging);
+        sheet.bind(Events.EditEnded, me.onEditEnded);
+        sheet.bind(Events.EditStarting, me.onEditStarting);
+        sheet.bind(Events.ClipboardPasting, me.onClipboardPasting);
+        sheet.bind(Events.ClipboardPasted, me.onClipboardPasted);
+    },
+
+    onSelectionChanging: function (sender, info) {
+        let me = sectionTreeObj;
+        if(info.oldSelections.length === 0 && info.newSelections.length > 0 || info.oldSelections[0].row !== info.newSelections[0].row){
+            let row = info.newSelections[0].row;
+            let section = me.cache[row];
+            me.initSelection(section);
+        }
+        else {
+            me.refreshBtn(null);
+        }
+    },
+
+    onEditStarting: function (sender, args) {
+        let me = sectionTreeObj;
+        let node = me.cache[args.row];
+        if(!me.isDef(node)){
+            args.cancel = true;
+            return;
+        }
+        if(node.data.type === me.type.std){
+            args.cancel = true;
+        }
+    },
+
+    onEditEnded: function (sender, args) {
+        let me = sectionTreeObj;
+        let postData = [];
+        let v = me.isDef(args.editingText) ? args.editingText.toString().trim() : '';
+        let node = me.cache[args.row];
+        if(me.isDef(node) && node.data.name !== v){
+            let updateObj = me.getUpdateObj(me.updateType.update, {ID: node.getID(), name: v});
+            postData.push(updateObj);
+            //ajax
+            //update
+            me.sectionTreeAjax(postData, function (rstData) {
+                node.data.name = v;
+            }, function () {
+                args.sheet.setValue(args.row, args.col, node.data.name ? node.data.name : '');
+            });
+        }
+    },
+
+    onClipboardPasting: function (sender, info) {
+        let me = sectionTreeObj;
+        let hasStd = false;
+        for(let row = info.cellRange.row, len = info.cellRange.row + info.cellRange.rowCount - 1; row < len; row ++){
+            if(me.isDef(me.cache[row]) && me.cache[row].data.type === me.type.std){
+                hasStd = true;
+            }
+        }
+        if(hasStd){
+            info.cancel = true;
+        }
+    },
+
+    onClipboardPasted: function (sender, info) {
+        let me = sectionTreeObj;
+        let items = sheetCommonObj.analyzePasteData({header: [{dataCode: 'name'}]}, info);
+        let postData = [];
+        let frontData = [];
+        for(let i = 0, len = items.length; i < len; i++){
+            let row = info.cellRange.row + i;
+            let node = me.cache[row];
+            if(me.isDef(node) && me.isDef(items[i].name) && node.data.name !== items[i].name){
+                let updateObj = me.getUpdateObj(me.updateType.update, {ID: node.getID(), name: items[i].name});
+                postData.push(updateObj);
+                frontData.push({row: row, name: items[i].name});
+                node.data.name = items[i].name;
+            }
+        }
+        if(postData.length > 0){
+            //ajax
+            me.sectionTreeAjax(postData, function (rstData) {
+                for(let i = 0, len = frontData.length; i < len; i++){
+                    let node = me.cache[frontData[i]['row']];
+                    if(me.isDef(node)){
+                        node.data.name = frontData[i]['name'];
+                    }
+                }
+            }, function () {
+                for(let i = 0, len = frontData.length; i < len; i++){
+                    let node = me.cache[frontData[i]['row']];
+                    me.sheet.setValue(frontData[i]['row'], 0, me.isDef(node) ? node.data.name : '');
+                }
+            });
+        }
+    },
+
+    getSectionTree: function (repId) {
+        let me = sectionTreeObj;
+        let url = 'api/getRationTree';
+        let postData = {rationRepId: repId};
+        let sucFunc = function (rstData) {
+            if(rstData.length > 0){
+                storageUtil.setSessionCache("RationGrp","repositoryID",rstData[0].rationRepId);
+            }
+            //init
+            me.buildSheet();
+            me.initTree(rstData);
+            me.cache = me.tree.items;
+            me.bindBtn();
+            me.initController(me.tree, me.sheet, me.setting.sheet);
+            me.controller.showTreeData();
+            me.setColor(me.cache);
+            me.sheet.setFormatter(-1, 0, '@');
+            me.initSelection(me.tree.selected);
+            explanatoryOprObj.bindEvents($('#explanationShow'), $('#ruleTextShow'));
+        };
+        let errFunc = function () {
+
+        };
+        CommonAjax.post(url, postData, sucFunc, errFunc);
+    },
+
+    setColor: function (nodes) {
+        let me = this;
+        me.renderFunc(me.sheet, function () {
+            for(let i = 0, len = nodes.length; i < len; i++){
+                if(nodes[i].data.type === me.type.complementary){
+                    me.sheet.getCell(i, 0).foreColor('gray');
+                }
+            }
+        });
+    },
+
+    initTree: function (datas) {
+        this.tree = idTree.createNew(this.setting.tree);
+        this.tree.loadDatas(datas);
+        this.tree.selected = this.tree.items.length > 0 ? this.tree.items[0] : null;
+    },
+
+    initController: function (tree, sheet, setting) {
+        this.controller = TREE_SHEET_CONTROLLER.createNew(tree, sheet, setting);
+    },
+    
+    refreshBtn: function (selected) {
+        let me = this;
+        me.insertBtn.removeClass('disabled');
+        me.removeBtn.removeClass('disabled');
+        if(!me.isDef(selected)){
+            me.removeBtn.addClass('disabled');
+        }
+        else if(me.isDef(selected.data.type) && selected.data.type !== me.type.complementary){
+            me.removeBtn.addClass('disabled');
+        }
+    },
+    
+    bindBtn: function () {
+        let me = this;
+        me.insertBtn.click(function () {
+            me.insert();
+        });
+        me.removeBtn.click(function () {
+           me.remove(me.tree.selected);
+        });
+    },
+    
+    insert: function () {
+        let me = this;
+        me.insertBtn.addClass('disabled');
+        let postData = [];
+        CommonAjax.post('api/getNewTreeID', {user_id: userID}, function (newID) {
+            if(!me.isDef(newID)){
+                return;
+            }
+            me.tree.maxNodeID(newID - 1);
+            let selected = me.tree.selected;
+            let insertObj = me.getUpdateObj(me.updateType.new, {ID: newID, NextSiblingID: -1, ParentID: -1, name: ''});
+            if(me.isDef(selected)) {
+                insertObj.updateData.ParentID = selected.getParentID();
+                //同级节点
+                let slNodes = [];
+                slNodes = !me.isDef(selected.parent)? me.tree.roots : selected.parent.children;
+                let updateNode = slNodes[slNodes.length - 1];
+                if(me.isDef(updateNode)){
+                    me.controller.setTreeSelected(updateNode);
+                    if(updateNode.data.type === me.type.complementary){
+                        let updateObj = me.getUpdateObj(me.updateType.update, {ID: updateNode.getID(), NextSiblingID: newID});
+                        postData.push('updateObj');
+                        postData.push(updateObj);
+                    }
+                    else {
+                        insertObj.updateData.isFirst = true;
+                    }
+                }
+            }
+            postData.push(insertObj);
+            if(postData.length > 0){
+                //ajax
+                me.sectionTreeAjax(postData, function (rstData) {
+                    me.controller.insert();
+                    me.sheet.getCell(me.sheet.getActiveRowIndex(), 0).foreColor('gray');
+                    me.tree.selected.data = insertObj.updateData;
+                    me.tree.selected.data.type = me.type.complementary;
+                    me.refreshBtn(me.tree.selected);
+                    //fresh tools
+                    me.initTools(me.tree.selected);
+                });
+            }
+        });
+    },
+    remove: function (selected) {
+        let me = this;
+        me.removeBtn.addClass('disabled');
+        let postData = [], IDs = [];
+        let deleteObj = Object.create(null);
+        deleteObj.deleted = true;
+        deleteObj.deleteDateTime = new Date();
+        deleteObj.deleteBy = userID;
+        if(!selected){
+            return;
+        }
+        getDelIds(selected);
+        function getDelIds(node){
+            if(me.isDef(node)){
+                IDs.push(node.getID());
+                if(node.children.length > 0){
+                    for(let i = 0, len = node.children.length; i < len; i++){
+                        getDelIds(node.children[i]);
+                    }
+                }
+            }
+        }
+        if(me.isDef(selected.preSibling) && selected.preSibling.data.type === me.type.complementary){
+            let updateObj = me.getUpdateObj(me.updateType.update, selected.preSibling.getID(), selected.getNextSiblingID(), null, null, null);
+            postData.push(updateObj);
+        }
+        else if((!me.isDef(selected.preSibling) || (me.isDef(selected.preSibling) && selected.preSibling.data.type === me.type.std))
+            && me.isDef(selected.nextSibling)){
+            let updateNextObj = me.getUpdateObj(me.updateType.update, {ID: selected.nextSibling.getID(), isFirst: true});
+            postData.push(updateNextObj);
+        }
+        if(IDs.length > 0){
+            for(let i = 0, len = IDs.length; i < len; i++){
+                let delObj = me.getUpdateObj(me.updateType.update, {ID: IDs[i], deleteInfo: deleteObj});
+                postData.push(delObj);
+            }
+        }
+        if(postData.length > 0){
+            //ajax
+            me.sectionTreeAjax(postData, function (rstData) {
+                me.controller.delete();
+                me.refreshBtn(me.tree.selected);
+                me.initTools(me.tree.selected);
+            });
+        }
+    },
+    getUpdateObj: function (updateType, updateData) {
+        let updateObj = Object.create(null);
+        updateObj.updateType = '';
+        updateObj.updateData = Object.create(null);
+        updateObj.updateData.rationRepId = pageOprObj.rationLibId;
+        if(this.isDef(updateType)){
+            updateObj.updateType = updateType;
+        }
+        if(this.isDef(updateData)){
+            for(let attr in updateData){
+                updateObj.updateData[attr] = updateData[attr];
+            }
+        }
+        return updateObj;
+    },
+    sectionTreeAjax: function (postData, scFunc, errFunc) {
+        CommonAjax.post('api/updateRationSection', {updateData: postData}, scFunc, errFunc);
+    },
+    initTools: function (node) {
+        if(this.isDef(node)){
+            explanatoryOprObj.setAttribute(explanatoryOprObj.currentTreeNode ? explanatoryOprObj.currentTreeNode : node, node, node.data.explanation, node.data.ruleText);
+            explanatoryOprObj.clickUpdate($('#explanationShow'), $('#ruleTextShow'));
+            explanatoryOprObj.showText($('#explanationShow'), $('#ruleTextShow'), node.data.explanation, node.data.ruleText);
+            //job
+            jobContentOprObj.currentSituation = typeof node.data.jobContentSituation !== 'undefined'? node.data.jobContentSituation : jobContentOprObj.situations.NONE;
+            jobContentOprObj.setAttribute(jobContentOprObj.currentTreeNode ? jobContentOprObj.currentTreeNode : node, node);
+            jobContentOprObj.clickUpdate($('#txtareaAll'));
+            //fz
+            annotationOprObj.currentSituation = typeof node.data.annotationSituation !== 'undefined'? node.data.annotationSituation : annotationOprObj.situations.NONE;
+            annotationOprObj.clickUpdate($('#fzTxtareaAll'));
+        }
+    },
+    //模仿默认点击
+    initSelection: function (node) {
+        let me = this;
+        if(!me.isDef(node)){
+            return;
+        }
+        me.initTools(node);
+        me.refreshBtn(node);
+        if(!me.isDef(node.children) || node.children.length === 0){
+            rationOprObj.canRations = true;
+            rationOprObj.workBook.getSheet(0).clearSelection();
+            rationOprObj.getRationItems(node.data.ID);
+            rationOprObj.setCombo(rationOprObj.workBook.getSheet(0), 'dynamic');
+        }
+        else {
+            rationOprObj.canRations = false;
+            rationOprObj.currentSectionId = node.data.ID;
+            rationOprObj.workBook.getSheet(0).setRowCount(30);
+            rationOprObj.setCombo(rationOprObj.workBook.getSheet(0), null);
+           // jobContentOprObj.setRadiosDisabled(true, jobContentOprObj.radios);
+            jobContentOprObj.hideTable($('#tableAll'), $('#tablePartial'));
+          //  annotationOprObj.setRadiosDisabled(true, annotationOprObj.radios);
+            annotationOprObj.hideTable($('#fzTableAll'), $('#fzTablePartial'));
+            sheetCommonObj.cleanSheet(rationOprObj.workBook.getSheet(0), rationOprObj.setting, -1);
+        }
+        sheetCommonObj.cleanSheet(rationGLJOprObj.sheet, rationGLJOprObj.setting, -1);
+        sheetCommonObj.cleanSheet(rationCoeOprObj.sheet, rationCoeOprObj.setting, -1);
+        sheetCommonObj.cleanSheet(rationAssistOprObj.sheet, rationAssistOprObj.setting, -1);
+        //rationGLJOprObj.sheet.getParent().focus(false);
+        me.workBook.focus(true);
+    }
+};

+ 202 - 0
web/building_saas/complementary_ration_lib/js/sheetsOpr.js

@@ -0,0 +1,202 @@
+/**
+ * Created by Zhong on 2017/9/29.
+ */
+let sheetsOprObj = {
+    setAreaAlign: function(area, hAlign, vAlign){
+        if (!(hAlign) || hAlign === "left") {
+            area.hAlign(GC.Spread.Sheets.HorizontalAlign.left);
+        } else if (hAlign === "right") {
+            area.hAlign(GC.Spread.Sheets.HorizontalAlign.right);
+        } else if (hAlign === "center") {
+            area.hAlign(GC.Spread.Sheets.HorizontalAlign.center);
+        } else {
+            area.hAlign(GC.Spread.Sheets.HorizontalAlign.left);
+        }
+        if (!(vAlign) || vAlign === "center") {
+            area.vAlign(GC.Spread.Sheets.VerticalAlign.center);
+        } else if (vAlign === "top") {
+            area.vAlign(GC.Spread.Sheets.VerticalAlign.top);
+        } else if (vAlign === "bottom") {
+            area.vAlign(GC.Spread.Sheets.VerticalAlign.bottom);
+        } else {
+            area.vAlign(GC.Spread.Sheets.VerticalAlign.center);
+        }
+    },
+    showData: function(sheet, setting, data, distTypeTree) {
+        var me = this, ch = GC.Spread.Sheets.SheetArea.viewport;
+        sheet.suspendPaint();
+        sheet.suspendEvent();
+        if(typeof setting.owner !== 'undefined' && setting.owner === 'gljComponent'){
+            sheet.setRowCount(data.length + 5);
+        }
+        else{
+            sheet.setRowCount(typeof repositoryGljObj !== 'undefined' && repositoryGljObj.currentOprParent === 1 ? data.length : data.length + 10);
+        }
+        /*if(data.length === 0){
+            for(let i = 0; i < sheet.getRowCount(); i++){
+                sheet.getCell(i, 4, GC.Spread.Sheets.SheetArea.viewport).locked(false);
+            }
+        }*/
+        for (var col = 0; col < setting.header.length; col++) {
+            var hAlign = "left", vAlign = "center";
+            if (setting.header[col].hAlign) {
+                hAlign = setting.header[col].hAlign;
+            } else if (setting.header[col].dataType !== "String"){
+                hAlign = "right";
+            }
+            vAlign = setting.header[col].vAlign?setting.header[col].vAlign:vAlign;
+            me.setAreaAlign(sheet.getRange(-1, col, -1, 1), hAlign, vAlign);
+            if (setting.header[col].formatter) {
+                //var style = new GC.Spread.Sheets.Style();
+                //style.formatter = setting.header[col].formatter;
+                //sheet.setStyle(row,col,style,GC.Spread.Sheets.SheetArea.viewport);
+                sheet.setFormatter(-1, col, setting.header[col].formatter, GC.Spread.Sheets.SheetArea.viewport);
+            }
+            for (var row = 0; row < data.length; row++) {
+                //var cell = sheet.getCell(row, col, GC.Spread.Sheets.SheetArea.viewport);
+                if(setting.header[col].dataCode === 'gljType' && data[row].gljType){
+                   /* if(typeof repositoryGljObj !== 'undefined' && typeof repositoryGljObj.allowComponent !== 'undefined' && repositoryGljObj.allowComponent.indexOf(data[row].gljType) !== -1){
+                        sheet.getCell(row, 4, GC.Spread.Sheets.SheetArea.viewport).locked(true);
+                    }
+                    else if(typeof repositoryGljObj !== 'undefined' && typeof repositoryGljObj.allowComponent !== 'undefined' && repositoryGljObj.allowComponent.indexOf(data[row].gljType) === -1){
+                        sheet.getCell(row, 4, GC.Spread.Sheets.SheetArea.viewport).locked(false);
+                    }*/
+                    let distTypeVal =  distTypeTree.distTypes[distTypeTree.prefix + data[row].gljType].data.fullName;
+                    sheet.setValue(row, col, distTypeVal, ch);
+                }
+                else {
+                    sheet.setValue(row, col, data[row][setting.header[col].dataCode], ch);
+                    sheet.setTag(row, 0, data[row].ID, ch);
+                    /*if(typeof setting.owner !== 'undefined' && setting.owner !== 'gljComponent'){
+                        sheet.getCell(row, 0, GC.Spread.Sheets.SheetArea.viewport).locked(true);
+                    }*/
+                }
+            }
+          /*  for(let i = data.length; i < sheet.getRowCount(); i++){
+                sheet.getCell(i, 4, GC.Spread.Sheets.SheetArea.viewport).locked(false);
+            }*/
+        }
+        sheet.resumeEvent();
+        sheet.resumePaint();
+        //me.shieldAllCells(sheet);
+    },
+    combineRowData: function(sheet, setting, row, repositoryGljObj) {
+        let me = this;
+        var rst = {};
+        let comboBoxCellType = sheet.getCellType(row, 5);
+        let items = comboBoxCellType.items();
+        for (var col = 0; col < setting.header.length; col++) {
+            if(setting.header[col].dataCode === 'gljType'){
+                items.forEach(function(item){
+                    if(sheet.getValue(row, col) === item.text){
+                        rst[setting.header[col].dataCode] = item.value;
+                        if(repositoryGljObj){
+                            rst.shortName = repositoryGljObj.distTypeTree.distTypes[repositoryGljObj.distTypeTree.prefix + item.value].data.shortName;
+                        }
+                    }
+                });
+            }
+            else if (setting.header[col].dataCode === 'code'){
+                if(repositoryGljObj){
+                    let gljList = repositoryGljObj.gljList,
+                        orgCode = repositoryGljObj.orgCode,
+                        isExist = false;
+                    for(let i=0; i< gljList.length; i++){
+                        if(gljList[i].code === sheet.getValue(row, col) && sheet.getValue(row, col)!== orgCode){
+                           // sheetCommonObj.lockAllCells(sheet);
+                            $('#alertText').text("输入的编号已存在,请重新输入!");
+                            $('#codeAlertBtn').click();
+                            $('#codAleConfBtn').click(function () {
+                                // me.reLockSomeCodes(sheet, 0, repositoryGljObj.currentCache.length);
+                               // sheetCommonObj.unLockAllCells(sheet);
+                                //me.reLockSomeCodes(sheet, 0, repositoryGljObj.currentCache.length);
+                                sheet.setValue(row, 0, orgCode);
+                                sheet.getCell(row, 0).formatter("@");
+                                sheet.setActiveCell(row, 0);
+                            });
+                            $('#codAleClose').click(function () {
+                                //me.reLockSomeCodes(sheet, 0, repositoryGljObj.currentCache.length);
+                                //sheetCommonObj.unLockAllCells(sheet);
+                                //me.reLockSomeCodes(sheet, 0, repositoryGljObj.currentCache.length);
+                                sheet.setValue(row, 0, orgCode);
+                                sheet.getCell(row, 0).formatter("@");
+                                sheet.setActiveCell(row, 0);
+                            });
+                            // sheet.setValue(row, col, orgCode);
+                            isExist = true
+                        }
+                    }
+                    if(!isExist){
+                        rst[setting.header[col].dataCode] = sheet.getValue(row, col);
+                    }
+                }
+                else{
+                    rst[setting.header[col].dataCode] = sheet.getValue(row, col);
+                }
+            }
+            else{
+                rst[setting.header[col].dataCode] = sheet.getValue(row, col);
+            }
+        }
+        return rst;
+    },
+    combineRationRowData: function(sheet, setting, row) {
+        var rst = {};
+        for (var col = 0; col < setting.header.length; col++) {
+            rst[setting.header[col].dataCode] = sheet.getValue(row, col);
+        }
+        return rst;
+    },
+    reLockSomeCodes: function (sheet, beginRow, endRow) {
+        sheet.suspendPaint();
+        sheet.suspendEvent();
+        let defaultStyle = new GC.Spread.Sheets.Style();
+        defaultStyle.locked = false;
+        sheet.setDefaultStyle(defaultStyle, GC.Spread.Sheets.SheetArea.viewport);
+        let unLockStyle = new GC.Spread.Sheets.Style();
+        unLockStyle.locked = false;
+        let lockStyle = new GC.Spread.Sheets.Style();
+        lockStyle.locked = true;
+        for(let row = beginRow; row < endRow; row++){
+            sheet.setStyle(row, 0, lockStyle);
+        }
+        for(let row = endRow; row < sheet.getRowCount(); row++){
+            sheet.setStyle(row, 0, unLockStyle);
+        }
+        sheet.options.isProtected = true;
+        sheet.resumePaint();
+        sheet.resumeEvent();
+    },
+    lockSomeCodes: function (sheet, beginRow, endRow) {
+        let defaultStyle = new GC.Spread.Sheets.Style();
+        defaultStyle.locked = false;
+        sheet.setDefaultStyle(defaultStyle, GC.Spread.Sheets.SheetArea.viewport);
+        let style = new  GC.Spread.Sheets.Style();
+        style.locked = true;
+        sheet.suspendPaint();
+        sheet.suspendEvent();
+        for(let i = beginRow; i < endRow; i++){
+            sheet.setStyle(i, 0, style);
+        }
+        sheet.options.isProtected = true;
+        sheet.resumePaint();
+        sheet.resumeEvent();
+    },
+    lockCodeCells: function (sheet, rowCount) {
+        sheet.suspendPaint();
+        sheet.suspendEvent();
+        let sheetRowCount = sheet.getRowCount();
+        let defaultStyle = new GC.Spread.Sheets.Style();
+        defaultStyle.locked = false;
+        sheet.setDefaultStyle(defaultStyle, GC.Spread.Sheets.SheetArea.viewport);
+        let style = new GC.Spread.Sheets.Style();
+        style.locked = true;
+        sheet.setStyle(-1, 0, style);
+        for(let i =rowCount; i<sheetRowCount; i++){
+            sheet.setStyle(i, -1, style);
+        }
+        sheet.options.isProtected = true;
+        sheet.resumePaint();
+        sheet.resumeEvent();
+    }
+};

+ 1 - 1
web/building_saas/glj/js/composition.js

@@ -25,7 +25,7 @@ $(document).ready(function() {
             }
 
             // 筛选数据显示(显示混凝土、砂浆、配合比)
-            projectGLJSheet.filterData('unit_price.type', [GLJTypeConst.CONCRETE, GLJTypeConst.MORTAR, GLJTypeConst.MIX_RATIO]);
+            projectGLJSheet.filterData('unit_price.type', [GLJTypeConst.CONCRETE, GLJTypeConst.MORTAR, GLJTypeConst.MIX_RATIO,GLJTypeConst.MAIN_MATERIAL]);
 
             projectGLJSheet.selectRow(projectGLJSpread.firstMixRatioRow);
             projectGLJId = projectGLJSheet.getActiveDataByField('id');

+ 2 - 2
web/building_saas/glj/js/composition_spread.js

@@ -275,8 +275,8 @@ CompositionSpread.prototype.getCompositionSumPrice = function(scene, affectRow,
         parentBasePrice += operationWithRound(consumption,basePrice,"glj.unitPrice","*");
     }
 
-    parentMarketPrice = parentMarketPrice.toDecimal(2);
-    parentBasePrice = parentBasePrice.toDecimal(2);
+    parentMarketPrice = parentMarketPrice.toDecimal(getDecimal("glj.unitPrice"));
+    parentBasePrice = parentBasePrice.toDecimal(getDecimal("glj.unitPrice"));
 
     return [parentMarketPrice, parentBasePrice]
 };

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

@@ -417,6 +417,7 @@ function filterProjectGLJ(jsonData) {
     return jsonData;
 }
 
+
 function sortProjectGLJ(jsonData) {
     if (jsonData.length > 0) {
         jsonData = _.sortByAll(jsonData, [function (item) {

+ 7 - 1
web/building_saas/glj/js/project_glj_spread.js

@@ -44,10 +44,12 @@ ProjectGLJSpread.prototype.init = function () {
         {name: '名称', field: 'name', visible: true,width:160},
         {name: '规格型号', field: 'specs', visible: true,width:120},
         {name: '单位', field: 'unit', visible: true,width:45},
-        {name: '类型', field: 'unit_price.short_name', visible: true,width:45},
+        {name: '类型', field: 'short_name', visible: true,width:45},
         {name: 'ID', field: 'id', visible: false},
         {name: '类型', field: 'unit_price.type', visible: false},
         {name: '总消耗量', field: 'quantity', visible: true,width:100,decimalField:'glj.quantity'},
+        {name: '分部分项总消耗量', field: 'subdivisionQuantity', visible: false,width:100,decimalField:'glj.quantity'},
+        {name: '技术措施项目总消耗量', field: 'techQuantity', visible: false,width:100,decimalField:'glj.quantity'},
         {name: '定额价', field: "base_price", visible: true,width:70,decimalField:"glj.unitPrice",validator: 'number'},//这里feiedID设置是为了在计不计取价差的时候做显示用
         {name: '调整价', field: 'adjust_price', visible: true,width:70,decimalField:"glj.unitPrice"},
         {name: '市场价', field: "unit_price.market_price", visible: true, validator: 'number',width:70,decimalField:"glj.unitPrice"},
@@ -281,10 +283,14 @@ ProjectGLJSpread.prototype.specialColumn = function (sourceData) {
     let connectCodeColumn = this.sheetObj.getFieldColumn('connect_code');
     let consumptionColumn = this.sheetObj.getFieldColumn('consumption');
     let supplyColumn = this.sheetObj.getFieldColumn('supply');
+    let shortNameColumn = this.sheetObj.getFieldColumn('short_name');
     let supplyQuantity = this.sheetObj.getFieldColumn('supply_quantity');
     let activeSheet = this.sheetObj.getSheet();
 
+
     for (let data of sourceData) {
+        //设置类型名称:
+        activeSheet.setValue(rowCounter, shortNameColumn,projectObj.project.projectGLJ.getShortNameByID(data.unit_price.type));
         // 只有材料才显示是否暂估
         if (materialIdList.indexOf(data.unit_price.type) < 0) {
             let string = new GC.Spread.Sheets.CellTypes.Text();

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

@@ -557,7 +557,7 @@
     </div>    
     <!--弹出列设置-->
     <div class="modal fade" id="column" data-backdrop="static">
-        <div class="modal-dialog modal-lg" role="document">
+        <div class="modal-dialog modal-lg" role="document" style="width: 350px;">
             <div class="modal-content">
                 <div class="modal-header">
                     <h5 class="modal-title"><i class="fa fa-table"></i> 列设置</h5>
@@ -574,9 +574,9 @@
         </div>
     </div>
     <!--工料机选择窗口-->
-    <div class="modal fade" id="glj_tree_div" data-backdrop="static">
+    <!--<div class="modal fade" id="glj_tree_div" data-backdrop="static">
         <div class="modal-dialog modal-lg" role="document" id="modalCon">
-            <div class="modal-content" >
+            <div class="modal-content" style="width: 910px;">
                 <div class="modal-header">
                     <h5 class="modal-title">请选择工料机</h5>
                     <button type="button" class="close" data-dismiss="modal" aria-label="Close">
@@ -586,8 +586,50 @@
                 </div>
                 <div class="modal-body">
                     <div class="row">
-                        <div class="col-4">
-                            <div  class="modal-auto-height" id="componentTreeDiv" style="overflow: hidden">
+                        <div class="col-4" >
+                            <div  class="modal-auto-height" id="componentTreeDiv" style="overflow: hidden;">
+                                &lt;!&ndash;<div class="print-list">&ndash;&gt;
+                                <div style="width: 100%; height: 100%; overflow: auto">
+                                    <ul id="gljTree" class="ztree"></ul>
+                                </div>
+                                &lt;!&ndash;</div>&ndash;&gt;
+                            </div>
+                        </div>
+                        <div class="col-8">
+                            <div class="row">
+                                <div class="col-12" id="gljRadios">
+                                    <input type="radio" class="glj-radio" name="glj" value="allGljs" checked>所有工料机&nbsp;&nbsp;
+                                    <input type="radio" class="glj-radio" name="glj" value="stdGLJ">标准工料机&nbsp;&nbsp;
+                                    <input type="radio" class="glj-radio" name="glj" value="complementaryGLJs">补充工料机&nbsp;&nbsp;
+                                    &lt;!&ndash; <div class="form-group"><input id="searchGlj" type="text" class="form-control-sm" placeholder="查询工料机"></div>&ndash;&gt;
+                                </div>
+                                <div class="modal-auto-height col-12" style="overflow: hidden" id="gljLibSheet">
+
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" id="componentsCacnel" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                    <a href="javascript:void(0);" id="glj_selected_conf" class="btn btn-primary">确定</a>
+                </div>
+            </div>
+        </div>
+    </div>-->
+    <div class="modal fade" id="glj_tree_div" data-backdrop="static">
+        <div class="modal-dialog modal-lg" role="document" id="modalCon">
+            <div class="modal-content" style="width: 910px;">
+                <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>
+                    <input type="hidden" id="actionType">
+                </div>
+                <div class="modal-body">
+                        <div style="width: 33%; float: left;">
+                            <div  class="modal-auto-height" id="componentTreeDiv" style=" height: 415px; overflow: hidden;">
                                 <!--<div class="print-list">-->
                                 <div style="width: 100%; height: 100%; overflow: auto">
                                     <ul id="gljTree" class="ztree"></ul>
@@ -595,7 +637,7 @@
                                 <!--</div>-->
                             </div>
                         </div>
-                        <div class="col-8">
+                        <div style="width:67%; padding-left: 8px; float: left;">
                             <div class="row">
                                 <div class="col-12" id="gljRadios">
                                     <input type="radio" class="glj-radio" name="glj" value="allGljs" checked>所有工料机&nbsp;&nbsp;
@@ -608,7 +650,6 @@
                                 </div>
                             </div>
                         </div>
-                    </div>
                 </div>
                 <div class="modal-footer">
                     <button type="button" id="componentsCacnel" class="btn btn-secondary" data-dismiss="modal">取消</button>
@@ -703,6 +744,26 @@
             </div>
         </div>
     </div>
+    <!--弹出补充定额库-->
+    <div class="modal fade" id="comple-ration" data-backdrop="static">
+        <div class="modal-dialog modal-lg" 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-auto-height">
+                    <table class="table table-hover table-bordered">
+                        <thead><tr><th>定额库名称</th></tr></thead>
+                        <tbody id="comple_ration_table">
+                        </tbody>
+                    </table>
+                </div>
+            </div>
+        </div>
+    </div>
         <!-- JS. -->
         <script type="text/javascript" src="/lib/spreadjs/sheets/gc.spread.sheets.all.10.0.1.min.js"></script>
 
@@ -824,6 +885,8 @@
         <script type="text/javascript" src="/web/building_saas/main/js/views/sub_fee_rate_views.js"></script>
         <script type="text/javascript" src="/web/building_saas/main/js/views/calc_base_view.js"></script>
         <script type="text/javascript" src="/web/building_saas/main/js/views/project_property_labour_coe_view.js"></script>
+        <script type="text/javascript" src="/web/building_saas/complementary_ration_lib/js/main.js"></script>
+         <script type="text/javascript" src="/public/web/storageUtil.js"></script>
         <!-- endinject -->
 
         <script type="text/javascript">

+ 0 - 49
web/building_saas/main/js/calc/calc_fees.js

@@ -1,38 +1,6 @@
 /**
  * Created by Mai on 2017/7/21.
  */
-
-let feeType = [
-    // {type: 'common', name: '工程造价'},
-    // {type: 'baseLabour', name: '基价人工费'},
-    // {type: 'material', name: '材料费'},
-    // {type: 'machine', name: '机械费'},
-    // {type: 'rationDirect', name: '定额直接费'},
-    // {type: 'manage', name: '企业管理费'},
-    // {type: 'profit', name: '利润'},
-    // {type: 'risk', name: '风险费'},
-
-// 以下标准由缪佩玲提供
-    {type: 'direct', name: '直接费'},
-    {type: 'labour', name: '人工费'},
-    {type: 'material', name: '材料费'},
-    {type: 'machine', name: '机械费'},
-    {type: 'mainMaterial', name: '主材费'},
-    {type: 'equipment', name: '设备费'},
-    {type: 'manage', name: '企业管理费'},
-    {type: 'profit', name: '利润'},
-    {type: 'risk', name: '风险费'},
-    {type: 'labourDiff', name: '人工价差'},
-    {type: 'materialDiff', name: '材料价差'},
-    {type: 'machineDiff', name: '机械价差'},
-    {type: 'common', name: '工程造价'},
-    {type: 'adjustLabour', name: '调整人工费'},
-    {type: 'adjustMachineLabour', name: '调整机上人工费'},
-    {type: 'zangu', name: '暂估'},
-    // 模拟用户新增
-    {type: 'fee1', name: '甲供材料费'}
-];
-
 let calcFees = {
     findFee: function (data, fieldName) {
         if (!data.fees) {
@@ -107,22 +75,5 @@ let calcFees = {
                 };
             }
         }
-    },
-    // CSL,2017.08.28
-    feeTypeToName: function (type) {
-        for (let ft of feeType) {
-            if (ft.type === type) {
-                return ft.name;
-            };
-        };
-    },
-
-    feeNameToType: function (name) {
-        for (let ft of feeType) {
-            if (ft.name === name) {
-                return ft.type;
-            };
-        };
-        return '';
     }
 }

+ 46 - 4
web/building_saas/main/js/controllers/project_controller.js

@@ -23,7 +23,6 @@ ProjectController = {
     },
     addBills: function (project, sheetController, std) {
         if (!project || !sheetController) { return null; }
-
         let target = project.getParentTarget(project.mainTree.selected, 'sourceType', project.Bills.getSourceType());
         let newSource = null, newNode = null, parentID, nextSiblingID;
         if (target) {
@@ -54,6 +53,50 @@ ProjectController = {
             this.syncDisplayNewNode(sheetController, newNode);
         }
     },
+    addRootBill:function (project, sheetController) {//添加大项费用
+        if (!project || !sheetController) { return null; }
+        this.addSpecialBill(project, sheetController,null, null,true,billType.DXFY);
+    },
+    addFB:function(project, sheetController) {//添加分部
+        if (!project || !sheetController) { return null; }
+        let selected = project.mainTree.selected;
+        if(selected.parent==null&&isFlag(selected.data)&&selected.data.flagsIndex.fixed.flag==fixedFlag.SUB_ENGINERRING){//选中的是分部分项,则插入做为最后一个子项
+            this.addSpecialBill(project, sheetController,selected, null,true,billType.FB);
+        }
+        if(selected.parent){
+            this.addSpecialBill(project, sheetController,selected.parent, selected.nextSibling,true,billType.FB);
+        }
+
+    },
+    addFX:function(project, sheetController) {//添加分项
+        if (!project || !sheetController) { return null; }
+        let selected = project.mainTree.selected;
+        if(selected.data.type==billType.FB||(selected.parent==null&&isFlag(selected.data)&&selected.data.flagsIndex.fixed.flag==fixedFlag.SUB_ENGINERRING)){//选中的是分部或者是分部分项工程,则插入做为最后一个子项
+            this.addSpecialBill(project, sheetController,selected, null,true,billType.FX);
+        }
+        if(selected.parent){
+            if(selected.data.type==billType.FX){
+                this.addSpecialBill(project, sheetController,selected.parent, selected.nextSibling,true,billType.FX);
+            }
+        }
+    },
+    addSpecialBill(project,sheetController,parent,nextSibling,isUserAdd,type){
+        let newSource = null, newNode = null;
+        let b_nexID = nextSibling==null?-1:nextSibling.source.getID();//主树和清单树,对应的树节点ID不一样
+        let m_nexID = nextSibling==null?-1:nextSibling.getID();
+        let b_parent = parent==null?-1:parent.source.getID();
+        let m_parent = parent==null?-1:parent.getID();
+
+        newSource = project.Bills.insertSpecialBill(b_parent, b_nexID,isUserAdd,type);
+        newNode = project.mainTree.insert(m_parent,m_nexID);
+        if (newNode) {
+            newNode.source = newSource;
+            newNode.sourceType = project.Bills.getSourceType();
+            newNode.data = newSource.data;
+            this.syncDisplayNewNode(sheetController, newNode);
+        }
+    },
+
     addRation: function (project, sheetController, rationType, std) {
         if (!project || !sheetController) { return; }
 
@@ -63,8 +106,8 @@ ProjectController = {
         if (selected.sourceType === project.Bills.getSourceType() && selected.depth() > 0) {
             if (selected.source.children.length > 0) {
                 alert('当前清单已有清单子项,不能套用定额。');
-            } else if (false) {
-                alert('当前清单已有公式计算,不能套用定额。');
+            } else if (selected.data.calcBase&&selected.data.calcBase!="") {
+                alert('当前有基数计算不能插入定额/量价/工料机。');
             } else {
                 if (std) {
                     newSource = project.Ration.insertStdRation(selected.source.getID(), null, std);
@@ -72,7 +115,6 @@ ProjectController = {
                 } else {
                     newSource = project.Ration.insertRation(selected.source.getID(),null, rationType);
                 }
-
                 newNode = project.mainTree.insert(selected.getID(), selected.tree.rootID());
             }
         } else if (selected.sourceType === project.Ration.getSourceType()) {

+ 88 - 4
web/building_saas/main/js/models/bills.js

@@ -118,7 +118,7 @@ var Bills = {
 
         // 提交数据后的错误处理方法
         bills.prototype.doAfterUpdate = function(err, data){
-            console.log(data)
+            // console.log(data)
             if(data.quantityRefresh){
                 this.refreshDatas(data,'quantity');
             }
@@ -150,12 +150,31 @@ var Bills = {
             }
             return updateData;
         };
+        bills.prototype.insertSpecialBill=function(parentId, nextSiblingId,isUserAdd,type){
+            var insertData = this.tree.getInsertData(parentId, nextSiblingId);
+            var that = this, newData = null;
+            insertData.forEach(function (data) {
+                if (data.type === idTree.updateType.new) {
+                    if(isUserAdd==true){//如果是用户新增的
+                        data.data.isAdd = 1;
+                    }
+                    data.data.type = type;
+                    newData = data.data;
+                }
+            });
+            this.project.pushNow('insertBills', [this.getSourceType(), this.project.projCounter()],
+                [ tools.coverseTreeUpdateData(insertData, this.project.ID()), this.getCounterData()]);
+            //project.pushNow('insertBills', ModuleNames.bills, tools.coverseTreeUpdateData(insertData));
 
+            this.datas.push(newData);
+            return this.tree.insertByData(newData,parentId, nextSiblingId);
+        };
         bills.prototype.insertBills = function (parentId, nextSiblingId) {
             var insertData = this.tree.getInsertData(parentId, nextSiblingId);
             var that = this, newData = null;
             insertData.forEach(function (data) {
                 if (data.type === idTree.updateType.new) {
+                    data.data.type = billType.BILL;
                     newData = data.data;
                 }
             });
@@ -164,7 +183,7 @@ var Bills = {
             //project.pushNow('insertBills', ModuleNames.bills, tools.coverseTreeUpdateData(insertData));
 
             this.datas.push(newData);
-            return this.tree.insert(parentId, nextSiblingId);
+            return this.tree.insertByData(newData,parentId, nextSiblingId);
         };
         bills.prototype.insertStdBills = function (parentId, nextSiblingId, stdBillsData) {
             var insertData = this.tree.getInsertData(parentId, nextSiblingId);
@@ -184,6 +203,7 @@ var Bills = {
                     data.data.jobContentText = stdBillsData.jobContentText;
                     data.data.itemCharacterText = stdBillsData.itemCharacterText;
                     data.data.programID = stdBillsData.engineering;
+                    data.data.type = billType.BILL;//插入清单类型
                     //zhong
                     newData = data.data;
                 }
@@ -328,7 +348,6 @@ var Bills = {
             this.project.pushNow('replaceBills', this.getSourceType(), updateData);
             return node;            
         };
-
         bills.prototype.sameStdCodeBillsData = function (stdCode) {
             let reg = new RegExp('^' + stdCode);
             for (let data of this.datas) {
@@ -337,8 +356,73 @@ var Bills = {
                 }
             }
             return null;            
-        }
+        };
 
+        bills.prototype.getSubdivisionProjectLeavesID=function () {//取所有分部分项工程清单叶子节点ID
+            let roots = projectObj.project.mainTree.roots;//所有根节点
+            let subdivisionNode = null;
+            for(let r of roots){
+               if(isFlag(r.data)&&r.data.flagsIndex.fixed.flag==fixedFlag.SUB_ENGINERRING) {
+                   subdivisionNode = r;
+                   break;
+               }
+            }
+            let nodes = this.getLeavesBillNodes(subdivisionNode);
+            return  _.map(nodes,"data.ID");
+        };
+
+
+        bills.prototype.getTechLeavesID=function () {//取所有分计算技术措施项目清单叶子节点ID
+            let items = projectObj.project.mainTree.roots;//所有节点;
+            let techNode = null;
+            for(let item of items){
+                if(isFlag(item.data)&&item.data.flagsIndex.fixed.flag==fixedFlag.CONSTRUCTION_TECH){
+                    techNode = item;
+                    break;
+                }
+            }
+            let nodes = this.getLeavesBillNodes(techNode);
+            return  _.map(nodes,"data.ID");
+        };
+        bills.prototype.getLeavesBillNodes = function (rnode) {//取该节点下的所有清单叶子节点
+            let leaves = [];
+            getLeaves(rnode,leaves);
+            return leaves;
+
+            function  getLeaves(node,children) {
+                if(node){
+                    if(node.source.children.length>0){
+                        for(let c of node.children){
+                            getLeaves(c,children)
+                        }
+                    }else {
+                        children.push(node);
+                    }
+                }
+            }
+        };
+        bills.prototype.getRootNode = function (node) {
+            if(node.parent){
+                return this.getRootNode(node.parent)
+            }else {
+                return node
+            }
+        };
+        bills.prototype.isFBFX = function (node) {//判读是否属于分部分项
+           let rootNode = this.getRootNode(node);
+            if(isFlag(rootNode.data)&&rootNode.data.flagsIndex.fixed.flag==fixedFlag.SUB_ENGINERRING){
+                return true
+            }else {
+                return false
+            }
+        };
         return new bills(project);
     }
 };
+function isDef(v) {
+    return v !== undefined && v !== null;
+}
+
+function isFlag(v) {
+    return this.isDef(v.flagsIndex) && this.isDef(v.flagsIndex.fixed);
+}

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

@@ -380,7 +380,6 @@ var cacheTree = {
             }
             return success;
         };
-
         return new Tree(owner);
     }
 };

+ 216 - 104
web/building_saas/main/js/models/calc_base.js

@@ -1,47 +1,7 @@
 /**
  * Created by Zhong on 2017/11/28.
  */
-//清单固定行
-const fixedFlag = {
-    // 分部分项工程
-    SUB_ENGINERRING: 1,
-    // 措施项目
-    MEASURE: 2,
-    // 施工技术措施项目
-    CONSTRUCTION_TECH: 3,
-    // 安全文明施工按实计算费用
-    SAFETY_CONSTRUCTION_ACTUAL: 4,
-    // 施工组织措施专项费用
-    CONSTRUCTION_ORGANIZATION: 5,
-    // 安全文明施工专项费用
-    SAFETY_CONSTRUCTION: 6,
-    // 其他项目
-    OTHER: 7,
-    // 暂列金额
-    PROVISIONAL: 8,
-    // 暂估价
-    ESTIMATE: 9,
-    // 材料(工程设备)暂估价
-    MATERIAL_PROVISIONAL: 10,
-    // 专业工程暂估价
-    ENGINEERING_ESITIMATE: 11,
-    // 计日工
-    DAYWORK: 12,
-    // 总承包服务费
-    TURN_KEY_CONTRACT: 13,
-    // 索赔与现场签证
-    CLAIM_VISA: 14,
-    // 规费
-    CHARGE: 15,
-    // 社会保险费及住房公积金 Social insurance fee and housing accumulation fund
-    SOCIAL_INSURANCE_HOUSING_FUND: 16,
-    // 工程排污费 charges for disposing pollutants
-    POLLUTANTS: 17,
-    // 税金
-    TAX: 18,
-    //工程造价
-    ENGINEERINGCOST: 19
-};
+
 
 let cbTools = {
     isDef: function (v) {
@@ -70,6 +30,38 @@ let cbTools = {
             }
         }
     },
+    //通过行获取根节点清单
+    getBillByRow: function (items, row) {
+        if(cbTools.isDef(items[row]) &&
+            cbTools.isUnDef(items[row]['parent'])&&
+            cbTools.isDef(items[row]['sourceType']) &&
+            items[row]['sourceType'] === calcBase.project.Bills.getSourceType()){
+            return items[row];
+        }
+        return null;
+    },
+    //获取该节点所有父节点
+    getParents: function (node) {
+        let rst = [];
+        rParent(node);
+        return rst;
+        function rParent(node){
+            if(cbTools.isDef(node.parent)){
+                rst.push(node.parent);
+                rParent(node.parent);
+            }
+        }
+    },
+    //获取所有节点的ID
+    getNodeIDs: function (nodes) {
+        let rst = [];
+        for(let i = 0, len = nodes.length; i < len; i++){
+            if(this.isDef(nodes[i]['data']['ID'])){
+                rst.push(nodes[i]['data']['ID']);
+            }
+        }
+        return rst;
+    },
     //需要用到计算基数的时候,先找出所有的固定清单,避免每个基数都要去遍历寻找清单
     setFixedBills: function (project, billsObj, fixedFlag) {
         let bills = project.Bills.datas;
@@ -190,20 +182,28 @@ let cbTools = {
             return tempBases;
         }
         else {
+            //获取基数和行引用
             getBase(node);
             let bases = Array.from(new Set(tempBases));
+            //根据基数和行引用获取清单ID
             for(let i = 0, len = bases.length; i < len; i++){
-                if(cbTools.isDef(calcBase.baseFigures[bases[i]])){
-                    block.push(calcBase.baseFigures[bases[i]]['fixedBill']['bill']['ID']);
+                if(bases[i]['type'] === 'base' && cbTools.isDef(calcBase.baseFigures[bases[i]['value']])){
+                    block.push(calcBase.baseFigures[bases[i]['value']]['fixedBill']['bill']['ID']);
+                }
+                else if(bases[i]['type'] === 'row'){
+                    let node = cbTools.getBillByRow(calcBase.project.mainTree.items, bases[i]['value'] - 1);
+                    if(cbTools.isDef(node)){
+                        block.push(node.data.ID);
+                    }
                 }
             }
             return Array.from(new Set(block));
         }
         function getBase(node){
             if(node && node.children.length === 0){
-                if(cbTools.isDef(node.data.calcBase)){
-                    let figures = cbParser.getFigure(node.data.calcBase);
-                    tempBases = tempBases.concat(figures);
+                if(cbTools.isDef(node.data.calcBase) && node.data.calcBase !== ''){
+                    let figureF = cbParser.getFigureF(cbParser.getFigure(node.data.calcBase), cbParser.getRArr(cbParser.getFArr(node.data.calcBase)));
+                    tempBases = tempBases.concat(figureF);
                 }
             }
             else if(node && node.children.length > 0) {
@@ -228,52 +228,52 @@ let baseFigureTemplate = {
         let bill = calcBase.fixedBills[calcBase.fixedFlag.SUB_ENGINERRING]['bill'];
         if(cbTools.isUnDef(bill)) return 0;
         if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
-        return bill.feesIndex.common.totalFee || 0;
+        return cbTools.isDef(bill.feesIndex.common) && cbTools.isDef(bill.feesIndex.common.totalFee) ? bill.feesIndex.common.totalFee : 0;
     },
     'FBFXDEJJRGF': function () {
         let bill = calcBase.fixedBills[calcBase.fixedFlag.SUB_ENGINERRING]['bill'];
         if(cbTools.isUnDef(bill)) return 0;
         if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
-        return bill.feesIndex.labour.totalFee || 0;
+        return cbTools.isDef(bill.feesIndex.labour) && cbTools.isDef(bill.feesIndex.labour.totalFee) ? bill.feesIndex.labour.totalFee : 0;
     },
     'FBFXDEJJCLF': function () {
         let bill = calcBase.fixedBills[calcBase.fixedFlag.SUB_ENGINERRING]['bill'];
         if(cbTools.isUnDef(bill)) return 0;
         if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
-        return bill.feesIndex.material.totalFee || 0;
+        return cbTools.isDef(bill.feesIndex.material) && cbTools.isDef(bill.feesIndex.material.totalFee) ? bill.feesIndex.material.totalFee : 0;
     },
     'FBFXDEJJJXF': function () {
         let bill = calcBase.fixedBills[calcBase.fixedFlag.SUB_ENGINERRING]['bill'];
         if(cbTools.isUnDef(bill)) return 0;
         if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
-        return bill.feesIndex.machine.totalFee || 0;
+        return cbTools.isDef(bill.feesIndex.machine) && cbTools.isDef(bill.feesIndex.machine.totalFee) ? bill.feesIndex.machine.totalFee : 0;
     },
     'FBFXTZRGF': function () {
         let bill = calcBase.fixedBills[calcBase.fixedFlag.SUB_ENGINERRING]['bill'];
         if(cbTools.isUnDef(bill)) return 0;
         if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
-        return bill.feesIndex.adjustLabour.totalFee || 0;
+        return cbTools.isDef(bill.feesIndex.adjustLabour) && cbTools.isDef(bill.feesIndex.adjustLabour.totalFee) ? bill.feesIndex.adjustLabour.totalFee : 0;
     },
     'FBFXTZJSRGF': function () {
         let bill = calcBase.fixedBills[calcBase.fixedFlag.SUB_ENGINERRING]['bill'];
         if(cbTools.isUnDef(bill)) return 0;
         if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
-        return bill.feesIndex.adjustMachineLabour.totalFee || 0;
+        return cbTools.isDef(bill.feesIndex.adjustMachineLabour) && cbTools.isDef(bill.feesIndex.adjustMachineLabour.totalFee) ? bill.feesIndex.adjustMachineLabour.totalFee : 0;
     },
     'FBFXZCF': function () {
         let bill = calcBase.fixedBills[calcBase.fixedFlag.SUB_ENGINERRING]['bill'];
         if(cbTools.isUnDef(bill)) return 0;
         if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
-        return bill.feesIndex.mainMaterial.totalFee || 0;
+        return cbTools.isDef(bill.feesIndex.mainMaterial) && cbTools.isDef(bill.feesIndex.mainMaterial.totalFee) ? bill.feesIndex.mainMaterial.totalFee : 0;
     },
     'FBFXSBF': function () {
         let bill = calcBase.fixedBills[calcBase.fixedFlag.SUB_ENGINERRING]['bill'];
         if(cbTools.isUnDef(bill)) return 0;
         if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
-        return bill.feesIndex.mainMaterial.totalFee || 0;
+        return cbTools.isDef(bill.feesIndex.equipment) && cbTools.isDef(bill.feesIndex.equipment.totalFee) ? bill.feesIndex.equipment.totalFee : 0;
     },
     'FBFXWJJCLF': function () {
-        return 0;
+        return (this['FBFXZCF']() + this['FBFXSBF']()).toDecimal(decimalObj.bills.totalPrice);
     },
     'FBFXRGGR': function () {
         return 0;
@@ -285,13 +285,13 @@ let baseFigureTemplate = {
         let bill = calcBase.fixedBills[calcBase.fixedFlag.MEASURE]['bill'];
         if(cbTools.isUnDef(bill)) return 0;
         if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
-        return bill.feesIndex.common.totalFee || 0;
+        return cbTools.isDef(bill.feesIndex.common) && cbTools.isDef(bill.feesIndex.common.totalFee) ? bill.feesIndex.common.totalFee : 0;
     },
     'ZZCSXMF': function () {
         let bill = calcBase.fixedBills[calcBase.fixedFlag.CONSTRUCTION_ORGANIZATION]['bill'];
         if(cbTools.isUnDef(bill)) return 0;
         if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
-        return bill.feesIndex.common.totalFee || 0;
+        return cbTools.isDef(bill.feesIndex.common) && cbTools.isDef(bill.feesIndex.common.totalFee) ? bill.feesIndex.common.totalFee : 0;
     },
     'ZZCSXMDEJJZJGCF': function () {
         return (this['ZZCSXMDEJJRGF']() + this['ZZCSXMDEJJCLF']() + this['ZZCSXMDEJJJXF']()).toDecimal(decimalObj.bills.totalPrice);
@@ -300,67 +300,70 @@ let baseFigureTemplate = {
         let bill = calcBase.fixedBills[calcBase.fixedFlag.CONSTRUCTION_ORGANIZATION]['bill'];
         if(cbTools.isUnDef(bill)) return 0;
         if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
-        return bill.feesIndex.labour.totalFee || 0;
+        return cbTools.isDef(bill.feesIndex.labour) && cbTools.isDef(bill.feesIndex.labour.totalFee) ? bill.feesIndex.labour.totalFee : 0;
     },
     'ZZCSXMDEJJCLF': function () {
         let bill = calcBase.fixedBills[calcBase.fixedFlag.CONSTRUCTION_ORGANIZATION]['bill'];
         if(cbTools.isUnDef(bill)) return 0;
         if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
-        return bill.feesIndex.material.totalFee || 0;
+        return cbTools.isDef(bill.feesIndex.material) && cbTools.isDef(bill.feesIndex.material.totalFee) ? bill.feesIndex.material.totalFee : 0;
     },
     'ZZCSXMDEJJJXF': function () {
         let bill = calcBase.fixedBills[calcBase.fixedFlag.CONSTRUCTION_ORGANIZATION]['bill'];
         if(cbTools.isUnDef(bill)) return 0;
         if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
-        return bill.feesIndex.machine.totalFee || 0;
+        return cbTools.isDef(bill.feesIndex.machine) && cbTools.isDef(bill.feesIndex.machine.totalFee) ? bill.feesIndex.machine.totalFee : 0;
     },
     'JSCSXMF': function () {
         let bill = calcBase.fixedBills[calcBase.fixedFlag.CONSTRUCTION_TECH]['bill'];
         if(cbTools.isUnDef(bill)) return 0;
         if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
-        return bill.feesIndex.common.totalFee || 0;
+        return cbTools.isDef(bill.feesIndex.common) && cbTools.isDef(bill.feesIndex.common.totalFee) ? bill.feesIndex.common.totalFee : 0;
     },
     'JSCSXMDEJJRGF': function () {
         let bill = calcBase.fixedBills[calcBase.fixedFlag.CONSTRUCTION_TECH]['bill'];
         if(cbTools.isUnDef(bill)) return 0;
         if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
-        return bill.feesIndex.labour.totalFee || 0;
+        return cbTools.isDef(bill.feesIndex.labour) && cbTools.isDef(bill.feesIndex.labour.totalFee) ? bill.feesIndex.labour.totalFee : 0;
     },
     'JSCSXMDEJJCLF': function () {
         let bill = calcBase.fixedBills[calcBase.fixedFlag.CONSTRUCTION_TECH]['bill'];
         if(cbTools.isUnDef(bill)) return 0;
         if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
-        return bill.feesIndex.material.totalFee || 0;
+        return cbTools.isDef(bill.feesIndex.material) && cbTools.isDef(bill.feesIndex.material.totalFee) ? bill.feesIndex.material.totalFee : 0;
     },
     'JSCSXMDEJJJXF': function () {
         let bill = calcBase.fixedBills[calcBase.fixedFlag.CONSTRUCTION_TECH]['bill'];
         if(cbTools.isUnDef(bill)) return 0;
         if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
-        return bill.feesIndex.machine.totalFee || 0;
+        return cbTools.isDef(bill.feesIndex.machine) && cbTools.isDef(bill.feesIndex.machine.totalFee) ? bill.feesIndex.machine.totalFee : 0;
     },
     'JSCSXMTZRGF': function () {
         let bill = calcBase.fixedBills[calcBase.fixedFlag.CONSTRUCTION_TECH]['bill'];
         if(cbTools.isUnDef(bill)) return 0;
         if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
-        return bill.feesIndex.adjustLabour.totalFee || 0;
+        return cbTools.isDef(bill.feesIndex.adjustLabour) && cbTools.isDef(bill.feesIndex.adjustLabour.totalFee) ? bill.feesIndex.adjustLabour.totalFee : 0;
     },
     'JSCSXMTZJSRGF': function () {
         let bill = calcBase.fixedBills[calcBase.fixedFlag.CONSTRUCTION_TECH]['bill'];
         if(cbTools.isUnDef(bill)) return 0;
         if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
-        return bill.feesIndex.adjustMachineLabour.totalFee || 0;
+        return cbTools.isDef(bill.feesIndex.adjustMachineLabour) && cbTools.isDef(bill.feesIndex.adjustMachineLabour.totalFee) ? bill.feesIndex.adjustMachineLabour.totalFee : 0;
     },
     'JSCSXMZCF': function () {
         let bill = calcBase.fixedBills[calcBase.fixedFlag.CONSTRUCTION_TECH]['bill'];
         if(cbTools.isUnDef(bill)) return 0;
         if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
-        return bill.feesIndex.mainMaterial.totalFee || 0;
+        return cbTools.isDef(bill.feesIndex.mainMaterial) && cbTools.isDef(bill.feesIndex.mainMaterial.totalFee) ? bill.feesIndex.mainMaterial.totalFee : 0;
     },
     'JSCSXMSBF': function () {
-        return 0;
+        let bill = calcBase.fixedBills[calcBase.fixedFlag.CONSTRUCTION_TECH]['bill'];
+        if(cbTools.isUnDef(bill)) return 0;
+        if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
+        return cbTools.isDef(bill.feesIndex.equipment) && cbTools.isDef(bill.feesIndex.equipment.totalFee) ? bill.feesIndex.equipment.totalFee : 0;
     },
     'JSCSXMWJJCLF': function () {
-        return 0;
+        return (this['JSCSXMZCF']() + this['JSCSXMSBF']()).toDecimal(decimalObj.bills.totalPrice);
     },
     'JSCSXMRGGR': function () {
         return 0;
@@ -372,19 +375,19 @@ let baseFigureTemplate = {
         let bill = calcBase.fixedBills[calcBase.fixedFlag.OTHER]['bill'];
         if(cbTools.isUnDef(bill)) return 0;
         if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
-        return bill.feesIndex.common.totalFee || 0;
+        return cbTools.isDef(bill.feesIndex.common) && cbTools.isDef(bill.feesIndex.common.totalFee) ? bill.feesIndex.common.totalFee : 0;
     },
     'GF': function () {
         let bill = calcBase.fixedBills[calcBase.fixedFlag.CHARGE]['bill'];
         if(cbTools.isUnDef(bill)) return 0;
         if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
-        return bill.feesIndex.common.totalFee || 0;
+        return cbTools.isDef(bill.feesIndex.common) && cbTools.isDef(bill.feesIndex.common.totalFee) ? bill.feesIndex.common.totalFee : 0;
     },
     'SJ': function () {
         let bill = calcBase.fixedBills[calcBase.fixedFlag.TAX]['bill'];
         if(cbTools.isUnDef(bill)) return 0;
         if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
-        return bill.feesIndex.common.totalFee || 0;
+        return cbTools.isDef(bill.feesIndex.common) && cbTools.isDef(bill.feesIndex.common.totalFee) ? bill.feesIndex.common.totalFee : 0;
     }
 };
 
@@ -435,12 +438,23 @@ let cbAnalyzer = {
     },
     //输入合法性
     inputLegal: function (exp) {
-        let ilegalRex = /[^0-9,\u4e00-\u9fa5,\+,\-,\/,\*,\(,\),.]/g;
+        let ilegalRex = /[^0-9,\u4e00-\u9fa5,\+,\-,\/,\*,\(,\),.,{,},F]/g;
         return !ilegalRex.test(exp);
     },
     //基数合法性、存在性
     baseLegal: function (baseFigures, exp) {
+        //保证中文表达式在{}里
+        let cnExps = cbParser.getCN(exp);
         let expFigures = cbParser.getFigure(exp);
+        if(cnExps.length !== expFigures.length){
+            return false;
+        }
+        for(let i = 0, len = cnExps.length; i < len; i++){
+            if(cnExps[i] !== expFigures[i]){
+                return false;
+            }
+        }
+        //基数存在性
         for(let i = 0, len = expFigures.length; i < len; i++){
             if(cbTools.isUnDef(baseFigures[expFigures[i]])){
                 return false;
@@ -448,29 +462,56 @@ let cbAnalyzer = {
         }
         return true;
     },
+    //行引用合法性、存在性
+    fLegal: function (items, exp) {
+        //提取行引用
+        let fArr = cbParser.getFArr(exp);
+        //提取行数
+        let rArr = cbParser.getRArr(fArr);
+        //判断合法性和存在性
+        for(let i = 0, len = rArr.length; i < len; i++){
+            let idx = rArr[i] - 1;
+            if(cbTools.isUnDef(cbTools.getBillByRow(items, idx))){
+                calcBase.errMsg = '行引用不合法';
+                return false;
+            }
+        }
+        return true;
+    },
     //循环计算
     cycleCalc: function (node, baseFigures, exp) {
         let stack = [];
         if(node.sourceType !== calcBase.project.Bills.getSourceType()){
             return false;
         }
-        let sbillID = cbTools.getBaseBill(node).data.ID;
-        let expFigures = cbParser.getFigure(exp);
-        for(let i = 0, len = expFigures.length; i < len; i++){
-            let figure = expFigures[i];
-            if(cbTools.isDef(baseFigures[figure])){
-                let bill = baseFigures[figure]['fixedBill']['bill'];
-                if(checkStack(getRefStack([bill.ID]), sbillID)){
-                    console.log('循环计算');
-                    calcBase.errMsg = '表达式出现循环计算';
-                    return true;
-                }
+        //用于判断的起始清单ID
+        let sIDs = cbTools.getNodeIDs(Array.from(new Set([cbTools.getBaseBill(node)].concat(cbTools.getParents(node)))));
+        let figureF = cbParser.getFigureF(cbParser.getFigure(exp), cbParser.getRArr(cbParser.getFArr(exp)));
+        for(let i = 0, len = figureF.length; i < len; i++){
+            let figure = figureF[i];
+            let bill = null;
+            if(figure.type === 'base' && cbTools.isDef(baseFigures[figure.value])){
+                bill = baseFigures[figure.value]['fixedBill']['bill'];
+            }
+            else if(figure.type === 'row'){
+                let tempBill = cbTools.getBillByRow(calcBase.project.mainTree.items, figure.value - 1);
+                bill = cbTools.isDef(tempBill) ? tempBill.data : null;
+            }
+            if(cbTools.isDef(bill) && checkStack(getRefStack([bill.ID]), sIDs)){
+                console.log('循环计算');
+                calcBase.errMsg = '表达式出现循环计算';
+                return true;
             }
         }
         return false;
-        function checkStack(stack, startBillID){
+        function checkStack(stack, sIDs){
             //引用栈发现了初始引用
-            return stack.indexOf(startBillID) !== -1;
+            for(let i = 0, len = sIDs.length; i < len; i++){
+                if(stack.indexOf(sIDs[i]) !== -1){
+                    return true;
+                }
+            }
+            return false;
         }
         function getRefStack(billIDs){
             stack = Array.from(new Set(stack.concat(billIDs)));
@@ -484,23 +525,27 @@ let cbAnalyzer = {
             return stack;
         }
     },
-    //四则运算合法性,前端控制不允许重复出现运算符,这里主要判断()的使用问题,这里再判断一次
-    arithmeticLeagl: function (exp) {
+    //四则运算合法性,前端控制不允许重复出现运算符,这里主要判断()的使用问题,这里再判断一次,控制行引用只能F
+    arithmeticLegal: function (exp) {
         let ilegalRex = /[\+,\-,\*,\/]{2}/g;
-        return !ilegalRex.test(exp);
+        let rex2 = /[{]{2}/g;
+        let rex3 = /[}]{2}/g;
+        let rex4 = /[F]{2}/g
+        return !ilegalRex.test(exp) && !rex2.test(exp) && !rex3.test(exp) && !rex4.test(exp);
     },
     //
     legalExp: function (node) {
         let exp = this.standar(node.data.userCalcBase);
         if(this.inputLegal(exp)){
             if(this.baseLegal(cbTools.getFigure(node), exp)){
-                if(!this.cycleCalc(node, cbTools.getFigure(node), exp)){
-                    if(this.arithmeticLeagl(exp)){
-                        return exp;
+                if(this.fLegal(calcBase.project.mainTree.items, exp)){
+                    if(!this.cycleCalc(node, cbTools.getFigure(node), exp)){
+                        if(this.arithmeticLegal(exp)){
+                            return exp;
+                        }
                     }
                 }
             }
-            return null;
         }
         return null;
     }
@@ -508,8 +553,24 @@ let cbAnalyzer = {
 
 //输入式转换器
 let cbParser = {
-    //获取表达式中的基数
-    getFigure: function(expr){
+    //获取行引用 eg: F10
+    getFArr: function (exp) {
+        let fRex = /F\d+/g;
+        let fArr = exp.match(fRex);
+        return cbTools.isDef(fArr) ? fArr : [];
+    },
+    //获取行 eg: F10  10
+    getRArr: function (fArr) {
+        let rRex = /\d+/g;
+        let tempArr = [];
+        for(let i = 0, len = fArr.length; i < len; i++){
+            tempArr = tempArr.concat(fArr[i].match(rRex));
+        }
+        let rArr = Array.from(new Set(tempArr));
+        return rArr;
+    },
+    //获取表达式中的中文式,没有{}需求时
+    getCN: function(expr){
         let rst = [];
         let cnRex = /[^\u4e00-\u9fa5]/;
         let temp = expr.split(cnRex);
@@ -520,12 +581,42 @@ let cbParser = {
         }
         return rst;
     },
+    //获取表达式中的基数
+    getFigure: function(expr){
+        let rst = [];
+        let rex = /\{([^}]*)\}/g;
+        let temp = expr.match(rex);
+        if(cbTools.isDef(temp)){
+            for(let i = 0, len = temp.length; i < len; i++){
+                rst.push(temp[i].replace(/[{,}]/g, ''));
+            }
+        }
+        return rst;
+    },
+    //获取表达式中的基数和行
+    getFigureF: function (figures, rArr) {
+        let rst = [];
+        for(let i = 0, len = figures.length; i < len; i++){
+            let obj = Object.create(null);
+            obj.type = 'base';
+            obj.value = figures[i];
+            rst.push(obj);
+        }
+        for(let i = 0, len = rArr.length; i < len; i++){
+            let obj = Object.create(null);
+            obj.type = 'row';
+            obj.value = rArr[i];
+            rst.push(obj);
+        }
+        return rst;
+    },
 
     //将表达式转换为可编译的表达式
     toCompileExpr: function(v){
         if(v === ''){
             return '$CBC.base(\'NONE\')';
         }
+        //基数
         let strs = this.getFigure(v);
         let exps = [];
         for(let i = 0, len = strs.length; i < len; i++){
@@ -533,10 +624,23 @@ let cbParser = {
             exp.orgExp = strs[i];
             exps.push(exp);
         }
+        //去{}
+        v = v.replace(/[{, }]/g, '');
         for(let i = 0, len = exps.length;i < len; i++){
-            exps[i].compileExp = '$CBC.base(\'' + exps[i].orgExp;
-            exps[i].compileExp = exps[i].compileExp + '\')';
-            v = v.replace(new RegExp(exps[i].orgExp,"g"), exps[i].compileExp);
+            exps[i].compileExp = '$CBC.base(\'' + exps[i].orgExp + '\')';
+            v = v.replace(new RegExp(exps[i].orgExp, 'g'), exps[i].compileExp);
+        }
+        //行引用
+        let fArr = this.getFArr(v);
+        let fExps = [];
+        for(let i = 0, len = fArr.length; i < len; i++){
+            let fExp = Object.create(null);
+            fExp.orgExp = fArr[i];
+            fExps.push(fExp);
+        }
+        for(let i = 0, len = fExps.length; i < len; i++){
+            fExps[i].compileExp = '$CBC.f(\'' + fExps[i].orgExp + '\')';
+            v = v.replace(new RegExp(fExps[i].orgExp, 'g'), fExps[i].compileExp);
         }
         return v;
     }
@@ -550,6 +654,14 @@ let cbCalctor = {
         }
         return baseFigureTemplate[calcBase.baseFigures[figure]['base']]();
     },
+    //行引用
+    f: function (fExp) {
+        let r = cbParser.getRArr([fExp]);
+        return cbTools.isDef(calcBase.project.mainTree.items[r[0] - 1]['data']['feesIndex']) &&
+            cbTools.isDef(calcBase.project.mainTree.items[r[0] - 1]['data']['feesIndex']['common'])&&
+            cbTools.isDef(calcBase.project.mainTree.items[r[0] - 1]['data']['feesIndex']['common']['totalFee']) ?
+            calcBase.project.mainTree.items[r[0] - 1]['data']['feesIndex']['common']['totalFee'] : 0;
+    },
     //计算
     exec: function () {
 
@@ -586,7 +698,7 @@ let calcBase = {
     getBaseBill: function (node) {
         return cbTools.getBaseBill(node);
     },
-    calculate: function (node) {
+    calculate: function (node, reCalc = null) {
         let me = calcBase,
             $CBA = cbAnalyzer,
             $CBP = cbParser,
@@ -595,14 +707,16 @@ let calcBase = {
             me.success = false;
             me.errMsg = '表达式不正确';
             //分析输入式合法性
-            let exp = $CBA.legalExp(node);
+            let exp = reCalc
+                ? cbTools.isDef(node.data.calcBase)
+                    ? node.data.calcBase
+                    : ''
+                : $CBA.legalExp(node);
             if(!cbTools.isDef(exp)){
                 throw '表达式不正确';
             }
-
             //输入式转换表达式
             let compileExp = $CBP.toCompileExpr(exp);
-
             //计算
             let calcBaseValue = eval(compileExp);
             if(!cbTools.isNum(calcBaseValue)){
@@ -613,8 +727,6 @@ let calcBase = {
             me.success = true;
             node.data.calcBase = exp;
             node.data.calcBaseValue = parseFloat(calcBaseValue).toDecimal(decimalObj.decimal('totalPrice', node));
-           /* me.project.calcProgram.calculate(node);
-            me.project.calcProgram.saveNode(node);*/
         }
         catch (err){
             alert(me.errMsg);

+ 284 - 166
web/building_saas/main/js/models/calc_program.js

@@ -6,7 +6,8 @@
  *  用到费率的规则必须有feeRateID属性,当有该属性时,会自动显示费率值。
  */
 
-/*let defaultBillTemplate = {
+/*  新版GLD 取消了默认清单模板,所以这里废弃。先留着,预防不时之需。
+let defaultBillTemplate = {
     ID: 15,
     name: "清单公式",
     calcItems: [
@@ -150,6 +151,27 @@ let rationCalcBase = [
     }
 ];
 
+let cpFeeTypes = [
+    {type: 'direct', name: '直接费'},
+    {type: 'labour', name: '人工费'},
+    {type: 'material', name: '材料费'},
+    {type: 'machine', name: '机械费'},
+    {type: 'mainMaterial', name: '主材费'},
+    {type: 'equipment', name: '设备费'},
+    {type: 'manage', name: '企业管理费'},
+    {type: 'profit', name: '利润'},
+    {type: 'risk', name: '风险费'},
+    {type: 'labourDiff', name: '人工价差'},
+    {type: 'materialDiff', name: '材料价差'},
+    {type: 'machineDiff', name: '机械价差'},
+    {type: 'adjustLabour', name: '调整人工费'},
+    {type: 'adjustMachineLabour', name: '调整机上人工费'},
+    {type: 'zangu', name: '暂估'},
+    {type: 'fee1', name: '甲供材料费'},
+    // 模拟用户新增
+    {type: 'common', name: '工程造价'}
+];
+
 let analyzer = {
     calcTemplate: null,
     success: true,
@@ -321,12 +343,12 @@ let executeObj = {
                 for (let glj of me.treeNode.data.gljList) {
                     if (glj.type == gljType.GENERAL_MACHINE) {
                         // 获取机械组成物
-                        let mds = projectObj.project.composition.getCompositionByCode(glj.code);
+                        let mds = projectObj.project.composition.getCompositionByGLJ(glj);
                         if (!mds) mds = [];
                         for (let md of mds){
-                            if (base.gljTypes.indexOf(md.glj_type) >= 0) {
+                            if (base.gljTypes.indexOf(md.type) >= 0) {
                                 let q = md["consumption"] ? md["consumption"] : 0;
-                                let p = md["base_price"] ? md["base_price"] : 0;
+                                let p = md["basePrice"] ? md["basePrice"] : 0;
                                 mdSum = mdSum + (q * p).toDecimal(decimalObj.process);
                                 mdSum = (mdSum).toDecimal(decimalObj.process);
                             }
@@ -363,7 +385,7 @@ let executeObj = {
                 };
                 return result;
             };
-            // 量价没有具体的工料机类型,但仍然要用定额的计算程序,所以要给计算基数直接指定。
+            // 量价没有具体的工料机类型,但仍然要用定额的计算程序,所以要给计算基数直接指定。
             function volumePriceFee() {
                 let result = 0;
                 if (
@@ -399,6 +421,134 @@ let executeObj = {
     }
 };
 
+let treeNodeTools = {
+    // 获取全部有公式的树节点清单
+    getFormulaNodes: function () {
+        let nodes = [];
+        for (let node of projectObj.project.mainTree.items){
+              if (node.sourceType == ModuleNames.bills && node.data.calcBase && node.data.calcBase != '')
+                  nodes.push(node);
+        };
+
+        if (nodes.length >= 2) return this.orderFormulaNodes(nodes)
+        else return nodes;
+    },
+
+    // 给公式结点清单换照引用计算顺序排序。
+    orderFormulaNodes: function (nodesArr) {
+        let orderArr = [];
+
+        function getNodesByExp(expression){
+            // for test --------------
+            function getNode(name) {
+                for (let node of projectObj.project.mainTree.items){
+                    if (node.data.name == name)
+                        return node;
+                };
+            };
+
+            if (expression.hasSubStr("{措施项目费}")){
+                let node = getNode('措施项目');
+                return [node];
+            }
+
+            else if (expression.hasSubStr("{技术措施项目费}")){
+                let node = getNode('1.技术措施项目');
+                return [node];
+            }
+            // -------------------------------
+
+            return [];
+        };
+
+        function recursionNode(nodes) {
+            for (let node of nodes){
+                if (orderArr.includes(node)) continue;    // 已排过序的节点则跳过
+
+                if (node.data.calcBase){
+                    let subNodes = getNodesByExp(node.data.calcBase);
+                    recursionNode(subNodes);
+                };
+
+                if (nodesArr.includes(node) && !orderArr.includes(node)) orderArr.push(node);
+            };
+        }
+
+        recursionNode(nodesArr);
+        return orderArr;
+    },
+
+    isBill: function(treeNode){
+        return treeNode.sourceType === ModuleNames.bills;
+    },
+    isLeafBill: function(treeNode){
+        return treeNode.sourceType === ModuleNames.bills &&
+            treeNode.source.children &&
+            treeNode.source.children.length === 0;
+    },
+    isNullBill: function (treeNode) {
+        return this.isLeafBill(treeNode) && (treeNode.children.length === 0) && (!treeNode.data.calcBase);
+    },
+
+    isRationCategory: function(treeNode){
+        return treeNode.sourceType === ModuleNames.ration;
+    },
+    isRation: function(treeNode){
+        return treeNode.sourceType === ModuleNames.ration && treeNode.data.type === rationType.ration;
+    },
+    isVolumePrice: function (treeNode) {
+        return treeNode.sourceType === ModuleNames.ration && treeNode.data.type === rationType.volumePrice;
+    },
+    isGljRation: function (treeNode) {
+        return treeNode.sourceType === ModuleNames.ration && treeNode.data.type === rationType.gljRation;
+    },
+
+    initFeeField(treeNode, fieldName){
+        if (!treeNode.data.fees) {
+            treeNode.data.fees = [];
+            treeNode.data.feesIndex = {};
+        };
+        if (!treeNode.data.feesIndex[fieldName]) {
+            let fee = {
+                'fieldName': fieldName,
+                'unitFee': 0,
+                'totalFee': 0,
+                'tenderUnitFee': 0,
+                'tenderTotalFee': 0
+            };
+            treeNode.data.fees.push(fee);
+            treeNode.data.feesIndex[fieldName] = fee;
+        };
+    },
+
+    getCalcType(treeNode) {
+        if (this.isRationCategory(treeNode)){
+            return treeNodeCalcType.ctRationCalcProgram;
+        }
+        else if (this.isNullBill(treeNode)){
+            return treeNodeCalcType.ctCommonUnitFee;
+        }
+        else if (this.isLeafBill(treeNode)) {
+            if (treeNode.children && treeNode.children.length > 0){
+                // 清单单价计算模式下的叶子清单:取自己的计算程序ID,找到自己的计算程序计算。(汇总清单所有定额的工料机)
+                if (projectObj.project.property.billsCalcMode === leafBillGetFeeType.billsPrice)
+                    return treeNodeCalcType.ctBillCalcProgram;
+                else                                        // 前三种计算模式下的叶子清单:汇总定额的计算程序的费用类别
+                    return treeNodeCalcType.ctGatherRationsFees;
+            }
+            else{                                          // 公式计算
+                return treeNodeCalcType.ctCalcBaseValue;
+            };
+        }
+        else if (this.isBill(treeNode)) {                              // 父清单:汇总子清单的费用类别
+            return treeNodeCalcType.ctGatherBillsFees;
+        }
+        else {
+            return treeNodeCalcType.ctRationCalcProgram;
+        };
+    }
+};
+
 class CalcProgram {
     constructor(project){
         let me = this;
@@ -407,15 +557,18 @@ class CalcProgram {
         project.registerModule(ModuleNames.calc_program, me);
     };
 
+    // 兼容Project框架方法
     getSourceType () {
         return ModuleNames.calc_program;
     };
 
+    // 兼容Project框架方法
     loadData (datas) {
         this.datas = datas;
         this.compileAllTemps();
     };
 
+    // 兼容Project框架方法
     doAfterUpdate (err, data) {
         if(!err){
             $.bootstrapLoading.end();
@@ -437,7 +590,7 @@ class CalcProgram {
 
         me.feeRates = this.project.FeeRate.datas.rates;
         me.labourCoes = this.project.labourCoe.datas.coes;
-        me.feeTypes = feeType;
+        me.feeTypes = cpFeeTypes;
         me.calcBases = rationCalcBase;
         me.templates = this.project.calcProgram.datas.templates;
 
@@ -594,52 +747,63 @@ class CalcProgram {
         };
     };
 
-    isLeafBill(treeNode){
-        let me = this;
-        return treeNode.sourceType === me.project.Bills.getSourceType() &&
-               treeNode.source.children &&
-               treeNode.source.children.length === 0;
-    };
+    // 存储、刷新零散的多个结点。
+    saveNodes(treeNodes){
+        if (treeNodes.length < 1) return;
 
-    isNullBill(treeNode){
         let me = this;
-        return me.isLeafBill(treeNode) && (treeNode.children.length ===0) && (!treeNode.data.calcBase);
-    };
 
-    isRation(treeNode){
-        return treeNode.sourceType === ModuleNames.ration && treeNode.data.type === rationType.ration;
-    };
+        me.project.beginUpdate('');
+        for (let node of treeNodes){
+            if (node.changed){
+                let data = {
+                    ID: node.data.ID,
+                    projectID: me.project.ID(),
+                    unit:node.data.unit,//对清单来说,改变单位,工程量精度会跟着改变从而影响计算。
+                    /*  subType、quantity、calcBase、programID、marketUnitFee等等字段较为特殊,它们的改变一定会触发计算并导致计算
+                    结果的变化,从而引发保存动作。将这些字段放在该位置跟计算结果一起保存,可减少前端跟后端的通讯频率。              */
+                    subType: node.data.subType,
+                    quantity: node.data.quantity,
+                    calcBase: node.data.calcBase,
+                    calcBaseValue: node.data.calcBaseValue,
+                    programID: node.data.programID,
+                    marketUnitFee: node.data.marketUnitFee,
+                    marketTotalFee: node.data.marketTotalFee,
+                    fees: node.data.fees,
+                    isFromDetail:node.data.isFromDetail,
+                    feeRate: node.data.feeRate,
+                    feeRateID: node.data.feeRateID,
+                    contain:node.data.contain,
+                    quantityEXP:node.data.quantityEXP
+                };
+                if(node.sourceType==ModuleNames.ration && node.data.type==rationType.gljRation){//定额类型的工料机做特殊处理
+                    data.code=node.data.code;
+                    data.projectGLJID = node.data.projectGLJID;
+                    delete data.marketUnitFee;
+                }
 
-    isVolumePrice(treeNode){
-        return treeNode.sourceType === ModuleNames.ration && treeNode.data.type === rationType.volumePrice;
-    };
+                let newData = {'updateType': 'ut_update', 'updateData': data};
+                me.project.push(node.sourceType, [newData]);
+            }
+        };
+        me.project.endUpdate();
 
-    isGljRation(treeNode){
-        return treeNode.sourceType === ModuleNames.ration && treeNode.data.type === rationType.gljRation;
-    };
+        for (let node of treeNodes){delete node.changed};
+        projectObj.mainController.refreshTreeNode(treeNodes);
 
-    initFeeField(treeNode, fieldName){
-        if (!treeNode.data.fees) {
-            treeNode.data.fees = [];
-            treeNode.data.feesIndex = {};
-        };
-        if (!treeNode.data.feesIndex[fieldName]) {
-            let fee = {
-                'fieldName': fieldName,
-                'unitFee': 0,
-                'totalFee': 0,
-                'tenderUnitFee': 0,
-                'tenderTotalFee': 0
-            };
-            treeNode.data.fees.push(fee);
-            treeNode.data.feesIndex[fieldName] = fee;
+        if (activeSubSheetIs(subSheetIndex.ssiCalcProgram)) {
+            calcProgramObj.showData(me.project.mainTree.selected, false);
         };
     };
 
-  // 仅内部调用。注意:外部不能直接使用,因为这里传入的树节点必须有一定的初始化
-    InnerCalc(treeNode){
+    // 只计算treeNode自身。changedArr: 外部传来的一个数组,专门存储发生变动的节点。
+    innerCalc(treeNode, changedArr){
         let me = this;
-        let project = me.project;
+        // 仅用作树节点显示的工料机不能参与计算。
+        if (treeNode.sourceType === me.project.ration_glj.getSourceType()) return;
+
+        treeNode.calcType = treeNodeTools.getCalcType(treeNode);
+        // if (treeNode.calcType == treeNodeCalcType.ctCalcBaseValue) return;
 
         function initFees(treeNode){
             if (!treeNode.data.fees) {
@@ -681,14 +845,15 @@ class CalcProgram {
             return ['labour', 'material', 'machine', 'mainMaterial', 'equipment'].indexOf(type) > -1;
         };
 
-        // 汇总定额或子清单的费用类别
-        if (treeNode.calcType == treeNodeCalcType.ctGatherRationsFees || treeNode.calcType == treeNodeCalcType.ctGatherBillsFees){
+        // 父清单汇总子项(定额或子清单)的费用类别
+        if (treeNode.calcType == treeNodeCalcType.ctGatherRationsFees ||
+            treeNode.calcType == treeNodeCalcType.ctGatherBillsFees){
             treeNode.data.programID = null;
             initFees(treeNode);
 
-            let objsArr = (treeNode.calcType == treeNodeCalcType.ctGatherRationsFees) ? project.Ration.getRationsByNode(treeNode) : treeNode.children;
+            let objsArr = (treeNode.calcType == treeNodeCalcType.ctGatherRationsFees) ? me.project.Ration.getRationsByNode(treeNode) : treeNode.children;
             let rst = [];
-            for (let ft of feeType) {
+            for (let ft of cpFeeTypes) {
                 let ftObj = {};
                 ftObj.fieldName = ft.type;
                 ftObj.name = ft.name;
@@ -768,7 +933,7 @@ class CalcProgram {
 
             delete treeNode.data.fees;    // 直接删掉再新增,不用一个个费判断更新,效率更高。
             delete treeNode.data.feesIndex;
-            me.initFeeField(treeNode, 'common');
+            treeNodeTools.initFeeField(treeNode, 'common');
             treeNode.data.feesIndex.common.unitFee = uf.toDecimal(decimalObj.bills.unitPrice);
             treeNode.data.feesIndex.common.totalFee = tf.toDecimal(decimalObj.bills.totalPrice);
             treeNode.data.feesIndex.common.tenderUnitFee = tuf.toDecimal(decimalObj.bills.unitPrice);
@@ -776,13 +941,14 @@ class CalcProgram {
             treeNode.changed = true;
             treeNode.data.calcTemplate = {"calcItems": []};
         }
-        // 叶子清单的计算基数计算
+        // 叶子清单公式计算
         else if (treeNode.calcType == treeNodeCalcType.ctCalcBaseValue){
             delete treeNode.data.gljList;
             if (treeNode.data.programID) treeNode.data.programID = null;
 
             let f = treeNode.data.feeRate ? treeNode.data.feeRate : 100;
-            let q = treeNode.data.quantity ? treeNode.data.quantity : 0;
+            if (!treeNode.data.quantity) treeNode.data.quantity = 1;
+            let q = treeNode.data.quantity;
             let b = treeNode.data.calcBaseValue ? treeNode.data.calcBaseValue : 0;
             let uf = (b * f * q / 100).toDecimal(decimalObj.bills.unitPrice);
             let tuf = uf;
@@ -791,7 +957,7 @@ class CalcProgram {
 
             delete treeNode.data.fees;    // 直接删掉再新增,不用一个个费判断更新,效率更高。
             delete treeNode.data.feesIndex;
-            me.initFeeField(treeNode, 'common');
+            treeNodeTools.initFeeField(treeNode, 'common');
             treeNode.data.feesIndex.common.unitFee = uf;
             treeNode.data.feesIndex.common.totalFee = tf;
             treeNode.data.feesIndex.common.tenderUnitFee = tuf;
@@ -799,7 +965,7 @@ class CalcProgram {
             treeNode.changed = true;
             treeNode.data.calcTemplate = {"calcItems": []};
         }
-        // 定额或清单自己的计算程序计算
+        // 定额或叶子清单自己的计算程序计算
         else{
             if (treeNode.calcType == treeNodeCalcType.ctRationCalcProgram) {
                 if (treeNode.data.type == rationType.volumePrice){
@@ -820,10 +986,9 @@ class CalcProgram {
                 };
             }
             else if (treeNode.calcType == treeNodeCalcType.ctBillCalcProgram) {
-                let rations = project.Ration.getBillsSortRation(treeNode.source.getID());
-                treeNode.data.gljList = project.ration_glj.getGatherGljArrByRations(rations);
+                let rations = me.project.Ration.getBillsSortRation(treeNode.source.getID());
+                treeNode.data.gljList = me.project.ration_glj.getGatherGljArrByRations(rations);
 
-                // if (treeNode.data.programID == undefined || treeNode.data.programID == defaultBillTemplate.ID){
                 if (treeNode.data.programID == undefined){
                     treeNode.data.programID = projectInfoObj.projectInfo.property.engineering;
                 }
@@ -857,102 +1022,34 @@ class CalcProgram {
                 };
             }
         };
-    };
-
-    // 计算本节点(默认同时递归计算所有父节点,可选)
-    calculate(treeNode, calcParents = true){
-        let me = this;
-        if (treeNode.sourceType === me.project.ration_glj.getSourceType()) return;     // 仅用作树节点显示的工料机不能参与计算。
-        let isRation = treeNode.sourceType === me.project.Ration.getSourceType();
-        let isBill = treeNode.sourceType === me.project.Bills.getSourceType();
 
-        if (isRation){
-            treeNode.calcType = treeNodeCalcType.ctRationCalcProgram;
-        }
-        else  if (me.isNullBill(treeNode)){
-            treeNode.calcType = treeNodeCalcType.ctCommonUnitFee;
-        }
-        else if (me.isLeafBill(treeNode)) {
-            if (treeNode.children && treeNode.children.length > 0){
-                // 清单单价计算模式下的叶子清单:取自己的计算程序ID,找到自己的计算程序计算。(汇总清单所有定额的工料机)
-                if (me.project.property.billsCalcMode === leafBillGetFeeType.billsPrice)
-                    treeNode.calcType = treeNodeCalcType.ctBillCalcProgram;
-                else                                        // 前三种计算模式下的叶子清单:汇总定额的计算程序的费用类别
-                    treeNode.calcType = treeNodeCalcType.ctGatherRationsFees;
-            }
-            else{                                          // 公式计算
-                treeNode.calcType = treeNodeCalcType.ctCalcBaseValue;
-            };
-        }
-        else if (isBill)                                 // 父清单:汇总子清单的费用类别
-            treeNode.calcType = treeNodeCalcType.ctGatherBillsFees;
-
-        me.InnerCalc(treeNode);
-
-        // 计算所有父结点
-        if (treeNode.changed && calcParents && treeNode.parent) {
-            me.calculate(treeNode.parent);
-        };
+        if (treeNode.changed && !changedArr.includes(treeNode)) changedArr.push(treeNode);
     };
 
-    // 存储、刷新本节点(默认存储刷新所有父节点,可选)
-    saveNode(treeNode, saveParents = true) {
-        if (!treeNode.changed) return;
+    // 计算本节点、所有父节点(默认,可选)、公式引用节点。
+    calculate(treeNode, calcParents = true, calcFormulas = true){
         let me = this;
-        let nodesArr = [];
-        let curNode = treeNode;
-        while (curNode) {
-            if (curNode.changed){nodesArr.push(curNode)};
-            if (saveParents) curNode = curNode.parent
-            else break;
-        };
-        me.saveNodes(nodesArr);
-    };
-
-    // 存储、刷新零散的多个树结点
-    saveNodes(treeNodes){
-        if (treeNodes.length < 1) return;
+        let changedNodes = [];
 
-        let me = this;
+        me.innerCalc(treeNode, changedNodes);
 
-        me.project.beginUpdate('');
-        for (let node of treeNodes){
-            if (node.changed){
-                let data = {
-                    ID: node.data.ID,
-                    projectID: me.project.ID(),
-                    /*  subType、quantity、calcBase、programID、marketUnitFee等等字段较为特殊,它们的改变一定会触发计算并导致计算
-                    结果的变化,从而引发保存动作。将这些字段放在该位置跟计算结果一起保存,可减少前端跟后端的通讯频率。              */
-                    subType: node.data.subType,
-                    quantity: node.data.quantity,
-                    calcBase: node.data.calcBase,
-                    calcBaseValue: node.data.calcBaseValue,
-                    programID: node.data.programID,
-                    marketUnitFee: node.data.marketUnitFee,
-                    marketTotalFee: node.data.marketTotalFee,
-                    fees: node.data.fees,
-                    isFromDetail:node.data.isFromDetail,
-                    feeRate: node.data.feeRate,
-                    feeRateID: node.data.feeRateID
+        if (treeNode.changed) {
+            // 计算父结点
+            if (calcParents){
+                let curNode = treeNode.parent;
+                while (curNode){
+                    me.innerCalc(curNode, changedNodes);
+                    curNode = curNode.parent;
                 };
-                if(node.sourceType==ModuleNames.ration && node.data.type==rationType.gljRation){//定额类型的工料机做特殊处理
-                    data.code=node.data.code;
-                    data.projectGLJID = node.data.projectGLJID;
-                    delete data.marketUnitFee;
-                }
+            };
 
-                let newData = {'updateType': 'ut_update', 'updateData': data};
-                me.project.push(node.sourceType, [newData]);
-            }
+            // 父结点算完,再计算所有的公式结点(必须先算完父结点,再算公式结点)
+            if (calcFormulas) {
+                me.calcFormulaNodes(changedNodes);
+            };
         };
-        me.project.endUpdate();
 
-        for (let node of treeNodes){delete node.changed};
-        projectObj.mainController.refreshTreeNode(treeNodes);
-
-        if (activeSubSheetIs(subSheetIndex.ssiCalcProgram)) {
-            calcProgramObj.showData(me.project.mainTree.selected, false);
-        };
+        return changedNodes;
     };
 
     /* 计算所有树结点(分3种情况),并返回发生变动的零散的多个树结点。
@@ -970,60 +1067,81 @@ class CalcProgram {
                     calcNodes(node.children);
                 };
 
-                if ((calcType == calcAllType.catAll) || (calcType == node.sourceType)) {
-                    me.calculate(node, false);
-                    if (node.changed) changedNodes.push(node);
+                if ((calcType == calcAllType.catAll || calcType == node.sourceType) && node.calcType != treeNodeCalcType.ctCalcBaseValue) {
+                    me.innerCalc(node, changedNodes);
                 };
             }
         };
 
         calcNodes(me.project.mainTree.roots);
-        // me.saveNodes(changedNodes);   保存要与计算分离,否则实际应用场景中,会产生多次通讯。
+
+        me.calcFormulaNodes(changedNodes);
         return changedNodes;
     };
 
-    // 计算叶子清单下的所有子结点(如定额、量价、工料机定额等), 并计算自身和所有父结点。最后打包存储。
+    // 计算全部公式项。 (参数意义:将通过本方法后发生改变的节点存入changedNodesArr中)
+    calcFormulaNodes(changedArr){
+        let me = this;
+        let formulaNodes = treeNodeTools.getFormulaNodes();
+        if (formulaNodes.length == 0) return;
+        for (let formulaNode of formulaNodes){
+            formulaNode.data.userCalcBase = formulaNode.data.calcBase;    // 这句不该出现,projectObj.project.calcBase中要改进。
+            projectObj.project.calcBase.calculate(formulaNode, true);
+            if (projectObj.project.calcBase.success){
+                // 计算公式结点
+                me.innerCalc(formulaNode, changedArr);
+
+                // 计算父结点
+                if (formulaNode.changed){
+                    let curNode = formulaNode.parent;
+                    while (curNode){
+                        me.innerCalc(curNode, changedArr);
+                        curNode = curNode.parent;
+                    };
+                };
+            };
+        };
+    };
+
+    // 计算叶子清单下的所有子结点、自身、所有父结点、公式引用结点(即跟该叶子清单相关的所有结点)。最后打包存储。
     calcLeafAndSave(treeNode){
         let me = this;
-        if(!me.isLeafBill(treeNode)) return;
+        if(!treeNodeTools.isLeafBill(treeNode)) return;
         if (treeNode.children && treeNode.children.length > 0) {
             let changedNodes = [];
             for (let child of treeNode.children){
-                me.calculate(child, false);
-                if (child.changed) changedNodes.push(child);
-            };
-
-            me.calculate(treeNode);
-            let cur = treeNode;
-            while (cur) {
-                if (cur.changed) changedNodes.push(cur);
-                cur = cur.parent;
+                me.innerCalc(child, changedNodes);
             };
 
+            let curChangeds = me.calculate(treeNode);
+            mergeArr(changedNodes, curChangeds);
             me.saveNodes(changedNodes);
         };
     };
 
     // 计算多条零散的定额,并计算他们所属的清单、父级清单,然后打包存储。如:批量替换工料机后受影响的定额。
     calcRationsAndSave(rationNodes){
-        let me = this, leafBills = [], changedNodes = [];
+        let me = this, leafBills = [], allChangedNodes = [];
         for (let node of rationNodes) {
-            me.calculate(node, false);
-            if (node.changed) changedNodes.push(node);
+            me.innerCalc(node, allChangedNodes);
             let leafBill = node.parent;
-            if (leafBill && leafBills.indexOf(leafBill) < 0) leafBills.push(leafBill);      // 多条定额同属一条叶子清单时,避免叶子清单重复计算
+            // 多条定额同属一条叶子清单时,避免叶子清单重复计算
+            if (leafBill && leafBills.indexOf(leafBill) < 0) leafBills.push(leafBill);
         };
 
         for (let node of leafBills){
-            me.calculate(node);
-            let cur = node;
-            while (cur) {
-                if (cur.changed && changedNodes.indexOf(cur) < 0) changedNodes.push(cur);
-                cur = cur.parent;
-            };
+            let curChangeds = me.calculate(node);
+            mergeArr(allChangedNodes, curChangeds);
         };
 
-        me.saveNodes(changedNodes);
+        me.saveNodes(allChangedNodes);
+    };
+
+    // 计算并保存指定的一个树节点。修改一个树节点,实际上要计算和保存的是一批树结点:层层父结点、被其它结点(的公式)引用的公式结点。
+    // 这个方法实际上封装了calculate()和saveNodes()两个方法,主要目的是为了外部调用方便,少写一点累赘代码。
+    calcAndSave(treeNode){
+        let changedNodes = this.calculate(treeNode);
+        this.saveNodes(changedNodes);
     };
 
 }

+ 12 - 1
web/building_saas/main/js/models/composition.js

@@ -74,4 +74,15 @@ Composition.prototype.getCompositionByCode = function(code, gljType = 0) {
     }
 
     return result;
-};
+};
+
+Composition.prototype.getCompositionByGLJ = function (glj) {
+    let mixRatioMap = projectObj.project.projectGLJ.datas.mixRatioMap;
+    let projectGljs = projectObj.project.projectGLJ.datas.gljList;
+    let connect_index = gljOprObj.getIndex(glj,gljKeyArray);
+    let gljList=[];
+    if(mixRatioMap[connect_index]){ //说明是有组成物的类型
+        gljList =  gljOprObj.getMixRationShowDatas(mixRatioMap[connect_index], projectGljs);
+    }
+    return gljList;
+}

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

@@ -348,8 +348,7 @@ var FeeRate = {
                     var rate =me.getFeeRateByID(bill.feeRateID);
                     var data=me.getfbUpdateData(rate,bill,fee_value,value);
                     if(data==null){//只更改清单的值的情况下,由计算程序更新
-                        project.calcProgram.calculate(node);
-                        project.calcProgram.saveNode(node);
+                        project.calcProgram.calcAndSave(node);
                     }
                     this.setFeeRateToBill(data,function (result) {
                         if(data.hasOwnProperty('feeRate')){

+ 58 - 4
web/building_saas/main/js/models/main_consts.js

@@ -11,7 +11,6 @@ const ModuleNames = {
     ration_coe:'ration_coe',
     ration_ass:'ration_ass',
     quantity_detail:'quantity_detail',
-    // volume_price: 'volume_price',
     labour_coe: 'labour_coe',
     calc_program: 'calc_program'
 };
@@ -51,7 +50,8 @@ const notEditType = [
     gljType.CONCRETE,
     gljType.MORTAR,
     gljType.MIX_RATIO,
-    gljType.GENERAL_MACHINE
+    gljType.GENERAL_MACHINE,
+    gljType.MAIN_MATERIAL
 ];
 
 const CP_Col_Width = {          // 多处计算程序界面的列宽统一设置
@@ -114,7 +114,6 @@ const volumePriceMaps = {
     5: "量设"
 };
 
-
 const rationType = {
     ration: 1,
     volumePrice: 2,
@@ -133,5 +132,60 @@ const zanguCalcType = {
     gatherMaterial: 1
 };
 
+//清单固定行
+const fixedFlag = {
+    // 分部分项工程
+    SUB_ENGINERRING: 1,
+    // 措施项目
+    MEASURE: 2,
+    // 施工技术措施项目
+    CONSTRUCTION_TECH: 3,
+    // 安全文明施工按实计算费用
+    SAFETY_CONSTRUCTION_ACTUAL: 4,
+    // 施工组织措施专项费用
+    CONSTRUCTION_ORGANIZATION: 5,
+    // 安全文明施工专项费用
+    SAFETY_CONSTRUCTION: 6,
+    // 其他项目
+    OTHER: 7,
+    // 暂列金额
+    PROVISIONAL: 8,
+    // 暂估价
+    ESTIMATE: 9,
+    // 材料(工程设备)暂估价
+    MATERIAL_PROVISIONAL: 10,
+    // 专业工程暂估价
+    ENGINEERING_ESITIMATE: 11,
+    // 计日工
+    DAYWORK: 12,
+    // 总承包服务费
+    TURN_KEY_CONTRACT: 13,
+    // 索赔与现场签证
+    CLAIM_VISA: 14,
+    // 规费
+    CHARGE: 15,
+    // 社会保险费及住房公积金 Social insurance fee and housing accumulation fund
+    SOCIAL_INSURANCE_HOUSING_FUND: 16,
+    // 工程排污费 charges for disposing pollutants
+    POLLUTANTS: 17,
+    // 税金
+    TAX: 18,
+    //工程造价
+    ENGINEERINGCOST: 19
+};
+
 const gljKeyArray =['code','name','specs','unit','type'];
-const gljLibKeyArray =['code', 'name', 'specs', 'unit', 'gljType']
+const rationKeyArray =['code','name','specs','unit','subType'];
+const gljLibKeyArray =['code', 'name', 'specs', 'unit', 'gljType'];
+const billType ={
+    DXFY:1,//大项费用
+    FB:2,//分部
+    FX:3,//分项
+    BILL:4//清单
+};
+const billText = {
+    1:'费用',
+    2:'分部',
+    3:'分项',
+    4:'清单'
+};

+ 97 - 5
web/building_saas/main/js/models/project_glj.js

@@ -41,6 +41,7 @@ ProjectGLJ.prototype.loadData = function (callback = null) {
                 return false;
             }
             self.datas = response.data;
+            self.calcQuantity();
             // 回调函数
             if (callback !== null) {
                 callback(response.data);
@@ -157,8 +158,10 @@ ProjectGLJ.prototype.updatePriceFromRG = function (recode, updateField, newval)
 };
 
 ProjectGLJ.prototype.updatePropertyFromMainSpread = function (node, updateField, newval) {
-    if (updateField == "contain") {
-
+    if (updateField == "contain") {//更新含量和工程量时,要走定额更新的逻辑
+        projectObj.project.Ration.updateContain(newval,node);
+    }if(updateField == "quantity"){
+        projectObj.project.quantity_detail.editMainTreeNodeQuantity(newval,node,updateField);
     } else {
         this.updateGLJProperty(node, updateField, newval);
     }
@@ -214,8 +217,7 @@ ProjectGLJ.prototype.updateGLJProperty = function (node, updateField, newval) {
         //触发计算并更新节点信息
         node.changed = true;
         projectObj.project.projectGLJ.loadData(function () {
-            projectObj.project.calcProgram.calculate(node);
-            projectObj.project.calcProgram.saveNode(node);
+            projectObj.project.calcProgram.calcAndSave(node);
             $.bootstrapLoading.end();
         });//重新加载项目工料机数据
         //上面两步都是异步操作,这句应该是要等上面两步做完了再执行的
@@ -370,7 +372,7 @@ ProjectGLJ.prototype.getAdjustPrice = function (glj) {
         //let labour=1;
         let coe = labour && labour.coe ? labour.coe : 1;
         return scMathUtil.roundTo(parseFloat(coe * scMathUtil.roundForObj(glj.unit_price.base_price,decimal)), -decimal);
-    } else if (notEditType.indexOf(glj.unit_price.type)>0) {//对于混凝土、配合比、砂浆、机械台班,调整价根据组成物计算得出。
+    } else if (notEditType.indexOf(glj.unit_price.type)>0&&glj.ratio_data.length>0) {//对于混凝土、配合比、砂浆、机械台班,调整价根据组成物计算得出。
         let p =0;
         for(let ratio of glj.ratio_data){
            let tem =  _.find( projectObj.project.projectGLJ.datas.gljList,{
@@ -394,3 +396,93 @@ ProjectGLJ.prototype.getShortNameByID = function (ID) {
     let gljTypeMap = this.datas.constData.gljTypeMap;
     return gljTypeMap["typeId" + ID].shortName;
 }
+
+ProjectGLJ.prototype.calcQuantity  = function (){
+    let project_gljs = this.datas.gljList;
+    let mixRatioConnectData = this.datas.mixRatioConnectData;
+    let mixRatioSubdivisionMap = {};
+    let mixRatioTechMap={};
+    for(let pglj of project_gljs ){
+        if(pglj.quantity !== 0 && pglj.quantity !== '0'){
+            let result = this.getQuantityPerGLJ(pglj,mixRatioSubdivisionMap,mixRatioTechMap);
+            pglj.subdivisionQuantity = result.subdivisionQuantity;
+            pglj.techQuantity = result.techQuantity;
+        }
+    }
+    //计算做为组成物的消耗量
+    for(let pg of project_gljs ){
+        if(pg.quantity !== 0 && pg.quantity !== '0'){
+            let pg_index = gljOprObj.getIndex(pg,gljKeyArray);
+            if(mixRatioConnectData[pg_index]){
+                if(mixRatioSubdivisionMap[pg_index]){
+                    pg.subdivisionQuantity = scMathUtil.roundForObj(mixRatioSubdivisionMap[pg_index]+pg.subdivisionQuantity,getDecimal("glj.quantity"));
+                }
+                if(mixRatioTechMap[pg_index]){
+                    pg.techQuantity = scMathUtil.roundForObj(mixRatioTechMap[pg_index]+pg.techQuantity,getDecimal("glj.quantity"));
+                }
+            }
+        }
+    }
+
+}
+
+ProjectGLJ.prototype.getQuantityPerGLJ =function (pglj,mixRatioSubdivisionMap,mixRatioTechMap) {
+    let billIDs =   projectObj.project.Bills.getSubdivisionProjectLeavesID();//取分部分项上的所有叶子清单ID
+    let tech_billIDS =  projectObj.project.Bills.getTechLeavesID();//取所有技术措施项目叶子清单ID
+    let ration_glj_list = projectObj.project.ration_glj.datas;
+    let mixRatioMap = this.datas.mixRatioMap;
+    let rations = projectObj.project.Ration.datas;
+    let q_decimal = getDecimal("glj.quantity");
+    let result={};
+    let sum = 0;
+    let tech_sum = 0;
+    for(let rg of ration_glj_list){
+        if(rg.projectGLJID==pglj.id){
+            if(_.includes(billIDs,rg.billsItemID)){//计算分部分项
+               let total = calcQuantity(rg,mixRatioSubdivisionMap);
+               sum = scMathUtil.roundForObj(sum+total,q_decimal);
+            }
+            if(_.includes(tech_billIDS,rg.billsItemID)){//计算技术措施项目消耗量
+                let tech_total = calcQuantity(rg,mixRatioTechMap);
+                tech_sum = scMathUtil.roundForObj(tech_sum+tech_total,q_decimal);
+            }
+        }
+
+    }
+    for(let ra of rations){//计算定额类型工料机的消耗量
+        if(ra.type == rationType.gljRation&&ra.projectGLJID===pglj.id){
+            let r_quantity = scMathUtil.roundForObj(ra.quantity,q_decimal);
+            r_quantity = r_quantity?r_quantity:0;
+            if(_.includes(billIDs,ra.billsItemID)){//计算分部分项
+                sum = scMathUtil.roundForObj(sum+r_quantity,q_decimal);
+            }
+            if(_.includes(tech_billIDS,ra.billsItemID)){//计算技术措施项目消耗量
+                tech_sum = scMathUtil.roundForObj(tech_sum+r_quantity,q_decimal);
+            }
+        }
+
+    }
+    result.subdivisionQuantity = sum;
+    result.techQuantity = tech_sum;
+    return result;
+
+    function calcQuantity(rg,quantityMap) { //计算工料机在所属定额下的总消耗量
+        let tem_ration = _.find(rations,{"ID":rg.rationID});
+        let total = parseFloat(gljOprObj.getTotalQuantity(rg,tem_ration));
+        let r_index = gljOprObj.getIndex(rg,gljKeyArray);
+        if(mixRatioMap.hasOwnProperty(r_index)){
+            let mixRatioList = mixRatioMap[r_index];
+            for(let m of mixRatioList){
+                let m_index = gljOprObj.getIndex(m,gljKeyArray);
+                let m_quantity = scMathUtil.roundForObj(total*m.consumption,q_decimal);
+                if(quantityMap[m_index]){
+                    quantityMap[m_index] = scMathUtil.roundForObj(quantityMap[m_index]+m_quantity,q_decimal);
+                }else {
+                    quantityMap[m_index] = m_quantity;
+                }
+            }
+        }
+        return total;
+    }
+
+} 

+ 113 - 5
web/building_saas/main/js/models/quantity_detail.js

@@ -146,7 +146,9 @@ var quantity_detail = {
                     me.cleanQuantityDetail();
                 }else {
                     data.newRecord?me.refreshAfterSave(data.newRecord):me.refreshAfterSave(data);
-                    data.node?gljOprObj.refreshTreeNode(data.node):"";
+                    if(data.node){
+                      me.refreshRationOrBillNodes(data.node);
+                    }
                     //gljOprObj.detailSheet.setActiveCell(0,0);
                     //gljOprObj.detailSheet.clearSelection();
                 }
@@ -156,6 +158,19 @@ var quantity_detail = {
                 $.bootstrapLoading.end();
             });
         };
+        quantity_detail.prototype.refreshRationOrBillNodes=function(node){//工程量明细更新后触发定额或清单工程量改变,进行相应的更新
+            var nodes = gljOprObj.refreshTreeNode(node);
+            if(nodes.length>0){//触发计算
+                let newNode = nodes[0];
+                if(newNode.sourceType === project.Bills.getSourceType()){
+                    console.log(newNode.data.quantity);
+                    this.updateBillQuantity(newNode.data.quantity,newNode);
+                }else {//更新定额所使用的值要用还没转换前的
+                    this.updateRationQuantity(node.data.r_quantity,newNode,newNode.data.quantityEXP);//to do 加上工程量表达式和含量更新
+                }
+            }
+        };
+
         quantity_detail.prototype.insertQuantityDetail = function (row) {
             var args = {
                 row:row,
@@ -175,7 +190,9 @@ var quantity_detail = {
                $.bootstrapLoading.start();
                var callback=function (result) {
                    me.refreshAfterDelete(result.data);
-                   result.node?gljOprObj.refreshTreeNode(result.node):"";
+                   if(result.node){//触发计算
+                       me.refreshRationOrBillNodes(result.node);
+                   }
                    $.bootstrapLoading.end();
                }
                CommonAjax.post("/quantity_detail/deleteRecode",recode,callback,function () {
@@ -315,7 +332,9 @@ var quantity_detail = {
             $.bootstrapLoading.start();
             var callback = function (data) {
                 me.refreshAfterUpdate(data);
-                data.node?gljOprObj.refreshTreeNode(data.node):"";
+                if(data.node){
+                  me.refreshRationOrBillNodes(data.node);
+                }
                 $.bootstrapLoading.end();
             }
             CommonAjax.post(url,postData,callback,function () {
@@ -489,10 +508,9 @@ var quantity_detail = {
             }
             return validate;
         };
-        quantity_detail.prototype.autoTransformQuantity = function(value,node){
+        quantity_detail.prototype.autoTransformQuantity = function(value,node){//根据单位转换定额工程量
             let data = node.data;
             let option = optionsOprObj.getOption(optionsOprObj.optionsTypes.GENERALOPTS,'rationQuanACToRationUnit');
-            console.log(option);
             if(option==true&&node.sourceType === project.Ration.getSourceType()&&data.unit) {//还需加入判读是否转换
                 let times = parseInt(data.unit);
                 if (isNaN(times)) {
@@ -502,6 +520,96 @@ var quantity_detail = {
             }
             return value;
         };
+        quantity_detail.prototype.reverseQuantity = function (value,node) {//根据单位反向运算出工程量
+            let data = node.data;
+            if(node.sourceType === project.Ration.getSourceType()&&data.unit){
+                let times = parseInt(data.unit);
+                if (isNaN(times)) {
+                    times = 1
+                }
+                value = value * times;
+            }
+            return value
+        };
+        quantity_detail.prototype.editMainTreeNodeQuantity=function (value,node,fieldName) {
+            var me = this;
+            if(isNaN(value)){
+                alert("当前输入的数据类型不正确,请重新输入");
+                projectObj.mainController.refreshTreeNode([node]);
+            }else {
+                value=value?value:0;
+                setTimeout(function () {//spreadjs事件和提示窗口会有冲突,所以要用延时的方法
+                    if(project.quantity_detail.quantityEditChecking(value,node,fieldName)){
+                        node.data.isFromDetail=0;
+                        project.quantity_detail.cleanQuantityDetail(node,true);
+                        if(node.sourceType === project.Bills.getSourceType()){
+                            me.updateBillQuantity(value,node);
+                        }else {
+                            me.updateRationQuantity(value,node);
+                        }
+                    }else {
+                        projectObj.mainController.refreshTreeNode([node]);
+                    }
+                },100);
+            }
+        };
+        quantity_detail.prototype.updateBillQuantity=function (value,node) {
+            value = scMathUtil.roundForObj(value,getDecimal("quantity",node));
+            node.data.quantity = value+"";
+            let needUpdateChildren = [];//需更新的子定额
+            let gljNodes=[];//当定额工程量改变时需刷新的子工料机
+            if(node.children.length>0){//如果有子项则
+                for(let rationNode of node.children){
+                    let EXPString = rationNode.data.quantityEXP+"";
+                    if(EXPString.indexOf("QDL")!=-1){//如果定额的工程量是通过计算出来的,则应该重新计算。
+                        let tem_contain = scMathUtil.roundForObj(rationNode.data.contain,getDecimal("process"));
+                        let tem_quantity = scMathUtil.roundForObj(value*tem_contain,getDecimal("quantity",rationNode));
+                        rationNode.data.quantity = this.autoTransformQuantity(tem_quantity,rationNode);
+                        rationNode.changed = true;
+                        needUpdateChildren.push(rationNode);
+                        if (rationNode.children.length>0){//如果有子工料机
+                            gljNodes = gljNodes.concat(rationNode.children);
+                        }
+                    }else {
+                        let tem_contain=0;
+                        if(value&&value!=0){
+                           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"));
+                        }
+                        rationNode.data.contain = tem_contain;
+                        rationNode.changed = true;
+                        needUpdateChildren.push(rationNode);
+                    }
+                }
+            }
+            if(needUpdateChildren.length>0){
+                project.calcProgram.calcRationsAndSave(needUpdateChildren);
+            }else {
+                node.changed = true;
+                project.calcProgram.calcAndSave(node);
+            }
+            if(gljNodes.length>0){
+                projectObj.mainController.refreshTreeNode(gljNodes);
+            }
+        };
+        quantity_detail.prototype.updateRationQuantity=function(value,node,quantityEXP){
+            node.data.quantityEXP = quantityEXP?quantityEXP:value;
+            value = scMathUtil.roundForObj(value,getDecimal("ration.quantity"));
+            if(node.parent.data.quantity&&node.parent.data.quantity!=0&&node.parent.data.quantity!=""){
+                var billQuantity = scMathUtil.roundForObj(node.parent.data.quantity,getDecimal("quantity",node.parent));
+                node.data.contain = scMathUtil.roundForObj(value/billQuantity,getDecimal("process"));
+            }else {
+                node.data.contain=0;
+            }
+            value = project.quantity_detail.autoTransformQuantity(value,node);
+            value = scMathUtil.roundForObj(value,decimalObj.decimal("quantity",node))
+            node.data.quantity=value;
+            node.changed = true;
+            project.calcProgram.calcAndSave(node);
+            projectObj.mainController.refreshTreeNode(node.children);//刷新子工料机总消耗量
+            gljOprObj.showRationGLJSheetData();
+        };
         quantity_detail.prototype.getDecimal=function (node) {
             var decimal = 3;
             if(node.sourceType === project.Bills.getSourceType()){

+ 36 - 4
web/building_saas/main/js/models/ration.js

@@ -253,7 +253,7 @@ var Ration = {
             let updateData = [];
             for (let node of nodes) {
                 if (node.children.length > 0) {
-                    updateData = updateData.concat(this.getDeleteDataByBills[node.children]);
+                    updateData = updateData.concat(this.getDeleteDataByBill(node.children));
                 } else {
                     let rations = this.getBillsSortRation(node.getID());
                     for (let r of rations) {
@@ -266,7 +266,7 @@ var Ration = {
         ration.prototype.deleteByBills = function (nodes) {
             for (let node of nodes) {
                 if (node.children.length > 0) {
-                    this.deleteByBills([node.children]);
+                    this.deleteByBills(node.children);
                 } else {
                     let rations = this.getBillsSortRation(node.getID());
                     for (let r of rations) {
@@ -335,13 +335,17 @@ var Ration = {
 
         ration.prototype.CalculateQuantity = function (ration) {
             // calculate ration Quantity
+            let quantity_decimal = getDecimal("ration.quantity");
+            let process_decimal = getDecimal("process");
             if (optionsOprObj.getOption(optionsOprObj.optionsTypes.GENERALOPTS, 'rationQuanACToBillsQuan')) {
                 let billsNode = this.project.Bills.tree.findNode(ration[this.project.masterField.ration]);
                 let billsQuantity = billsNode.data.quantity ? billsNode.data.quantity : 0;
+                ration.contain = 1;
+                ration.quantityEXP="QDL";
                 if (optionsOprObj.getOption(optionsOprObj.optionsTypes.GENERALOPTS, 'rationQuanACToRationUnit')) {
-                    ration.quantity = (billsQuantity / this.FilterNumberFromUnit(ration.unit)).toDecimal(4);
+                    ration.quantity = (billsQuantity / this.FilterNumberFromUnit(ration.unit)).toDecimal(quantity_decimal);
                 } else {
-                    ration.quantity = billsQuantity.toDecimal(4);
+                    ration.quantity = billsQuantity.toDecimal(quantity_decimal);
                 }
             }
         };
@@ -379,6 +383,34 @@ var Ration = {
 
             this.project.endUpdate();
         };
+        ration.prototype.updateContain=function (value,node) {
+            if(isNaN(value)){
+                alert("当前输入的数据类型不正确,请重新输入");
+                projectObj.mainController.refreshTreeNode([node]);
+                return;
+            }
+            let billNode = node.parent;
+            let contain = scMathUtil.roundForObj(value,getDecimal("process"));
+            if(node.data.quantityEXP=="GCLMXHJ"){//如果定额工程量是来自工程量明细
+                var c = confirm('已有工程量明细,是否清空明细表,采用手工输入的表达式?');
+                if(c){
+                    node.data.isFromDetail=0;
+                    project.quantity_detail.cleanQuantityDetail(node,true);
+                }else {
+                    projectObj.mainController.refreshTreeNode([node]);
+                    return;
+                }
+            }
+            let billQuantity = billNode.data.quantity||billNode.data.quantity!=""?billNode.data.quantity:0;
+            billQuantity = parseFloat(billQuantity);
+            node.data.contain = contain;
+            node.data.quantityEXP="QDL*"+contain;
+            node.data.quantity=scMathUtil.roundForObj(billQuantity*contain,getDecimal("quantity"),node);
+            node.data.quantity = projectObj.project.quantity_detail.autoTransformQuantity(node.data.quantity,node);//按单位做转换
+            node.changed = true;
+            project.calcProgram.calcAndSave(node);
+            projectObj.mainController.refreshTreeNode(node.children);//刷新子工料机树节点总消耗量
+        };
         
         return new ration(project);
     }

+ 21 - 19
web/building_saas/main/js/models/ration_glj.js

@@ -114,16 +114,16 @@ var ration_glj = {
             } else {
                 me.datas = neRecodes;
             }
-            gljOprObj.showRationGLJSheetData(true);
-            //add to mainTree;
-            me.addToMainTree(neRecodes);
-            let node = project.mainTree.selected;
-            project.calcProgram.calculate(node);
-            project.calcProgram.saveNode(node);
-            if (activeSubSheetIs(subSheetIndex.ssiCalcProgram)) {
-                calcProgramObj.showData(node, false);
-            }
-            ;
+            project.projectGLJ.loadData(function () {
+                gljOprObj.showRationGLJSheetData(true);
+                //add to mainTree;
+                me.addToMainTree(neRecodes);
+                let node = project.mainTree.selected;
+                project.calcProgram.calcAndSave(node);
+                if (activeSubSheetIs(subSheetIndex.ssiCalcProgram)) {
+                    calcProgramObj.showData(node, false);
+                }
+            });
         };
         ration_glj.prototype.addToMainTree = function (datas) {
             datas = sortRationGLJ(datas);
@@ -154,14 +154,16 @@ var ration_glj = {
         };
         ration_glj.prototype.refreshAfterUpdate = function (data) {
             var me = this;
+            var rationID=null;
             if (data.quantityRefresh) {
                 data.glj_result.forEach(function (item) {
-                    me.refreshEachItme(item.doc, item.query);
+                   rationID = me.refreshEachItme(item.doc, item.query);
                 })
             } else {
-                me.refreshEachItme(data.doc, data.query);
+                rationID =  me.refreshEachItme(data.doc, data.query);
             }
             gljOprObj.showRationGLJSheetData(true);
+            this.reCalcWhenGLJChange({rationID:rationID});
         };
         ration_glj.prototype.refreshEachItme = function (doc, query) {
             var glj_list = projectObj.project.ration_glj.datas;
@@ -367,8 +369,8 @@ var ration_glj = {
                 if (initShow == false) {//不需要初始化,只需耍新当前显示就可以了
                     gljOprObj.showRationGLJSheetData();
                 }
-                me.reCalcWhenGLJChange(recode);//触发计算定额以及父节点
                 projectObj.project.projectGLJ.loadData(function () {//等项目工料机加载完成后再给用户编辑
+                    me.reCalcWhenGLJChange(recode);//触发计算定额以及父节点
                     if (initShow == true) {
                         gljOprObj.refreshView();
                     }
@@ -492,7 +494,6 @@ var ration_glj = {
             selectedSerialNo == null ? "" : postData.selectedSerialNo = selectedSerialNo;
             $.bootstrapLoading.start();
             CommonAjax.post("/ration/insertGLJAsRation", postData, function (data) {
-                console.log(data);
                 // 更新兄弟节点的序列号
                 if (selectedSerialNo != null) {
                     let selectIndex = _.findIndex(children, {"serialNo": selectedSerialNo});
@@ -502,11 +503,12 @@ var ration_glj = {
                         }
                     }
                 }
+                let newNode=null;
                 for (let r_glj of data) {
                     r_glj.marketUnitFee = r_glj.marketPrice;
                     r_glj.quantity = r_glj.quantity + "";
                     project.Ration.datas.push(r_glj);
-                    let newNode = project.mainTree.insert(parentNodeID, nextNodeID);
+                    newNode = project.mainTree.insert(parentNodeID, nextNodeID);
                     newNode.source = r_glj;
                     newNode.sourceType = project.Ration.getSourceType();
                     newNode.data = r_glj;
@@ -515,7 +517,7 @@ var ration_glj = {
                 let parentNode = project.mainTree.nodes[project.mainTree.prefix + parentNodeID];
                 project.calcProgram.calcLeafAndSave(parentNode);//计算父级清单的所有子节点
                 //this.nodes[this.prefix + parentID];
-                callback();
+                callback(newNode);
                 $.bootstrapLoading.end();
             }, function () {
                 $.bootstrapLoading.end();
@@ -746,11 +748,11 @@ var ration_glj = {
             });
             return node;
         };
-        ration_glj.prototype.reCalcWhenGLJChange = function (ration_glj) {//当改变定额工料机时,重新计算定额以及父节点
+        ration_glj.prototype.reCalcWhenGLJChange = function (ration_glj) {//当改变定额工料机时,重新计算定额以及父节点
             let node = this.findRationNodeByID(ration_glj.rationID);
             if (node) {
-                project.calcProgram.calculate(node);
-                project.calcProgram.saveNode(node);
+                node.changed = true;
+                project.calcProgram.calcAndSave(node);
             }
         };
         return new ration_glj(project);

+ 9 - 8
web/building_saas/main/js/views/calc_base_view.js

@@ -8,7 +8,6 @@ let calcBaseView = {
     //可用计算基数的清单固定列映射(与fixedFlag)
     inputExpr: $('#calcBaseExp'),
     confirmBtn: $('#calcBaseConf'),
-    noBaseBills: [1, 3],
     editingCell: null,
     workBook: null,
     setting:{
@@ -24,7 +23,6 @@ let calcBaseView = {
             allowUserDragFill: false,
             scrollbarMaxAlign : true
         },
-        dateRows: [],
         locked: {
             rows: [],
             cols: [0, 1]
@@ -96,7 +94,7 @@ let calcBaseView = {
     onCellDoubleClick: function (sender, args) {
         let me = calcBaseView;
         if(args.col === 0){
-            let baseFigure = args.sheet.getValue(args.row, args.col);
+            let baseFigure = '{' + args.sheet.getValue(args.row, args.col) + '}';
             if(baseFigure.trim() !== ''){
                 //在光标后面插入
                 let insertStr = me.insertStr(baseFigure);
@@ -138,7 +136,7 @@ let calcBaseView = {
         }
         me.buildSheet();
         let baseObj = projectObj.project.calcBase.getBaseByClass(node);
-        console.log(baseObj);
+        // console.log(baseObj);
         me.showData(me.toViewData(baseObj));
 
     },
@@ -148,9 +146,12 @@ let calcBaseView = {
     },
 
     //四则运算符控制,不可连续出现: ++ +*...
-    arithmeticLeagl: function (v) {
+    arithmeticLegal: function (v) {
         let rex = /[\+,\-,\*,\/]{2}/g;
-        return !rex.test(v);
+        let rex2 = /[{]{2}/g;
+        let rex3 = /[}]{2}/g;
+        let rex4 = /[F]{2}/g;
+        return !rex.test(v) && !rex2.test(v) && !rex3.test(v) && !rex4.test(v);
     },
 
     //运算符点击显示到运算窗口
@@ -160,7 +161,7 @@ let calcBaseView = {
             operators[i].bind('click', function () {
                 let v = $(this)[0].textContent;
                 let insertStr = me.insertStr(v);
-                if(me.arithmeticLeagl(insertStr)){
+                if(me.arithmeticLegal(insertStr)){
                     me.inputExpr.val(insertStr);
                 }
                 me.inputExpr.focus();
@@ -184,7 +185,7 @@ let calcBaseView = {
     inputControl: function () {
         let me = calcBaseView;
         me.inputExpr.keydown(function (e) {
-            if(!me.arithmeticLeagl(me.inputExpr.val() + e.key)){
+            if(!me.arithmeticLegal(me.inputExpr.val() + e.key)){
                 return false;
             }
         });

+ 1 - 2
web/building_saas/main/js/views/calc_program_view.js

@@ -43,8 +43,7 @@ let calcProgramObj = {
         var me = this;
         me.treeNode = treeNode;
         if (needCalc){
-            projectObj.project.calcProgram.calculate(treeNode);
-            projectObj.project.calcProgram.saveNode(treeNode);
+            projectObj.project.calcProgram.calcAndSave(treeNode);
         };
         me.datas = treeNode.data.calcTemplate ? treeNode.data.calcTemplate.calcItems : [];
         sheetCommonObj.initSheet(me.sheet, me.setting, me.datas.length);

+ 54 - 42
web/building_saas/main/js/views/character_content_view.js

@@ -78,27 +78,31 @@ let contentOprObj = {
         sheet.addRows(sheet.getRowCount(), 1);
         sheet.getCell(sheet.getRowCount() - 1, 1).cellType(checkBox);
     },
-    upMove: function (rowIdx) {
+    upMove: function (cell) {
         let me = contentOprObj;
-        let thisObj = me.currentCache[rowIdx],
-            preObj = me.currentCache[rowIdx - 1],
+        let thisObj = me.currentCache[cell.row],
+            preObj = me.currentCache[cell.row - 1],
             temp, contentTxt;
         temp = thisObj.serialNo;
         thisObj.serialNo = preObj.serialNo;
         preObj.serialNo = temp;
         me.sortCache(me.currentCache);
-        me.save();
+        me.save(function () {
+            me.workBook.getSheet(0).setActiveCell(cell.row - 1, cell.col);
+        });
     },
-    downMove: function (rowIdx) {
+    downMove: function (cell) {
         let me = contentOprObj;
-        let thisObj = me.currentCache[rowIdx],
-            nextObj = me.currentCache[rowIdx + 1],
+        let thisObj = me.currentCache[cell.row],
+            nextObj = me.currentCache[cell.row + 1],
             temp, contentTxt;
         temp = thisObj.serialNo;
         thisObj.serialNo = nextObj.serialNo;
         nextObj.serialNo = temp;
         me.sortCache(me.currentCache);
-        me.save();
+        me.save(function () {
+            me.workBook.getSheet(0).setActiveCell(cell.row + 1, cell.col);
+        });
     },
     deleteContent: function (rowIdx) {
         let me = contentOprObj;
@@ -117,14 +121,10 @@ let contentOprObj = {
         me.currentCache.push(newObj);
 
     },
-    save: function () {
+    save: function (callback) {
         let selectedNode = projectObj.mainController.tree.selected;
-        const setting = projectObj.project.property.addRule !== undefined ? projectObj.project.property.addRule : null;
-        pageCCOprObj.setCharacterBySetting(selectedNode, setting);
-        // let me = contentOprObj;
-        // let contentTxt = me.getColData(me.currentCache);
-        // let txtObj =  {field: 'jobContentText', text: contentTxt ? contentTxt : ''};
-        // pageCCOprObj.updateCharacterContent(pageCCOprObj.currentFindSet, {field: 'jobContent', updateArr: me.currentCache}, txtObj, contentOprObj);
+        const setting = projectObj.project.property.addRule !== undefined ? projectObj.project.property.addRule : getAddRuleSetting();
+        pageCCOprObj.setCharacterBySetting(selectedNode, setting, callback, contentOprObj);
     },
     onEditEnded: function (sender, args) {
         let me = contentOprObj;
@@ -248,11 +248,11 @@ let contentOprObj = {
                                 me.deleteContent(target.row);
                             }},
                             "upMove": {name: "上移", disabled: upDis, icon: "fa-arrow-up", callback: function (key, opt) {
-                                me.upMove(target.row);
+                                me.upMove({row: target.row, col: target.col});
 
                             }},
                             "downMove": {name: "下移", disabled: downDis, icon: "fa-arrow-down", callback: function (key, opt) {
-                                me.downMove(target.row);
+                                me.downMove({row: target.row, col: target.col});
                             }}
                         }
                     };
@@ -391,27 +391,31 @@ let characterOprObj = {
         sheet.getCell(rowIdx, 1).cellType(combo);
         sheet.getCell(rowIdx, 2).cellType(checkBox);
     },
-    upMove: function (rowIdx) {
+    upMove: function (cell) {
         let me = characterOprObj;
-        let thisObj = me.currentCache[rowIdx],
-            preObj = me.currentCache[rowIdx - 1],
+        let thisObj = me.currentCache[cell.row],
+            preObj = me.currentCache[cell.row - 1],
             temp;
         temp = thisObj.serialNo;
         thisObj.serialNo = preObj.serialNo;
         preObj.serialNo = temp;
         contentOprObj.sortCache(me.currentCache);
-        me.save();
+        me.save(function () {
+            me.workBook.getSheet(0).setActiveCell(cell.row - 1, cell.col);
+        });
     },
-    downMove: function (rowIdx) {
+    downMove: function (cell) {
         let me = characterOprObj;
-        let thisObj = me.currentCache[rowIdx],
-            nextObj = me.currentCache[rowIdx + 1],
+        let thisObj = me.currentCache[cell.row],
+            nextObj = me.currentCache[cell.row + 1],
             temp;
         temp = thisObj.serialNo;
         thisObj.serialNo = nextObj.serialNo;
         nextObj.serialNo = temp;
         contentOprObj.sortCache(me.currentCache);
-        me.save();
+        me.save(function () {
+            me.workBook.getSheet(0).setActiveCell(cell.row + 1, cell.col);
+        });
     },
     deleteCharacter: function (rowIdx) {
         let me = characterOprObj;
@@ -491,14 +495,10 @@ let characterOprObj = {
             me.currentCache.push(newCharacter);
         }
     },
-    save: function () {
+    save: function (callback) {
         let selectedNode = projectObj.mainController.tree.selected;
-        const setting = projectObj.project.property.addRule !== undefined ? projectObj.project.property.addRule : null;
-        pageCCOprObj.setCharacterBySetting(selectedNode, setting);
-        // let me = characterOprObj;
-        // let characterTxt = me.getColData(me.currentCache);
-        // let txtObj =  {field: 'itemCharacterText', text: characterTxt ? characterTxt : ''};
-        // pageCCOprObj.updateCharacterContent(pageCCOprObj.currentFindSet, {field: 'itemCharacter', updateArr: me.currentCache}, txtObj, characterOprObj);
+        const setting = projectObj.project.property.addRule !== undefined ? projectObj.project.property.addRule : getAddRuleSetting();
+        pageCCOprObj.setCharacterBySetting(selectedNode, setting, callback, characterOprObj);
     },
     onEditStart: function (sender, args) {
         let me = characterOprObj;
@@ -627,10 +627,10 @@ let characterOprObj = {
                                 me.deleteCharacter(target.row);
                             }},
                             "upMove": {name: "上移", disabled: upDis, icon: "fa-arrow-up", callback: function (key, opt) {
-                                me.upMove(target.row);
+                                me.upMove({row: target.row, col: target.col});
                             }},
                             "downMove": {name: "下移", disabled: downDis, icon: "fa-arrow-down", callback: function (key, opt) {
-                                me.downMove(target.row);
+                                me.downMove({row: target.row, col: target.col});
                             }}
                         }
                     };
@@ -668,7 +668,7 @@ let pageCCOprObj = {
         node.data.itemCharacter = itemCharacter;
         this.nameCache = name;
         // 根据规则设置对应特征、内容、名称格式
-        const setting = projectObj.project.property.addRule !== undefined ? projectObj.project.property.addRule : null;
+        const setting = projectObj.project.property.addRule !== undefined ? projectObj.project.property.addRule : getAddRuleSetting();
         const updateData = pageCCOprObj.getCharacterUpdateData(setting, node);
         node.data.jobContentText = updateData.jobContentText;
         node.data.itemCharacterText = updateData.itemCharacterText;
@@ -737,7 +737,7 @@ let pageCCOprObj = {
         projectObj.mainSpread.focus(true);
     },
     //更新特征及内容数据
-    updateCharacterContent: function (findSet, updateObj, txtObj, oprObj) {
+    updateCharacterContent: function (findSet, updateObj, txtObj, oprObj, callback) {
         let me = pageCCOprObj, updateCol;
         if(txtObj){
             updateCol = txtObj.field === 'itemCharacterText' ? 4 : 5;//更新清单行特征列或内容列
@@ -763,6 +763,9 @@ let pageCCOprObj = {
                 let activeCell = projectObj.mainSpread.getActiveSheet().getSelections()[0];
                 projectObj.mainSpread.getActiveSheet().setValue(activeCell.row, updateCol, txtObj.text + ''); //刷新输出显示
                 projectObj.mainSpread.getActiveSheet().autoFitRow(activeCell.row);
+                if(callback){
+                    callback();
+                }
             }
         });
     },
@@ -819,9 +822,8 @@ let pageCCOprObj = {
      * @param {Object} setting - 设置
      * @return {void}
      */
-    setCharacterBySetting: function(node, setting) {
+    setCharacterBySetting: function(node, setting, callback = null, oprObj = null) {
         let self = this;
-
         // 保存的条件数据
         const findSet = { ID: node.data.ID, projectID: node.data.projectID };
         const updateData = this.getCharacterUpdateData(setting, node);
@@ -840,6 +842,12 @@ let pageCCOprObj = {
             node.data.name = updateData.name;
             node.data.itemCharacterText = updateData.itemCharacterText;
             node.data.jobContentText = updateData.jobContentText;
+            if (oprObj) {
+                pageCCOprObj.showData(oprObj.workBook.getSheet(0), oprObj.setting, oprObj.currentCache);//刷新特征及内容Spread
+            }
+            if(callback){
+                callback();
+            }
         });
 
     },
@@ -979,6 +987,10 @@ let pageCCOprObj = {
      * @return {Object} - 返回更新的数据
      */
     getCharacterUpdateData: function(setting, node) {
+        // 获取原名称
+        const name = node.data.name.split("\n");
+        this.nameCache = name[0] !== undefined ? name[0] : "";
+
         let updateData = {
             itemCharacterText: '',
             jobContentText: '',
@@ -1027,10 +1039,10 @@ let pageCCOprObj = {
         switch (setting.displayFormat) {
             case "1":
                 // 换行分隔
-                content = contentArray.join("\r\n");
+                content = contentArray.join("\n");
 
-                currentData.character = currentData.character.join("\r\n");
-                currentData.content = currentData.content.join("\r\n");
+                currentData.character = currentData.character.join("\n");
+                currentData.content = currentData.content.join("\n");
                 break;
             case "2":
                 // 逗号分隔
@@ -1052,7 +1064,7 @@ let pageCCOprObj = {
                 break;
             case "2":
                 // 添加到清单名称列
-                content = this.nameCache + "\r\n" + content;
+                content = this.nameCache + "\n" + content;
                 updateData.name = content;
                 break;
             case "3":

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

@@ -363,7 +363,7 @@ var feeRateObject={
         this.mainViews = new GC.Spread.Views.DataView($('#divFee')[0],
             this.dataSource, this.columns, new GC.Spread.Views.Plugins.GridLayout(this.options));
         this.mainViews["rowClick"].addHandler(subRateObject.reFreshRateViews);
-        this.mainViews .invalidate();
+        this.mainViews.invalidate();
         document.querySelector('#divFee').focus();
     },
     reFreshRateViews:function() {
@@ -652,8 +652,7 @@ var feeRateObject={
             selected.data.feeRateID=rate.ID.toString();
             selected.data.feeRate=scMathUtil.roundToString(rate.rate,getDecimal("feeRate"));
             selected.changed = true;
-            projectObj.project.calcProgram.calculate(selected);
-            projectObj.project.calcProgram.saveNode(selected);
+            projectObj.project.calcProgram.calcAndSave(selected);
             //projectObj.mainController.refreshTreeNode([selected]);
             $("#fee_rate_tree").modal('hide');
         });

+ 136 - 55
web/building_saas/main/js/views/glj_view.js

@@ -226,8 +226,8 @@ var gljOprObj = {
                 vAlign: "center"
             },
             {
-                headerName: "计量单位",
-                headerWidth: 80,
+                headerName: "单位",
+                headerWidth: 40,
                 dataCode: "unit",
                 dataType: "String",
                 hAlign: "center",
@@ -289,6 +289,12 @@ var gljOprObj = {
         // me.detailSheet.selectionUnit(0);//0 cell,1 row,2 col;
         sheet.name('quantity_detail');
         me.bindSheetEvent(sheet);
+        sheet.bind(GC.Spread.Sheets.Events.EditStarting, function (sender, args) {
+            if(args.sheet.getValue(args.row,args.col)==null){//这里是为了解决当单元格里的值是null的时候,在单元格里输入数据,按键盘箭头移动光标的时候,会直接结束编辑,跳到另外的单元格。
+                args.sheet.setValue(args.row,args.col,"");
+            }
+        });
+
 
     },
     showCoeData: function (sheet, setting, datas) {
@@ -390,6 +396,10 @@ var gljOprObj = {
         }
     },
     onCheckBoxClick: function (sender, args) {
+        let selected = projectObj.project.mainTree.selected;
+        if(selected.sourceType == ModuleNames.ration_glj||(selected.sourceType == ModuleNames.ration&&selected.data.type==rationType.gljRation)){//选中的是工料机时不可编辑
+            return ;
+        }
         var checkboxValue = args.sheet.getCell(args.row, args.col).value();
         var newval = 0;
         if (checkboxValue) {
@@ -575,7 +585,7 @@ var gljOprObj = {
                 disable = true;
             }else {
                 if (header[args.col] && header[args.col].dataCode == 'marketPrice') {
-                    if(me.hasComposition(me.sheetData[args.row])){
+                    if(me.marketPriceReadOnly({data:me.sheetData[args.row]})){
                         disable = true;
                     }else {
                         disable = false;
@@ -584,7 +594,7 @@ var gljOprObj = {
                 if (header[args.col] && header[args.col].dataCode == 'basePrice') {
                     var isAdd = me.sheetData[args.row].isAdd;
                     if(isAdd==1){//是新增但没有组成物时允许修改定额价
-                        if(me.hasComposition(me.sheetData[args.row])){//如果有组成物,不可修改
+                        if(me.marketPriceReadOnly({data:me.sheetData[args.row]})){//如果有组成物,不可修改
                             disable = true;
                         }else {
                             disable = false;
@@ -599,9 +609,11 @@ var gljOprObj = {
             me.sheet.getCell(args.row, args.col, GC.Spread.Sheets.SheetArea.viewport).locked(disable);
         }
     },
-    hasComposition:function (ration_glj) {//判断是否有组成物,有则返回true
-        if(notEditType.indexOf(ration_glj.type)!=-1){
-            let con_key = this.getIndex(ration_glj,gljKeyArray);
+    hasComposition:function (ration_glj,isRationType) {//判断是否有组成物,有则返回true   现在主材类型的工料机也有可能有组成物。
+        let type = isRationType==true? ration_glj.subType:ration_glj.type;
+        if(notEditType.indexOf(type)!=-1||type==gljType.MAIN_MATERIAL){
+            let keyArray = isRationType==true? rationKeyArray:gljKeyArray;
+            let con_key = this.getIndex(ration_glj,keyArray);
             var mixRatioMap = projectObj.project.projectGLJ.datas.mixRatioMap;
             if(mixRatioMap[con_key]&&mixRatioMap[con_key].length>0){
                 return true;
@@ -681,11 +693,20 @@ var gljOprObj = {
                 this.selectedNodeId = node.getID();
             }
             if (node.sourceType == "ration") {
-                this.showRationGLJData(node);
-                this.showRationCoeData(node);
-                this.showRationAssData(node);
+                if(node.data.type==rationType.gljRation){
+                    this.showMixRatio(node);
+                }else {
+                    this.showRationGLJData(node);
+                    this.showRationCoeData(node);
+                    this.showRationAssData(node);
+                }
+                isShow = true;
+            }
+            if(node.sourceType == ModuleNames.ration_glj){
+                this.showMixRatio(node);
                 isShow = true;
             }
+
             this.showQuantityDetailData(node);
         } else {
             this.selectedNodeId = null;
@@ -700,6 +721,38 @@ var gljOprObj = {
         }
         //   $('#dropdown').hide();
     },
+    showMixRatio:function (node) {//显示组成物到定额工料机
+        let mixRatioMap = projectObj.project.projectGLJ.datas.mixRatioMap;
+        let projectGljs = projectObj.project.projectGLJ.datas.gljList;
+        let indexArray =node.sourceType==ModuleNames.ration?rationKeyArray:gljKeyArray;
+        let connect_index = this.getIndex(node.data,indexArray);
+        let gljList=[];
+        if(mixRatioMap[connect_index]){ //说明是有组成物的类型
+            gljList =  this.getMixRationShowDatas(mixRatioMap[connect_index], projectGljs);
+        }
+        if(gljList.length>0){//计算总消耗量
+            if(node.sourceType==ModuleNames.ration){
+                this.calcMixRationTotalQuantity(gljList,node.data.quantity);
+            }else {
+               let totalQuantity = this.getTotalQuantity(node.data);
+               this.calcMixRationTotalQuantity(gljList,totalQuantity)
+            }
+        }
+        this.sheetData = gljList;
+        this.sheet.setRowCount(0);
+        this.sheetData = sortRationGLJ(this.sheetData);
+        sheetCommonObj.showData(this.sheet, this.setting, this.sheetData);
+
+        this.sheet.getRange(-1, 0, -1, this.setting.header.length).locked(true);//锁住定额工料机的所有列
+        this.detailSheet.getRange(-1, 0, -1, this.detailSetting.header.length).locked(true);//锁住工程量明细的所有列
+
+        sheetCommonObj.showData(this.coeSheet, this.coeSetting, []);
+        sheetCommonObj.showData(this.assSheet, this.assSetting, []);
+
+        this.coeSheetData = [];
+        this.assSheetData = [];
+    },
+
     showRationGLJData: function (node) {
         var gljList = [];
         var ration_glj = projectObj.project.ration_glj;
@@ -711,6 +764,7 @@ var gljOprObj = {
         }
     },
     showRationGLJSheetData: function (init) {
+        let selected = this.sheet.getSelections();
         this.combineWithProjectGlj(this.sheetData);
         this.sheet.setRowCount(0);
         //console.log(+new Date())
@@ -720,7 +774,9 @@ var gljOprObj = {
         this.addMixRatioToShow();//显示组成物信息
         this.initRationTree(init);
         sheetCommonObj.showData(this.sheet, this.setting, this.sheetData);
-
+        if(selected){//定位光标到之前的位置
+            this.sheet.setSelection(selected[0].row,selected[0].col,selected[0].rowCount,selected[0].colCount);
+        }
     },
     initRationTree: function (init) {
         this.sheet.getRange(-1, 0, -1, 1).cellType(this.getTreeNodeCellType(this.sheetData));
@@ -775,14 +831,18 @@ var gljOprObj = {
             glj.quantity = scMathUtil.roundForObj(glj.quantity, getDecimal("glj.quantity"));
             glj.totalQuantity = scMathUtil.roundToString(quantity * glj.quantity, getDecimal("glj.quantity"));
             if (glj.hasOwnProperty('subList')) {//需要计算glj下挂的组成物的总消耗量
-                for (let subG of glj.subList) {
-                    subG.rationItemQuantity = scMathUtil.roundForObj(subG.rationItemQuantity, getDecimal("glj.quantity"));
-                    subG.totalQuantity = scMathUtil.roundToString(subG.rationItemQuantity * glj.totalQuantity, getDecimal("glj.quantity"));
-                }
+                this.calcMixRationTotalQuantity(glj.subList,glj.totalQuantity);
             }
             return  glj.totalQuantity;
         }
     },
+    calcMixRationTotalQuantity(mList,pTotal){ //计算组成物的总消耗量
+        for (let subG of mList) {
+            subG.rationItemQuantity = scMathUtil.roundForObj(subG.rationItemQuantity, getDecimal("glj.quantity"));
+            subG.totalQuantity = scMathUtil.roundToString(subG.rationItemQuantity * pTotal, getDecimal("glj.quantity"));
+        }
+    },
+
     addMixRatioToShow: function () {
         var newList = [];
         _.remove(this.sheetData, {'isMixRatio': true});
@@ -803,12 +863,13 @@ var gljOprObj = {
                 var glj = _.find(projectGljs, {'id': ration_gljs[i].projectGLJID});
                 if (glj) {
                     let typeString = ration_gljs[i].type + "";
-                    if (typeString.indexOf("2") != -1||typeString=='4'||typeString=='5') {//只有材料类型才显示是否暂估
+                    if (typeString.startsWith("2")||typeString=='4'||typeString=='5') {//只有材料类型才显示是否暂估
                         ration_gljs[i].isEstimate = glj.is_evaluate;
                     }
+                    ration_gljs[i].shortName =projectObj.project.projectGLJ.getShortNameByID(ration_gljs[i].type);
                     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)
+                    var connect_index = this.getIndex(glj, gljKeyArray);
                     if (mixRatioMap.hasOwnProperty(connect_index)) {
                         var mixRatios = this.getMixRationShowDatas(mixRatioMap[connect_index], projectGljs);
                         ration_gljs[i].subList = mixRatios;
@@ -882,17 +943,24 @@ var gljOprObj = {
                 name: pg.name,
                 specs: pg.specs,
                 unit: pg.unit,
-                shortName: pg.unit_price.short_name,
+                type:mixRatioList[i].type,
+                shortName: projectObj.project.projectGLJ.getShortNameByID(mixRatioList[i].type),
+                consumption:mixRatioList[i].consumption,
                 rationItemQuantity: mixRatioList[i].consumption,
                 // quantity:mixRatioList[i].consumption,
-                basePrice: pg.unit_price.base_price,
+              /*  basePrice: pg.unit_price.base_price,
                 marketPrice: pg.unit_price.market_price,
-                adjustPrice: pg.adjust_price,
-                isEstimate: pg.is_evaluate,
+                adjustPrice: pg.adjust_price,*/
+                //isEstimate: pg.is_evaluate,
                 isMixRatio: true,
                 isAdd: pg.unit_price.is_add,
                 GLJID: pg.glj_id
+            };
+            let typeString = pg.type + "";
+            if (typeString.startsWith("2")||typeString=='4'||typeString=='5') {//只有材料类型才显示是否暂估
+                tem.isEstimate =  pg.is_evaluate;
             }
+            this.setGLJPrice(tem,pg);
             temRationGLJs.push(tem);
         }
         temRationGLJs = _.sortBy(temRationGLJs, 'code');
@@ -992,8 +1060,6 @@ var gljOprObj = {
         }
     },
     updateRationTypeGLJ: function (value, node, fieldName) {
-        console.log(fieldName)
-        console.log(value);
         let newval;
         let updatePrice = false;
         if (fieldName == "marketUnitFee") {
@@ -1205,15 +1271,22 @@ var gljOprObj = {
         return distTypeTree;
     },
     doInsertGLJ: function () {
+        var me = this;
         var selected = projectObj.project.mainTree.selected;
         var project = projectObj.project;
-        if (gljOprObj.GLJSelection.length <= 0) {
+        if (me.GLJSelection.length <= 0) {
             return;
         }
         $("#glj_tree_div").modal('hide');
-        project.ration_glj.insertGLJAsRation(gljOprObj.GLJSelection, selected, function (result) {
-            project.projectGLJ.loadData();
-            gljOprObj.showRationGLJSheetData();
+        project.ration_glj.insertGLJAsRation(me.GLJSelection, selected, function (node) {
+            project.projectGLJ.loadData(function () {
+                if(me.hasComposition(node.data,true)){
+                    me.showMixRatio(node);
+                }else {
+                    me.showRationGLJSheetData();
+                }
+            });
+
         })
     },
     doAddGLJ: function () {
@@ -1234,13 +1307,13 @@ var gljOprObj = {
                     //project.ration_glj.datas = project.ration_glj.datas.concat(result.newRecodes);//显示和缓存统一,这样的话就不用更新两个位置了
                     project.ration_glj.datas = project.ration_glj.datas.concat(result.showData);
                     gljOprObj.sheetData = gljOprObj.sheetData.concat(result.showData);
-                    gljOprObj.showRationGLJSheetData();
                     project.ration_glj.addToMainTree(result.showData);
-                    project.projectGLJ.loadData();
-                    project.calcProgram.calculate(selected);
-                    project.calcProgram.saveNode(selected);
-                    projectObj.mainController.refreshTreeNode([selected]);
-                    $.bootstrapLoading.end();
+                    project.projectGLJ.loadData(function () {
+                        gljOprObj.showRationGLJSheetData();
+                        project.calcProgram.calcAndSave(selected);
+                        projectObj.mainController.refreshTreeNode([selected]);
+                        $.bootstrapLoading.end();
+                    });
                 }
             });//doc.rationID=selected.data.ID;
         } else {
@@ -1265,24 +1338,24 @@ var gljOprObj = {
                 var nodes = [selected];
                 gljOprObj.sheetData[index] = data;
                 glj_list[list_index] = data;
-                gljOprObj.showRationGLJSheetData();
-                if (project.ration_glj.needShowToTree(data)) {//当替换的是主材或设备时,刷新对应的树节点
-                    var node = project.ration_glj.findGLJNodeByID(data.ID);
-                    if (node) {
-                        project.ration_glj.transferToNodeData(data);
-                        node.source = data;
-                        node.data = data;
+                project.projectGLJ.loadData(function () {//加载完项目工料机再计算
+                    gljOprObj.showRationGLJSheetData();
+                    if (project.ration_glj.needShowToTree(data)) {//当替换的是主材或设备时,刷新对应的树节点
+                        var node = project.ration_glj.findGLJNodeByID(data.ID);
+                        if (node) {
+                            project.ration_glj.transferToNodeData(data);
+                            node.source = data;
+                            node.data = data;
+                        }
+                        node ? nodes.push(node) : "";
                     }
-                    node ? nodes.push(node) : "";
-                }
-                //project.ration_glj.addToMainTree(data);
-                project.projectGLJ.loadData();
-                selected.data.adjustState = result.adjustState;
-                projectObj.mainController.refreshTreeNode(nodes);
-                project.calcProgram.calculate(selected);
-                project.calcProgram.saveNode(selected);
+                    //project.ration_glj.addToMainTree(data);
+                    selected.data.adjustState = result.adjustState;
+                    projectObj.mainController.refreshTreeNode(nodes);
+                    project.calcProgram.calcAndSave(selected);
+                    $.bootstrapLoading.end();
+                });
             }
-            $.bootstrapLoading.end();
         })
     },
     doMReplaceGLJ: function () {
@@ -1307,11 +1380,12 @@ var gljOprObj = {
                     }
                 }
             })
-            me.showRationGLJSheetData();
-            project.projectGLJ.loadData();
-            var rationNodes = me.refreshStateAfterMreplace(stateList, nodes);
-            project.calcProgram.calcRationsAndSave(rationNodes);
-            $.bootstrapLoading.end();
+            project.projectGLJ.loadData(function () {
+                me.showRationGLJSheetData();
+                var rationNodes = me.refreshStateAfterMreplace(stateList, nodes);
+                project.calcProgram.calcRationsAndSave(rationNodes);
+                $.bootstrapLoading.end();
+            });
         })
     },
     updateProperty: function (obj, doc) {
@@ -1363,6 +1437,7 @@ var gljOprObj = {
             }
         }
         projectObj.mainController.refreshTreeNode(nodes);
+        return nodes;
 
     },
     getTreeNodeCellType: function (data) {
@@ -1473,7 +1548,13 @@ var gljOprObj = {
         return new TreeNodeCellType()
     },
     marketPriceReadOnly: function (node) {
-        return node.data.type == gljType.CONCRETE || node.data.type == gljType.MORTAR || node.data.type == gljType.MIX_RATIO || node.data.type == gljType.GENERAL_MACHINE || node.data.isEstimate == 1
+        let hasCom = false;
+        if(node.sourceType==ModuleNames.ration&&node.data.type==rationType.gljRation){
+            hasCom = this.hasComposition(node.data,true);
+        }else {
+            hasCom = this.hasComposition(node.data);
+        }
+        return hasCom|| node.data.isEstimate == 1;
     }
 
 }

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

@@ -35,7 +35,7 @@ var gljContextMenu = {
                         var disable = true;
                         var selected = projectObj.project.mainTree.selected;
                         var sheetData = gljOprObj.sheetData;
-                        if(selected&&selected.sourceType==ModuleNames.ration){
+                        if(selected&&selected.sourceType==ModuleNames.ration&&selected.data.type==rationType.ration){
                             disable=false;
                         }
                         if(subSpread.getActiveSheetIndex()==0&&sheetData!=null&&sheetData.length>0&&gljContextMenu.selectedRow<sheetData.length){

+ 27 - 22
web/building_saas/main/js/views/main_tree_col.js

@@ -6,7 +6,7 @@ let MainTreeCol = {
     getText: {
         subType: function (node) {
             if (node.sourceType === projectObj.project.Bills.getSourceType()) {
-                return '';
+                return billText[node.data.type];
                 // CSL, 2017-11-29
             } else if (node.sourceType === projectObj.project.Ration.getSourceType()) {
                 if (node.data.type == 1 || node.data.type == undefined)    // 兼容旧定额
@@ -38,12 +38,12 @@ let MainTreeCol = {
     readOnly: {
         // CSL, 2017-11-28
         subType: function (node) {
-            return (node.data.type != 2 && node.data.type != 3 && !MainTreeCol.readOnly.glj(node)) || (node.data.type == rationType.gljRation && MainTreeCol.readOnly.non_editSubType(node));
+            return MainTreeCol.readOnly.bills(node)||(node.data.type != 2 && node.data.type != 3 && !MainTreeCol.readOnly.glj(node)) || (node.data.type == rationType.gljRation && MainTreeCol.readOnly.non_editSubType(node));
         },
         calcProgramName: function (node) {
             if (
                 node.sourceType === projectObj.project.Ration.getSourceType() ||
-                (projectObj.project.calcProgram.isLeafBill(node) && projectObj.project.property.billsCalcMode === leafBillGetFeeType.billsPrice)
+                (treeNodeTools.isLeafBill(node) && projectObj.project.property.billsCalcMode === leafBillGetFeeType.billsPrice)
             ) return false
             else return true;
         },
@@ -51,7 +51,7 @@ let MainTreeCol = {
             return node.data.subType != 201 && node.data.subType != 4 && node.data.subType != 5
         },
         commonUnitFee: function (node) {
-            return !projectObj.project.calcProgram.isNullBill(node);
+            return !treeNodeTools.isNullBill(node);
         },
         //根据节点、父节点类型判断是否可用计算基数
         calcBaseType: function (node) {
@@ -85,7 +85,7 @@ let MainTreeCol = {
             return node.sourceType === projectObj.project.Bills.getSourceType();
         },
         ration: function (node) {
-            return projectObj.project.calcProgram.isRation(node);
+            return treeNodeTools.isRation(node);
         },
         glj: function (node) {
             return node.sourceType == projectObj.project.ration_glj.getSourceType();
@@ -128,13 +128,16 @@ let MainTreeCol = {
             return MainTreeCol.readOnly.glj(node) || MainTreeCol.readOnly.billsParent(node)
         },
         forMarketPrice: function (node) {
-            return MainTreeCol.readOnly.bills(node) || (MainTreeCol.readOnly.ration(node) && node.data.type == rationType.ration) || gljOprObj.marketPriceReadOnly(node);
+            return MainTreeCol.readOnly.bills(node) || (node.sourceType === ModuleNames.ration && (node.data.type == rationType.ration||node.data.type== rationType.volumePrice)) || gljOprObj.marketPriceReadOnly(node);
+        },
+        forContain:function (node) {
+            return MainTreeCol.readOnly.non_ration(node)&&!MainTreeCol.readOnly.glj(node);
         }
     },
     cellType: {
         unit: function () {
             //let combo = new GC.Spread.Sheets.CellTypes.ComboBox();
-            let dynamicCombo = sheetCommonObj.getDynamicCombo();
+            let dynamicCombo = sheetCommonObj.getDynamicCombo(true);
             dynamicCombo.itemHeight(10).items(['m', 'm2', 'm3', 'km', 't', 'kg', '台班', '工日', '昼夜', '元', '项', '处', '个', '件',
                 '根', '组', '系统', '台', '套', '株', '丛', '缸', '支', '只', '块', '座', '对', '份', '樘', '攒', '榀']);
             return dynamicCombo;
@@ -156,7 +159,7 @@ let MainTreeCol = {
         calcProgramName: function (node) {
             if (
                 node.sourceType === projectObj.project.Ration.getSourceType() ||
-                (projectObj.project.calcProgram.isLeafBill(node) && projectObj.project.property.billsCalcMode === leafBillGetFeeType.billsPrice)
+                (treeNodeTools.isLeafBill(node) && projectObj.project.property.billsCalcMode === leafBillGetFeeType.billsPrice)
             ) {
                 // var names = new GC.Spread.Sheets.CellTypes.ComboBox();
                 var names = sheetCommonObj.getDynamicCombo();
@@ -167,19 +170,20 @@ let MainTreeCol = {
 
         // CSL, 2017-11-28
         subType: function (node) {
-            if (node.data.type == rationType.volumePrice || node.data.type == rationType.gljRation || node.sourceType === projectObj.project.ration_glj.getSourceType()) {
-                let VPType = sheetCommonObj.getDynamicCombo();
-                if (node.data.type == rationType.volumePrice)
-                    VPType.itemHeight(5).items(["人工", "材料", "机械", "主材", "设备"])
-                else if (node.data.type == rationType.gljRation || node.sourceType === projectObj.project.ration_glj.getSourceType())
-                    if (!MainTreeCol.readOnly.non_editSubType(node)) {
-                        VPType.itemHeight(3).items(["材料", "主材", "设备"]);
-                    } else {
-                        return null;
-                    }
-                return VPType;
+            if(node.sourceType!=projectObj.project.Bills.getSourceType()){
+                if (node.data.type == rationType.volumePrice || node.data.type == rationType.gljRation || node.sourceType === projectObj.project.ration_glj.getSourceType()) {
+                    let VPType = sheetCommonObj.getDynamicCombo();
+                    if (node.data.type == rationType.volumePrice)
+                        VPType.itemHeight(5).items(["人工", "材料", "机械", "主材", "设备"])
+                    else if (node.data.type == rationType.gljRation || node.sourceType === projectObj.project.ration_glj.getSourceType())
+                        if (!MainTreeCol.readOnly.non_editSubType(node)) {
+                            VPType.itemHeight(3).items(["材料", "主材", "设备"]);
+                        } else {
+                            return null;
+                        }
+                    return VPType;
+                }
             }
-            ;
         },
     },
     getEvent: function (eventName) {
@@ -249,7 +253,8 @@ let colSettingObj = {
         sheet.setColumnCount(1);
         sheet.getRange(-1, 0, -1, 1).cellType(this.checkBox).hAlign(GC.Spread.Sheets.HorizontalAlign.center);
         sheet.getCell(0, 0, GC.Spread.Sheets.SheetArea.colHeader).value('显示');
-        sheet.setColumnWidth(0, 300);
+        sheet.setColumnWidth(0, 100);
+        sheet.setColumnWidth(0, 150, GC.Spread.Sheets.SheetArea.rowHeader);
 
         setting.cols.forEach(function (col, index) {
             let i, iCol = 0, cell;
@@ -266,7 +271,7 @@ let colSettingObj = {
             ;
             let colWidth = sheet.getColumnWidth(index, GC.Spread.Sheets.SheetArea.rowHeader);
             colWidth = colWidth > col.width ? colWidth : col.width;
-            sheet.setColumnWidth(index, colWidth, GC.Spread.Sheets.SheetArea.rowHeader);
+            //sheet.setColumnWidth(index, colWidth, GC.Spread.Sheets.SheetArea.rowHeader);
             cell = sheet.getCell(index, 0).value(col.visible);
             sheet.autoFitRow(index);
         });

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

@@ -105,7 +105,7 @@ function toUpdateDecimal(orgV, newV){
 function setDecimal(_digits, data){
     if(isDef(data)){
         for(let attr in data){
-            _digits[attr] = data[attr] || defaultDecimal['_def'][attr]['data'];
+            _digits[attr] = returnV(data[attr], defaultDecimal['_def'][attr]['data']);
         }
     }
     else {

+ 130 - 38
web/building_saas/main/js/views/project_view.js

@@ -119,7 +119,7 @@ var projectObj = {
         return value;
     },
     checkSpreadEditingText: function (editingText, colSetting) {
-        if (colSetting.data.field === 'quantity') {
+        if (colSetting.data.field === 'quantity'||colSetting.data.field === 'contain') {
             return this.checkFormulaValidField(editingText, colSetting);
         }
         else if (colSetting.data.field === 'programID') {
@@ -210,11 +210,11 @@ var projectObj = {
                 });
             }
         }
-        if (value.length === 9 && /^[\d]+$/.test(value)) {
+        if (value&&value.length === 9 && /^[\d]+$/.test(value)) {
             stdMatchCode = value;
             formatCode = project.Bills.newFormatCode(stdMatchCode);
             searchStdBillsAndUpdate(stdMatchCode, formatCode);
-        } else if (value.length === 12 && /^[\d]+$/.test(value)) {
+        } else if (value&&value.length === 12 && /^[\d]+$/.test(value)) {
             stdMatchCode = value.substr(0, 9);
             matchs = project.Bills.sameStdCode(stdMatchCode, node.data.code);
             if (matchs.indexOf(value) === -1) {
@@ -257,8 +257,7 @@ var projectObj = {
         } else if (node.sourceType === project.Ration.getSourceType()) {
             this.updateRationCode(node, value);  // 新套定额适合实时计算
             // 这里因异步问题暂时缺少工料机价格。该过程移到:ration_glj.js的refreshAfterSave方法中。
-            /*project.calcProgram.calculate(node);
-            project.calcProgram.saveNode(node);
+            /*project.calcProgram.calcAndSave(node);
             if (activeSubSheetIs(subSheetIndex.ssiCalcProgram)) {
                 calcProgramObj.showData(node, false);
             };*/
@@ -268,33 +267,22 @@ var projectObj = {
         let project = projectObj.project, fieldName = colSetting.data.field;
         if(node.sourceType==project.ration_glj.getSourceType()){
             project.ration_glj.updateFromMainSpread(value,node,fieldName);
-        }if(node.sourceType==ModuleNames.ration&&node.data.type==rationType.gljRation){
+        }else if(treeNodeTools.isGljRation(node)){
             gljOprObj.updateRationTypeGLJ(value,node,fieldName);
         } else if (value !== calcFees.getFee(node.data, fieldName)||fieldName == 'quantity') {//工程量需要进行转换,所以做特殊处理
-            if (fieldName === 'code' && !project.calcProgram.isVolumePrice(node)) {
+            if (fieldName === 'code' && !treeNodeTools.isVolumePrice(node)) {
                 projectObj.updateCode(node, value);
             }
             else if(fieldName ==='feeRate'){
                 project.FeeRate.updateFeeRateFromBills(value,node,fieldName);
+            }else if(fieldName ==='contain'){//编辑含量
+                project.Ration.updateContain(value,node);
             }
             else if (fieldName === 'quantity' || fieldName === 'marketUnitFee' || fieldName === 'programID' ||
                 fieldName === 'subType' || fieldName === 'calcBase' || fieldName === 'feesIndex.common.unitFee'){
                 if (fieldName === 'quantity') {
-                   if (value) {
-                       value = project.quantity_detail.autoTransformQuantity(value,node);
-                       value = scMathUtil.roundForObj(value,decimalObj.decimal(fieldName,node));
-                       if(value==node.data[fieldName]){
-                           projectObj.mainController.refreshTreeNode([node]);
-                           return;
-                       }
-                   };
-                   if(project.quantity_detail.quantityEditChecking(value,node,fieldName)){
-                       node.data.isFromDetail=0;
-                       project.quantity_detail.cleanQuantityDetail(node,true);
-                   }else {
-                       projectObj.mainController.refreshTreeNode([node]);
-                       return;
-                   }
+                    project.quantity_detail.editMainTreeNodeQuantity(value,node,fieldName);
+                    return;
                 }
                 else if (fieldName === 'marketUnitFee' || fieldName === 'feesIndex.common.unitFee') {
                     if (value) {value = parseFloat(value).toDecimal(decimalObj.decimal("unitPrice", node))};
@@ -315,13 +303,19 @@ var projectObj = {
                 };
                 node.changed = true;
                 if (fieldName == 'feesIndex.common.unitFee'){
-                    project.calcProgram.initFeeField(node, 'common');
+                    treeNodeTools.initFeeField(node, 'common');
                     node.data.feesIndex.common.unitFee = value;
                 }
                 else node.data[fieldName] = value;
-                project.calcProgram.calculate(node);
-                project.calcProgram.saveNode(node);
+                project.calcProgram.calcAndSave(node);
                 gljOprObj.showRationGLJSheetData();
+            } else if (node.sourceType === project.Bills.getSourceType()&&fieldName === 'unit'){//修改清单单位的时候清单工程量要重新4舍5入
+                node.data[fieldName] = value;
+                node.changed = true;
+                if(node.data.quantity){
+                    node.data.quantity =scMathUtil.roundForObj(node.data.quantity,getDecimal("quantity",node));
+                }
+                project.calcProgram.calcAndSave(node);
             }
             else {
                 if (node.sourceType === project.Bills.getSourceType()) {
@@ -394,13 +388,15 @@ var projectObj = {
     loadProjectData: function () {
         var that = this;
         this.project = PROJECT.createNew(scUrlUtil.GetQueryString('project'), userID);
+        let startTime = +new Date();
+        console.log("开始加载-----"+startTime);
         this.project.loadDatas(function (err) {
-
             if (!err) {
+                that.project.projectGLJ.calcQuantity();//计算分部分项和技术措施项目消耗量;
                 that.project.property = projectInfoObj.projectInfo.property;
                 //that.project.calcProgram.compileAllTemps();
                 that.project.calcBase.init(that.project);
-                that.project.calcFields = JSON.parse(JSON.stringify(feeType));
+                that.project.calcFields = JSON.parse(JSON.stringify(cpFeeTypes));
                 // that.project.initCalcFields();
                 let str = JSON.stringify(that.project.projSetting.main_tree_col);
                 that.project.projSetting.mainGridSetting = JSON.parse(str);
@@ -446,7 +442,9 @@ var projectObj = {
                             col.data.wordWrap = true;
                         }
                     }
-
+                    if(col.data.field ==='quantity'){
+                        col.showHint = true;
+                    }
                     // for test digit. CSLAAAAA
                     if (col.data.field.hasSubStr("totalFee"))
                        col.data.formatter = MainTreeCol.getNumberFormatter(decimalObj.ration.totalPrice, false)
@@ -469,6 +467,8 @@ var projectObj = {
                 that.mainSpread.bind(GC.Spread.Sheets.Events.SelectionChanged, that.amountAreaNumber);
                 that.loadMainSpreadContextMenu();
                 that.loadFocusLocation();
+                let endTime = +new Date();
+                console.log("加载完成-----"+endTime);
             }
             else {
 
@@ -486,6 +486,76 @@ var projectObj = {
                 return target.hitTestType === GC.Spread.Sheets.SheetArea.viewport || target.hitTestType === GC.Spread.Sheets.SheetArea.rowHeader;
             },
             items: {
+                "insertRootBill": {
+                    name: "插入大项费用",
+                    icon: 'fa-sign-in',
+                    disabled: function () {
+                        //return project.mainTree.selected ? project.mainTree.selected.sourceType !== project.Bills.getSourceType() : false;
+                    },
+                    callback: function (key, opt) {
+                        ProjectController.addRootBill(project, controller);
+                    },
+                    visible: function(key, opt){
+                        return project.mainTree.selected&&project.mainTree.selected.parent==null;
+                    }
+                },
+                "insertFB": {
+                    name: "插入分部",
+                    icon: 'fa-sign-in',
+                    disabled: function () {
+                        let selected = project.mainTree.selected;
+                        if(selected.sourceType==project.Bills.getSourceType()){
+                            if(selected.data.type==billType.FB){
+                                return false;
+                            }
+                            if(isFlag(selected.data)&&selected.data.flagsIndex.fixed.flag==fixedFlag.SUB_ENGINERRING){//焦点行是分部分项工程
+                                if(selected.children.length>0){
+                                   return selected.children[0].data.type==billType.FX;//焦点行是分部分项工程,且子项是分项
+                                }
+                            }
+                        }
+                        return true;//除了清单,其它类型都只读
+                    },
+                    callback: function (key, opt) {
+                        ProjectController.addFB(project, controller);
+                    },
+                    visible: function(key, opt){
+                        return project.Bills.isFBFX(project.mainTree.selected );//不属于分部分项的话隐藏
+                    }
+                },
+                "insertFX": {
+                    name: "插入分项",
+                    icon: 'fa-sign-in',
+                    disabled: function () {
+                        let selected = project.mainTree.selected;
+                        if(selected.sourceType==project.Bills.getSourceType()){
+                            if(selected.data.type==billType.FX){//焦点行是分项,有效显示
+                                return false
+                            }
+                            if(selected.data.type==billType.FB){//点行是分部,
+                                if(selected.children.length>0){//且有子项,子项是分部,灰显。
+                                    return selected.children[0].data.type == billType.FB
+                                }else {
+                                    return false;
+                                }
+                            }
+                            if(isFlag(selected.data)&&selected.data.flagsIndex.fixed.flag==fixedFlag.SUB_ENGINERRING){//焦点行是分部分项工程
+                                if(selected.children.length>0){
+                                    return selected.children[0].data.type==billType.FB;//焦点行是分部分项工程,且子项是分部时灰显
+                                }else {
+                                    return false
+                                }
+                            }
+                        }
+                        return true;//除了清单,其它类型都只读
+                    },
+                    callback: function (key, opt) {
+                        ProjectController.addFX(project, controller);
+                    },
+                    visible: function(key, opt){
+                        return project.Bills.isFBFX(project.mainTree.selected );//不属于分部分项的话隐藏
+                    }
+                },
                 "insertBills": {
                     name: "插入清单",
                     icon: 'fa-sign-in',
@@ -493,24 +563,47 @@ var projectObj = {
                         return project.mainTree.selected ? project.mainTree.selected.sourceType !== project.Bills.getSourceType() : false;
                     },
                     callback: function (key, opt) {
+                        if(project.mainTree.selected.data.type == billType.DXFY){
+                            if(project.mainTree.selected.data.calcBase&&project.mainTree.selected.data.calcBase!=""){
+                                alert("当前有基数计算不能插入子项。");
+                                return;
+                            }
+                        }
                         ProjectController.addBills(project, controller);
-                    }
+                    },
+                     visible: function(key, opt){
+                         return  project.Bills.isFBFX(project.mainTree.selected)==true?false:true;//不属于分部分项的话隐藏
+                     }
                 },
                 "insertRation": {
                     name: "插入定额",
                     icon: 'fa-sign-in',
                     disabled: function () {
                         var selected = project.mainTree.selected;
-                        if (selected) {
-                            if (            // CSL, 2017-11-28
-                                selected.sourceType === project.Ration.getSourceType() ||
-                                (selected.sourceType === project.Bills.getSourceType() && selected.source.children.length === 0)
-                               ) return false
-                            else return true
-                        } else return true
+                        if (selected) {// Vincent, 2018-01-02
+                            if(selected.sourceType === project.Ration.getSourceType()){ // 焦点行是定额/量价/工料机,有效显示。
+                                return false;
+                            }else if(selected.sourceType === project.Bills.getSourceType()){
+                               if(selected.data.type == billType.FX){//焦点行是分项,有效显示。
+                                  return false
+                               }
+                               if(selected.data.type == billType.BILL && selected.source.children.length === 0){//焦点行是清单,且没有子项,有效显示。
+                                    return false
+                               }
+                            }
+                        }
+                        return true;
                     },
                     callback: function (key, opt) {
                         ProjectController.addRation(project, controller, rationType.ration);
+                    },
+                    visible: function(key, opt){
+                        var selected = project.mainTree.selected;
+                        if(selected.sourceType == ModuleNames.bills&&selected.data.type == billType.DXFY){
+                            return false
+                        }else {
+                            return true
+                        }
                     }
                 },
                 "insertLJ": {
@@ -589,8 +682,7 @@ var projectObj = {
             this.project.Bills.updateNodes(nodes, true);
             calc = null;
         }*/
-        projectObj.project.calcProgram.calculate(node);
-        projectObj.project.calcProgram.saveNode(node);
+        projectObj.project.calcProgram.calcAndSave(node);
     },
     // 计算全部清单
 /*    calculateAll: function () {

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

@@ -281,7 +281,7 @@ var billsLibObj = {
                 "font":"Arial"
             }
         }, {
-            "width":50,
+            "width":45,
             "readOnly": true,
             "showHint": true,
             "head":{

+ 7 - 31
web/building_saas/main/js/views/sub_view.js

@@ -129,9 +129,6 @@ $("#use-to-current").click(function() {
     const self = $(this);
     self.attr('disabled', 'disabled');
     let selectedNode = projectObj.mainController.tree.selected;
-    // 获取原名称
-    const name = selectedNode.data.name.split("\r\n");
-    pageCCOprObj.nameCache = name[0] !== undefined ? name[0] : "";
     // 操作内容
     pageCCOprObj.setCharacterBySetting(selectedNode, setting);
 
@@ -148,35 +145,14 @@ $("#use-to-all").click(function() {
     if (treeNode.items === undefined || treeNode.items.length <= 0) {
         return false;
     }
-    // 获取所有标准清单
-    const stdBillsLibID = $("#stdBillsLibSelect").is(":visible") ?
-        $("#stdBillsLibSelect").val() : (projectInfoObj.projectInfo.engineeringInfo.bill_lib[0] !== undefined ? projectInfoObj.projectInfo.engineeringInfo.bill_lib[0].id : 0);
-    if (stdBillsLibID <= 0) {
-        return false;
-    }
-    let stdBillData = {};
-    CommonAjax.post('/stdBillsEditor/getBills', {userId: userID, billsLibId: stdBillsLibID}, function (data) {
-        if (!data instanceof Array || data.length <= 0) {
-            return false;
+    // 处理结果
+    for (const item of treeNode.items) {
+        if (item.data.jobContent === undefined || item.data.jobContent.length <= 0 ||
+            item.data.itemCharacter === undefined || item.data.itemCharacter.length <= 0 || item.data.code === undefined) {
+            continue;
         }
-        // 整理数据
-        for (const tmp of data) {
-            stdBillData[tmp.code] = tmp;
-        }
-        // 处理结果
-        for (const item of treeNode.items) {
-            if (item.data.jobContent === undefined || item.data.jobContent.length <= 0 ||
-                item.data.itemCharacter === undefined || item.data.itemCharacter.length <= 0 || item.data.code === undefined) {
-                continue;
-            }
-            const orgCode = item.data.code.substr(0, 9);
-            if (stdBillData[orgCode] === undefined) {
-                continue;
-            }
-            pageCCOprObj.nameCache = stdBillData[orgCode].name;
-            pageCCOprObj.setCharacterBySetting(item, setting);
-        }
-    });
+        pageCCOprObj.setCharacterBySetting(item, setting);
+    }
 });
 
 // 添加位置选择

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

@@ -10,7 +10,8 @@
         <li class="nav-item dropdown">
             <a class="nav-link dropdown-toggle" href="#" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="fa fa-wrench"></i> 工具</a>
             <div class="dropdown-menu">
-                <a class="dropdown-item" href="#">定额库编辑器</a>
+                <!--<a class="dropdown-item" href="/complementaryRation/main">定额库编辑器</a>-->
+                <a class="dropdown-item" href="javascript:void(0);" data-toggle="modal" data-target="#comple-ration">定额库编辑器</a>
                 <a class="dropdown-item" href="/complementaryGlj">工料机库编辑器</a>
             </div>
         </li>