Browse Source

Merge branch '1.0.0_online' of http://smartcost.f3322.net:3000/SmartCost/ConstructionOperation into 1.0.0_online

TonyKang 7 years ago
parent
commit
35fcdbc2db
70 changed files with 2428 additions and 516 deletions
  1. 13 2
      config/config.js
  2. 8 3
      config/menu.js
  3. 35 0
      modules/all_models/block_lib_model.js
  4. 1 1
      modules/all_models/compleGlj_glj.js
  5. 23 0
      modules/all_models/compleGlj_section.js
  6. 30 0
      modules/all_models/compleGlj_sectionTemplate.js
  7. 1 1
      modules/all_models/compleRation_ration.js
  8. 31 0
      modules/all_models/compleRation_section.js
  9. 5 5
      modules/all_models/comple_section_template.js
  10. 1 1
      modules/all_models/counter.js
  11. 32 0
      modules/all_models/log.js
  12. 16 0
      modules/all_models/options.js
  13. 49 0
      modules/all_models/permission.js
  14. 26 0
      modules/all_models/permission_group.js
  15. 26 0
      modules/all_models/ration_template.js
  16. 30 0
      modules/all_models/setting.js
  17. 3 0
      modules/all_models/stdRation_coe.js
  18. 39 0
      modules/all_models/user_message.js
  19. 37 17
      modules/common/base/base_controller.js
  20. 19 39
      modules/ration_repository/controllers/ration_section_tree_controller.js
  21. 9 9
      modules/ration_repository/controllers/search_controller.js
  22. 2 2
      modules/ration_repository/models/glj_repository.js
  23. 3 14
      modules/ration_repository/models/ration_item.js
  24. 22 0
      modules/ration_repository/models/ration_section_tree.js
  25. 3 0
      modules/ration_repository/models/repository_map.js
  26. 3 1
      modules/ration_repository/routes/ration_rep_routes.js
  27. 1 2
      modules/std_glj_lib/controllers/gljController.js
  28. 19 0
      modules/std_glj_lib/controllers/gljMapController.js
  29. 21 29
      modules/std_glj_lib/models/gljMapModel.js
  30. 34 27
      modules/std_glj_lib/models/gljModel.js
  31. 2 0
      modules/std_glj_lib/routes/routes.js
  32. 12 0
      modules/sys_tools/controllers/sys_controller.js
  33. 37 5
      modules/sys_tools/models/sys_model.js
  34. 1 0
      modules/sys_tools/routes/routes.js
  35. 136 1
      modules/users/controllers/login_controller.js
  36. 276 45
      modules/users/controllers/manager_controller.js
  37. 3 0
      modules/users/controllers/tool_controller.js
  38. 40 4
      modules/users/controllers/user_controller.js
  39. 40 5
      modules/users/models/manager_model.js
  40. 120 0
      modules/users/models/permission_group_model.js
  41. 77 0
      modules/users/models/permission_model.js
  42. 59 1
      modules/users/models/user_model.js
  43. 14 2
      modules/users/routes/manager_route.js
  44. 2 1
      modules/users/routes/user_route.js
  45. 13 2
      public/counter/counter.js
  46. 20 0
      public/web/sheet/sheet_common.js
  47. 2 0
      robots.txt
  48. 72 21
      web/common/js/slideResize.js
  49. 20 5
      web/maintain/billsGuidance_lib/js/billsGuidance.js
  50. 3 9
      web/maintain/bills_lib/scripts/bills_lib_ajax.js
  51. 12 7
      web/maintain/ration_repository/dinge.html
  52. 48 21
      web/maintain/ration_repository/js/coe.js
  53. 6 3
      web/maintain/ration_repository/js/gljSelect.js
  54. 1 0
      web/maintain/ration_repository/js/global.js
  55. 53 14
      web/maintain/ration_repository/js/main.js
  56. 6 4
      web/maintain/ration_repository/js/ration.js
  57. 14 4
      web/maintain/ration_repository/js/ration_template.js
  58. 65 7
      web/maintain/ration_repository/js/section_tree.js
  59. 26 2
      web/maintain/ration_repository/main.html
  60. 27 3
      web/maintain/std_glj_lib/html/main.html
  61. 43 29
      web/maintain/std_glj_lib/js/glj.js
  62. 47 10
      web/maintain/std_glj_lib/js/main.js
  63. 110 0
      web/users/js/manager.js
  64. 31 1
      web/users/js/user.js
  65. 1 0
      web/users/views/layout/layout.html
  66. 137 0
      web/users/views/manager/authority.html
  67. 82 16
      web/users/views/manager/index.html
  68. 172 122
      web/users/views/tool/index.html
  69. 46 16
      web/users/views/user/index.html
  70. 10 3
      web/users/views/user/test_user.html

File diff suppressed because it is too large
+ 13 - 2
config/config.js


+ 8 - 3
config/menu.js

@@ -22,12 +22,12 @@ let menuData = {
                 title: '普通用户',
                 url: '/user',
                 name: 'index',
-            }/*,
-            'test-user' : {
+            },
+            'testUser' : {
                 title: '测试用户',
                 url: '/user/test-user',
                 name: 'test-user',
-            }*/
+            }
         }
     },
     'notify': {
@@ -59,6 +59,11 @@ let menuData = {
                 url: '/manager',
                 name: 'index',
             },
+            'authority' : {
+                title: '权限组',
+                url: '/manager/authority',
+                name: 'authority',
+            },
             'admin' : {
                 title: '超级管理员',
                 url: '/manager/admin',

+ 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');

+ 1 - 1
modules/all_models/compleGlj_glj.js

@@ -16,7 +16,7 @@ const comple_gljComponent = new Schema(
 );
 //补充工料机跟用户和编办绑定
 const comple_glj = new Schema({
-    userId: Number,
+    userId: String,
     compilationId: String,
     ID: Number,
     code: String,

+ 23 - 0
modules/all_models/compleGlj_section.js

@@ -0,0 +1,23 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2018/1/2
+ * @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/1/2
+ * @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');
+

+ 1 - 1
modules/all_models/compleRation_ration.js

@@ -35,7 +35,7 @@ const rationInstSchema = new Schema({
 
 //补充定额
 const compleRationSchema = new Schema({
-    userId: Number,
+    userId: String,
     compilationId: String,
     rationRepId: Number,
     ID:Number,

+ 31 - 0
modules/all_models/compleRation_section.js

@@ -0,0 +1,31 @@
+/**
+ * Created by Zhong on 2018/3/22.
+ */
+/*补充定额库-章节树*/
+const mongoose = require('mongoose');
+const Schema = mongoose.Schema;
+const deleteSchema = require('../all_schemas/delete_schema');
+//补充定额章节树
+const compleRationSectionTreeSchema = new Schema({
+    //用户名
+    userId: String,
+    //编办
+    compilationId: String,
+    //标准定额库
+    //rationRepId: Number,
+    //名称
+    name: String,
+    //是否是同层第一个节点
+   // 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');

+ 5 - 5
modules/all_models/comple_section_template.js

@@ -9,11 +9,11 @@
  */
 
 /*
-* 我的补充定额库章节树模板,一个费用定额有一个模板
-* 模板的生成目前由手工生成(借助定额库编辑器的章节树编辑)
-* 新用户第一次进入某费用定额的补充定额库时,拷贝模板给该用户
-*
-* */
+ * 我的补充定额库章节树模板,一个费用定额有一个模板
+ * 模板的生成目前由手工生成(借助定额库编辑器的章节树编辑)
+ * 新用户第一次进入某费用定额的补充定额库时,拷贝模板给该用户
+ *
+ * */
 
 import mongoose from 'mongoose';
 

+ 1 - 1
modules/all_models/counter.js

@@ -6,5 +6,5 @@ var Schema = mongoose.Schema;
 var counterSchema = new Schema({
     _id: String,
     sequence_value: Number
-});
+},{versionKey:false});
 mongoose.model("counters_operation", counterSchema,"counters_operation");

+ 32 - 0
modules/all_models/log.js

@@ -0,0 +1,32 @@
+/**
+ * 日志数据结构
+ *
+ * @author CaiAoLin
+ * @date 2017/7/27
+ * @version
+ */
+import mongoose from "mongoose";
+
+let Schema = mongoose.Schema;
+let collectionName = 'log';
+let messageSchema = new Schema({
+    ip: String,
+    ip_info: String,
+    browser: String,
+    os: String
+}, {_id: false});
+let modelSchema = {
+    // 日志类型
+    type: {
+        type: Number
+    },
+    // 日志内容
+    message: messageSchema,
+    // 关联用户id
+    user_id: {
+        type: String
+    },
+    // 创建时间
+    create_time: Number
+};
+mongoose.model(collectionName, new Schema(modelSchema, {versionKey: false, collection: collectionName}));

+ 16 - 0
modules/all_models/options.js

@@ -0,0 +1,16 @@
+/**
+ * Created by Zhong on 2018/3/22.
+ */
+/*选项*/
+const mongoose = require('mongoose');
+const Schema = mongoose.Schema;
+const optionSchema = new Schema({
+    user_id: String,
+    compilation_id: String,
+    options: {
+        type: Schema.Types.Mixed,
+        default: {}
+    }
+}, {versionKey: false});
+
+mongoose.model('options', optionSchema, 'options');

+ 49 - 0
modules/all_models/permission.js

@@ -0,0 +1,49 @@
+/**
+ * 后台管理权限数据模型
+ *
+ * @author EllisRan
+ * @date 2018/12/06
+ * @version
+ */
+import mongoose from "mongoose";
+
+let Schema = mongoose.Schema;
+let collectionName = 'permission';
+let modelSchema = {
+    // ID
+    ID: {
+        type: Number,
+        default: 0
+    },
+    // 权限名称
+    name: {
+        type: String,
+        index: true
+    },
+    // 控制器名称
+    controller: String,
+    // 针对工具里一个页面多个控制器的问题(特殊优化)
+    otherController: String,
+    // 方法名称
+    action: String,
+    // 路径
+    url: String,
+    // 图标类名
+    iconClass: String,
+    // 父级id(初始默认0为父级)
+    pid: {
+        type: Number,
+        default: 0
+    },
+    // 是否属于菜单列表里的
+    isMenu: {
+        type: Boolean,
+        default: true
+    },
+    // 创建时间
+    create_time: {
+        type: Number,
+        default: 0
+    },
+};
+mongoose.model(collectionName, new Schema(modelSchema, {versionKey: false, collection: collectionName}));

+ 26 - 0
modules/all_models/permission_group.js

@@ -0,0 +1,26 @@
+/**
+ * 后台管理权限组数据模型
+ *
+ * @author EllisRan
+ * @date 2018/12/06
+ * @version
+ */
+import mongoose from "mongoose";
+
+let Schema = mongoose.Schema;
+let collectionName = 'permission_group';
+let modelSchema = {
+    // 组名
+    name: {
+        type: String,
+        index: true
+    },
+    // 权限ID JSON列表
+    permission: String,
+    // 创建时间
+    create_time: {
+        type: Number,
+        default: 0
+    },
+};
+mongoose.model(collectionName, new Schema(modelSchema, {versionKey: false, collection: collectionName}));

+ 26 - 0
modules/all_models/ration_template.js

@@ -0,0 +1,26 @@
+/**
+ * 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,
+        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");

+ 30 - 0
modules/all_models/setting.js

@@ -0,0 +1,30 @@
+/**
+ * 个人设置数据结构
+ *
+ * @author CaiAoLin
+ * @date 2017/7/27
+ * @version
+ */
+import mongoose from "mongoose";
+
+let Schema = mongoose.Schema;
+let collectionName = 'setting';
+let modelSchema = {
+    // 设置类型
+    type: {
+        type: Number,
+        index: true
+    },
+    // 设置内容
+    data: {
+        type: Schema.Types.Mixed,
+    },
+    // 关联用户id
+    user_id: {
+        type: String,
+        index: true
+    },
+    // 创建时间
+    create_time: Number
+};
+mongoose.model(collectionName, new Schema(modelSchema, {versionKey: false, collection: collectionName}));

+ 3 - 0
modules/all_models/stdRation_coe.js

@@ -23,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});
 

+ 39 - 0
modules/all_models/user_message.js

@@ -0,0 +1,39 @@
+/**
+ * 用户消息数据模型
+ *
+ * @author CaiAoLin
+ * @date 2017/9/22
+ * @version
+ */
+let mongoose = require("mongoose");
+let Schema = mongoose.Schema;
+
+// 表名
+let collectionName = 'user_message';
+
+// 表结构
+let schema = {
+    // 用户id
+    user_id: {
+        type: String,
+    },
+    // 是否已读
+    is_read: {
+        type: Number,
+        default: 0
+    },
+    // 是否删除
+    is_delete: {
+        type: Number,
+        default: 0
+    },
+    // 消息关联数据
+    message: {
+        type: Schema.Types.ObjectId,
+        ref: 'message'
+    },
+    // 创建时间
+    create_time: Number,
+};
+
+mongoose.model(collectionName, new Schema(schema, {versionKey: false}));

+ 37 - 17
modules/common/base/base_controller.js

@@ -8,7 +8,7 @@
 import crypto from "crypto";
 import Url from "url";
 import Moment from "moment";
-import menuData from "../../../config/menu";
+// import menuData from "../../../config/menu";
 
 class BaseController {
 
@@ -65,35 +65,55 @@ class BaseController {
             console.log('enterINit');
             // 如果不适超级管理员则判断权限
             let sessionManager = request.session.managerData;
+            let MenuPermission = sessionManager.menuData;
             if (sessionManager.superAdmin !== 1) {
-                let currentPermission = sessionManager.permission;
-                // 校验权限
+                let currentPermission = sessionManager.toolPermission;
+                // MenuPermission = sessionManager.menuData;
+                // 校验权限 暂时只检测能否使用该controller名称的总权限,不细分
                 currentPermission = currentPermission.split(',');
                 let withoutPermission = ['login', 'dashboard'];
-                // 工具页面整合
-                let toolPermission = ['rationRepository', 'stdBillsmain', 'stdGljRepository'];
-                let hasToolPermission = false;
-                if (controller === 'tool') {
-                    for (let tmpPermission of toolPermission) {
-                        if (currentPermission.indexOf(tmpPermission) >= 0) {
-                            hasToolPermission = true;
-                            break;
-                        }
+
+                // 工具
+                let toolAllPermission = sessionManager.toolAllPermission;
+                toolAllPermission = toolAllPermission.split(',');
+                // let toolAllPermission = ['stdBillsmain', 'rationRepository', 'rpt_tpl', 'stdGljRepository',
+                //     'billsGuidance', 'clearJunk', 'billsTemplate', 'mainTreeCol',
+                //     'materialReplace', 'projectFeature', 'feeRate', 'calcProgram'];
+                let hasToolPermission = true;
+                if (toolAllPermission.indexOf(controller) >= 0 && currentPermission.indexOf(controller) < 0) {
+                    hasToolPermission = false;
+                }
+
+                let currentControllerPermission = '';
+                // let currentActionPermission = true;
+
+                if(withoutPermission.indexOf(controller) < 0) {
+                    if (MenuPermission.hasOwnProperty(controller)) {
+                        currentControllerPermission = MenuPermission[controller];
+
                     }
+
+                    // if (currentControllerPermission !== '' && action !== 'index') {
+                    //     if (currentControllerPermission.children.hasOwnProperty(action)) {
+                    //         currentActionPermission = true;
+                    //     }
+                    // } else if (action === 'index') {
+                    //     currentActionPermission = true
+                    // }
                 }
 
-                if (!hasToolPermission && withoutPermission.indexOf(controller) < 0 &&
-                    (currentPermission.length <= 0 || currentPermission.indexOf(controller)) < 0) {
+                if (withoutPermission.indexOf(controller) < 0 &&
+                    !(hasToolPermission || currentControllerPermission !== '')) {
 
                     throw '没有权限';
                 }
             }
 
             // 菜单数据
-            response.locals.menu = menuData;
+            response.locals.menu = MenuPermission;
             // 二级菜单数据
-            response.locals.secondMenu = menuData[controller] !== undefined && menuData[controller].children !== undefined ?
-                menuData[controller].children : {};
+            response.locals.secondMenu = MenuPermission[controller] !== undefined && MenuPermission[controller].children !== undefined ?
+                MenuPermission[controller].children : {};
 
             // url相关数据
             response.locals.urlQuery = JSON.stringify(urlInfo.query);

+ 19 - 39
modules/ration_repository/controllers/ration_section_tree_controller.js

@@ -9,6 +9,25 @@ var callback = function(req,res,err,message, data){
 }
 
 class RationChapterTreeController extends BaseController{
+    //某费用定额下补充定额库章节树模板数据条数
+    async sectionTemplateCount(req, res) {
+        try {
+            let count = await rationChapterTreeData.sectionTemplateCount(req.params.compilationId);
+            callback(req, res, 0, 'success', {count});
+        } catch (err) {
+            callback(req, res, 1, err, {count: 0});
+        }
+    }
+    //将该标准定额库的章节树设置为该费用定额下补充定额章节树的模板
+    async initSectionTemplate(req, res) {
+        try {
+            let data = JSON.parse(req.body.data);
+            await rationChapterTreeData.initSectionTemplate(data.rationLibId, data.compilationId);
+            callback(req, res, 0, 'success', null);
+        } catch (err) {
+            callback(req, res, 1, err, null)
+        }
+    }
     getRationChapterTree(req,res){
         let data = JSON.parse(req.body.data);
         var rationLibId = data.rationLibId;
@@ -97,42 +116,3 @@ class RationChapterTreeController extends BaseController{
 }
 
 export default RationChapterTreeController;
-
-/*
-module.exports ={
-    getRationChapterTree: function(req,res){
-        var rationLibId = req.body.rationLibId;
-        var repId = req.body.rationRepositoryId;
-        if (rationLibId) {
-            rationChapterTreeData.getRationChapterTree(rationLibId,function(err,data){
-                callback(req,res,err, "", data);
-            })
-        } else if (repId) {
-            rationChapterTreeData.getRationChapterTreeByRepId(repId,function(err,data){
-                callback(req,res,err,"", data)
-            })
-        }
-    },
-    createNewNode: function(req, res){
-        var libId = req.body.rationLibId;
-        var lastNodeId = req.body.lastNodeId;
-        var nodeData = JSON.parse(req.body.rawNodeData);
-        rationChapterTreeData.createNewNode(libId, lastNodeId, nodeData, function(err,data){
-            callback(req,res,err,"", data)
-        });
-    },
-    updateNodes: function(req, res) {
-        var nodes = JSON.parse(req.body.nodes);
-        rationChapterTreeData.updateNodes(nodes, function(err,results){
-            callback(req,res, err, "", results)
-        });
-    },
-    deleteNodes: function(req, res) {
-        var nodes = JSON.parse(req.body.nodes);
-        var preNodeId = req.body.preNodeId;
-        var preNodeNextId = req.body.preNodeNextId;
-        rationChapterTreeData.removeNodes(nodes, preNodeId, preNodeNextId, function(err,results){
-            callback(req,res, err, "", results)
-        });
-    }
-}*/

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

@@ -8,15 +8,15 @@ var callback = function(req, res, err, message, data){
 };
 
 class SearchController extends BaseController{
-    getRationItem (req, res) {
-        var rId = req.body.rationLibId, code = req.body.code;
-        var rationData = {}
-        rationItem.getRationItem(rId, code).then(function (result) {
-            rationData = result._doc;
-            callback(req, res, null, '', rationData);
-        }).catch(function (err, message) {
-            callback(req, res, err, message, null);
-        })
+    async getRationItem (req, res) {
+        try {
+            let data = JSON.parse(req.body.data);
+            let rId = data.rationLibId, code = data.code;
+            let ration = await rationItem.getRationItem(rId, code);
+            callback(req, res, 0, '', ration);
+        } catch (err) {
+            callback(req, res, 1, err, null);
+        }
     }
     findRation (req, res) {
         var rId = req.body.rationLibId, keyword = req.body.keyword;

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

@@ -79,11 +79,11 @@ gljItemDAO.prototype.getStdCompleGljItems = async function (compleGljIds, stdGlj
     try{
         let rst = [];
         if(compleGljIds.length > 0){
-            let compleGlj = await compleGljModel.find({ID: {$in: compleGljIds}, deleteInfo: null}, {ID: 1, gljType: 1, basePrice: 1});
+            let compleGlj = await compleGljModel.find({ID: {$in: compleGljIds}}, {ID: 1, gljType: 1, basePrice: 1});
             rst = rst.concat(compleGlj);
         }
         if(stdGljIds.length > 0){
-            let stdGlj = await gljModel.find({ID: {$in: stdGljIds}, $or: [{deleted: null}, {deleted: false}]}, {ID: 1, gljType: 1, basePrice: 1});
+            let stdGlj = await gljModel.find({ID: {$in: stdGljIds}}, {ID: 1, gljType: 1, basePrice: 1, priceProperty: 1});
             rst = rst.concat(stdGlj);
         }
         callback(0, rst);

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

@@ -222,20 +222,9 @@ rationItemDAO.prototype.findRation = function (repId, keyword, callback) {
     })
 }
 
-rationItemDAO.prototype.getRationItem = function (repId, code, callback) {
-    if (callback) {
-        rationItemModel.findOne({rationRepId: repId, code: code, "$or": [{"isDeleted": null}, {"isDeleted": false}]}, '-_id').exec()
-            .then(function (result, err) {
-                if (err) {
-                    callback(1, '找不到定额“' + code +'”' , null);
-                } else {
-                    callback(0, '', result);
-                }
-            });
-        return null;
-    } else {
-        return rationItemModel.findOne({rationRepId: repId, code: code, "$or": [{"isDeleted": null}, {"isDeleted": false}]}, '-_id').exec();
-    }
+rationItemDAO.prototype.getRationItem = async function (repId, code) {
+    let ration = await rationItemModel.findOne({rationRepId: repId, code: code});
+    return ration;
 };
 
 rationItemDAO.prototype.addRationItems = function(rationLibId, lastOpr, sectionId, items,callback){

+ 22 - 0
modules/ration_repository/models/ration_section_tree.js

@@ -8,8 +8,30 @@ let counter = require('../../../public/counter/counter');
 let rationRepositoryDao = require('./repository_map');
 const rationChapterTreeModel = mongoose.model('std_ration_lib_ration_chapter_trees');
 const rationModel = mongoose.model('std_ration_lib_ration_items');
+const compleRationSectionTemp = mongoose.model('complementary_ration_section_templates');
 var rationChapterTreeDAO = function(){};
 
+rationChapterTreeDAO.prototype.sectionTemplateCount = async function (compilationId) {
+    return await compleRationSectionTemp.find({compilationId}).count();
+};
+
+rationChapterTreeDAO.prototype.initSectionTemplate = async function (rationLibId, compilationId) {
+    let sectionTempCount = await compleRationSectionTemp.find({compilationId}).count();
+    if (sectionTempCount > 0) {
+        await compleRationSectionTemp.remove({compilationId});
+    }
+    let bulks = [];
+    let stdRationSection = await rationChapterTreeModel.find({rationRepId: rationLibId});
+    for (let data of stdRationSection) {
+        delete data._doc._id;
+        data._doc.compilationId = compilationId;
+        bulks.push({insertOne: {document: data}});
+    }
+    if (bulks.length > 0) {
+        await compleRationSectionTemp.bulkWrite(bulks);
+    }
+};
+
 rationChapterTreeDAO.prototype.getRationChapterTree = function(rationLibId,callback){
     rationChapterTreeModel.find({"rationRepId": rationLibId, "$or": [{"isDeleted": null}, {"isDeleted": false} ]},function(err,data){
         if(data.length) callback(0,data);

+ 3 - 0
modules/ration_repository/models/repository_map.js

@@ -136,6 +136,9 @@ rationRepositoryDao.prototype.getRepositoryById = function(repId,callback = null
 
 rationRepositoryDao.prototype.addRationRepository = function( rationLibObj,callback){
     counter.counterDAO.getIDAfterCount(counter.moduleName.rationMap, 1, function(err, result){
+        if (!result) {
+            callback('获取不到新的库ID,创建失败', null);
+        }
         var rMap = createNewLibModel(rationLibObj);
         rMap.ID = result.sequence_value;
         new rationRepository(rMap).save(function(err, result) {

+ 3 - 1
modules/ration_repository/routes/ration_rep_routes.js

@@ -32,8 +32,8 @@ module.exports =  function (app) {
 
     apiRouter.post("/getCompilationList", rationRepositoryController.auth, rationRepositoryController.init, rationRepositoryController.getCompilationList);
     apiRouter.post("/getRationLibsByCompilation", rationRepositoryController.auth, rationRepositoryController.init, rationRepositoryController.getRationLibsByCompilation);
-
     apiRouter.post("/getRationLib",rationRepositoryController.auth, rationRepositoryController.init, rationRepositoryController.getRationLib);
+
     apiRouter.post("/getRationDisplayNames",rationRepositoryController.auth, rationRepositoryController.init, rationRepositoryController.getDisPlayRationLibs);
     apiRouter.post("/editRationLibs",rationRepositoryController.auth, rationRepositoryController.init, rationRepositoryController.updateRationRepositoryName);
     apiRouter.post("/addRationRepository",rationRepositoryController.auth, rationRepositoryController.init, rationRepositoryController.addRationRepository);
@@ -41,6 +41,8 @@ module.exports =  function (app) {
     apiRouter.post("/getRealLibName",rationRepositoryController.auth, rationRepositoryController.init, rationRepositoryController.getRealLibName);
     apiRouter.post("/getLibIDByName",rationRepositoryController.auth, rationRepositoryController.init, rationRepositoryController.getLibIDByName);
 
+    apiRouter.get('/sectionTemplateCount/:compilationId', rationChapterTreeController.auth, rationChapterTreeController.init, rationChapterTreeController.sectionTemplateCount);
+    apiRouter.post('/initSectionTemplate', rationChapterTreeController.auth, rationChapterTreeController.init, rationChapterTreeController.initSectionTemplate);
     apiRouter.post("/getRationTree",rationChapterTreeController.auth, rationChapterTreeController.init, rationChapterTreeController.getRationChapterTree);
     apiRouter.post("/getNewRationTreeID",rationChapterTreeController.auth, rationChapterTreeController.init, rationChapterTreeController.getNewRationTreeID);
     apiRouter.post("/createNewNode",rationChapterTreeController.auth, rationChapterTreeController.init, rationChapterTreeController.createNewNode);

+ 1 - 2
modules/std_glj_lib/controllers/gljController.js

@@ -13,7 +13,6 @@ const gljModel = mongoose.model('std_glj_lib_gljList');
 const stdRationModel = mongoose.model('std_ration_lib_ration_items');
 const cplRationModel = mongoose.model('complementary_ration_items');
 const fs = require('fs');
-
 let gljDao = new GljDao();
 let callback = function(req, res, err, message, data){
     res.json({error: err, message: message, data: data});
@@ -227,7 +226,7 @@ class GljController extends BaseController{
                 }
                 //更新人材机价格
                 await gljDao.batchUpdateGljPrice(gljLibId, sheet[0].data);
-
+                console.log('endeeee');
                 // 删除文件
                 if(uploadFullName && fs.existsSync(uploadFullName)){
                     fs.unlink(uploadFullName);

+ 19 - 0
modules/std_glj_lib/controllers/gljMapController.js

@@ -11,6 +11,25 @@ let callback = function(req, res, err, message, data){
     res.json({error: err, message: message, data: data});
 };
 class GljMapController extends BaseController{
+    //该费用定额下补充人材机分类树模板数据条数
+    async classTemplateCount(req, res) {
+        try {
+            let count = await gljMapDao.classTemplateCount(req.params.compilationId);
+            callback(req, res, 0, 'success', {count});
+        } catch (err) {
+            callback(req, res, 1, err, {count: 0});
+        }
+    }
+    //将该标准人材机库的分类树设置为该费用定额下补充人材机分类树的模板
+    async initClassTemplate(req, res) {
+        try {
+            let data = JSON.parse(req.body.data);
+            await gljMapDao.initClassTemplate(data.gljLibId, data.compilationId);
+            callback(req, res, 0, 'success', null);
+        } catch (err) {
+            callback(req, res, 1, err, null);
+        }
+    }
     async getCompilationList(req, res){
         try{
             let compilationModel = new CompilationModel(), rst = [];

+ 21 - 29
modules/std_glj_lib/models/gljMapModel.js

@@ -5,9 +5,9 @@ const mongoose = require('mongoose');
 const gljMapModel = mongoose.model('std_glj_lib_map');
 const gljModel = mongoose.model('std_glj_lib_gljList');
 const gljClassModel = mongoose.model('std_glj_lib_gljClass');
-const gljClassTemplateModel = mongoose.model('std_glj_lib_gljClassTemplate');
 const rationRepository = mongoose.model('std_ration_lib_map');
 const engLibModel = mongoose.model('engineering_lib');
+const compleGljClassTemp = mongoose.model('complementary_glj_section_templates');
 import moment from "moment";
 import counter from "../../../public/counter/counter";
 import async from "async";
@@ -121,34 +121,7 @@ class GljMapDao extends OprDao{
                         callback(err, '创建新工料机库失败!', null);
                     }
                     else{
-                        //创建分类模板
-                        gljClassTemplateModel.find({'$or': [{isDeleted: null}, {isDeleted: false}, {deleted: false}]}, function (err, datas) {
-                            if(err){
-                                callback(err, "获取工料机类型错误!", null);
-                            }
-                            else{
-                                let rst = [];
-                                async.each(datas, function (data, cb) {
-                                    let newClassObj = {};
-                                    newClassObj.ID = data.ID;
-                                    newClassObj.ParentID = data.ParentID;
-                                    newClassObj.NextSiblingID = data.NextSiblingID;
-                                    newClassObj.Name = data.Name;
-                                    newClassObj.repositoryId = newGljLib.ID;
-                                    newClassObj.deleted = false;
-                                    gljClassModel.create(newClassObj, function(err){
-                                        if(err)cb(err);
-                                        else{
-                                            rst.push(newClassObj);
-                                            cb(null);
-                                        }
-                                    });
-                                }, function (err) {
-                                    if(err) callback(err, "新增工料机类型错误!", null);
-                                    else callback(null, '创建成功', result);
-                                });
-                            }
-                        });
+                        callback(null, '创建成功', result);
                     }
                 });
             }
@@ -246,6 +219,25 @@ class GljMapDao extends OprDao{
             }
         });
     }
+    async classTemplateCount (compilationId) {
+        return await compleGljClassTemp.find({compilationId}).count();
+    }
+    async initClassTemplate (gljLibId, compilationId) {
+        let classTempCount = await compleGljClassTemp.find({compilationId}).count();
+        if (classTempCount > 0) {
+            await compleGljClassTemp.remove({compilationId});
+        }
+        let bulks = [];
+        let stdGljClass = await gljClassModel.find({repositoryId: gljLibId});
+        for (let data of stdGljClass) {
+            delete data._doc._id;
+            data._doc.compilationId = compilationId;
+            bulks.push({insertOne: {document: data}});
+        }
+        if (bulks.length > 0) {
+            await compleGljClassTemp.bulkWrite(bulks);
+        }
+    }
 }
 
 export {OprDao, GljMapDao};

+ 34 - 27
modules/std_glj_lib/models/gljModel.js

@@ -5,9 +5,9 @@ const mongoose = require('mongoose');
 const gljMapModel = mongoose.model('std_glj_lib_map');
 const gljModel = mongoose.model('std_glj_lib_gljList');
 const gljClassModel = mongoose.model('std_glj_lib_gljClass');
-const gljClassTemplateModel = mongoose.model('std_glj_lib_gljClassTemplate');
 const compilationModel = mongoose.model('compilation');
 const scMathUtil = require('../../../public/scMathUtil').getUtil();
+const rationModel = mongoose.model('std_ration_lib_ration_items');
 import {OprDao} from  "./gljMapModel";
 import moment from "moment";
 import counter from "../../../public/counter/counter";
@@ -45,22 +45,13 @@ class GljDao  extends OprDao{
     }
 
     async getGljItemsByRep(repositoryId,callback = null){
-   /*     let me = this;
-        if (callback === null) {
-            return gljModel.find({"repositoryId": repositoryId});
-        } else {
-            gljModel.find({"repositoryId": repositoryId},function(err,data){
-                if(err) callback(true, "")
-                else {
-                    me.sortToNumber(data);
-                    callback(false,data);
-                }
-            })
-        }*/
-
-        let me = this;
-        let rst = [];
-        //批量获取异步
+        try {
+            let rst = await gljModel.find({repositoryId: repositoryId});
+            callback(0, rst);
+        } catch (err) {
+            callback(1, null);
+        }
+        /*//批量获取异步
         let functions = [];
         let count = await gljModel.find({repositoryId: repositoryId, $or: [{deleted: null}, {deleted: false}]}).count();
         let findCount = Math.ceil(count/500);
@@ -82,7 +73,7 @@ class GljDao  extends OprDao{
                 me.sortToNumber(rst);
                 callback(0, rst);
             }
-        });
+        });*/
     }
 
     getGljItemByType (repositoryId, type, callback){
@@ -540,24 +531,37 @@ class GljDao  extends OprDao{
         let updateBulk = [];
         //避免重复
         let updateCodes = [];
+        //库中存在的人材机
+        let dateA = Date.now();
+        let existGljs = await gljModel.find({repositoryId: gljLibId}, '-_id code ID');
+        let existMapping = {};
+        for (let glj of existGljs) {
+            existMapping[glj.code] = glj;
+        }
         for(let row = 0; row < sheetData.length; row++){
             if(row === 0){
                 continue;
             }
-            let gljCode = sheetData[row][colMapping.code];
-            if(gljCode && gljCode !== '' && !updateCodes.includes(gljCode)){
+            let gljCode = sheetData[row][colMapping.code],
+                existGlj = existMapping[gljCode];
+            //更新多单价、不覆盖priceProperty字段,覆盖priceProperty下的子字段'priceProperty.x'
+            if(gljCode && gljCode !== '' && !updateCodes.includes(gljCode) && existGlj){
                 if(priceProperties.length > 0){
-                    let priceProperty = {};
                     for(let priceProp of priceProperties){
                         let dataCode = priceProp.price.dataCode;
                         let priceCellData = sheetData[row][colMapping[dataCode]];
-                        priceProperty[dataCode] = colMapping[dataCode] && priceCellData && !isNaN(priceCellData) ?
+                        //Excel中没有这个单价则跳过
+                        if (!colMapping[dataCode]) {
+                            continue;
+                        }
+                        let updateSet = {};
+                        updateSet['priceProperty.' + dataCode] = priceCellData && !isNaN(priceCellData) ?
                             scMathUtil.roundTo(parseFloat(priceCellData), -2) : 0;
+                        updateBulk.push({
+                            updateOne: {filter: {ID: existGlj.ID}, update: {$set: updateSet}}
+                        });
                     }
                     updateCodes.push(gljCode);
-                    updateBulk.push({
-                        updateOne: {filter: {repositoryId: gljLibId, code: gljCode}, update: {$set: {priceProperty: priceProperty}}}
-                    });
                 }
                 else {
                     if(colMapping.basePrice){
@@ -566,14 +570,17 @@ class GljDao  extends OprDao{
                             scMathUtil.roundTo(priceCellData, -2) : 0;
                         updateCodes.push(gljCode);
                         updateBulk.push({
-                            updateOne: {filter: {repositoryId: gljLibId, code: gljCode}, update: {$set: {basePrice: basePrice}}}
+                            updateOne: {filter: {ID: existGlj.ID}, update: {$set: {basePrice: basePrice}}}
                         });
                     }
                 }
             }
         }
         if(updateBulk.length > 0){
-            await gljModel.bulkWrite(updateBulk);
+            while (updateBulk.length > 0) {
+                let sliceBulk = updateBulk.splice(0, 1000);
+                await gljModel.bulkWrite(sliceBulk);
+            }
         }
 
     }

+ 2 - 0
modules/std_glj_lib/routes/routes.js

@@ -17,6 +17,8 @@ module.exports = function (app) {
     app.get('/stdGljRepository/main', viewsController.auth, viewsController.init, viewsController.redirectMain);
     app.get('/stdGljRepository/glj', viewsController.auth, viewsController.init, viewsController.redirectGlj);
 
+    router.get('/classTemplateCount/:compilationId', gljMapController.auth, gljMapController.init, gljMapController.classTemplateCount);
+    router.post('/initClassTemplate', gljMapController.auth, gljMapController.init, gljMapController.initClassTemplate);
     router.post('/getCompilationList', gljMapController.auth, gljMapController.init, gljMapController.getCompilationList);
     router.post('/getGljLib', gljMapController.auth, gljMapController.init, gljMapController.getGljLib);
     router.post('/getAllGljLib', gljMapController.auth, gljMapController.init, gljMapController.getAllGljLib);

+ 12 - 0
modules/sys_tools/controllers/sys_controller.js

@@ -26,6 +26,18 @@ class SysTools extends BaseController{
             callback(req, res, errCode, msg, null);
         });
     }
+
+    clearFakeData(req, res){
+        sysSchedule.clearFakeData(function (err) {
+            let msg = '清除成功';
+            let errCode = 0;
+            if(err){
+                msg = '清除失败';
+                errCode = 1;
+            }
+            callback(req, res, errCode, msg, null);
+        });
+    }
 }
 
 export {SysTools as default};

+ 37 - 5
modules/sys_tools/models/sys_model.js

@@ -22,12 +22,14 @@ const rationGljModel = mongoose.model('ration_glj');
 const rationCoeMolde = mongoose.model('ration_coe');
 const installationModel = mongoose.model('installation_fee');
 const rationInstallationModel = mongoose.model('ration_installation');
+const rationTemplateModel  = mongoose.model('ration_template')
 const quantityDetailModel = mongoose.model('quantity_detail');
 const unitPriceFileModel = mongoose.model('unit_price_file');
 const unitPriceModel = mongoose.model('unit_price');
 const mixRatioModel = mongoose.model('mix_ratio');
 const feeRateFileModel = mongoose.model('fee_rate_file');
 const feeRateModel = mongoose.model('fee_rates');
+const compleRationSection = mongoose.model('complementary_ration_section_tree');
 
 //删除垃圾数据
 async function clearJunkData(callback){
@@ -79,6 +81,10 @@ async function clearJunkData(callback){
         functions.push(function(cb){
             rationInstallationModel.remove({projectID: {$in: junkProjIds}}, cb);
         });
+        //清除ration_installation
+        functions.push(function(cb){
+            rationTemplateModel.remove({projectID: {$in: junkProjIds}}, cb);
+        });
         //清除quantity_detail
         functions.push(function(cb){
             quantityDetailModel.remove({projectID: {$in: junkProjIds}}, cb);
@@ -120,19 +126,45 @@ async function clearJunkData(callback){
                 //清除费率文件
                 await feeRateFileModel.remove({feeRateID: {$in: junkFFIds}});
             }
-            if(callback){
-                callback(err);
-            }
+            if(callback) callback(err);
         });
     }
     else {
-        callback(0);
+        if(callback) callback(0);
     }
+}
+
 
+
+//删除假删除数据
+/*
+* 1.之前的删除造价书数据,都是做的假删除,这部分数据会一直存在并且随着项目重复使用越来越多,现要改为真删除,所以做这个清除功能。
+* 2.原假删除包括清单的所有类型(大项费用、分部、分项、补项、清单)、定额的所有类型(定额、数量单价、与定额同级的人材机)
+* */
+async function clearFakeData(callback) {
+    let functions = [];
+    //删除清单
+    functions.push(function (cb) {
+        billsModel.remove({deleteInfo: {$exists: true}}, cb);
+    });
+    //删除定额
+    functions.push(function (cb) {
+        rationModel.remove({deleteInfo: {$exists: true}}, cb);
+    });
+    //删除补充定额章节树
+    functions.push(function (cb) {
+        compleRationSection.remove({deleteInfo: {$exists: true}}, cb);
+    });
+    async.parallel(functions, async function(err, result){
+        if(callback){
+            callback(err);
+        }
+    });
 }
 
 const sysSchedule = {
-    clearJunkData: clearJunkData
+    clearJunkData,
+    clearFakeData
 };
 
 //export {sysSchedule as default}

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

@@ -15,6 +15,7 @@ let sysToolsController = new SysToolsController();
 
 module.exports = function (app) {
     router.post('/clearJunkData', sysToolsController.auth, sysToolsController.init, sysToolsController.clearJunkData);
+    router.post('/clearFakeData', sysToolsController.auth, sysToolsController.init, sysToolsController.clearFakeData);
 
     app.use("/sysTools/api", router);
 

+ 136 - 1
modules/users/controllers/login_controller.js

@@ -7,6 +7,8 @@
  */
 import BaseController from "../../common/base/base_controller";
 import ManagerModel from "../models/manager_model";
+import PermissionModel from "../models/permission_model";
+import PermissionGroupModel from "../models/permission_group_model";
 import crypto from "crypto";
 
 import Test1Model from "../../../test/models/test1_model";
@@ -44,6 +46,8 @@ class LoginController extends BaseController {
         let username = request.body.username;
         let password = request.body.password;
         let managerModel = new ManagerModel();
+        let permissionModel = new PermissionModel();
+        let permissionGroupModel = new PermissionGroupModel();
 
         let responseData = {
             error: 0,
@@ -56,13 +60,144 @@ class LoginController extends BaseController {
             let currentTime = new Date().getTime();
             let sessionToken = crypto.createHmac('sha1', currentTime + '').update(managerData.username)
                 .digest().toString('base64');
+
+            // 对权限进行管理分类
+            let menuData = {
+                'dashboard': {
+                    title: '首页',
+                    url: '/dashboard',
+                    name: 'dashboard',
+                    iconClass: 'glyphicon glyphicon-home'
+                }
+            };
+            let toolMenuData = [];
+            let toolPermissionController = [];
+            if (managerData.super_admin !== 1) {
+                let permissionGroup = managerData.permission !== undefined && managerData.permission !== '' ?
+                    await permissionGroupModel.findDataByCondition({_id: managerData.permission}) : '';
+                // let otherPermission = [];
+                if (permissionGroup !== undefined && permissionGroup !== '' && permissionGroup.permission !== undefined && permissionGroup.permission !== '') {
+                    let permissionIdList = JSON.parse(permissionGroup.permission);
+                    for (let top of permissionIdList.top) {
+                        let permissionInfo = await permissionModel.findDataByCondition({_id:top});
+                        menuData[permissionInfo.controller] = {
+                            title: permissionInfo.name,
+                            url: permissionInfo.url,
+                            name: permissionInfo.controller,
+                            iconClass: 'glyphicon ' + permissionInfo.iconClass,
+                            children: {},
+                        }
+                    }
+                    for (let per in permissionIdList) {
+                        if (per !== 'top' && per !== 'tool') {
+                            let permissionArray = permissionIdList[per];
+                            for (let pa of permissionArray) {
+                                let permissionInfo = await permissionModel.findDataByCondition({_id:pa});
+                                if (permissionInfo !== undefined && permissionInfo !== '') {
+                                    if (permissionInfo.isMenu) {
+                                        // 属于二级菜单
+                                        let action = {
+                                            title: permissionInfo.name,
+                                            url: permissionInfo.url,
+                                            name: permissionInfo.action,
+                                        };
+                                        console.log(Object.keys(menuData[permissionInfo.controller].children).length);
+                                        if (Object.keys(menuData[permissionInfo.controller].children).length === 0) {
+                                            menuData[permissionInfo.controller].url = action.url;
+                                        }
+                                        menuData[permissionInfo.controller].children[permissionInfo.action] = action;
+                                    } else {
+                                        // 其它权限
+                                        // otherPermission.push({
+                                        //     title: permissionInfo.name,
+                                        //     url: permissionInfo.url,
+                                        //     name: permissionInfo.action,
+                                        // });
+                                    }
+                                }
+                            }
+                        } else if (per === 'tool') {
+                            // 工具里的页面权限
+                            let permissionArray = permissionIdList[per];
+                            for (let pa of permissionArray) {
+                                let permissionInfo = await permissionModel.findDataByCondition({_id:pa});
+                                if (permissionInfo.isMenu) {
+                                    toolMenuData.push({
+                                        title: permissionInfo.name,
+                                        controller: permissionInfo.controller,
+                                        url: permissionInfo.url,
+                                        sort: permissionInfo.ID  // 用来排序
+                                    });
+                                }
+                                toolPermissionController.push(permissionInfo.controller);
+                                // 对于工具里的多个控制层进行优化处理
+                                if (permissionInfo.otherController !== undefined && permissionInfo.otherController !== '') {
+                                    for (let other of permissionInfo.otherController.split(',')) {
+                                        toolPermissionController.push(other);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            } else {
+                // 获取数据库菜单列表
+                let menuPermissionList = await permissionModel.getList({isMenu:true});
+                for (let menu of menuPermissionList) {
+                    if (menu.pid === 0) {
+                        menuData[menu.controller] = {
+                            title: menu.name,
+                            url: menu.url,
+                            name: menu.controller,
+                            iconClass: 'glyphicon ' + menu.iconClass,
+                            children: {},
+                        }
+                    } else if (menu.pid !== 4) {
+                        let action = {
+                            title: menu.name,
+                            url: menu.url,
+                            name: menu.action,
+                        };
+                        menuData[menu.controller].children[menu.action] = action;
+                    }
+                }
+                // 超级管理员二级菜单添加
+                menuData['manager'].children['admin'] = {
+                    title: '超级管理员',
+                    url: '/manager/admin',
+                    name: 'admin',
+                }
+            }
+            // 获取所有工具里的权限控制器名称
+            let toolAllPermission = [];
+            let toolAllPermissionList = await permissionModel.getList({pid:4});
+            for (let tool of toolAllPermissionList) {
+                toolAllPermission.push(tool.controller);
+                if (managerData.super_admin === 1) {
+                    toolMenuData.push({
+                        title: tool.name,
+                        controller: tool.controller,
+                        url: tool.url,
+                        sort: tool.ID  // 用来排序
+                    });
+                }
+                if (tool.otherController !== undefined && tool.otherController !== '') {
+                    for (let other of tool.otherController.split(',')) {
+                        toolAllPermission.push(other);
+                    }
+                }
+            }
+
             let managerSession = {
                 username: managerData.username,
                 real_name:managerData.real_name,
                 loginTime: currentTime,
                 sessionToken: sessionToken,
                 userID: managerData.id,
-                permission: managerData.permission === undefined ? '' : managerData.permission,
+                toolPermission: toolPermissionController.join(','),
+                toolMenuData: toolMenuData,
+                toolAllPermission: toolAllPermission.join(','),
+                menuData: menuData,
                 superAdmin: managerData.super_admin
             };
             request.session.managerData = managerSession;

+ 276 - 45
modules/users/controllers/manager_controller.js

@@ -7,8 +7,11 @@
  */
 import BaseController from "../../common/base/base_controller";
 import ManagerModel from "../models/manager_model";
+import PermissionModel from "../models/permission_model";
+import PermissionGroupModel from "../models/permission_group_model";
 import Config from "../../../config/config";
 let config = require("../../../config/config.js");
+import {default as category, List as categoryList} from "../../common/const/category_const.js";
 
 class ManagerController extends BaseController {
 
@@ -22,10 +25,12 @@ class ManagerController extends BaseController {
     async index(request, response) {
         let pageData = {};
         let managerList = [];
+        let permissionGroupList = [];
+        let filter = request.query;
         try {
             // 查找管理员用户列表
             let managerModel = new ManagerModel();
-            let total = await managerModel.count();
+            let total = await managerModel.count({super_admin: 0});
 
             // 分页数据
             let page = request.query.page === undefined ? 1 : request.query.page;
@@ -36,76 +41,128 @@ class ManagerController extends BaseController {
             };
 
             // 获取管理员列表
-            managerList = await managerModel.getList(null, page);
+            let condition = managerModel.getFilterCondition(request);
+            condition.super_admin = 0;
+            managerList = JSON.parse(JSON.stringify(await managerModel.getList(condition, page)));
 
-            // 整理数据
-            if (managerList.length > 0) {
-                for (let tmp in managerList) {
-                    let permission = managerList[tmp].permission;
-                    permission = permission.split(',');
+            let permissionGroupModel = new PermissionGroupModel();
+            let permissionModel = new PermissionModel();
 
-                    if (permission.length <= 0) {
-                        continue;
-                    }
+            // 添加特定数据到filter里
+            if (request.query.office !== undefined && request.query.office !== '') {
+                let officeInfo = await categoryList.find(function (item) {
+                    return item.id === parseInt(request.query.office);
+                });
+                filter.officeName = officeInfo.name
+            }
+            if (request.query.permission !== undefined && request.query.permission !== '0') {
+                let permissionGroupInfo = await permissionGroupModel.findDataByCondition({_id: request.query.permission});
+                filter.permissionGroupName = permissionGroupInfo.name;
+            }
 
-                    let permissionString = [];
-                    for (let name of permission) {
-                        if (managerModel.permission[name] === undefined) {
-                            continue;
+            // 获取权限组列表
+            permissionGroupList = JSON.parse(JSON.stringify(await permissionGroupModel.getList()));
+            if (permissionGroupList.length > 0) {
+                for (let tmp in permissionGroupList) {
+                    let topPermissionList = [];
+                    if (permissionGroupList[tmp].permission !== undefined && permissionGroupList[tmp].permission !== '') {
+                        let groupPermissionList = JSON.parse(permissionGroupList[tmp].permission);
+                        for (let p in groupPermissionList) {
+                            if (p === 'top') {
+                                for (let t of groupPermissionList[p]) {
+                                    let topInfo = await permissionModel.findDataByCondition({_id:t});
+                                    topPermissionList.push(topInfo.name);
+                                }
+                                break;
+                            }
                         }
-                        permissionString.push(managerModel.permission[name]);
                     }
-                    permissionString = permissionString.join(',');
-                    managerList[tmp].permissionStr = permissionString;
+                    permissionGroupList[tmp].top_name = topPermissionList.join(',');
                 }
             }
-        } catch (error) {
 
+            // 整理数据
+            if (managerList.length > 0) {
+                for (let tmp in managerList) {
+                    let cate = await categoryList.find(function (item) {
+                        return item.id === managerList[tmp].office;
+                    });
+                    managerList[tmp].officeName = cate !== undefined ? cate.name : '';
+
+                    let groupInfo = managerList[tmp].permission !== '' ? await permissionGroupModel.findDataByCondition({_id:managerList[tmp].permission}) : '';
+                    managerList[tmp].permissionName = groupInfo !== undefined && groupInfo !== '' ? groupInfo.name : '';
+                }
+            }
+        } catch (error) {
+            console.log(error);
         }
 
+        let permissionGroupList2 = JSON.stringify(permissionGroupList);
         let renderData = {
             managerList: managerList,
             pages: pageData,
+            categoryList: categoryList,
+            permissionGroupList: permissionGroupList,
+            permissionGroupList2: permissionGroupList2,
             layout: 'users/views/layout/layout',
+            filter: filter,
             LicenseKey:config.getLicenseKey(process.env.NODE_ENV)
         };
         response.render('users/views/manager/index', renderData);
     }
 
     /**
+     * 权限组分配(管理员页面)
+     * @param request
+     * @param response
+     * @return {Promise.<void>}
+     */
+    async groupSave(request, response) {
+        let id = request.body.manager_id;
+        let permission = request.body.permission !== '0' ? request.body.permission : '';
+        let managerModel = new ManagerModel();
+        let result = await managerModel.updateById(id, {permission: permission});
+
+        if (!result) {
+            throw '修改失败';
+        }
+        response.redirect(request.headers.referer);
+    }
+
+    /**
      * 保存管理员
      *
      * @param {object} request
      * @param {object} response
      * @return {void}
      */
-    async modify(request, response) {
-        let permission = request.body.permission;
-        let canLogin = request.body.login;
-        let id = request.params.id;
-
-        let responseData = {
-            err: 0,
-            msg: ""
-        };
-        try {
-            if (id === '' || id === undefined) {
-                throw 'id有误';
-            }
-            let managerModel = new ManagerModel();
-            let result = await managerModel.updateById(id, {permission: permission, can_login: canLogin});
-
-            if (!result) {
-                throw '修改失败';
-            }
-
-        } catch (error) {
-            responseData.err = 1;
-            responseData.msg = error;
-        }
-
-        response.json(responseData);
-    }
+    // async modify(request, response) {
+    //     let permission = request.body.permission;
+    //     let canLogin = request.body.login;
+    //     let id = request.params.id;
+    //
+    //     let responseData = {
+    //         err: 0,
+    //         msg: ""
+    //     };
+    //     try {
+    //         if (id === '' || id === undefined) {
+    //             throw 'id有误';
+    //         }
+    //         let managerModel = new ManagerModel();
+    //         let result = await managerModel.updateById(id, {permission: permission, can_login: canLogin});
+    //
+    //         if (!result) {
+    //             throw '修改失败';
+    //         }
+    //
+    //     } catch (error) {
+    //         responseData.err = 1;
+    //         responseData.msg = error;
+    //     }
+    //
+    //     response.json(responseData);
+    // }
 
     /**
      * 删除管理员
@@ -127,6 +184,27 @@ class ManagerController extends BaseController {
     }
 
     /**
+     * 操作管理员(启用和停用)
+     *
+     * @param {object} request
+     * @param {object} response
+     * @return {void}
+     */
+    async modify(request, response) {
+        let canLogin = request.params.login;
+        let id = request.params.id;
+
+        let managerModel = new ManagerModel();
+        let result = await managerModel.updateById(id, {can_login: canLogin});
+
+        // 修改成功
+        if (!result) {
+            throw '修改失败';
+        }
+        response.redirect(request.headers.referer);
+    }
+
+    /**
      * 超级管理员修改
      *
      * @param {object} request
@@ -192,6 +270,159 @@ class ManagerController extends BaseController {
         // let result = await managerModel.createManager();
         response.end('success');
     }
+
+    /**
+     * 权限组页面
+     * @param request
+     * @param response
+     * @return {Promise.<void>}
+     */
+    async authority(request, response) {
+        let pageData = {};
+        let groupList = [];
+        let topPermissionList = [];
+        let permissionList = [];
+        try {
+            // 获取最高级权限列表
+            let permissionModel = new PermissionModel();
+            topPermissionList = await permissionModel.getList({pid:0});
+
+            // 获取所有权限列表,按排序
+            permissionList = topPermissionList;
+            for (let index in permissionList) {
+                let count = await permissionModel.count({pid:permissionList[index].ID});
+                if (count > 0) {
+                    permissionList[index].secondPermissionList = await permissionModel.getList({pid: permissionList[index].ID});
+                } else {
+                    permissionList[index].secondPermissionList = [];
+                }
+                permissionList[index].count = count;
+            }
+
+            // 获取权限组列表
+            let permissionGroupModel = new PermissionGroupModel();
+            let total = await permissionGroupModel.count();
+
+            // 分页数据
+            let page = request.query.page === undefined ? 1 : request.query.page;
+            pageData = {
+                current: page,
+                total: parseInt(total / Config.pageSize),
+                queryData: response.locals.urlQuery
+            };
+
+            // 获取管理员列表
+            groupList = JSON.parse(JSON.stringify(await permissionGroupModel.getList(null, page)));
+
+            // 整理数据
+            if (groupList.length > 0) {
+                let managerModel = new ManagerModel();
+                for (let tmp in groupList) {
+                    let managerCount = await managerModel.count({permission: groupList[tmp]._id});
+                    groupList[tmp].manager_count = managerCount;
+                    let groupPermissionList = JSON.parse(groupList[tmp].permission);
+                    for (let p in groupPermissionList) {
+                        if (p === 'top') {
+                            let topPermissionList = [];
+                            for (let t of groupPermissionList[p]) {
+                                let topInfo = await permissionModel.findDataByCondition({_id:t});
+                                topPermissionList.push(topInfo.name);
+                            }
+                            groupList[tmp].top_name = topPermissionList.join(',');
+                        }
+                    }
+                }
+            }
+        } catch (error) {
+
+        }
+        let renderData = {
+            groupList: groupList,
+            topPermissionList: topPermissionList,
+            permissionList: permissionList,
+            pages: pageData,
+            layout: 'users/views/layout/layout',
+            LicenseKey:config.getLicenseKey(process.env.NODE_ENV)
+        };
+        response.render('users/views/manager/authority', renderData);
+    }
+
+    /**
+     * 权限组添加
+     * @param request
+     * @param response
+     * @return {Promise.<void>}
+     */
+    async authorityAdd(request, response) {
+        let permissionGroupModel = new PermissionGroupModel();
+        let result = await permissionGroupModel.createPermissionGroup(request.body);
+        if (!result) {
+            throw '添加失败';
+        }
+        response.redirect(request.headers.referer);
+    }
+
+    /**
+     * 权限组修改保存
+     * @param request
+     * @param response
+     * @return {Promise.<void>}
+     */
+    async authoritySave(request, response) {
+        let permissionGroupModel = new PermissionGroupModel();
+        let result = await permissionGroupModel.savePermissionGroup(request.body);
+        if (!result) {
+            throw '修改失败';
+        }
+        response.redirect(request.headers.referer);
+    }
+
+    /**
+     * 权限组删除
+     * @param request
+     * @param response
+     * @return {Promise.<void>}
+     */
+    async authorityDelete(request, response) {
+        let id = request.body.id;
+        try {
+            let permissionGroupModel = new PermissionGroupModel();
+            await permissionGroupModel.deleteById(id, true);
+            // 并清空用户所在权限组
+            let managerModel = new ManagerModel();
+            await managerModel.updateByPermission(id);
+        } catch(err) {
+            throw err;
+        }
+        response.redirect(request.headers.referer);
+    }
+
+    /**
+     * 权限添加接口
+     * @param request
+     * @param response
+     * @return {Promise.<void>}
+     */
+    async permissionAdd(request, response) {
+        let permissionModel = new PermissionModel();
+        let responseData = {
+            err: 0,
+            msg: ''
+        };
+        try {
+            permissionModel.setScene('insert');
+            let result = await permissionModel.createPermission(request.body);
+            if (!result) {
+                throw '添加失败';
+            }
+        } catch (error) {
+            console.log(error);
+            responseData.err = 1;
+            responseData.msg = error;
+        }
+
+        response.json(responseData);
+    }
 }
 
 export default ManagerController;

+ 3 - 0
modules/users/controllers/tool_controller.js

@@ -18,8 +18,11 @@ class ToolController extends BaseController {
      * @return {void}
      */
     index(request, response) {
+        let toolMenuData = request.session.managerData.toolMenuData;
+        console.log(toolMenuData);
         let renderData = {
             layout: 'users/views/layout/layout',
+            toolMenu: toolMenuData,
             LicenseKey:config.getLicenseKey(process.env.NODE_ENV)
         };
         response.render('users/views/tool/index', renderData);

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

@@ -62,15 +62,22 @@ class UserController extends BaseController {
                 total: Math.ceil(total / Config.pageSize),
                 queryData: response.locals.urlQuery
             };
-            console.log("取用户信息=========================");
-            console.log(condition);
+            // console.log("取用户信息=========================");
+            // console.log(condition);
             // 获取用户列表
             userList = await userModel.getList(condition, page, Config.pageSize);
-            console.log(userList)
+            // console.log(userList)
         } catch (error) {
             console.log(error);
         }
 
+        // 用户管理二级菜单独立出来
+        let secondMenu = response.locals.secondMenu;
+        let userMenu = [];
+        for (let second in secondMenu) {
+            userMenu.push(secondMenu[second]);
+        }
+
         // 渲染数据
         let renderData = {
             compilationList:compilationList,
@@ -82,6 +89,7 @@ class UserController extends BaseController {
             total: total,
             filter: filter,
             model: userModel,
+            userMenu: userMenu,
             layout: 'users/views/layout/layout',
             LicenseKey:config.getLicenseKey(process.env.NODE_ENV)
         };
@@ -137,6 +145,13 @@ class UserController extends BaseController {
             console.log(error);
         }
 
+        // 用户管理二级菜单独立出来
+        let secondMenu = response.locals.secondMenu;
+        let userMenu = [];
+        for (let second in secondMenu) {
+            userMenu.push(secondMenu[second]);
+        }
+
         // 渲染数据
         let renderData = {
             compilationList:compilationList,
@@ -148,6 +163,7 @@ class UserController extends BaseController {
             total: total,
             filter: filter,
             model: userModel,
+            userMenu: userMenu,
             layout: 'users/views/layout/layout',
             LicenseKey:config.getLicenseKey(process.env.NODE_ENV)
         };
@@ -231,7 +247,27 @@ class UserController extends BaseController {
         }
         response.json(responseData);
     }
-
+    async deleteUser(request, response) {
+        let data = JSON.parse(request.body.data);
+        let userModel = new UserModel();
+        let responseData = {
+            error: 0,
+            message: '',
+            data: null
+        };
+        try{
+            let manager = request.session.managerData;
+            if(manager.superAdmin !=1 ){
+                throw { code: 1, message: '没有删除用户权限'};
+            }
+            responseData.data =  await userModel.deleteUser(data.userID,manager.userID);
+        } catch (error) {
+            console.log(error);
+            responseData.error = error.code;
+            responseData.message = error.message;
+        }
+        response.json(responseData);
+    }
 
     /**
      * 根据用户id列表获取用户信息列表 json

+ 40 - 5
modules/users/models/manager_model.js

@@ -65,7 +65,28 @@ class ManagerModel extends BaseModel {
     }
 
     /**
-     * 获取列表
+     * 获取过滤条件
+     *
+     * @return {Object}
+     */
+    getFilterCondition(request) {
+        let condition = {};
+        let office = request.query.office;
+        if (office !== '' && office !== undefined) {
+            condition.office = parseInt(office);
+        }
+
+        let permission = request.query.permission;
+        if (permission !== undefined) {
+            // 0 :权限为空的情况
+            condition.permission = permission === '0' ? '' : permission;
+        }
+
+        return condition;
+    }
+
+    /**
+     * 获取按创建时间倒序列表
      *
      * @param {object} condition
      * @param {number} page
@@ -74,7 +95,7 @@ class ManagerModel extends BaseModel {
     getList(condition = null, page = 1) {
         page = parseInt(page);
         page = page <= 1 ? 1 : page;
-        let option = {page: page};
+        let option = {page: page, sort: {create_time:-1}};
         return this.db.find(condition, null, option);
     }
 
@@ -138,12 +159,15 @@ class ManagerModel extends BaseModel {
 
         // 是否禁止登录
         if (managerData && managerData.can_login !== 1) {
-            throw {code: 44002, err: '用户名不存在'};
+            throw {code: 44002, err: '账号被停用'};
         }
 
         // 如果不是超级管理员登录则走CLD接口登录流程
         if (managerData === null || managerData._id === undefined || username !== this.adminUsername) {
             let CLDLoginInfo = await this.CLDLogin(username, password, managerData);
+            if (CLDLoginInfo.can_login !== 1) {
+                throw {code: 44002, err: '账号被停用'};
+            }
             managerData = CLDLoginInfo;
         } else {
             // 加密密码
@@ -205,8 +229,8 @@ class ManagerModel extends BaseModel {
             last_login: current,
             office: responseData.office,
             position: responseData.position,
-            permission: 'user',
-            can_login: 1
+            permission: '',
+            can_login: 0
         };
         result = this.db.create(insertData);
 
@@ -275,6 +299,17 @@ class ManagerModel extends BaseModel {
         return result;
     }
 
+    /**
+     * 删除后台用户权限
+     * @param permission
+     * @return {Promise.<void>}
+     */
+    async updateByPermission(permission) {
+        let result = await this.db.update({permission: permission}, {permission: ''});
+
+        return result.ok === 1;
+    }
+
 }
 
 export default ManagerModel;

+ 120 - 0
modules/users/models/permission_group_model.js

@@ -0,0 +1,120 @@
+/**
+ * 后台权限组数据模型
+ *
+ * @author EllisRan
+ * @date 2018/12/07
+ * @version
+ */
+import mongoose from "mongoose";
+import BaseModel from "../../common/base/base_model";
+
+class PermissionGroupModel extends BaseModel {
+
+    /**
+     * 构造函数
+     *
+     * @return {void}
+     */
+    constructor() {
+        let parent = super();
+        parent.model = mongoose.model('permission_group');
+        parent.init();
+    }
+
+    /**
+     * 新增权限
+     *
+     * @param {Object} data
+     * @return {Promise}
+     */
+    async createPermission(data) {
+        if (Object.keys(data).length <= 0) {
+            throw '数据格式错误';
+        }
+        data.create_time = new Date().getTime();
+        let result = await this.db.create(data);
+
+        return result;
+    }
+
+    /**
+     * 获取列表
+     *
+     * @param {object} condition
+     * @param {number} page
+     * @return {Promise}
+     */
+    async getList(condition = null, page = 1, pageSize = 30) {
+        page = parseInt(page);
+        page = page <= 1 ? 1 : page;
+        let option = {pageSize: pageSize, offset: parseInt((page - 1) * pageSize)};
+        console.log(condition);
+        let list = await this.db.find(condition, null, option);
+        list = list.length > 0 ? list : [];
+
+        return list;
+    }
+
+    /**
+     * 根据条件返回数据数量
+     *
+     * @param {object} condition
+     * @return {Promise}
+     */
+    async count(condition = null) {
+        let total = 0;
+        try {
+            total = await this.db.count(condition);
+        } catch (error) {
+            total = 0;
+        }
+        return total;
+    }
+
+    /**
+     * 新增权限组
+     *
+     * @param {Object} data
+     * @return {Promise}
+     */
+    async createPermissionGroup(data) {
+        if (Object.keys(data).length <= 0) {
+            throw '数据格式错误';
+        }
+        data.create_time = new Date().getTime();
+        let result = await this.db.create(data);
+
+        return result;
+    }
+
+    /**
+     * 修改权限组
+     *
+     * @param {Object} data
+     * @return {Promise}
+     */
+    async savePermissionGroup(data) {
+        if (Object.keys(data).length <= 0) {
+            throw '数据格式错误';
+        }
+        let permission = {
+            top: data.topPermission !== undefined ? data.topPermission : [],
+        };
+        for (let index in data) {
+            if (index.indexOf('permission_') > -1) {
+                let key = index.split('_')[1];
+                permission[key] = data[index];
+            }
+        }
+        let postData = {
+            name: data.name,
+            permission: JSON.stringify(permission),
+        };
+        let result = await this.updateById(data.id, postData);
+
+        return result;
+    }
+
+}
+
+export default PermissionGroupModel;

+ 77 - 0
modules/users/models/permission_model.js

@@ -0,0 +1,77 @@
+/**
+ * 后台权限数据模型
+ *
+ * @author EllisRan
+ * @date 2018/12/06
+ * @version
+ */
+import mongoose from "mongoose";
+import BaseModel from "../../common/base/base_model";
+
+class PermissionModel extends BaseModel {
+
+    /**
+     * 构造函数
+     *
+     * @return {void}
+     */
+    constructor() {
+        let parent = super();
+        parent.model = mongoose.model('permission');
+        parent.init();
+    }
+    /**
+     * 设置场景
+     *
+     * @param {string} scene
+     * @return {void}
+     */
+    setScene(scene = '') {
+        switch (scene) {
+            // 新增权限
+            case 'insert':
+                // this.model.schema.path('ID').required(true);
+                this.model.schema.path('name').required(true);
+                this.model.schema.path('controller').required(true);
+                this.model.schema.path('url').required(true);
+                this.model.schema.path('pid').required(true);
+                break;
+        }
+    }
+
+    /**
+     * 新增权限
+     *
+     * @param {Object} data
+     * @return {Promise}
+     */
+    async createPermission(data) {
+        if (Object.keys(data).length <= 0) {
+            throw '数据格式错误';
+        }
+        data.create_time = new Date().getTime();
+        let result = await this.db.create(data);
+
+        return result;
+    }
+
+    /**
+     * 获取列表
+     *
+     * @param {object} condition
+     * @param {number} page
+     * @return {Promise}
+     */
+    async getList(condition = null, page = 1, pageSize = 30) {
+        page = parseInt(page);
+        page = page <= 1 ? 1 : page;
+        let option = {pageSize: pageSize, offset: parseInt((page - 1) * pageSize), sort: {ID:1}};
+        let list = await this.db.find(condition, null, option);
+        list = list.length > 0 ? list : [];
+
+        return list;
+    }
+
+}
+
+export default PermissionModel;

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

@@ -8,6 +8,27 @@
 import mongoose from "mongoose";
 import Moment from "moment";
 import BaseModel from "../../common/base/base_model";
+const projectModel = mongoose.model('projects');
+const unitPriceFileModel = mongoose.model('unit_price_file');
+const feeRateFileModel = mongoose.model('fee_rate_file');
+const optionsModel = mongoose.model('options');
+const settingModel = mongoose.model('setting');
+const messageModel = mongoose.model('user_message');
+const logModel = mongoose.model('log');
+const rptCfgModel =  mongoose.model("rpt_cfg");
+const rptCusCfgModel = mongoose.model("rpt_customize_cfg");
+const comRationSecTreeModel  = mongoose.model('complementary_ration_section_tree');
+const blockLibModel =  mongoose.model('blockLibsModel');
+const comGLJLibMode =  mongoose.model('complementary_glj_lib');
+const comGLJSectionModel = mongoose.model('complementary_glj_section');
+const comRationItemsModel = mongoose.model('complementary_ration_items');
+const comRationCoeModel = mongoose.model('complementary_ration_coe_list');
+const comRationInstalModel = mongoose.model('complementary_ration_installation');
+const comRationInstalSectionModel = mongoose.model('complementary_ration_installationSection');
+const rptTplTreeMode =  mongoose.model("rpt_tpl_tree");
+let sysSchedule = require('../../sys_tools/models/sys_model');
+
+
 
 class UserModel extends BaseModel {
 
@@ -85,7 +106,7 @@ class UserModel extends BaseModel {
     async getList(condition = null, page = 1, pageSize = 30) {
         page = parseInt(page);
         page = page <= 1 ? 1 : page;
-        let option = {pageSize: pageSize, offset: parseInt((page - 1) * pageSize)};
+        let option = {pageSize: pageSize, offset: parseInt((page - 1) * pageSize), sort: {_id:-1}};
 
         let userList = await this.db.find(condition, null, option);
         userList = userList.length > 0 ? userList : [];
@@ -171,6 +192,43 @@ class UserModel extends BaseModel {
     getDayMsg(index){
         return this.dayMsg[index];
     }
+    async deleteUser(userID,managerID){
+        //把用户的项目,单价文件,费率文件标记为真删除状态,然后统一调用清除项目数据的方法
+        let deleteInfo = {
+            deleted:true,
+            deleteDateTime : new Date(),
+            deleteBy:managerID,
+            completeDeleted:true
+        };
+        //标记删除
+        await unitPriceFileModel.updateMany({"user_id":userID},{"deleteInfo":deleteInfo});
+        await feeRateFileModel.updateMany({"userID":userID},{"deleteInfo":deleteInfo});
+        await projectModel.updateMany({"userID":userID},{"deleteInfo":deleteInfo});
+        //删除项目相关数据
+        await sysSchedule.clearJunkData();
+
+        //删除用户私有数据
+        await optionsModel.deleteMany({"user_id":userID});
+        await settingModel.deleteMany({"user_id":userID});
+        await messageModel.deleteMany({"user_id":userID});
+        await logModel.deleteMany({"user_id":userID});
+
+        await rptCfgModel.deleteMany({"userId":userID});
+        await rptCusCfgModel.deleteMany({"userId":userID});
+        await comRationSecTreeModel.deleteMany({"userId":userID});
+        await comGLJLibMode.deleteMany({"userId":userID});
+        await rptTplTreeMode.deleteMany({"userId":userID});
+        await comGLJSectionModel.deleteMany({"userId":userID});
+        await comRationItemsModel.deleteMany({"userId":userID});
+        await comRationCoeModel.deleteMany({"userId":userID});
+        await comRationInstalModel.deleteMany({"userId":userID});
+        await comRationInstalSectionModel.deleteMany({"userId":userID});
+        await blockLibModel.deleteMany({"userID":userID});
+
+        //最后删除用户信息:
+        await this.db.model.deleteOne({_id:mongoose.Types.ObjectId(userID)});
+        return "success";
+    }
 
 }
 

+ 14 - 2
modules/users/routes/manager_route.js

@@ -16,12 +16,24 @@ module.exports =function (app) {
     // 管理员列表action
     router.get('/', managerController.auth, managerController.init, managerController.index);
     // 修改管理员
-    router.post('/modify/:id', managerController.auth, managerController.init, managerController.modify);
+    // router.post('/modify/:id', managerController.auth, managerController.init, managerController.modify);
     // 删除管理员
-    router.get('/delete/:id',managerController.auth,  managerController.init, managerController.delete);
+    // router.get('/delete/:id',managerController.auth,  managerController.init, managerController.delete);
+    // 管理员权限组分配
+    router.post('/group/save', managerController.auth, managerController.init, managerController.groupSave);
+    // 停用或启用管理员
+    router.get('/modify/:id/:login',managerController.auth,  managerController.init, managerController.modify);
     // 超级管理员action
     router.get('/admin', managerController.auth, managerController.init, managerController.admin);
     router.post('/admin', managerController.auth, managerController.init, managerController.adminSubmit);
+    // 权限组列表
+    router.get('/authority', managerController.auth, managerController.init, managerController.authority);
+    router.post('/authority/add', managerController.auth, managerController.init, managerController.authorityAdd);
+    router.post('/authority/save', managerController.auth, managerController.init, managerController.authoritySave);
+    router.post('/authority/delete', managerController.auth, managerController.init, managerController.authorityDelete);
+
+    // 权限添加接口
+    router.post('/permission/add', managerController.auth, managerController.init, managerController.permissionAdd);
 
     router.get('/create', managerController.create);
 

+ 2 - 1
modules/users/routes/user_route.js

@@ -14,10 +14,11 @@ const userController = new UserController();
 module.exports =function (app) {
     // action定义区域
     router.get('/', userController.auth, userController.init, userController.normalUsers);
-    router.get('/test-user', userController.auth, userController.init, userController.testUsers);
+    router.get('/testUser', userController.auth, userController.init, userController.testUsers);
     router.get('/search', userController.auth, userController.init, userController.search);
     router.post('/findByID', userController.auth, userController.init, userController.findByID);
     router.post('/getUserList', userController.auth, userController.init, userController.getUserList);
     router.post('/updateUser', userController.auth, userController.init, userController.updateUser);
+    router.post('/deleteUser', userController.auth, userController.init, userController.deleteUser);
     app.use("/user", router);
 };

+ 13 - 2
public/counter/counter.js

@@ -45,12 +45,23 @@ counterDAO.prototype.getIDAfterCount = async function(moduleName, stepCount, cal
     }
     if (callback === null) {
         let result = await counterModel.findOneAndUpdate({_id: moduleName}, { $inc: { sequence_value: sc } }, {'new':true});
-        return result
+        return await checkIDResult(result,moduleName,null)
     } else {
-        counterModel.findOneAndUpdate({_id: moduleName}, { $inc: { sequence_value: sc } }, {'new':true}, callback);
+        counterModel.findOneAndUpdate({_id: moduleName}, { $inc: { sequence_value: sc } }, {'new':true}, function (err,result) {
+            checkIDResult(result,moduleName,callback,err)
+        });
     }
 }
 
+async function checkIDResult(result,moduleName,callback,err){
+    if(result){
+        return callback?callback(err,result):result;
+    }else {
+        return callback?counterModel.create({_id: moduleName,sequence_value:1},callback): await counterModel.create({_id: moduleName,sequence_value:1});
+    }
+
+}
+
 counterDAO.prototype.getCurrentID = function(moduleName, callback) {
     if (callback) {
         counterModel.findOne({_id: moduleName}).exec()

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

@@ -440,4 +440,24 @@ var sheetCommonObj = {
         console.log(colMapping);
         obj.colMapping = colMapping
     },
+    //动态根据工作簿宽度和各列宽度比例设置宽度
+    setColumnWidthByRate: function (workBookWidth, workBook, headers){
+        if(workBook){
+            const sheet = workBook.getActiveSheet();
+            sheet.suspendEvent();
+            sheet.suspendPaint();
+            for(let col = 0; col < headers.length; col++){
+                if(headers[col]['rateWidth'] !== undefined && headers[col]['rateWidth'] !== null && headers[col]['rateWidth'] !== ''){
+                    sheet.setColumnWidth(col, workBookWidth * headers[col]['rateWidth'], GC.Spread.Sheets.SheetArea.colHeader)
+                }
+                else {
+                    if(headers[col]['headerWidth'] !== undefined && headers[col]['headerWidth'] !== null && headers[col]['headerWidth'] !== ''){
+                        sheet.setColumnWidth(col, headers[col]['headerWidth'], GC.Spread.Sheets.SheetArea.colHeader)
+                    }
+                }
+            }
+            sheet.resumeEvent();
+            sheet.resumePaint();
+        }
+    },
 }

+ 2 - 0
robots.txt

@@ -0,0 +1,2 @@
+User-agent: *
+Disallow: /

+ 72 - 21
web/common/js/slideResize.js

@@ -9,10 +9,9 @@
  */
 
 /*
- * div之间的水平拖动,适应各种情况
- * module: 所属模块,防止不同页面相同id导致localstorage数据被覆盖
- * eleObj: resize, parent, left, right
- * limit: min, max
+ * 拖动相关公共接口
+ * 前台使用此接口时,注意在恢复系统默认设置时,
+ * 清除相关缓存数据: project_view.js--->$('#property_default').click(callback)
  * */
 
 const SlideResize = (function() {
@@ -20,9 +19,8 @@ const SlideResize = (function() {
     //@param {Object dom}resize滚动条
     function setResizeWidth (resize) {
         const fixedWidth = 10;
-        //跟滚动条同层的其他节点
-        let bros = resize.parent().children();
         //滚动条节点 及 同层非滚动条节点的索引
+        let bros = resize.parent().children();
         let index = bros.index(resize),
             otherIndex = index ? 0 : 1;
         const other = resize.parent().children(`:eq(${otherIndex})`);
@@ -36,7 +34,14 @@ const SlideResize = (function() {
     }
 
     let mouseMoveCount = 0;
-    function horizontalSlide(module, eleObj, limit, callback) {
+    /*
+     * div之间的水平拖动,适应各种情况
+     * @param {Object}eleObj: module所属模块,防止不同页面相同id导致localstorage数据被覆盖(放在对象里,因为可能有的地方要实时改这个module)
+     *         resize, parent, left, right
+     * @param {Object}limit: min, max
+     * @param {Function}callback 回调
+     * */
+    function horizontalSlide(eleObj, limit, callback) {
         const triggerCBSize = 5;
         let drag = false,
             startPoint = 0,
@@ -55,13 +60,14 @@ const SlideResize = (function() {
         });
         $('body').mousemove(function (e) {
             if (drag) {
+                console.log('drag');
                 let moveSize = e.clientX - startPoint;
                 leftChange = leftWidth + moveSize;
                 leftChange = leftChange < limit.min ? limit.min : leftChange;
-                leftChange = leftChange > limitMax ? limitMax - 3 : leftChange;
+                leftChange = leftChange > limitMax ? limitMax - 5 : leftChange;
                 rightChange = rightWidth - moveSize;
                 rightChange = rightChange < limit.min ? limit.min : rightChange;
-                rightChange = rightChange > limitMax ? limitMax - 3 : rightChange;
+                rightChange = rightChange > limitMax ? limitMax - 5 : rightChange;
                 let leftPercentWidth = leftChange / eleObj.parent.width() * 100 + '%',
                     rightPercentWidth = rightChange / eleObj.parent.width() * 100 + '%';
                 eleObj.left.css('width', leftPercentWidth);
@@ -80,9 +86,9 @@ const SlideResize = (function() {
                 mouseMoveCount = 0;
                 //将宽度信息存储到localstorage
                 let leftWidthInfo = eleObj.left[0].style.width;
-                setLocalCache(`${module}${eleObj.left.attr('id')}Width`, leftWidthInfo);
+                setLocalCache(`${eleObj.module}${eleObj.left.attr('id')}Width`, leftWidthInfo);
                 let rightWidthInfo = eleObj.right[0].style.width;
-                setLocalCache(`${module}${eleObj.right.attr('id')}Width`, rightWidthInfo);
+                setLocalCache(`${eleObj.module}${eleObj.right.attr('id')}Width`, rightWidthInfo);
             }
         });
     }
@@ -105,11 +111,12 @@ const SlideResize = (function() {
 
     /*
      * div上下拖动
-     * module: 所属模块,防止不同页面相同id导致localstorage数据被覆盖
-     * eleObj: resize, top, topSpread, bottom, bottomSpread
-     * limit: min, max, notTopSpread(上部分非spread部分的高度) notBottomSpread(下部分非spread部分的高度)
+     * @param {Object} eleObj: module所属模块,防止不同页面相同id导致localstorage数据被覆盖(放在对象里,因为可能有的地方要实时改这个module)
+     *        resize, top, topSpread, bottom, bottomSpread
+     * @param {Object}limit: min, max, notTopSpread(上部分非spread部分的高度) notBottomSpread(下部分非spread部分的高度)
+     * @param {Function}callback 回调
      * */
-    function verticalSlide(module, eleObj, limit, callback) {
+    function verticalSlide(eleObj, limit, callback) {
         const triggerCBSize = 5;
         let drag = false,
             startPoint = 0,
@@ -157,18 +164,19 @@ const SlideResize = (function() {
                 mouseMoveCount = 0;
                 //将高度信息存储到localstorage
                 let topHeightInfo = eleObj.top.height();
-                setLocalCache(`${module}${eleObj.top.attr('id')}Height`, topHeightInfo);
+                setLocalCache(`${eleObj.module}${eleObj.top.attr('id')}Height`, topHeightInfo);
                 let bottomHeightInfo = eleObj.bottom.height();
-                setLocalCache(`${module}${eleObj.bottom.attr('id')}Height`, bottomHeightInfo);
+                setLocalCache(`${eleObj.module}${eleObj.bottom.attr('id')}Height`, bottomHeightInfo);
             }
         });
     }
 
     /*
      * 加载上下高度
-     * module: 所属模块,防止不同页面相同id导致localstorage数据被覆盖
-     * eleObj: top, topSpread, bottom, bottomSpread
-     * limit: totalHeight(实时的上下部分总高度) notTopSpread(上部分非spread部分的高度) notBottomSpread(下部分非spread部分的高度)
+     * @param {String}module 所属模块,防止不同页面相同id导致localstorage数据被覆盖
+     * @param {Object}eleObj: module所属模块,防止不同页面相同id导致localstorage数据被覆盖(放在对象里,因为可能有的地方要实时改这个module) top, topSpread, bottom, bottomSpread
+     * @param {Object}limit: totalHeight(实时的上下部分总高度) notTopSpread(上部分非spread部分的高度) notBottomSpread(下部分非spread部分的高度)
+     * @param {Function}callback 回调
      * */
 
     function loadVerticalHeight(module, eleObj, limit, callback) {
@@ -196,5 +204,48 @@ const SlideResize = (function() {
         }
     }
 
-    return {horizontalSlide, loadHorizonWidth, verticalSlide, loadVerticalHeight}
+    /*
+     * 包含多个上下结构的拖动(n>= 2,只包含上下结构的地方可以用loadVerticalHeight)
+     * 加载多个结构高度
+     * @param {String}module所属模块,防止不同页面相同id导致localstorage数据被覆盖
+     * @param {Array}eles 元素为结构对象 内部: {container: 外部div, spread: 该div的Spread, notSpread: 该div不含Spread的高度, defaultProportion: 默认高度比例0.6}
+     * @param {String}totalHeight 各个结构div总高度-可编译字符串
+     * @param {Function}callback 回调
+     * */
+    function loadMultiVerticalHeight(module, eles, totalHeight, callback) {
+        //当前窗口拖动区域总高度
+        totalHeight = eval(totalHeight);
+        let cacheHeight = 0,//缓存中设置了高度的div总高度
+            notCacheProportion = 0;//缓存中没设置高度的div占用的总高度比例(每个div都有默认的高度比例) (有了缓存高度的div就是被拖动过的,被拖动过的div,其默认高度比例就没用了)
+        //获取缓存的总高度、未被拖动过的所有div的默认比例之和notCacheProportion (1-notCacheProportion)就是缓存高度的占总的比例
+        for (let ele of eles) {
+            let eleHeight = getLocalCache(`${module}${ele.container.attr('id')}Height`);
+            if (eleHeight !== null) {
+                eleHeight = parseFloat(eleHeight);
+                cacheHeight += eleHeight;
+            } else {
+                notCacheProportion += ele.defaultProportion;
+            }
+        }
+        //缓存高度占总的比例
+        let cacheProportion = 1 - notCacheProportion;
+        for (let ele of eles) {
+            let eleHeight = getLocalCache(`${module}${ele.container.attr('id')}Height`),
+                curHeight = 0;
+            if (eleHeight !== null) {
+                eleHeight = parseFloat(eleHeight);
+                //ele在当前窗口大小中的高度
+                curHeight = eleHeight / cacheHeight * cacheProportion * totalHeight;
+            } else {
+                curHeight = ele.defaultProportion * totalHeight;
+            }
+            ele.container.height(curHeight);
+            ele.spread.height(curHeight - ele.notSpread);
+        }
+        if (callback) {
+            callback();
+        }
+    }
+
+    return {setResizeWidth, horizontalSlide, loadHorizonWidth, verticalSlide, loadVerticalHeight, loadMultiVerticalHeight}
 })();

+ 20 - 5
web/maintain/billsGuidance_lib/js/billsGuidance.js

@@ -882,7 +882,7 @@ const billsGuidance = (function () {
         });
     }
     //编辑后自动去除换行符回车符
-    const deESC = /[\r, \n]/g;
+    const deESC = /[\n]/g;
     //项目指引编辑
     //@param {Object}sheet {Array}cells
     function edit(sheet, cells){
@@ -1387,6 +1387,17 @@ const billsGuidance = (function () {
                                     let pasteNode = bills.tree.selected.guidance.tree.items[target.row];
                                     pasteBlock(pasteNode);
                                 }},
+                            "del": {
+                                name: '删除',
+                                disabled: function () {
+                                    let node = bills.tree.selected.guidance.tree.items[target.row];
+                                    return !node
+                                },
+                                icon: "fa-arrow-left",
+                                callback: function (key, opt) {
+                                    $('#delAlert').modal('show');
+                                }
+                            },
                             "insertSibling": {
                                 name: '插入行',
                                 disabled: function () {
@@ -1558,6 +1569,7 @@ const billsGuidance = (function () {
         });
         //定额高度拖动调整
         let heightEleObj = {
+            module: moduleName,
             resize: $('#deResize'),
             top: $('#topContent'),
             topSpread: $('#sectionSpread'),
@@ -1570,7 +1582,7 @@ const billsGuidance = (function () {
                 notTopSpread: 0,
                 notBottomSpread: 0,
             };
-        SlideResize.verticalSlide(moduleName, heightEleObj, heightLimit, function () {
+        SlideResize.verticalSlide(heightEleObj, heightLimit, function () {
             if(section.workBook){
                 section.workBook.refresh();
             }
@@ -1590,20 +1602,22 @@ const billsGuidance = (function () {
         //左右拖动
         //清单表与项目指引表
         let leftElesObj = {};
+        leftElesObj.module = moduleName;
         leftElesObj.resize = $('#slideResizeLeft');
         leftElesObj.parent = $('#dataRow');
         leftElesObj.left = $('#leftContent');
         leftElesObj.right = $('#midContent');
-        SlideResize.horizontalSlide(moduleName, leftElesObj, {min: 200, max: `$('#dataRow').width() - $('#rightContent').width() - 200`}, function () {
+        SlideResize.horizontalSlide(leftElesObj, {min: 200, max: `$('#dataRow').width() - $('#rightContent').width() - 200`}, function () {
             refreshALlWorkBook();
         });
         //人材机表与人材机组成物表
         let rightElesObj = {};
+        rightElesObj.module = moduleName;
         rightElesObj.resize = $('#slideResizeRight');
         rightElesObj.parent = $('#dataRow');
         rightElesObj.left = $('#midContent');
         rightElesObj.right = $('#rightContent');
-        SlideResize.horizontalSlide(moduleName, rightElesObj, {min: 200, max: `$('#dataRow').width() - $('#leftContent').width() - 200`}, function () {
+        SlideResize.horizontalSlide(rightElesObj, {min: 200, max: `$('#dataRow').width() - $('#leftContent').width() - 200`}, function () {
             refreshALlWorkBook();
         });
     }
@@ -1632,12 +1646,13 @@ const billsGuidance = (function () {
     function initSlideSize() {
         //定额表上下
         let heightEleObj = {
+            module: moduleName,
             top: $('#topContent'),
             topSpread: $('#sectionSpread'),
             bottom: $('#bottomContent'),
             bottomSpread: $('#rationSpread')
         };
-        SlideResize.loadVerticalHeight(moduleName, heightEleObj,
+        SlideResize.loadVerticalHeight(heightEleObj.module, heightEleObj,
             {totalHeight: `$(window).height()-$('.header').height()-$('.sidebar-tools-bar').height()-10`,
              notTopSpread: 0, notBottomSpread: 0}, function () {
                 if(section.workBook){

+ 3 - 9
web/maintain/bills_lib/scripts/bills_lib_ajax.js

@@ -63,17 +63,14 @@ var mainAjax = {
                         var createDate = result.data[i].createDate;
                         var createDateFmt = new Date(createDate).format("yyyy-MM-dd");
                         $("#showArea").append(
-                            "<tr id='tempId'>" +
-                            "<td><a href='stdBills'>"+billsLibName+"</a></td>" +
+                            "<tr id='"+id+"'>" +
+                            "<td><a href='stdBills?billsLibId="+id+"'>"+billsLibName+"</a></td>" +
                             "<td>"+createDateFmt+" </td>" +
                             "<td><a href='javascript:void(0);' data-toggle='modal' data-target='#edit' title='编辑'>" +
                             "<i class='fa fa-pencil-square-o'></i></a> <a href='javascript:void(0);' data-toggle='modal' data-target='#del' class='text-danger' title='删除'>" +
                             "<i class='fa fa-remove'></i></a></td>" +
                             "<td><a class='btn btn-secondary btn-sm import-data' href='javacript:void(0);' data-id='"+ id +"' title='导入数据'><i class='fa fa-sign-in fa-rotate-90'></i>导入</a></td>"+
                             "</tr>");
-                        var newHref = "stdBills?billsLibId="+id;
-                        $("#tempId td:first a").attr("href", newHref);
-                        $("#tempId").attr("id", id);
                     }
                 }
 
@@ -92,15 +89,12 @@ var mainAjax = {
                     var createDate = result.data[0].createDate;
                     var createDateFmt = new Date(createDate).format("yyyy-MM-dd");
                     $("#showArea").append(
-                        "<tr id='tempId'><td><a href='stdBills'>"+billsLibName+"</a></td><td>"+createDateFmt+" </td><td><a href='javascript:void(0);' data-toggle='modal' data-target='#edit' title='编辑'>" +
+                        "<tr id='"+id+"'><td><a href='stdBills?billsLibId="+id+"'>"+billsLibName+"</a></td><td>"+createDateFmt+" </td><td><a href='javascript:void(0);' data-toggle='modal' data-target='#edit' title='编辑'>" +
                         "<i class='fa fa-pencil-square-o'></i></a> <a href='javascript:void(0);' data-toggle='modal' data-target='#del' class='text-danger' title='删除'>" +
                         "<i class='fa fa-remove'></i></a></td>" +
                         "<td><a class='btn btn-secondary btn-sm import-data' href='javacript:void(0);' data-id='"+ id +"' title='导入数据'><i class='fa fa-sign-in fa-rotate-90'></i>导入</a></td>" +
                         "</tr>"
                     );
-                    var newHref = "stdBills?billsLibId="+id;
-                    $("#tempId td:first a").attr("href", newHref);
-                    $("#tempId").attr("id", id);
                     $('#cancelBtn').click();
                 }
             }

+ 12 - 7
web/maintain/ration_repository/dinge.html

@@ -60,13 +60,18 @@
                 <div class="row" id="dataRow">
                     <div class="main-side p-0" id="leftContent" style="width: 25%; height: 100%; overflow: hidden">
                         <div style="width: 99%; float: left">
-                            <div class="tab-bar">
-                                <a href="javascript:void(0);" id="tree_Insert" class="btn btn-sm" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="插入"><i class="fa fa-plus" aria-hidden="true"></i></a>
-                                <a href="javascript:void(0);" id="tree_remove" class="btn btn-sm" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="删除"><i class="fa fa-remove" aria-hidden="true"></i></a>
-                                <a href="javascript:void(0);" id="tree_upLevel" class="btn btn-sm " data-toggle="tooltip" data-placement="bottom" title="" data-original-title="升级"><i class="fa fa-arrow-left" aria-hidden="true"></i></a>
-                                <a href="javascript:void(0);" id="tree_downLevel" class="btn btn-sm " data-toggle="tooltip" data-placement="bottom" title="" data-original-title="降级"><i class="fa fa-arrow-right" aria-hidden="true"></i></a>
-                                <a href="javascript:void(0);" id="tree_downMove" class="btn btn-sm" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="下移"><i class="fa fa-arrow-down" aria-hidden="true"></i></a>
-                                <a href="javascript:void(0);" id="tree_upMove" class="btn btn-sm" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="上移"><i class="fa fa-arrow-up" aria-hidden="true"></i></a>
+                            <div class="tab-bar row">
+                                <div>
+                                    <a href="javascript:void(0);" id="tree_Insert" class="btn btn-sm" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="插入"><i class="fa fa-plus" aria-hidden="true"></i></a>
+                                    <a href="javascript:void(0);" id="tree_remove" class="btn btn-sm" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="删除"><i class="fa fa-remove" aria-hidden="true"></i></a>
+                                    <a href="javascript:void(0);" id="tree_upLevel" class="btn btn-sm " data-toggle="tooltip" data-placement="bottom" title="" data-original-title="升级"><i class="fa fa-arrow-left" aria-hidden="true"></i></a>
+                                    <a href="javascript:void(0);" id="tree_downLevel" class="btn btn-sm " data-toggle="tooltip" data-placement="bottom" title="" data-original-title="降级"><i class="fa fa-arrow-right" aria-hidden="true"></i></a>
+                                    <a href="javascript:void(0);" id="tree_downMove" class="btn btn-sm" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="下移"><i class="fa fa-arrow-down" aria-hidden="true"></i></a>
+                                    <a href="javascript:void(0);" id="tree_upMove" class="btn btn-sm" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="上移"><i class="fa fa-arrow-up" aria-hidden="true"></i></a>
+                                </div>
+                                <div>
+                                    <input type="text" class="form-control form-control-sm" placeholder="搜索定额" value="" id="rationSearch">
+                                </div>
                             </div>
                             <div class="tab-content" id="sectionSpread" style="overflow: hidden">
                             </div>

+ 48 - 21
web/maintain/ration_repository/js/coe.js

@@ -23,13 +23,15 @@ $(document).ready(function () {
     }
     //定额章节树与定额表
     let leftElesObj = {};
+    leftElesObj.module = moduleName;
     leftElesObj.resize = $('#slideResizeLeft');
     leftElesObj.parent = $('#dataRow');
     leftElesObj.left = $('#leftContent');
     leftElesObj.right = $('#mainContent');
     let maxEval = `$('#zmhsContent').is(':visible') ? $('#dataRow').width() - $('#zmhsContent').width() - 300 : $('#dataRow').width()  - 300`;
-    SlideResize.horizontalSlide(moduleName, leftElesObj, {min: 300, max: maxEval}, function () {
+    SlideResize.horizontalSlide(leftElesObj, {min: 300, max: maxEval}, function () {
         refreshALlWorkBook();
+        sectionTreeObj.loadRateWidth();
     });
     SlideResize.loadHorizonWidth(moduleName, [$('#slideResizeLeft')], [$('#leftContent'), $('#mainContent')], function () {
         //refreshAfterZmhs(false);
@@ -43,12 +45,13 @@ $(document).ready(function () {
     });
     //定额表与子目换算表
     let rightElesObj = {};
+    rightElesObj.module = moduleName;
     rightElesObj.resize = $('#slideResizeRight');
     rightElesObj.parent = $('#dataRow');
     rightElesObj.left = $('#mainContent');
     rightElesObj.right = $('#zmhsContent');
     let maxEvalRight = `$('#dataRow').width() - $('#leftContent').width() - 200`;
-    SlideResize.horizontalSlide(moduleName, rightElesObj, {min: 200, max: maxEvalRight}, function () {
+    SlideResize.horizontalSlide(rightElesObj, {min: 200, max: maxEvalRight}, function () {
         refreshALlWorkBook();
     });
     //设置水平拖动条的宽度
@@ -102,6 +105,7 @@ $(document).ready(function () {
         for (let resize of resizes) {
             setResizeWidth(resize);
         }
+        sectionTreeObj.loadRateWidth();
     }
     $('#zmhs').click(function () {
         if(!$(this).hasClass('active')){
@@ -121,7 +125,7 @@ $(document).ready(function () {
     });
     //子目换算和调整表上下拖动
     let zmhsAdjResize = getZmhsAdjResize();
-    SlideResize.verticalSlide(moduleName, zmhsAdjResize.eleObj, zmhsAdjResize.limit, function () {
+    SlideResize.verticalSlide(zmhsAdjResize.eleObj, zmhsAdjResize.limit, function () {
         if (coeOprObj.workBook) {
             coeOprObj.workBook.refresh();
         }
@@ -134,6 +138,7 @@ $(document).ready(function () {
 function getZmhsAdjResize() {
     let zmhsAdjResize = {};
     zmhsAdjResize.eleObj = {
+        module: moduleName,
         resize: $('#zmhsAdjResize'),
         top: $('#mainSpread'),
         topSpread: $('#mainSpread'),
@@ -153,7 +158,7 @@ function loadZmhsAdjSize(resizeObj) {
     if (!resizeObj) {
         resizeObj = getZmhsAdjResize();
     }
-    SlideResize.loadVerticalHeight(moduleName, resizeObj.eleObj, resizeObj.limit, function () {
+    SlideResize.loadVerticalHeight(resizeObj.eleObj.module, resizeObj.eleObj, resizeObj.limit, function () {
         if (coeOprObj.workBook) {
             coeOprObj.workBook.refresh();
         }
@@ -224,8 +229,10 @@ let coeOprObj = {
     setting: {
         header: [
             {headerName:"编号", headerWidth:50, dataCode:"serialNo", dataType: "String", hAlign: "center", vAlign: "center", readOnly: false},
-            {headerName:"名称", headerWidth:280, dataCode:"name", dataType: "String", hAlign: "left", vAlign: "center", readOnly: false},
+            {headerName:"名称", headerWidth:200, dataCode:"name", dataType: "String", hAlign: "left", vAlign: "center", readOnly: false},
             {headerName:"内容", headerWidth:150, dataCode:"content", dataType: "String", hAlign: "left", vAlign: "center", readOnly: false},
+            {headerName:"原人材机编码", headerWidth:90, dataCode:"original_code", dataType: "String", hAlign: "center", vAlign: "center", readOnly: false},
+            {headerName:"可选人材机编码", headerWidth:150, dataCode:"option_codes", dataType: "String", hAlign: "center", vAlign: "center", readOnly: false}
         ]
     },
     buildSheet: function (container) {
@@ -286,6 +293,7 @@ let coeOprObj = {
                     }
                     else {
                         updateObj[dataCode] = inputT;
+                        me.setOptionList(dataCode,inputT,updateObj);
                         updateArr.push(updateObj);
                         me.save([], updateArr, [], true);
                     }
@@ -316,6 +324,7 @@ let coeOprObj = {
                 else{
                     newCoe.serialNo = ++me.currentMaxNo;
                     newCoe[dataCode] = inputT;
+                    me.setOptionList(dataCode,inputT,newCoe);
                     addArr.push(newCoe);
                     me.save(addArr, [], [], true, function (result) {
                         me.updateCurrentCoeList(result);
@@ -324,6 +333,18 @@ let coeOprObj = {
             }
         }
     },
+    setOptionList:function (dataCode,inputT,obj) {
+        if(dataCode == "option_codes"){//所选人材的情况,要获取人材机下拉列表
+            inputT = inputT.replace(/[\s\r\n]/g, "")//去掉空格换行等字符
+            let optionList = [];
+            let options = inputT.split("|");
+            for(let code of options){
+                let name = gljAdjOprObj.getGljName(code,gljAdjOprObj.gljList,true);
+                if(name) optionList.push({text:name,value:code});
+            }
+            obj.option_list = optionList;
+        }
+    },
     onClipboardPasting: function (sender, info) {
         let me = coeOprObj, maxCol = info.cellRange.col + info.cellRange.colCount - 1;
         if(maxCol > me.setting.header.length){
@@ -532,9 +553,9 @@ let gljAdjOprObj = {
         ],
         comboItems: {
             //调整类型下拉菜单
-            coeType: ['定额', '人工', '材料', '机械', '主材', '设备', '单个工料机','替换人材机'],
+            coeType: ['定额', '人工', '材料', '机械', '主材', '设备', '单个工料机','替换人材机',"所选人材机"],
             //操作符下拉菜单
-            operator: ['+', '-', '*', '/', '=']
+            operator: ['+', '-', '*', '/', '=','+*','-*']
         }
     },
     buildSheet: function (container) {
@@ -660,7 +681,7 @@ let gljAdjOprObj = {
     onClipboardPasting: function (sender, info) {
 
     },
-    getValidPasteDatas: function (pasteItems, info) {
+    getValidPasteDatas: function (pasteItems, info) {//2018-12-21  这里的if else 太多了,不好维护
         let me = gljAdjOprObj;
         let rst = [];
         for(let i = 0, len = pasteItems.length; i < len; i++){
@@ -669,20 +690,21 @@ let gljAdjOprObj = {
             //update
             if(row < me.currentGljAdjList.length){
                 let updateObj = me.currentGljAdjList[row];
+                validObj.index = row;//要有下标做为匹配的依据,不然在复制多行并且某个单元格是只读的情况下,这里返回的updateList个数会比选中的行数少,造成更新行和实际不匹配的情况
                 if(typeof pasteItems[i].coeType !== 'undefined' && typeof pasteItems[i].gljCode !== 'undefined'){
                     let gljName = me.getGljName(pasteItems[i].gljCode, me.gljList);
-                    if(pasteItems[i].coeType === '单个工料机' && gljName){
+                    if((updateObj.coeType === '单个工料机'||updateObj.coeType === '替换人材机') && gljName){
                         validObj.coeType = pasteItems[i].coeType;
                         validObj.gljCode = pasteItems[i].gljCode;
                         validObj.gljName = gljName;
                     }
-                    else if(pasteItems[i].coeType !== '单个工料机' && me.setting.comboItems.coeType.indexOf(pasteItems[i].coeType) !== -1){
+                    else if((pasteItems[i].coeType !== '单个工料机'||pasteItems[i].coeType !== '替换人材机') && me.setting.comboItems.coeType.indexOf(pasteItems[i].coeType) !== -1){
                         validObj.coeType = pasteItems[i].coeType;
                     }
                 }
                 else if(typeof pasteItems[i].coeType === 'undefined' && typeof pasteItems[i].gljCode !== 'undefined'){
                     let gljName = me.getGljName(pasteItems[i].gljCode, me.gljList);
-                    if(typeof updateObj.coeType !== 'undefined' && updateObj.coeType === '单个工料机' && gljName){
+                    if(typeof updateObj.coeType !== 'undefined' && (updateObj.coeType === '单个工料机'||updateObj.coeType === '替换人材机') && gljName){
                         validObj.gljCode = pasteItems[i].gljCode;
                         validObj.gljName = gljName;
                     }
@@ -690,13 +712,12 @@ let gljAdjOprObj = {
                 else if(typeof pasteItems[i].coeType !== 'undefined' && typeof pasteItems[i].gljCode === 'undefined'){
                     if(me.setting.comboItems.coeType.indexOf(pasteItems[i].coeType) !== -1){
                         validObj.coeType = pasteItems[i].coeType;
-                        if(validObj.coeType !== '单个工料机' && typeof updateObj.gljCode !== '单个工料机' && updateObj.gljCode.toString().trim().length > 0){
+                        if(validObj.coeType !== '单个工料机' && typeof updateObj.coeType !== '单个工料机' && updateObj.gljCode.toString().trim().length > 0){
                             validObj.gljCode = '';
                             validObj.gljName = '';
                         }
                     }
-                }
-                else {
+                } else {
                     if(typeof pasteItems[i].operator !== 'undefined' && me.setting.comboItems.operator.indexOf(pasteItems[i].operator) !== -1){
                         validObj.operator = pasteItems[i].operator;
                     }
@@ -704,16 +725,21 @@ let gljAdjOprObj = {
                         validObj.amount = pasteItems[i].amount;
                     }
                 }
+                if(typeof pasteItems[i].replaceCode !== 'undefined' && updateObj.coeType === '替换人材机'){
+                    let gljName = me.getGljName(pasteItems[i].replaceCode, me.gljList);
+                    validObj.replaceCode = pasteItems[i].replaceCode;
+                    validObj.replaceName = gljName;
+                }
             }
             else {
                 if(typeof pasteItems[i].coeType !== 'undefined' && typeof pasteItems[i].gljCode !== 'undefined'){
                     let gljName = me.getGljName(pasteItems[i].gljCode, me.gljList);
-                    if(pasteItems[i].coeType === '单个工料机' && gljName){
+                    if((pasteItems[i].coeType === '单个工料机'||pasteItems[i].coeType === '替换人材机') && gljName){
                         validObj.coeType = pasteItems[i].coeType;
                         validObj.gljCode = pasteItems[i].gljCode;
                         validObj.gljName = gljName;
                     }
-                    else if(pasteItems[i].coeType !== '单个工料机' && me.setting.comboItems.coeType.indexOf(pasteItems[i].coeType) !== -1){
+                    else if((pasteItems[i].coeType !== '单个工料机'||pasteItems[i].coeType !== '替换人材机') && me.setting.comboItems.coeType.indexOf(pasteItems[i].coeType) !== -1){
                         validObj.coeType = pasteItems[i].coeType;
                     }
                 }
@@ -742,8 +768,9 @@ let gljAdjOprObj = {
         for(let i = 0, len = validDatas.length; i < len; i++){
             row = i + info.cellRange.row;
             //update
-            if(row < me.currentGljAdjList.length){
-                let updateObj = me.currentGljAdjList[row];
+            if(row < me.currentGljAdjList.length && typeof validDatas[i].index !=='undefined'){
+                let updateObj = me.currentGljAdjList[validDatas[i].index];//这里改成读取下标
+                delete  validDatas[i].index; //清除下标
                 for(let attr in validDatas[i]){
                     updateObj[attr] = validDatas[i][attr];
                 }
@@ -785,11 +812,11 @@ let gljAdjOprObj = {
         workBook.commandManager().setShortcutKey(null, GC.Spread.Commands.Key.del, false, false, false, false);
         workBook.commandManager().setShortcutKey('gljAdjDel', GC.Spread.Commands.Key.del, false, false, false, false);
     },
-    getGljName: function (gljCode, gljList) {
+    getGljName: function (gljCode, gljList,withSpecs) {//withSpecs 是否带上规格型号
         let rst = null;
         for(let i = 0, len = gljList.length; i < len; i++){
             if(gljCode === gljList[i].code){
-                rst = gljList[i].name;
+                rst = withSpecs == true ?gljList[i].name +" - "+gljList[i].specs :gljList[i].name;
                 break;
             }
         }
@@ -804,7 +831,7 @@ let gljAdjOprObj = {
         $.ajax({
             type: 'post',
             url: '/stdGljRepository/api/getGljItemsOccupied',
-            data: {repId: pageObj.gljLibID, occupation: '-_id code name'},
+            data: {repId: pageObj.gljLibID, occupation: '-_id code name specs'},
             dataType: 'json',
             timeout: 5000,
             success:function(result){

+ 6 - 3
web/maintain/ration_repository/js/gljSelect.js

@@ -40,6 +40,7 @@ let gljSelOprObj = {
         }
     },
     getSelGljItems: function(stdGljLibId, callback) {
+        $.bootstrapLoading.start();
         let me = this;
         $.ajax({
             type:"POST",
@@ -47,7 +48,7 @@ let gljSelOprObj = {
             data:{"repositoryId": stdGljLibId},
             dataType:"json",
             cache:false,
-            timeout:20000,
+            timeout:240000,
             success:function(result){
                 if(!result.error) {
                     if(priceProperties && priceProperties.length > 0){
@@ -63,9 +64,11 @@ let gljSelOprObj = {
                         callback();
                     }
                 }
+                $.bootstrapLoading.end();
             },
             error:function(err){
-                alert(err.responseJSON.error);
+                $.bootstrapLoading.end();
+                alert('获取人材机失败');
             }
         });
     },
@@ -126,7 +129,7 @@ let gljSelOprObj = {
                 }
                 if(!isExist){
                     thisGlj.consumeAmt = 0;
-                    me.selectedList.push(thisGlj);
+                    me.selectedList.push(_.cloneDeep(thisGlj));
                 }
             }
             else if(val === false){

+ 1 - 0
web/maintain/ration_repository/js/global.js

@@ -27,6 +27,7 @@ function autoFlashHeight(){
     $('#ruleTextShow').height($(window).height()-headerHeight-toolsBar-100);
     typeof loadRationSubSize !== 'undefined' ? loadRationSubSize() : '';
     typeof loadZmhsAdjSize !== 'undefined' ? loadZmhsAdjSize() : '';
+    typeof sectionTreeObj !== 'undefined' ? sectionTreeObj.loadRateWidth() : '';
 };
 $(window).resize(autoFlashHeight);
 /*全局自适应高度结束*/

+ 53 - 14
web/maintain/ration_repository/js/main.js

@@ -6,6 +6,8 @@ $(function () {
     let dispNameArr;
     let preDeleteId = null;
     let deleteCount = 0;
+    let selCompilationId,
+        compilationsArr = [];
     $('#del').on('hidden.bs.modal', function () {
         deleteCount = 0;
     });
@@ -124,7 +126,9 @@ $(function () {
         });
 
     });
-    getCompilationList();
+    getCompilationList(function (data) {
+        compilationsArr = data.compilation;
+    });
 
     // 导入原始数据按钮
     let rationRepId = 0;
@@ -216,6 +220,46 @@ $(function () {
         }
         window.location.href = '/rationRepository/api/export?rationRepId=' + id;
     });
+
+    //设置补充定额库章节树模板
+    $("#showArea").on("click", ".set-comple", function () {
+        let id = $(this).data("id");
+        id = parseInt(id);
+        if (isNaN(id) || id <= 0) {
+            return false;
+        }
+        rationRepId = id;
+        $('#templateA').addClass('disabled');
+        $('#template').modal('show');
+        $('#compilations').empty();
+        for (let data of compilationsArr) {
+            let $opt = $(`<option value="${data._id}">${data.name}</option>`);
+            $('#compilations').append($opt);
+        }
+        $('#compilations').change();
+    });
+    $('#compilations').change(function () {
+        selCompilationId = $(this).select().val();
+        CommonAjax.get(`api/sectionTemplateCount/${selCompilationId}`, function (rstData) {
+            rstData.data.count > 0 ?
+                $('#templateText').text('该费用定额下已有定额章节树模板数据,是否确认覆盖数据?') :
+                $('#templateText').text('确认是否将此库的章节树设置成该费用定额下补充定额章节树模板?');
+            $('#templateA').removeClass('disabled');
+        });
+    });
+    $('#templateA').click(function () {
+        if (rationRepId <= 0 && selCompilationId) {
+            return false;
+        }
+        $.bootstrapLoading.start();
+        CommonAjax.post('api/initSectionTemplate', {rationLibId: rationRepId, compilationId: selCompilationId}, function () {
+            $.bootstrapLoading.end();
+            $('#template').modal('hide');
+        }, function () {
+            $.bootstrapLoading.end();
+            $('#template').modal('hide');
+        });
+    });
 });
 
 function getAllRationLib(callback){
@@ -237,8 +281,8 @@ function getAllRationLib(callback){
                     let compilationName = result.data[i].compilationName;
                     dispNames.push(result.data[i].dispName);
                     $("#showArea").append(
-                        "<tr id='tempId'>" +
-                        "<td><a href='/stdGljRepository/glj'>"+libName+"</a></td>" +
+                        "<tr id='"+id+"'>" +
+                        "<td><a href='/rationRepository/ration?repository=" + id +"'>"+libName+"</a></td>" +
                         "<td>"+compilationName+" </td>" +
                         "<td>"+createDate+" </td>" +
                         "<td><a href='javascript:void(0);' data-toggle='modal' data-target='#edit' title='编辑'>" +
@@ -248,23 +292,20 @@ function getAllRationLib(callback){
                         "<td><a class='btn btn-secondary btn-sm import-source' href='javacript:void(0);' data-id='"+ id +"' title='导入原始数据'><i class='fa fa-sign-in fa-rotate-90'></i>导入</a></td>" +
                         "<td><a class='btn btn-success btn-sm export' href='javacript:void(0);' data-toggle='modal' data-id='"+ id +"' data-target='#emport' title='导出内部数据'><i class='fa fa-sign-out fa-rotate-270'></i>导出</a> " +
                         "<a class='btn btn-secondary btn-sm import-data' href='javacript:void(0);' data-id='"+ id +"' title='导入内部数据'><i class='fa fa-sign-in fa-rotate-90'></i>导入</a></td>" +
+                        "<td><a class='btn btn-secondary btn-sm set-comple' href='javacript:void(0);' data-id='"+ id +"' title='将章节树设为补充模板数据'><i class='fa fa-sign-in fa-rotate-90'></i>设置</a></td>" +
                         "</tr>");
-                    var newHref = "/rationRepository/ration?repository="+id;
-                    $("#tempId td:first a").attr("href", newHref);
-                    $("#tempId").attr("id", id);
                 }
             }
             callback(dispNames);
         }
     });
 }
-function getCompilationList(){
+function getCompilationList(callback){
     $.ajax({
         type: 'post',
         url: 'api/getCompilationList',
         dataType: 'json',
         success: function (result) {
-            console.log(result);
             //addoptions
             for(let i = 0; i < result.data.compilation.length; i++){
                 let $option =  $("<option >"+ result.data.compilation[i].name +"</option>");
@@ -276,7 +317,6 @@ function getCompilationList(){
                 let compilationId = result.data.compilation[0]._id;
                 //console.log(compilationId);
                 let gljLibOps = getGljLibOps(compilationId, result.data.gljLibs);
-                console.log(gljLibOps);
                 for(let i = 0; i < gljLibOps.length; i++){
                     let $option =  $("<option >"+ gljLibOps[i].dispName +"</option>");
                     $option.val(gljLibOps[i].ID);
@@ -294,6 +334,7 @@ function getCompilationList(){
                     $('#gljLibSels').append($option);
                 }
             });
+            callback(result.data);
         }
     });
 }
@@ -327,8 +368,8 @@ function createRationLib(rationObj, dispNamesArr){
                 let compilationName = result.data.compilationName;
                 dispNamesArr.push(libName);
                 $("#showArea").append(
-                    "<tr id='tempId'>" +
-                    "<td><a href='/stdGljRepository/glj'>"+libName+"</a></td>" +
+                    "<tr id='"+id+"'>" +
+                    "<td><a href='/rationRepository/ration?repository=" + id +"'>"+libName+"</a></td>" +
                     "<td>"+compilationName+" </td>" +
                     "<td>"+createDate+" </td>" +
                     "<td><a href='javascript:void(0);' data-toggle='modal' data-target='#edit' title='编辑'>" +
@@ -338,10 +379,8 @@ function createRationLib(rationObj, dispNamesArr){
                     "<td><a class='btn btn-secondary btn-sm import-source' href='javacript:void(0);' data-id='"+ id +"' title='导入原始数据'><i class='fa fa-sign-in fa-rotate-90'></i>导入</a></td>" +
                     "<td><a class='btn btn-success btn-sm export' href='javacript:void(0);' data-toggle='modal' data-id='"+ id +"' data-target='#emport' title='导出内部数据'><i class='fa fa-sign-out fa-rotate-270'></i>导出</a> " +
                     "<a class='btn btn-secondary btn-sm import-data' href='javacript:void(0);' data-id='"+ id +"' title='导入内部数据'><i class='fa fa-sign-in fa-rotate-90'></i>导入</a></td>" +
+                    "<td><a class='btn btn-secondary btn-sm set-comple' href='javacript:void(0);' data-id='"+ id +"' title='将章节树设为补充模板数据'><i class='fa fa-sign-in fa-rotate-90'></i>设置</a></td>" +
                     "</tr>");
-                var newHref = "/rationRepository/ration?repository="+id;
-                $("#tempId td:first a").attr("href", newHref);
-                $("#tempId").attr("id", id);
             }
             $('#cancelBtn').click();
         }

+ 6 - 4
web/maintain/ration_repository/js/ration.js

@@ -5,7 +5,7 @@
 $(document).ready(function () {
    //定额表与下方子表上下拖动
     let rationSubResize = getRationSubResize();
-    SlideResize.verticalSlide(moduleName, rationSubResize.eleObj, rationSubResize.limit, function () {
+    SlideResize.verticalSlide(rationSubResize.eleObj, rationSubResize.limit, function () {
         if (rationOprObj.workBook) {
             rationOprObj.workBook.refresh();
         }
@@ -13,7 +13,7 @@ $(document).ready(function () {
             rationGLJOprObj.sheet.getParent().refresh();
         }
     });
-    SlideResize.loadVerticalHeight(moduleName, rationSubResize.eleObj, rationSubResize.limit, function () {
+    SlideResize.loadVerticalHeight(rationSubResize.eleObj.module, rationSubResize.eleObj, rationSubResize.limit, function () {
         if (rationOprObj.workBook) {
             rationOprObj.workBook.refresh();
         }
@@ -25,6 +25,7 @@ $(document).ready(function () {
 function getRationSubResize() {
     let rationSubResize = {};
     rationSubResize.eleObj = {
+        module: moduleName,
         resize: $('#rationSubResize'),
         top: $('#rationItemsSheet'),
         topSpread: $('#rationItemsSheet'),
@@ -44,7 +45,7 @@ function loadRationSubSize(resizeObj) {
     if (!resizeObj) {
         resizeObj = getRationSubResize();
     }
-    SlideResize.loadVerticalHeight(moduleName, resizeObj.eleObj, resizeObj.limit, function () {
+    SlideResize.loadVerticalHeight(resizeObj.eleObj.module, resizeObj.eleObj, resizeObj.limit, function () {
         if (rationOprObj.workBook) {
             rationOprObj.workBook.refresh();
         }
@@ -692,6 +693,7 @@ let rationOprObj = {
             }
         });
     },
+    doAfterGetRation: null,
     getRationItems: function(sectionID, callback = null){
         if (sectionID != -1) {
             let me = rationOprObj;
@@ -729,7 +731,7 @@ let rationOprObj = {
                         }
                         sectionTreeObj.removeBtn.removeClass('disabled');
                         if(callback) {
-                            callback();
+                            callback(result.data);
                         }
                     },
                     error:function(err){

+ 14 - 4
web/maintain/ration_repository/js/ration_template.js

@@ -84,6 +84,9 @@ const RationTemplate = (function () {
                 text = validateData(dataCode, text);
                 if (text !== '') {
                     rowExistData = true;
+                    if (dataCode === 'code') {//编码没有小写,自动转化为大写
+                        text = text.toString().toUpperCase();
+                    }
                     rowData[dataCode] = text;
                 } else {
                     if (dataCode === 'code') {
@@ -123,6 +126,12 @@ const RationTemplate = (function () {
         onEnterCell: function (sender, args) {
             args.sheet.repaint();
         },
+        onEditStarting: function (sender, args) {
+            let dataCode = setting.header[args.col]['dataCode'];
+            if (dataCode === 'name') {
+                args.cancel = true;
+            }
+        },
         onEditEnded: function (sender, args) {
             edit();
         },
@@ -163,6 +172,7 @@ const RationTemplate = (function () {
         templateSheet.options.isProtected = true;
         setComboCells();
         const Events = GC.Spread.Sheets.Events;
+        sheet.bind(Events.EditStarting, events.onEditStarting);
         sheet.bind(Events.EditEnded, events.onEditEnded);
         sheet.bind(Events.RangeChanged, events.onRangeChanged);
         sheet.bind(Events.EnterCell, events.onEnterCell);
@@ -173,11 +183,11 @@ const RationTemplate = (function () {
     function changeLockMode(locked) {
         if (templateSheet) {
             if (!locked) {
-                templateSheet.getRange(-1, 0, -1, 2).locked(false);
-                templateSheet.getRange(-1, 3, -1, 1).locked(false);
+                templateSheet.getRange(-1, 0, -1, 4).locked(false);
+                //templateSheet.getRange(-1, 3, -1, 1).locked(false);
             } else {
-                templateSheet.getRange(-1, 0, -1, 2).locked(true);
-                templateSheet.getRange(-1, 3, -1, 1).locked(true);
+                templateSheet.getRange(-1, 0, -1, 4).locked(true);
+                //templateSheet.getRange(-1, 3, -1, 1).locked(true);
             }
         }
     }

+ 65 - 7
web/maintain/ration_repository/js/section_tree.js

@@ -234,7 +234,15 @@ let sectionTreeObj = {
             });
         }
     },
-
+    loadRateWidth: function () {
+        if (this.workBook) {
+            //ID列固定40宽度
+            let spreadWidth = $('#sectionSpread').width() - 65; //65: 列头宽度和垂直滚动条宽度和
+            let IDRate = 40 / spreadWidth,
+                nameRate = 1 - IDRate;
+            sheetCommonObj.setColumnWidthByRate($('#sectionSpread').width() - 65, this.workBook, [{rateWidth: IDRate}, {rateWidth: nameRate}]);
+        }
+    },
     getSectionTree: function (repId) {
         let me = sectionTreeObj;
         let url = 'api/getRationTree';
@@ -253,6 +261,7 @@ let sectionTreeObj = {
             me.sheet.setFormatter(-1, 0, '@');
             me.initSelection(me.tree.selected);
             explanatoryOprObj.bindEvents(exEditor, calcEditor);
+            me.loadRateWidth();
         };
         let errFunc = function () {
 
@@ -616,7 +625,7 @@ let sectionTreeObj = {
         }
     },
     //模仿默认点击
-    initSelection: function (node) {
+    initSelection: function (node, doAfterGetRation = null) {
         if (node && node.tree){
             node.tree.selected = node ? node : null;
         }
@@ -637,10 +646,17 @@ let sectionTreeObj = {
             me.removeBtn.addClass('disabled');
             rationOprObj.canRations = true;
             rationOprObj.workBook.getSheet(0).clearSelection();
-            rationOprObj.getRationItems(node.data.ID, function () {
-                rationOprObj.workBook.getActiveSheet().setActiveCell(0, 0);
-                rationOprObj.rationSelInit(0, true);
-            });
+            //获取定额后的回调操作:1.正常变更章节树节点,则默认获取定额后定位至首行定额 2.搜索定额后,获取定额后定位至匹配到的定额
+            if (doAfterGetRation && typeof doAfterGetRation === 'function') {
+                rationOprObj.doAfterGetRation = doAfterGetRation;
+            } else {
+                rationOprObj.doAfterGetRation = function (rations) {
+                    rationOprObj.workBook.getActiveSheet().setActiveCell(0, 0);
+                    rationOprObj.rationSelInit(0, true);
+                    rationOprObj.workBook.getActiveSheet().showRow(0, GC.Spread.Sheets.VerticalPosition.top);
+                };
+            }
+            rationOprObj.getRationItems(node.data.ID, rationOprObj.doAfterGetRation);
             rationOprObj.setCombo(rationOprObj.workBook.getSheet(0), 'dynamic');
         }
         else {
@@ -660,5 +676,47 @@ let sectionTreeObj = {
             sheetCommonObj.cleanSheet(rationInstObj.sheet, rationInstObj.setting, -1);
         }
         me.workBook.focus(true);
+    },
+    //根据定额定位至章节树
+    locateToSection: function (rationCode) {
+        let me = this;
+        //去后台搜索该定额
+        CommonAjax.post('/rationRepository/api/getRationItem', {rationLibId: pageOprObj.rationLibId, code: rationCode}, function (rstData) {
+            if (!rstData) {
+                alert(`不存在定额${rationCode}`);
+                return;
+            }
+            //定位至相关章节
+            let sectionId = rstData.sectionId;
+            if (!sectionId) {
+                return;
+            }
+            let sectionNode = me.tree.nodes[`id_${sectionId}`];
+            if (!sectionNode) {
+                return;
+            }
+            me.sheet.setActiveCell(sectionNode.serialNo(), 1);
+            let doAfterGetRation = function (rations) {
+                let findRation = _.find(rations, {code: rationCode}),
+                    rIdx = rations.indexOf(findRation),
+                    rationSheet = rationOprObj.workBook.getActiveSheet();
+                rationSheet.setActiveCell(rIdx, 0);
+                rationOprObj.rationSelInit(rIdx, true);
+                rationOprObj.workBook.getActiveSheet().showRow(rIdx, GC.Spread.Sheets.VerticalPosition.top);
+            };
+            me.initSelection(sectionNode, doAfterGetRation);
+        }, function () {
+        });
     }
-};
+};
+$(document).ready(function () {
+    $('#rationSearch').keydown(function (event) {
+        if(event.keyCode === 13){
+            $(this).blur();
+            let rationCode = $(this).val().toUpperCase();
+            if (rationCode) {
+                sectionTreeObj.locateToSection(rationCode);
+            }
+        }
+    });
+});

+ 26 - 2
web/maintain/ration_repository/main.html

@@ -35,7 +35,7 @@
                   <div class="col-md-8">
                     <div class="warp-p2 mt-3">
                       <table class="table table-hover table-bordered">
-                        <thead><tr><th>定额库名称</th><th width="160">编办</th><th width="160">添加时间</th><th width="90">操作</th><th width="90">原始数据</th><th width="150">内部数据</th></tr></thead>
+                        <thead><tr><th>定额库名称</th><th width="160">费用定额</th><th width="160">添加时间</th><th width="90">操作</th><th width="90">原始数据</th><th width="150">内部数据</th><th width="90">补充模板</th></tr></thead>
                         <tbody id="showArea">
                         </tbody>
                       </table>
@@ -86,7 +86,7 @@
                             <input id="libNameTxt" class="form-control" placeholder="输入定额库名称" type="text">
                         </div>
                         <div class="form-group">
-                            <label>编办名称</label>
+                            <label>费用定额名称</label>
                             <select id="compilationSels" class="form-control"></select>
                         </div>
                         <div class="form-group">
@@ -229,6 +229,30 @@
             </div>
         </div>
     </div>
+    <!--弹出设置模板-->
+    <div class="modal fade" id="template" data-backdrop="static" style="display: none;" aria-hidden="true">
+        <div class="modal-dialog" role="document">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <h5 class="modal-title">设置确认</h5>
+                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                        <span aria-hidden="true">×</span>
+                    </button>
+                </div>
+                <div class="modal-body">
+                    <h5 id="templateText">确认是否将此库的章节树设置成该费用定额下补充定额章节树模板?</h5>
+                    <div class="form-group">
+                        <label>费用定额名称</label>
+                        <select id="compilations" class="form-control"></select>
+                    </div>
+                </div>
+                <div class="modal-footer">
+                    <a id="templateA" href="javascript: void(0);" class="btn btn-primary">确认</a>
+                    <button id="templateCancel" type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                </div>
+            </div>
+        </div>
+    </div>
     <!-- JS. -->
     <script src="/lib/jquery/jquery.min.js"></script>
     <script src="/lib/tether/tether.min.js"></script>

+ 27 - 3
web/maintain/std_glj_lib/html/main.html

@@ -33,7 +33,7 @@
                   <div class="col-md-8">
                     <div class="warp-p2 mt-3">
                       <table class="table table-hover table-bordered">
-                        <thead><tr><th>人材机库名称</th><th>编办</th><th>定额库</th><th width="160">添加时间</th><th width="90">操作</th><th width="90">价格数据</th></tr></thead>
+                        <thead><tr><th>人材机库名称</th><th>费用定额</th><th>定额库</th><th width="160">添加时间</th><th width="90">操作</th><th width="90">价格数据</th><th width="90">补充模板</th></tr></thead>
                         <tbody id="showArea">
                       <!--    <tr><td><a href="gongliao.html">XX工料机库</a></td><td>重庆2018</td><td>XXX定额库(重庆2018)</td><td>2017-01-01 </td><td><a href="javacript:void(0);" data-toggle="modal" data-target="#edit" title="编辑"><i class="fa fa-pencil-square-o"></i></a> <a href="javacript:void(0);" data-toggle="modal" data-target="#del" class="text-danger" title="删除"><i class="fa fa-remove"></i></a></td></tr>
                           <tr><td><a href="gongliao.html">XX工料机库</a></td><td>重庆2018</td><td></td><td>2017-01-01 </td><td><a href="javacript:void(0);" data-toggle="modal" data-target="#edit" title="编辑"><i class="fa fa-pencil-square-o"></i></a> <a href="javacript:void(0);" data-toggle="modal" data-target="#del" class="text-danger" title="删除"><i class="fa fa-remove"></i></a></td></tr>
@@ -63,7 +63,7 @@
                       <input id="libNameTxt" class="form-control" placeholder="输入人材机库名称" type="text">
                     </div>
                     <div class="form-group">
-                      <label>编办名称</label>
+                      <label>费用定额名称</label>
                       <select id="compilationSels" class="form-control"></select>
                     </div>
                   </form>
@@ -92,7 +92,7 @@
                       <input class="form-control" id="renameText" placeholder="输入人材机库名称" type="text" value="">
                     </div>
                     <div class="form-group">
-                      <label>编办名称</label>
+                      <label>费用定额名称</label>
                       <select id="compilationEdit" class="form-control" disabled><option></option></select>
                     </div>
                   </form>
@@ -153,6 +153,30 @@
             </div>
         </div>
     </div>
+    <!--弹出设置模板-->
+    <div class="modal fade" id="template" data-backdrop="static" style="display: none;" aria-hidden="true">
+        <div class="modal-dialog" role="document">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <h5 class="modal-title">设置确认</h5>
+                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                        <span aria-hidden="true">×</span>
+                    </button>
+                </div>
+                <div class="modal-body">
+                    <h5 id="templateText">确认是否将此库的分类树设置成该费用定额下补充人材机分类树模板?</h5>
+                    <div class="form-group">
+                        <label>费用定额名称</label>
+                        <select id="compilations" class="form-control"></select>
+                    </div>
+                </div>
+                <div class="modal-footer">
+                    <a id="templateA" href="javascript: void(0);" class="btn btn-primary">确认</a>
+                    <button id="templateCancel" type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                </div>
+            </div>
+        </div>
+    </div>
     <!-- JS. -->
     <script src="/lib/jquery/jquery.min.js"></script>
     <script src="/lib/tether/tether.min.js"></script>

+ 43 - 29
web/maintain/std_glj_lib/js/glj.js

@@ -20,20 +20,22 @@ $(document).ready(function () {
     });
     //章节树与人材机表
     let leftElesObj = {};
+    leftElesObj.module = moduleName;
     leftElesObj.resize = $('#slideResizeLeft');
     leftElesObj.parent = $('#dataRow');
     leftElesObj.left = $('#leftContent');
     leftElesObj.right = $('#midContent');
-    SlideResize.horizontalSlide(moduleName, leftElesObj, {min: 200, max: `$('#dataRow').width() - $('#rightContent').width() - 200`}, function () {
+    SlideResize.horizontalSlide(leftElesObj, {min: 200, max: `$('#dataRow').width() - $('#rightContent').width() - 200`}, function () {
         refreshALlWorkBook();
     });
     //人材机表与人材机组成物表
     let rightElesObj = {};
+    rightElesObj.module = moduleName;
     rightElesObj.resize = $('#slideResizeRight');
     rightElesObj.parent = $('#dataRow');
     rightElesObj.left = $('#midContent');
     rightElesObj.right = $('#rightContent');
-    SlideResize.horizontalSlide(moduleName, rightElesObj, {min: 200, max: `$('#dataRow').width() - $('#leftContent').width() - 200`}, function () {
+    SlideResize.horizontalSlide(rightElesObj, {min: 200, max: `$('#dataRow').width() - $('#leftContent').width() - 200`}, function () {
        refreshALlWorkBook();
     });
 });
@@ -373,7 +375,7 @@ let repositoryGljObj = {
             data:{"repositoryId": repId},
             dataType:"json",
             cache:false,
-            timeout:20000,
+            timeout:240000,
             success:function(result){
                 if(!result.error) {
                     me.gljList = result.data;
@@ -386,7 +388,7 @@ let repositoryGljObj = {
                 }
             },
             error:function(err){
-                alert(err.responseJSON.error);
+                alert(err);
             }
         })
     },
@@ -480,7 +482,9 @@ let repositoryGljObj = {
     },
 
     getCurrentComponent: function (gljComponent, sort = false) {
-        let me = repositoryGljObj, rst = [];
+        let me = repositoryGljObj,
+            rst = [],
+            IDCodeMapping = {};
         for(let i = 0; i < gljComponent.length; i++){
             let obj = {};
             for(let j = 0; j < me.gljList.length; j++){
@@ -495,6 +499,7 @@ let repositoryGljObj = {
                     obj.consumeAmt = gljComponent[i].consumeAmt;
                     obj.consumeAmtProperty = gljComponent[i].consumeAmtProperty ? gljComponent[i].consumeAmtProperty : {};
                     rst.push(obj);
+                    IDCodeMapping[obj.ID] = obj.code;
                 }
             }
         }
@@ -505,6 +510,16 @@ let repositoryGljObj = {
                 else if(a.code < b.code) r = -1;
                 return r;
             });
+            gljComponent.sort(function (a, b) {
+               let aV = IDCodeMapping[a.ID],
+                   bV = IDCodeMapping[b.ID];
+               if (aV > bV) {
+                   return 1;
+               } else if (aV < bV) {
+                   return -1;
+               }
+               return 0;
+            });
         }
         return rst;
     },
@@ -1005,10 +1020,10 @@ let repositoryGljObj = {
                                 }
                             }
                             me.mixUpdateRequest(updateArr, [], removeIDs);
-                            if(updateBasePrcArr.length > 0 && me.rationLibs.length > 0){
+                           /* if(updateBasePrcArr.length > 0 && me.rationLibs.length > 0){
                                 me.updateRationBasePrcRq(updateBasePrcArr);
                                 me.workBook.focus(true);
-                            }
+                            }*/
                         });
                     }
                 }, function () {
@@ -1383,6 +1398,7 @@ let repositoryGljObj = {
         }
     },
     onClipboardPasted: function(e, info) {
+        $.bootstrapLoading.start();
         let me = repositoryGljObj;
         let updateArr = [], addArr = [];
         let items = sheetCommonObj.analyzePasteData(me.setting, info);
@@ -1477,6 +1493,8 @@ let repositoryGljObj = {
         }
         if (updateArr.length > 0 || addArr.length > 0) {
             me.mixUpdateRequest(updateArr, addArr, []);
+        } else {
+            $.bootstrapLoading.end();
         }
         if(updateBasePrcArr.length > 0 && me.rationLibs.length > 0){
             me.updateRationBasePrcRq(updateBasePrcArr);
@@ -1485,7 +1503,9 @@ let repositoryGljObj = {
     updateRationBasePrcRq: function (basePrcArr, workBook, callback) {
         let me = this;
         me.prevent = true;
-        $.bootstrapLoading.start();
+        if (!$.bootstrapLoading.isLoading()) {
+            $.bootstrapLoading.start();
+        }
         $.ajax({
             type: 'post',
             url: 'api/updateRationBasePrc',
@@ -1505,7 +1525,9 @@ let repositoryGljObj = {
                 if(callback){
                     callback();
                 }
-                $.bootstrapLoading.end();
+                if ($.bootstrapLoading.isLoading()) {
+                    $.bootstrapLoading.end();
+                }
             }
         });
     },
@@ -1544,8 +1566,14 @@ let repositoryGljObj = {
                     sheetCommonObj.cleanData(gljComponentOprObj.workBook.getSheet(0), gljComponentOprObj.setting, -1);
                     sheetsOprObj.showData(gljComponentOprObj, gljComponentOprObj.workBook.getSheet(0), gljComponentOprObj.setting, me.currentComponent);
                 }
+                if ($.bootstrapLoading.isLoading()) {
+                    $.bootstrapLoading.end();
+                }
             },
             error:function(err){
+                if ($.bootstrapLoading.isLoading()) {
+                    $.bootstrapLoading.end();
+                }
                 console.log(err);
                 alert("保存失败");
             }
@@ -1672,26 +1700,12 @@ let repositoryGljObj = {
             }
             return 0;
         }
-      /*  if(this.currentOprParent){
-            datas.sort(function (a, b) {
-                let rst = 0;
-                if(a.code > b.code){
-                    rst = 1;
-                }
-                else if(a.code < b.code){
-                    rst = -1;
-                }
-                return rst;
-            });
-        }
-        else {*/
-            //排序符号-
-            datas.sort(function (a, b) {
-                let aArr = a.code.split('-'),
-                    bArr = b.code.split('-');
-                return recurCompare(aArr, bArr, 0);
-            });
-       // }
+        //排序符号-
+        datas.sort(function (a, b) {
+            let aArr = a.code.split('-'),
+                bArr = b.code.split('-');
+            return recurCompare(aArr, bArr, 0);
+        });
     },
     //工料机排序
     sortGlj: function() {

+ 47 - 10
web/maintain/std_glj_lib/js/main.js

@@ -7,6 +7,7 @@ $(function () {
     let usedCom;
     let deleteCount = 0;
     let preDeleteId = null;
+    let selCompilationId;
     $('#del').on('hidden.bs.modal', function () {
         deleteCount = 0;
     });
@@ -186,6 +187,45 @@ $(function () {
             $.bootstrapLoading.end();
         }
     });
+    //设置补充人材机库分类树模板
+    $("#showArea").on("click", ".set-comple", function () {
+        let id = $(this).data("id");
+        id = parseInt(id);
+        if (isNaN(id) || id <= 0) {
+            return false;
+        }
+        selLibId = id;
+        $('#templateA').addClass('disabled');
+        $('#template').modal('show');
+        $('#compilations').empty();
+        for (let data of compilationsArr) {
+            let $opt = $(`<option value="${data._id}">${data.name}</option>`);
+            $('#compilations').append($opt);
+        }
+        $('#compilations').change();
+    });
+    $('#compilations').change(function () {
+        selCompilationId = $(this).select().val();
+        CommonAjax.get(`api/classTemplateCount/${selCompilationId}`, function (rstData) {
+            rstData.data.count > 0 ?
+                $('#templateText').text('该费用定额下已有人材机分类树模板数据,是否确认覆盖数据?') :
+                $('#templateText').text('确认是否将此库的分类树设置成该费用定额下补充人材机分类树模板?');
+            $('#templateA').removeClass('disabled');
+        });
+    });
+    $('#templateA').click(function () {
+        if (selLibId <= 0 && selCompilationId) {
+            return false;
+        }
+        $.bootstrapLoading.start();
+        CommonAjax.post('api/initClassTemplate', {gljLibId: selLibId, compilationId: selCompilationId}, function () {
+            $.bootstrapLoading.end();
+            $('#template').modal('hide');
+        }, function () {
+            $.bootstrapLoading.end();
+            $('#template').modal('hide');
+        });
+    });
 });
 
 function getAllGljLib(callback){
@@ -203,6 +243,7 @@ function getAllGljLib(callback){
                     let libName = result.data[i].dispName;
                     let createDate = result.data[i].createDate.split(' ')[0];
                     let compilationName = result.data[i].compilationName;
+                    let compilationId = result.data[i].compilationId;
                     let rationLibs = result.data[i].rationLibs;
                     let rationLibsName = '';
                     for(let j = 0; j < rationLibs.length; j++){
@@ -210,8 +251,8 @@ function getAllGljLib(callback){
                     }
                     dispNames.push(result.data[i].dispName);
                     $("#showArea").append(
-                        "<tr id='tempId'>" +
-                        "<td><a href='/stdGljRepository/glj'>"+libName+"</a></td>" +
+                        "<tr id='"+id+"' data-compilationId='"+ compilationId + "'>" +
+                        "<td><a href='/stdGljRepository/glj?gljLibId="+id+"'>"+libName+"</a></td>" +
                         "<td>"+compilationName+" </td>" +
                         "<td>"+rationLibsName+" </td>" +
                         "<td>"+createDate+" </td>" +
@@ -219,10 +260,8 @@ function getAllGljLib(callback){
                         "<i class='fa fa-pencil-square-o'></i></a> <a href='javascript:void(0);' data-toggle='modal' data-target='#del' class='text-danger' title='删除'>" +
                         "<i class='fa fa-remove'></i></a></td>" +
                         "<td><a class='btn btn-secondary btn-sm import-data' href='javacript:void(0);' data-id='"+ id +"' title='导入数据'><i class='fa fa-sign-in fa-rotate-90'></i>导入</a></td>" +
+                        "<td><a class='btn btn-secondary btn-sm set-comple' href='javacript:void(0);' data-id='"+ id +"' title='将分类树设为补充模板数据'><i class='fa fa-sign-in fa-rotate-90'></i>设置</a></td>" +
                         "</tr>");
-                    var newHref = "/stdGljRepository/glj?gljLibId="+id;
-                    $("#tempId td:first a").attr("href", newHref);
-                    $("#tempId").attr("id", id);
                 }
             }
             callback(dispNames, compilationsUsedArr);
@@ -262,8 +301,8 @@ function createGljLib(gljLibObj, dispNamesArr, usedCom){
                 dispNamesArr.push(libName);
                 usedCom.push(gljLibObj.compilationId);
                 $("#showArea").append(
-                    "<tr id='tempId'>" +
-                    "<td><a href='/stdGljRepository/glj'>"+libName+"</a></td>" +
+                    "<tr id='"+id+"' data-compilationId='"+ gljLibObj.compilationId + "'>" +
+                    "<td><a href='/stdGljRepository/glj?gljLibId="+id+"'>"+libName+"</a></td>" +
                     "<td>"+compilationName+" </td>" +
                     "<td>"+''+" </td>" +
                     "<td>"+createDate+" </td>" +
@@ -271,10 +310,8 @@ function createGljLib(gljLibObj, dispNamesArr, usedCom){
                     "<i class='fa fa-pencil-square-o'></i></a> <a href='javascript:void(0);' data-toggle='modal' data-target='#del' class='text-danger' title='删除'>" +
                     "<i class='fa fa-remove'></i></a></td>" +
                     "<td><a class='btn btn-secondary btn-sm import-data' href='javacript:void(0);' data-id='"+ id +"' title='导入数据'><i class='fa fa-sign-in fa-rotate-90'></i>导入</a></td>" +
+                    "<td><a class='btn btn-secondary btn-sm set-comple' href='javacript:void(0);' data-id='"+ id +"' title='将分类树设为补充模板数据'><i class='fa fa-sign-in fa-rotate-90'></i>设置</a></td>" +
                     "</tr>");
-                var newHref = "/stdGljRepository/glj?gljLibId="+id;
-                $("#tempId td:first a").attr("href", newHref);
-                $("#tempId").attr("id", id);
             }
             $('#cancelBtn').click();
         }

+ 110 - 0
web/users/js/manager.js

@@ -77,4 +77,114 @@ $(document).ready(function() {
         });
     });
 
+    // 编辑权限组权限
+    $('.edit_permission').on('click', function () {
+        // 清空权限列表
+        $('#id').val('');
+        $('#title1').val('');
+        $("input[type='checkbox']").prop('checked', false);
+        let group_id = $(this).attr('data-permission-id');
+        let group_name = $(this).attr('data-permission-name');
+        $('#id').val(group_id);
+        $('#title1').val(group_name);
+        if ($(this).attr('data-permission') !== '') {
+            let group_permission = JSON.parse($(this).attr('data-permission'));
+            for (let gp in group_permission) {
+                let plist = group_permission[gp];
+                for (let p of plist) {
+                    $("input[value='"+p+"'").prop('checked', true);
+                }
+            }
+        }
+    });
+
+    // 一级权限选中或取消
+    $("input[name='topPermission[]']").on('click', function () {
+        let id = $(this).attr('id');
+        if($(this).is(':checked')) {
+            // 选中
+            $("input[name='permission_"+id+"[]']").prop('checked', true);
+        } else {
+            // 取消选中
+            $("input[name='permission_"+id+"[]']").prop('checked', false);
+        }
+    });
+
+    // 二级权限选中或取消
+    $("input[name^='permission_']").on('click', function () {
+        let topid = $(this).attr('data-controller');
+        if($(this).is(':checked')) {
+            // 选中
+            $('#'+ topid).prop('checked', true);
+        } else {
+            // 取消选中(排除工具这个独立分离的url)
+            if (topid !== 'tool') {
+                // 不存在选中权限
+                if (!$("input[name='permission_"+ topid +"[]']").is(':checked')) {
+                    $('#'+ topid).prop('checked', false);
+                }
+            }
+        }
+    });
+
+    // 删除权限组传值
+    $('.del_permission').on('click', function () {
+        let id = $(this).data('id');
+        $('#delete_id').val(id);
+    });
+
+    // 账号管理权限组选择
+    $('.edit_group').on('click', function () {
+        let name = $(this).attr('data-name');
+        let id = $(this).attr('data-id');
+        let permission = $(this).attr('data-permission');
+        if (name !== '') {
+            $('#group_name').text(name);
+        } else {
+            $('#group_name').text('未分配');
+        }
+        $('#manager_id').val(id);
+        if (permission !== '') {
+            $('#group_permission').val(permission);
+        } else {
+            $('#group_permission').val(0);
+        }
+        let groupInfo = permissionGroupList.find(function (item) {
+            return item._id === permission;
+        });
+        let top_name = groupInfo !== undefined ? groupInfo.top_name : '';
+        $('#group_permission_name').text(top_name);
+    });
+
+    // 权限组变更时改变
+    $('#group_permission').change(function () {
+        let permission = $(this).val();
+        let groupInfo = permissionGroupList.find(function (item) {
+            return item._id === permission;
+        });
+        let top_name = groupInfo !== undefined ? groupInfo.top_name : '';
+        $('#group_permission_name').text(top_name);
+    });
+
+    // 选择框
+    $(".selector > li > a").click(function() {
+        let value = $(this).data("value");
+        let string = $(this).text();
+        let selector = $(this).parent().parent();
+        selector.next("input:hidden").val(value);
+        selector.prev("button").children("span").eq(0).html(string);
+
+        // 筛选结果跳转
+        console.log($('#office_select').val());
+        console.log($('#permission_select').val());
+        let query = [];
+        if ($('#office_select').val() !== 'all' && $('#office_select').val() !== '') {
+            query.push('office=' + $('#office_select').val());
+        }
+        if ($('#permission_select').val() !== 'all' && $('#permission_select').val() !== '') {
+            query.push('permission=' + $('#permission_select').val());
+        }
+        let requestUrl = query.join('&');
+        window.location.href = requestUrl !== '' ? '/manager?' + requestUrl :  '/manager';
+    });
 });

+ 31 - 1
web/users/js/user.js

@@ -15,11 +15,34 @@ $(document).ready(function() {
         selector.prev("button").children("lable").text(string);
         //selector.prev("button").html(string + ' <span class="caret"></span>');
     });
+    $("#deleteConfirm").click(async function () {
+        let userID = $("#userID").val();
+        let delCount = parseInt($("#delCount").val());
+        delCount = delCount+1;
+        $("#delCount").val(delCount);
+        if(delCount == 3){//连续点3次才做真删除
+            if(userID!=""){
+                try {
+                    $.bootstrapLoading.start();
+                   let  result  = await ajaxPost("/user/deleteUser",{userID:userID});
+                    $.bootstrapLoading.end();
+                   if(result == "success"){
+                       window.location.reload();
+                   }else {
+                       alert("删除失败!");
+                       $("#delCount").val(0);
+                   }
+                }catch (err){
+                    $.bootstrapLoading.end();
+                    $("#delCount").val(0);
+                }
+            }
+        }
+    });
 });
 let cacheUser = null;
 
 async function getUserInfo(ID) {
-    console.log(ID);
     let user = await ajaxPost("/user/findByID",{ID:ID});
     let infoString = `<tr><th>注册时间</th><td>${user.create_time}</td><th>最近登录</th><td>${user.last_login}</td></tr>
                       <tr><th>手机</th><td >${user.mobile}</td><th>邮箱</th><td>${user.email}</td></tr>
@@ -30,6 +53,13 @@ async function getUserInfo(ID) {
     $('#userInfoTable').html(infoString);
 }
 
+function deleteUser(userID) {
+    $("#delCount").val(0);
+    $("#userID").val(userID);
+}
+
+
+
 async function getUserUpgradeInfo(ID){
     try {
         cacheUser  = await ajaxPost("/user/findByID",{ID:ID});

+ 1 - 0
web/users/views/layout/layout.html

@@ -21,6 +21,7 @@
     <script src="/web/users/js/lib/bootstrap-paginator.js"></script>
     <script src="/lib/lodash/lodash.js"></script>
     <script type="text/javascript" src="/public/web/common_ajax.js"></script>
+    <script type="text/javascript" src="/public/web/PerfectLoad.js"></script>
     <script type="text/javascript" src="/node_modules/moment/min/moment.min.js"></script>
     <!-- spreadJs -->
     <script src = "/lib/spreadjs/sheets/gc.spread.sheets.all.11.1.2.min.js"></script>

+ 137 - 0
web/users/views/manager/authority.html

@@ -0,0 +1,137 @@
+<%include ../layout/second_menu.html %>
+<div class="panel-content">
+    <div class="panel-title">
+        <div class="title-main">
+            <h2><%= secondMenu[action].title %>
+                <a href="#add-group" data-toggle="modal" data-target="#add-group" class="btn btn-default btn-sm pull-right">添加新组</a>
+            </h2>
+        </div>
+    </div>
+    <div class="content-wrap">
+        <div class="c-header">
+        </div>
+        <div class="c-body">
+            <table class="table table-hover">
+                <thead>
+                <tr>
+                    <th>组名</th>
+                    <th>权限</th>
+                    <th>使用账号</th>
+                    <th width="100">操作</th>
+                </tr>
+                </thead>
+                <tbody>
+                <% for (let group of groupList) { %>
+                <tr>
+                    <td><%= group.name %></td>
+                    <td><%= group.top_name %></td>
+                    <td><%= group.manager_count %></td>
+                    <td>
+                        <a href="#edit-group" class="edit_permission btn btn-xs"
+                           data-permission-id="<%= group._id %>"
+                           data-permission-name="<%= group.name %>"
+                           data-permission="<%= group.permission %>" data-toggle="modal" data-target="#edit-group">编辑</a>
+                        <a href="#del-group" data-id="<%= group._id %>" class="del_permission btn btn-xs text-danger" data-toggle="modal" data-target="#del-group">删除</a>
+                    </td>
+                </tr>
+                <% } %>
+                </tbody>
+            </table>
+            <nav aria-label="Page navigation">
+                <%include ../layout/page.html %>
+            </nav>
+        </div>
+    </div>
+</div>
+
+<script type="text/javascript" src="/web/users/js/manager.js"></script>
+<!-- 编辑组 -->
+<div class="modal fade" id="edit-group" tabindex="-1" role="dialog">
+    <div class="modal-dialog" role="document">
+        <form method="post" action="/manager/authority/save">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                    <h4 class="modal-title" id="myModalLabel1">编辑权限组</h4>
+                </div>
+                <div class="modal-body">
+                    <div class="form-group">
+                        <label for="title">组名</label>
+                        <input class="form-control" type="text" id="title1" name="name" placeholder="输入组名" value="">
+                        <input type="hidden" id="id" name="id" value="">
+                    </div>
+                    <div class="form-group">
+                        <label for="title">权限</label>
+                        <div class="checkbox" id="top_permission">
+                            <% for(let permission of topPermissionList){ %>
+                            <label><input type="checkbox" name="topPermission[]" id="<%= permission.controller %>" value="<%= permission._id %>"> <%= permission.name %> </label>&nbsp;
+                            <% } %>
+                        </div>
+                    </div>
+                    <!--打勾管理二级权限-->
+                    <% for (let permission of permissionList) { %>
+                    <% if (permission.count > 0) { %>
+                    <div class="form-group">
+                        <label for="title"><%= permission.name %>二级权限</label>
+                        <div class="checkbox" id="<%= permission.controller %>_permission">
+                            <% for(let second of permission.secondPermissionList){ %>
+                            <label>
+                                <input type="checkbox" data-controller="<%= permission.controller %>" name="permission_<%= permission.controller %>[]" value="<%= second._id %>"> <%= second.name %>
+                            </label>&nbsp;
+                            <% } %>
+                        </div>
+                    </div>
+                    <% } %>
+                    <% } %>
+                </div>
+                <div class="modal-footer">
+                    <button type="submit" class="btn btn-primary">确定</button>
+                </div>
+            </div>
+        </form>
+    </div>
+</div>
+<!-- 添加组 -->
+<div class="modal fade" id="add-group" tabindex="-1" role="dialog">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                <h4 class="modal-title" id="myModalLabel2">添加新组</h4>
+            </div>
+            <form action="/manager/authority/add" method="post">
+                <div class="modal-body">
+                    <div class="form-group">
+                        <label for="title">组名</label>
+                        <input class="form-control" id="title" name="name" placeholder="输入组名">
+                    </div>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
+                    <button type="sumbit" class="btn btn-primary" >确认</button>
+                </div>
+            </form>
+        </div>
+    </div>
+</div>
+<!-- 删除组 -->
+<div class="modal fade" id="del-group" tabindex="-1" role="dialog">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                <h4 class="modal-title" id="myModalLabel3">删除组</h4>
+            </div>
+            <div class="modal-body">
+                <h4>删除后,相关账号将无法正常使用。</h4>
+            </div>
+            <form action="/manager/authority/delete" method="post">
+                <input type="hidden" id="delete_id" name="id" value="">
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
+                    <button type="submit" class="btn btn-danger" >确认删除</button>
+                </div>
+            </form>
+        </div>
+    </div>
+</div>

+ 82 - 16
web/users/views/manager/index.html

@@ -11,21 +11,38 @@
             <div class="btn-group">
                 <button type="button" class="btn btn-default dropdown-toggle btn-sm" data-toggle="dropdown"
                         aria-haspopup="true" aria-expanded="false">
-                    办事处 <span class="caret"></span>
+                    办事处:<span><%= filter.office === undefined ? '所有' : filter.officeName %></span> <span class="caret"></span>
                 </button>
-                <ul class="dropdown-menu">
-                    <li><a href="#">广东办</a></li>
-                    <li><a href="#">总部</a></li>
+                <ul class="dropdown-menu selector">
+                    <li><a href="javascript:void(0);" data-value="all">所有</a></li>
+                    <% for (let category of categoryList) { %>
+                    <li><a href="javascript:void(0);" data-value="<%= category.id %>"><%= category.name %></a></li>
+                    <% } %>
                 </ul>
+                <input type="hidden" id="office_select" value="<%= filter.office %>" />
+            </div>
+            <div class="btn-group">
+                <button type="button" class="btn btn-default dropdown-toggle btn-sm" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+                    权限组:<span><%= filter.permission === undefined ? '所有' : (filter.permission === '0' ? '未分配' : filter.permissionGroupName) %></span> <span class="caret"></span>
+                </button>
+                <ul class="dropdown-menu selector">
+                    <li><a href="javascript:void(0);" data-value="all">所有</a></li>
+                    <li><a href="javascript:void(0);" data-value="0">未分配</a></li>
+                    <% for (let pg of permissionGroupList) { %>
+                    <li><a href="javascript:void(0);" data-value="<%= pg._id %>"><%= pg.name %></a></li>
+                    <% } %>
+                </ul>
+                <input type="hidden" id="permission_select" value="<%= filter.permission %>" />
             </div>
         </div>
         <div class="c-body">
             <table class="table">
                 <thead>
                 <tr>
-                    <th>姓名</th>
+                    <th>姓名(CLD)</th>
                     <th>办事处</th>
-                    <th>权限</th>
+                    <th>权限组</th>
+                    <th>状态</th>
                     <th width="100">操作</th>
                 </tr>
                 </thead>
@@ -33,16 +50,14 @@
                 <% managerList.forEach(function(manager) { %>
                 <tr>
                     <td><%= manager.username %></td>
-                    <td><%= manager.office %></td>
-                    <td><%= manager.permissionStr %></td>
-                    <td>
-                        <a href="javascript:void(0);" class="edit btn btn-xs"
-                            data-permission="<%= manager.permission %>" data-login="<%= manager.can_login %>"
-                            data-id="<%= manager._id %>">编辑</a>
-                        <% if (manager.super_admin !== 1) { %>
-                        <a href="/manager/delete/<%= manager._id %>" class="btn btn-xs">删除</a>
-                        <% } %>
-                    </td>
+                    <td><%= manager.officeName %></td>
+                    <td><a href="#updatea" class="edit_group" data-id="<%= manager._id %>" data-name="<%= manager.permissionName %>" data-permission="<%= manager.permission %>" data-toggle="modal" data-target="#group"><% if (manager.permission !== '') { %><%= manager.permissionName %><% } else { %>未分配<% } %></a></td>
+                    <% if (manager.can_login === 1) { %>
+                    <td>正常</td>
+                    <% } else { %>
+                    <td class="text-danger"><i class="glyphicon glyphicon-minus-sign"></i> 停用</td>
+                    <% } %>
+                    <td><% if (manager.can_login === 1) { %><a href="/manager/modify/<%= manager._id %>/0" class="text-danger">停用</a><% } else { %><a href="/manager/modify/<%= manager._id %>/1" class="text-success">启用</a><% } %></td>
                 </tr>
                 <% }) %>
                 </tbody>
@@ -53,6 +68,9 @@
         </div>
     </div>
 </div>
+<script type="text/javascript">
+    let permissionGroupList = <%- permissionGroupList2 %>;
+</script>
 <script type="text/javascript" src="/web/users/js/manager.js"></script>
 <div class="modal fade" id="edit-account" tabindex="-1" role="dialog">
     <div class="modal-dialog" role="document">
@@ -96,4 +114,52 @@
             </div>
         </div>
     </div>
+</div>
+<!-- 更新账号 -->
+<div class="modal fade" id="updatea" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                <h4 class="modal-title" id="myModalLabel">CLD账号更新成功</h4>
+            </div>
+            <div class="modal-body">
+                <p>更新了2个账号:张三、王五</p>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-default" data-dismiss="modal">好的</button>
+            </div>
+        </div>
+    </div>
+</div>
+<!-- 权限组 -->
+<div class="modal fade" id="group" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                <h4 class="modal-title" id="myModalLabel2">权限组:<span id="group_name">销售权限</span></h4>
+            </div>
+            <form method="post" action="/manager/group/save">
+            <div class="modal-body">
+                <p>该组包含以下权限:</p>
+                <p id="group_permission_name">用户管理,通知管理,工具,后台管理</p>
+                <div class="form-group">
+                    <label class="title">更换组</label>
+                    <input type="hidden" value="" id="manager_id" name="manager_id">
+                    <select class="form-control" name="permission" id="group_permission">
+                        <option value="0">未分配</option>
+                        <% for (let pg of permissionGroupList) { %>
+                        <option value="<%= pg._id %>"><%= pg.name %></option>
+                        <% } %>
+                    </select>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
+                <button type="submit" class="btn btn-primary">确认修改</button>
+            </div>
+            </form>
+        </div>
+    </div>
 </div>

+ 172 - 122
web/users/views/tool/index.html

@@ -6,90 +6,105 @@
     </div>
     <div class="content-wrap">
         <div class="row">
+            <% for (let tool of toolMenu) { %>
             <div class="col-xs-6 mb-30 ">
                 <div class="c-body">
-                    <h2>清单规则编辑器
-                        <a id="billsLib" href="javascript:void(0);" class="btn btn-primary pull-right">进入</a>
-                    </h2>
-                </div>
-            </div>
-            <div class="col-xs-6 mb-30 ">
-                <div class="c-body">
-                    <h2>定额编辑器
-                        <a id="rationLib" href="javascript:void(0);" class="btn btn-primary pull-right">进入</a>
-                    </h2>
-                </div>
-            </div>
-            <div class="col-xs-6 mb-30 ">
-                <div class="c-body">
-                    <h2>报表模板
-                        <a id="rptTemplate" href="javascript:void(0);" class="btn btn-primary pull-right">进入</a>
-                    </h2>
-                </div>
-            </div>
-            <div class="col-xs-6 mb-30 ">
-                <div class="c-body">
-                    <h2>人材机库
-                        <a id="gljLib" href="javascript:void(0);" class="btn btn-primary pull-right">进入</a>
-                    </h2>
-                </div>
-            </div>
-            <div class="col-xs-6 mb-30 ">
-                <div class="c-body">
-                    <h2>清单指引编辑器
-                        <a id="billsGuidanceLib" href="javascript:void(0);" class="btn btn-primary pull-right">进入</a>
-                    </h2>
-                </div>
-            </div>
-            <div class="col-xs-6 mb-30 ">
-                <div class="c-body">
-                    <h2>清除项目残留数据
+                    <h2><%= tool.title %>
+                        <% if (tool.url === '/sysTools/api/clearJunkData' ) { %>
                         <a id="clearJunkBtn" href="javascript:void(0);" class="btn btn-primary pull-right">清除</a>
+                        <% } else if (tool.url === '/sysTools/api/clearFakeData' ) { %>
+                        <a id="clearFakeBtn" href="javascript:void(0);" class="btn btn-primary pull-right">清除</a>
+                        <% } else { %>
+                        <a id="<%= tool.controller %>" href="<%= tool.url %>" target="_blank" class="btn btn-primary pull-right">进入</a>
+                        <% } %>
                     </h2>
                 </div>
             </div>
-            <div class="col-xs-6 mb-30 ">
-                <div class="c-body">
-                    <h2>清单模板编辑器
-                        <a id="billTemplate" href="/billsTemplate/main" target="_blank" class="btn btn-primary pull-right">进入</a>
-                    </h2>
-                </div>
-            </div>
-            <div class="col-xs-6 mb-30 ">
-                <div class="c-body">
-                    <h2>列设置
-                        <a id="mainTreeCol" href="/mainTreeCol/main" target="_blank" class="btn btn-primary pull-right">进入</a>
-                    </h2>
-                </div>
-            </div>
-            <div class="col-xs-6 mb-30 ">
-                <div class="c-body">
-                    <h2>材料替换库
-                        <a id="materialReplace" href="/materialReplace/main" target="_blank" class="btn btn-primary pull-right">进入</a>
-                    </h2>
-                </div>
-            </div>
-            <div class="col-xs-6 mb-30 ">
-                <div class="c-body">
-                    <h2>工程特征库
-                        <a id="projectFeature" href="/projectFeature/main" target="_blank" class="btn btn-primary pull-right">进入</a>
-                    </h2>
-                </div>
-            </div>
-            <div class="col-xs-6 mb-30 ">
-                <div class="c-body">
-                    <h2>费率标准库
-                        <a id="feeRate" href="/feeRate/main" target="_blank" class="btn btn-primary pull-right">进入</a>
-                    </h2>
-                </div>
-            </div>
-            <div class="col-xs-6 mb-30 ">
-                <div class="c-body">
-                    <h2>计算程序模板库
-                        <a id="calcProgram" href="/calcProgram/main" target="_blank" class="btn btn-primary pull-right">进入</a>
-                    </h2>
-                </div>
-            </div>
+            <% } %>
+            <!--<div class="col-xs-6 mb-30 ">-->
+            <!--<div class="c-body">-->
+            <!--<h2>清单规则编辑器-->
+            <!--<a id="stdBillsmain" href="/stdBillsmain" target="_blank" class="btn btn-primary pull-right">进入</a>-->
+            <!--</h2>-->
+            <!--</div>-->
+            <!--</div>-->
+            <!--<div class="col-xs-6 mb-30 ">-->
+            <!--<div class="c-body">-->
+            <!--<h2>定额编辑器-->
+            <!--<a id="rationRepository" href="/rationRepository/main" target="_blank" class="btn btn-primary pull-right">进入</a>-->
+            <!--</h2>-->
+            <!--</div>-->
+            <!--</div>-->
+            <!--<div class="col-xs-6 mb-30 ">-->
+            <!--<div class="c-body">-->
+            <!--<h2>报表模板-->
+            <!--<a id="rpt_tpl" href="/rpt_tpl" target="_blank" class="btn btn-primary pull-right">进入</a>-->
+            <!--</h2>-->
+            <!--</div>-->
+            <!--</div>-->
+            <!--<div class="col-xs-6 mb-30 ">-->
+            <!--<div class="c-body">-->
+            <!--<h2>人材机库-->
+            <!--<a id="stdGljRepository" href="/stdGljRepository/main" target="_blank" class="btn btn-primary pull-right">进入</a>-->
+            <!--</h2>-->
+            <!--</div>-->
+            <!--</div>-->
+            <!--<div class="col-xs-6 mb-30 ">-->
+            <!--<div class="c-body">-->
+            <!--<h2>清单指引编辑器-->
+            <!--<a id="billsGuidance" href="/billsGuidance/main" target="_blank" class="btn btn-primary pull-right">进入</a>-->
+            <!--</h2>-->
+            <!--</div>-->
+            <!--</div>-->
+            <!--<div class="col-xs-6 mb-30 ">-->
+            <!--<div class="c-body">-->
+            <!--<h2>清除项目残留数据-->
+            <!--<a id="clearJunkBtn" href="javascript:void(0);" class="btn btn-primary pull-right">清除</a>-->
+            <!--</h2>-->
+            <!--</div>-->
+            <!--</div>-->
+            <!--<div class="col-xs-6 mb-30 ">-->
+            <!--<div class="c-body">-->
+            <!--<h2>清单模板编辑器-->
+            <!--<a id="billTemplate" href="/billsTemplate/main" target="_blank" class="btn btn-primary pull-right">进入</a>-->
+            <!--</h2>-->
+            <!--</div>-->
+            <!--</div>-->
+            <!--<div class="col-xs-6 mb-30 ">-->
+            <!--<div class="c-body">-->
+            <!--<h2>列设置-->
+            <!--<a id="mainTreeCol" href="/mainTreeCol/main" target="_blank" class="btn btn-primary pull-right">进入</a>-->
+            <!--</h2>-->
+            <!--</div>-->
+            <!--</div>-->
+            <!--<div class="col-xs-6 mb-30 ">-->
+            <!--<div class="c-body">-->
+            <!--<h2>材料替换库-->
+            <!--<a id="materialReplace" href="/materialReplace/main" target="_blank" class="btn btn-primary pull-right">进入</a>-->
+            <!--</h2>-->
+            <!--</div>-->
+            <!--</div>-->
+            <!--<div class="col-xs-6 mb-30 ">-->
+            <!--<div class="c-body">-->
+            <!--<h2>工程特征库-->
+            <!--<a id="projectFeature" href="/projectFeature/main" target="_blank" class="btn btn-primary pull-right">进入</a>-->
+            <!--</h2>-->
+            <!--</div>-->
+            <!--</div>-->
+            <!--<div class="col-xs-6 mb-30 ">-->
+            <!--<div class="c-body">-->
+            <!--<h2>费率标准库-->
+            <!--<a id="feeRate" href="/feeRate/main" target="_blank" class="btn btn-primary pull-right">进入</a>-->
+            <!--</h2>-->
+            <!--</div>-->
+            <!--</div>-->
+            <!--<div class="col-xs-6 mb-30 ">-->
+            <!--<div class="c-body">-->
+            <!--<h2>计算程序模板库-->
+            <!--<a id="calcProgram" href="/calcProgram/main" target="_blank" class="btn btn-primary pull-right">进入</a>-->
+            <!--</h2>-->
+            <!--</div>-->
+            <!--</div>-->
         </div>
     </div>
 </div>
@@ -117,61 +132,96 @@
         </div>
     </div>
 </div>
+<!--弹出 是否清除假删除数据-->
+<div class="modal fade" id="clearFakeModal" data-backdrop="static">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">删除确认</h5>
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                    <span aria-hidden="true">&times;</span>
+                </button>
+            </div>
+            <div class="modal-body">
+                <div class="form-group">
+                    <div>
+                        <label>确认要清除数据库中项目假删除数据吗?(清单、定额)</label>
+                    </div>
+                </div>
+            </div>
+            <div class="modal-footer" style="justify-content: center">
+                <button type="button" class="btn btn-primary"  data-dismiss="modal" id="clearFakeY" >是</button>
+                <button type="button" class="btn btn-primary"  data-dismiss="modal">否</button>
+            </div>
+        </div>
+    </div>
+</div>
 
 <script type="text/javascript" src="/public/web/common_ajax.js"></script>
 <script type="text/javascript" src="/public/web/PerfectLoad.js"></script>
 <script type="text/javascript">
     $(document).ready(function () {
-        $('#billsLib').click(function () {
-            let href = '/stdBillsmain';
-            let newTab = window.open('about:blank');
-            CommonAjax.get(href, {}, function () {
-               newTab.location.href = href;
-            });
-        });
-
-        $('#rationLib').click(function () {
-            let href = '/rationRepository/main';
-            let newTab = window.open('about:blank');
-            CommonAjax.get(href, {}, function () {
-               newTab.location.href = href;
-            });
-        });
-
-        $('#rptTemplate').click(function () {
-            let href = '/rpt_tpl';
-            let newTab = window.open('about:blank');
-            CommonAjax.get(href, {}, function () {
-               newTab.location.href = href;
-            });
-        });
-
-        $('#gljLib').click(function () {
-            let href = '/stdGljRepository/main';
-            let newTab = window.open('about:blank');
-            CommonAjax.get(href, {}, function () {
-               newTab.location.href = href;
-            });
-        });
-
-        $('#billsGuidanceLib').click(function () {
-            let href = '/billsGuidance/main';
-            let newTab = window.open('about:blank');
-            CommonAjax.get(href, {}, function () {
-               newTab.location.href = href;
-            });
-        });
+//        $('#billsLib').click(function () {
+//            let href = '/stdBillsmain';
+//            let newTab = window.open('about:blank');
+//            CommonAjax.get(href, {}, function () {
+//               newTab.location.href = href;
+//            });
+//        });
+//
+//        $('#rationLib').click(function () {
+//            let href = '/rationRepository/main';
+//            let newTab = window.open('about:blank');
+//            CommonAjax.get(href, {}, function () {
+//               newTab.location.href = href;
+//            });
+//        });
+//
+//        $('#rptTemplate').click(function () {
+//            let href = '/rpt_tpl';
+//            let newTab = window.open('about:blank');
+//            CommonAjax.get(href, {}, function () {
+//               newTab.location.href = href;
+//            });
+//        });
+//
+//        $('#gljLib').click(function () {
+//            let href = '/stdGljRepository/main';
+//            let newTab = window.open('about:blank');
+//            CommonAjax.get(href, {}, function () {
+//               newTab.location.href = href;
+//            });
+//        });
+//
+//        $('#billsGuidanceLib').click(function () {
+//            let href = '/billsGuidance/main';
+//            let newTab = window.open('about:blank');
+//            CommonAjax.get(href, {}, function () {
+//               newTab.location.href = href;
+//            });
+//        });
 
         $('#clearJunkBtn').click(function () {
             $('#clearJunkModal').modal('show');
         });
+        $('#clearFakeBtn').click(function () {
+            $('#clearFakeModal').modal('show');
+        });
         $('#clearJunkY').click(function () {
             $.bootstrapLoading.start();
-             CommonAjax.post('/sysTools/api/clearJunkData', '', function (rstData) {
-             $.bootstrapLoading.end();
-             }, function () {
-             $.bootstrapLoading.end();
-             })
+            CommonAjax.post('/sysTools/api/clearJunkData', '', function (rstData) {
+                $.bootstrapLoading.end();
+            }, function () {
+                $.bootstrapLoading.end();
+            })
+        });
+        $('#clearFakeY').click(function () {
+            $.bootstrapLoading.start();
+            CommonAjax.post('/sysTools/api/clearFakeData', '', function (rstData) {
+                $.bootstrapLoading.end();
+            }, function () {
+                $.bootstrapLoading.end();
+            })
         });
     });
 </script>

+ 46 - 16
web/users/views/user/index.html

@@ -1,8 +1,14 @@
-<%include ../layout/second_menu.html %>
 <div class="panel-content">
-    <div class="panel-title">
+    <div class="panel-title fluid">
         <div class="title-main">
-            <h2><%= secondMenu[action].title %></h2>
+            <% for (let menu of userMenu) { %>
+            <% if (menu.title === secondMenu[action].title) { %>
+            <%= menu.title %>
+            <% } else { %>
+            <a href="<%= menu.url %>" class="btn btn-primary btn-link" style="margin-left: 0;margin-right: 12px"><%= menu.title %></a>
+            <% } %>
+            <% } %>
+            <!--<h2><%= secondMenu[action].title %><a href="/user/testUser" class="btn btn-primary btn-link">测试用户</a></h2>-->
         </div>
     </div>
     <div class="content-wrap">
@@ -91,27 +97,28 @@
                     <th>姓名</th>
                     <th>企业名称</th>
                     <th>企业地区</th>
-                    <th>最近使用版本</th>
-                    <th width="180">最近登录</th>
-                    <th width="180">注册时间</th>
-                    <th>详细</th>
-                    <th>升级</th>
+                    <th>最近使用版本 </th>
+                    <th width="180">注册时间 / 最近登录</th>
+                    <% if (manager.superAdmin == 1) { %>
+                    <th>操作</th>
+                    <% }%>
+                    <!--<th>详细</th>-->
                 </tr>
                 </thead>
                 <tbody>
                 <% userList.forEach(function (user){ %>
                 <tr>
-                    <td><%= user.mobile %> / <%= user.email %></td>
+                    <td><%= user.mobile %><br><%= user.email %></td>
                     <td><%= user.real_name %></td>
-                    <td><a tabindex="0" role="button" data-toggle="popover" data-trigger="focus" title="更多信息"
-                           data-content="企业类型:<%= model.companyType[user.company_type] %>,企业规模:<%= model.companyScale[user.company_scale] %>"><%= user.company %></a>
-                    </td>
+                    <td><%= user.company %></td>
                     <td><%= model.province[user.province] %></td>
                     <td><%= compilationMap[user.latest_used]?compilationMap[user.latest_used].name:""%></td>
-                    <td><%= user.latest_login?moment(user.latest_login).format('YYYY-MM-DD HH:mm:ss'):"" %></td>
-                    <td><%= moment(user.create_time).format('YYYY-MM-DD HH:mm:ss') %></td>
-                    <td><a role="button" data-toggle="modal" data-target="#view" onclick='getUserInfo("<%= user._id.toString()%>")'>详细</a></td>
-                    <td><a href="#update" data-toggle="modal" data-target="#update" onclick='getUserUpgradeInfo("<%= user._id.toString()%>")'>升级</a></td>
+                    <td><%= moment(user.create_time).format('YYYY-MM-DD HH:mm:ss') %><br><%= user.latest_login?moment(user.latest_login).format('YYYY-MM-DD HH:mm:ss'):"" %></td>
+                    <% if (manager.superAdmin == 1) { %>
+                    <td><a onclick='deleteUser("<%= user._id.toString()%>")' data-toggle="modal" data-target="#delUser" class="btn btn-link btn-sm" style="padding: 0px">删除</a></td>
+                    <% }%>
+                    <!--<td><a role="button" data-toggle="modal" data-target="#view" onclick='getUserInfo("<%= user._id.toString()%>")'>详细</a></td>-->
+                    <!--<td><a href="#update" data-toggle="modal" data-target="#update" onclick='getUserUpgradeInfo("<%= user._id.toString()%>")'>升级</a></td>-->
                 </tr>
                 <% }) %>
                 </tbody>
@@ -166,6 +173,29 @@
     </div>
 </div>
 
+<!--弹出删除-->
+<div class="modal fade" id="delUser" data-backdrop="static" style="display: none;" aria-hidden="true">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">删除确认</h5>
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                    <span aria-hidden="true">×</span>
+                </button>
+            </div>
+            <div class="modal-body">
+                <h5 class="text-danger">删除用户的同时会删除项目数据和用户补充人材库、定额库等数据,且无法恢复,确认是否删除?</h5>
+                <input type="hidden" id="userID">
+                <input type="hidden" id="delCount">
+            </div>
+            <div class="modal-footer">
+                <a id="deleteConfirm" href="javascript:void(0);" class="btn btn-danger" >确认</a>
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+            </div>
+        </div>
+    </div>
+</div>
+
 <script type="text/javascript">
     let compilationList = JSON.parse('<%- compilationString %>');
     let adminName = '<%- adminName %>';

+ 10 - 3
web/users/views/user/test_user.html

@@ -1,8 +1,15 @@
-<%include ../layout/second_menu.html %>
+<!--<%include ../layout/second_menu.html %>-->
 <div class="panel-content">
-    <div class="panel-title">
+    <div class="panel-title fluid">
         <div class="title-main">
-            <h2><%= secondMenu[action].title %>
+            <h2>
+                <% for (let menu of userMenu) { %>
+                <% if (menu.title === secondMenu[action].title) { %>
+                <%= menu.title %>
+                <% } else { %>
+                <a href="<%= menu.url %>" class="btn btn-primary btn-link" style="padding-left:0;margin-left: 0;margin-right: 12px"><%= menu.title %></a>
+                <% } %>
+                <% } %>
                 <a href="#news-add" data-toggle="modal" data-target="#news-add" class="btn btn-primary btn-sm pull-right">添加用户</a>
             </h2>
         </div>