Преглед изворни кода

Merge branch '1.0.0_online'

Conflicts:
	config/config.js
chenshilong пре 6 година
родитељ
комит
b66635b879
100 измењених фајлова са 3272 додато и 1103 уклоњено
  1. 2 0
      .gitignore
  2. 2 2
      Dockerfile
  3. 2 2
      Dockerfile_pp
  4. 1 1
      Dockerfile_qa
  5. 24 4
      config/config.js
  6. 3 1
      config/db/db_manager.js
  7. 38 18
      config/gulpConfig.js
  8. 1 1
      gulpfile.js
  9. 11 0
      lib/jquery-editable-select/jquery.editable-select.min.css
  10. 7 0
      lib/jquery-editable-select/jquery.editable-select.min.js
  11. 12 12
      lib/jquery-ui/jquery-ui.css
  12. 1 0
      lib/lz-string/lz-string.min.js
  13. 0 54
      lib/spreadjs/sheets/gc.spread.sheets.all.10.0.1.min.js
  14. 0 13
      lib/spreadjs/sheets/interop/angular.gc.spread.sheets.10.0.1.min.js
  15. 0 30
      lib/spreadjs/sheets/interop/gc.spread.excelio.10.0.1.min.js
  16. 36 0
      lib/spreadjs/sheets/interop/gc.spread.excelio.11.1.2.min.js
  17. 0 3
      lib/spreadjs/sheets/interop/gc.spread.sheets.migration.10.0.1.min.js
  18. 2 1
      modules/all_models/bills_template_items.js
  19. 35 0
      modules/all_models/block_lib_model.js
  20. 10 0
      modules/all_models/compilation.js
  21. 2 1
      modules/all_models/compleGlj_glj.js
  22. 23 0
      modules/all_models/compleGlj_section.js
  23. 30 0
      modules/all_models/compleGlj_sectionTemplate.js
  24. 41 0
      modules/all_models/compleRation_coe.js
  25. 30 0
      modules/all_models/compleRation_installFeeItem.js
  26. 43 0
      modules/all_models/compleRation_installSection.js
  27. 6 1
      modules/all_models/compleRation_ration.js
  28. 11 6
      modules/all_models/compleRation_section.js
  29. 34 0
      modules/all_models/comple_section_template.js
  30. 16 8
      modules/all_models/engineering_lib.js
  31. 53 0
      modules/all_models/material_replace_lib.js
  32. 2 1
      modules/all_models/mix_ratio.js
  33. 22 0
      modules/all_models/project_feature_lib.js
  34. 2 0
      modules/all_models/project_glj.js
  35. 1 0
      modules/all_models/projects.js
  36. 5 2
      modules/all_models/ration.js
  37. 7 0
      modules/all_models/ration_coe.js
  38. 2 0
      modules/all_models/ration_glj.js
  39. 27 0
      modules/all_models/ration_template.js
  40. 2 1
      modules/all_models/stdBills_bills.js
  41. 7 0
      modules/all_models/stdRation_coe.js
  42. 10 2
      modules/all_models/stdRation_ration.js
  43. 1 0
      modules/all_models/std_billsGuidance_lib.js
  44. 10 1
      modules/all_models/std_glj.js
  45. 9 8
      modules/all_models/tpl_tree_node.js
  46. 24 0
      modules/all_models/user.js
  47. 12 3
      modules/bills_lib/models/bills_lib_interfaces.js
  48. 0 2
      modules/common/base/base_controller.js
  49. 3 1
      modules/common/const/bills_fixed.js
  50. 29 28
      modules/common/const/glj_type_const.js
  51. 1 0
      modules/common/helper/mongoose_helper.js
  52. 5 1
      modules/common/std/std_glj_lib_glj_list_model.js
  53. 17 2
      modules/complementary_glj_lib/controllers/gljController.js
  54. 10 1
      modules/complementary_glj_lib/models/gljModel.js
  55. 1 0
      modules/complementary_glj_lib/routes/routes.js
  56. 94 27
      modules/complementary_ration_lib/controllers/compleRationController.js
  57. 1 1
      modules/complementary_ration_lib/controllers/compleSectionTreeController.js
  58. 51 20
      modules/complementary_ration_lib/controllers/compleViewController.js
  59. 2 2
      modules/complementary_ration_lib/controllers/searchController.js
  60. 99 0
      modules/complementary_ration_lib/facades/compleCoeFacade.js
  61. 91 0
      modules/complementary_ration_lib/facades/compleInstallFacade.js
  62. 132 55
      modules/complementary_ration_lib/models/compleRationModel.js
  63. 140 21
      modules/complementary_ration_lib/models/searchModel.js
  64. 53 6
      modules/complementary_ration_lib/models/sectionTreeModel.js
  65. 4 0
      modules/complementary_ration_lib/routes/routes.js
  66. 53 10
      modules/fee_rates/facade/fee_rates_facade.js
  67. 20 7
      modules/glj/controllers/glj_controller.js
  68. 80 0
      modules/glj/facade/glj_facade.js
  69. 22 12
      modules/glj/models/glj_list_model.js
  70. 16 3
      modules/glj/models/unit_price_file_model.js
  71. 20 10
      modules/glj/models/unit_price_model.js
  72. 65 360
      modules/main/controllers/bills_controller.js
  73. 23 0
      modules/main/controllers/block_lib_controller.js
  74. 34 0
      modules/main/controllers/material_replace_controller.js
  75. 1 2
      modules/main/controllers/project_controller.js
  76. 103 78
      modules/main/controllers/ration_controller.js
  77. 46 5
      modules/main/facade/bill_facade.js
  78. 128 0
      modules/main/facade/block_lib_facade.js
  79. 122 0
      modules/main/facade/material_replace_facade.js
  80. 27 13
      modules/main/facade/project_facade.js
  81. 301 69
      modules/main/facade/ration_facade.js
  82. 21 0
      modules/main/facade/ration_template_facade.js
  83. 11 3
      modules/main/models/bills.js
  84. 4 4
      modules/main/models/project.js
  85. 9 1
      modules/main/models/project_consts.js
  86. 2 1
      modules/main/routes/bills_route.js
  87. 19 0
      modules/main/routes/block_lib_route.js
  88. 12 9
      modules/main/routes/main_route.js
  89. 16 0
      modules/main/routes/material_replace_route.js
  90. 9 5
      modules/main/routes/ration_route.js
  91. 7 6
      modules/options/models/optionTypes.js
  92. 0 34
      modules/options/models/optionsModel.js
  93. 156 54
      modules/pm/controllers/pm_controller.js
  94. 441 35
      modules/pm/facade/pm_facade.js
  95. 115 29
      modules/pm/models/project_model.js
  96. 6 4
      modules/pm/models/project_property_template.js
  97. 1 1
      modules/pm/models/templates/bills_template_model.js
  98. 6 1
      modules/pm/routes/pm_route.js
  99. 24 4
      modules/ration_glj/controllers/ration_glj_controller.js
  100. 0 0
      modules/ration_glj/facade/glj_calculate_facade.js

+ 2 - 0
.gitignore

@@ -7,3 +7,5 @@ tmp/*.pdf
 tmp/*.jsp
 test/unit/logs
 *.log
+modules/reports/util/pdf_base_files/*.ttf
+modules/reports/util/pdf_base_files/*.ttc

+ 2 - 2
Dockerfile

@@ -1,8 +1,8 @@
-FROM costbase:latest
+FROM costbase:2.0
 
 WORKDIR /home/ConstructionCost
 
-RUN git pull http://192.168.1.12:3000/SmartCost/ConstructionCost master
+COPY . /home/ConstructionCost
 
 RUN cnpm install
 

+ 2 - 2
Dockerfile_pp

@@ -1,8 +1,8 @@
-FROM costbase:latest
+FROM costbase:2.0
 
 WORKDIR /home/ConstructionCost
 
-RUN git pull http://192.168.1.12:3000/SmartCost/ConstructionCost master
+COPY . /home/ConstructionCost
 
 RUN cnpm install
 

+ 1 - 1
Dockerfile_qa

@@ -1,4 +1,4 @@
-FROM costbase:latest
+FROM costbase:2.0
 
 WORKDIR /home/ConstructionCost
 

Разлика између датотеке није приказан због своје велике величине
+ 24 - 4
config/config.js


+ 3 - 1
config/db/db_manager.js

@@ -49,7 +49,9 @@ module.exports = {
     connect:function (env="local") {
         var config = require("../config.js");
         var dbURL = 'mongodb://' + config[env].server + ":" + config[env].port + '/scConstruct';
-        if(config[env].options){
+        if(config[env].dbURL){
+            mg.connect(config[env].dbURL,{connectTimeoutMS: 20000,useMongoClient: true});
+        } else if(config[env].options){
             mg.connect(dbURL,config[env].options);
         }else {
             mg.connect(dbURL,{connectTimeoutMS: 20000,useMongoClient: true});//useMongoClient': true*! //报 DeprecationWarning: `open()` is deprecated in mongoose这个错

+ 38 - 18
config/gulpConfig.js

@@ -6,53 +6,62 @@ module.exports = {
     version:'1.0.1',
     common_jspaths:[
         'lib/jquery/jquery-3.2.1.min.js',
+        'lib/jquery-ui/jquery-ui.min.js',
         'lib/popper/popper.min.js',
-        'lib/jquery-ui/jquery-0i.min.js',
         'lib/bootstrap/bootstrap.min.js',
         'web/building_saas/js/*.js',
         'public/web/scMathUtil.js',
         'public/web/gljUtil.js',
         'public/web/PerfectLoad.js',
         'lib/lodash/lodash.js',
-        'public/web/commonAlert.js'
+        'public/web/commonAlert.js',
+        'public/web/headerOpr.js',
+        'lib/jquery-editable-select/jquery.editable-select.min.js'
     ],
     common_css:[
+        'lib/jquery-ui/jquery-ui.css',
         'lib/bootstrap/css/bootstrap.min.css',
+        'lib/spreadjs/sheets/css/gc.spread.sheets.sc.css',
         'web/building_saas/css/main.css',
         'web/building_saas/css/custom.css',
-        'lib/font-awesome/font-awesome.min.css'
+        'lib/font-awesome/font-awesome.min.css',
+        'lib/jquery-editable-select/jquery.editable-select.min.css'
     ],
     login_jspaths:[
         'public/web/url_util.js',
-        'web/users/js/login.js'
+        'web/users/js/login.js',
     ],
     pm_css:[
         'lib/ztree/css/zTreeStyle.css',
-        'lib/spreadjs/sheets/css/gc.spread.sheets.sc.css',
         'lib/jquery-contextmenu/jquery.contextMenu.css'
     ],
     pm_jspaths:[
+        'public/web/uuid.js',
         'public/web/date_util.js',
+        'public/web/id_tree.js',
         'public/web/tree_sheet/tree_sheet_helper.js',
         'public/web/sheet/sheet_data_helper.js',
+        'public/web/sheet/sheet_common.js',
         'public/web/common_ajax.js',
         'lib/JSExpressionEval_src/Date.js',
+        'web/building_saas/glj/js/socket.io.slim.js',
+        'public/web/socket/connection.js',
         'web/building_saas/pm/js/**/*.js',
         'lib/ztree/*.js',
         'lib/jquery-contextmenu/jquery.contextMenu.min.js'
     ],
     main_css:[
         'lib/ztree/css/zTreeStyle.css',
-        'lib/jquery-ui/jquery-ui.css',
-        'lib/spreadjs/sheets/css/gc.spread.sheets.sc.css',
+        //'lib/jquery-ui/jquery-ui.css',
+        //'lib/spreadjs/sheets/css/gc.spread.sheets.sc.css',
         'lib/jquery-contextmenu/jquery.contextMenu.css'
     ],
     main_jspaths:[
         'lib/JSExpressionEval_src/*.js',
         '!lib/JSExpressionEval_src/JsHashMap.js',
-        'lib/jquery-ui/jquery-ui.min.js',
+       /* 'lib/jquery-ui/jquery-ui.min.js',
         'lib/jquery-ui/jquery-ui-datepickerCN.js',
-        'lib/jquery-contextmenu/*.js',
+        'lib/jquery-contextmenu/!*.js',*/
         //'lib/lodash/lodash.js',
         // 'test/tmp_data/test_ration_calc/ration_calc_base.js',
         'web/building_saas/main/js/models/main_consts.js',
@@ -73,6 +82,7 @@ module.exports = {
         'public/web/url_util.js',
         'public/web/number_util.js',
         'public/web/sheet/sheet_common.js',
+        'public/web/slideResize.js',
        // 'lib/ztree/*.js',
         'lib/spreadjs/sheets/gc.spread.sheets.all.11.1.2',
        // 'lib/spreadjs/views/gc.spread.views.dataview.10.0.0.min.js',
@@ -89,6 +99,7 @@ module.exports = {
         'web/building_saas/main/js/models/ration_coe.js',
         'web/building_saas/main/js/models/ration_ass.js',
         'web/building_saas/main/js/models/ration_installation.js',
+        'web/building_saas/main/js/models/ration_template.js',
         // 'web/building_saas/main/js/models/volume_price.js',
         'web/building_saas/main/js/models/labour_coe.js',
         'web/building_saas/main/js/models/installation_fee.js',
@@ -116,10 +127,12 @@ module.exports = {
         'web/building_saas/main/js/main.js',
         'web/building_saas/main/js/controllers/project_controller.js',
         'web/building_saas/main/js/controllers/block_controller.js',
+        'web/building_saas/main/js/controllers/material_controller.js',
         'web/building_saas/main/js/views/side_tools.js',
         'web/building_saas/main/js/views/std_billsGuidance_lib.js',
         'web/building_saas/main/js/views/std_bills_lib.js',
         'web/building_saas/main/js/views/std_ration_lib.js',
+        'web/building_saas/main/js/views/block_lib.js',
         'web/building_saas/main/js/models/quantity_detail.js',
         'web/building_saas/main/js/views/glj_view_contextMenu.js',
         'web/building_saas/main/js/views/calc_program_view.js',
@@ -127,8 +140,10 @@ module.exports = {
         'web/building_saas/main/js/views/zlfb_view.js',
         'web/building_saas/main/js/views/installation_fee_view.js',
         'web/building_saas/main/js/views/project_glj_view.js',
+        'web/building_saas/main/js/views/importBills.js',
         'public/web/rpt_tpl_def.js',
         'public/web/treeDataHelper.js',
+        'public/web/string_util_light.js',
         'public/web/ztree_common.js',
         'web/building_saas/report/js/rpt_main.js',
         'web/building_saas/report/js/rpt_cfg_const.js',
@@ -138,20 +153,22 @@ module.exports = {
         'web/building_saas/main/js/views/character_content_view.js',
         'web/building_saas/main/js/views/glj_view.js',
         'web/building_saas/main/js/views/zmhs_view.js',
+        'web/building_saas/main/js/views/mbzm_view.js',
         'web/building_saas/main/js/views/tender_price_view.js',
+        'web/building_saas/main/js/views/billsElf.js',
         'web/building_saas/main/js/views/sub_view.js',
         'web/building_saas/main/js/views/fee_rate_view.js',
         'web/building_saas/main/js/views/quantity_edit_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/locate_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.sc.css'
     ],
     compleGlj_jspaths: [
         'public/web/common_ajax.js',
@@ -161,6 +178,7 @@ module.exports = {
         'public/web/id_tree.js',
         'public/web/tree_sheet/tree_sheet_controller.js',
         'public/web/tree_sheet/tree_sheet_helper.js',
+        'public/web/tools_const.js',
         'public/web/ration_glj_units.js',
         'web/building_saas/complementary_glj_lib/js/glj.js',
         'web/building_saas/complementary_glj_lib/js/gljClassTree.js',
@@ -169,14 +187,17 @@ module.exports = {
         'public/web/ztree_common.js',
         'public/web/sheet/sheet_common.js',
         'web/building_saas/complementary_glj_lib/js/sheetOpr.js',
-        'public/web/storageUtil.js'
+        'public/web/storageUtil.js',
+        'public/web/slideResize.js'
     ],
     compleRation_ration_css: [
-        'lib/jquery-contextmenu/jquery.contextMenu.css',
         'lib/ztree/css/zTreeStyle.css',
-        'lib/spreadjs/sheets/css/gc.spread.sheets.sc.css'
+        'lib/jquery-contextmenu/jquery.contextMenu.css',
     ],
     compleRation_ration_jspaths:[
+        '/public/web/uuid.js',
+        'lib/jquery-contextmenu/jquery.contextMenu.min.js',
+        'lib/jquery-contextmenu/jquery.ui.position.js',
         'lib/ztree/jquery.ztree.core.js',
         'web/building_saas/complementary_ration_lib/js/global.js',
         'public/web/id_tree.js',
@@ -201,10 +222,11 @@ module.exports = {
         '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',
-        'web/building_saas/complementary_ration_lib/js/ration_installation.js.js'
+        'web/building_saas/complementary_ration_lib/js/ration_installation.js.js',
+        'public/web/slideResize.js',
+        'web/building_saas/complementary_ration_lib/js/coe.js'
     ],
     compleRation_glj_css: [
-        'lib/spreadjs/sheets/css/gc.spread.sheets.sc.css'
     ],
     compleRation_glj_jspaths: [
         'web/building_saas/complementary_ration_lib/js/global.js',
@@ -218,7 +240,6 @@ module.exports = {
         'public/web/storageUtil.js'
     ],
     compleRation_coe_css: [
-        'lib/spreadjs/sheets/css/gc.spread.sheets.sc.css'
     ],
     compleRation_coe_jspaths: [
         'web/building_saas/complementary_ration_lib/js/global.js',
@@ -232,8 +253,7 @@ module.exports = {
         'web/building_saas/complementary_ration_lib/js/coe.js'
     ],
     compleRation_inst_css: [
-        'lib/spreadjs/sheets/css/gc.spread.sheets.sc.css',
-        'lib/jquery-contextmenu/jquery.contextMenu.css'
+        'lib/jquery-contextmenu/jquery.contextMenu.css',
     ],
     compleRation_inst_jspaths: [
         'public/web/QueryParam.js',

+ 1 - 1
gulpfile.js

@@ -276,7 +276,7 @@ gulp.task('main_css',function () {
     return css(mainOptions);
 })
 
-gulp.task('main_inject',['main_minify','main_css'],function () {
+gulp.task('main_inject',['main_minify'],function () {//, ['main_minify','main_css'  ] main css 打包到一起会出现样式冲突问题, 现改成不打包
     return inject(mainOptions);
 })
 

Разлика између датотеке није приказан због своје велике величине
+ 11 - 0
lib/jquery-editable-select/jquery.editable-select.min.css


Разлика између датотеке није приказан због своје велике величине
+ 7 - 0
lib/jquery-editable-select/jquery.editable-select.min.js


+ 12 - 12
lib/jquery-ui/jquery-ui.css

@@ -979,7 +979,7 @@ a.ui-button:focus {
 .ui-widget-header .ui-state-active,
 a.ui-button:active,
 .ui-button:active,
-.ui-button.ui-state-active:hover {
+/*.ui-button.ui-state-active:hover {
 	border: 1px solid #003eff;
 	background: #007fff;
 	font-weight: normal;
@@ -989,7 +989,7 @@ a.ui-button:active,
 .ui-state-active .ui-icon-background {
 	border: #003eff;
 	background-color: #ffffff;
-}
+}*/
 .ui-state-active a,
 .ui-state-active a:link,
 .ui-state-active a:visited {
@@ -1058,38 +1058,38 @@ a.ui-button:active,
 /* Icons
 ----------------------------------*/
 
-/* states and images */
-.ui-icon {
+ states and images
+/*.ui-icon {
 	width: 16px;
 	height: 16px;
 }
-/*.ui-icon,
+.ui-icon,
 .ui-widget-content .ui-icon {
-	background-image: url("images/ui-icons_444444_256x240.png");
+	background-image: url("./images/ui-icons_444444_256x240.png");
 }
 .ui-widget-header .ui-icon {
-	background-image: url("images/ui-icons_444444_256x240.png");
+	background-image: url("./images/ui-icons_444444_256x240.png");
 }
 .ui-state-hover .ui-icon,
 .ui-state-focus .ui-icon,
 .ui-button:hover .ui-icon,
 .ui-button:focus .ui-icon {
-	background-image: url("images/ui-icons_555555_256x240.png");
+	background-image: url("./images/ui-icons_555555_256x240.png");
 }
 .ui-state-active .ui-icon,
 .ui-button:active .ui-icon {
-	background-image: url("images/ui-icons_ffffff_256x240.png");
+	background-image: url("./images/ui-icons_ffffff_256x240.png");
 }
 .ui-state-highlight .ui-icon,
 .ui-button .ui-state-highlight.ui-icon {
-	background-image: url("images/ui-icons_777620_256x240.png");
+	background-image: url("./images/ui-icons_777620_256x240.png");
 }
 .ui-state-error .ui-icon,
 .ui-state-error-text .ui-icon {
-	background-image: url("images/ui-icons_cc0000_256x240.png");
+	background-image: url("./images/ui-icons_cc0000_256x240.png");
 }
 .ui-button .ui-icon {
-	background-image: url("images/ui-icons_777777_256x240.png");
+	background-image: url("./images/ui-icons_777777_256x240.png");
 }*/
 
 /* positioning */

Разлика између датотеке није приказан због своје велике величине
+ 1 - 0
lib/lz-string/lz-string.min.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 54
lib/spreadjs/sheets/gc.spread.sheets.all.10.0.1.min.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 13
lib/spreadjs/sheets/interop/angular.gc.spread.sheets.10.0.1.min.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 30
lib/spreadjs/sheets/interop/gc.spread.excelio.10.0.1.min.js


Разлика између датотеке није приказан због своје велике величине
+ 36 - 0
lib/spreadjs/sheets/interop/gc.spread.excelio.11.1.2.min.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 3
lib/spreadjs/sheets/interop/gc.spread.sheets.migration.10.0.1.min.js


+ 2 - 1
modules/all_models/bills_template_items.js

@@ -34,7 +34,8 @@ let BillsTemplateSchema = {
     //计算基数
     calcBase: String,
     //费率ID
-    feeRateID:Number
+    feeRateID:Number,
+    quantity: String,
 };
 
 mongoose.model(collectionName, new Schema(BillsTemplateSchema, {versionKey: false, collection: collectionName}));

+ 35 - 0
modules/all_models/block_lib_model.js

@@ -0,0 +1,35 @@
+/**
+ * Created by CSL on 2018-12-17.
+ */
+let mongoose = require('mongoose');
+let Schema = mongoose.Schema;
+
+let dataSchema = new Schema({
+    ID: String,
+    NextSiblingID: String,
+    ParentID: String,
+    children: [],
+    code: String,
+    compilationID: String,
+    copyTime: Number,
+    firstNodeType: Number,
+    isFBFX: {type: Boolean, default: true},
+    itemCharacterText: String,
+    name: String,
+    nodeName: String,
+    type: Number,
+    unit: String,
+    unitFee: String,
+    _id: false
+},{versionKey:false});
+
+let blockLibsSchema = new Schema({
+    userID: String,
+    compilationID: String,
+    libID: String,
+    libName: String,
+    datas: [dataSchema],
+    share: {}
+},{versionKey:false});
+
+mongoose.model('blockLibsModel', blockLibsSchema, 'block_libs');

+ 10 - 0
modules/all_models/compilation.js

@@ -49,6 +49,10 @@ let modelSchema = {
     name: String,
     //描述
     description: String,
+    //例题
+    example: [],
+    //代码覆盖路径
+    overWriteUrl:String,
     // 创建时间
     create_time: Number,
     // 创建者id
@@ -57,6 +61,12 @@ let modelSchema = {
     release_time: {
         type: Number,
         default: 0
+    },
+
+    // cld 办事处id
+    categoryID: {
+        type: Number,
+        default: 12 // 总部id
     }
 };
 mongoose.model(collectionName, new Schema(modelSchema, {versionKey: false, collection: collectionName}));

+ 2 - 1
modules/all_models/compleGlj_glj.js

@@ -24,8 +24,9 @@ const comple_glj = new Schema({
     specs: String,
     unit: String,
     basePrice: String,
-    gljClass: Number,
+    gljClass: String,
     gljType: Number,
+    model: Number,
     shortName: String,
     component: [comple_gljComponent]
 }, {versionKey: false});

+ 23 - 0
modules/all_models/compleGlj_section.js

@@ -0,0 +1,23 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2018/12/13
+ * @version
+ */
+
+import mongoose from 'mongoose';
+
+const Schema = mongoose.Schema;
+const compleGljSection = new Schema({
+    userId: String,
+    compilationId: String,
+    Name: String,
+    ID: String,
+    ParentID: String,
+    NextSiblingID: String,
+});
+
+mongoose.model('complementary_glj_section', compleGljSection, 'complementary_glj_section');

+ 30 - 0
modules/all_models/compleGlj_sectionTemplate.js

@@ -0,0 +1,30 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2018/12/13
+ * @version
+ */
+
+/*
+ * 我的补充人材机库章节树模板,一个费用定额有一个模板
+ * 模板的生成目前由手工生成(借助定额库编辑器的章节树编辑)
+ * 新用户第一次进入某费用定额的补充定额库时,拷贝模板给该用户
+ *
+ * */
+
+import mongoose from 'mongoose';
+
+const Schema = mongoose.Schema;
+const compleGljSectionTemp = new Schema({
+    compilationId: String,
+    Name: String,
+    ID: Number,
+    ParentID: Number,
+    NextSiblingID: Number,
+});
+
+mongoose.model('complementary_glj_section_templates', compleGljSectionTemp, 'complementary_glj_section_templates');
+

+ 41 - 0
modules/all_models/compleRation_coe.js

@@ -0,0 +1,41 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2018/10/23
+ * @version
+ */
+
+/*
+* 补充定额库用户新增子目换算
+* 用户ID与费用定额ID绑定子目换算
+* */
+
+import mongoose from 'mongoose';
+const deleteSchema = require('../all_schemas/delete_schema');
+const Schema = mongoose.Schema;
+const coeSchema = new Schema({
+    coeType: String,                // 系数类型
+    gljCode: String,                //要调整的人材机编码
+    gljName: String,
+    operator: String,               // 运算符(*、+、-、=)
+    amount: String,                 // 调整的量
+    replaceCode:String,
+    replaceName:String,
+    _id: false
+});
+
+const coeListSchema = new Schema({
+    userId: String,
+    compilationId: String,
+    ID: Number,
+    serialNo: Number,                  //编号
+    name: String,                       // 名称
+    content: String,                    // 说明
+    coes: [coeSchema],
+    deleteInfo: deleteSchema
+}, {versionKey: false});
+
+mongoose.model('complementary_ration_coe_list', coeListSchema, 'complementary_ration_coe_list');

+ 30 - 0
modules/all_models/compleRation_installFeeItem.js

@@ -0,0 +1,30 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2018/10/23
+ * @version
+ */
+
+/*
+* 补充定额库用户新增安装增加费费用项
+*
+* */
+const mongoose = require('mongoose');
+const Schema = mongoose.Schema;
+const deleteSchema = require('../all_schemas/delete_schema');
+//补充安装增加费-费用项
+const installFeeItemSchema = new Schema({
+    userId: String,
+    compilationId: String,
+    ID: String,
+    feeItem: String, //费用项
+    feeType: String, //费用类型
+    position: String, //记取位置
+    section: [],
+    deleteInfo: deleteSchema
+}, {versionKey: false});
+
+mongoose.model('complementary_ration_installation', installFeeItemSchema, 'complementary_ration_installation');

+ 43 - 0
modules/all_models/compleRation_installSection.js

@@ -0,0 +1,43 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2018/10/23
+ * @version
+ */
+
+/*
+* 补充定额库用户新增安装增加费分册章节
+*
+*
+* */
+
+const mongoose = require('mongoose');
+const Schema = mongoose.Schema;
+const deleteSchema = require('../all_schemas/delete_schema');
+//安装增加费-费用规则
+const feeRuleSchema = new Schema({
+    ID: String,
+    code: String,
+    rule: String,
+    base: String,
+    feeRate: Number,
+    labour: Number,
+    material: Number,
+    machine: Number
+});
+
+//补充安装增加费-分册章节
+const installSectionSchema = new Schema({
+    userId: String,
+    compilationId: String,
+    ID: String,
+    feeItemId: String,
+    name: String,
+    feeRule: [feeRuleSchema],
+    deleteInfo: deleteSchema
+}, {versionKey: false});
+
+mongoose.model('complementary_ration_installationSection', installSectionSchema, 'complementary_ration_installationSection');

+ 6 - 1
modules/all_models/compleRation_ration.js

@@ -46,7 +46,7 @@ const compleRationSchema = new Schema({
     materialPrice: String,
     machinePrice: String,
     basePrice: String,
-    sectionId: Number,
+    sectionId: String,
     caption: String,
     feeType: Number,
     jobContent: String,
@@ -55,6 +55,11 @@ const compleRationSchema = new Schema({
     rationCoeList: Array,
     rationAssList: [compleRationAssItemSchema],
     rationInstList: [rationInstSchema],
+    rationTemplateList : [new Schema({
+        rationID:Number,
+        type: String,
+        billsLocation: String
+    }, { _id: false })],
     deleteInfo: deleteSchema
 }, {versionKey: false});
 

+ 11 - 6
modules/all_models/compleRation_section.js

@@ -12,15 +12,20 @@ const compleRationSectionTreeSchema = new Schema({
     //编办
     compilationId: String,
     //标准定额库
-    rationRepId: Number,
+    //rationRepId: Number,
     //名称
     name: String,
     //是否是同层第一个节点
-    isFirst: Boolean,
-    ID: Number,
-    NextSiblingID: Number,
-    ParentID: Number,
-    deleteInfo: deleteSchema
+   // isFirst: Boolean,
+    ID: String,
+    NextSiblingID: String,
+    ParentID: String,
+    deleteInfo: deleteSchema,
+    //以下预留数据,以后开放可用
+    explanation: String,//说明
+    ruleText: String,//计算规则,
+    jobContentSituation: String,//工作内容适用情况,ALL适用本项全部定额,PARTIAL适用本项部分定额
+    annotationSituation: String,//附注适用情况,ALL适用本项全部定额,PARTIAL适用本项部分定额
 }, {versionKey: false});
 
 mongoose.model('complementary_ration_section_tree', compleRationSectionTreeSchema, 'complementary_ration_section_tree');

+ 34 - 0
modules/all_models/comple_section_template.js

@@ -0,0 +1,34 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2018/10/23
+ * @version
+ */
+
+/*
+* 我的补充定额库章节树模板,一个费用定额有一个模板
+* 模板的生成目前由手工生成(借助定额库编辑器的章节树编辑)
+* 新用户第一次进入某费用定额的补充定额库时,拷贝模板给该用户
+*
+* */
+
+import mongoose from 'mongoose';
+
+const Schema = mongoose.Schema;
+const compleRationSectionTemp = new Schema({
+    compilationId: String,
+    name: String,
+    ID: Number,
+    ParentID: Number,
+    NextSiblingID: Number,
+    //以下预留结构,以防后续需要默认数据
+    explanation: String,//说明
+    ruleText: String,//计算规则,
+    jobContentSituation: String,//工作内容适用情况,ALL适用本项全部定额,PARTIAL适用本项部分定额
+    annotationSituation: String,//附注适用情况,ALL适用本项全部定额,PARTIAL适用本项部分定额
+});
+
+mongoose.model('complementary_ration_section_templates', compleRationSectionTemp, 'complementary_ration_section_templates');

+ 16 - 8
modules/all_models/engineering_lib.js

@@ -13,7 +13,8 @@ let taxGroupSchema = new  Schema({
     taxType: String,//计税方式
     program_lib: { type: Schema.Types.Mixed,default:{}},// 计算程序标准库
     template_lib:{ type: Schema.Types.Mixed,default:{}},//清单模板库
-    col_lib:{ type: Schema.Types.Mixed,default:{}}
+    col_lib:{ type: Schema.Types.Mixed,default:{}},
+    fee_lib:{ type: Schema.Types.Mixed,default:{}}//费率标准库
 },{_id: false});
 
 let modelSchema = {
@@ -41,16 +42,21 @@ let modelSchema = {
         type: [taxGroupSchema],
         default: []
     },
-    // 费率标准库
+   /* // 费率标准库
     fee_lib: {
         type: Schema.Types.Mixed,
         default: []
-    },
+    },*/
     // 人工系数标准库
     artificial_lib: {
         type: Schema.Types.Mixed,
         default: []
     },
+    //工程特征库
+    feature_lib:{
+        type: Schema.Types.Mixed,
+        default: []
+    },
     //设置人材机显示列
     glj_col:{
         showAdjustPrice:Boolean//是否显示调整价列
@@ -59,12 +65,14 @@ let modelSchema = {
     valuationID:{type:String,index: true},
     //工程专业名称
     name:String,
+    //费用标准
+    feeName:String,
     //前端是否显示
-    visible:{
-        type: Boolean,
-        default: false
-    },
-    engineering:Number
+    visible:{type: Boolean, default: false},
+    //取费专业
+    engineering:Number,
+    //是否计算安装增加费
+    isInstall:{type: Boolean, default: false}
 };
 mongoose.model(collectionName, new Schema(modelSchema, {versionKey: false, collection: collectionName}));
 

+ 53 - 0
modules/all_models/material_replace_lib.js

@@ -0,0 +1,53 @@
+/**
+ * Created by zhang on 2018/8/22.
+ */
+//材料替换库
+const mongoose = require('mongoose');
+const Schema = mongoose.Schema;
+const oprSchema = require('../all_schemas/opr_schema');
+const material_lib = new Schema({
+        ID:{type:String,index:true},
+        creator: String,
+        createDate: Number,
+        recentOpr: [oprSchema],
+        name: String,
+        compilationId: String,
+        compilationName: String,
+        billsLibId:Number,
+        billsLibName:String,
+        deleted: Boolean
+    }, {versionKey: false}
+);
+
+mongoose.model("std_material_replace_lib", material_lib,"std_material_replace_lib");
+
+
+const std_replace_bills = new Schema({
+        ID: {type:String,index:true},
+        libID:{type:String,index:true},
+        code: {type:String,index:true},
+        name: String,
+        rule:Number//规则类型
+    }, {versionKey: false}
+);
+
+mongoose.model('std_replace_bills', std_replace_bills, 'std_replace_bills');
+
+
+const std_replace_material = new Schema({
+    ID: {type:String,index:true},
+    libID:{type:String,index:true},
+    billsItemID:{type:String,index:true},
+    code: String,
+    name: String,
+    specs: String,
+    type: Number,
+    unit: String
+},{versionKey: false});
+
+mongoose.model('std_replace_material', std_replace_material, 'std_replace_material');
+
+
+
+
+

+ 2 - 1
modules/all_models/mix_ratio.js

@@ -45,6 +45,7 @@ let modelSchema = {
     // 对应工料机code
     code: String,
     // 工料机类型
-    type: Number
+    type: Number,
+    model: Number// 机型
 };
 mongoose.model(collectionName, new Schema(modelSchema, {versionKey: false, collection: collectionName}));

+ 22 - 0
modules/all_models/project_feature_lib.js

@@ -0,0 +1,22 @@
+/**
+ * Created by zhang on 2018/9/3.
+ */
+
+//工程特征库
+const mongoose = require('mongoose');
+const Schema = mongoose.Schema;
+const oprSchema = require('../all_schemas/opr_schema');
+const project_feature_lib = new Schema({
+        ID:{type:String,index:true},
+        creator: String,
+        createDate: Number,
+        recentOpr: [oprSchema],
+        name: String,
+        feature:{
+            type: [Schema.Types.Mixed],
+            default: []
+        }
+    }, {versionKey: false}
+);
+
+mongoose.model("std_project_feature_lib", project_feature_lib,"std_project_feature_lib");

+ 2 - 0
modules/all_models/project_glj.js

@@ -75,6 +75,8 @@ let modelSchema = {
     },
     // 类型
     type: Number,
+    // 机型
+    model: Number,
     // 单位
     unit: String,
     // 显示调整基价

+ 1 - 0
modules/all_models/projects.js

@@ -10,6 +10,7 @@ const collectionName = 'projects';
 const shareSchema = new Schema({
     userID: String, //userID
     allowCopy: {type: Boolean, default: false},
+    allowCooperate: {type: Boolean, default: false},
     shareDate: String,
 }, {versionKey: false, _id: false});
 const ProjectSchema = new Schema({

+ 5 - 2
modules/all_models/ration.js

@@ -51,12 +51,13 @@ let rationSchema = new Schema({
     from:{type: String,default:'std'},          //std, cpt  来自标准、补充
     isSubcontract: Boolean,                     // 是否分包
     installationKey:String,                   //用来记录安装增加费的关联字段
-
     // 定额特有属性:
+    stdID: Number,                            //来自的标准定额ID
     libID: Number,
     maskName: String,
     caption: String,
-    isFromDetail:{type: Number,default:0},       // 1 true 2 false
+    evaluationProject:{type: Number,default:0},       // 1 true 0 false 估价项目
+    isFromDetail:{type: Number,default:0},       // 1 true 0 false
     adjustState: String,
     rationProjName: String,
     comments: String,                           // 说明
@@ -66,6 +67,7 @@ let rationSchema = new Schema({
     annotation: String,                         //附注
     ruleText: String,                            // 计算规则
     prefix: {type: String, default: ''},                              //定额是补充、借用时用  补 借
+    referenceRationID:String,//如果是通过模板关联子目生成的定额,这里记录对应的主定额ID
 
     //工料机特有属性
     projectGLJID:Number,  //项目工料机ID
@@ -74,6 +76,7 @@ let rationSchema = new Schema({
     specs:String,//规格型号
     shortName:String,//缩写
     customQuantity:String,//自定义消耗
+    model: Number,// 机型
     adjCoe:Number,
     remark:String
 });

+ 7 - 0
modules/all_models/ration_coe.js

@@ -7,8 +7,11 @@ var mongoose = require('mongoose'),
 var coeSchema = mongoose.Schema({
     coeType: String,                // 系数类型,指作用范围:// 单个(如:111量0.001)、人工类、材料类、机械类、全部(如:定额×0.925)。
     gljCode: String,                  // 要调整的工料机ID(当coeType=0时有效)
+    gljName: String,
     operator: String,               // 运算符(*、+、-、=)
     amount: Number,                 // 调整的量
+    replaceCode:String,
+    replaceName:String,
     _id: false
 });
 
@@ -17,6 +20,10 @@ var coeListSchema = mongoose.Schema({
     ID: String,                         // 系数ID(流水号ID)
     name: String,                       // 名称
     content: String,                    // 说明
+    original_code:String,               //原人材机编码
+    option_codes:String,                //可选人材机编码
+    option_list:[Schema.Types.Mixed],//下拉列表选项
+    select_code:String,
     rationID:String,
     projectID:Number,
     coeID:Number,

+ 2 - 0
modules/all_models/ration_glj.js

@@ -24,6 +24,8 @@ var ration_glj = new Schema({
     shortName:String,
     billsItemID: String,
     type:Number,
+    // 机型
+    model: Number,
     // 调整系数ID
     adjCoe: Number,
     quantity:String,

+ 27 - 0
modules/all_models/ration_template.js

@@ -0,0 +1,27 @@
+/**
+ * Created by zhang on 2018/11/26.
+ */
+
+var mongoose = require('mongoose'),
+    Schema = mongoose.Schema;
+
+let ration_template =  new Schema({
+    ID:String,
+    projectID: Number,
+    rationID:String,
+    createLocation:Number,//提取位置
+    templateList:[new Schema({
+        code:String,
+        name:String,
+        type:String,
+        defaultLocation:String,//记录默认给定的清单编号,恢复原始数据时用(目前复制整块)
+        billsLocation:String,//这个是清单编号
+        fxID:String,//这个是分项对应的ID
+        unit:String,
+        quantity:String,
+        coe:String,
+        billID:String//记取位置对应的清单ID
+    },{ _id: false })]
+},{versionKey:false});
+
+mongoose.model('ration_template', ration_template,"ration_template");

+ 2 - 1
modules/all_models/stdBills_bills.js

@@ -14,10 +14,11 @@ const stdBills_bills = new Schema({
             ruleText: String,
             engineering: Number, //工程专业,填计算程序工程专业ID
             Expression: String,
+            comment: String, //备注,后台清单精灵录入
             jobs: [],
             items: [],
             recharge:String,
-            billsLibId: Number,
+            billsLibId: {type:Number, index: true},
             deleted: Boolean
     },
     {versionKey: false}

+ 7 - 0
modules/all_models/stdRation_coe.js

@@ -10,6 +10,10 @@ const coeSchema = new Schema({
     gljID: Number,                  // 要调整的工料机ID(当coeType=0时有效)
     operator: String,               // 运算符(*、+、-、=)
     amount: String,                 // 调整的量
+    gljCode: String,
+    gljName: String,
+    replaceCode:String,
+    replaceName:String,
     _id: false
 });
 
@@ -19,6 +23,9 @@ const coeListSchema = new Schema({
     serialNo: Number,                  //编号
     name: String,                       // 名称
     content: String,                    // 说明
+    original_code:String,               //原人材机编码
+    option_codes:String,                //可选人材机编码
+    option_list:[Schema.Types.Mixed],//下拉列表选项
     coes: [coeSchema]
 }, {versionKey: false});
 

+ 10 - 2
modules/all_models/stdRation_ration.js

@@ -34,6 +34,9 @@ const rationItemSchema = new Schema({
     name: String,
     unit: String,
     basePrice: Number,
+    labourPrice: Number,
+    materialPrice: Number,
+    machinePrice: Number,
     sectionId: Number,
     rationRepId: Number,
     caption: String,
@@ -43,7 +46,12 @@ const rationItemSchema = new Schema({
     rationGljList: [rationGljItemSchema],
     rationCoeList: Array,
     rationAssList: [rationAssItemSchema],
-    rationInstList: [rationInstSchema]
-});
+    rationInstList: [rationInstSchema],
+    rationTemplateList : [new Schema({
+        rationID:Number,
+        type: String,
+        billsLocation: String
+    }, { _id: false })]
 
+});
 mongoose.model('std_ration_lib_ration_items', rationItemSchema, 'std_ration_lib_ration_items');

+ 1 - 0
modules/all_models/std_billsGuidance_lib.js

@@ -12,6 +12,7 @@ const mongoose = require('mongoose');
 const Schema = mongoose.Schema;
 
 const stdBillsGuidanceLib = new Schema({
+    type: Number, //1:清单指引, 2:清单精灵
     ID: String, //uuid
     compilationId: String,
     compilationName: String,

+ 10 - 1
modules/all_models/std_glj.js

@@ -8,7 +8,11 @@ const Schema = mongoose.Schema;
 const std_gljComponent = new Schema(
     {
         ID: Number,
-        consumeAmt: Number
+        consumeAmt: Number,
+        consumeAmtProperty: {
+            type: Schema.Types.Mixed,
+            default: {}
+        }
     },
     {_id: false},
     {versionKey: false}
@@ -22,8 +26,13 @@ const std_glj = new Schema({
     name: String,
     specs: String,
     basePrice: Number,
+    priceProperty: {
+        type: Schema.Types.Mixed,
+        default: {}
+    },
     gljClass: Number,
     gljType: Number,
+    model: Number,// 机型
     shortName: String,
     unit: String,
     adjCoe: Number,

+ 9 - 8
modules/all_models/tpl_tree_node.js

@@ -28,14 +28,15 @@ let TplNodeSchema = new Schema({
 });
 
 let RptTplTreeSchema = new Schema({
-    compilationId: String,  //编办的ObjectId
-    // engineerId: Number,     //工程专业Id(参考 /modules/common/const/engineering.js)
-    userId: String,        //用户名的object_id串
-    properties: [],         //这是一个预留的属性,假定未来还会有不同的划分细节(如:招标/投标/清单 ... etc)
-    name: String,           //显示名称
-    released: Boolean,      //是否已发布
-    isDeleted: Boolean,     //删除标记
-    items: []               //TplNodeSchema entity
+    compilationId: String,      //编办的ObjectId
+    // engineerId: Number,         //工程专业Id(参考 /modules/common/const/engineering.js)
+    userId: String,             //用户名的object_id串
+    properties: [],             //这是一个预留的属性,假定未来还会有不同的划分细节(如:招标/投标/清单 ... etc)
+    name: String,               //显示名称
+    released: Boolean,          //是否已发布
+    isDeleted: Boolean,         //删除标记
+    flags: Schema.Types.Mixed,  //额外标记集合(这些标记可能会影响到前端显示,如‘计税方式’等)
+    items: []                   //TplNodeSchema entity
 });
 RptTplTreeSchema.statics.findAndModify = function (query, sort, doc, options, callback) {
     return this.collection.findAndModify(query, sort, doc, options, callback);

+ 24 - 0
modules/all_models/user.js

@@ -25,6 +25,17 @@ const versionSchema = new Schema({
     invalidInfo: [invalidSchema]
 });
 
+let upgrade = mongoose.Schema({
+    compilationID:String,//编办ID
+    upgrade_time:Number,
+    isUpgrade:Boolean,
+    remark:String//描述:广东办刘飞 2018-06-17 启用/关闭
+}, { _id: false })
+
+const userdList = mongoose.Schema({
+    compilationId: String
+}, {_id: false});
+
 // 表结构
 let schema = {
     ssoId: Number,
@@ -55,10 +66,23 @@ let schema = {
         type: Number,
         default: -1
     },
+    // 最后登录时间
+    latest_login: {
+        type: Number,
+        default: 0
+    },
+    //最近使用编办
+    latest_used:String,
     create_time: Number,
+    upgrade_list:[upgrade],
     user_type:{
         type:String,
         default:'normal'//  normal : 普通用户,test:测试用户
+    },
+    //使用过的费用定额,主要目的拷贝用户在该费用定额下的一些数据模板 eg:用户第一次进入该费用定额的补充定额库时,拷贝补充定额的章节树
+    used_list: {
+        type: [userdList],
+        default: []
     }
 };
 mongoose.model(collectionName, new Schema(schema, {versionKey: false}));

+ 12 - 3
modules/bills_lib/models/bills_lib_interfaces.js

@@ -4,6 +4,7 @@
 let mongoose = require('mongoose');
 let counter = require("../../../public/counter/counter");
 let async = require("async");
+let _ = require("lodash");
 let StdBillsLib = mongoose.model('std_bills_lib_list');
 let Bills = mongoose.model('std_bills_lib_bills');
 let JobContent = mongoose.model('std_bills_lib_jobContent');
@@ -225,7 +226,7 @@ billsLibDao.prototype.getCurrentUniqId = function(callback){
 }
 //----------------------------Bills---------------------
 billsLibDao.prototype.getBills = function (billsLibId, callback) {
-    Bills.find({billsLibId: billsLibId, deleted: false}, "-_id",  function(err, billsData){
+    Bills.find({billsLibId: billsLibId}, "-_id -ruleText -recharge",  function(err, billsData){
         if(err){
             callback(1, "Error", null);
         }
@@ -3069,10 +3070,12 @@ billsLibDao.prototype.getStdBillsByCode = async function (data, callback) {
             //设置项目特征
             let itemCharacters = await ItemCharacter.find({billsLibId: data.billsLibId, deleted: false}, '-_id');
             bills._doc.itemCharacter = [];
+            bills.items = _.sortBy(bills.items,"serialNo");//排序
             if(itemCharacters && bills.items){
                 for(let item of bills.items){
                     let itemData = findData(item, 'id', itemCharacters);
                     if(itemData){
+                        itemData._doc.serialNo = item.serialNo;
                         bills._doc.itemCharacter.push(itemData);
                     }
                 }
@@ -3081,20 +3084,26 @@ billsLibDao.prototype.getStdBillsByCode = async function (data, callback) {
             //设置工作内容
             let jobContents = await JobContent.find({billsLibId: data.billsLibId, deleted: false}, '-_id');
             bills._doc.jobContent = [];
+            bills.jobs = _.sortBy(bills.jobs,"serialNo");//排序
             if(jobContents && bills.jobs){
                 for(let job of bills.jobs){
                     let jobData = findData(job, 'id', jobContents);
                     jobData.isChecked = true;
+                    jobData._doc.serialNo = job.serialNo;
                     bills._doc.jobContent.push(jobData);
                 }
             }
             bills._doc.jobContentText = MergeData(bills._doc.jobContent);
         }
-        callback(0, '', bills);
-
+        if(callback){
+            callback(0, '', bills);
+        }else {
+            return bills;
+        }
     }
     catch(err){
         callback(1, err, null);
+        return null;
     }
 };
 billsLibDao.prototype.getStdBillsByCodet = function (data, callback) {

+ 0 - 2
modules/common/base/base_controller.js

@@ -60,8 +60,6 @@ class BaseController {
         // 获取当前用户消息数量
         let userMessageModel = new UserMessageModel();
         // 消息处理
-        console.log(`sessionUser`);
-        console.log(sessionUser);
         await userMessageModel.initMessage(sessionUser.id);
         // 获取未读数据
         let messageUnreadCount = await userMessageModel.count({user_id: sessionUser.id, is_read: 0, is_delete: 0});

+ 3 - 1
modules/common/const/bills_fixed.js

@@ -39,7 +39,9 @@ const fixedFlag = {
     // 税金
     TAX: 18,
     //工程造价
-    ENGINEERINGCOST: 19
+    ENGINEERINGCOST: 19,
+    //增值税
+    ADDED_VALUE_TAX: 20
 };
 
 export default fixedFlag;

+ 29 - 28
modules/common/const/glj_type_const.js

@@ -7,34 +7,35 @@
  */
 
 const gljType = {
-    // 人工
-    LABOUR: 1,
-    // ==============材料类型=================
-    // 普通材料
-    GENERAL_MATERIAL: 201,
-    // 混凝土
-    CONCRETE: 202,
-    // 砂浆
-    MORTAR: 203,
-    // 配合比
-    MIX_RATIO: 204,
-    // 商品混凝土
-    COMMERCIAL_CONCRETE: 205,
-    // 商品砂浆
-    COMMERCIAL_MORTAR: 206,
-    // ==============材料类型=================
-    // ==============机械类型=================
-    // 普通机械
-    GENERAL_MACHINE: 301,
-    // 机械组成物
-    MACHINE_COMPOSITION: 302,
-    // 机上人工
-    MACHINE_LABOUR: 303,
-    // ==============机械类型=================
-    // 主材
-    MAIN_MATERIAL: 4,
-    // 设备
-    EQUIPMENT: 5
+    LABOUR: 1,                                  // 人工
+    // ==============材料类型 ↓=================
+    GENERAL_MATERIAL: 201,                      // 普通材料
+    CONCRETE: 202,                              // 混凝土
+    MORTAR: 203,                                // 砂浆
+    MIX_RATIO: 204,                             // 配合比
+    COMMERCIAL_CONCRETE: 205,                   // 商品混凝土
+    COMMERCIAL_MORTAR: 206,                     // 商品砂浆
+    OTHER_MATERIAL: 207,                        // 其它材料
+    // ==============材料类型 ↑=================
+    // ==============机械类型 ↓=================
+    GENERAL_MACHINE: 301,                       // 机械台班
+    MACHINE_COMPOSITION: 302,                   // 机械组成物
+    MACHINE_LABOUR: 303,                        // 机上人工
+    INSTRUMENT: 304,                            // 仪器仪表
+    FUEL_POWER_FEE:305,                         // 燃料动力费
+    DEPRECIATION_FEE:306,                       // 折旧费
+    INSPECTION_FEE:307,                         // 检修费
+    MAINTENANCE:308,                            // 维护费
+    DISMANTLING_FREIGHT_FEE:309,                // 安拆费及场外运费
+    VERIFICATION_FEE:310,                       // 校验费
+    OTHER_FEE:311,                              // 其他费用
+    OTHER_MACHINE_USED:312,                     // 其他施工机具使用费
+    // ==============机械类型 ↑=================
+    MAIN_MATERIAL: 4,                           // 主材
+    EQUIPMENT: 5,                               // 设备
+    MANAGEMENT_FEE: 6,                          // 企业管理费
+    PROFIT: 7,                                  // 利润
+    GENERAL_RISK_FEE: 8                         // 一般风险费
 };
 
 export default gljType;

+ 1 - 0
modules/common/helper/mongoose_helper.js

@@ -221,6 +221,7 @@ class MongooseHelper {
         if (condition === null || condition._id === undefined) {
             return condition;
         }
+        condition._id = condition._id.toString();
         let result = mongoose.Types.ObjectId(condition._id);
         condition._id = result;
 

+ 5 - 1
modules/common/std/std_glj_lib_glj_list_model.js

@@ -64,7 +64,11 @@ class STDGLJLibGLJListModel extends BaseModel {
         // 整理数据
         for (let component of libGljData.component) {
             componentIdList.push(component.ID);
-            componentConsume[component.ID] = component.consumeAmt;
+            if(component.consumeAmt != undefined && component.consumeAmt != null) {
+                componentConsume[component.ID] = component.consumeAmt;
+            }else if(component.consumeAmtProperty){
+                componentConsume[component.ID] = component.consumeAmtProperty;
+            }
         }
 
         let condition = {ID: {$in: componentIdList}};

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

@@ -33,12 +33,16 @@ class GljController extends BaseController{
             let engineeringInfo = await engineeringLibModel.findDataByCondition({'valuationID': {"$in": valuationIDs},"glj_lib.0": {$exists:1}});//数组大于0
             gljLibId = engineeringInfo.glj_lib.length > 0 && typeof engineeringInfo.glj_lib !== 'undefined' ? engineeringInfo.glj_lib[0].id : null;
         }
+        let overWriteUrl = req.session.sessionCompilation && req.session.sessionCompilation.overWriteUrl &&
+                            req.session.sessionCompilation._id !== '5b4d581023a924000b760f2d' ? req.session.sessionCompilation.overWriteUrl : null;
         res.render('building_saas/complementary_glj_lib/html/tools-gongliaoji.html',{
             userID: req.session.sessionUser.id,
             gljLibId: gljLibId,
             compilationId: sessionCompilation._id,
-            versionName: req.session.sessionCompilation.name + '免费版',
-            LicenseKey:config.getLicenseKey(process.env.NODE_ENV)
+            compilationName: sessionCompilation.name,
+            versionName: `纵横建筑云计价(${req.session.compilationVersion})`,
+            LicenseKey:config.getLicenseKey(process.env.NODE_ENV),
+            overWriteUrl: overWriteUrl,
         });
     }
     getGljDistType (req, res) {
@@ -57,6 +61,17 @@ class GljController extends BaseController{
             callback(req,res,err, 'Get Tree', data)
         });
     }
+    //获取标准分类树和补充分类树
+    async getMixedTree(req, res){
+        try {
+            let data = JSON.parse(req.body.data);
+            let treeData = await gljDao.getMixedTree(data.gljLibId, req.session.sessionUser.id, req.session.sessionCompilation._id);
+            callback(req, res, 0, 'success', treeData);
+        } catch (err) {
+            console.log(err);
+            callback(req, res, 1, err, null);
+        }
+    }
 
     createNewGljTypeNode(req, res) {
         let repId = req.body.repositoryId;

+ 10 - 1
modules/complementary_glj_lib/models/gljModel.js

@@ -5,13 +5,14 @@ const mongoose = require('mongoose');
 const complementaryGljModel = mongoose.model('complementary_glj_lib');
 const stdGljModel = mongoose.model('std_glj_lib_gljList');
 const gljClassModel = mongoose.model('std_glj_lib_gljClass');
+const compleClassModel = mongoose.model('complementary_glj_section');
 import counter from "../../../public/counter/counter";
 import async from "async";
 import STDGLJLibGLJListModel from "../../common/std/std_glj_lib_glj_list_model";
 
 class GljDao {
     getGljTypes (gljLibId, callback){
-        gljClassModel.find({"repositoryId": gljLibId, "$or": [{"isDeleted": null}, {"isDeleted": false} ]},function(err,data){
+        gljClassModel.find({"repositoryId": gljLibId},function(err,data){
             if(data.length) {
                 callback(0,data);
             }
@@ -286,6 +287,7 @@ class GljDao {
                 componentIdListCpt.push(component.ID);
             }
             let isStdFlag = component.isStd ? 'std' : 'cpt';
+            //对于补充人材机的组成物,不会有多单价的情况
             componentConsume[component.ID + '_' + isStdFlag] = component.consumeAmt;
         }
 
@@ -334,6 +336,13 @@ class GljDao {
 
         return result;
     }
+
+    async getMixedTree(gljLibId, userId, compilationId){
+        let rst = {std: [], comple: []};
+        rst.std = await gljClassModel.find({repositoryId: gljLibId});
+        rst.comple = await compleClassModel.find({userId: userId, compilationId: compilationId});
+        return rst;
+    }
 }
 
 export default GljDao;

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

@@ -26,6 +26,7 @@ module.exports = function (app) {
     router.post("/updateRationBasePrc",compleRationController.init, compleRationController.updateRationBasePrc);//更新定额单价
     //router.post("/getGljItemsByIds", gljController.init, gljController.getGljItemsByIds);
     //router.post("/getGljItemsByCodes", gljController.init, gljController.getGljItemsByCodes);
+    router.post('/getMixedTree', gljController.init, gljController.getMixedTree);
 
     app.use("/complementartGlj/api", router);
 

+ 94 - 27
modules/complementary_ration_lib/controllers/compleRationController.js

@@ -7,14 +7,21 @@ import CompleRationDao from '../models/compleRationModel';
 
 let compleRationDao = new CompleRationDao();
 let coeListDAO = require('../../ration_repository/models/coe');
+const coeFacade = require('../facades/compleCoeFacade');
+const installFacade = require('../facades/compleInstallFacade');
 let callback = function (req, res, err, msg, data) {
     res.json({error: err, message: msg, data: data})
-}
+};
+const libType = {
+    complementary: 0,
+    std: 1
+};
+
 
 class CompleRationController extends BaseController{
     getRationItems(req, res){
         let data = JSON.parse(req.body.data);
-        compleRationDao.getRationItems(req.session.sessionUser.id, data.rationRepId, data.sectionId, function (err, data) {
+        compleRationDao.getRationItems(data.sectionId, function (err, data) {
             callback(req, res, err, '', data);
         });
     }
@@ -78,39 +85,99 @@ class CompleRationController extends BaseController{
         });
     }
 
-    getRationGljItemsBySection(req, res){
-        let data = JSON.parse(req.body.data);
-        compleRationDao.getRationGljItemsBySection(req.session.sessionUser.id, data.sectionId, function (err, data) {
-            callback(req, res, err, '', data);
-        });
+    async getRationGljItemsBySection(req, res){
+        let data = JSON.parse(req.body.data),
+            rations = [];
+        try {
+            if (data.type === libType.complementary) {
+                rations = await compleRationDao.getCompleRationBySection(req.session.sessionUser.id, data.sectionId);
+            }  else {
+                rations = await compleRationDao.getRationGljItemsBySection(data.sectionId);
+            }
+            callback(req, res, 0, 'success', rations);
+        } catch (err) {
+            callback(req, res, 1, err, rations);
+        }
     }
 
-    getCoeList(req, res){
-        let data = JSON.parse(req.body.data);
-        coeListDAO.getCoesByLibID(data.libID, function (err, data) {
-            callback(req, res, err, '', data);
-        });
+    async getCoeList(req, res){
+        try{
+            let coeList = await coeFacade.getComplementaryCoes(req.session.sessionUser.id, req.session.sessionCompilation._id);
+            callback(req, res, 0, 'success', coeList);
+        } catch (err) {
+            callback(req, res, 1, err, null);
+        }
     }
 
-    getCoeItemsByIDs(req, res){
-        let data = JSON.parse(req.body.data);
-        coeListDAO.getCoeItemsByIDs(data, function (err, data) {
-            callback(req, res, err, '', data);
-        });
+    async saveCoeList(req, res){
+        try {
+            let data = JSON.parse(req.body.data);
+            let newDatas = await coeFacade.saveToCoeList(req.session.sessionUser.id, req.session.sessionCompilation._id, data);
+            callback(req, res, 0, 'success', newDatas);
+        } catch (err) {
+            console.log(err);
+            callback(req, res, 1, err, null);
+        }
     }
 
-    getCoeItemsByNos(req, res){
-        let data = JSON.parse(req.body.data);
-        coeListDAO.getCoeItemsByNos(data, function (err, data) {
-            callback(req, res, err, '', data);
-        });
+    async getCoeItemsByIDs(req, res){
+        try{
+            let data = JSON.parse(req.body.data);
+            let coeList = await coeFacade.getCoeItemsByIDs(data.coeIDs);
+            callback(req, res, 0, 'success', coeList);
+        } catch (err) {
+            callback(req, res, 1, err, null);
+        }
     }
 
-    getInstallation(req, res){
-        let data = JSON.parse(req.body.data);
-        compleRationDao.getInstallation(data.rationRepId, function (err, data) {
-            callback(req, res, err, '', data);
-        });
+    async getCoeItemsByNos(req, res){
+        try{
+            let data = JSON.parse(req.body.data);
+            let coeList = await coeFacade.getCoeItemsByNos(req.session.sessionUser.id, req.session.sessionCompilation._id, data.coeNos);
+            callback(req, res, 0, 'success', coeList);
+        } catch (err) {
+            console.log(err);
+            callback(req, res, 1, err, null);
+        }
+    }
+
+    async getInstallation(req, res){
+        try {
+            let installData = await installFacade.getInstallation(req.session.sessionUser.id, req.session.sessionCompilation._id);
+            callback(req, res, 0, 'success', installData);
+        } catch (err) {
+            callback(req, res, 1, err, null);
+        }
+    }
+
+    async updateFeeItem(req, res){
+        try {
+            let data = JSON.parse(req.body.data);
+            await installFacade.updateFeeItem(req.session.sessionUser.id, req.session.sessionCompilation._id, data.updateData);
+            callback(req, res, 0, 'success', null);
+        } catch (err) {
+            callback(req, res, 1, err, null);
+        }
+    }
+
+    async updateInstallSection(req, res){
+        try {
+            let data = JSON.parse(req.body.data);
+            await installFacade.updateSection(req.session.sessionUser.id, req.session.sessionCompilation._id, data.updateData);
+            callback(req, res, 0, 'success', null);
+        } catch (err) {
+            callback(req, res, 1, err, null);
+        }
+    }
+
+    async batchUpdateInst(req, res){
+        try {
+            let data = JSON.parse(req.body.data);
+            await installFacade.batchUpdateInst(data.rationSection, data.inst);
+            callback(req, res, 0, 'success', null);
+        } catch (err) {
+            callback(req, res, 1, err, null);
+        }
     }
 }
 

+ 1 - 1
modules/complementary_ration_lib/controllers/compleSectionTreeController.js

@@ -20,7 +20,7 @@ class CompleSectionTreeController extends BaseController{
 
     getRationTree(req, res){
         let data = JSON.parse(req.body.data);
-        sectionTreeDao.getRationTree(req.session.sessionUser.id, data.rationRepId, function (err, data) {
+        sectionTreeDao.getRationTree(req.session.sessionUser.id, req.session.sessionCompilation._id, data.rationRepId, data.type, function (err, data) {
             callback(req, res, err, '', data);
         });
     }

+ 51 - 20
modules/complementary_ration_lib/controllers/compleViewController.js

@@ -4,6 +4,7 @@
 
 import BaseController from '../../common/base/base_controller';
 import CompleViewModel from '../models/compleViewModel';
+import EngineeringLibModel from "../../users/models/engineering_lib_model";
 let config = require("../../../config/config.js");
 
 let compleViewModel = new CompleViewModel();
@@ -11,55 +12,84 @@ let callback = function (req, res, err, msg, data) {
     res.json({error: err, message: msg, data: data});
 };
 
+async function getGljLibId(sessionCompilation) {
+    let gljLibId = null,
+        rationValuation = sessionCompilation.ration_valuation,
+        billValuation = sessionCompilation.bill_valuation,
+        engineeringLibModel = new EngineeringLibModel(),
+        valuationIDs = [] ;
+    for(let r of rationValuation){//{ "glj_lib.0": {$exists:1} }
+        if(r.id){
+            valuationIDs.push(r.id);
+        }
+    }
+    for(let b of billValuation){
+        if(b.id){
+            valuationIDs.push(b.id);
+        }
+    }
+    if(valuationIDs.length > 0){
+        let engineeringInfo = await engineeringLibModel.findDataByCondition({'valuationID': {"$in": valuationIDs},"glj_lib.0": {$exists:1}});//数组大于0
+        gljLibId = engineeringInfo.glj_lib.length > 0 && typeof engineeringInfo.glj_lib !== 'undefined' ? engineeringInfo.glj_lib[0].id : null;
+    }
+    return gljLibId;
+}
+
 class CompleViewController extends BaseController{
-    redirectRation(req, res){
-        const repId = req.query.repository;
-        const redirectGlj = `/complementaryRation/glj?repository=${repId}`;
-        const redirectCoe = `/complementaryRation/coe?repository=${repId}`;
-        const redirectInstallation = `/complementaryRation/installation?repository=${repId}`;
+    async redirectRation(req, res){
+        const gljLibId = await getGljLibId(req.session.sessionCompilation);
+        const redirectGlj = `/complementaryRation/glj`;
+        const redirectCoe = `/complementaryRation/coe`;
+        const redirectInstallation = `/complementaryRation/installation`;
         res.render('building_saas/complementary_ration_lib/html/dinge.html', {
             userID: req.session.sessionUser.id,
             redirectGlj: redirectGlj,
             redirectCoe: redirectCoe,
             redirectInstallation: redirectInstallation,
-            versionName: req.session.sessionCompilation.name + '免费版',
+            gljLibId: gljLibId,
+            compilationName: req.session.sessionCompilation.name,
+            versionName: `纵横建筑云计价(${req.session.compilationVersion})`,
             LicenseKey:config.getLicenseKey(process.env.NODE_ENV)
         });
     }
 
-    redirectGljList(req, res){
-        const repId = req.query.repository;
-        const redirectRation = `/complementaryRation/ration?repository=${repId}`;
-        const redirectCoe = `/complementaryRation/coe?repository=${repId}`;
-        const redirectInstallation = `/complementaryRation/installation?repository=${repId}`;
+    async redirectGljList(req, res){
+        const gljLibId = await getGljLibId(req.session.sessionCompilation);
+        const redirectRation = `/complementaryRation/ration`;
+        const redirectCoe = `/complementaryRation/coe`;
+        const redirectInstallation = `/complementaryRation/installation`;
         res.render('building_saas/complementary_ration_lib/html/gongliao.html', {
             userID: req.session.sessionUser.id,
             redirectRation: redirectRation,
             redirectCoe: redirectCoe,
             redirectInstallation: redirectInstallation,
-            versionName: req.session.sessionCompilation.name + '免费版',
+            gljLibId: gljLibId,
+            compilationName: req.session.sessionCompilation.name,
+            versionName: `纵横建筑云计价(${req.session.compilationVersion})`,
             LicenseKey:config.getLicenseKey(process.env.NODE_ENV)
         });
     }
 
-    redirectCoeList(req, res){
-        const repId = req.query.repository;
-        const redirectRation = `/complementaryRation/ration?repository=${repId}`;
-        const redirectGlj = `/complementaryRation/glj?repository=${repId}`;
-        const redirectInstallation = `/complementaryRation/installation?repository=${repId}`;
+    async redirectCoeList(req, res){
+        const gljLibId = await getGljLibId(req.session.sessionCompilation);
+        const redirectRation = `/complementaryRation/ration`;
+        const redirectGlj = `/complementaryRation/glj`;
+        const redirectInstallation = `/complementaryRation/installation`;
         res.render('building_saas/complementary_ration_lib/html/fuzhu.html', {
             userID: req.session.sessionUser.id,
             redirectRation: redirectRation,
             redirectGlj: redirectGlj,
             redirectInstallation: redirectInstallation,
-            versionName: req.session.sessionCompilation.name + '免费版',
+            gljLibId: gljLibId,
+            compilationName: req.session.sessionCompilation.name,
+            versionName: `纵横建筑云计价(${req.session.compilationVersion})`,
             LicenseKey:config.getLicenseKey(process.env.NODE_ENV)
         });
     }
 
     redirectInstallation(req, res){
         const repId = req.query.repository;
-        const redirectRation = `/complementaryRation/ration?repository=${repId}`;
+        const redirectRation = `/complementaryRation/ration`;
         const redirectGlj = `/complementaryRation/glj?repository=${repId}`;
         const redirectCoe = `/complementaryRation/coe?repository=${repId}`;
         res.render('building_saas/complementary_ration_lib/html/anzhuang.html', {
@@ -67,7 +97,8 @@ class CompleViewController extends BaseController{
             redirectRation: redirectRation,
             redirectGlj: redirectGlj,
             redirectCoe: redirectCoe,
-            versionName: req.session.sessionCompilation.name + '免费版',
+            compilationName: req.session.sessionCompilation.name,
+            versionName: `纵横建筑云计价(${req.session.compilationVersion})`,
             LicenseKey:config.getLicenseKey(process.env.NODE_ENV)
         });
     }

+ 2 - 2
modules/complementary_ration_lib/controllers/searchController.js

@@ -13,14 +13,14 @@ let callback = function (req, res, err, message, data) {
 class SearchController extends BaseController{
     getRationItem(req, res){
         let data = JSON.parse(req.body.data);
-        searchDao.getRationItem(req.session.sessionUser.id, data.rationRepIds, data.code, function (err, data) {
+        searchDao.getRationItem(req.session.sessionUser.id, req.session.sessionCompilation._id, data.rationRepIds, data.code, null, function (err, data) {
             callback(req, res, err, '', data);
         });
     }
 
     findRation(req, res){
         let data = JSON.parse(req.body.data);
-        searchDao.findRation(req.session.sessionUser.id, data.rationRepId, data.keyword, function (err, data) {
+        searchDao.findRation(req.session.sessionUser.id, req.session.sessionCompilation._id, data.rationRepId, data.keyword, data.skip, function (err, data) {
             callback(req, res, err, '', data);
         });
     }

+ 99 - 0
modules/complementary_ration_lib/facades/compleCoeFacade.js

@@ -0,0 +1,99 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2018/10/25
+ * @version
+ */
+
+module.exports = {
+    getComplementaryCoes,
+    getCoeItemsByIDs,
+    getCoeItemsByNos,
+    saveToCoeList,
+};
+
+const mongoose = require("mongoose");
+const counter = require('../../../public/counter/counter');
+const compleCoeModel = mongoose.model('complementary_ration_coe_list');
+const async = require('async');
+const deleteQuery = [{deleteInfo: null}, {'deleteInfo.deleted': false}];
+
+//获取用户总的补充子目换算
+async function getComplementaryCoes(userId, compilationId) {
+    let coeData =  await compleCoeModel.find({userId: userId, compilationId: compilationId, $or: deleteQuery});
+    return coeData;
+}
+
+
+//补充子目换算增删改
+async function saveToCoeList(userId, compilationId, data, callback) {
+    let bulks = [],
+        newDatas = [];
+    if (data.addArr && data.addArr.length > 0) {
+        let insertOprs = await getInsertBulk(userId, compilationId, data.addArr);
+        bulks = bulks.concat(insertOprs.insertBulk);
+        newDatas = insertOprs.newDatas;
+    }
+    if (data.updateArr && data.updateArr.length > 0) {
+        bulks = bulks.concat(getUpdateBulk(data.updateArr));
+    }
+    if (data.deleteArr && data.deleteArr.length > 0) {
+        let deleteObj = {
+            deleted: true,
+            deleteDateTime: new Date(),
+            deleteBy: userId
+        };
+        for (let delData of data.deleteArr) {
+            delData.deleteInfo = deleteObj
+        }
+        bulks = bulks.concat(getUpdateBulk(data.deleteArr));
+    }
+    if (bulks.length > 0) {
+        await compleCoeModel.bulkWrite(bulks);
+    }
+    return newDatas;
+}
+
+async function getInsertBulk(userId, compilationId, addArr) {
+    let insertBulk = [],
+        newDatas = [];
+    let counterResult = await counter.counterDAO.getIDAfterCountSync(counter.moduleName.complementaryCoeList, addArr.length);
+    let maxId = counterResult.sequence_value;
+    for (let insertData of addArr) {
+        insertData.userId = userId;
+        insertData.compilationId = compilationId;
+        insertData.ID = (maxId - (addArr.length - 1) + addArr.indexOf(insertData));
+        insertData.coes = [];
+        newDatas.push(insertData);
+        insertBulk.push({insertOne: {document: insertData}});
+    }
+    return {insertBulk, newDatas};
+}
+
+function getUpdateBulk(updateArr) {
+    let updateBulk = [],
+        updateFields = ['name', 'content', 'coes', 'deleteInfo'];
+    for (let updateData of updateArr) {
+        let needSet = {};
+        for (let attr in updateData){
+            if (updateFields.includes(attr)){
+                needSet[attr] = updateData[attr];
+            }
+        }
+        updateBulk.push({updateOne:{filter: {ID: updateData.ID}, update: {$set: needSet}}});
+    }
+    return updateBulk;
+}
+//根据序号获取子目换算,插入子目换算时用
+async function getCoeItemsByNos(userId, compilationId, serialNos) {
+    return await compleCoeModel.find({userId: userId, compilationId: compilationId, serialNo: {$in: serialNos}}, '-_id ID serialNo name content');
+}
+
+//根据ID获取子目换算,获取定额子目换算用
+async function getCoeItemsByIDs(coeIds) {
+    return await compleCoeModel.find({ID: {$in: coeIds}}, '-_id ID serialNo name content');
+}
+

+ 91 - 0
modules/complementary_ration_lib/facades/compleInstallFacade.js

@@ -0,0 +1,91 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2018/10/25
+ * @version
+ */
+
+module.exports = {
+    getInstallation,
+    updateFeeItem,
+    updateSection,
+    batchUpdateInst,
+};
+
+const mongoose = require("mongoose");
+const counter = require('../../../public/counter/counter');
+const async = require('async');
+const deleteQuery = [{deleteInfo: null}, {'deleteInfo.deleted': false}];
+const complefeeItemModel = mongoose.model('complementary_ration_installation');
+const compleSectionModel = mongoose.model('complementary_ration_installationSection');
+const compleRationModel = mongoose.model('complementary_ration_items');
+
+async function getInstallation(userId, compilationId){
+        let feeItems = await complefeeItemModel.find({userId: userId, compilationId: compilationId, $or: deleteQuery});
+        for (let feeItem of feeItems) {
+            let sids = [];
+            for (let sec of feeItem.section) {
+                sids.push(sec.ID);
+            }
+            if (sids.length > 0) {
+                let sections = await compleSectionModel.find({ID: {$in: sids}, $or: deleteQuery});
+                feeItem._doc.section = sections;
+            }
+        }
+        return feeItems;
+}
+
+//更新费用项
+async function updateFeeItem(userId, compilationId, updateData){
+    for (let data of updateData) {
+        if (data.updateType === 'new') {
+            data.updateData.userId = userId;
+            data.updateData.compilationId = compilationId;
+            await complefeeItemModel.create(data.updateData);
+        } else if (data.updateType === 'update' && !data.updateData.deleted) {
+            await complefeeItemModel.update({ID: data.updateData.ID}, data.updateData);
+        } else {
+            let deleteInfo = {
+                deleted: true,
+                deleteDateTime: new Date(),
+                deleteBy: userId
+            };
+            data.updateData.deleteInfo = deleteInfo;
+            delete data.updateData.deleted;
+            await complefeeItemModel.remove({ID: data.updateData.ID});
+        }
+    }
+}
+
+//更新分册章节
+async function updateSection(userId, compilationId, updateData){
+    for (let data of updateData) {
+        if (data.updateType === 'new') {
+            data.updateData.userId = userId;
+            data.updateData.compilationId = compilationId;
+            await compleSectionModel.create(data.updateData);
+        } else if (data.updateType === 'update' && !data.updateData.deleted) {
+            await compleSectionModel.update({ID: data.updateData.ID}, data.updateData);
+        } else {
+            let deleteInfo = {
+                deleted: true,
+                deleteDateTime: new Date(),
+                deleteBy: userId
+            };
+            data.updateData.deleteInfo = deleteInfo;
+            delete data.updateData.deleted;
+            await compleSectionModel.remove({ID: data.updateData.ID});
+        }
+    }
+}
+
+//批量关联至定额(选择某一章节)
+async function batchUpdateInst(rationSection, inst){
+    for (let sectionId of rationSection) {
+        await compleRationModel.update({sectionId: sectionId, $or: deleteQuery},
+            {$addToSet: {rationInstList: {feeItemId: inst.feeItemId, sectionId: inst.sectionId}}}, {multi: true});
+    }
+}

+ 132 - 55
modules/complementary_ration_lib/models/compleRationModel.js

@@ -34,19 +34,10 @@ class CompleRatoinDao {
         }
     }
 
-    async getRationItems(userID, rationRepId, sectionId, callback){
+    async getRationItems(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));
+            let compleRations = await compleRationModel.find({sectionId: sectionId, deleteInfo: null});
+            callback(0, compleRations);
         }
         catch(err){
             callback(err, null);
@@ -138,60 +129,146 @@ class CompleRatoinDao {
             callback(err, null);
         }
     }
-    //造价书定额库
-    async getRationGljItemsBySection(userId, sectionId, callback){
-        try{
-            const perHintHeight = 17.2;
-            let stdRations = await stdRationModel.find({sectionId: sectionId, $or: [{isDeleted: null}, {isDeleted: false}]});
-            for(let ration of stdRations){
-                ration._doc.type = 'std';
+
+    //根据章节树获取补充定额
+    async getCompleRationBySection(userId, sectionId) {
+        const deleteQuery = [{deleteInfo: null}, {'deleteInfo.deleted': false}];
+        let compleRations = await compleRationModel.find({sectionId: sectionId, $or: deleteQuery});
+        for(let ration of compleRations){
+            ration._doc.type = 'complementary';
+            let hintsArr = [];
+            let stdGljIds = [],
+                comGljIds = [],
+                stdGljs = [],
+                comGljs = [];
+            let gljAmtMapping = {};
+            for(let rationGlj of ration.rationGljList){
+                gljAmtMapping[rationGlj.gljId] = rationGlj.consumeAmt;
+                if(!isDef(rationGlj.type) || rationGlj.type === 'std'){
+                    stdGljIds.push(rationGlj.gljId);
+                }
+                else {
+                    comGljIds.push(rationGlj.gljId);
+                }
             }
-            let compleRations = await compleRationModel.find({userId: userId, sectionId: sectionId, deleteInfo: null});
-            for(let ration of compleRations){
-                ration._doc.type = 'complementary';
+            if(stdGljIds.length > 0) {
+                stdGljs = await stdGljModel.find({ID: {$in: stdGljIds}});
             }
-            let rations = stdRations.concat(compleRations);
-            rations.sort(function (a, b) {
-                let rst = 0;
-                if(a.code > b.code){
-                    rst = 1;
-                }
-                else if(a.code < b.code){
-                    rst = -1;
+            if(comGljIds.length > 0) {
+                comGljs = await complementaryGljModel.find({userId: userId, ID: {$in: comGljIds}});
+            }
+            let gljDatas = stdGljs.concat(comGljs);
+            gljDatas.sort(function (a, b) {
+                let aV = a.gljType + a.code,
+                    bV = b.gljType + b.code;
+                if(aV > bV) {
+                    return 1;
+                } else if (aV < bV) {
+                    return -1;
                 }
-                return rst;
+                return 0;
             });
-            for(let ration of rations){
-                let hintsArr = [];
-                for(let rationGlj of ration.rationGljList){
-                    let glj;
-                    if(!isDef(rationGlj.type) || rationGlj.type === 'std'){
-                         glj = await stdGljModel.findOne({ID: rationGlj.gljId});
-                    }
-                    else {
-                         glj = await complementaryGljModel.findOne({uesrId: userId, ID: rationGlj.gljId});
+            for(let glj of gljDatas){
+                hintsArr.push(` ${glj.code} ${glj.name}${glj.specs ? '&nbsp;&nbsp;&nbsp;' + glj.specs : ''}&nbsp;&nbsp&nbsp;${glj.unit}&nbsp;&nbsp;&nbsp;${gljAmtMapping[glj.ID]}`)
+            }
+            hintsArr.push(`基价 元 ${ration.basePrice}`);
+            if(ration.jobContent && ration.jobContent.toString().trim() !== ''){
+                hintsArr.push(`工作内容:`);
+                hintsArr = hintsArr.concat(ration.jobContent.split('\n'));
+            }
+            if(ration.annotation && ration.annotation.toString().trim() !== ''){
+                hintsArr.push(`附注:`);
+                hintsArr = hintsArr.concat(ration.annotation.split('\n'));
+            }
+            ration._doc.hint = hintsArr.join('<br>');
+        }
+        return compleRations;
+    }
+
+    //造价书定额库 根据章节树过去标准定额
+    async getRationGljItemsBySection(sectionId, callback){
+        let stdRations = await stdRationModel.find({sectionId: sectionId});
+        for(let ration of stdRations){
+            ration._doc.type = 'std';
+        }
+        function sortByCode(arr) {
+            function recurCompare(a, b, index){
+                if (a[index] && !b[index]) {
+                    return 1;
+                } else if (!a[index] && b[index]) {
+                    return -1;
+                } else if (a[index] && b[index]) {
+                    let aV = a[index],
+                        bV = b[index];
+                    if (!isNaN(aV) && !isNaN(bV)) {
+                        aV = parseFloat(a[index]);
+                        bV = parseFloat(b[index]);
                     }
-                    if(isDef(glj)){
-                        hintsArr.push(` ${glj.code} ${glj.name} ${glj.unit} ${rationGlj.consumeAmt}`);
+                    if (aV > bV) {
+                        return 1;
+                    } else if (aV < bV) {
+                        return -1;
+                    } else {
+                        return recurCompare(a, b, index + 1);
                     }
                 }
-                hintsArr.push(`基价 元 ${ration.basePrice}`);
-                hintsArr.push(`工作内容:`);
-                if(ration.jobContent){
-                    hintsArr = hintsArr.concat(ration.jobContent.split('\n'));
+                return 0;
+            }
+            arr.sort(function (a, b) {
+                let aArr = a.code.split('-'),
+                    bArr = b.code.split('-');
+                return recurCompare(aArr, bArr, 0);
+            });
+        }
+        /*stdRations.sort(function (a, b) {
+            let rst = 0;
+            if(a.code > b.code){
+                rst = 1;
+            }
+            else if(a.code < b.code){
+                rst = -1;
+            }
+            return rst;
+        });*/
+        sortByCode(stdRations);
+        for(let ration of stdRations){
+            let hintsArr = [];
+            let stdGljIds = [],
+                stdGljs = [];
+            let gljAmtMapping = {};
+            for(let rationGlj of ration.rationGljList){
+                gljAmtMapping[rationGlj.gljId] = rationGlj.consumeAmt;
+                stdGljIds.push(rationGlj.gljId);
+            }
+            if(stdGljIds.length > 0) {
+                stdGljs = await stdGljModel.find({ID: {$in: stdGljIds}});
+            }
+            let gljDatas = stdGljs;
+            gljDatas.sort(function (a, b) {
+                let aV = a.gljType + a.code,
+                    bV = b.gljType + b.code;
+                if(aV > bV) {
+                    return 1;
+                } else if (aV < bV) {
+                    return -1;
                 }
+                return 0;
+            });
+            for(let glj of gljDatas){
+                hintsArr.push(` ${glj.code} ${glj.name}${glj.specs ? '&nbsp;&nbsp;&nbsp;' + glj.specs : ''}&nbsp;&nbsp&nbsp;${glj.unit}&nbsp;&nbsp;&nbsp;${gljAmtMapping[glj.ID]}`)
+            }
+            hintsArr.push(`基价 元 ${ration.basePrice}`);
+            if(ration.jobContent && ration.jobContent.toString().trim() !== ''){
+                hintsArr.push(`工作内容:`);
+                hintsArr = hintsArr.concat(ration.jobContent.split('\n'));
+            }
+            if(ration.annotation && ration.annotation.toString().trim() !== ''){
                 hintsArr.push(`附注:`);
-                if(ration.annotation){
-                    hintsArr = hintsArr.concat(ration.annotation.split('\n'));
-                }
-                ration._doc.hint = hintsArr.join('<br>');
-                ration._doc.hintHeight = hintsArr.length * perHintHeight;//控制定额库悬浮提示位置
+                hintsArr = hintsArr.concat(ration.annotation.split('\n'));
             }
-            callback(0, rations);
-        }
-        catch(err){
-            callback(err, null);
+            ration._doc.hint = hintsArr.join('<br>');
         }
+        return stdRations;
     }
 
     updateRationBasePrc(userID, basePrcArr, callback){

+ 140 - 21
modules/complementary_ration_lib/models/searchModel.js

@@ -9,26 +9,28 @@ const compleRationSectionTreeModel = mongoose.model('complementary_ration_sectio
 let stdSectionTreeModel = require ('../../ration_repository/models/ration_section_tree').Model;
 let stdRationModel = require ('../../ration_repository/models/ration_item').Model;
 
+const compleRationLib = 'compleRationLib';
+
 class SearchDao{
-    async getRationItem(userId, rationRepIds, code, ID, callback){
+    async getRationItem(userId, compilationId, rationRepIds, code, ID, callback){
         let ration = null;
         try{
+            if(rationRepIds.includes(compleRationLib)) {
+                rationRepIds.splice(rationRepIds.indexOf(compleRationLib), 1);
+            }
             let stdQuery = {rationRepId: {$in: rationRepIds}, code: code, $or: [{isDeleted: null}, {isDeleted: false}]};
             if(ID){
                 stdQuery = {ID: ID, $or: [{isDeleted: null}, {isDeleted: false}]};
             }
-            //let stdRation = await stdRationModel.findOne({rationRepId: {$in: rationRepIds}, code: code, $or: [{isDeleted: null}, {isDeleted: false}]});
             let stdRation = await stdRationModel.findOne(stdQuery);
             if(isDef(stdRation)){
                 ration = stdRation._doc;
                 ration.type = 'std';
-            }
-            else{
-                let compleQuery = {userId: userId, rationRepId: {$in: rationRepIds}, code: code, deleteInfo: null};
+            } else{
+                let compleQuery = {userId: userId, compilationId: compilationId, code: code, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]};
                 if(ID){
-                    compleQuery = {ID: ID, deleteInfo: null};
+                    compleQuery.ID = ID;
                 }
-                //let compleRation = await compleRationModel.findOne({userId: userId, rationRepId: {$in: rationRepIds}, code: code, deleteInfo: null});
                 let compleRation = await compleRationModel.findOne(compleQuery);
                 if(isDef(compleRation)){
                     ration = compleRation._doc;
@@ -36,12 +38,13 @@ class SearchDao{
                 }
             }
             if(isDef(ration)){
-                let stdChapter = await stdSectionTreeModel.findOne({rationRepId: ration.rationRepId, ID: ration.sectionId, $or: [{isDeleted: null}, {isDeleted: false}]});
-                if(isDef(stdChapter)){
-                    ration.chapter = stdChapter._doc;
-                }
-                else{
-                    let compleChapter = await compleRationSectionTreeModel.findOne({userId: userId, ID: ration.sectionId, deleteInfo: null});
+                if (ration.type === 'std') {
+                    let stdChapter = await stdSectionTreeModel.findOne({rationRepId: ration.rationRepId, ID: ration.sectionId, $or: [{isDeleted: null}, {isDeleted: false}]});
+                    if(isDef(stdChapter)){
+                        ration.chapter = stdChapter._doc;
+                    }
+                } else {
+                    let compleChapter = await compleRationSectionTreeModel.findOne({ID: ration.sectionId, $or: [{isDeleted: null}, {isDeleted: false}]});
                     if(isDef(compleChapter)){
                         ration.chapter = compleChapter._doc;
                     }
@@ -59,28 +62,144 @@ class SearchDao{
         return ration;
     }
 
-    async findRation(userId, rationRepId, keyword, callback){
+    //@param {Object}skip({std: Number, comple: Number})
+    async findRation(userId, compilationId, rationRepId, keyword, skip, callback){
+        //每次限制结果数
+        const limit = 50;
+        //结果数
+        let resultCount = 0,
+            rst = {data: [], count: null};
         try{
+            //是否需要查找补充定额
+            let findCompleRtion = rationRepId.length > 0 && rationRepId.includes(compleRationLib) ? true : false;
+            //剔除补充定额库id
+            if (rationRepId.includes(compleRationLib)) {
+                rationRepId.splice(rationRepId.indexOf(compleRationLib), 1);
+            }
             let filter = {
-                'rationRepId': rationRepId,
+                'rationRepId': {$in: rationRepId},
                 '$and': [{
                     '$or': [{'code': {'$regex': keyword, $options: '$i'}}, {'name': {'$regex': keyword, $options: '$i'}}]
                 }, {
                     '$or': [{'isDeleted': {"$exists":false}}, {'isDeleted': null}, {'isDeleted': false}, {deleteInfo: null}]
                 }]
             };
-            let stdRations = await stdRationModel.find(filter);
+            let compleFilter = {
+                userId: userId,
+                compilationId: compilationId,
+                '$and': [{
+                    '$or': [{'code': {'$regex': keyword, $options: '$i'}}, {'name': {'$regex': keyword, $options: '$i'}}]
+                }, {
+                    '$or': [{deleteInfo: null}, {'deleteInfo.deleted': false}]
+                }]
+            };
+            //结果数
+            if (skip && skip.std === 0 && skip.comple === 0) {
+                resultCount += rationRepId.length === 0 ? 0 : await stdRationModel.find(filter).count();
+                resultCount += findCompleRtion ? await compleRationModel.find(compleFilter).count() : 0;
+                rst.count = resultCount;
+            }
+            //搜索定额
+            let stdGljIds = [],
+                comGljIds = [];
+            let stdRations = rationRepId.length === 0 ? [] : await stdRationModel.find(filter).sort({code: 1}).skip(skip.std).limit(limit);
             for(let i = 0, len = stdRations.length; i < len; i++){
                 stdRations[i]._doc.type = 'std';
+                for(let glj of stdRations[i].rationGljList){
+                    stdGljIds.push(glj.gljId);
+                }
+            }
+            let compleRations = [];
+            let residueLimit = limit - stdRations.length;
+            if (residueLimit > 0) {
+                compleRations = findCompleRtion ? await compleRationModel.find(compleFilter).sort({code: 1}).skip(skip.comple).limit(residueLimit) : [];
+                for(let i = 0, len = compleRations.length; i <len; i++){
+                    compleRations[i]._doc.type = 'complementary';
+                    for(let glj of compleRations[i].rationGljList){
+                        if(glj.type === 'std'){
+                            stdGljIds.push(glj.gljId);
+                        }
+                        else {
+                            comGljIds.push(glj.gljId);
+                        }
+                    }
+                }
             }
-            filter.userId = userId;
-            let compleRations = await compleRationModel.find(filter);
-            for(let i = 0, len = compleRations.length; i <len; i++){
-                compleRations[i]._doc.type = 'complementary';
+
+            //设置悬浮信息
+            stdGljIds = Array.from(new Set(stdGljIds));
+            comGljIds = Array.from(new Set(comGljIds));
+            let gljIDMapping = {};
+            if(stdGljIds.length > 0){
+                let stdGljs = await stdGljModel.find({ID: {$in: stdGljIds}}, '-_id ID code name specs unit gljType');
+                for(let stdGlj of stdGljs){
+                    gljIDMapping[stdGlj.ID] = stdGlj;
+                }
+            }
+            if(comGljIds.length > 0){
+                let comGljs = await complementaryGljModel.find({ID: {$in: stdGljIds}});
+                for(let comGlj of comGljs){
+                    gljIDMapping[comGlj.ID] = comGlj;
+                }
+            }
+            for(let ration of stdRations){
+                let hintsArr = [];
+                //对人材机进行排序
+                ration.rationGljList.sort(function (a, b) {
+                    let gljA = gljIDMapping[a.gljId],
+                        gljB = gljIDMapping[b.gljId];
+                    if(gljA && gljB){
+                        let aV = gljA.gljType + gljA.code,
+                            bV = gljB.gljType + gljB.code;
+                        if(aV > bV) {
+                            return 1;
+                        } else if(aV < bV) {
+                            return -1;
+                        }
+                    }
+                    return 0;
+                });
+                for(let rationGlj of ration.rationGljList){
+                    let glj = gljIDMapping[rationGlj.gljId];
+                    if(glj){
+                        hintsArr.push(` ${glj.code} ${glj.name}${glj.specs ? ' ' + glj.specs : ''} ${glj.unit} ${rationGlj.consumeAmt}`);
+                    }
+                }
+                hintsArr.push(`基价 元 ${ration.basePrice}`);
+                if(ration.jobContent && ration.jobContent.toString().trim() !== ''){
+                    hintsArr.push(`工作内容:`);
+                    hintsArr = hintsArr.concat(ration.jobContent.split('\n'));
+                }
+                if(ration.annotation && ration.annotation.toString().trim() !== ''){
+                    hintsArr.push(`附注:`);
+                    hintsArr = hintsArr.concat(ration.annotation.split('\n'));
+                }
+                ration._doc.hint = hintsArr.join('<br>');
+            }
+            for(let ration of compleRations){
+                let hintsArr = [];
+                for(let rationGlj of ration.rationGljList){
+                    let glj = gljIDMapping[rationGlj.gljId];
+                    if(glj){
+                        hintsArr.push(` ${glj.code} ${glj.name}${glj.specs ? ' ' + glj.specs : ''} ${glj.unit} ${rationGlj.consumeAmt}`);
+                    }
+                }
+                hintsArr.push(`基价 元 ${ration.basePrice}`);
+                if(ration.jobContent && ration.jobContent.toString().trim() !== ''){
+                    hintsArr.push(`工作内容:`);
+                    hintsArr = hintsArr.concat(ration.jobContent.split('\n'));
+                }
+                if(ration.annotation && ration.annotation.toString().trim() !== ''){
+                    hintsArr.push(`附注:`);
+                    hintsArr = hintsArr.concat(ration.annotation.split('\n'));
+                }
+                ration._doc.hint = hintsArr.join('<br>');
             }
-            callback(0, stdRations.concat(compleRations));
+            rst.data = stdRations.concat(compleRations);
+            callback(0, rst);
         }
         catch(err){
+            console.log(err);
             callback(err, null);
         }
     }

+ 53 - 6
modules/complementary_ration_lib/models/sectionTreeModel.js

@@ -7,8 +7,36 @@ const compleRationSectionTreeModel = mongoose.model('complementary_ration_sectio
 const compleRationModel = mongoose.model('complementary_ration_items');
 let counter = require('../../../public/counter/counter');
 let stdSectionTreeModel = require ('../../ration_repository/models/ration_section_tree').Model;
+const uuidV1 = require('uuid/v1');
+const sectionTemplateModel = mongoose.model('complementary_ration_section_templates');
 
 class SectionTreeDao {
+    //从补充定额章节树模板中拷贝数据到用户的补充定额章节树中
+    async copyDataFromTemplate(userId, compilationId){
+        let templateData = await sectionTemplateModel.find({compilationId: compilationId});
+        if (templateData.length > 0) {
+            let insertDatas = [],
+                uuidMapping = {};
+            //将ID替换成UUID
+            for (let temData of templateData) {
+                uuidMapping[temData.ID] = uuidV1();
+            }
+            for(let temData of templateData) {
+                let insertD = {
+                    userId: userId,
+                    compilationId: compilationId,
+                    name: temData.name,
+                    ID: uuidMapping[temData.ID],
+                    ParentID: uuidMapping[temData.ParentID] || -1,
+                    NextSiblingID: uuidMapping[temData.NextSiblingID] || -1,
+                };
+                insertDatas.push(insertD);
+            }
+            //插入数据
+            await compleRationSectionTreeModel.insertMany(insertDatas);
+        }
+    }
+
     getNewTreeID(callback){
         counter.counterDAO.getIDAfterCount(counter.moduleName.rationTree, 1, function (err, result) {
             if(err){
@@ -20,9 +48,28 @@ class SectionTreeDao {
         });
 
     }
+    async getRationTree(userId, compilationId, rationRepId, type, callback) {
+        //区分要获取的是标准的数据还是补充的数据
+        const rationLibType = {
+            complementary: 0,
+            std: 1
+        };
+        try {
+            let treeData;
+            if (type === rationLibType.complementary) {
+                treeData = await compleRationSectionTreeModel.find({userId: userId, compilationId: compilationId, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]});
+            } else {
+                treeData = await stdSectionTreeModel.find({rationRepId: rationRepId});
+            }
+            callback(0, treeData);
+        } catch (err) {
+            console.log(err);
+            callback(1, null);
+        }
+    }
 
     //获取补充定额拼接章节树
-    async getRationTree(userID, rationRepId, callback){
+   /* 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});
@@ -63,7 +110,7 @@ class SectionTreeDao {
         catch (err){
             callback(err, null);
         }
-    }
+    }*/
 
     async updateSection(userID, compilationId, updateData, callback){
         try{
@@ -75,10 +122,10 @@ class SectionTreeDao {
                     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);
-                    if(updateObj.updateData.deleteInfo){
-                        await compleRationModel.update({userId: userID, sectionId: updateObj.updateData.ID},
-                            {$set: {deleteInfo: {deleted: true, deleteBy: userID, deleteDateTime: Date.now()}}}, {multi: true});
+                    if(!updateObj.updateData.deleteInfo){
+                        await compleRationSectionTreeModel.update({userId: userID, ID: updateObj.updateData.ID}, updateObj.updateData);
+                    } else {
+                        await compleRationSectionTreeModel.remove({userId: userID, ID: updateObj.updateData.ID});
                     }
                 }
             }

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

@@ -41,11 +41,15 @@ module.exports = function (app) {
     router.post('/getGljItemsByCodes', compleRationController.init, compleRationController.getGljItemsByCodes);
 
     router.post('/getCoeList', compleRationController.init, compleRationController.getCoeList);
+    router.post('/saveCoeList', compleRationController.init, compleRationController.saveCoeList);
     router.post('/getCoeItemsByIDs', compleRationController.init, compleRationController.getCoeItemsByIDs);
     router.post('/getCoeItemsByNos', compleRationController.init, compleRationController.getCoeItemsByNos);
 
     //安装增加费
     router.post('/getInstallation', compleRationController.init, compleRationController.getInstallation);
+    router.post('/updateFeeItem', compleRationController.init, compleRationController.updateFeeItem);
+    router.post('/updateInstallSection', compleRationController.init, compleRationController.updateInstallSection);
+    router.post('/batchUpdateInst', compleRationController.init, compleRationController.batchUpdateInst);
 
     //造价书定额库
     router.post('/getRationItem', searchController.init, searchController.getRationItem);

+ 53 - 10
modules/fee_rates/facade/fee_rates_facade.js

@@ -33,7 +33,8 @@ module.exports={
     updateFeeRates:updateFeeRates,
     updateRates:update_rates,
     feeRateFileSaveAs:feeRateFileSaveAs,
-    getFeeRateByID:getFeeRateByID
+    getFeeRateByID:getFeeRateByID,
+    changeFeeRateFile:changeFeeRateFile
 };
 let operationMap={
     'ut_create':create_fee_rate,
@@ -235,7 +236,9 @@ async function getFeeRateStandardsByProjectID(projectID) {
     logger.info("get feeRate standard, projectID:"+projectID)
     let feeRateStandards=[];
     let project =  await projectsModel.findOne({ID:projectID});
-    let engineeringLibModel = new EngineeringLibModel();
+    let temFee = await feeRateFileModel.findOne({ID:project.property.feeFile.id});
+    feeRateStandards.push({ID:temFee.libID,libName:temFee.libName});
+   /* let engineeringLibModel = new EngineeringLibModel();
     let engineeringInfo = project !== null && project.property.engineering_id !== undefined ?
         await engineeringLibModel.getEngineering(project.property.engineering_id) : null;
     if(engineeringInfo!=null){
@@ -243,7 +246,7 @@ async function getFeeRateStandardsByProjectID(projectID) {
         for(let lib of fee_lib){
             feeRateStandards.push({ID:lib.id,libName:lib.name});
         }
-    }
+    }*/
     return feeRateStandards;
 }
 
@@ -281,7 +284,7 @@ async function newFeeRateFile(userId, updateData){
                 newFeeRate.name = temFee.name;
                 return newFeeRate;
             }
-            let temA = feeFile.id.split("-");
+            let temA = feeFile.id.split("@@");
             let libID = temA[1];
             let doc={
                 userID: userId,
@@ -325,11 +328,18 @@ async function checkFeeRateName(jdata) {
 async function getChangeInfo(jdata,compilation){
     let data = JSON.parse(jdata);
     //{ rootProjectID: 99, user_id: '76075' }
+    const notDeleted = [{deleteInfo: null}, {'deleteInfo.deleted':false}];
     let result={};
     let treeData = [];
     let currentProject = await projectsModel.findOne({'ID':data.rootProjectID},['ID','NextSiblingID','ParentID','name']); //{projectID:99,name:'建设项目1'};//dummy 数据
+    let currentTender = await projectsModel.findOne({ID: data.projectID, $or: notDeleted});
     if(currentProject){
-        currentProject._doc.currentOptions=await getFeeRatesByProject(data.rootProjectID);
+        //剔除自身
+        let currentFeeFile = await getFeeRatesByProject(data.rootProjectID);
+        let currentUsedFF = currentTender.property.feeFile.id;
+        currentProject._doc.currentOptions = _.filter(currentFeeFile, function (ff) {
+            return ff.ID !== currentUsedFF;
+        });
     }
     //根据用户ID 找除了当前项目的其它建设项目;
     let others =await projectsModel.find({'$and': [
@@ -340,7 +350,7 @@ async function getChangeInfo(jdata,compilation){
         o._doc.optionList = await getFeeRatesByProject(o.ID);
     }
     //获取对应用户所有文件夹
-    let folders = await projectsModel.find({userID: data.user_id, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}], projType: 'Folder'}, ['ID','NextSiblingID','ParentID','name']);
+    let folders = await projectsModel.find({userID: data.user_id, $or: notDeleted, projType: 'Folder'}, ['ID','NextSiblingID','ParentID','name']);
     treeData = treeData.concat(currentProject);
     treeData = treeData.concat(others);
     treeData = treeData.concat(folders);
@@ -392,7 +402,7 @@ async function updateFeeRates(datas){//批量更新费率
 async function changeFeeRateFileFromCurrent(jdata){
     let data = JSON.parse(jdata);
     let newFeeRateFile=data.newFeeRateFile;
-    let result = await  projectsModel.findOneAndUpdate({ID:data.projectID},{'property.feeFile':newFeeRateFile});
+    await changeFeeRateFile(data,newFeeRateFile,0);
     let feeRateData = await feeRateFileModel.findOne({'ID':newFeeRateFile.id});
     if(feeRateData!==null){
         let feeRate = await feeRateModel.findOne({ID:feeRateData.feeRateID});
@@ -403,10 +413,43 @@ async function changeFeeRateFileFromCurrent(jdata){
     return feeRateData;
 }
 
+async function changeFeeRateFile(projectData,feeRateFile,type,userID) {
+    let temFile=null,newFeeRateFile = {};
+    if(type == 0){//从本建设项目中替换,直接赋值
+        temFile =  feeRateFile
+    }else if(type == 1) {//从其它建设项目中复制
+        let oldFeeRateFile = await feeRateFileModel.findOne({'ID':feeRateFile.id});
+        let feeRate = await feeRateModel.findOne({ID:oldFeeRateFile.feeRateID});
+        let newFeeRate={};
+        if(! feeRate){
+            throw '不存在对应费率文件';
+        }
+        newFeeRate.ID=uuidV1();
+        newFeeRate.rates =feeRate.rates;
+        newFeeRateFile.ID = uuidV1();
+        newFeeRateFile.name = feeRateFile.name;
+        newFeeRateFile.userID = userID;
+        newFeeRateFile.libName = oldFeeRateFile.libName;
+        newFeeRateFile.libID=oldFeeRateFile.libID;
+        newFeeRateFile.rootProjectID = projectData.rootProjectID;
+        newFeeRateFile.feeRateID =newFeeRate.ID;
+        await feeRateModel.create(newFeeRate);
+        await feeRateFileModel.create(newFeeRateFile);
+        temFile={
+            id:newFeeRateFile.ID,
+            name:feeRateFile.name
+        };
+        newFeeRateFile.rates=newFeeRate.rates;//构建返回数据
+    }
+    await  projectsModel.findOneAndUpdate({ID:projectData.projectID},{'property.feeFile':temFile});
+    return newFeeRateFile
+}
+
+
 async function changeFeeRateFileFromOthers(jdata) {
     let data = JSON.parse(jdata);
-    console.log(data);
-    let feeRateFile = await feeRateFileModel.findOne({'ID':data.feeRateFileID});
+    let newFeeRateFile = await changeFeeRateFile(data,{id:data.feeRateFileID,name:data.name},1,data.userID);
+   /* let feeRateFile = await feeRateFileModel.findOne({'ID':data.feeRateFileID});
     let feeRate = await feeRateModel.findOne({ID:feeRateFile.feeRateID});
     let newFeeRate={};
     newFeeRate.ID=uuidV1();
@@ -426,7 +469,7 @@ async function changeFeeRateFileFromOthers(jdata) {
         name:data.name
     }
     await projectsModel.findOneAndUpdate({ID:data.projectID},{'property.feeFile':feeFile});
-    newFeeRateFile.rates=newFeeRate.rates;
+    newFeeRateFile.rates=newFeeRate.rates;*/
     newFeeRateFile.usageProjects=await getUsageProjects(newFeeRateFile.ID);
     return newFeeRateFile;
 }

+ 20 - 7
modules/glj/controllers/glj_controller.js

@@ -17,6 +17,7 @@ let glj_type_util = require('../../../public/cache/std_glj_type_util');
 let mongoose = require('mongoose');
 let ration = mongoose.model('ration');
 let projectModel = mongoose.model('projects');
+let _ = require('lodash');
 
 
 const ProjectModel = require('../../pm/models/project_model').project;
@@ -232,10 +233,8 @@ class GLJController extends BaseController {
         response.json(responseData);
     }
 
-
     //添加组成物
     async addMixRatio(request,response){
-
         let result={
             error:0
         };
@@ -256,7 +255,8 @@ class GLJController extends BaseController {
                     code: newProjectGLJ.code,
                     specs:newProjectGLJ.specs,
                     name:newProjectGLJ.name,
-                    unit:newProjectGLJ.unit
+                    unit:newProjectGLJ.unit,
+                    model:newProjectGLJ.model
                 };
                 newProjectGLJ.ratio_data = await mixRatioModel.add(mixRatio);
                 mixRatios.push(newProjectGLJ);
@@ -277,19 +277,28 @@ class GLJController extends BaseController {
      * @return {void}
      */
     async getProjectInfo(request, response) {
+        if(typeof request.body.data == "string"){
+            request.body = JSON.parse(request.body.data)
+        }
         let projectId = request.body.project_id;
         let rootProjectID = request.body.rootProjectID;
         projectId = parseInt(projectId);
+        const notDeleted = [{deleteInfo: null}, {'deleteInfo.deleted': false}];
         let responseData = {
             err: 0,
             data: null
         };
         try {
             let sessionUserData = request.session.sessionUser;
+            //获取当前单位工程
+            let currentTender = await projectModel.findOne({ID: projectId, $or: notDeleted});
             // 获取对应用户所有的建设项目数据
             let projectList = await ProjectModel.getUserProjectData(sessionUserData.id,request.session.sessionCompilation._id);
             //获取对应用户所有文件夹
-            let folders = await projectModel.find({userID: sessionUserData.id, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}], projType: 'Folder'}, {_id: 0, name: 1, ID: 1, NextSiblingID: 1, ParentID: 1});
+            let folders = await projectModel.find({userID: sessionUserData.id, $or: notDeleted, projType: 'Folder'}, {_id: 0, name: 1, ID: 1, NextSiblingID: 1, ParentID: 1});
+            if(currentTender === null){
+                throw '当前单位工程不存在';
+            }
             if (projectList === null) {
                 throw '没有找到对应的项目数据';
             }
@@ -310,9 +319,12 @@ class GLJController extends BaseController {
 
                 // 归类
                 if (rootProjectID == projectList[index].ID) {
-                    result.self = unitPriceFileData;
+                    //剔除自身
+                    let currentUsedUF = currentTender.property.unitPriceFile.id;
+                    result.self = _.filter(unitPriceFileData, function (uf) {
+                        return uf.id !== currentUsedUF;
+                    });
                     result.currentProjectName =  projectList[index].name;
-
                 } else {
                     result.other.push(projectList[index]);
                 }
@@ -803,11 +815,12 @@ async function getGLJListByProjectID(projectId){
         responseData.data.gljList = gljList;
         // 先获取对应标段的项目工料机数据
         let gljListModel = new GLJListModel();
-        let [gljList, mixRatioConnectData,mixRationMap] = await gljListModel.getListByProjectId(projectId, unitPriceFileId);
+        let [gljList, mixRatioConnectData,mixRationMap,unitPriceMap] = await gljListModel.getListByProjectId(projectId, unitPriceFileId);
         responseData.data.gljList = gljList;
         responseData.data.mixRatioConnectData = mixRatioConnectData;
         responseData.data.mixRatioMap = mixRationMap;
         responseData.data.usedTenderList = usedTenderList;
+        responseData.data.unitPriceMap = unitPriceMap;
         let gljTypeMap = glj_type_util.getStdGljTypeCacheObj().innerGljTypeObj;
         responseData.data.constData = {
             materialIdList: gljListModel.materialIdList,

+ 80 - 0
modules/glj/facade/glj_facade.js

@@ -0,0 +1,80 @@
+/**
+ * Created by zhang on 2019/1/2.
+ */
+module.exports={ //先导出后require可以解决循环引用问题
+    changeUnitFile:changeUnitFile
+};
+
+const ProjectModel = require('../../pm/models/project_model').project;
+import UnitPriceFileModel from "../models/unit_price_file_model";
+import UnitPriceModel from "../models/unit_price_model";
+
+async function changeUnitFile(projectData,unitFile,type,userID) {
+    let projectId = projectData.projectID;
+    let changeUnitPriceId = unitFile.id;
+    let newName = unitFile.name;
+    type = parseInt(type);
+
+        let currentUnitPriceId = await ProjectModel.getUnitPriceFileId(projectId);
+        let unitPriceFileModel = new UnitPriceFileModel();
+
+        let insertData = null;
+        if (type > 0) {
+            let currentUnitPrice = await unitPriceFileModel.findDataByCondition({id: changeUnitPriceId});
+            if (currentUnitPrice === null) {
+                throw '不存在对应单价文件';
+            }
+            // 获取当前项目的rootProjectId
+            let projectData = await ProjectModel.getProject(projectId);
+            let rootProjectId = projectData.property.rootProjectID !== undefined ? projectData.property.rootProjectID : 0;
+
+            insertData = JSON.parse(JSON.stringify(currentUnitPrice));
+            insertData.root_project_id = rootProjectId;
+            newName?insertData.name = newName:'';
+            insertData.user_id = userID;
+            delete insertData._id;
+            delete insertData.ID;
+        }
+        // 获取即将更改的单价文件信息
+        let targetUnitPriceFile = type === 0 ? await unitPriceFileModel.findDataByCondition({id: changeUnitPriceId}) :
+            await unitPriceFileModel.add(insertData);
+        if (targetUnitPriceFile === null) {
+            throw '没有找到对应的单价文件';
+        }
+
+        // 查找对应单价文件的项目工料机数据
+        let unitPriceModel = new UnitPriceModel();
+        if(type ===1){//从其它项目复制,则先复制一份数据。
+            let needCopyList = await unitPriceModel.findDataByCondition({unit_price_file_id: changeUnitPriceId}, null, false);
+            if(needCopyList){
+                // 过滤mongoose格式
+                needCopyList = JSON.stringify(needCopyList);
+                needCopyList = JSON.parse(needCopyList);
+                let copyList = [];
+                for(let n of needCopyList){
+                    delete n._id;  // 删除原有id信息
+                    delete n.id;
+                    n.unit_price_file_id = targetUnitPriceFile.id;
+                    copyList.push(n);
+                }
+                copyList.length>0 ? await unitPriceModel.add(copyList):'';
+            }
+        }
+
+
+        let copyResult = await unitPriceModel.copyNotExist(currentUnitPriceId, targetUnitPriceFile.id,projectId);
+        // 复制成功后更改project数据
+        if (!copyResult) {
+            throw '复制数据失败';
+        }
+
+        let changeUnitPriceFileInfo = {
+            id: targetUnitPriceFile.id,
+            name: targetUnitPriceFile.name
+        };
+        let result = ProjectModel.changeUnitPriceFileInfo(projectId, changeUnitPriceFileInfo);
+        if (!result) {
+            throw '切换单价文件失败!';
+        }
+        return changeUnitPriceFileInfo;
+}

+ 22 - 12
modules/glj/models/glj_list_model.js

@@ -38,7 +38,7 @@ class GLJListModel extends BaseModel {
      * @var {Array}
      */
     ownCompositionTypes = [GLJTypeConst.CONCRETE, GLJTypeConst.MORTAR, GLJTypeConst.MIX_RATIO,
-        GLJTypeConst.GENERAL_MACHINE,GLJTypeConst.MAIN_MATERIAL];
+        GLJTypeConst.GENERAL_MACHINE,GLJTypeConst.MAIN_MATERIAL,GLJTypeConst.INSTRUMENT];
 
     /**
      * 构造函数
@@ -83,6 +83,7 @@ class GLJListModel extends BaseModel {
         let mixRatioConnectData = {};
         let mixRationMap={};
         let keyMap={};
+        let unitPriceList={};
         try {
             // 首先获取对应标段下所有的项目工料机数据
             let condition = {project_id: projectId};
@@ -95,7 +96,7 @@ class GLJListModel extends BaseModel {
 
             // 获取标段设置的单价文件数据
             let unitPriceModel = new UnitPriceModel();
-            let unitPriceList = await unitPriceModel.getDataByFileId(unitPriceFileId);
+            unitPriceList = await unitPriceModel.getDataByFileId(unitPriceFileId);
             // 整理获取工料机ID list
             let gljIdList = [];
             for(let tmp of gljData) {
@@ -172,7 +173,7 @@ class GLJListModel extends BaseModel {
             gljData = [];
         }
 
-        return [gljData, mixRatioConnectData,mixRationMap];
+        return [gljData, mixRatioConnectData,mixRationMap,unitPriceList];
     }
     /**
      * 组合工料机数据和单价文件数据
@@ -234,7 +235,7 @@ class GLJListModel extends BaseModel {
      * @param {object} data
      * @return {Promise} 返回插入成功的数据id
      */
-    async addList(data,unitFileId) {
+    async addList(data,unitFileId,ext) {
         let result = null;
         try {
             if (Object.keys(data).length <= 0) {
@@ -276,11 +277,11 @@ class GLJListModel extends BaseModel {
             if(this.ownCompositionTypes.indexOf(data.type)!=-1) {
                 //如果是新增
                 if(isAddProjectGLJ ){
-                    await this.compositionInit(data, unitPriceFileId);
+                    await this.compositionInit(data, unitPriceFileId,ext);
                 }
                 CompositionGLJ=await this.getCompositionGLJByData(data,unitPriceFileId);
                 if(isAddProjectGLJ==false&&CompositionGLJ.length==0){//如果不是新增,并且是有组成物的类型但又没有发现组成物的情况下,有可能是错误数据,重新在库中查找一下组成物,有则插入
-                    await this.compositionInit(data, unitPriceFileId);
+                    await this.compositionInit(data, unitPriceFileId,ext);
                     CompositionGLJ=await this.getCompositionGLJByData(data,unitPriceFileId);
 
                     if(CompositionGLJ.length>0){//如果这次发现又有组成物了,则把旧的单价数据删除,在后面的操作中会重新增加
@@ -534,7 +535,7 @@ class GLJListModel extends BaseModel {
      * @param {Number} projectId
      * @return {void}
      */
-    async compositionInit(data, unitPriceFileId) {
+    async compositionInit(data, unitPriceFileId,ext) {
         let gljId = data.glj_id === undefined ? 0 : data.glj_id;
         let projectId = data.project_id === undefined ? 0 : data.project_id;
         let mixRatioModel = new MixRatioModel();
@@ -552,9 +553,14 @@ class GLJListModel extends BaseModel {
         let e_mList = await mixRatioModel.findDataByCondition({unit_price_file_id: unitPriceFileId,connect_key: connect_key},null,false);
         if(e_mList.length <= 0){
             for (let tmp of compositionGljList) {
+                let consumpiton = tmp.consumption;
+                //只有标准的工料机的组成物才会有多单价、多组成物消耗量的情况 fromTable
+                if(fromTable == 'std' && ext && ext.quantityField &&( tmp.consumption[ext.quantityField]!= undefined && tmp.consumption[ext.quantityField]!=null)){
+                    consumpiton = tmp.consumption[ext.quantityField];
+                }
                 // 配合比数据插入
                 let mixRatioData = {
-                    consumption: tmp.consumption,
+                    consumption: consumpiton,
                     glj_id: tmp.ID,
                     unit_price_file_id: unitPriceFileId,
                     connect_key: connect_key,
@@ -600,7 +606,13 @@ class GLJListModel extends BaseModel {
                 };
                 gljInsertData.push(gljData);
             }
-            let basePrice = scMathUtil.roundTo(tmp.basePrice,-6);
+            let basePrice = tmp.basePrice;
+            //只有标准的工料机的组成物才会有多单价、多组成物消耗量的情况 fromTable
+            if(fromTable == 'std' && ext && ext.priceField &&( tmp.priceProperty[ext.priceField]!= undefined && tmp.priceProperty[ext.priceField]!=null)){
+                basePrice = tmp.priceProperty[ext.priceField];
+            }
+            basePrice = scMathUtil.roundTo(basePrice,-6);
+
             // 单价文件插入的数据
             let unitPriceData = {
                 base_price: basePrice,
@@ -629,8 +641,6 @@ class GLJListModel extends BaseModel {
         if(unitPriceInsertData.length >0) await unitPriceModel.add(unitPriceInsertData);
        //插入项目工料机
         if(gljInsertData.length > 0) await this.add(gljInsertData);
-
-
         return
     }
 
@@ -769,7 +779,7 @@ class GLJListModel extends BaseModel {
         // 整理数据
         let unitPriceData = {};
         for(let tmp of unitPriceList) {
-            let u_index = this.getIndex(tmp,['code','name','specs','unit','type'])
+            let u_index = this.getIndex(tmp,['code','name','specs','unit','type']);
             unitPriceData[u_index] = tmp;
         }
         return [gljData,mixRatioData,unitPriceData];

+ 16 - 3
modules/glj/models/unit_price_file_model.js

@@ -8,9 +8,8 @@
 import mongoose from "mongoose";
 import BaseModel from "../../common/base/base_model";
 import CounterModel from "./counter_model";
-const ProjectModel = require('../../pm/models/project_model').project;
 let collectionName = 'unit_price_file';
-
+let Projects = mongoose.model('projects');
 class UnitPriceFileModel extends BaseModel {
 
     /**
@@ -74,7 +73,7 @@ class UnitPriceFileModel extends BaseModel {
                 throw '标段id有误';
             }
 
-            let unitPriceFileId =await ProjectModel.getUnitPriceFileId(projectId);
+            let unitPriceFileId =await this.getUnitPriceFileId(projectId);
             if (unitPriceFileId <= 0) {
                 throw '没有对应的单价文件';
             }
@@ -88,6 +87,20 @@ class UnitPriceFileModel extends BaseModel {
         return result;
     }
 
+    async getUnitPriceFileId(projectId){
+        let result = 0;
+        let startTime = +new Date();
+        let projectData = await Projects.find({ID: projectId},['property.unitPriceFile']);
+        if (projectData === null) {
+            return result;
+        }
+        let endTime = +new Date();
+        console.log("取单价文件列表id时间-----"+(endTime - startTime));
+        projectData = projectData[0];
+        result = projectData.property.unitPriceFile !== undefined ? projectData.property.unitPriceFile.id : 0;
+        return result;
+    }
+
     /**
      * 新增单条工料机数据
      *

+ 20 - 10
modules/glj/models/unit_price_model.js

@@ -128,13 +128,25 @@ class UnitPriceModel extends BaseModel {
         }
 
         if (unitPriceData&&unitPriceData.length>0&&operation!='add') {// 如果原始编码能找到,但不存在一样的编号,名称,单位.型号等,更改code和添加新增标记,新增的时候除外。新增的情况下能到这一步说明有存在编码一致但其它属性不一致的情况,所以不用更改编码
-            insertData.code = data.original_code+"-"+unitPriceData.length;
+            //insertData.code = data.original_code+"-"+unitPriceData.length;
+            insertData.code = data.original_code+"-"+this.getLastNumber(data.original_code,unitPriceData);
             insertData.is_add=1;
         }
         let addPriceResult = await this.add(insertData);
         return [addPriceResult, true];
     }
-
+     getLastNumber(original_code,unitPriceData){
+        let codeArray = _.map(unitPriceData,'code');
+        let last = 1;
+        while (true){
+            if(_.includes(codeArray,original_code+"-"+last)){
+                last +=1
+            }else {
+                break;
+            }
+        }
+        return last;
+     }
     /**
      * 新增记录
      *
@@ -178,20 +190,18 @@ class UnitPriceModel extends BaseModel {
     }
 
     isPropertyInclude(data,pops,obj){
-        let condition={};
+        let condition={},me = this;
         if (data.length <= 0) {
             return null;
         }
         if(pops instanceof  Array){
-            for(let p of pops){
-                if(obj[p]!==undefined && obj[p]!==undefined!=null){
-                    condition[p]=obj[p]
-                }
-            }
+            return _.find(data,function (d) {
+                return me.getIndex(d,pops) == me.getIndex(obj,pops)
+            });
         }else {
-            condition[pops]=obj[pops]
+            condition[pops]=obj[pops];
+            return _.find(data,condition);
         }
-        return _.find(data,condition);
     }
     /**
      * 更新市场单价

+ 65 - 360
modules/main/controllers/bills_controller.js

@@ -8,13 +8,12 @@ let ProjectsData = require('../../pm/models/project_model').project;
 let logger = require("../../../logs/log_helper").logger;
 let quantity_detail = require("../facade/quantity_detail_facade");
 let bill_facade = require("../facade/bill_facade");
-let ration_glj = mongoose.model('ration_glj');
-let ration_coe = mongoose.model('ration_coe');
-let rationInstallationModel = mongoose.model('ration_installation');
+let raiton_facade = require("../facade/ration_facade");
 let stdBillsModel = mongoose.model('std_bills_lib_bills');
 let stdBillJobsModel = mongoose.model('std_bills_lib_jobContent');
 let stdBillCharacterModel = mongoose.model('std_bills_lib_itemCharacter');
 import fixedFlag from  '../../common/const/bills_fixed';
+let LZString = require('lz-string');
 const uuidV1 = require('uuid/v1');
 const billType ={
     DXFY:1,//大项费用
@@ -77,6 +76,16 @@ module.exports = {
             callback(req, res, err, message, null);
         });
     },
+    updateBills: async function (req, res) {
+        try{
+            let data = JSON.parse(req.body.data);
+            await billsData.updateBills(data.updateDatas);
+            callback(req, res, 0, 'success', null);
+        }
+        catch (err){
+            callback(req, res, 1, err, null);
+        }
+    },
     updateBill: async function(request, response) {
         const data = JSON.parse(request.body.data);
         const findSet = data.findSet;
@@ -201,18 +210,13 @@ module.exports = {
 
     },
     //导入清单
-    upload: async function(req, res){
+    import: async function(req, res){
         let responseData = {
             err: 0,
             msg: '',
             data: []
         };
-        const allowHeader = ['application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'];
-        const uploadOption = {
-            uploadDir: './public'
-        };
-        const form = new multiparty.Form(uploadOption);
-        let uploadFullName;
+        const form = new multiparty.Form();
         form.parse(req, async function(err, fields, files) {
             try{
                 const projectID = fields.projectID !== undefined && fields.projectID.length > 0 ?
@@ -220,91 +224,37 @@ module.exports = {
                 if (projectID <= 0) {
                     throw '参数错误';
                 }
-                const file = files.file !== undefined ? files.file[0] : null;
-                if (err || file === null) {
-                    throw '上传失败';
-                }
-                // 判断类型
-                if (file.headers['content-type'] === undefined || allowHeader.indexOf(file.headers['content-type']) < 0) {
-                    throw '不支持该类型';
-                }
-                //导入表类型(09表lj、广联达gld)
-                const fileType = fields.fileType !== undefined && fields.fileType.length > 0 ? fields.fileType[0] : uploadType.lj;
-                // 重命名文件名
-                uploadFullName = uploadOption.uploadDir + '/' + file.originalFilename;
-                fs.renameSync(file.path, uploadFullName);
-
-                const sheets = excel.parse(uploadFullName);
-                if (sheets[0] === undefined || sheets[0].data === undefined) {
-                    throw 'excel没有对应数据';
-                }
-                //出现错误的表表名,前端提示用
-                let invalidSheets = [];
-                let validSheets = {fbfx: [], jscsxm: [], zzcsxm: []};
-                //获得选择的导入的表及导入位置
-                const uploadWorkBook = fields.uploadWorkBook !== undefined && fields.uploadWorkBook.length > 0 ? JSON.parse(fields.uploadWorkBook[0]) : [];
-                //识别非法和合法表,sheetInfo存储前端勾选的表的位置索引以及选择的导入位置
-                for(let sheetInfo of uploadWorkBook){
-                    let sheet = sheets[sheetInfo.sheetIdx];
-                    if(sheet.data === undefined){
-                        invalidSheets.push(sheet.name);
-                        continue;
-                    }
-                    //获取表的列设置确定导入的格式是否合法(09、广联达)
-                    let colMapping = getColMapping(sheet.data);
-                    if(!isValidSheet(colMapping, fileType)){
-                        invalidSheets.push(sheet.name);
-                        continue;
-                    }
-                    //合法的表
-                    sheet.colMapping = colMapping;
-                    //将合法的表按导入位置分类当做一个表来处理
-                    if(validSheets[sheetInfo.position] !== undefined){
-                        validSheets[sheetInfo.position].push(sheet)
-                    }
-                }
-                //合并同类表并提取表的有效数据
-                let toImportSheets = [];
-                for(let uploadPosition in validSheets){
-                    let validExcelData = [];
-                    for(let uSheet of validSheets[uploadPosition]){
-                        validExcelData = validExcelData.concat(getValidImportData(uSheet.colMapping, uSheet.data))
-                    }
-                    if(validSheets[uploadPosition].length > 0){
-                        toImportSheets.push({position: uploadPosition, colMapping: validSheets[uploadPosition][0].colMapping, validExcelData: validExcelData});
-                    }
+                //导入清单数据
+                let compressData = fields.compressData !== undefined && fields.compressData.length > 0 ?
+                    fields.compressData[0] : null;
+                if(compressData === null){
+                    throw 'excel没有对应数据'
                 }
+                let importData = JSON.parse(LZString.decompressFromUTF16(compressData));
                 //匹配的清单库
                 const billsLibId = fields.billsLibId !== undefined && fields.billsLibId.length > 0 && fields.billsLibId[0]? parseInt(fields.billsLibId[0]) : null;
                 let stdBills = [], stdJobs = [], stdCharacters = [];
                 if(billsLibId){
-                    stdBills = await stdBillsModel.find({billsLibId: billsLibId, deleted: false}, '-_id code jobs items engineering billsLibId');
+                    stdBills = await stdBillsModel.find({billsLibId: billsLibId, deleted: false}, '-_id code jobs items engineering billsLibId ruleText');
                     stdJobs = await stdBillJobsModel.find({billsLibId: billsLibId, deleted: false});
                     stdCharacters = await stdBillCharacterModel.find({billsLibId: billsLibId, deleted: false});
                 }
                 let stdData = {stdBills: stdBills, stdJobs: stdJobs, stdCharacters: stdCharacters};
                 //导入表
-                for(let importData of toImportSheets){
-                    let updateFrontData = await importSheet(importData, req.session.sessionUser.id, projectID, stdData);
-                    if(updateFrontData){
-                        responseData.data.push(updateFrontData);
+                let importDateA = +new Date();
+                for(let position in importData){
+                    if(importData[position].length > 0){
+                        let updateFrontData = await importSheet(position, importData[position], req.session.sessionUser.id, projectID, stdData);
+                        if(updateFrontData){
+                            responseData.data.push(updateFrontData);
+                        }
                     }
                 }
-                if(responseData.data.length === 0){
-                    throw 'excel无有效数据';
-                }
-                if(invalidSheets.length > 0){
-                    let msg = invalidSheets.join('、');
-                    responseData.msg = `${msg},导入失败`;
-                }
-                //删除暂存文件
-                fs.unlink(uploadFullName);
+                let importDateB = +new Date();
+                console.log(`导入时间: ${importDateB - importDateA}=========================================================================`);
                 res.json(responseData);
             }
             catch (error){
-                if(fs.existsSync(uploadFullName)){
-                    fs.unlink(uploadFullName);
-                }
                 responseData.err = 1;
                 console.log(error);
                 responseData.msg = typeof error === 'object' ? '上传失败' : error;
@@ -315,10 +265,9 @@ module.exports = {
     }
 };
 
-//
-async function importSheet(importData, userID, projectID, stdData){
+async function importSheet(position, excelBills, userID, projectID, stdData){
         //导入位置的有固定行
-        let flag = getImportFlag(importData.position);
+        let flag = getImportFlag(position);
         if(!flag){
             throw 'excel数据错误';
         }
@@ -349,170 +298,19 @@ async function importSheet(importData, userID, projectID, stdData){
             await billsData.model.create(insertFixedBill);
             fixedBill = insertFixedBill;
         }
-        //将excel数据转换成清单树结构数据
-        let insertDatas = parseToBillData(importData.validExcelData, importData.colMapping, fixedBill, projectID, stdData);
-        /*if(insertDatas.length === 0){
-            throw 'excel无有效数据';
-        }*/
-        if(insertDatas.length === 0){
-            return null;
-        }
+        //将excel清单数据转换成完整清单数据(设置ParentID、匹配标准清单库)
+        parseToCompleteBills(excelBills, fixedBill, stdData);
         //删除相关数据
         let deleteDatas = await billsData.deepDeleteBill([fixedBill], userID);
         //新增清单数据
-        await billsData.importBills(insertDatas);
+        await billsData.importBills(excelBills);
         //返回数据以更新前端
         if(insertFixedBill){
-            insertDatas.push(insertFixedBill);
+            excelBills.push(insertFixedBill);
         }
-        return {fixedBill: fixedBill, insert: {bill: insertDatas, ration: []}, remove: {bill: deleteDatas.bill, ration: deleteDatas.ration}};
+        return {fixedBill: fixedBill, insert: {bill: excelBills, ration: []}, remove: {bill: deleteDatas.bill, ration: deleteDatas.ration}};
 }
 
-//是否是有效的表头列格式,只要含有各表需要的列就行,不严格控制多少列
-function isValidSheet(colMapping, fileType){
-    function hasField(field, all){
-        for(let i of all){
-            if(field === i){
-                return true;
-            }
-        }
-        return false;
-    }
-    let needFields;
-    if(fileType === uploadType.lj){
-        //09表:序号、项目编码、项目名称、项目特征、计量单位、工程量、金额
-        needFields = ['serialNo', 'code', 'name', 'money'];
-    }
-    else {
-        //广联达表:序号、项目编码、项目名称、项目特征、计量单位、工程量、工程量明细、费用明细
-        needFields = ['serialNo', 'code', 'name', 'itemCharacterText', 'unit', 'quantity', 'quantityDetail', 'feeDetail'];
-    }
-    let hasFieldCount = 0;
-    for(let attr in colMapping){
-        if(hasField(attr, needFields)){
-            hasFieldCount++;
-        }
-    }
-    return hasFieldCount === needFields.length;
-}
-
-//提取excel表头列对应数据
-function getColMapping(sheetData){
-    //获取表头
-    function getHeadRow(sheetData){
-        for(let rData of sheetData) {
-            //寻找含有序号的行,认作表头行
-            for(let cData of rData){
-                if (cData && cData.toString().replace(/\s/g, '') === '序号') {
-                    headRow = rData;
-                    return rData;
-                }
-            }
-        }
-        return [];
-    }
-    //获取需要的表头列与列号对应关系
-    let colMapping = {};
-    let headRow = getHeadRow(sheetData);
-    for(let c = 0; c < headRow.length; c++){
-        if(headRow[c]){
-            headRow[c] = headRow[c].toString().replace(/\s/g, '');
-            //重复的,只取第一个
-            console.log(headRow[c]);
-            if(headRow[c] === '序号' && colMapping.serialNo === undefined){
-                colMapping.serialNo = c;
-            }
-            else if((headRow[c] === '编码' || headRow[c] === '项目编码') && colMapping.code === undefined){
-                colMapping.code = c;
-            }
-            else if((headRow[c] === '名称' || headRow[c] === '项目名称') && colMapping.name === undefined){
-                colMapping.name = c;
-            }
-            else if((headRow[c] === '特征' || headRow[c] === '项目特征') && colMapping.itemCharacterText === undefined){
-                colMapping.itemCharacterText = c;
-            }
-            else if((headRow[c] === '单位' || headRow[c] === '计量单位') && colMapping.unit === undefined){
-                colMapping.unit = c;
-            }
-            else if((headRow[c] === '工程量' || headRow[c] === '项目工程量') && colMapping.quantity === undefined){
-                colMapping.quantity = c;
-            }
-            else if(headRow[c].includes('金额') && colMapping.money === undefined){
-                colMapping.money = c;
-            }
-            else if(headRow[c] === '工程量明细' && colMapping.quantityDetail === undefined){
-                colMapping.quantityDetail = c;
-            }
-            else if(headRow[c] === '费用明细' && colMapping.feeDetail === undefined){
-                colMapping.feeDetail = c;
-            }
-        }
-    }
-    return colMapping;
-}
-function rowExistData(rowData){
-    for(let cData of rowData){
-        if(cData !== undefined && cData !== ''){
-            return true;
-        }
-    }
-    return false;
-}
-//提取excel表数据中的有效数据(去表头表尾,提取其中的excel数据)(根据fixedBill获取栏头占行数)
-function getValidImportData(colMapping, sheetData){
-    let withingD = false;
-    let validData = [];
-    function isHead(rData){
-        return rData[colMapping.serialNo] && rData[colMapping.serialNo].toString().replace(/\s/g, '') === '序号';
-    }
-    function isTail(rData){
-        for(let cData of rData){
-            if(cData){
-                let trimCData = cData.toString().replace(/\s/g, '');
-                if(trimCData === '本页小计' || trimCData === '本页小计'){
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-    for(let r = 0; r < sheetData.length; r++){
-        let rData = sheetData[r];
-        if(isHead(rData)){
-            withingD = true;
-          /*  if(fixedBill.name !== '施工组织措施项目'){
-                r++;
-            }*/
-            continue;
-        }
-        else if(isTail(rData)){
-            withingD = false;
-        }
-        if(withingD && rowExistData(rData)){
-            validData.push(rData);
-        }
-        /*if(rData[0]){
-            //首列去空格
-            rData[0] = rData[0].toString().replace(/\s/g, '');
-            //表头
-            if(rData[0] === '序号'){
-                withingD = true;
-                if(fixedBill.name !== '施工组织措施项目'){
-                    r++;
-                }
-                continue;
-            }
-            //表尾
-            else if(rData[0] === '本页小计' || rData[0] === '合计'){
-                withingD = false;
-            }
-        }
-        if(withingD && rowExistData(rData)){
-            validData.push(rData);
-        }*/
-    }
-    return validData;
-}
 
 function getImportFlag(position){
     const fixedItem = {'fbfx': fixedFlag.SUB_ENGINERRING, 'jscsxm': fixedFlag.CONSTRUCTION_TECH, 'zzcsxm': fixedFlag.CONSTRUCTION_ORGANIZATION};
@@ -521,51 +319,27 @@ function getImportFlag(position){
 function isDef(data){
     return typeof data !== 'undefined' && data !== null && data !== '';
 }
-//excel数据转换成清单数据
-function parseToBillData(validData, colMapping, fixedBill, projectID, stdData){
-    let rst = [];
-    let billIdx = {};
-    let preRootID = -1,
-        preLeafID = -1,
-        preID = -1;
-    //去除转义字符
-    function removeESC(data){
-        return isDef(data) ? data.toString().replace(/[\r,\n,\s,\t]/g, '') : data;
-    }
-    //父节点:1.无序号 2有编码
-    function isRoot(rData){
-        //序号和编码去除转义字符(有的表格单元格看起来是没数据,实际含有\r,\n等数据)
-        let serialNo = removeESC(rData[colMapping.serialNo]);
-        let code = removeESC(rData[colMapping.code]);
-        return !isDef(serialNo) && isDef(code);
-    }
-    //子节点:有序号
-    function isLeaf(rData){
-        let serialNo = removeESC(rData[colMapping.serialNo]);
-        return isDef(serialNo);
-    }
-    //续数据:1. 前数据有效 2.无序号 3.无编码 4.有名称或特征
-    function isExtend(preData, rData){
-        let serialNo = removeESC(rData[colMapping.serialNo]);
-        let code = removeESC(rData[colMapping.code]);
-        let name = rData[colMapping.name];
-        let itemCharacterText = rData[colMapping.itemCharacterText];
-        return isDef(preData) && (isRoot(preData) || isLeaf(preData)) && !isDef(serialNo) && !isDef(code) && (isDef(name) || isDef(itemCharacterText));
-    }
-    function getBillType(rData, flag){
-        if(flag === fixedFlag.CONSTRUCTION_TECH || flag === fixedFlag.CONSTRUCTION_ORGANIZATION){
-            return billType.BILL;
+//将前端解析生成的清单节点数据完善(ParentID、匹配标准清单)
+function parseToCompleteBills(excelBills, fixedBills, stdData){
+    //设置清单ParentID
+    let rootID = fixedBills ? fixedBills.ID: -1;
+    for(let bills of excelBills){
+        if(bills.nodeType === 'root'){
+            rootID = bills.ID;
+            bills.ParentID = fixedBills.ID;
         }
-        else if(flag === fixedFlag.SUB_ENGINERRING){
-            return isLeaf(rData) ? billType.FX : billType.FB;
+        else {
+            bills.ParentID = rootID;
         }
-        return null;
+        delete bills.nodeType;
+        matchStdBill(bills, stdData);
     }
+
     //excel数据与标准库数据匹配,根据清单前九位编码匹配,匹配成功则获取标准清单对应的工程专业、特征及内容
     function matchStdBill(excelBill, stdData){
         let isMatch = false;
         let regExp = /^\d{12}$/g;
-        if(regExp.test(excelBill.code)){
+        if(excelBill.code.length >8){
             let nineCode = excelBill.code.substr(0, 9);
             for(let stdBill of stdData.stdBills){
                 //set programID
@@ -573,6 +347,7 @@ function parseToBillData(validData, colMapping, fixedBill, projectID, stdData){
                     isMatch = true;
                     excelBill.programID = stdBill.engineering ? stdBill.engineering : null;
                     excelBill.billsLibId = stdBill.billsLibId ? stdBill.billsLibId : null;
+                    excelBill.ruleText = stdBill.ruleText ? stdBill.ruleText : '';
                     //set jobContent and itemCharacter
                     let tempJob = [], tempCharacter = [];
                     for(let billJob of stdBill.jobs){
@@ -599,86 +374,9 @@ function parseToBillData(validData, colMapping, fixedBill, projectID, stdData){
             }
         }
         if(!isMatch && excelBill.type === billType.FX){//分项不为空,同时在标准清单中不匹配,则识别为补项
-                excelBill.type = billType.BX;
-        }
-    }
-    for(let r = 0; r < validData.length; r++){
-       /* //序号和编码去除转义字符(有的表格单元格看起来是没数据,实际含有\r,\n等数据)
-        let serialNo = validData[r][colMapping.serialNo];
-        let code = validData[r][colMapping.code];
-        if(isDef(serialNo)){
-            serialNo = removeESC(serialNo);
-        }
-        if(isDef(code)){
-            code = removeESC(code);
-        }*/
-        let preData = validData[r-1],
-            rData = validData[r];
-        if(fixedBill.flags[0].flag == fixedFlag.CONSTRUCTION_TECH && rData[colMapping.name] === '施工技术措施项目'
-            || fixedBill.flags[0].flag == fixedFlag.CONSTRUCTION_ORGANIZATION && rData[colMapping.name] === '施工组织措施项目'){
-            continue;
-        }
-        //过滤无效数据
-        if(!isRoot(rData) && !isLeaf(rData) && !isExtend(preData, rData)){
-            continue;
-        }
-        if(isExtend(preData, rData)){
-            let preBill = billIdx[preID];
-            //合并续数据
-            if(preBill){
-                preBill.code += rData[colMapping.code] ? rData[colMapping.code] : '';
-                preBill.name += rData[colMapping.name] ? rData[colMapping.name] : '';
-                preBill.itemCharacterText += rData[colMapping.itemCharacterText] ? rData[colMapping.itemCharacterText] : '';
-                preBill.unit += rData[colMapping.unit] ? rData[colMapping.unit] : '';
-                preBill.quantity += rData[colMapping.quantity] ? rData[colMapping.quantity] : '';
-            }
-        }
-        else {
-            let newID = uuidV1();
-            let pID = -1;
-            let preBill = null;
-            if(isRoot(rData)){
-                pID = fixedBill.ID;
-                preBill = billIdx[preRootID];
-            }
-            else if(isLeaf(rData)){
-                pID = preRootID !== -1 ? preRootID : fixedBill.ID;
-                preBill = billIdx[preLeafID];
-            }
-            //set bill data
-            billIdx[newID] = {
-                ID: newID, ParentID: pID, NextSiblingID: -1,
-                code: rData[colMapping.code] ? removeESC(rData[colMapping.code]) : '',
-                name: rData[colMapping.name] ? removeESC(rData[colMapping.name]) : '',
-                itemCharacterText: rData[colMapping.itemCharacterText] ? rData[colMapping.itemCharacterText] : '',
-                itemCharacter: [],
-                jobContentText: '',
-                jobContent: [],
-                programID: null,
-                unit: rData[colMapping.unit] ? rData[colMapping.unit] : '',
-                quantity: rData[colMapping.quantity] ? rData[colMapping.quantity] : '',
-                //安全文明
-                flags: fixedBill.flags[0].flag === fixedFlag.CONSTRUCTION_ORGANIZATION && (rData[colMapping.name] === '安全文明施工专项费用' || rData[colMapping.name] === '安全文明施工费') ?
-                    [{fieldName: 'fixed', flag: fixedFlag.SAFETY_CONSTRUCTION}] : [],
-                fees: [],
-                projectID: projectID,
-                type: getBillType(rData, fixedBill.flags[0].flag)};
-            //match stdBill and reset programID、jobContent、itemCharacter
-            matchStdBill(billIdx[newID], stdData);
-            //update preBill NextSibling
-            if(preBill){
-                preBill.NextSiblingID = newID;
-            }
-            //set new preID
-            preID = newID;
-            preRootID = isRoot(rData) ? newID : preRootID;
-            preLeafID = isLeaf(rData) ? newID : preLeafID;
+            excelBill.type = billType.BX;
         }
     }
-    for(let i in billIdx){
-        rst.push(billIdx[i]);
-    }
-    return rst;
 }
 
 async function doBillsOrRationsDelete(data) {
@@ -725,9 +423,7 @@ async function doBillsOrRationsDelete(data) {
         await quantity_detail.deleteByQuery(qd_query) ;
     }
     if(sub_query!=null){
-        await ration_coe.deleteMany(sub_query);//删除附注条件
-        await ration_glj.deleteMany(sub_query);//删除定额工料机
-        await rationInstallationModel.deleteMany(sub_query);//删除安装增加费
+        await raiton_facade.deleteSubListByQuery(sub_query);
     }
     if(rationTask.length>0){
         await ration_model.model.bulkWrite(rationTask);//删除定额
@@ -761,9 +457,18 @@ function  generateUpdateTasks(data,projectID,user_id) {
             }
         };
         if(updateData[key]===true){
-            task.updateOne.update={
+            //原先是假删除,现在改成真删除
+            task = {
+                deleteOne:{
+                    filter:{
+                        ID:key,
+                        projectID:projectID
+                    }
+                }
+            }
+           /* task.updateOne.update={
                 deleteInfo:deleteInfo
-            };
+            };*/
         }else {
             task.updateOne.update=updateData[key];
         }

+ 23 - 0
modules/main/controllers/block_lib_controller.js

@@ -0,0 +1,23 @@
+/**
+ * Created by CSL on 2018-12-17.
+ */
+
+let mongoose = require('mongoose');
+let blFacade = require('../facade/block_lib_facade');
+
+module.exports = {
+    doController: async function (req, res) {
+        let result = {error: 0, message: '', data: null};
+        try {
+            let funcName = req.url.replace(/\//g, "");
+            let dataObj = JSON.parse(req.body.data);
+            result.data = await blFacade[funcName](dataObj);
+        } catch (err) {
+            console.log(err);
+            result.error = 1;
+            result.message = err.message;
+        }
+        res.json(result);
+    }
+};
+

+ 34 - 0
modules/main/controllers/material_replace_controller.js

@@ -0,0 +1,34 @@
+/**
+ * Created by zhang on 2018/9/12.
+ */
+
+let materialFacade = require('../facade/material_replace_facade');
+let logger = require("../../../logs/log_helper").logger;
+let controller = {
+    getMaterial:async function(req) {
+        let data = req.body.data;
+        return await materialFacade.findMaterial(JSON.parse(data),req.session.sessionCompilation._id);
+
+    },
+    replace:async function(req){
+        let data = req.body.data;
+        return await materialFacade.replace(JSON.parse(data));
+    },
+};
+
+module.exports ={
+    action:async function(req,res){//自动跳转到URL对应的controller方法
+        let result={
+            error:0
+        };
+        try {
+            let functionName = req.url.replace(/\//g,"");
+            result.data = controller[functionName]?await controller[functionName](req):"";
+        }catch (err){
+            logger.err(err);
+            result.error=1;
+            result.message = err.message;
+        }
+        res.json(result);
+    }
+};

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

@@ -28,8 +28,7 @@ module.exports = {
     getData: function (req, res) {
         //add
         console.log(`------------------------------------------`);
-        console.log(req.session.sessionUser);
-        console.log(req.session.userAccount);
+        console.log(`${req.session.sessionUser.real_name}--id:${req.session.sessionUser.id}--取getdata数据`);
         console.log(`------------------------------------------`);
         //add
         if(typeof req.body.data === 'object'){

+ 103 - 78
modules/main/controllers/ration_controller.js

@@ -1,13 +1,101 @@
 /**
  * Created by jimiz on 2017/4/9.
  */
-var rationData = require('../models/ration');
-var ration_glj_facade = require('../../ration_glj/facade/ration_glj_facade');
-var ration_facade = require('../facade/ration_facade');
+let rationData = require('../models/ration');
+let ration_glj_facade = require('../../ration_glj/facade/ration_glj_facade');
+let ration_ass_facade = require('../../ration_glj/facade/ration_ass_facade');
+let ration_facade = require('../facade/ration_facade');
+let bill_facade = require('../facade/bill_facade');
+let project_facade = require("../facade/project_facade");
 let logger = require("../../../logs/log_helper").logger;
+let controller = {
+    insertGLJAsRation:async function (req){
+        let data = req.body.data;
+        data = JSON.parse(data);
+        return await ration_glj_facade.insertGLJAsRation(data,req.session.sessionCompilation);
+    },
+    replaceRations:async function (req) {
+        let data = req.body.data;
+        data = JSON.parse(data);
+        let userID = req.session.sessionUser.id;
+        return await ration_facade.replaceRations(userID,data,req.session.sessionCompilation);
+    },
+    addNewRation:async function(req) {
+        let data = req.body.data;
+        if(typeof data === 'object'){
+            data = JSON.stringify(data);
+        }
+        data = JSON.parse(data);
+        return await ration_facade.addNewRation(data,req.session.sessionCompilation);
+    },
+    addMultiRation: async function (req) {
+        let data = req.body.data;
+        if(typeof data === 'object'){
+            data = JSON.stringify(data);
+        }
+        data = JSON.parse(data);
+        return await ration_facade.addMultiRation(data.newDatas,req.session.sessionCompilation);
+    },
+    getSameSectionRations:async function(req){//取同个章节相邻的定额
+        let data = req.body.data;
+        data = JSON.parse(data);
+        return await ration_facade.getSameSectionRations(data,req.session.sessionUser.id, req.session.sessionCompilation._id);
+    },
+    //取定额默认的取费专业
+    getDefaultProgramID:async function(req){
+        let data = req.body.data;
+        data = JSON.parse(data);
+        data.userID = req.session.sessionUser.id;
+        data.compilationId = req.session.sessionCompilation._id;
+        return await ration_facade.getDefaultProgramID(data);
+
+
+    },
+    //应用定额关联子目
+    applyTemplate:async function(req){
+        let data = req.body.data;
+        data = JSON.parse(data);
+        let updateDatas =[];
+        let applyTasks = [
+            ration_facade.addMultiRation(data.rations.create,req.session.sessionCompilation),//先生成新定额
+            bill_facade.createNewBills(data.bills.create),
+        ];
+        //整理更新的数据,调用一个方法更新
+        updateDatas.push(data.ration_template);
+        if(data.rations.update.length > 0)  prepareUpdateNodes(data.rations.update,updateDatas,"ration");
+        if(data.bills.update.length > 0)  prepareUpdateNodes(data.bills.update,updateDatas,"bills");
+        applyTasks.push(project_facade.updateNodes(updateDatas));
+        let [rationResult,billsResult,updates] = await Promise.all(applyTasks);
+        return {rationResult:rationResult,billsResult:billsResult,updateDatas:updateDatas};
+    },
+    //更新辅助定额
+    updateRationAss:async function(req){
+        let data = req.body.data;
+        data = JSON.parse(data);
+        return ration_ass_facade.updateRationAss(data);
+    },
+    //勾选定额调整系数
+    updateCoeAdjust:async function(req){
+        let data = req.body.data;
+        data = JSON.parse(data);
+        return await ration_facade.updateCoeAdjust(data,req.session.sessionCompilation);
+
+    }
+
+
+};
+
+function prepareUpdateNodes(datas,nodes,type) {
+    for(let d of datas){
+        nodes.push({type:type,data:d});
+    }
+
+}
+
+
 
 //统一回调函数
-var callback = function(req, res, err, message, data){
+let callback = function(req, res, err, message, data){
     res.json({error: err, message: message, data: data});
 };
 
@@ -43,85 +131,22 @@ module.exports = {
             }
         });
     },
-    insertGLJAsRation:insertGLJAsRation,
-    replaceRations:replaceRations,
-    addNewRation:addNewRation,
-    addMultiRation: addMultiRation
-};
-
-async function addNewRation(req,res) {
-    let result={
-        error:0
-    }
-    try {
-        let data = req.body.data;
-        if(typeof data === 'object'){
-            data = JSON.stringify(data);
+    action:async function(req,res){//自动跳转到URL对应的controller方法
+        let result={
+            error:0
         }
-        data = JSON.parse(data);
-        result.data = await ration_facade.addNewRation(data);
-    }catch (err){
-        logger.err(err);
-        result.error=1;
-        result.message = err.message;
-    }
-    res.json(result);
-}
-
-async function addMultiRation(req,res) {
-    let result={
-        error:0
-    }
-    try {
-        let data = req.body.data;
-        if(typeof data === 'object'){
-            data = JSON.stringify(data);
+        try {
+            let functionName = req.url.replace(/\//g,"");
+            result.data = controller[functionName]?await controller[functionName](req):"";
+        }catch (err){
+            logger.err(err);
+            result.error=1;
+            result.message = err.message;
         }
-        data = JSON.parse(data);
-        console.log(`data`);
-        console.log(data);
-        result.data = await ration_facade.addMultiRation(data.newDatas);
-    }catch (err){
-        logger.err(err);
-        result.error=1;
-        result.message = err.message;
-    }
-    res.json(result);
-}
-
-async function replaceRations(req,res) {
-    let result={
-        error:0
-    }
-    try {
-        let data = req.body.data;
-        data = JSON.parse(data);
-        let userID = req.session.sessionUser.id;
-        result.data = await ration_facade.replaceRations(userID,data);
-    }catch (err){
-        logger.err(err);
-        result.error=1;
-        result.message = err.message;
+        res.json(result);
     }
-    res.json(result);
 };
 
 
-async function insertGLJAsRation(req, res){
-    let result={
-        error:0
-    }
-    try {
-        let data = req.body.data;
-        data = JSON.parse(data);
-        let datas= await ration_glj_facade.insertGLJAsRation(data);
-        result.data=datas;
-    }catch (err){
-        logger.err(err);
-        result.error=1;
-        result.message = err.message;
-    }
-    res.json(result);
 
 
-}

+ 46 - 5
modules/main/facade/bill_facade.js

@@ -14,7 +14,11 @@ let ration_Model = mongoose.model('ration');
 let ration_glj_Model = mongoose.model('ration_glj');
 let ration_coe_Model = mongoose.model('ration_coe');
 let ration_installation_Model = mongoose.model('ration_installation');
+let ration_template_Model = mongoose.model('ration_template');
 let bill_Model = require('../models/bills').model;
+let billsLibDao = require("../../bills_lib/models/bills_lib_interfaces");
+
+
 import GLJController from "../../glj/controllers/glj_controller";
 
 import GLJListModel from '../../glj/models/glj_list_model';
@@ -81,7 +85,31 @@ module.exports={
         resultMap.ration_gljs = rationsAndRationGLJ.new_ration_gljs;
         resultMap.gljData = projectGLJ.data;
         return resultMap;
-    }
+    },
+    createNewBills:async function(newDatas){
+        // billsLibDao.getStdBillsByCode  从这里取数据
+        let results = [];
+        for(let bills of newDatas){
+            let stdB = await  billsLibDao.getStdBillsByCode({billsLibId:bills.billsLibId,code:bills.billsLocation});
+            if(stdB){
+                stdB = JSON.parse(JSON.stringify(stdB));
+                if(!bills.unit && /\//.test(stdB.unit)){
+                    bills.unit = stdB.unit.split(/\//)[0];
+                }
+                //处理项目特征和工作内容,现在默认都添加到项目特征列中
+                stdB.itemCharacterText = "[项目特征]\n[工作内容]\n"+stdB.jobContentText;
+                stdB.jobContentText="";
+                bills =  _.merge(stdB,bills);
+            }
+            delete bills.billsLocation;
+            results.push(bills);
+        }
+        if(results.length > 0){
+            await bill_Model.create(results);
+        }
+        return results;
+
+    },
 };
 
 async function pasteOtherData(data) {
@@ -89,6 +117,7 @@ async function pasteOtherData(data) {
     let quantity_details = data.quantity_details;
     let ration_coes = data.ration_coes;
     let ration_installations = data.ration_installations;
+    let ration_templates = data.ration_templates;
     let updateData = data.updateData;
     let uModel = null;
     let tasks = [];
@@ -113,9 +142,10 @@ async function pasteOtherData(data) {
     quantity_details.length > 0 ? await insertMany(quantity_details,quantity_detail_model):'';
     ration_coes.length > 0 ? await insertMany(ration_coes,ration_coe_Model):'';
     ration_installations.length > 0 ? await insertMany(ration_installations,ration_installation_Model):'';
+    ration_templates.length > 0? await insertMany(ration_templates,ration_template_Model):'';
     tasks.length>0?await uModel.bulkWrite(tasks):'';
 
-    return {bills:bills,quantity_details:quantity_details,ration_coes:ration_coes,ration_installations:ration_installations,updateData:updateData}
+    return {bills:bills,quantity_details:quantity_details,ration_coes:ration_coes,ration_installations:ration_installations,ration_templates:ration_templates,updateData:updateData}
 }
 
 async function pasteRationsAndRationGLJ (rations,ration_gljs) {
@@ -178,7 +208,16 @@ function generateBillTasks(data) {
     let deleteInfo={deleted: true, deleteDateTime: new Date(), deleteBy: user_id};
     if(data.delete && data.delete.length > 0){
         for(let d_ID of data.delete){
-            let task={
+            //原先是假删除,现在改成真删除
+            let task = {
+                deleteOne:{
+                    filter:{
+                        ID:d_ID,
+                        projectID:projectID
+                    }
+                }
+            };
+          /*  let task={
                 updateOne:{
                     filter:{
                         ID:d_ID,
@@ -188,7 +227,7 @@ function generateBillTasks(data) {
                         deleteInfo:deleteInfo
                     }
                 }
-            };
+            };*/
             tasks.push(task);
         }
     }
@@ -221,10 +260,12 @@ function generateBillTasks(data) {
 
 
 async function insertMany(datas,model) {
+    let tem = [];
     while (datas.length>1000){//因为mongoose限制了批量插入的条数为1000.所以超出限制后需要分批插入
         let newList = datas.splice(0,1000);//一次插入1000条
         await model.insertMany(newList);
+        tem = tem.concat(newList);
     }
     await model.insertMany(datas);
-
+    if(tem.length > 0) datas.push(...tem);//还原数组
 }

+ 128 - 0
modules/main/facade/block_lib_facade.js

@@ -0,0 +1,128 @@
+/**
+ * Created by CSL on 2018-12-17.
+ */
+
+let mongoose = require('mongoose');
+let blModel = mongoose.model('blockLibsModel');
+let uuid = require('../../../public/web/uuid');
+
+module.exports = {
+    getLibNames: getLibNames,
+    getLib: getLib,
+    getLibNamesAndFirstLib: getLibNamesAndFirstLib,
+    copyTemplateLib: copyTemplateLib,
+    saveBlock: saveBlock
+};
+
+// userID、compilationID
+async function getLibNames(data) {
+    let libNames = await blModel.find({userID: data.userID, compilationID: data.compilationID}, ["libID","libName","-_id"]);
+    return libNames;
+};
+
+// libID
+async function getLib(data) {
+    let lib = await blModel.findOne({libID: data.libID});
+    return lib;
+};
+
+// userID、compilationID
+async function getLibNamesAndFirstLib(data) {
+    let libNames = await getLibNames(data);
+    let lib = null;
+    if (libNames.length == 0){
+        lib = await copyTemplateLib(data.userID, data.userName, data.compilationID);
+        libNames.push({libID: lib.libID, libName: lib.libName});
+    }
+    else{
+        lib = await getLib(libNames[0]);
+    }
+    return {libNames: libNames, firstLib: lib};
+};
+
+
+async function copyTemplateLib(userID, userName, compilationID) {
+    // let template = await getLib({libID: '00000000'});
+    let template = {
+        libID: "00000000",
+        libName: "模板",
+        datas: [
+            {
+                "ID": "00000001",
+                "ParentID": "-1",
+                "NextSiblingID": "00000002",
+                "type": 1,
+                "nodeName": "分类1"
+            },
+            {
+                "ID": "00000002",
+                "ParentID": "-1",
+                "NextSiblingID": "00000003",
+                "type": 1,
+                "nodeName": "分类2"
+            },
+            {
+                "ID": "00000003",
+                "ParentID": "-1",
+                "NextSiblingID": "-1",
+                "type": 1,
+                "nodeName": "分类3"
+            }
+        ],
+        share: {
+            "shareName": "共享",
+            "shareTo": []
+        }
+    };
+
+    let newLib = {
+        userID: userID,
+        compilationID: compilationID,
+        libID: uuid.v1(),
+        libName: `${userName}的块模板库`,
+        datas: template.datas,
+        share: template.share
+    };
+    newLib.share.shareName = `共享-${newLib.libName}`;
+    await blModel.create(newLib);
+    // console.log(JSON.stringify(newLib));
+    return newLib;
+};
+
+/*------------------------------------------------------------------------------
+参数:   {libID: n, nodeID: m, create: {node} | delete: true | update: {A:'xxx', B:'xxx'} }
+说明:   libID、nodeID 必须。 create|update|delete三选一。
+        create属性值:完整的node节点数据。
+        delete属性值:固定为true(false没有实际意义)。
+        update属性值:列出多个要修改的结点属性(键值对组成的对象)。
+示例:   {libID: 3, nodeID: 5, create: {....}}
+        {libID: 3, nodeID: 5, delete: true}
+        {libID: 3, nodeID: 5, update: {nodeName: 'xxx', children: [...]} }
+------------------------------------------------------------------------------*/
+async function saveBlock(data) {
+    if (data.create) {
+        await blModel.update({libID: data.libID}, {$addToSet: {datas: data.create}});
+    }
+    if (data.delete) {
+        console.log(JSON.stringify(data));
+        console.log(data.nodeID);
+        await blModel.update({libID: data.libID}, {$pull: {datas: {ID: data.nodeID}}});
+        if (data.delete.nodeType == 1){    // 同步删除所有子结点
+            await blModel.update({libID: data.libID}, {$pull: {datas: {ParentID: data.nodeID}}});
+        }
+    }
+    else if (data.update){
+        let doc = await blModel.findOne({libID: data.libID});
+        let datas = doc._doc.datas;
+        for (let i = 0; i < datas.length; i++) {
+            if (datas[i].ID == data.nodeID) {
+                for (let pn in data.update){
+                    datas[i][pn] = data.update[pn];
+                };
+                await doc.save();
+                break;
+            }
+        };
+    };
+    return 'saveBlock.OK';
+};

+ 122 - 0
modules/main/facade/material_replace_facade.js

@@ -0,0 +1,122 @@
+/**
+ * Created by zhang on 2018/9/12.
+ */
+let logger = require("../../../logs/log_helper").logger;
+let mongoose = require('mongoose');
+let material_lib = mongoose.model('std_material_replace_lib');
+let replace_bills = mongoose.model('std_replace_bills');
+let replace_material = mongoose.model('std_replace_material');
+let _=require("lodash");
+let ration_glj_facade = require('../../ration_glj/facade/ration_glj_facade');
+let glj_calculate_facade = require('../../ration_glj/facade/glj_calculate_facade');
+
+
+module.exports = {
+    findMaterial: async function(dataMap,compilationId){
+        let libMap = {},resultMap={};
+        for(let key in dataMap) {
+            let billsLibId = dataMap[key].billsLibId;
+            let libID = libMap[compilationId + billsLibId] ? libMap[compilationId + billsLibId] : await getLibID(billsLibId, compilationId);
+            libMap[compilationId + billsLibId] = libID;
+            if (libID == null) continue;
+            let bills = await getBills(key, libID);
+            if (bills == null) continue;
+            let materialList = await getMaterialByBillsID(bills.ID);
+            resultMap[key] = {bills:bills,materialMap:_.indexBy(materialList,'code')};
+        }
+        return resultMap;
+    },
+    replace:async function(datas){
+        let resultList = [];
+        let rationMap = _.groupBy(datas,function(item){//先按定额进行分组
+            return item.glj.rationID;
+        });
+        for(let rationID in rationMap){
+           let result = await eachRationGroup(rationID,rationMap[rationID]);
+           resultList.push(result);
+        }
+        return resultList
+    }
+};
+
+async function eachRationGroup(rationID,datas) {
+    let query={rationID:rationID},gljs=[];
+    for(let d of datas){
+         query["projectID"] = d.glj.projectID;
+         gljs.push(await updateRationGLJ(d));
+    }
+    if(query.projectID){
+        let stateResult = await glj_calculate_facade.calculateQuantity(query,null,true);
+        return {rationID:rationID,name:stateResult.rationName,adjustState:stateResult.adjustState,ration_gljs:gljs}
+    }else {
+        throw new Error("人材机的项目ID有问题");
+    }
+
+}
+
+async function updateRationGLJ(data) {
+    let glj = data.glj;
+    let priceInfo = {
+        base_price: glj.basePrice,
+        market_price: glj.marketPrice
+    };
+    let [projcetGLJ_n,doc] = await ration_glj_facade.updateRationGLJFromDoc(glj,data.doc,priceInfo);
+    return {ID:glj.ID,doc:doc}
+
+}
+
+/*async function doRationGLJUpdate(data) {
+    let resutl = {};
+    let doc = data.doc;
+    let priceInfo = data.priceInfo;
+    let rg = await ration_glj.findOne(data.query);
+    let gljListModel = new GLJListModel();
+    let projectGLJ = getGLJSearchInfo(rg);
+    for (let key in doc) {
+        projectGLJ[key] = doc[key]
+    }
+    projectGLJ.base_price = priceInfo.base_price;
+    projectGLJ.market_price = priceInfo.market_price;
+    let projcetGLJ_n = await gljListModel.modifyGLJ(projectGLJ, rg);
+    doc.code = projcetGLJ_n.code;
+    doc.projectGLJID = projcetGLJ_n.id;
+    if (projcetGLJ_n.unit_price.is_add == 1) {
+        doc.createType = 'replace';
+        doc.rcode = projcetGLJ_n.original_code;
+    } else {
+        doc.createType = 'normal';
+        doc.rcode = '';
+    }
+    await ration_glj.findOneAndUpdate(data.query, doc);
+    //取价格
+    gljListModel.getGLJPrice(projcetGLJ_n);
+    doc.basePrice = projcetGLJ_n.unit_price.base_price;
+    doc.marketPrice = projcetGLJ_n.unit_price.market_price;
+    doc.adjustPrice = projcetGLJ_n.adjust_price;
+    doc.isAdd = projcetGLJ_n.unit_price.is_add;
+    resutl.doc = doc;
+    let stateResult = await glj_calculate_facade.calculateQuantity({
+        projectID: data.query.projectID,
+        rationID: data.query.rationID
+    },null,true);
+    resutl.adjustState = stateResult.adjustState;
+    resutl.name = stateResult.rationName;
+    return resutl;
+}*/
+
+
+async function getLibID(billsLibId,compilationId) {
+    let lib = await material_lib.findOne({"compilationId":compilationId,billsLibId:billsLibId});
+    if(lib) return lib.ID;
+    return null;
+}
+
+async function getBills(code,libID) {
+    let bills = await replace_bills.findOne({code:code,libID:libID});
+    if(bills) return bills;
+    return null;
+}
+
+async  function getMaterialByBillsID(billsItemID) {
+    return await replace_material.find({billsItemID:billsItemID},['code','name','specs','type','unit']);
+}

+ 27 - 13
modules/main/facade/project_facade.js

@@ -11,6 +11,7 @@ let bill_model = require('../models/bills');
 let consts = require('../models/project_consts');
 let projectConsts = consts.projectConst;
 let ration_glj_model = mongoose.model('ration_glj');
+let rationTemplateModel = mongoose.model('ration_template');
 let project_glj_model = mongoose.model('glj_list');
 let ration_glj_facade = require("../../ration_glj/facade/ration_glj_facade");
 const uuidV1 = require('uuid/v1');
@@ -23,7 +24,8 @@ module.exports = {
     updateNodes:updateNodes,
     calcInstallationFee:calcInstallationFee,
     saveProperty: saveProperty,
-    getDefaultColSetting: getDefaultColSetting
+    getDefaultColSetting: getDefaultColSetting,
+    markProjectsToChange:markProjectsToChange
 };
 
 async function calcInstallationFee(data) {
@@ -98,7 +100,16 @@ function generateTasks(data,userID) {
     let deleteInfo={deleted: true, deleteDateTime: new Date(), deleteBy: userID};
     if(data.delete && data.delete.length > 0){
         for(let bd of data.delete){
-            let task={
+            //原先是假删除,现在改成真删除
+            let task = {
+                deleteOne:{
+                    filter:{
+                        ID:bd.ID,
+                        projectID:bd.projectID
+                    }
+                }
+            };
+           /* let task={
                 updateOne:{
                     filter:{
                         ID:bd.ID,
@@ -108,7 +119,7 @@ function generateTasks(data,userID) {
                         deleteInfo:deleteInfo
                     }
                 }
-            };
+            };*/
             tasks.push(task);
         }
     }
@@ -132,6 +143,7 @@ async function updateNodes(datas){
     let rationGLJTasks = [];
     let projectGLJTasks = [];
     let projectTasks = [];
+    let rationTemplateTasks = [];
     let asyncTasks = [];
     for(let type in nodeGroups){
         for(let node of nodeGroups[type]){
@@ -145,6 +157,8 @@ async function updateNodes(datas){
                 projectGLJTasks.push(getTask(node,'id'));
             }else if(type == projectConsts.PROJECT){
                 projectTasks.push(getTask(node));
+            }else if(type == projectConsts.RATION_TEMPLATE){
+                rationTemplateTasks.push(getTask(node))
             }
 
         }
@@ -154,6 +168,7 @@ async function updateNodes(datas){
     rationGLJTasks.length>0?asyncTasks.push(ration_glj_model.bulkWrite(rationGLJTasks)):"";
     projectGLJTasks.length>0?asyncTasks.push(project_glj_model.bulkWrite(projectGLJTasks)):"";
     projectTasks.length>0?asyncTasks.push(projectsModel.bulkWrite(projectTasks)):"";
+    rationTemplateTasks.length>0?asyncTasks.push(rationTemplateModel.bulkWrite(rationTemplateTasks)):"";
     return  asyncTasks.length>0?await Promise.all(asyncTasks):"";
 
     function getTask(node,idFiled = 'ID') {
@@ -200,25 +215,24 @@ async function updateNodes(datas){
 
 //data = {feeRateID:111111,projectID:1245}; type = feeRate
 async function markUpdateProject(data,type) {
-    let tasks=[];
     let query = {deleteInfo:null};
-    let result = null;
     if(type=="feeRate"){//更改了费率
         query['property.feeFile.id'] = data.feeRateID;
     }
     if(type=="unitFile"){//更改了单价文件
         query['property.unitPriceFile.id'] = data.unitFileID;//unitPriceFile
     }
-    let projects =await projectsModel.find(query);
+    let projects = await projectsModel.find(query);
+    return await markProjectsToChange(projects,type,data.projectID);
+}
+
+async function markProjectsToChange(projects,type,extProjectID){
+    let tasks=[];
     for(let p of projects){
-        if(p.ID!=data.projectID){//当前项目不用更新
-            tasks.push(generateMarkTask(type,p.ID));
-        }
-    }
-    if(tasks.length>0){
-        result = await projectsModel.bulkWrite(tasks);
+        if(extProjectID && p.ID===extProjectID) continue;//排除当前项目
+        tasks.push(generateMarkTask(type,p.ID));
     }
-    return result;
+    return tasks.length>0 ? await projectsModel.bulkWrite(tasks):null;
 }
 
 async function removeProjectMark(projectID) {

+ 301 - 69
modules/main/facade/ration_facade.js

@@ -5,6 +5,7 @@ let mongoose = require('mongoose');
 import SearchDao from '../../complementary_ration_lib/models/searchModel';
 const scMathUtil = require('../../../public/scMathUtil').getUtil();
 let ration_glj_facade = require("../../ration_glj/facade/ration_glj_facade");
+let glj_calculate_facade = require("../../ration_glj/facade/glj_calculate_facade");
 let quantity_detail = require("../facade/quantity_detail_facade");
 let ration_glj = mongoose.model('ration_glj');
 let ration_coe = mongoose.model('ration_coe');
@@ -13,26 +14,38 @@ let bill_model = require('../models/bills');
 let decimal_facade = require('./decimal_facade');
 let installationFeeModel = mongoose.model("installation_fee");
 let rationInstallationModel = mongoose.model('ration_installation');
+let rationTemplateModel = mongoose.model('ration_template');
 const uuidV1 = require('uuid/v1');
 let std_glj_lib_gljList_model = mongoose.model('std_glj_lib_gljList');
 let complementary_glj_model =  mongoose.model('complementary_glj_lib');
+let rationItemModel = mongoose.model("std_ration_lib_ration_items");
+let complementaryRationModel = mongoose.model('complementary_ration_items');
+
 let coeMolde = mongoose.model('std_ration_lib_coe_list');
+let compleCoeModel = mongoose.model('complementary_ration_coe_list');
+
 let _= require('lodash');
 const projectDao = require('../../pm/models/project_model').project;
 let projectModel = mongoose.model('projects');
+const fs = require('fs');
 
 module.exports = {
     replaceRations: replaceRations,
     addNewRation:addNewRation,
-    addMultiRation: addMultiRation
+    addMultiRation: addMultiRation,
+    getSameSectionRations:getSameSectionRations,
+    getExtendData:getExtendData,
+    getDefaultProgramID:getDefaultProgramID,
+    deleteSubListByQuery:deleteSubListByQuery,
+    updateCoeAdjust:updateCoeAdjust
 };
-async function addNewRation(data) {
+async function addNewRation(data,compilation) {
     let query = data.itemQuery;
     let stdRation = null;
     let startTime = +new Date();
     if(query){
         let searchDao = new SearchDao();
-        stdRation = await searchDao.getRationItem(query.userID,[query.rationRepId],query.code, query.ID);
+        stdRation = await searchDao.getRationItem(query.userID, compilation._id, [query.rationRepId],query.code, query.ID);
         //data.newData.code = query.code;
     }
     let stdRationTime = +new Date();
@@ -40,25 +53,51 @@ async function addNewRation(data) {
     if(data.brUpdate.length>0){
         await updateSerialNo(data.brUpdate);
     }
-    let newRation =await insertNewRation(data.newData,data.firstLibID,stdRation,data.calQuantity);
+    let newRation =await insertNewRation(data.newData,data.defaultLibID,stdRation,data.calQuantity);
     let addRationGLJTime = +new Date();
     console.log("插入新定额时间-------------------------------"+(addRationGLJTime - stdRationTime));
     if(stdRation){
-        return await addRationSubList(stdRation,newRation,data.needInstall);
+        return await addRationSubList(stdRation,newRation,data.needInstall,compilation);
     }else {
         return {ration:newRation};
     }
 }
 
-async function addMultiRation(datas) {
+async function addMultiRation(datas,compilation) {
     let rst = [];
     for(let data of datas){
-        let r = await addNewRation(data);
+        let r = await addNewRation(data,compilation);
         rst.push(r);
     }
     return rst;
 }
 
+async function getSameSectionRations(data,userId,compilationId){
+    //let userId
+    //要先根据定额获取所属章节的ID
+    let from = data.from;    //定额类型,是标准的还是用户定义的
+    let code = data.code;
+    let libID = data.libID;
+    let sectionId,rations=[];
+    if(from == 'std'){
+        let ration = await rationItemModel.findOne({rationRepId:libID,code:code},['sectionId']);
+        sectionId = ration? ration.sectionId:null;
+    }else {
+        let ration = await complementaryRationModel.findOne({userId:userId,compilationId: compilationId,code:code},['sectionId']);
+        sectionId = ration?ration.sectionId:null;
+    }
+    if(sectionId){
+        if (from == 'std') {
+            rations = await rationItemModel.find({sectionId: sectionId});
+        } else {
+            rations = await complementaryRationModel.find({userId: userId, sectionId: sectionId});
+        }
+        rations = _.sortBy(rations,'code');
+    }
+    return rations
+}
+
+
 async function  updateSerialNo(serialNoUpdate){
     let tasks=[];
     for(let data of serialNoUpdate){
@@ -76,10 +115,9 @@ async function  updateSerialNo(serialNoUpdate){
         tasks.push(task);
     }
     await ration_model.model.bulkWrite(tasks);
-
 }
 
-async function insertNewRation(newData,firstLibID,std,calQuantity) {//插入新的定额
+async function insertNewRation(newData,defaultLibID,std,calQuantity) {//插入新的定额
     let startTime = +new Date();
     if(std){
         newData.code = std.code;
@@ -87,6 +125,7 @@ async function insertNewRation(newData,firstLibID,std,calQuantity) {//插入新
         newData.caption = std.caption;
         newData.unit = std.unit;
         newData.libID = std.rationRepId;
+        newData.stdID = std.ID;
         newData.content = std.jobContent;
         newData.annotation = std.annotation;
         if (std.chapter) {
@@ -95,13 +134,17 @@ async function insertNewRation(newData,firstLibID,std,calQuantity) {//插入新
         }
         newData.prefix = '';
         newData.from = std.type === 'complementary' ? 'cpt' : 'std';
-        if(firstLibID !== std.rationRepId){//借
+        if(defaultLibID !== std.rationRepId){//借
             newData.prefix = '借';
         }
-        else if(std.rationRepId === firstLibID && newData.from === 'cpt') {
+        else if(std.rationRepId === defaultLibID && newData.from === 'cpt') {
             newData.prefix = '补';
         }
-        newData.programID = std.feeType;
+        if(std.feeType == undefined || std.feeType == null || std.feeType ==''){//定额取费专业为空的情况下,取项目属性中的定额取费专业ID
+            newData.programID = await getProgramForProject(newData.projectID);
+        }else {
+            newData.programID = std.feeType;
+        }
         newData.rationAssList =  createRationAss(std);
         // calculate ration Quantity
     }
@@ -110,19 +153,18 @@ async function insertNewRation(newData,firstLibID,std,calQuantity) {//插入新
     }
     let addRationGLJTime = +new Date();
     console.log("计算消耗量时间-------------------------------"+(addRationGLJTime - startTime));
-    console.log(newData);
     let newRation = await ration_model.model.create(newData);
     return newRation;
     /*ration_model.model.create(newData);
     return newData;*/
 }
 
-async function replaceRations(userID,data) {
+async function replaceRations(userID,data,compilation) {
     let searchDao = new SearchDao();
     let recodes = [];
     for(let recode of data.nodeInfo){
-        let stdRation = await searchDao.getRationItem(userID,data.libIDs,recode.newCode, null);
-        let newRecode = await replaceRation(recode,stdRation,data.firstLibID,data.projectID,data.calQuantity);
+        let stdRation = await searchDao.getRationItem(userID,compilation._id,data.libIDs,recode.newCode, null);
+        let newRecode = await replaceRation(recode,stdRation,data.defaultLibID,data.projectID,data.calQuantity,compilation);
         if(newRecode){
             recodes.push(newRecode);
         }else {
@@ -132,37 +174,55 @@ async function replaceRations(userID,data) {
     return recodes;
 }
 
-async function replaceRation(nodeInfo,stdRation,firstLibID,projectID,calQuantity) {
-    if(stdRation){
-        await deleRationSubRecode(projectID,nodeInfo.ID);
-        let newRation = await updateRation(stdRation,firstLibID,nodeInfo.ID,nodeInfo.billsItemID,projectID,calQuantity);//生成并插入新的定额
-        return await addRationSubList(stdRation,newRation,nodeInfo.needInstall);
+async function getDefaultProgramID(data) {
+    let searchDao = new SearchDao();
+    let programID;
+    let std = await searchDao.getRationItem(data.userID,data.compilationId,[data.libID],data.code, null);
+    if(std == null||std ==undefined || std.feeType == undefined || std.feeType == null || std.feeType ==''){//定额取费专业为空的情况下,取项目属性中的定额取费专业ID
+        programID = await getProgramForProject(data.projectID);
+    }else {
+        programID = std.feeType;
+    }
+    return programID;
+}
+
+async function replaceRation(nodeInfo,stdRation,defaultLibID,projectID,calQuantity,compilation) {
+    if(nodeInfo.newCode == null||nodeInfo.newCode ==""){//说明是删除编号,则要变成一条空定额
+        await deleRationSubRecode(projectID,nodeInfo.ID);//删除定额下挂的各种数据,如定额工料机等
+        return await setEmptyRation(projectID,nodeInfo.ID);
+    }else if(stdRation){
+        await deleRationSubRecode(projectID,nodeInfo.ID);//删除定额下挂的各种数据,如定额工料机等
+        let newRation = await updateRation(stdRation,defaultLibID,nodeInfo.ID,nodeInfo.billsItemID,projectID,calQuantity);//生成并插入新的定额
+        return await addRationSubList(stdRation,newRation,nodeInfo.needInstall,compilation);
     }else {
         return null;
     }
 }
 
-async function addRationSubList(stdRation,newRation,needInstall) {
+async function addRationSubList(stdRation,newRation,needInstall,compilation) {
     let startTime = +new Date();
-    let ration_gljs = await addRationGLJ(stdRation,newRation);
+    let ration_gljs = await addRationGLJ(stdRation,newRation,compilation);
     let addRationGLJTime = +new Date();
     console.log("添加定额工料机时间-----"+(addRationGLJTime - startTime));
-    let ration_coes = await addRationCoe(stdRation,newRation);
+    let ration_coes = await addRationCoe(stdRation,newRation,compilation);
     let addRationCoeTime = +new Date();
     console.log("添加定额coe时间-----"+(addRationCoeTime - addRationGLJTime));
-    let ration_installs = [];
-    if(needInstall){
-        ration_installs =  await addRationInstallFee(stdRation,newRation);
+    let ration_installations = [];
+    if(needInstall && stdRation.type == 'std'){//只有标准的定额才有安装增加费,补充的定额没有安装增加费
+        ration_installations =  await addRationInstallFee(stdRation,newRation);
     }
     let addRationInstallFeeTime = +new Date();
     console.log("添加定额install时间-----"+(addRationInstallFeeTime - addRationCoeTime));
-    return {ration:newRation,ration_gljs:ration_gljs,ration_coes:ration_coes,ration_installs:ration_installs};
+    //添加定额模板子目
+    let ration_template = await addRationTemplate(stdRation,newRation);
+    return {ration:newRation,ration_gljs:ration_gljs,ration_coes:ration_coes,ration_installations:ration_installations,ration_templates:ration_template?[ration_template]:[]};
 }
 
 async function addRationInstallFee(std,newRation) {
     let install_fee_list = [];
     if(std.hasOwnProperty('rationInstList') && std.rationInstList.length > 0){
         let installFee = await installationFeeModel.findOne({'projectID': newRation.projectID});
+        if(!installFee) return;//如果没有找到项目对应的安装增加费,则不添加
         for(let ri of std.rationInstList){
             let feeItem = _.find(installFee.installFeeItem,{'ID':ri.feeItemId});
             let section = _.find(installFee.installSection,{'ID':ri.sectionId});
@@ -197,12 +257,53 @@ async function addRationInstallFee(std,newRation) {
     return install_fee_list;
 }
 
-async function addRationCoe(std,newRation) {
+async function addRationTemplate(std,newRation) {
+    let templateList = [];
+    if(std.hasOwnProperty('rationTemplateList') && std.rationTemplateList.length > 0){
+        for(let tem of std.rationTemplateList){
+            let re_ration = await rationItemModel.findOne({rationRepId:std.rationRepId,ID:tem.rationID});
+            if(re_ration){
+                let template = {
+                    billID:"",
+                    fxID:"",
+                    quantity:"0",
+                    coe:"0"
+                };
+                template.code = re_ration.code;
+                template.name = re_ration.name;
+                template.type = tem.type;
+                template.unit = re_ration.unit;
+                template.billsLocation = tem.billsLocation;
+                template.defaultLocation = tem.billsLocation;
+                templateList.push(template)
+            }
+        }
+    }
+    if(templateList.length > 0){
+        let ration_template = {};
+        ration_template.ID = uuidV1();
+        ration_template.projectID = newRation.projectID;
+        ration_template.rationID = newRation.ID;
+        ration_template.createLocation = 1; //默认模板子目分别放在措施项目下
+        ration_template.templateList = templateList;
+        await  rationTemplateModel.create(ration_template);
+        return ration_template;
+    }
+    return null;
+}
+
+
+async function addRationCoe(std,newRation,compilation) {
     let ration_coe_list = [];
     let seq = 0;
     if(std.hasOwnProperty('rationCoeList')&&std.rationCoeList.length>0){//添加标准库的工料机
         for(let sub of std.rationCoeList){
-            let libCoe = await coeMolde.findOne({'libID':std.rationRepId,'ID':sub.ID,"$or": [{"isDeleted": null}, {"isDeleted": false}]});//std.rationRepId;
+            let libCoe;
+            if (std.type === 'std') {
+                libCoe = await coeMolde.findOne({'libID':std.rationRepId,'ID':sub.ID,"$or": [{"isDeleted": null}, {"isDeleted": false}]});//std.rationRepId;
+            } else {
+                libCoe = await compleCoeModel.findOne({ID: sub.ID, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]});
+            }
             if(libCoe){
                 let newCoe = {};
                 newCoe.ID = uuidV1();
@@ -210,6 +311,9 @@ async function addRationCoe(std,newRation) {
                 newCoe.seq = seq;
                 newCoe.name = libCoe.name;
                 newCoe.content = libCoe.content;
+                newCoe.original_code = libCoe.original_code;
+                newCoe.option_codes = libCoe.option_codes;
+                newCoe.option_list = libCoe.option_list;
                 newCoe.isAdjust=0;
                 newCoe.coes = libCoe.coes;
                 newCoe.rationID = newRation.ID;
@@ -219,39 +323,71 @@ async function addRationCoe(std,newRation) {
             }
         }
     }
+    let lastCoe = await getCustomerCoe(newRation.projectID,newRation.ID,seq,compilation);
+    ration_coe_list.push(lastCoe);
+    await ration_coe.insertMany(ration_coe_list);
+    return ration_coe_list;
+
+}
+
+function getCustomerCoeData() {
+    var coeList = [
+         {amount:1, operator:'*', gljCode:null, coeType:'定额'},
+        { amount:1, operator:'*', gljCode:null, coeType:'人工'},
+        { amount:1, operator:'*', gljCode:null, coeType:'材料'},
+        { amount:1, operator:'*', gljCode:null, coeType:'机械'},
+        { amount:1, operator:'*', gljCode:null, coeType:'主材'},
+        { amount:1, operator:'*', gljCode:null, coeType:'设备'}
+    ];
+    return coeList;
+};
+
+
+async function getCustomerCoe(projectID,rationID,seq,compilation){//取自定义乘系数,根据编办不同,内容可能不同
+    //生成默认的自定义乘系数
     let lastCoe ={
         coeID:-1,
         name : '自定义系数',
         content:'人工×1,材料×1,机械×1,主材×1,设备×1',
-        isAdjust:0,
+        isAdjust:1,
         seq:seq,
-        rationID : newRation.ID,
-        projectID : newRation.projectID
+        rationID : rationID,
+        projectID : projectID
     };
     lastCoe.ID = uuidV1();
     lastCoe.coes = getCustomerCoeData();
-    ration_coe_list.push(lastCoe);
-    await ration_coe.insertMany(ration_coe_list);
-    return ration_coe_list;
+    try {
+    //查看编办中有没有重写路径
+     if(compilation.overWriteUrl && compilation.overWriteUrl!=""){
+         let overWrite = require("../../.."+compilation.overWriteUrl);
+         if(overWrite.getCusCoeContent) lastCoe.content = overWrite.getCusCoeContent();
+         if(overWrite.getCustomerCoeData) lastCoe.coes = overWrite.getCustomerCoeData();
+     }
+     return lastCoe
+   }catch (err){
+       console.log("读取自定义系数重写文件失败");
+       console.log(err.message);
+       return lastCoe
+   }
+}
 
+//对于多单价,多组成物消耗量的编办,通过这个方法获取单价、组成物消耗量的字段,
+function getExtendData(property,compilation) {
+    return projectDao.getExtendData(property,compilation);
 }
 
-function getCustomerCoeData() {
-    var coeList = [];
-    coeList.push({ amount:1, operator:'*', gljCode:null, coeType:'定额'});
-    coeList.push({ amount:1, operator:'*', gljCode:null, coeType:'人工'});
-    coeList.push({ amount:1, operator:'*', gljCode:null, coeType:'材料'});
-    coeList.push({ amount:1, operator:'*', gljCode:null, coeType:'机械'});
-    coeList.push({ amount:1, operator:'*', gljCode:null, coeType:'主材'});
-    coeList.push({ amount:1, operator:'*', gljCode:null, coeType:'设备'});
-    return coeList;
-};
 
-async function addRationGLJ(std,newRation) {
+
+
+async function addRationGLJ(std,newRation,compilation) {
     let newRationGLJList = [];
     let rationGLJShowList = [];
-    let unitPriceFileId = await projectDao.getUnitPriceFileId(newRation.projectID);
-    let sum=0;
+    let unitPriceFileId = 0;
+    let property = await projectDao.getProjectProperty(newRation.projectID);
+    if(property){
+        unitPriceFileId = property.unitPriceFile !== undefined ? property.unitPriceFile.id : 0;
+    }
+    let ext = getExtendData(property,compilation);
     let first = +new Date();
     if(std.hasOwnProperty('rationGljList') && std.rationGljList.length > 0){
         let stdGLJID =[];//标准工料机ID数组
@@ -281,20 +417,24 @@ async function addRationGLJ(std,newRation) {
             newGLJ.quantity = sub.consumeAmt;
             newGLJ.glj_repository_id = std.rationRepId;
             let std_glj = null;
-           if(sub.type == 'complementary'){//有可能来自标准工料机库或补充工料机库
+            if(sub.type == 'complementary'){//有可能来自标准工料机库或补充工料机库
                 std_glj = cptGLJMap[sub.gljId];
                 newGLJ.from = 'cpt';
             }else {
-               std_glj = stdGLJMap[sub.gljId];
-               newGLJ.from = 'std';
-           }
-            let std_gljTime = +new Date();
+                std_glj = stdGLJMap[sub.gljId];
+                newGLJ.from = 'std';
+                //多单价情况处理
+                if(ext && ext.priceField && std_glj && std_glj.priceProperty){
+                    std_glj.basePrice =  std_glj.priceProperty[ext.priceField];
+                }
+            }
             if(std_glj){
                 newGLJ.name = std_glj.name;
                 newGLJ.code = std_glj.code;
                 newGLJ.original_code = std_glj.code;
                 newGLJ.unit = std_glj.unit;
                 newGLJ.specs = std_glj.specs;
+                newGLJ.model = std_glj.model;
                 newGLJ.basePrice = std_glj.basePrice;
                 newGLJ.marketPrice = std_glj.basePrice;
                 newGLJ.shortName = std_glj.shortName;
@@ -304,13 +444,13 @@ async function addRationGLJ(std,newRation) {
                 newGLJ.materialType = std_glj.materialType;
                 newGLJ.materialCoe = std_glj.materialCoe;
                 newGLJ.createType = 'normal';
-                let info = await  ration_glj_facade.getInfoFromProjectGLJ(newGLJ,unitPriceFileId);
+                let info =  await ration_glj_facade.getInfoFromProjectGLJ(newGLJ,unitPriceFileId,ext);
                 newGLJ = ration_glj_facade.createNewRecord(info);
                 newRationGLJList.push(newGLJ);
                 rationGLJShowList.push(info);
             }
-            let InfoFromProjectGLJ = +new Date();
-            console.log("找到项目工料机时间-------------------------------"+(InfoFromProjectGLJ - std_gljTime));
+            //let InfoFromProjectGLJ = +new Date();
+            //console.log("找到项目工料机时间-------------------------------"+(InfoFromProjectGLJ - std_gljTime));
         }
     }
     let before = +new Date();
@@ -327,20 +467,62 @@ async function addRationGLJ(std,newRation) {
 async function deleRationSubRecode(projectID,rationID) {//删除挂在定额下的数据,如工程量明细,定额工料机等
     let delete_query={projectID: projectID, rationID: rationID};
     //删除工程量明细
-    await quantity_detail.deleteByQuery(delete_query) ;
+    await deleteSubListByQuery(delete_query) ;
+}
+
+async function deleteSubListByQuery(delete_query) {
+    await quantity_detail.deleteByQuery(delete_query) ;//删除工程量明细
     await ration_coe.deleteMany(delete_query);//删除附注条件
     await ration_glj.deleteMany(delete_query);//删除定额工料机
     await rationInstallationModel.deleteMany(delete_query);//删除安装增加费
+    await rationTemplateModel.deleteMany(delete_query);//删除模板关联子目
+}
+
+async function updateCoeAdjust(data,compilation) {
+    let replace = [];
+    await ration_coe.update({ID:data.ID},data.doc);
+    //添加单个工料机的情况
+    if (data.add.length > 0)   await ration_glj_facade.insertAddTypeGLJ(data.add,compilation);
+    if(data.delete.length > 0) await ration_glj_facade.deleteGLJ(data.delete);
+
+    //替换工料机的情况
+    if (data.replace.length > 0){
+        for(let r of data.replace){
+            replace.push(await  ration_glj_facade.replaceGLJByData(r,compilation)) ;
+        }
+    }
+
+    let cal_result = await glj_calculate_facade.calculateQuantity({projectID:data.projectID,rationID:data.rationID},null,true);
+    let coe = {
+        query:{ID:data.ID,projectID:data.projectID},
+        doc:data.doc
+    };
+    let ration_glj ={
+        quantityRefresh:true,
+        glj_result:cal_result.glj_result
+    };
+    let ration = {
+        ID:cal_result.rationID,
+        adjustState:cal_result.adjustState,
+        name:cal_result.rationName
+    };
+    return {coe:coe,ration_glj:ration_glj,ration:ration,add:data.add,delete:data.delete,replace:replace}
+
 }
 
-async function  updateRation(std,firstLibID,rationID,billsItemID,projectID,calQuantity) {
+
+
+async function  updateRation(std,defaultLibID,rationID,billsItemID,projectID,calQuantity) {
     // insertNewRation
     let ration ={};
     ration.code = std.code;
     ration.name = std.name;
     ration.caption = std.caption;
     ration.unit = std.unit;
-    ration.libID = std.rationRepId;
+    if (std.type === 'std') {
+        ration.libID = std.rationRepId;
+        ration.stdID = std.ID;
+    }
     ration.content = std.jobContent;
     ration.adjustState = '';
     ration.isFromDetail=0;
@@ -354,33 +536,73 @@ async function  updateRation(std,firstLibID,rationID,billsItemID,projectID,calQu
     //定额前缀 none:0, complementary:1, borrow: 2
     ration.prefix = '';
     //借用优先级比补充高
-    if(std.rationRepId !== parseInt(firstLibID)){//借用
+    if(std.rationRepId !== parseInt(defaultLibID)){//借用
         ration.prefix = '借';
     }
-    else if(std.rationRepId === firstLibID && ration.from === 'cpt') {
+    else if(std.rationRepId === defaultLibID && ration.from === 'cpt') {
         ration.prefix = '补';
     }
-    ration.programID = std.feeType;
+    if(std.feeType == undefined || std.feeType == null || std.feeType ==''){//定额取费专业为空的情况下,取项目属性中的定额取费专业ID
+        ration.programID = await getProgramForProject(projectID);
+    }else {
+        ration.programID = std.feeType;
+    }
     ration.rationAssList = createRationAss(std);//生成辅助定额
     if(calQuantity){
        await CalculateQuantity(ration,billsItemID,projectID);
     }
 
- let unsetObject = {
-     "marketUnitFee":1,
-     'marketTotalFee':1,
-     "maskName":1
- }
+     let unsetObject = {
+         "marketUnitFee":1,
+         'marketTotalFee':1,
+         "maskName":1
+     }
     let newRation = await ration_model.model.findOneAndUpdate({ID:rationID,projectID:projectID},{"$set":ration,"$unset":unsetObject},{new: true});//;
     return newRation;
 }
 
+async function setEmptyRation(projectID,rationID){
+    let ration ={};
+    ration.code = "";
+    ration.name = "";
+    ration.caption = "";
+    ration.unit = "";
+    ration.libID = null;
+    ration.content = "";
+    ration.adjustState = '';
+    ration.isFromDetail=0;
+    ration.isSubcontract=false;
+    ration.fees=[];
+    ration.comments = "";
+    ration.ruleText = "";
+    ration.quantity="";
+    ration.contain="";
+    ration.quantityEXP="";
+    ration.from = 'std';
+    //定额前缀 none:0, complementary:1, borrow: 2
+    ration.prefix = '';
+    ration.rationAssList = [];
+    ration.marketUnitFee ="";
+    ration.marketTotalFee ="";
+    ration.maskName = "";
+    ration.targetTotalFee ='';
+    ration.targetUnitFee = "";
+    ration.deleteInfo = null;
+    ration.quantityCoe = {};
+    ration.rationQuantityCoe="";
+    ration.tenderQuantity = "";
+    ration.programID = null;
+    let newRation = await ration_model.model.findOneAndUpdate({ID:rationID,projectID:projectID},{"$set":ration},{new: true});//;
+    return {ration:newRation,ration_gljs:[],ration_coes:[],ration_installs:[]};
+}
+
 function createRationAss(std) {
     let  rationAssList = [];//生成辅助定额
     if(std.hasOwnProperty('rationAssList')&&std.rationAssList.length>0){
         for(let i=0;i<std.rationAssList.length;i++){
             let ass = std.rationAssList[i];
-            ass.actualValue = ass.stdValue;
+            ass._doc.actualValue = ass.stdValue;
+            if(_.isString(ass._doc.assistCode)) ass._doc.assistCode = ass._doc.assistCode.replace("\n","");
             rationAssList.push(ass);
         }
     }
@@ -393,6 +615,10 @@ async function CalculateQuantity (ration,billsItemID,projectID) {
     let decimalObject =await decimal_facade.getProjectDecimal(projectID,project);
     let quantity_decimal = (decimalObject&&decimalObject.ration&&decimalObject.ration.quantity)?decimalObject.ration.quantity:3;
     let pbill = await bill_model.model.findOne({projectID:projectID,ID:billsItemID});
+    let  t_unit = ration.unit?ration.unit.replace(/^\d+/,""):"";
+    if(t_unit!=pbill.unit){//如果定额工程量的单位去除前面的数字后不等于清单单位,定额工程量保持不变
+        return ;
+    }
     let billsQuantity = pbill.quantity ? pbill.quantity : 0;
     let bill_decimal = await decimal_facade.getBillsQuantityDecimal(projectID,pbill.unit,project);
     billsQuantity=scMathUtil.roundForObj(billsQuantity,bill_decimal);
@@ -401,6 +627,12 @@ async function CalculateQuantity (ration,billsItemID,projectID) {
     ration.contain =  scMathUtil.roundForObj(ration.quantity/billsQuantity,6);
 };
 
+
+async function getProgramForProject(projectID){
+    let project = await projectModel.findOne({ID:projectID});
+    return project.property.engineering;
+}
+
 function FilterNumberFromUnit (unit) {
     let reg = new RegExp('^[0-9]+');
     if (reg.test(unit)) {

+ 21 - 0
modules/main/facade/ration_template_facade.js

@@ -0,0 +1,21 @@
+/**
+ * Created by zhang on 2018/11/26.
+ */
+
+let mongoose = require('mongoose');
+let rationTemplateModel = mongoose.model('ration_template');
+let consts = require('../models/project_consts');
+
+module.exports={
+    getData:getData,
+};
+
+function getData(projectID, callback) {
+    rationTemplateModel.find({'projectID': projectID}, (err, datas) => {
+        if (err) {
+            callback(1, '', null);
+        } else {
+            callback(0, consts.projectConst.RATION_TEMPLATE, datas);
+        }
+    })
+}

+ 11 - 3
modules/main/models/bills.js

@@ -71,7 +71,8 @@ class billsModel extends baseModel {
                         break;
                     case commonConsts.UT_DELETE:
                         doc.updateData.deleteInfo = {deleted: true, deleteDateTime: new Date(), deleteBy: user_id};
-                        bills.update({projectID: doc.updateData.projectID, ID: doc.updateData.ID}, doc.updateData, cb);
+                       //bills.update({projectID: doc.updateData.projectID, ID: doc.updateData.ID}, doc.updateData, cb);
+                        bills.deleteOne({projectID: doc.updateData.projectID, ID: doc.updateData.ID},cb);
                         break;
                 }
             }
@@ -118,6 +119,13 @@ class billsModel extends baseModel {
            }
        });
     };
+    async updateBills(updateDatas){
+        let bulk = [];
+        for(let updateData of updateDatas){
+            bulk.push({updateOne: {filter: updateData.findSet, update: {$set: updateData.updateData}}});
+        }
+        await bills.bulkWrite(bulk);
+    };
     async updateBill(findSet, updateData) {
         let update = {};
         if (!updateData instanceof Array) {
@@ -174,13 +182,13 @@ class billsModel extends baseModel {
         let deleteInfo = {deleted: true, deleteDateTime: new Date(), deleteBy: userID};
         if(bill_ids.length > 0){
             //删除bills
-            await me.model.updateMany({ID: {$in: bill_ids}, deleteInfo: null}, {$set: {deleteInfo: deleteInfo}});
+            await me.model.deleteMany({ID: {$in: bill_ids}});
             //删除bill-quantity_detail
             await quantityDelModel.deleteMany({billID: {$in: bill_ids}});
         }
         if(ration_ids.length > 0){
             //删除rations
-            await rationModel.updateMany({ID: {$in: ration_ids}, deleteInfo: null}, {$set: {deleteInfo: deleteInfo}});
+            await rationModel.deleteMany({ID: {$in: ration_ids}});
             //删除ration-glj
             await rationGljModel.deleteMany({rationID: {$in: ration_ids}});
             //删除ration-coe

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

@@ -7,6 +7,7 @@ var ration_glj_data = require('../../ration_glj/facade/ration_glj_facade');
 var ration_coe_data = require('../../ration_glj/facade/ration_coe_facade');
 var ration_ass_data = require('../../ration_glj/facade/ration_ass_facade');
 let ration_installation = require('../facade/ration_installation_facade');
+let ration_template = require('../facade/ration_template_facade');
 var quantity_detail_data = require('../facade/quantity_detail_facade');
 var fee_rate_data = require('../../fee_rates/facade/fee_rates_facade');
 let projCounter = require('./proj_counter_model');
@@ -29,7 +30,6 @@ var moduleMap = {};
 
 moduleMap[projectConsts.BILLS] = billsData;
 moduleMap[projectConsts.RATION] = rationData;
-//moduleMap[projectConsts.GLJ] = GLJData;
 moduleMap[projectConsts.RATION_GLJ] = ration_glj_data;
 moduleMap[projectConsts.RATION_COE] = ration_coe_data;
 moduleMap[projectConsts.RATION_ASS] = ration_ass_data;
@@ -37,12 +37,12 @@ moduleMap[projectConsts.RATION_INSTALLATION] = ration_installation;
 moduleMap[projectConsts.QUANTITY_DETAIL] = quantity_detail_data;
 moduleMap[projCounter.collectionName] = projCounter;
 moduleMap[projSetting.collectionName] = projSetting;
-// moduleMap[volumePriceData.collectionName] = volumePriceData;
 moduleMap[projectConsts.FEERATE] = fee_rate_data;
 moduleMap[projectConsts.LABOUR_COE] = labour_coe_facade;
 moduleMap[projectConsts.CALC_PROGRAM] = calc_program_facade;
 moduleMap[projectConsts.PROJECTGLJ] = new GLJController();
 moduleMap[projectConsts.INSTALLATION_FEE] = installation_facade;
+moduleMap[projectConsts.RATION_TEMPLATE] = ration_template;
 
 var Project = function (){};
 
@@ -86,8 +86,8 @@ Project.prototype.save = function(datas, callback){
     asyncTool.parallel(functions, function(err, results) {
         if (!err){
             callback(null, '', results)
-        }
-        else{
+        } else{
+            console.log(err);
             callback(1, 'save project failed', null)
         }
     });

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

@@ -10,6 +10,7 @@ let projectConst = {
     RATION_COE:'ration_coe',
     RATION_ASS:'ration_ass',
     RATION_INSTALLATION:'ration_installation',
+    RATION_TEMPLATE:'ration_template',
     QUANTITY_DETAIL:'quantity_detail',
     PROJECTGLJ: 'projectGLJ',
     GLJLIST: 'GLJList',
@@ -40,6 +41,13 @@ let projectConstList = [
     'calc_program'
 ];
 
+let summaryConstList = [
+    `Construct`,
+    `ConstructDetail`,
+    `Segment`,
+    `SegmentDetail`
+];
+
 let commonConst = {
     UT_UPDATE: 'ut_update',
     UT_CREATE: 'ut_create',
@@ -54,4 +62,4 @@ const rationType = {
     gljRation: 3,
     install:4
 };
-module.exports = {projectConst: projectConst, commonConst: commonConst, projectConstList: projectConstList,gljKeyArray:gljKeyArray,rationKeyArray:rationKeyArray,rationType:rationType};
+module.exports = {projectConst: projectConst, commonConst: commonConst, projectConstList: projectConstList,gljKeyArray:gljKeyArray,rationKeyArray:rationKeyArray,rationType:rationType, summaryConstList: summaryConstList};

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

@@ -11,6 +11,7 @@ module.exports = function (app) {
     billsRouter.post('/allocIDs', billsController.allocIDs);
     billsRouter.post('/updateCharacterContent', billsController.updateCharacterContent);//特征及内容更新 zhong 2017-9-1
     // 批量更新bill数据
+    billsRouter.post('/updateBills', billsController.updateBills);
     billsRouter.post('/updateBill', billsController.updateBill);
     //删除单个清单,不删除子项
     billsRouter.post('/singleDelete',billsController.singleDelete);
@@ -18,7 +19,7 @@ module.exports = function (app) {
     billsRouter.post('/getSectionInfo', billsController.getSectionInfo);
     billsRouter.post('/reorganizeFBFX', billsController.reorganizeFBFX);
     billsRouter.post('/pasteBlock', billsController.pasteBlock);
-    billsRouter.post('/upload', billsController.upload);
+    billsRouter.post('/import', billsController.import);
     billsRouter.get('/downloadExamp', billsController.downloadExample);
     app.use('/bills', billsRouter);
 };

+ 19 - 0
modules/main/routes/block_lib_route.js

@@ -0,0 +1,19 @@
+/**
+ * Created by CSL on 2018-12-14.
+ */
+
+let express = require('express');
+let blController = require('../controllers/block_lib_controller');
+
+module.exports = function (app) {
+    let blRouter = express.Router();
+    let funcNames = ['getLibNames', 'getLib', 'getLibNamesAndFirstLib', 'saveBlock'];
+    for (let name of funcNames) {
+        blRouter.post(`/${name}`, blController.doController);
+    }
+    app.use('/blockLib', blRouter);
+}
+
+
+
+

+ 12 - 9
modules/main/routes/main_route.js

@@ -11,25 +11,28 @@ module.exports =function (app) {
     app.get('/main', baseController.init, function(req, res) {
         let pm = require('../../pm/controllers/pm_controller');
 
-        pm.checkProjectRight(req.session.sessionUser.id, req.query.project, async function (hasRight) {
+        pm.checkProjectRight(req.session.sessionUser.id, req.query.project, async function (hasRight, projectData, shareInfo) {
             if (hasRight) {
-                // 获取项目信息
-                const projectId = req.query.project;
-                const projectData = await projectModel.project.getProject(projectId);
-                //分享的项目,只读
-                let projectReadOnly = false;
+                //分享的项目,只读、协作(允许编辑)
+                let projectReadOnly = false,
+                    projectCooperate = false;
                 if(req.session.sessionUser.id !== projectData.userID){
                     projectData._doc.readOnly = true;
-                    projectReadOnly = true;
+                    projectCooperate = !!shareInfo.allowCooperate;
+                    //允许协作的项目允许编辑,非只读
+                    projectReadOnly = !projectCooperate;
                 }
                 res.render('building_saas/main/html/main.html',
                     {
                         userAccount: req.session.userAccount,
                         userID: req.session.sessionUser.id,
                         projectData: projectData,
-                        versionName: req.session.sessionCompilation.name + '免费版',
+                        compilationName: req.session.sessionCompilation.name,
+                        versionName: `纵横建筑云计价(${req.session.compilationVersion})`,
                         projectReadOnly: projectReadOnly,
-                        LicenseKey:config.getLicenseKey(process.env.NODE_ENV)
+                        projectCooperate: projectCooperate,
+                        LicenseKey:config.getLicenseKey(process.env.NODE_ENV),
+                        overWriteUrl:req.session.sessionCompilation.overWriteUrl
                     });
             } else {
                 res.redirect('/pm');

+ 16 - 0
modules/main/routes/material_replace_route.js

@@ -0,0 +1,16 @@
+/**
+ * Created by zhang on 2018/9/12.
+ */
+
+let express = require('express');
+let materialController = require('../controllers/material_replace_controller');
+
+module.exports = function (app) {
+
+    var materialRouter = express.Router();
+
+    materialRouter.post('/getMaterial', materialController.action);
+    materialRouter.post('/replace', materialController.action);//材料替换,其实是材料修改
+
+    app.use('/material',materialRouter);
+}

+ 9 - 5
modules/main/routes/ration_route.js

@@ -9,10 +9,14 @@ module.exports = function (app) {
     rationRouter.post('/getData', rationController.getData);
     rationRouter.post('/getItemTemplate', rationController.getItemTemplate);
     rationRouter.post('/allocIDs', rationController.allocIDs);
-    rationRouter.post('/insertGLJAsRation', rationController.insertGLJAsRation);
-    rationRouter.post('/replaceRations', rationController.replaceRations);
-    rationRouter.post('/addNewRation', rationController.addNewRation);
-    rationRouter.post('/addMultiRation', rationController.addMultiRation);
-
+    rationRouter.post('/insertGLJAsRation', rationController.action);
+    rationRouter.post('/replaceRations', rationController.action);
+    rationRouter.post('/addNewRation', rationController.action);
+    rationRouter.post('/addMultiRation', rationController.action);
+    rationRouter.post('/getSameSectionRations', rationController.action);
+    rationRouter.post('/getDefaultProgramID', rationController.action);
+    rationRouter.post('/applyTemplate', rationController.action);
+    rationRouter.post('/updateRationAss', rationController.action);
+    rationRouter.post('/updateCoeAdjust', rationController.action);
     app.use('/ration', rationRouter);
 };

+ 7 - 6
modules/options/models/optionTypes.js

@@ -15,11 +15,11 @@ const optionSetting = {
         DEFAULT: {
             backColor: 'White',
             foreColor: 'Black',
-            stringFont: '15px Arial',
-            numFont: '13px Arial'
+            stringFont: '0.9rem Arial',
+            numFont: '0.9rem Arial'
         },
         SELECTED: {
-            backColor: '#dddddd',
+            backColor: '#FFFACD',
             foreColor: 'default',
             stringFont: 'default',
             numFont: 'default'
@@ -27,8 +27,8 @@ const optionSetting = {
         DXFY: {
             backColor: 'default',
             foreColor: 'default',
-            stringFont: 'bold 15px Arial',
-            numFont: 'bold 13px Arial'
+            stringFont: 'bold 0.9rem Arial',
+            numFont: 'bold 0.9rem Arial'
         },
         FB: {
             backColor: '#C4CAFB',
@@ -60,8 +60,9 @@ const optionSetting = {
             stringFont: 'default',
             numFont: 'default'
         },
+        //含有计算基数的节点
         CBBILL: {
-            backColor: '#E5F3F2',
+            backColor: '#DFE8F9',
             foreColor: 'default',
             stringFont: 'default',
             numFont: 'default'

+ 0 - 34
modules/options/models/optionsModel.js

@@ -28,38 +28,4 @@ class OptionsDao {
     }
 }
 
-
-
-
-/*class OptionsDao {
-    async getOptions(user_id, compilation_id){
-        let rst = await optionsModel.find({user_id: user_id, compilation_id: compilation_id});
-        rst = rst.length > 0 && typeof rst[0].options !== 'undefined' ? rst[0].options : null;
-        return rst;
-    }
-
-    async getOptionsByType(user_id, compilation_id, optsType){
-        let rst = await optionsModel.find({user_id: user_id, compilation_id: compilation_id});
-        if(rst.length > 0){
-            let opts = rst[0].options;
-            for(let i = 0, len = opts.length; i < len; i++){
-                if(opts[i].type === optsType){
-                    return opts[i];
-                }
-            }
-        }
-        return null;
-    }
-
-    async saveOptions(user_id, compilation_id, opsType, opts){
-        let optionsData = await optionsModel.find({user_id: user_id, compilation_id: compilation_id});
-        if(optionsData.length === 0){
-            await optionsModel.create({user_id: user_id, compilation_id: compilation_id, options: [{type: opsType, opts: opts}]});
-        }
-        await optionsModel.update({user_id: user_id, compilation_id: compilation_id, 'options.type': opsType}, {$set: {'options.$.opts': opts}});
-        let rst = await optionsModel.find({user_id: user_id, compilation_id: compilation_id});
-        return rst;
-    }
-}*/
-
 export default OptionsDao;

+ 156 - 54
modules/pm/controllers/pm_controller.js

@@ -21,6 +21,12 @@ let asyncTool = require('async');
 let pm_facade = require('../facade/pm_facade');
 const userModel = mongoose.model('user');
 let config = require("../../../config/config.js");
+const optionModel = mongoose.model('options');
+const stdBillsGuidanceLibModel = mongoose.model('std_billsGuidance_lib');
+const fs = require('fs');
+const _ = require('lodash');
+import SectionTreeDao from '../../complementary_ration_lib/models/sectionTreeModel';
+let sectionTreeDao = new SectionTreeDao();
 
 //统一回调函数
 let callback = function(req, res, err, message, data){
@@ -41,24 +47,18 @@ module.exports = {
         }
     },
     checkProjectRight: function (userId, projectId, callback) {
-        ProjectsData.getProject(projectId).then(function (result) {
+        ProjectsData.getProject(projectId).then(async function (result) {
             /**
              * result._doc.userID(Number): MongoDB
              * userId(String): Session.userID
              */
-            //result._doc.userID == userId &&
-            let isShare = false;
+            let shareInfo = null;
+            //判断是否是打开分享的项目,分享项目shareInfo不为null
             if(userId !== result.userID){
-                //判断是否是打开分享的项目
-                for(let shareData of result.shareInfo){
-                    if(shareData.userID === userId){
-                        isShare = true;
-                        break;
-                    }
-                }
+                shareInfo = await pm_facade.getShareInfo(userId, result);
             }
-            if ((userId === result.userID || isShare) && result._doc.projType === projType.tender) {
-                callback(true);
+            if ((userId === result.userID || shareInfo) && result._doc.projType === projType.tender) {
+                callback(true, result, shareInfo);
             } else {
                 callback(false);
             }
@@ -77,7 +77,7 @@ module.exports = {
     },
     updateProjects: async function (req, res) {
         let data = JSON.parse(req.body.data);
-        await ProjectsData.updateUserProjects(req.session.sessionUser.id, req.session.sessionCompilation._id, data.updateData, function (err, message, data) {
+        await ProjectsData.updateUserProjects(req.session.sessionUser.id, req.session.sessionCompilation._id, req.session.sessionCompilation.name, data.updateData, function (err, message, data) {
             if (err === 0) {
                 callback(req, res, err, message, data);
             } else {
@@ -86,7 +86,7 @@ module.exports = {
         });
     },
     // CSL, 2017-12-14 该方法用于项目属性:提交保存混合型数据,这些数据来自不同的表,包括projects.property、ration、bills、labour_coes.
-    updateMixDatas: function(req, res){
+    updateMixDatas: async function(req, res){
         let datas = JSON.parse(req.body.data).mixDataArr;
         let functions = [];
 
@@ -105,9 +105,22 @@ module.exports = {
 
         // 项目属性
         if (Object.keys(datas.properties).length > 0){
+            //基本信息特殊处理,更新建设项目
+            if(datas.properties['property.basicInformation']){
+                let constructionProject = await pm_facade.getConstructionProject(datas.projectID);
+                if(constructionProject){
+                    functions.push(updateFunc(projectModel, {ID: constructionProject.ID}, {'property.basicInformation': datas.properties['property.basicInformation']}));
+                }
+                delete datas.properties['property.basicInformation'];
+            }
             functions.push(updateFunc(projectModel, {ID: datas.projectID}, datas.properties));
         };
 
+        //选项
+        if(datas.options && datas.options.updateData){
+            functions.push(updateFunc(optionModel, {user_id: req.session.sessionUser.id, compilation_id: req.session.sessionCompilation._id}, {'options.GENERALOPTS': datas.options.updateData}));
+        }
+
         // 人工系数
         if (datas.labourCoes&&datas.labourCoes.updateData){
             functions.push(updateLC());
@@ -144,6 +157,21 @@ module.exports = {
             callback(req, res, err, message, data);
         });
     },
+    defaultSettings: async function(req, res){
+        try{
+            let data = JSON.parse(req.body.data);
+            let projectID = data.projectID;
+            let defaultSettingSc = await ProjectsData.defaultSettings(req.session.sessionUser.id, req.session.sessionCompilation._id, projectID);
+            if(!defaultSettingSc){
+                throw '恢复失败';
+            }
+            res.json({error: 0, message: '恢复成功', data: null});
+        }
+        catch(error){
+            console.log(error);
+            res.json({error: 1, message: error, data: null});
+        }
+    },
  /*   copyProjects: function (req, res) {
         let data = JSON.parse(req.body.data);
         ProjectsData.copyUserProjects(req.session.sessionUser.id, req.session.sessionCompilation._id, data.updateData, function (err, message, data) {
@@ -162,6 +190,7 @@ module.exports = {
     },
     getProject: function(req, res){
         let data = JSON.parse(req.body.data);
+        let projectID = data.proj_id;
         ProjectsData.getUserProject(req.session.sessionUser.id, data.proj_id, async function(err, message, data){
             if (err === 0) {
                 let engineeringLibModel = new EngineeringLibModel();
@@ -170,8 +199,24 @@ module.exports = {
                 let strData = JSON.stringify(data);
                 let projInfo = JSON.parse(strData);
                 if (engineeringInfo !== null) {
+                    if(engineeringInfo.billsGuidance_lib){
+                        for(let billsGuidanceLib of engineeringInfo.billsGuidance_lib){
+                            let stdBillsGuidanceLib = await stdBillsGuidanceLibModel.findOne({ID: billsGuidanceLib.id});
+                            if(stdBillsGuidanceLib){
+                                billsGuidanceLib.type = stdBillsGuidanceLib.type ? stdBillsGuidanceLib.type : 1;
+                            }
+                        }
+                    }
                     projInfo.engineeringInfo = engineeringInfo;
                 }
+                //读取建设项目的基本信息
+                let basicInfo = await ProjectsData.getBasicInfo(projectID);
+                if(basicInfo !== null){
+                    projInfo.property.basicInformation = basicInfo;
+                }
+                //获取单位工程完整目录结构
+                let fullPath = await pm_facade.getFullPath(projectID);
+                projInfo.fullPath = fullPath;
                 callback(req, res, err, message, projInfo);
             } else {
                 callback(req, res, err, message, null);
@@ -194,7 +239,7 @@ module.exports = {
     index: async function(request, response) {
         // 获取编办信息
         let sessionCompilation = request.session.sessionCompilation;
-        if (sessionCompilation === undefined) {
+        if (sessionCompilation === undefined ||sessionCompilation ===null) {
             return response.redirect('/logout');
         }
         let compilationModel = new CompilationModel();
@@ -202,7 +247,15 @@ module.exports = {
         let compilationData = await compilationModel.getCompilationById(sessionCompilation._id);
         request.session.sessionCompilation = compilationData;
         sessionCompilation = request.session.sessionCompilation;
-
+        //更新用户的使用过的费用定额列表
+        let userData = await userModel.findOne({_id: mongoose.Types.ObjectId(request.session.sessionUser.id)}, '-_id used_list');
+        //是否第一次进入该费用定额
+        let isFirst = false;
+        if (userData) {
+            isFirst = !_.find(userData.used_list, function (o) {
+                return o.compilationId === compilationData._id.toString();
+            });;
+        }
         // 清单计价
         let billValuation = sessionCompilation.bill_valuation !== undefined ?
             sessionCompilation.bill_valuation : [];
@@ -215,19 +268,34 @@ module.exports = {
         let rationValuation = sessionCompilation.ration_valuation !== undefined ?
             sessionCompilation.ration_valuation : [];
         rationValuation = await engineeringLibModel.getLib(rationValuation);
+        let absoluteUrl = compilationData.overWriteUrl ? request.app.locals.rootDir + compilationData.overWriteUrl : request.app.locals.rootDir;
+        let overWriteUrl = fs.existsSync(absoluteUrl) && fs.statSync(absoluteUrl).isFile()? compilationData.overWriteUrl : null;
         let renderData = {
+            isFirst: isFirst,
             userAccount: request.session.userAccount,
             userID: request.session.sessionUser.id,
             compilationData: JSON.stringify(sessionCompilation),
+            overWriteUrl: overWriteUrl,
             billValuation: JSON.stringify(billValuation),
             rationValuation: JSON.stringify(rationValuation),
             engineeringList: JSON.stringify(engineering.List),
-            versionName: sessionCompilation.name + '免费版',
+            compilationName: sessionCompilation.name,
+            versionName: `纵横建筑云计价(${request.session.compilationVersion})`,
             LicenseKey:config.getLicenseKey(process.env.NODE_ENV)
         };
 
         response.render('building_saas/pm/html/project-management.html', renderData);
     },
+    //第一次进入该费用定额时准备的初始数据
+    prepareInitialData: async function(request, response) {
+        try {
+            let sessionCompilation = request.session.sessionCompilation;
+            await pm_facade.prepareInitialData(request.session.sessionUser.id, sessionCompilation._id, sessionCompilation.example);
+            callback(request, response, 0, 'success', null);
+        } catch(err) {
+            callback(request, response, 1, err, null);
+        }
+    },
     // 获取单价文件列表
     getUnitFileList: async function(request, response) {
         let data = request.body.data;
@@ -454,61 +522,47 @@ module.exports = {
     share: async function(req, res){
         try{
             let data = JSON.parse(req.body.data);
+            let shareDate = moment(Date.now()).format('YYYY-MM-DD HH:mm:ss'),
+                shareUserIDs = [];
+            for (let data of data.shareData) {
+                shareUserIDs.push(data.userID);
+                data.shareDate = shareDate;
+            }
             //添加分享
-            let shareData = {userID: data.userID, allowCopy: data.allowCopy, shareDate: moment(Date.now()).format('YYYY-MM-DD HH:mm:ss')};
             if(data.type === 'create'){
-                await projectModel.update({ID: data.projectID, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]}, {$addToSet: {shareInfo: shareData}});
+                //新增
+                for (let sData of data.shareData) {
+                    await projectModel.update({ID: data.projectID, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]}, {$addToSet: {shareInfo: sData}});
+                }
+            } else if (data.type === 'update') {
+                await projectModel.update({ID: data.projectID, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]}, {$set: {shareInfo: data.shareData}});
             }
             //取消分享
             else {
-                await projectModel.update({ID: data.projectID, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]}, {$pull: {shareInfo: {userID: data.userID}}});
+                await projectModel.update({ID: data.projectID, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]}, {$pull: {shareInfo: {userID: {$in: shareUserIDs}}}});
             }
-            callback(req, res, 0, 'success', null);
+            callback(req, res, 0, 'success', data.shareData);
         }
         catch (err){
             callback(req, res, 1, err, null);
         }
     },
-    getShareProjects: async function (req, res) {
+    receiveProjects: async function(req, res) {
         try {
+            let rst = {grouped: [], ungrouped: [], summaryInfo: null};
             let userID = req.session.sessionUser.id;
-            let rst = {receive: [], share: []}//接收的、由我分享的
-            let shareProjects = await projectModel.find({userID: userID,
-                $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}], compilation: req.session.sessionCompilation._id, 'shareInfo.0': {$exists: true}});
-            //项目类型为分享给别人
-            let shareToUserIDs = [];
-            for(let proj of shareProjects){
-                proj._doc.shareType = 'shareTo';
-                 for(let shareToUser of proj.shareInfo){
-                     shareToUserIDs.push(shareToUser.userID);
-                 }
-            }
-            shareToUserIDs = Array.from(new Set(shareToUserIDs));
-            let shareToObjIDs = [];
-            for(let userID of shareToUserIDs){
-                shareToObjIDs.push(mongoose.Types.ObjectId(userID));
-            }
-            let shareToUsers = await userModel.find({_id: {$in: shareToObjIDs}});
-            for(let shareToUser of shareToUsers){
-                for(let proj of shareProjects){
-                    for(let user of proj.shareInfo){
-                        if(user.userID === shareToUser._id.toString()){
-                            user._doc.company = shareToUser.company;
-                            user._doc.email = shareToUser.email;
-                            user._doc.name = shareToUser.real_name;
-                            user._doc.mobile = shareToUser.mobile;
-                        }
-                    }
-                }
-            }
-            rst.share = shareProjects;
             let receiveProjects = await projectModel.find({
-                $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}], compilation: req.session.sessionCompilation._id, 'shareInfo.userID': userID});
+                $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}], compilation: req.session.sessionCompilation._id, 'shareInfo.userID': userID}, '-_id');
             //设置原项目用户信息
             if(receiveProjects.length > 0){
                 let orgUserIDs = [];
                 for(let proj of receiveProjects){
                     orgUserIDs.push(proj.userID);
+                    if (proj.projType === projType.tender) {
+                        //设置工程专业
+                        proj._doc.feeStandardName = proj.property.feeStandardName || '';
+                    }
+                    delete proj._doc.property;
                 }
                 orgUserIDs = Array.from(new Set(orgUserIDs));
                 let userObjIDs = [];
@@ -516,7 +570,37 @@ module.exports = {
                     userObjIDs.push(mongoose.Types.ObjectId(uID));
                 }
                 let orgUsersInfo = await userModel.find({_id: {$in : userObjIDs}});
+                //建设项目
+                let consProjIDs = [],
+                    ungroupedTenders = [];
                 for(let proj of receiveProjects){
+                    if (proj.projType === projType.project) {
+                        consProjIDs.push(proj.ID);
+                    }
+                    //获取分享项目子项
+                    if (proj.projType !== projType.tender) {
+                        proj._doc.children = await pm_facade.getPosterityProjects([proj.ID]);
+                        for (let projC of proj._doc.children) {
+                            if (projC.projType === projType.project) {
+                                consProjIDs.push(projC.ID);
+                            } else if (projC.projType === projType.tender) {
+                                //设置工程专业
+                                projC._doc.feeStandardName = projC.property.feeStandardName || '';
+                                if (proj.projType === projType.engineering) {
+                                    ungroupedTenders.push(projC._doc);
+                                }
+                            }
+                            delete projC._doc.property;
+                        }
+                    } else {//未分类的单位工程不进行汇总,只取价格信息
+                        ungroupedTenders.push(proj._doc);
+                    }
+                    //设置分组,单位工程及单项工程分到未分组那
+                    if (proj.projType === projType.tender || proj.projType === projType.engineering) {
+                        rst.ungrouped.push(proj);
+                    } else {
+                        rst.grouped.push(proj);
+                    }
                     //设置项目类型为来自别人分享
                     proj._doc.shareType = 'receive';
                     for(let userData of orgUsersInfo){
@@ -526,18 +610,24 @@ module.exports = {
                         }
                     }
                 }
+                consProjIDs = Array.from(new Set(consProjIDs));
+                let summaryInfo = await pm_facade.getSummaryInfo(consProjIDs);
+                let tendersFeeInfo = await pm_facade.getTendersFeeInfo(ungroupedTenders);
+                rst.summaryInfo = {grouped: summaryInfo, ungrouped: tendersFeeInfo};
             }
-            rst.receive = receiveProjects;
             callback(req, res, 0, 'success', rst);
         }
         catch (err){
+            console.log(err);
             callback(req, res, 1, err, null);
         }
     },
     getProjectsByQuery: async function (req, res) {
         try{
             let data = JSON.parse(req.body.data);
+            let compilation = req.session.sessionCompilation._id;
             let query = data.query;
+            query.compilation = compilation;
             let options = data.options;
             let projects = await projectModel.find(query, options);
             callback(req, res, 0, 'success', projects);
@@ -556,4 +646,16 @@ module.exports = {
             callback(req, res, 1, err, null);
         }
     },
+    changeFile:async function(req,res){
+        try{
+            let data = JSON.parse(req.body.data);
+            console.log(data);
+            await pm_facade.changeFile(data.projects,data.user_id,data.fileID,data.name,data.from,data.type);
+            callback(req, res, 0, 'success', []);
+        }
+        catch (err){
+            console.log(err);
+            callback(req, res, 1, err, null);
+        }
+    }
 };

+ 441 - 35
modules/pm/facade/pm_facade.js

@@ -1,9 +1,38 @@
 /**
  * Created by zhang on 2018/4/17.
  */
+const projectType = {
+    folder: 'Folder',
+    tender: 'Tender',
+    project: 'Project',
+    engineering: 'Engineering',
+};
+//先导出后require可以解决循环引用问题
+module.exports={
+    moveProject:moveProject,
+    copyProject:copyProject,
+    copyExample: copyExample,
+    getSummaryInfo: getSummaryInfo,
+    getSummaryInfoByTender: getSummaryInfoByTender,
+    getTendersFeeInfo: getTendersFeeInfo,
+    getConstructionProject: getConstructionProject,
+    getFullPath: getFullPath,
+    getProjectFeature:getProjectFeature,
+    projectType: projectType,
+    getPosterityProjects: getPosterityProjects,
+    isShare: isShare,
+    getShareInfo: getShareInfo,
+    prepareInitialData: prepareInitialData,
+    changeFile:changeFile
+};
+
+
+
 let mongoose = require('mongoose');
 let _ = require("lodash");
 let feeRate_facade = require('../../fee_rates/facade/fee_rates_facade');
+let glj_facade = require('../../glj/facade/glj_facade');
+let project_facade = require('../../main/facade/project_facade');
 let logger = require("../../../logs/log_helper").logger;
 const uuidV1 = require('uuid/v1');
 let projectModel = mongoose.model('projects');
@@ -23,28 +52,103 @@ let rationGLJModel = mongoose.model('ration_glj');
 let rationCoeModel = mongoose.model('ration_coe');
 let rationInstallationModel = mongoose.model('ration_installation');
 let quantityDetailModel = mongoose.model('quantity_detail');
+let rationTemplateModel = mongoose.model('ration_template');
+let userModel = mongoose.model('user');
+let compleGljSectionModel = mongoose.model('complementary_glj_section');
+let compleGljSectionTModel = mongoose.model('complementary_glj_section_templates');
+
+let featureLibModel =  mongoose.model("std_project_feature_lib");
 let scMathUtil = require('../../../public/scMathUtil').getUtil();
+let counter = require('../../../public/counter/counter');
+import SectionTreeDao from '../../complementary_ration_lib/models/sectionTreeModel';
+let sectionTreeDao = new SectionTreeDao();
 import CounterModel from "../../glj/models/counter_model";
 import moment from 'moment';
 import billsFlags from '../../common/const/bills_fixed';
-const projectType = {
-    folder: 'Folder',
-    tender: 'Tender',
-    project: 'Project',
-    engineering: 'Engineering',
-};
-
-
-module.exports={
-    moveProject:moveProject,
-    copyProject:copyProject,
-    getSummaryInfo: getSummaryInfo
-};
+const notDeleted = [{deleteInfo: null}, {'deleteInfo.deleted': false}];
+
+
+
+//拷贝例题项目
+//@param {String}userID {Array}projIDs拷贝的例题项目ID(建设项目、文件夹)@return {Boolean}
+async function copyExample(userID, compilation, projIDs){
+    let allProjs = [],
+        IDMapping = {},
+        projMapping = {};
+    //例题项目不可为单项工程、单位工程、只能是建设项目、文件夹,否则不自动新建例题项目(这里不报错,让用户没有感觉)
+    let parentExample = await projectModel.find({ID: {$in: projIDs}, $or: notDeleted});
+    if (parentExample.length === 0) {
+        return false;
+    }
+    allProjs = allProjs.concat(parentExample);
+    for (let i = 0; i < parentExample.length; i++) {
+        let data = parentExample[i];
+        if (data.projType === projectType.tender || data.projType === projectType.engineering) {
+            return false;
+        }
+        //设置成顶节点,最后一个节点设置成末节
+        data.ParentID = -1;
+        if (i === parentExample.length - 1) {
+            data.NextSiblingID = -1;
+        }
+    }
+    //获取所有的子项目
+    let posterityProjs = await getPosterityProjects(projIDs);
+    allProjs = allProjs.concat(posterityProjs);
+    let projCounter = await counter.counterDAO.getIDAfterCountSync(counter.moduleName.project, allProjs.length);
+    //旧ID与新ID映射
+    for (let i = 0; i < allProjs.length; i++) {
+        let data = allProjs[i];
+        let newID = projCounter.sequence_value - (allProjs.length - 1) + i;
+        IDMapping[data.ID] = newID;
+        projMapping[newID] = data;
+    }
+    //return;
+    //设置新的树结构数据
+    let newDate = new Date(),
+        parentBulks = [];
+    for (let data of allProjs) {
+        let orgID = data.ID;
+        data.ID = IDMapping[data.ID];
+        data.ParentID = IDMapping[data.ParentID] ? IDMapping[data.ParentID] : -1;
+        data.NextSiblingID = IDMapping[data.NextSiblingID] ? IDMapping[data.NextSiblingID] : -1;
+        data.createDateTime = newDate;
+        data.userID = userID;
+        data.compilation = compilation;
+        data.shareInfo = [];
+        if (data.projType !== projectType.tender) {
+            let newData = _.cloneDeep(data._doc);
+            delete newData._id;
+          //  await projectModel.create(newData);
+            parentBulks.push({insertOne: {document: newData}});
+        } else {
+            //拷贝单位工程
+            let rootProjectID = projMapping[data.ParentID].ParentID;
+            let projectMap = {
+                copy: {
+                    document: {userID: userID, ID: orgID, NextSiblingID: data.NextSiblingID, ParentID: data.ParentID, name: data.name, shareInfo: [],
+                                compilation: compilation, fileVer: data.fileVer, projType: data.projType, property: {rootProjectID: rootProjectID}}
+                }
+            };
+            await copyProject(userID, compilation, {projectMap}, data.ID);
+        }
+    }
+    //最末顶层项目(兼容测试时已存在有项目,正常用户第一次进费用定额,该费用定额不存在项目)
+    let lastProj = await projectModel.findOne({userID: userID, compilation: compilation, ParentID: -1, NextSiblingID: -1, $or: notDeleted});
+    if (lastProj) {
+        parentBulks.push({updateOne: {filter: {ID: lastProj.ID}, update: {$set: {NextSiblingID: parentExample[0].ID}}}});
+    }
+    //拷贝父级文件
+    await projectModel.bulkWrite(parentBulks);
+    return true;
+}
 
-async function copyProject(userID, compilationID,data) {
+async function copyProject(userID, compilationID,data,newProjectID = null) {
     let projectMap = data.projectMap;
     let originalID = projectMap['copy'].document.ID;
-    let newProjectID = await getCounterID("projects");
+    if (!newProjectID) {
+        newProjectID = await getCounterID("projects");
+    }
     let newFeeName = null,newUnitName = null;
     let calcProgramFileID = uuidV1();//新的计算程序文件ID
     let labourCoeFileID = uuidV1();//新的人工调整系数文件ID
@@ -76,14 +180,21 @@ async function copyProject(userID, compilationID,data) {
 
     //更新项目的属性;
     projectMap['copy'].document.ID = newProjectID;
-    projectMap['copy'].document.property.calcProgramFile.ID = calcProgramFileID;
-    projectMap['copy'].document.property.labourCoeFile.ID = labourCoeFileID;
-    projectMap['copy'].document.property.feeFile.id = feeRateFileID;
-    projectMap['copy'].document.property.unitPriceFile.id = unitPriceFileID;
+    if(projectMap['copy'].document.property.calcProgramFile){
+        projectMap['copy'].document.property.calcProgramFile.ID = calcProgramFileID;
+    }
+    if(projectMap['copy'].document.property.labourCoeFile){
+        projectMap['copy'].document.property.labourCoeFile.ID = labourCoeFileID;
+    }
+    if(projectMap['copy'].document.property.feeFile){
+        projectMap['copy'].document.property.feeFile.id = feeRateFileID;
+    }
+    if(projectMap['copy'].document.property.unitPriceFile){
+        projectMap['copy'].document.property.unitPriceFile.id = unitPriceFileID;
+    }
     projectMap['copy'].document.userID = userID;
     projectMap['copy'].document.compilation = compilationID;
     projectMap['copy'].document.createDateTime = new Date();
-
     //清单、定额ID生成任务
     let IDtasks = [
         createIDsAndReturn(originalID,billsModel),
@@ -91,7 +202,6 @@ async function copyProject(userID, compilationID,data) {
         getProjectGLJIDAndReturn(originalID,newProjectID)
     ];
     let [billMap,rationMap,projectGLJMap] = await Promise.all(IDtasks);
-
     //所有复制任务异步处理,提升效率  复制清单,定额,4个文件,项目工料机, 定额工料机,人工系数,工程量明细,定额安装增加费,安装增加费
     let copyTasks = [
         createProject(projectMap),
@@ -99,16 +209,25 @@ async function copyProject(userID, compilationID,data) {
         copyBills(newProjectID,billMap),
         copyRations(newProjectID,billMap.uuidMaping,rationMap,projectGLJMap.IDMap),
         copyProjectGLJ(projectGLJMap.datas),
-        commonCopy(newProjectID,originalProperty.calcProgramFile.ID,calcProgramFileID,calcProgramsModel),
-        commonCopy(newProjectID,originalProperty.labourCoeFile.ID,labourCoeFileID,labourCoesModel),
-        copyFeeRate(originalProperty.rootProjectID,userID,originalProperty.feeFile.id,feeRateFileID,newFeeName),
-        copyUnitPriceFile(newProjectID,originalProperty.rootProjectID,userID,originalProperty.unitPriceFile.id,unitPriceFileID,newUnitName),
         copyInstallFee(originalID,newProjectID),
         copyRationSubList(originalID,newProjectID,billMap.uuidMaping,rationMap.uuidMaping,projectGLJMap.IDMap,rationGLJModel),
         copyRationSubList(originalID,newProjectID,billMap.uuidMaping,rationMap.uuidMaping,projectGLJMap.IDMap,rationCoeModel),
         copyRationSubList(originalID,newProjectID,billMap.uuidMaping,rationMap.uuidMaping,projectGLJMap.IDMap,quantityDetailModel),
-        copyRationSubList(originalID,newProjectID,billMap.uuidMaping,rationMap.uuidMaping,projectGLJMap.IDMap,rationInstallationModel)
+        copyRationSubList(originalID,newProjectID,billMap.uuidMaping,rationMap.uuidMaping,projectGLJMap.IDMap,rationInstallationModel),
+        copyRationSubList(originalID,newProjectID,billMap.uuidMaping,rationMap.uuidMaping,projectGLJMap.IDMap,rationTemplateModel)
     ];
+    if(originalProperty.calcProgramFile){
+        copyTasks.push(commonCopy(newProjectID,originalProperty.calcProgramFile.ID,calcProgramFileID,calcProgramsModel));
+    }
+    if(originalProperty.labourCoeFile){
+        copyTasks.push(commonCopy(newProjectID,originalProperty.labourCoeFile.ID,labourCoeFileID,labourCoesModel));
+    }
+    if(originalProperty.feeFile){
+        copyTasks.push(copyFeeRate(originalProperty.rootProjectID,userID,originalProperty.feeFile.id,feeRateFileID,newFeeName));
+    }
+    if(originalProperty.unitPriceFile){
+        copyTasks.push(copyUnitPriceFile(newProjectID,originalProperty.rootProjectID,userID,originalProperty.unitPriceFile.id,unitPriceFileID,newUnitName));
+    }
     let p = await Promise.all(copyTasks);
     return p[0];
 }
@@ -130,8 +249,11 @@ async function getProjectGLJIDAndReturn(originalID,newProjectID) {
     let IDMap = {};
     let datas = [];
     let result = await gljListModel.find({project_id:originalID}, '-_id');
-    for(let d of result){
-        let newID = await getCounterID("glj_list");
+    let gljCount = await counter.counterDAO.getIDAfterCountSync(counter.moduleName.glj_list, result.length);
+    for(let i = 0; i < result.length; i++){
+        let d = result[i];
+        let newID = gljCount.sequence_value - (result.length - 1) + i;
+        //let newID = await getCounterID("glj_list");
         IDMap[d.id] = newID;
         d._doc.project_id = newProjectID;
         d._doc.id = newID;
@@ -180,6 +302,7 @@ async function copyRations(newProjectID,billsIDMap,rationMap,projectGLJIDMap) {
         if(doc.billsItemID){
             doc.billsItemID = billsIDMap[doc.billsItemID]?billsIDMap[doc.billsItemID]:-1;
         }
+        if(doc.referenceRationID) doc.referenceRationID = uuidMaping[doc.referenceRationID]?uuidMaping[doc.referenceRationID]:undefined;
         //绑定定类型的工料机 项目工料机ID
         doc.type==3&&doc.projectGLJID&&projectGLJIDMap[doc.projectGLJID]?doc.projectGLJID = projectGLJIDMap[doc.projectGLJID]:'';
     }
@@ -500,6 +623,90 @@ function getBuildingArea(projFeature){
     return null;
 }
 
+//根据单位工程ID获取汇总信息
+//@param {Number}tenderID {String}summaryType @return {Object}
+async function getSummaryInfoByTender(tenderID, summaryType) {
+    const notDeleted = [{deleteInfo: null}, {'deleteInfo.deleted': false}];
+    let tender = await projectModel.findOne({ID: tenderID, $or: notDeleted});
+    let parentName;
+    let summaryList = [];
+    if(!tender){
+        return null;
+    }
+    let engineering = await projectModel.findOne({ID: tender.ParentID, $or: notDeleted});
+    if(!engineering){
+        return null;
+    }
+    let project = await projectModel.findOne({ID: engineering.ParentID, $or: notDeleted});
+    if(!project){
+        return null;
+    }
+    let summaryInfo = await getSummaryInfo([project.ID]);
+    if(summaryType === projectType.engineering){
+        parentName = engineering.name ? engineering.name : '';
+        let tenders = await projectModel.find({ParentID: engineering.ID, $or: notDeleted});
+        for(let t of tenders){
+            if(summaryInfo[t.ID]){
+                summaryInfo[t.ID]['name'] = t.name ? t.name : '';
+                summaryList.push(summaryInfo[t.ID]);
+            }
+        }
+    }
+    else {
+        parentName = project.name ? project.name : '';
+        let engs = await projectModel.find({ParentID: project.ID, $or: notDeleted});
+        for(let e of engs){
+            if(summaryInfo[e.ID]){
+                summaryInfo[e.ID]['name'] = e.name ? e.name : '';
+                summaryList.push(summaryInfo[e.ID]);
+            }
+        }
+    }
+    return {parent: {name: parentName}, subList: summaryList};
+}
+
+//获取单位工程的各标段费用信息(不进行汇总)
+async function getTendersFeeInfo(tenders) {
+    let IDMapping = {};
+    //固定清单类别与汇总金额字段映射
+    let flagFieldMapping = {};
+    flagFieldMapping[billsFlags.ENGINEERINGCOST] = 'engineeringCost';
+    flagFieldMapping[billsFlags.SUB_ENGINERRING] = 'subEngineering';
+    flagFieldMapping[billsFlags.MEASURE] = 'measure';
+    flagFieldMapping[billsFlags.SAFETY_CONSTRUCTION] = 'safetyConstruction';
+    flagFieldMapping[billsFlags.OTHER] = 'other';
+    flagFieldMapping[billsFlags.CHARGE] = 'charge';
+    flagFieldMapping[billsFlags.TAX] = 'tax';
+    let tenderIDs = [];
+    if(tenders.length > 0){
+        for(let tender of tenders){
+            tenderIDs.push(tender.ID);
+            IDMapping[tender.ID] = {engineeringCost: 0, subEngineering: 0, measure: 0, safetyConstruction: 0, other: 0, charge: 0, tax: 0, rate: 0, buildingArea: '', perCost: ''};
+            IDMapping[tender.ID]['buildingArea'] = '';
+        }
+        //需要获取的清单固定类别综合合价:工程造价、分部分项、措施项目、安全文明施工专项、规费、其他项目、税金
+        let needFlags = [billsFlags.ENGINEERINGCOST, billsFlags.SUB_ENGINERRING, billsFlags.MEASURE,
+            billsFlags.SAFETY_CONSTRUCTION, billsFlags.CHARGE, billsFlags.OTHER, billsFlags.TAX];
+        //获取单位工程汇总金额需要用到的所有清单
+        let allBills = await billsModel.find({projectID: {$in: tenderIDs}, 'flags.flag': {$in: needFlags}, $or: notDeleted},
+            '-_id projectID fees flags');
+        //进行单位工程级别的汇总
+        for(let bills of allBills){
+            let billsFlag = bills.flags[0]['flag'];
+            let costField = flagFieldMapping[billsFlag];
+            IDMapping[bills.projectID][costField] = getCommonTotalFee(bills);
+        }
+        //占造价比例、单方造价
+        for(let tender of tenders){
+            let tenderInfo = IDMapping[tender.ID];
+            tenderInfo.rate = '';
+            //单方造价
+            tenderInfo.perCost = '';
+        }
+    }
+    return IDMapping;
+}
+
 async function getSummaryInfo(projectIDs){
     //ID与汇总信息映射
     let IDMapping = {};
@@ -512,10 +719,24 @@ async function getSummaryInfo(projectIDs){
     flagFieldMapping[billsFlags.OTHER] = 'other';
     flagFieldMapping[billsFlags.CHARGE] = 'charge';
     flagFieldMapping[billsFlags.TAX] = 'tax';
-    for(let projectID of projectIDs){
-        IDMapping[projectID] = {engineeringCost: 0, subEngineering: 0, measure: 0, safetyConstruction: 0, other: 0, charge: 0, tax: 0, rate: 0, buildingArea: '', perCost: ''};
+    let projects = await projectModel.find({ID: {$in : projectIDs}, projType: projectType.project, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]});
+    //设置建设项目的总建筑面积
+    for(let project of projects){
+        let grossArea = '';
+        if(project.property && project.property.basicInformation){
+            for(let basicInfo of project.property.basicInformation){
+                if(basicInfo.key === 'basicInfo'){
+                    for(let k of basicInfo.items){
+                        if(k.key === 'grossArea'){
+                            grossArea = k.value;
+                        }
+                    }
+                }
+            }
+        }
+        IDMapping[project.ID] = {engineeringCost: 0, subEngineering: 0, measure: 0, safetyConstruction: 0, other: 0, charge: 0, tax: 0, rate: 0, buildingArea: grossArea, perCost: ''};
     }
-    //let projects = await projectModel.find({ID: {$in : projectIDs}, projType: projectType.project, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]});
+
     //单项工程
     let engineerings = await projectModel.find({ParentID: {$in : projectIDs}, projType: projectType.engineering, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]});
     //单位工程
@@ -532,7 +753,7 @@ async function getSummaryInfo(projectIDs){
     if(tenders.length > 0){
         for(let tender of tenders){
             tenderIDs.push(tender.ID);
-            IDMapping[tender.ID] = {engineeringCost: 0, subEngineering: 0, measure: 0, safetyConstruction: 0, other: 0, charge: 0, tax: 0, rate: 0, buildingArea: '', perCost: ''};
+            IDMapping[tender.ID] = {engineeringCost: 0, subEngineering: 0, measure: 0, safetyConstruction: 0, other: 0, charge: 0, tax: 0, rate: 0, buildingArea: '', perCost: '',changeMark:tender.changeMark,property:tender.property};
             let buildingArea = getBuildingArea(tender.property.projectFeature);
             if(buildingArea){
                 IDMapping[tender.ID]['buildingArea'] = buildingArea;
@@ -574,10 +795,195 @@ async function getSummaryInfo(projectIDs){
             let projInfo = IDMapping[eng.ParentID];
             engInfo.rate = !isDef(projInfo) || projInfo.engineeringCost == 0 ? 0 : scMathUtil.roundTo(engInfo.engineeringCost * 100 / projInfo.engineeringCost, rateDecimal);
         }
-        for(let projectID of projectIDs){
-            IDMapping[projectID].rate = 100;
+        //建设项目占造价比例及单方造价
+        for(let project of projects){
+            let projectInfo = IDMapping[project.ID];
+            projectInfo.rate = 100;
+            projectInfo.perCost = projectInfo.buildingArea.toString().trim() === '' || projectInfo.buildingArea == 0 ?
+                                  projectInfo.buildingArea.toString().trim() : scMathUtil.roundTo(projectInfo.engineeringCost / projectInfo.buildingArea, perCostDecimal);
         }
     }
-    console.log(IDMapping);
     return IDMapping;
+}
+
+//根据项目ID获取所属建设项目
+//@param {Number}projectID @return {Object}
+async function getConstructionProject(projectID){
+    function returnProject(project){
+        if(!project || project.projType === projectType.folder){
+            return null;
+        }
+        if(project.projType === projectType.project){
+            return project;
+        }
+    }
+    let project = await projectModel.findOne({ID: projectID, $or: notDeleted});
+    let returnV = returnProject(project);
+    if(returnV !== undefined){
+        return returnV;
+    }
+    let parent = await projectModel.findOne({ID: project.ParentID, $or: notDeleted});
+    returnV = returnProject(parent);
+    if(returnV !== undefined){
+        return returnV;
+    }
+    let grandParent = await projectModel.findOne({ID: parent.ParentID, $or: notDeleted});
+    returnV = returnProject(grandParent);
+    return returnV !== undefined ? returnV : null;
+}
+
+//获取单位工程完整目录结构
+//@param {Number}projectID @return {Arry}
+async function getFullPath(projectID) {
+    let fullPath = [];
+    let project = await projectModel.findOne({ID: projectID, $or: notDeleted}, '-_id ParentID name');
+    if(project){
+        fullPath.push(project.name);
+        await getParent(project.ParentID);
+    }
+    fullPath = fullPath.reverse();
+    return fullPath;
+    async function getParent(ParentID) {
+        if(ParentID != -1){
+            let parent = await projectModel.findOne({ID: ParentID, $or: notDeleted}, '-_id ParentID name');
+            if(parent){
+                fullPath.push(parent.name);
+                await getParent(parent.ParentID);
+            }
+        }
+    }
+}
+
+async function getProjectFeature(libID,feeStandardName){
+    let lib = await featureLibModel.findOne({'ID':libID})
+    if(lib){
+        let eng = _.find(lib.feature,{'key':'engineering'})
+        if(eng) eng.value = feeStandardName;
+        return lib.feature;
+    }else {
+        return [];
+    }
+}
+
+//获取projectIDs文件下所有子项目(不包括projectIDs本身)
+async function getPosterityProjects(projectIDs) {
+    let rst = [];
+    async function getProjects(IDs) {
+        if (IDs.length > 0) {
+            let newIDs = [];
+            let projs = await projectModel.find({ParentID: {$in: IDs}, $or: notDeleted}, '-_id');
+            for (let proj of projs) {
+                rst.push(proj);
+                newIDs.push(proj.ID);
+            }
+            await getProjects(newIDs);
+        }
+    }
+    await getProjects(projectIDs);
+    return rst;
+}
+
+//根据项目获得分享信息(分享层级不一定在项目级)(以最新为准)
+//@param {String}userId {Object}tender @return {Object} || {null}
+async function getShareInfo(userId, project) {
+    //与该用户相关的分享
+    let shareList = [];
+    while (project) {
+        for(let shareData of project.shareInfo){
+            if(shareData.userID === userId){
+                shareList.push(shareData);
+                break;
+            }
+        }
+        project = await projectModel.findOne({ID: project.ParentID}, '-_id shareInfo ID ParentID');
+    }
+    //获取最新分享
+    shareList.sort(function (a, b) {
+        let aV = Date.parse(a.shareDate),
+            bV = Date.parse(b.shareDate);
+        if (aV > bV) {
+            return -1;
+        } else if (aV < bV) {
+            return 1;
+        }
+        return 0;
+    });
+    return shareList[0] || null;
+}
+
+//打开的单位工程是否是被分享的.
+async function isShare(userId, project){
+    //判断是否是打开分享的项目,属于分享文件的子项也算
+    while (project) {
+        for(let shareData of project.shareInfo){
+            if(shareData.userID === userId){
+                return true;
+            }
+        }
+        project = await projectModel.findOne({ID: project.ParentID}, '-_id shareInfo ID ParentID');
+    }
+    return false;
+}
+
+//用户第一次进入费用定额的数据准备
+async function prepareInitialData(userId, compilation, example) {
+    let prepareTask = [
+        updateUsedList(userId, compilation),
+        copyCompleRationSection(userId, compilation),
+        copyCompleGljSection(userId, compilation)
+    ];
+    if (example && example.length > 0) {
+        prepareTask.push(copyExample(userId, compilation, example));
+    }
+    await Promise.all(prepareTask);
+}
+
+async function updateUsedList(userId, compilation) {
+    await userModel.update({_id: mongoose.Types.ObjectId(userId)}, {$push: {used_list: {compilationId: compilation}}});
+}
+
+//拷贝补充定额章节树
+async function copyCompleRationSection(userId, compilationId) {
+    await sectionTreeDao.copyDataFromTemplate(userId, compilationId);
+}
+//拷贝补充人材机分类树
+async function copyCompleGljSection(userId, compilationId) {
+    let templateData = await compleGljSectionTModel.find({compilationId: compilationId});
+    if (templateData.length > 0) {
+        let insertDatas = [],
+            uuidMapping = {};
+        //将ID替换成UUID
+        for (let temData of templateData) {
+            uuidMapping[temData.ID] = uuidV1();
+        }
+        for(let temData of templateData) {
+            let insertD = {
+                userId: userId,
+                compilationId: compilationId,
+                Name: temData.Name,
+                ID: uuidMapping[temData.ID],
+                ParentID: uuidMapping[temData.ParentID] || -1,
+                NextSiblingID: uuidMapping[temData.NextSiblingID] || -1,
+            };
+            insertDatas.push(insertD);
+        }
+        //插入数据
+        await compleGljSectionModel.insertMany(insertDatas);
+    }
+}
+
+async function changeFile(datas,userID,fileID,name,from,type){//from 费率或单价文件,type从单前建设项目还是从其它建设项目中复制
+    let projectIDs = [],newFile = {id:fileID,name:name};//计录从其它项目中复制的文件,选中多个的时候只需复制一次
+    let projectUpdateType = from == "feeRateFile"?"feeRate":"unitFile";
+    for(let d of datas){
+        let tem_file = from == "feeRateFile"? await feeRate_facade.changeFeeRateFile(d, newFile,type,userID):await glj_facade.changeUnitFile(d, newFile,type,userID);
+        if(type == 1 && tem_file){//从建设项目复制时,只有第一次需要复制,剩下的就相当于使用同个建设项目的情况了
+            let newID =  from == "feeRateFile"?tem_file.ID:tem_file.id;
+            newFile = {id:newID,name:tem_file.name};
+            type = 0;
+        }
+        projectIDs.push({ID:d.projectID})
+    }
+    await project_facade.markProjectsToChange(projectIDs,projectUpdateType)//项目标记为待刷新状态
+
 }

+ 115 - 29
modules/pm/models/project_model.js

@@ -1,6 +1,22 @@
 /**
  * Created by Mai on 2017/1/18.
  */
+let projectType = {
+    folder: 'Folder',
+    tender: 'Tender',
+    project: 'Project',
+    engineering: 'Engineering',
+};
+let fileType = {
+    unitPriceFile: 'UnitPriceFile',
+    feeRateFile: 'FeeRateFile'
+};
+//先导出后require可以解决循环引用问题
+module.exports ={    project: new ProjectsDAO(),
+    projType: projectType,
+    fileType: fileType
+};
+
 import mongoose from 'mongoose';
 import async_c from 'async';
 import UnitPriceFileModel from "../../glj/models/unit_price_file_model";
@@ -14,6 +30,7 @@ import {
     calcOptions,
     tenderSetting
 } from './project_property_template';
+import optionSetting from '../../options/models/optionTypes';
 import fixedFlag from '../../common/const/bills_fixed';
 let FeeRateFiles = mongoose.model('fee_rate_file');
 let counter = require("../../../public/counter/counter.js");
@@ -30,19 +47,12 @@ let BillsModel = require("../../main/models/bills").model;
 let _ = require('lodash');
 
 let Projects = mongoose.model('projects');
-let projectType = {
-    folder: 'Folder',
-    tender: 'Tender',
-    project: 'Project',
-    engineering: 'Engineering',
-};
-let fileType = {
-    unitPriceFile: 'UnitPriceFile',
-    feeRateFile: 'FeeRateFile'
-};
+let mainColLibModel = mongoose.model('std_main_col_lib');
+let projSettingModel = mongoose.model('proj_setting');
+let optionModel = mongoose.model('options');
 
-let ProjectsDAO = function () {
-};
+function ProjectsDAO() {
+}
 
 let G_FILE_VER = '1.0.1';
 
@@ -61,9 +71,7 @@ ProjectsDAO.prototype.getUserProjects = async function (userId, compilation, cal
                 projIDs.push(project.ID);
             }
         }
-        //test
         let summaryInfo = await pmFacade.getSummaryInfo(projIDs);
-        //test
         //设置汇总字段
         for(let proj of projects){
             let summaryProj = summaryInfo[proj.ID];
@@ -99,9 +107,9 @@ ProjectsDAO.prototype.getUserProject = function (userId, ProjId, callback) {
             callback(0, '', template);
         }
     });
-}
+};
 
-ProjectsDAO.prototype.updateUserProjects = async function (userId, compilationId, datas, callback) {
+ProjectsDAO.prototype.updateUserProjects = async function (userId, compilationId, compilationName, datas, callback) {
     let data, project, updateLength = 0, hasError = false, deleteInfo = null, i, newProject;
     let updateAll = function (err) {
         if (!err) {
@@ -130,6 +138,10 @@ ProjectsDAO.prototype.updateUserProjects = async function (userId, compilationId
                 data.updateData['compilation'] = compilationId;
                 data.updateData['createDateTime'] = new Date();
                 data.updateData['fileVer'] = G_FILE_VER;
+                if(data.updateData.projType === projectType.project){
+                    //设置建设项目基本信息,多个单位工程共用
+                    data.updateData.property = {basicInformation: basicInformation};
+                }
                 // 如果没有选中单价文件则新增单价文件
                 if (data.updateData.projType === projectType.tender && data.updateData.property !== null &&
                     Object.keys(data.updateData.property.unitPriceFile).length > 0 &&
@@ -156,11 +168,17 @@ ProjectsDAO.prototype.updateUserProjects = async function (userId, compilationId
                     data.updateData.property.decimal = defaultDecimal;
                     //清单工程量精度
                     data.updateData.property.billsQuantityDecimal = billsQuantityDecimal;
-                    //基本信息
-                    basicInformation[0]['items'][1]['value'] = data.updateData.property.engineeringName || '';
-                    data.updateData.property.basicInformation = basicInformation;
+                    //基本信息-挪到建设项目下,多个单位工程共用
+                    //basicInformation[0]['items'][1]['value'] = data.updateData.property.engineeringName || '';
+                    //data.updateData.property.basicInformation = basicInformation;
                     //工程特征
-                    data.updateData.property.projectFeature = projectFeature;
+                    if(data.updateData.property.featureLibID){
+                        //工程专业显示费用定额的名称
+                        data.updateData.property.projectFeature = await pmFacade.getProjectFeature(data.updateData.property.featureLibID, data.updateData.property.feeStandardName);
+                    }
+                    /*projectFeature[0]['value'] = data.updateData.property.engineeringName || '';
+                    data.updateData.property.projectFeature = projectFeature;*/
+
                     //呈现选项
                     data.updateData.property.displaySetting = displaySetting;
 
@@ -169,7 +187,7 @@ ProjectsDAO.prototype.updateUserProjects = async function (userId, compilationId
                     //计算选项
                     data.updateData.property.calcOptions = calcOptions;
                     //安装增加费
-                    if(parseInt(data.updateData.property.engineering)==4){
+                    if(data.updateData.property.isInstall == true || data.updateData.property.isInstall=='true'){//判断是否安装工程
                         await installationFacade.copyInstallationFeeFromLib(data.updateData.ID,data.updateData.property.engineering_id);
                     }
                     //锁定清单
@@ -179,12 +197,12 @@ ProjectsDAO.prototype.updateUserProjects = async function (userId, compilationId
                 }
 
                 newProject = new Projects(data.updateData);
-                // 查找同级是否存在同名数据
+               /* // 查找同级是否存在同名数据
                 let exist = await this.isExist(userId, compilationId, data.updateData.name, data.updateData.ParentID);
                 if (exist) {
                     callback(1, '同级目录已存在相同名称数据.', null);
                     return;
-                }
+                }*/
                 if (data.updateData.projType === 'Tender') {
                     let feeRateFileID = await feeRateFacade.newFeeRateFile(userId, data.updateData);
                     newProject.property.feeFile = feeRateFileID ? feeRateFileID : -1;
@@ -380,11 +398,12 @@ ProjectsDAO.prototype.rename = async function (userId, compilationId, data, call
             throw '请填写名称!';
         }
         data.newName = data.newName.trim();
-        // 查找同级是否存在同名数据
+        //重名前端控制
+       /* // 查找同级是否存在同名数据
         let exist = await this.isExist(userId, compilationId, data.newName, data.parentID);
         if (exist) {
             throw '同级目录已存在相同名称数据';
-        }
+        }*/
 
         Projects.update({userID: userId, ID: data.id}, {name: data.newName}, function (err) {
             if (err) {
@@ -668,6 +687,43 @@ ProjectsDAO.prototype.getUnitPriceFileId = async function (projectId) {
 };
 
 /**
+ * 根据项目id获取项目property信息
+ *
+ * @param {Number} projectId
+ * @return {Promise}
+ */
+ProjectsDAO.prototype.getProjectProperty = async function (projectId) {
+    let result = null;
+    let projectData = await Projects.findOne({ID: projectId},['property']);
+    if (projectData === null) {
+        return result;
+    }
+    return projectData.property;
+};
+
+ProjectsDAO.prototype.getExtendData = function(property,compilation) {
+    let ext = {};
+    if(property){
+        let region = property.region;
+        let taxType = property.taxType;
+        if(compilation.priceProperties && compilation.priceProperties.length > 0){//如果是具有多单价的编办,取单价对应的字段
+            let priceProperty  = _.find(compilation.priceProperties,{region:region,taxModel:parseInt(taxType)});
+            if(priceProperty){
+                ext['priceField'] =  priceProperty.price.dataCode;
+            }
+        }
+        if(compilation.consumeAmtProperties && compilation.consumeAmtProperties.length > 0){
+            let  consumeAmt =   _.find(compilation.consumeAmtProperties,{region:region,taxModel:parseInt(taxType)});
+            if(consumeAmt){
+                ext['quantityField'] =  consumeAmt.consumeAmt.dataCode;
+            }
+        }
+    }
+    return _.isEmpty(ext)?null:ext;
+}
+
+
+/**
  * 获取当前用户的建设项目数据
  *
  * @paraconsolem {Number} userId
@@ -759,9 +815,39 @@ ProjectsDAO.prototype.updateUnitFileToProject=async function(projectID,unitFile)
     return await Projects.findOneAndUpdate({'ID':projectID},{'property.unitPriceFile':unitFile});
 }
 
+ProjectsDAO.prototype.getBasicInfo = async function (projectID) {
+    //获取建设项目
+    let constructionProject = await pmFacade.getConstructionProject(projectID);
+    if(!constructionProject || !constructionProject.property || !constructionProject.property.basicInformation){
+        return null;
+    }
+    return constructionProject.property.basicInformation;
+};
 
-
-module.exports ={    project: new ProjectsDAO(),
-    projType: projectType,
-    fileType: fileType
+//恢复默认系统设置
+ProjectsDAO.prototype.defaultSettings = async function (userID, compilationId, projectID) {
+    let project = await Projects.findOne({ID: projectID});
+    if(!project){
+        return false;
+    }
+    let cloneProperty = _.cloneDeep(project.property);
+    //关于计算
+    cloneProperty.billsCalcMode = 0;
+    cloneProperty.zanguCalcMode = 0;
+    cloneProperty.calcOptions = calcOptions;
+    //清单工程量精度
+    cloneProperty.billsQuantityDecimal = billsQuantityDecimal;
+    //小数位数
+    cloneProperty.decimal = defaultDecimal;
+    //呈现选项
+    cloneProperty.displaySetting = displaySetting;
+    //列设置
+    let stdColLib = await mainColLibModel.findOne({ID: project.property.colLibID});
+    if(stdColLib){
+        await projSettingModel.update({projectID: projectID}, {$set: {main_tree_col: stdColLib.main_tree_col}});
+    }
+    //系统选项
+    await optionModel.update({user_id: userID, compilation_id: compilationId}, {$set: {options: optionSetting}});
+    await Projects.update({ID: projectID}, {$set: {property: cloneProperty}});
+    return true;
 };

+ 6 - 4
modules/pm/models/project_property_template.js

@@ -7,7 +7,7 @@ const defaultDecimal = {
     bills: {unitPrice: 2, totalPrice: 2},
     ration: {quantity: 4, unitPrice: 2, totalPrice: 2},
     glj: {quantity: 4, unitPriceHasMix: 2, unitPrice: 3},
-    feeRate: 2,
+    feeRate: 3,
     quantity_detail: 4,
     material:5,//三材系数
     process: 6
@@ -15,8 +15,8 @@ const defaultDecimal = {
 const displaySetting = {
     autoHeight:true,
     billsAutoHeight:true,
-    rationAutoHeight:false,
-    disPlayMainMaterial:true
+    rationAutoHeight:true,
+    disPlayMainMaterial:false
 };
 
 const tenderSetting = {
@@ -80,12 +80,13 @@ const billsQuantityDecimal = [
 const basicInformation = [
     {dispName: '基本信息', key: 'basicInfo', items: [
         {dispName: '合同号', key: 'contractNum', value: ''},
-        {dispName: '工程专业', key: 'engineering', value: ''},//只读,用户新建单位工程时选择的值
+       // {dispName: '工程专业', key: 'engineering', value: ''},//只读,用户新建单位工程时选择的值
         {dispName: '建设地点', key: 'constructionPlace', value: ''},
         {dispName: '质量标准', key: 'qualityStandard', value: ''},
         {dispName: '工程类别', key: 'projectCategory', value: ''},
         {dispName: '建设日期', key: 'constructionDate', value: ''},
         {dispName: '工程规模', key: 'projectScale', value: ''},
+        {dispName: '总建筑面积(m2)', key: 'grossArea', value: ''},
         {dispName: '建设单位', key: 'constructionUnit', value: ''},
         {dispName: '设计单位', key: 'designUnit', value: ''},
         {dispName: '施工单位', key: 'buildingUnit', value: ''},
@@ -116,6 +117,7 @@ const basicInformation = [
 ];
 
 const projectFeature = [
+    {dispName: '工程专业', key: 'engineering', value: ''},//只读,用户新建单位工程时选择的值
     {dispName: '工程类型', key: 'projType', value: ''},
     {dispName: '结构类型', key: 'structureType', value: ''},
     {dispName: '基础类型', key: 'baseType', value: ''},

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

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

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

@@ -24,6 +24,9 @@ module.exports = function (app) {
     /*
      req.body = {data: '{user_id}'}
      */
+
+    pmRouter.post('/prepareInitialData', pmController.prepareInitialData);
+
     pmRouter.post('/getProjects', pmController.getProjects);
     pmRouter.post('/getSummaryInfo', pmController.getSummaryInfo);
 
@@ -48,6 +51,7 @@ module.exports = function (app) {
     pmRouter.post('/getUnitFile', pmController.getUnitFileList);
     pmRouter.post('/getFeeRateFile', pmController.getFeeRateFileList);
     pmRouter.post('/updateFiles', pmController.updateFiles);
+    pmRouter.post('/defaultSettings', pmController.defaultSettings);
     //GC
     pmRouter.post('/getGCDatas', pmController.getGCDatas);
     pmRouter.post('/recGC', pmController.recGC);
@@ -55,7 +59,8 @@ module.exports = function (app) {
     //share
     pmRouter.post('/getProjectShareInfo', pmController.projectShareInfo);
     pmRouter.post('/share', pmController.share);
-    pmRouter.post('/getShareProjects', pmController.getShareProjects);
+    pmRouter.post('/receiveProjects', pmController.receiveProjects);
+    pmRouter.post('/changeFile', pmController.changeFile);
 
     app.use('/pm/api', pmRouter);
 };

+ 24 - 4
modules/ration_glj/controllers/ration_glj_controller.js

@@ -10,6 +10,7 @@ module.exports={
     createRationGLJ:createRationGLJ,
     testGetQuantify:testGetQuantify,
     getGLJData:getGLJData,
+    getGLJDataByCodes:getGLJDataByCodes,
     addGLJ:addGLJ,
     replaceGLJ:replaceGLJ,
     mReplaceGLJ:mReplaceGLJ,
@@ -38,6 +39,24 @@ async function testGetQuantify() {
     }
 }
 
+async function getGLJDataByCodes(req,res){
+    let result={
+        error:0
+    }
+    try {
+        let data = req.body.data;
+        data = JSON.parse(data);
+        let datas= await ration_glj_facade.getGLJDataByCodes(data,req.session.sessionCompilation);
+        result.data=datas;
+    }catch (err){
+        logger.err(err);
+        result.error=1;
+        result.message = err.message;
+    }
+    res.json(result);
+}
+
+
 async function getGLJData(req, res) {
     let result={
         error:0
@@ -49,6 +68,8 @@ async function getGLJData(req, res) {
                 result.error=1;
                 result.message = err.message;
             }else {
+                //多单价字段
+                if(req.session.sessionCompilation.priceProperties) datas.priceProperties = req.session.sessionCompilation.priceProperties;
                 result.datas = datas;
             }
             res.json(result);
@@ -68,7 +89,7 @@ async function addGLJ(req, res){
     try {
         let data = req.body.data;
         data = JSON.parse(data);
-        let datas= await ration_glj_facade.addGLJ(data);
+        let datas= await ration_glj_facade.addGLJ(data,req.session.sessionCompilation);
         result.data=datas;
     }catch (err){
         logger.err(err);
@@ -85,8 +106,7 @@ async function replaceGLJ(req, res){
     try {
         let data = req.body.data;
         data = JSON.parse(data);
-        console.log(data);
-        let rdata= await ration_glj_facade.replaceGLJ(data);
+        let rdata= await ration_glj_facade.replaceGLJ(data,req.session.sessionCompilation);
         result.data=rdata;
     }catch (err){
         logger.err(err);
@@ -103,7 +123,7 @@ async function mReplaceGLJ(req, res){
     try {
         let data = req.body.data;
         data = JSON.parse(data);
-        let mresult= await ration_glj_facade.mReplaceGLJ(data);
+        let mresult= await ration_glj_facade.mReplaceGLJ(data,req.session.sessionCompilation);
         result.data=mresult;
     }catch (err){
         logger.err(err);

+ 0 - 0
modules/ration_glj/facade/glj_calculate_facade.js


Неке датотеке нису приказане због велике количине промена