Browse Source

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

TonyKang 8 years ago
parent
commit
ce46080207
57 changed files with 15521 additions and 381 deletions
  1. 12557 0
      lib/lodash/lodash.js
  2. 44 0
      modules/common/base/base_controller.js
  3. 121 0
      modules/common/base/base_model.js
  4. 186 0
      modules/common/helper/mongoose_helper.js
  5. 199 0
      modules/glj/controllers/glj_controller.js
  6. 0 8
      modules/glj/db/user_glj_lib_db.js
  7. 54 0
      modules/glj/models/counter_model.js
  8. 303 0
      modules/glj/models/glj_list_model.js
  9. 70 0
      modules/glj/models/glj_repository_model.js
  10. 22 0
      modules/glj/models/schemas/counter.js
  11. 65 0
      modules/glj/models/schemas/glj.js
  12. 29 0
      modules/glj/models/schemas/glj_repository.js
  13. 36 0
      modules/glj/models/schemas/unit_price.js
  14. 21 0
      modules/glj/models/schemas/unit_price_file.js
  15. 65 43
      modules/glj/models/unit_price_file.js
  16. 112 0
      modules/glj/models/unit_price_file_model.js
  17. 207 0
      modules/glj/models/unit_price_model.js
  18. 5 1
      modules/glj/models/user_glj_lib.js
  19. 22 0
      modules/glj/routes/glj_router.js
  20. 2 2
      modules/main/controllers/project_controller.js
  21. 7 1
      modules/main/models/project.js
  22. 1 0
      modules/main/models/project_consts.js
  23. 6 6
      modules/main/models/project_glj.js
  24. 4 2
      modules/main/models/ration.js
  25. 8 9
      modules/pm/controllers/pm_controller.js
  26. 8 25
      modules/pm/models/project.js
  27. 26 0
      modules/pm/models/project_schema.js
  28. 256 0
      modules/ration_glj/facade/ration_glj_facade.js
  29. 4 6
      modules/ration_glj/models/ration_glj.js
  30. 49 0
      modules/ration_glj/models/ration_glj_temp.js
  31. 1 1
      modules/ration_repository/models/glj_repository.js
  32. 4 4
      modules/users/controllers/boot_controller.js
  33. 6 3
      modules/users/controllers/login_controller.js
  34. 3 1
      modules/users/controllers/user_controller.js
  35. 29 0
      modules/users/models/schema/user.js
  36. 41 95
      modules/users/models/user_model.js
  37. 2 3
      modules/users/routes/boot_route.js
  38. 4 2
      modules/users/routes/login_route.js
  39. 28 0
      public/web/sheet/sheet_common.js
  40. 6 3
      server.js
  41. 17 40
      web/building_saas/main/html/main.html
  42. 5 1
      web/building_saas/main/js/controllers/project_controller.js
  43. 10 4
      web/building_saas/main/js/models/bills.js
  44. 2 1
      web/building_saas/main/js/models/main_consts.js
  45. 1 0
      web/building_saas/main/js/models/project.js
  46. 6 1
      web/building_saas/main/js/models/ration.js
  47. 172 0
      web/building_saas/main/js/models/ration_glj.js
  48. 0 117
      web/building_saas/main/js/views/gljView.js
  49. 126 0
      web/building_saas/main/js/views/glj_view.js
  50. 13 1
      web/building_saas/main/js/views/project_view.js
  51. 58 0
      web/building_saas/main/js/views/sub_view.js
  52. 1 1
      web/building_saas/pm/js/pm_main.js
  53. 14 0
      web/glj/html/footer.html
  54. 46 0
      web/glj/html/glj_index.html
  55. 90 0
      web/glj/html/header.html
  56. 344 0
      web/glj/js/glj_index.js
  57. 3 0
      web/glj/js/socket.io.slim.js

File diff suppressed because it is too large
+ 12557 - 0
lib/lodash/lodash.js


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

@@ -0,0 +1,44 @@
+/**
+ * 控制器基类
+ *
+ * @author CaiAoLin
+ * @date 2017/6/29
+ * @version
+ */
+class BaseController {
+
+    /**
+     * 页面title
+     *
+     * @var string
+     */
+    title = '';
+
+    /**
+     * 构造函数
+     *
+     * @return {void}
+     */
+    constructor() {
+        if (new.target === BaseController) {
+            throw new Error('BaseController不能实例化,只能继承使用。');
+        }
+    }
+
+    /**
+     * 初始化函数
+     *
+     * @param {object} request
+     * @param {object} response
+     * @param {function} next
+     * @return {void}
+     */
+    init(request, response, next) {
+        // 页面标题
+        response.locals.title = 'test';
+
+        next();
+    }
+}
+
+export default BaseController;

+ 121 - 0
modules/common/base/base_model.js

@@ -0,0 +1,121 @@
+/**
+ * 数据模型基类
+ *
+ * @author CaiAoLin
+ * @date 2017/6/22
+ * @version
+ */
+import MongooseHelper from "../helper/mongoose_helper";
+
+class BaseModel {
+
+    /**
+     * mongoose数据模型
+     *
+     * @var {object}
+     */
+    model = null;
+
+    /**
+     * 构造函数
+     *
+     * @return {void}
+     */
+    constructor() {
+        if (new.target === BaseModel) {
+            throw new Error('BaseModel不能实例化,只能继承使用。');
+        }
+    }
+
+    /**
+     * 初始化函数
+     *
+     * @return {void}
+     */
+    init() {
+        if (this.model === null) {
+            throw new Error('子类数据有误');
+        }
+
+        this.db = new MongooseHelper();
+        this.db.model = this.model;
+    }
+
+    /**
+     * 根据id查找对应数据
+     *
+     * @param {Object} condition
+     * @param {Object} fields
+     * @param {boolean} singleData
+     * @return {Promise}
+     */
+    async findDataByCondition(condition, fields = null, singleData = true) {
+        if (Object.keys(condition).length <= 0) {
+            return null;
+        }
+
+        let data = await singleData ? this.db.findOne(condition, fields) : this.db.find(condition, fields);
+        return data;
+    }
+
+    /**
+     * 根据条件返回数据数量
+     *
+     * @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;
+    }
+
+    /**
+     * 根据id删除
+     *
+     * @param {Number} id
+     * @return {Promise}
+     */
+    async deleteById(id) {
+        let result = false;
+        id = parseInt(id);
+        if (isNaN(id) || id <= 0) {
+            return false;
+        }
+
+        try {
+            let deleteResult = await this.db.delete({id: id});
+            result = deleteResult.result.ok === 1;
+        } catch (error) {
+            console.log(error);
+            result = false;
+        }
+
+        return result;
+    }
+
+    /**
+     * 更新数据
+     *
+     * @param {Number} id
+     * @param {Object} updateData
+     * @return {Promise}
+     */
+    async updateById(id, updateData) {
+        id = parseInt(id);
+        if (isNaN(id) || id <= 0 || Object.keys(updateData).length <= 0) {
+            return false;
+        }
+
+        let result = await this.db.update({id: id}, updateData);
+
+        return result.ok !== undefined && result.ok === 1;
+    }
+
+}
+
+export default BaseModel;

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

@@ -0,0 +1,186 @@
+/**
+ * mongodb Helper
+ *
+ * @author caiaolin
+ * @date 2017/5/22.
+ */
+
+class MongooseHelper {
+
+    /**
+     * mongoose连接对象
+     *
+     * @var {object}
+     */
+    connect = null;
+
+    /**
+     * mongoose数据模型
+     *
+     * @var {object}
+     */
+    model = null;
+
+    /**
+     * 查找单一数据
+     *
+     * @param {object} conditions
+     * @param {object} fields
+     * @return {Promise}
+     */
+    findOne(conditions, fields = null) {
+        let self = this;
+        return new Promise(function (resolve, reject) {
+            self.model.findOne(conditions, fields, function (error, data) {
+                if (error) {
+                    reject(null);
+                } else {
+                    resolve(data);
+                }
+            });
+        });
+    }
+
+    /**
+     * 查找数据
+     *
+     * @param {object} conditions
+     * @param {object} fields
+     * @param {object} option
+     * @return {Promise}
+     */
+    find(conditions, fields = null, option = null) {
+        let self = this;
+        return new Promise(function (resolve, reject) {
+            self.model.find(conditions, fields, option, function (error, data) {
+                if (error) {
+                    reject(error);
+                } else {
+                    resolve(data);
+                }
+            });
+        });
+    }
+
+    /**
+     * 关联查找数据
+     *
+     * @param {object} conditions
+     * @param {object} fields
+     * @param {String|Object} populate
+     * @return {Promise}
+     */
+    findWithPopulate(conditions, fields = null, populate = '') {
+        let self = this;
+        return new Promise(function (resolve, reject) {
+            self.model.find(conditions, fields).populate(populate).exec(function(error, data) {
+                if (error) {
+                    reject(error);
+                } else {
+                    resolve(data);
+                }
+            });
+        });
+    }
+
+    /**
+     * 查找且更新(原子操作)
+     *
+     * @param {object} update
+     * @param {object} condition
+     * @param {object} options
+     * @return {Promise}
+     */
+    findAndModify(condition, update, options) {
+        let self = this;
+        return new Promise(function (resolve, reject) {
+            self.model.findOneAndUpdate(condition, update, options, function(error, data) {
+                    if (error) {
+                        reject(error);
+                    } else {
+                        resolve(data);
+                    }
+                });
+        });
+    }
+
+    /**
+     * 新增操作
+     *
+     * @param {object} data
+     * @return {Promise}
+     */
+    create(data) {
+        let self = this;
+        return new Promise(function (resolve, reject) {
+            self.model.create(data, function(error, data) {
+                if (error) {
+                    reject(error);
+                } else {
+                    resolve(data);
+                }
+            });
+        });
+    }
+
+    /**
+     * 统计数据数量
+     *
+     * @param {Object} condition
+     * @return {Promise}
+     */
+    count(condition) {
+        let self = this;
+        return new Promise(function(resolve, reject) {
+            self.model.count(condition, function(error, data) {
+                if (error) {
+                    reject(error);
+                } else {
+                    resolve(data);
+                }
+            });
+        });
+    }
+
+    /**
+     * 删除数据
+     *
+     * @param {Object} condition
+     * @return {Promise}
+     */
+    delete(condition) {
+        let self = this;
+        return new Promise(function(resolve, reject) {
+            self.model.remove(condition, function(error, data) {
+                if (error) {
+                    reject(error);
+                } else {
+                    resolve(data);
+                }
+            });
+        });
+    }
+
+    /**
+     * 更新数据
+     *
+     * @param {Object} condition
+     * @param {Object} updateData
+     * @return {Promise}
+     */
+    update(condition, updateData) {
+        let self = this;
+        return new Promise(function(resolve, reject) {
+            self.model.update(condition, {$set: updateData}, function(error, data) {
+                if (error) {
+                    reject(error);
+                } else {
+                    resolve(data);
+                }
+            });
+        });
+    }
+
+}
+
+export default MongooseHelper;

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

@@ -0,0 +1,199 @@
+/**
+ * 工料机相关控制器
+ *
+ * @author CaiAoLin
+ * @date 2017/6/22
+ * @version
+ */
+import BaseController from "../../common/base/base_controller";
+import GLJListModel from "../models/glj_list_model";
+import UnitPriceModel from "../models/unit_price_model";
+import UnitPriceFileModel from "../models/unit_price_file_model";
+
+class GLJController extends BaseController {
+
+    /**
+     * 构造函数
+     *
+     * @return {void}
+     */
+    constructor() {
+        let parent = super();
+        parent.title = '工料机';
+    }
+
+    /**
+     * 工料机汇总页
+     *
+     * @param {object} request
+     * @param {object} response
+     * @return {void}
+     */
+    async index(request, response) {
+        // 标段id
+        let projectId = request.query.project;
+        projectId = parseInt(projectId);
+        try {
+            if (isNaN(projectId) || projectId <= 0) {
+                throw '标段id有误';
+            }
+            // 先获取对应标段的项目工料机数据
+            let gljListModel = new GLJListModel();
+            let gljList = await gljListModel.getListByProjectId(projectId);
+
+            let renderData = {
+                gljList: JSON.stringify(gljList),
+                materialIdList: gljListModel.materialIdList,
+                autoChangeGLJType: UnitPriceModel.autoChangeGLJType,
+                triggerCalculateGLJType: UnitPriceModel.triggerCalculateGLJType
+            };
+            response.render('glj/html/glj_index', renderData);
+
+        } catch (error) {
+            response.status(404).send('404 Error');
+        }
+
+    }
+
+    /**
+     * 更新数据
+     *
+     * @param {object} request
+     * @param {object} response
+     * @return {void}
+     */
+    async updateData(request, response) {
+        let field = request.body.field;
+        let value = request.body.value;
+        value = value === 'true' ? 1 : value;
+        value = value === 'false' ? 0 : value;
+        let id = request.body.id;
+
+        let responseData = {
+            err: 0,
+            msg: ''
+        };
+        try {
+            // 可编辑的字段
+            let editableField = ['is_evaluate', 'unit_price.market_price', 'is_adjust_price'];
+            if (editableField.indexOf(field) < 0) {
+                throw '对应字段不能编辑';
+            }
+
+            let modelString = 'glj';
+            // 切割字段
+            let fieldArray = field.split('.');
+            modelString = fieldArray.length > 1 ? fieldArray[0] : modelString;
+            field = fieldArray.length > 1 ? fieldArray[1] : field;
+
+            // 组合数据
+            let updateData = new Object();
+            updateData[field] = value;
+
+            let result = false;
+            let model = null;
+            switch (modelString) {
+                case 'glj':
+                    model = new GLJListModel();
+                    // 更新数据
+                    result = await model.updateById(id, updateData);
+                    break;
+                case 'unit_price':
+                    model = new UnitPriceModel();
+                    // 更新数据
+                    result = await model.updatePriceById(id, updateData);
+                    break;
+            }
+
+            if (!result) {
+                throw '更新失败';
+            }
+        } catch (error) {
+            console.log('error:' + error);
+            responseData.err = 1;
+        }
+
+        response.json(responseData);
+    }
+
+    /**
+     * 模拟定额插入
+     *
+     * @param {object} request
+     * @param {object} response
+     * @return {void}
+     */
+    async test(request, response) {
+        // 从定额库获取的数据
+        let data = {
+            glj_repository_id: 1,
+            project_id: 1,
+            code: '00010201',
+            name: '土石方综合工日',
+            specs: '',
+            unit: '工日',
+            type: 2,
+            base_price: '44.76',
+            market_price: '44.76'
+        };
+        try {
+            let gljListModel = new GLJListModel();
+            let result = await gljListModel.addList(data);
+
+            console.log(result);
+        } catch (error) {
+            console.log(error);
+        }
+
+        response.end('success');
+    }
+
+    /**
+     * 模拟定额修改单价
+     *
+     * @param {object} request
+     * @param {object} response
+     * @return {void}
+     */
+    async testModify(request, response) {
+        let projectId = request.query.project;
+        // // 修改数据
+        let updateData = {
+            code: '00010201',
+            market_price: '49',
+            name: '土石方综合工日',
+            project_id: projectId
+        };
+
+        try {
+            let gljListModel = new GLJListModel();
+            let result = await gljListModel.modifyMarketPrice(updateData);
+
+            console.log(result);
+        } catch (error) {
+            console.log(error);
+        }
+        response.end('success');
+    }
+
+    /**
+     * 测试删除
+     *
+     * @param {object} request
+     * @param {object} response
+     * @return {void}
+     */
+    async delete(request, response) {
+        try {
+            let gljListModel = new GLJListModel();
+            let result = await gljListModel.deleteById(63);
+
+            console.log(result);
+        } catch (error) {
+            console.log(error);
+        }
+        response.end('success');
+    }
+}
+
+export default GLJController;

+ 0 - 8
modules/glj/db/user_glj_lib_db.js

@@ -1,8 +0,0 @@
-/**
- * Created by jimiz on 2017/5/12.
- */
-var mongoose = require("mongoose");
-var dbm = require("../../../config/db/db_manager");
-var db = dbm.getCfgConnection("userGLJLib");
-
-module.exports = db;

+ 54 - 0
modules/glj/models/counter_model.js

@@ -0,0 +1,54 @@
+/**
+ * ID计数器数据模型
+ *
+ * @author CaiAoLin
+ * @date 2017/6/23
+ * @version
+ */
+import BaseModel from "../../common/base/base_model";
+import CounterSchema from "./schemas/counter";
+
+class CounterModel extends BaseModel {
+
+
+    /**
+     * 构造函数
+     *
+     * @return {void}
+     */
+    constructor() {
+        let parent = super();
+        parent.model = CounterSchema;
+        parent.init();
+    }
+
+    /**
+     * 获取自增id
+     *
+     * @param {String} model
+     * @return {Number}
+     */
+    async getId(model = '') {
+        if (model === '') {
+            return 0;
+        }
+        let update = {$inc: {sequence_value: 1}};
+        let condition = {_id: model};
+        let options = {new: true};
+
+        // 先查找更新
+        let idData = await this.db.findAndModify(condition, update, options);
+        let idResult = idData === null || idData.sequence_value === undefined ? 0 : idData.sequence_value;
+
+        // 如果没有对应记录则新增
+        if (idResult === 0) {
+            let insertResult = await this.db.create({_id: model, sequence_value: 1});
+            idResult = Object.keys(insertResult).length > 0 ? 1 : 0;
+        }
+
+        return idResult;
+    }
+
+}
+
+export default CounterModel;

+ 303 - 0
modules/glj/models/glj_list_model.js

@@ -0,0 +1,303 @@
+/**
+ * 项目工料机列表数据模型
+ *
+ * @author CaiAoLin
+ * @date 2017/6/22
+ * @version
+ */
+import BaseModel from "../../common/base/base_model";
+import {default as GLJSchemas, collectionName as gljCollectionName} from "./schemas/glj";
+import CounterModel from "./counter_model";
+import UnitPriceModel from "./unit_price_model";
+import UnitPriceFileModel from "./unit_price_file_model";
+
+class GLJListModel extends BaseModel {
+
+    /**
+     * 材料类型id
+     *
+     * @var {Array}
+     */
+    materialIdList = [5, 6, 7];
+
+    /**
+     * 构造函数
+     *
+     * @return {void}
+     */
+    constructor() {
+        let parent = super();
+        parent.model = GLJSchemas;
+        parent.init();
+    }
+
+    /**
+     * 设置场景
+     *
+     * @param {string} scene
+     * @return {void}
+     */
+    setScene(scene = '') {
+        switch (scene) {
+            // 新增数据的验证规则
+            case 'add':
+                this.model.schema.path('glj_repository_id').required(true);
+                this.model.schema.path('project_id').required(true);
+                this.model.schema.path('code').required(true);
+                this.model.schema.path('name').required(true);
+                break;
+        }
+    }
+
+    /**
+     * 根据标段对应工料机数据
+     *
+     * @param {Number} projectId
+     * @return {Promise}
+     */
+    async getListByProjectId(projectId) {
+        let gljData = null;
+        try {
+            // 首先获取对应标段下所有的项目工料机数据
+            let condition = {project_id: projectId};
+            let fields = {_id: 0};
+            gljData = await this.db.find(condition, fields);
+
+            // 没有数据则直接返回空
+            if (gljData.length <= 0) {
+                throw '无数据';
+            }
+
+            // 获取标段对应的单价文件id
+            let unitPriceFileModel = new UnitPriceFileModel();
+            let unitPriceFile = await unitPriceFileModel.getDataByProject(projectId);
+            if (!unitPriceFile) {
+                throw '没有对应的单价文件';
+            }
+            let unitPriceFileId = unitPriceFile.id;
+
+            // 获取标段设置的单价文件数据
+            let unitPriceModel = new UnitPriceModel();
+            let unitPriceList = await unitPriceModel.getDataByFileId(unitPriceFileId);
+
+            // 组合数据
+            this.combineUnitPrice(gljData, unitPriceList);
+
+            // 排序
+            gljData.sort(function (a, b) {
+                return a.unit_price.type - b.unit_price.type;
+            });
+        } catch (error) {
+            console.log("glj_list_model:" + error);
+            gljData = [];
+        }
+
+        return gljData;
+    }
+
+    /**
+     * 组合工料机数据和单价文件数据
+     *
+     * @param {object} gljList
+     * @param {object} unitPriceList
+     * @return {void}
+     */
+    combineUnitPrice(gljList, unitPriceList) {
+        // @todo 以后从js获取?
+        let labour = 2;
+        let machine = 64;
+
+        // 循环组合数据
+        for(let glj of gljList) {
+            if (glj.code === undefined) {
+                continue;
+            }
+            glj.unit_price = unitPriceList[glj.code + glj.name] !== undefined ? unitPriceList[glj.code + glj.name] : null;
+            // 计算调整基价
+            switch (glj.type + '') {
+                // 人工: 调整基价=基价单价*调整系数
+                case labour:
+                    glj.adjust_price = glj.adjustment * glj.unit_price.base_price;
+                    break;
+                // 机械类型的算法
+                case machine:
+                    console.log('机械');
+                    break;
+                // 材料、主材、设备
+                default:
+                    glj.adjust_price = glj.unit_price.base_price;
+            }
+
+        }
+    }
+
+    /**
+     * 新增项目工料机数据(包括新增单价文件) 定额工料机新增时调用
+     *
+     * @param {object} data
+     * @return {Promise} 返回插入成功的数据id
+     */
+    async addList(data) {
+        let result = null;
+        try {
+            if (Object.keys(data).length <= 0) {
+                throw '新增数据为空';
+            }
+            // 首先查找是否有同编码同名称的工料机数据
+            let projectGljData = await this.findDataByCondition({code: data.code, project_id: data.project_id});
+            // 如果找不到数据则新增
+            if (!projectGljData) {
+                // 新增单条记录 (两个操作本来应该是事务操作,然而mongodb事务支持比较弱,就当作是都可以顺利执行)
+                let gljInsertData = await this.add(data);
+                if (!gljInsertData) {
+                    throw '新增项目工料机失败!';
+                }
+                projectGljData = gljInsertData;
+            }
+
+            // 获取标段对应的单价文件id
+            let unitPriceFileModel = new UnitPriceFileModel();
+            let unitPriceFile = await unitPriceFileModel.getDataByProject(data.project_id);
+            if (!unitPriceFile) {
+                throw '没有对应的单价文件';
+            }
+            let unitPriceFileId = unitPriceFile.id;
+
+            // 新增单价文件
+            let unitPriceModel = new UnitPriceModel();
+            let [unitPriceInsertData, isAdd] = await unitPriceModel.addUnitPrice(data, unitPriceFileId);
+
+            if (!unitPriceInsertData) {
+                throw '新增单价失败!';
+            }
+
+            projectGljData.unit_price = unitPriceInsertData;
+            result = projectGljData;
+        } catch (error) {
+            console.log(error);
+            result = null;
+        }
+
+        return result;
+    }
+
+    /**
+     * 新增单条工料机数据
+     *
+     * @param {object} data
+     * @return {Promise}
+     */
+    async add(data) {
+        if (Object.keys(data).length <= 0) {
+            throw '新增数据为空';
+        }
+
+        let counterModel = new CounterModel();
+        data.id = await counterModel.getId(gljCollectionName);
+
+        this.setScene('add');
+        let result = await this.db.create(data);
+        return result;
+    }
+
+    /**
+     * 根据工料机id修改市场单价
+     *
+     * @param {Object} updateData
+     * @return {Promise}
+     */
+    async modifyMarketPrice(updateData) {
+        let result = {};
+        try {
+            if (updateData.code === undefined || updateData.market_price === undefined ||
+                updateData.name === undefined || updateData.project_id === undefined) {
+                throw '参数有误!';
+            }
+
+            // 先查是否有对应code的数据
+            let gljListData = await this.findDataByCondition({code: updateData.code,
+                project_id: updateData.project_id}, {_id: 0}, false);
+            if (!gljListData) {
+                throw '不存在对应code数据';
+            }
+
+            // 获取标段对应的单价文件id
+            let unitPriceFileModel = new UnitPriceFileModel();
+            let unitPriceFile = await unitPriceFileModel.getDataByProject(updateData.project_id);
+            if (!unitPriceFile) {
+                throw '没有对应的单价文件';
+            }
+            let unitPriceFileId = unitPriceFile.id;
+            let unitPriceModel = new UnitPriceModel();
+
+            let gljCount = gljListData.length;
+            let [unitPriceData, isAdd] = await unitPriceModel.addUnitPrice(updateData, unitPriceFileId, gljCount);
+
+            // 判断是否已存在对应数据
+            let includeField = [
+                {field: 'name', value: unitPriceData.name}
+            ];
+            let gljIndex = this.isIncluded(gljListData, includeField);
+            let gljData = isAdd ? {} : gljListData[gljIndex];
+
+            // 如果单价数据新增则工料机也需要新增
+            if (isAdd) {
+                // 如果没有对应的记录则新增一条工料机数据,并更改name
+                let regular = /\(\d\)/;
+                let changeString = '(' + gljCount + ')';
+                updateData.name = regular.test(updateData.name) ? updateData.name.replace(regular, changeString) :
+                    updateData.name + changeString;
+
+                // 获取第一条数据作为数据源
+                let originalData = gljListData[0];
+
+                // 更改名称
+                originalData.name = updateData.name;
+                originalData = JSON.stringify(originalData);
+                gljData = await this.add(JSON.parse(originalData));
+                if (!gljData) {
+                    throw '新增工料机数据失败!';
+                }
+            }
+
+            gljData.unit_price = unitPriceData;
+
+            result = gljData;
+        } catch (error) {
+            console.log(error);
+            result = {};
+        }
+
+        return result;
+    }
+
+    /**
+     * 判断数据中是否包含某个数据
+     *
+     * @param {Array} data
+     * @param {Array} includeField
+     * @return {Number}
+     */
+    isIncluded(data, includeField) {
+        let index = -1;
+        if (data.length <= 0) {
+            return index;
+        }
+        for(let tmp in data) {
+            let counter = 0;
+            for (let includeTmp of includeField) {
+                if (data[tmp][includeTmp.field] === includeTmp.value) {
+                    counter++;
+                }
+            }
+            if (counter === includeField.length) {
+                index = tmp;
+                break;
+            }
+        }
+
+        return index;
+    }
+}
+
+export default GLJListModel;

+ 70 - 0
modules/glj/models/glj_repository_model.js

@@ -0,0 +1,70 @@
+/**
+ * 工料机数据源模块
+ *
+ * @author CaiAoLin
+ * @date 2017/6/23
+ * @version
+ */
+import BaseModel from "../../common/base/base_model";
+import GLJRepositorySchema from "./schemas/glj_repository";
+
+class GLJRepositoryModel extends BaseModel {
+
+    /**
+     * 构造函数
+     *
+     * @return {void}
+     */
+    constructor() {
+        let parent = super();
+        parent.model = GLJRepositorySchema;
+        parent.init();
+    }
+
+    /**
+     * 新增数据
+     *
+     * @param {object} data
+     * @return {Promise} boolean
+     */
+    async add(data) {
+        let result = false;
+        try {
+            result = await this.db.create(data);
+        } catch (error) {
+            if (error.name !== null && error.name === 'ValidationError') {
+                // 这里是数据验证失败
+                console.log('数据验证失败!');
+            }
+            result = false;
+        }
+
+        return result;
+    }
+
+    /**
+     * 根据条件获取对应工料机数据
+     *
+     * @param {Object} condition
+     * @return {Promise} Array
+     */
+    async getDataByCondition(condition) {
+        let gljData = [];
+        try {
+            if (Object.keys(condition).length <= 0) {
+                throw '筛选条件有误';
+            }
+
+            gljData = await this.db.find(condition);
+
+        } catch (error) {
+            console.log(error);
+            gljData = [];
+        }
+
+        return gljData;
+    }
+
+}
+
+export default GLJRepositoryModel;

+ 22 - 0
modules/glj/models/schemas/counter.js

@@ -0,0 +1,22 @@
+/**
+ * 计数器数据结构
+ *
+ * @author CaiAoLin
+ * @date 2017/6/29
+ * @version
+ */
+import mongoose from "mongoose";
+
+let Schema = mongoose.Schema;
+let collectionName = 'counter';
+let modelSchema = {
+    // 模块名称
+    _id: String,
+    // 计数器
+    sequence_value: {
+        type: Number,
+        default: 1
+    },
+};
+
+export default mongoose.model(collectionName, new Schema(modelSchema, {versionKey: false}));

+ 65 - 0
modules/glj/models/schemas/glj.js

@@ -0,0 +1,65 @@
+/**
+ * 工料机数据模型
+ *
+ * @author CaiAoLin
+ * @date 2017/6/29
+ * @version
+ */
+import mongoose from "mongoose";
+
+let Schema = mongoose.Schema;
+let collectionName = 'glj_list';
+let modelSchema = {
+    // 自增id
+    id: Number,
+    // 工料机总库ID
+    glj_repository_id: Number,
+    // 标段ID
+    project_id: Number,
+    // 编码
+    code: String,
+    // 名称
+    name: String,
+    // 是否暂估 (0为否 1为是)
+    is_evaluate: {
+        type: Number,
+        default: 0
+    },
+    // 供货方式
+    supply: {
+        type: String,
+        default: ''
+    },
+    // 甲供数量
+    supply_quantity: {
+        type: Number,
+        default: 0
+    },
+    // 交货方式
+    delivery: {
+        type: String,
+        default: ''
+    },
+    // 送达地点
+    delivery_address: {
+        type: String,
+        default: ''
+    },
+    // 不调价
+    is_adjust_price: {
+        type: Number,
+        default: 0
+    },
+    // 调整系数
+    adjustment: {
+        type: Number,
+        default: 1
+    },
+    // 显示调整基价
+    adjust_price: String,
+    // 显示关联单价文件的字段
+    unit_price: Schema.Types.Mixed
+};
+let model = mongoose.model(collectionName, new Schema(modelSchema, {versionKey: false}));
+
+export { model as default, collectionName as collectionName} ;

+ 29 - 0
modules/glj/models/schemas/glj_repository.js

@@ -0,0 +1,29 @@
+/**
+ * 数据结构
+ *
+ * @author CaiAoLin
+ * @date 2017/6/28
+ * @version
+ */
+import mongoose from "mongoose";
+
+let Schema = mongoose.Schema;
+let collectionName = 'glj_repository';
+let modelSchema = {
+    // 自增id
+    id: Number,
+    // 定额id
+    ration_id: Number,
+    // 名称
+    name: String,
+    // 编号
+    code: String,
+    // 单位
+    unit: String,
+    // 定额单价
+    ration_price: String,
+    // 规格
+    standard: String
+};
+
+export default mongoose.model(collectionName, new Schema(modelSchema, {versionKey: false}));

+ 36 - 0
modules/glj/models/schemas/unit_price.js

@@ -0,0 +1,36 @@
+/**
+ * 具体单价数据结构
+ *
+ * @author CaiAoLin
+ * @date 2017/6/29
+ * @version
+ */
+import mongoose from "mongoose";
+
+let Schema = mongoose.Schema;
+let collectionName = 'unit_price';
+let modelSchema = {
+    // 自增ID
+    id: Number,
+    // 基价单价
+    base_price: String,
+    // 市场单价
+    market_price: String,
+    // 编码
+    code: String,
+    // 名称
+    name: String,
+    // 规格型号
+    specs: {
+        type: String,
+        default: ''
+    },
+    // 单位
+    unit: String,
+    // 类型
+    type: Number,
+    // 单价文件表id
+    unit_price_file_id: Number,
+};
+let model = mongoose.model(collectionName, new Schema(modelSchema, {versionKey: false, collection: collectionName}));
+export {model as default, collectionName as collectionName};

+ 21 - 0
modules/glj/models/schemas/unit_price_file.js

@@ -0,0 +1,21 @@
+/**
+ * 具体单价数据结构
+ *
+ * @author CaiAoLin
+ * @date 2017/6/29
+ * @version
+ */
+import mongoose from "mongoose";
+
+let Schema = mongoose.Schema;
+let collectionName = 'unit_price_file';
+let modelSchema = {
+    // 自增id
+    id: Number,
+    // 标段id
+    project_id: Number,
+    // 显示名称
+    name: String,
+};
+let model = mongoose.model(collectionName, new Schema(modelSchema, {versionKey: false, collection: collectionName}));
+export {model as default, collectionName as collectionName};

+ 65 - 43
modules/glj/models/unit_price_file.js

@@ -1,77 +1,99 @@
 /**
 /**
- * Created by jimiz on 2017/5/12.
+ * Created by jimiz on 2017/5/10.
+ * 单价文件的GLJ列表,注意与项目GLJ区分
  */
  */
 var mongoose = require("mongoose");
 var mongoose = require("mongoose");
 var db = require("../db/unit_price_file_db");
 var db = require("../db/unit_price_file_db");
 var Schema = mongoose.Schema;
 var Schema = mongoose.Schema;
 var deleteSchema = require('../../../public/models/delete_schema');
 var deleteSchema = require('../../../public/models/delete_schema');
+var counter = require("../../../public/counter/counter.js");
 var consts = require('../../main/models/project_consts');
 var consts = require('../../main/models/project_consts');
 var projectConsts = consts.projectConst;
 var projectConsts = consts.projectConst;
 var commonConsts = consts.commonConst;
 var commonConsts = consts.commonConst;
-var GLJList = require('./glj_list');
 
 
-var unitPriceFileSchema = new Schema({
+var GLJListSchema = new Schema({
     ID: Number,
     ID: Number,
+    fileID: Number,
+    code: String,
     name: String,
     name: String,
-    version: Number,
-    projects: Array,
+    specs: String,
+    unit: String,
+    type: Number,
+    adjustPrice: String,
+    rationPrice: String,
+    price: String, //Decimal
     deleteInfo: deleteSchema
     deleteInfo: deleteSchema
 });
 });
 
 
-var unitPriceFile = db.model("unitPriceFile", unitPriceFileSchema, "unitPriceFile");
+var GLJList = db.model("GLJList", GLJListSchema, "GLJList");
 
 
-var unitPriceFileDAO = function(){};
+var GLJListDAO = function(){};
 
 
-unitPriceFileDAO.prototype.getData = function(fileID, callback){
-    var data;
-    unitPriceFile.find({'$or': [{fileID: fileID, deleteInfo: null}, {fileID: fileID, 'deleteInfo.deleted': {$in: [null, false]}}]}, '-_id', function(err, datas){
+GLJListDAO.prototype.getData = function(fileID, callback){
+    var me = this;
+    GLJList.find({'$or': [{fileID: fileID, deleteInfo: null}, {fileID: fileID, 'deleteInfo.deleted': {$in: [null, false]}}]}, '-_id', function(err, datas){
         if (!err) {
         if (!err) {
-            GLJList.getData(fileID, function(err, gljList){
-                data['properties'] = datas[0];
-                data['glj_list'] = gljList;
-                callback(0, projectConsts.UNITPRICEFILE, data);
-            });
+            callback(0, projectConsts.GLJLIST, datas);
         } else {
         } else {
             callback(1, '', null);
             callback(1, '', null);
         }
         }
     });
     });
 };
 };
 
 
-unitPriceFileDAO.prototype.save = function(fileId, datas, callback){
-    function changed(err, changedDatas){
-        sync(fileId, changedDatas, callback);
-    }
-
-
-    GLJList.save(fileID, datas, changed);
-};
-
-unitPriceFileDAO.prototype.sync = function(fileID, datas, callback){
-    unitPriceFile.find({'$or': [{ID: fileID, deleteInfo: null}, {ID: fileID, 'deleteInfo.deleted': {$in: [null, false]}}]}, '-_id', function(err, datas){
-        if (!err) {
-            // to do
+// 单价文件中的工料机不在这里新增,只能由add方法新增,删除需要在前端projectGLJ判断:1、是新工料机;2、没有定额引用,才可以删除
+GLJListDAO.prototype.save = function(fileId, datas, callback){
+    var functions = [];
+    var data;
 
 
-            callback(0, projectConsts.UNITPRICEFILE, datas);
-        } else {
-            callback(1, '', null);
+    // cb中返回doc,以便进行同步
+    function saveOne(doc) {
+        return function (cb) {
+            function updateCallback(err, data){
+                cb(err, doc);
+            }
+            switch (doc.updateType) {
+                case commonConsts.UT_UPDATE:
+                    ration.update({ID: doc.ID}, doc, updateCallback);
+                    break;
+                case commonConsts.UT_DELETE:
+                /* 假删除
+                 var item = new ration(doc);
+                 item.remove(cb);
+                 */
+            }
         }
         }
-    });
-};
-
-unitPriceFileDAO.prototype.add = function(fileID, count, callback){
-    GLJList.add(fileID, count, callback);
-};
-
-unitPriceFileDAO.prototype.newFile = function(data, callback){
+    }
+    for (var i = 0; i < datas.length; i++){
+        data = datas[i];
+        functions.push(saveOne(data));
+    }
 
 
+    async.parallel(functions, callback);
 };
 };
 
 
-unitPriceFileDAO.prototype.useFile = function(fileID, projectID, callback){
+GLJListDAO.prototype.add = function(fileID, count, callback){
 
 
-};
+    function newCallback(err, lowID, highID){
+        if (!err) {
+            var datas = [];
+            for (var i = lowID; i <= highID; i++){
+                var GLJ = new GLJList;
+                GLJ.ID = i;
+                GLJ.fileID = fileID;
+                datas.push(GLJ);
+            }
+            callback(err, datas);
 
 
-unitPriceFileDAO.prototype.unuseFile = function(fileID, projectID, callback){
+        }
+        else{
+            callback(err, null);
+        }
+    }
 
 
+    counter.counterDAO.getIDAfterCount(COUNTER_MODULE_NAME.unitPriceGLJ, IDStep, function(err, highID){
+        var lowID = highID - IDStep + 1;
+        newCallback(err, lowID, highID);
+    });
 };
 };
 
 
-module.exports = new unitPriceFileDAO();
+module.exports = new GLJListDAO();

+ 112 - 0
modules/glj/models/unit_price_file_model.js

@@ -0,0 +1,112 @@
+/**
+ * 单价文件显示业务模型(用于选择单价文件操作)
+ *
+ * @author CaiAoLin
+ * @date 2017/7/5
+ * @version
+ */
+import BaseModel from "../../common/base/base_model";
+import CounterModel from "./counter_model";
+import {default as UnitPriceFileSchema, collectionName as collectionName} from "./schemas/unit_price_file";
+
+class UnitPriceFileModel extends BaseModel {
+
+    /**
+     * 构造函数
+     *
+     * @return {void}
+     */
+    constructor() {
+        let parent = super();
+        parent.model = UnitPriceFileSchema;
+        parent.init();
+    }
+
+    /**
+     * 设置场景
+     *
+     * @param {string} scene
+     * @return {void}
+     */
+    setScene(scene = '') {
+        switch (scene) {
+            // 新增数据的验证规则
+            case 'add':
+                this.model.schema.path('name').required(true);
+                this.model.schema.path('project_id').required(true);
+                break;
+        }
+    }
+
+    /**
+     * 新增单价文件
+     *
+     * @param {object} data
+     * @return {Promise}
+     */
+    async add(data) {
+        let result = false;
+        try {
+            if (Object.keys(data).length <= 0) {
+                throw '数据为空';
+            }
+            result = await this.db.create(data);
+        } catch (error) {
+            result = false;
+        }
+
+        return result;
+    }
+
+    /**
+     * 根据项目id获取单价文件数据
+     *
+     * @param {Number} projectId
+     * @return {Promise}
+     */
+    async getDataByProject(projectId) {
+        let result = null;
+        projectId = parseInt(projectId);
+        try {
+            if (isNaN(projectId) || projectId <= 0) {
+                throw '标段id有误';
+            }
+            result = await this.findDataByCondition({project_id: projectId});
+
+            // 如果没有找到则新增一条记录
+            if (!result) {
+                let data = {
+                    // @todo 后续再项目中获取
+                    name: 'projectName',
+                    project_id: projectId
+                };
+                result = await this.add(data);
+            }
+        } catch (error) {
+            console.log('error:' + error);
+        }
+
+        return result;
+    }
+
+    /**
+     * 新增单条工料机数据
+     *
+     * @param {object} data
+     * @return {Promise}
+     */
+    async add(data) {
+        if (Object.keys(data).length <= 0) {
+            throw '新增数据为空';
+        }
+
+        let counterModel = new CounterModel();
+        data.id = await counterModel.getId(collectionName);
+
+        this.setScene('add');
+        let result = await this.db.create(data);
+        return result;
+    }
+}
+
+export default UnitPriceFileModel;

+ 207 - 0
modules/glj/models/unit_price_model.js

@@ -0,0 +1,207 @@
+/**
+ * 单价业务模型
+ *
+ * @author CaiAoLin
+ * @date 2017/6/30
+ * @version
+ */
+import BaseModel from "../../common/base/base_model"
+import CounterModel from "./counter_model"
+import GLJListModel from "./glj_list_model";
+import {default as UnitPriceSchema, collectionName as collectionName} from "./schemas/unit_price";
+
+class UnitPriceModel extends BaseModel {
+
+    /**
+     * 自动赋值的工料机类型集
+     * (主材、设备)
+     *
+     * @var {Array}
+     */
+    static autoChangeGLJType = [10, 11];
+
+    /**
+     * 触发计算混凝土、砂浆、配合比、机械的市场单价
+     * (人工、材料(普通材料))
+     *
+     * @var {Array}
+     */
+    static triggerCalculateGLJType = [2, 5];
+
+    /**
+     * 构造函数
+     *
+     * @return {void}
+     */
+    constructor() {
+        let parent = super();
+        parent.model = UnitPriceSchema;
+        parent.init();
+    }
+
+    /**
+     * 根据单价文件id获取单价数据
+     *
+     * @param {Number} fileId
+     * @return {Promise}
+     */
+    async getDataByFileId(fileId) {
+        fileId = parseInt(fileId);
+        if (isNaN(fileId) || fileId <= 0) {
+            return null;
+        }
+
+        let unitPriceList = await this.db.model.find({unit_price_file_id: fileId});
+        if (unitPriceList.length <= 0) {
+            return null;
+        }
+
+        // 整理数据
+        let result = {};
+        for(let tmp of unitPriceList) {
+            result[tmp.code + tmp.name] = tmp;
+        }
+
+        return result;
+    }
+
+    /**
+     * 设置场景
+     *
+     * @param {string} scene
+     * @return {void}
+     */
+    setScene(scene = '') {
+        switch (scene) {
+            // 新增数据的验证规则
+            case 'add':
+                this.model.schema.path('base_price').required(true);
+                this.model.schema.path('market_price').required(true);
+                this.model.schema.path('name').required(true);
+                this.model.schema.path('code').required(true);
+                this.model.schema.path('unit').required(true);
+                this.model.schema.path('type').required(true);
+                this.model.schema.path('unit_price_file_id').required(true);
+        }
+    }
+
+    /**
+     * 新增单价数据
+     *
+     * @param {Object} data
+     * @param {Number} unitPriceFileId
+     * @param {Number} gljCount
+     * @return {Promise} 返回数据以及是否新增
+     */
+    async addUnitPrice(data, unitPriceFileId, gljCount = 0) {
+        if (data.code === undefined || data.project_id === undefined || data.name === undefined
+            || data.market_price === undefined) {
+            return [null, false];
+        }
+
+        // 先查找是否有同code的单价记录 @todo 后续可能会加入单位这个字段进一步确定唯一性
+        let unitPriceData = await this.findDataByCondition({code: data.code, unit_price_file_id: unitPriceFileId}, null, false);
+
+        // 如果有记录,判断是否存在一样的市场单价,有则直接返回数据
+        let unitPriceIndex = this.isPriceIncluded(unitPriceData, data.market_price);
+        if (unitPriceData && unitPriceIndex >= 0) {
+            return [unitPriceData[unitPriceIndex], false];
+        }
+
+        // 如果不存在基价单价,则在数据源中获取
+        if (data.base_price === undefined) {
+            let firstUnitPrice = unitPriceData[0] !== undefined ? unitPriceData[0] : [];
+            data.base_price = firstUnitPrice.base_price !== undefined ? firstUnitPrice.base_price : 0;
+            data.type = firstUnitPrice.type !== undefined ? firstUnitPrice.type : 0;
+            data.unit = firstUnitPrice.unit !== undefined ? firstUnitPrice.unit : 0;
+        }
+
+        // 更改名称
+        if (gljCount > 0) {
+            let regular = /\(\d\)/;
+            let changeString = '(' + gljCount + ')';
+            data.name = regular.test(data.name) ? data.name.replace(regular, changeString) :
+                data.name + changeString;
+        }
+
+        let insertData = {
+            code: data.code,
+            base_price: data.base_price,
+            market_price: data.market_price,
+            unit_price_file_id: unitPriceFileId,
+            name: data.name,
+            type: data.type,
+            unit: data.unit
+        };
+
+        let addPriceResult = await this.add(insertData);
+        return [addPriceResult, true];
+    }
+
+    /**
+     * 新增记录
+     *
+     * @param {object} data
+     * @return {Promise}
+     */
+    async add(data) {
+        let counterModel = new CounterModel();
+        let unitPriceId = await counterModel.getId(collectionName);
+        data.id = unitPriceId;
+
+        this.setScene('add');
+        return this.db.model.create(data);
+    }
+
+    /**
+     * 判断数据中是否包含某个市场价格的记录
+     *
+     * @param {Array} data
+     * @param {Number} price
+     * @return {Number}
+     */
+    isPriceIncluded(data, price) {
+        let index = -1;
+        if (data.length <= 0) {
+            return index;
+        }
+        for(let tmp in data) {
+            if (data[tmp].market_price === price) {
+                index = tmp;
+                break;
+            }
+        }
+
+        return index;
+    }
+
+    /**
+     * 更新市场单价
+     *
+     * @param {Number} id
+     * @param {Object} updateData
+     * @return {Promise}
+     */
+    async updatePriceById(id, updateData) {
+        id = parseInt(id);
+        if (isNaN(id) || id <= 0 || Object.keys(updateData).length <= 0) {
+            return false;
+        }
+        // 首先查找相应的数据判断工料机类型
+        let unitPriceData = this.findDataByCondition({id: id});
+        if (!unitPriceData) {
+            throw '找不到对应的单价数据';
+        }
+
+        // 如果是主材、设备自动赋值基价单价=市场单价、调整基价=市场单价
+        if (UnitPriceModel.autoChangeGLJType.indexOf(unitPriceData.type) >= 0) {
+            updateData.base_price = updateData.market_price;
+        }
+
+        let result = await this.updateById(id, updateData);
+        return result;
+    }
+
+}
+
+export default UnitPriceModel;

+ 5 - 1
modules/glj/models/user_glj_lib.js

@@ -1,3 +1,7 @@
 /**
 /**
- * Created by jimiz on 2017/5/12.
+ *
+ *
+ * @author CaiAoLin
+ * @date 2017/7/5
+ * @version
  */
  */

+ 22 - 0
modules/glj/routes/glj_router.js

@@ -0,0 +1,22 @@
+/**
+ * 登录相关路由
+ *
+ * @author CaiAoLin
+ * @date 2017/6/22
+ * @version
+ */
+import Express from "express";
+import GLJController from "../controllers/glj_controller";
+
+const router = Express.Router();
+let gljController = new GLJController();
+
+// action定义区域
+router.get('/', gljController.init, gljController.index);
+router.post('/update', gljController.init, gljController.updateData);
+
+router.get('/test', gljController.init, gljController.test);
+router.get('/testModify', gljController.init, gljController.testModify);
+router.get('/testDelete', gljController.init, gljController.delete);
+
+module.exports = router;

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

@@ -13,9 +13,9 @@ module.exports = {
         var data = JSON.parse(req.body.data);
         var data = JSON.parse(req.body.data);
         Project.save(data, function (err, message, result) {
         Project.save(data, function (err, message, result) {
             if (err) {
             if (err) {
-                callback(req, res, err, message, result);
-            } else {
                 callback(req, res, err, message, null);
                 callback(req, res, err, message, null);
+            } else {
+                callback(req, res, err, message, result);
             }
             }
         });
         });
     },
     },

+ 7 - 1
modules/main/models/project.js

@@ -4,6 +4,7 @@
 var billsData = require('./bills');
 var billsData = require('./bills');
 var rationData = require('./ration');
 var rationData = require('./ration');
 var GLJData = require('./glj');
 var GLJData = require('./glj');
+var ration_glj_data = require('../../ration_glj/facade/ration_glj_facade')
 let projCounter = require('./proj_counter');
 let projCounter = require('./proj_counter');
 var consts = require('./project_consts');
 var consts = require('./project_consts');
 var projectConsts = consts.projectConst;
 var projectConsts = consts.projectConst;
@@ -14,6 +15,7 @@ var moduleMap = {};
 moduleMap[projectConsts.BILLS] = billsData;
 moduleMap[projectConsts.BILLS] = billsData;
 moduleMap[projectConsts.RATION] = rationData;
 moduleMap[projectConsts.RATION] = rationData;
 moduleMap[projectConsts.GLJ] = GLJData;
 moduleMap[projectConsts.GLJ] = GLJData;
+moduleMap[projectConsts.RATION_GLJ] = ration_glj_data;
 moduleMap[projCounter.collectionName] = projCounter;
 moduleMap[projCounter.collectionName] = projCounter;
 
 
 var Project = function (){};
 var Project = function (){};
@@ -42,7 +44,11 @@ Project.prototype.save = function(datas, callback){
 
 
     function saveModule(data) {
     function saveModule(data) {
         return function (cb) {
         return function (cb) {
-            moduleMap[data.moduleName].save(data.user_id, data.data, cb);
+            if(data.moduleName!=undefined){
+                moduleMap[data.moduleName].save(data.user_id, data.data, cb);
+            }
+           // console.log(moduleMap[data.moduleName])
+
         }
         }
     }
     }
     for (var i = 0; i < me.datas.length; i++){
     for (var i = 0; i < me.datas.length; i++){

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

@@ -5,6 +5,7 @@ var projectConst = {
     BILLS: 'bills',
     BILLS: 'bills',
     RATION: 'ration',
     RATION: 'ration',
     GLJ: 'GLJ',
     GLJ: 'GLJ',
+    RATION_GLJ:'ration_glj',
     PROJECTGLJ: 'projectGLJ',
     PROJECTGLJ: 'projectGLJ',
     GLJLIST: 'GLJList',
     GLJLIST: 'GLJList',
     UNITPRICEFILE: 'unitPriceFile',
     UNITPRICEFILE: 'unitPriceFile',

+ 6 - 6
modules/main/models/project_glj.js

@@ -2,6 +2,7 @@
  * Created by jimiz on 2017/4/1.
  * Created by jimiz on 2017/4/1.
  * 工料机汇总
  * 工料机汇总
  */
  */
+
 var mongoose = require("mongoose");
 var mongoose = require("mongoose");
 var db = require("../db/project_db");
 var db = require("../db/project_db");
 var Schema = mongoose.Schema;
 var Schema = mongoose.Schema;
@@ -94,16 +95,15 @@ projectGLJDAO.prototype.save = function(projectID, datas, callback){
                 case commonConsts.UT_UPDATE:
                 case commonConsts.UT_UPDATE:
                     projectGLJ.update({ID: doc.ID}, doc, cb);
                     projectGLJ.update({ID: doc.ID}, doc, cb);
                     break;
                     break;
-                case commonConsts.UT_DELETE:
-                /* 假删除
-                 var item = new ration(doc);
-                 item.remove(cb);
-                 */
+                // commonConsts.UT_DELETE:
+                 // 假删除
+                 // var item = new ration(doc);
+                 // item.remove(cb);
+
             }
             }
         }
         }
     }
     }
     for (var i = 0; i < datas.length; i++){
     for (var i = 0; i < datas.length; i++){
-        data = datas[i];
         functions.push(saveOne(data));
         functions.push(saveOne(data));
     }
     }
 
 

+ 4 - 2
modules/main/models/ration.js

@@ -68,16 +68,18 @@ class rationModel extends baseModel {
                         break;
                         break;
                     case commonConsts.UT_DELETE:
                     case commonConsts.UT_DELETE:
                         doc.updateData.deleteInfo = {deleted: true, deleteDateTime: new Date(), deleteBy: user_id};
                         doc.updateData.deleteInfo = {deleted: true, deleteDateTime: new Date(), deleteBy: user_id};
-                        ration.update({projectID: doc.updateData.projectID, ID: doc.updateData.ID}, doc.updateData, cb);
+                        ration.update({projectID: doc.updateData.projectID, ID: doc.updateData.ID}, doc.updateData,{multi: true},cb);
                         break;
                         break;
                 }
                 }
             }
             }
         }
         }
+
+        functions
+
         for (let i = 0; i < datas.length; i++){
         for (let i = 0; i < datas.length; i++){
             data = datas[i];
             data = datas[i];
             functions.push(saveOne(data));
             functions.push(saveOne(data));
         }
         }
-
         async.parallel(functions, callback);
         async.parallel(functions, callback);
     };
     };
 
 

+ 8 - 9
modules/pm/controllers/pm_controller.js

@@ -1,8 +1,8 @@
 /**
 /**
  * Created by Mai on 2017/1/18.
  * Created by Mai on 2017/1/18.
  */
  */
-let ProjectsData = require('../models/project').project;
-let projType = require('../models/project').projType;
+let ProjectsData = require('../models/project_model').project;
+let projType = require('../models/project_model').projType;
 
 
 //统一回调函数
 //统一回调函数
 let callback = function(req, res, err, message, data){
 let callback = function(req, res, err, message, data){
@@ -36,8 +36,7 @@ module.exports = {
         });
         });
     },
     },
     getProjects: function(req, res){
     getProjects: function(req, res){
-        let data = JSON.parse(req.body.data);
-        ProjectsData.getUserProjects(data.user_id, function(err, message, projects){
+        ProjectsData.getUserProjects(req.session.sessionUser.ssoId, function(err, message, projects){
             if (projects) {
             if (projects) {
                 callback(req, res, err, message, projects);
                 callback(req, res, err, message, projects);
             } else {
             } else {
@@ -47,7 +46,7 @@ module.exports = {
     },
     },
     updateProjects: function (req, res) {
     updateProjects: function (req, res) {
         let data = JSON.parse(req.body.data);
         let data = JSON.parse(req.body.data);
-        ProjectsData.updateUserProjects(data.user_id, data.updateData, function (err, message, data) {
+        ProjectsData.updateUserProjects(req.session.sessionUser.ssoId, data.updateData, function (err, message, data) {
             if (err === 0) {
             if (err === 0) {
                 callback(req, res, err, message, data);
                 callback(req, res, err, message, data);
             } else {
             } else {
@@ -57,7 +56,7 @@ module.exports = {
     },
     },
     copyProjects: function (req, res) {
     copyProjects: function (req, res) {
         let data = JSON.parse(req.body.data);
         let data = JSON.parse(req.body.data);
-        ProjectsData.copyUserProjects(data.user_id, data.updateData, function (err, message, data) {
+        ProjectsData.copyUserProjects(req.session.sessionUser.ssoId, data.updateData, function (err, message, data) {
             if (err === 0) {
             if (err === 0) {
                 callback(req, res, err, message, data);
                 callback(req, res, err, message, data);
             } else {
             } else {
@@ -67,13 +66,13 @@ module.exports = {
     },
     },
     rename: function (req, res) {
     rename: function (req, res) {
         let data = JSON.parse(req.body.data);
         let data = JSON.parse(req.body.data);
-        ProjectsData.rename(data.user_id, data.id, data.newName, function (err, message) {
+        ProjectsData.rename(req.session.sessionUser.ssoId, data.id, data.newName, function (err, message) {
             callback(req, res, err, message, null);
             callback(req, res, err, message, null);
         });
         });
     },
     },
     getProject: function(req, res){
     getProject: function(req, res){
         let data = JSON.parse(req.body.data);
         let data = JSON.parse(req.body.data);
-        ProjectsData.getUserProject(data.user_id, data.proj_id, function(err, message, data){
+        ProjectsData.getUserProject(req.session.sessionUser.ssoId, data.proj_id, function(err, message, data){
             if (err === 0) {
             if (err === 0) {
                 callback(req, res, err, message, data);
                 callback(req, res, err, message, data);
             } else {
             } else {
@@ -83,7 +82,7 @@ module.exports = {
     },
     },
     beforeOpenProject: function (req, res) {
     beforeOpenProject: function (req, res) {
         let data = JSON.parse(req.body.data);
         let data = JSON.parse(req.body.data);
-        ProjectsData.beforeOpenProject(data.user_id, data.proj_id, data.updateData, function (err, message, data) {
+        ProjectsData.beforeOpenProject(req.session.sessionUser.ssoId, data.proj_id, data.updateData, function (err, message, data) {
             callback(req, res, err, message, data);
             callback(req, res, err, message, data);
         });
         });
     },
     },

+ 8 - 25
modules/pm/models/project.js

@@ -6,25 +6,11 @@ let counter = require("../../../public/counter/counter.js");
 let newProjController = require('../controllers/new_proj_controller');
 let newProjController = require('../controllers/new_proj_controller');
 let copyProjController = require('../controllers/copy_proj_controller');
 let copyProjController = require('../controllers/copy_proj_controller');
 
 
-let mongoose = require("mongoose");
-
-let dbm = require("../../../config/db/db_manager");
-let db = dbm.getCfgConnection("usersManages");
-let Schema = mongoose.Schema;
-let deleteSchema = require('../../../public/models/delete_schema');
-let ProjectSchema = new Schema({
-    "ID": Number,
-    "ParentID": Number,
-    "NextSiblingID": Number,
-    "userID": Number,
-    "name": String,
-    "projType": String,
-    "recentDateTime": Date,
-    "createDateTime": Date,
-    "deleteInfo": deleteSchema,
-    'fullFolder': Array
-});
-let Projects = db.model("projects", ProjectSchema);
+let Projects = require("./project_schema");
+let projectType = {
+    folder: 'Folder',
+    tender: 'Tender'
+};
 
 
 let ProjectsDAO = function(){};
 let ProjectsDAO = function(){};
 
 
@@ -68,12 +54,12 @@ ProjectsDAO.prototype.updateUserProjects = function(userId, datas, callback){
                 Projects.update({userID: userId, ID: data.updateData.ID}, data.updateData, updateAll)
                 Projects.update({userID: userId, ID: data.updateData.ID}, data.updateData, updateAll)
             } else if (data.updateType === 'new') {
             } else if (data.updateType === 'new') {
                 data.updateData['userID'] = userId;
                 data.updateData['userID'] = userId;
-                if (data.updateData.projType === 'Tender') {
+                if (data.updateData.projType === projectType.folder) {
                     data.updateData['createDateTime'] = new Date();
                     data.updateData['createDateTime'] = new Date();
                 }
                 }
                 newProject = new Projects(data.updateData);
                 newProject = new Projects(data.updateData);
                 newProject.save(function (err, result) {
                 newProject.save(function (err, result) {
-                    if (!err && result._doc.projType === 'Tender') {
+                    if (!err && result._doc.projType === projectType.tender) {
                         newProjController.copyTemplateData(tempType, newProject.ID, updateAll);
                         newProjController.copyTemplateData(tempType, newProject.ID, updateAll);
                     } else {
                     } else {
                         updateAll(err);
                         updateAll(err);
@@ -181,8 +167,5 @@ ProjectsDAO.prototype.getProject = function (key, callback) {
 
 
 module.exports ={
 module.exports ={
     project: new ProjectsDAO(),
     project: new ProjectsDAO(),
-    projType: {
-        folder: 'Folder',
-        tender: 'Tender'
-    }
+    projType: projectType
 };
 };

+ 26 - 0
modules/pm/models/project_schema.js

@@ -0,0 +1,26 @@
+/**
+ * Created by Mai on 2017/7/5.
+ */
+
+let mongoose = require("mongoose");
+let Schema = mongoose.Schema;
+let deleteSchema = require('../../../public/models/delete_schema');
+
+let collectionName = 'projects';
+let ProjectSchema = new Schema({
+    "ID": Number,
+    "ParentID": Number,
+    "NextSiblingID": Number,
+    "userID": Number,
+    "name": String,
+    "projType": String,
+    "recentDateTime": Date,
+    "createDateTime": Date,
+    "deleteInfo": deleteSchema,
+    'fullFolder': Array
+});
+
+module.exports = mongoose.model(collectionName, ProjectSchema)
+
+
+

+ 256 - 0
modules/ration_glj/facade/ration_glj_facade.js

@@ -0,0 +1,256 @@
+/**
+ * Created by chen on 2017/6/29.
+ */
+
+let mongoose = require('mongoose');
+const uuidV1 = require('uuid/v1')
+let consts = require('../../main/models/project_consts')
+let commonConsts = consts.commonConst;
+let _=require("lodash");
+let ration_glj = mongoose.model('ration_glj');
+//let std_ration_lib_glj_list_model = require('../../ration_repository/models/glj_repository');
+let std_ration_lib_glj_list_model = mongoose.model('std_ration_lib_glj_list');
+let async = require("async");
+let ration = mongoose.model('ration');
+
+let operationMap={
+    'ut_create':create_ration_glj,
+    'ut_update':update_ration_glj,
+    'ut_delete':delete_ration_glj
+}
+
+
+module.exports={
+    save:save,
+    getData:getData,
+    deleteByRation:deleteByRation
+}
+
+function get_lib_glj_info(ration_glj) {
+    return function (cb) {
+        std_ration_lib_glj_list_model.findOne({'ID':ration_glj.GLJID},(err,glj)=>{
+            if(err){
+                cb(err,'')
+            }else {
+                ration_glj.name = glj.name;
+                ration_glj.code = glj.code;
+                ration_glj.unit = glj.unit;
+                ration_glj.specs = glj.specs;
+                ration_glj.basePrice = glj.basePrice;
+                ration_glj.gljDistType = glj.gljDistType;
+                cb(null,ration_glj)
+            }
+        })
+    }
+}
+
+function create_ration_glj(user_id,datas) {
+    return function (callback) {
+        let ration_glj_list=datas.ration_glj_list;
+        var tasks=[];
+        for(let i =0;i<ration_glj_list.length;i++){
+            ration_glj_list[i].ID = uuidV1();
+            tasks.push(get_lib_glj_info(ration_glj_list[i]))
+        }
+        async.parallel(tasks,(err,results)=>{
+            if(err){
+                callback(err,results)
+            }else {
+                ration_glj.insertMany(results,(err,doc)=>{
+                    if(err){
+                        callback(err,null);
+                    }else {
+                        let returndata ={
+                            updateTpye:commonConsts.UT_CREATE,
+                            moduleName:'ration_glj',
+                            data:results
+                        }
+                        callback(null,returndata)
+                    }
+                });
+            }
+        })
+    }
+
+}
+
+function update_ration_glj(user_id,datas) {
+    return function (callback) {
+        ration_glj.update(datas.query,datas.doc,(err,result)=>{
+            if(err){
+                callback(err,'');
+            }else {
+                let returndata ={
+                    moduleName:'ration_glj',
+                    data:{
+                        updateTpye:commonConsts.UT_UPDATE,
+                        query:datas.query,
+                        doc:datas.doc
+                    }
+                }
+                callback(null,returndata)
+            }
+
+        })
+    }
+}
+
+function delete_ration_glj(user_id,datas) {
+    return function (callback) {
+        if(datas.deleteType=="RATION"){
+            deleteByRation(datas,callback);
+        }else if(datas.deleteType=="BILL"){
+            deleteByBill(user_id,datas,callback);
+        } else{
+            deleteByID(datas,callback);
+        }
+    }
+}
+
+function deleteByRation(datas,callback) {
+    let data = datas.updateData;
+    ration_glj.deleteMany({projectID: data.projectID, rationID: data.ID},callback);
+}
+
+function deleteByBill(user_id,datas,callback) {
+    let tasks = [];
+    tasks.push(startingTask("deleteByBill"));
+    tasks.push(getRationsByBill(datas));
+    tasks.push(deleteRationsbyBill(user_id,datas));
+    tasks.push(deleteByMultiRations(datas));
+    async.waterfall(tasks,function (err,results) {
+        if(err){
+            callback(err,'');
+        }else {
+            callback(null,results);
+        }
+    })
+}
+
+
+function  deleteByID(datas,callback){
+    ration_glj.deleteOne(datas.query,(err,result)=>{
+        if(err){
+            callback(err,'');
+        }else {
+            let returndata ={
+                moduleName:'ration_glj',
+                data:{
+                    updateTpye:commonConsts.UT_DELETE,
+                    query:datas.query,
+                }
+            }
+            callback(null,returndata)
+        }
+    })
+}
+
+function startingTask(processName){
+    return function(asyncCallBack){
+        var result = {
+            processName : processName
+        };
+        asyncCallBack(null, result);
+    };
+}
+
+function  getRationsByBill(datas) {
+    return function (results,callback) {
+        ration.find({projectID:datas.updateData.projectID,billsItemID:datas.updateData.ID},function (err,rations) {
+            if(err){
+                callback(err,'')
+            }else {
+                results.rations=rations;
+                callback(null,results)
+            }
+        })
+    }
+}
+
+function deleteRationsbyBill (user_id,datas){
+    return function (results,callback) {
+       let deleteInfo ={
+            deleteInfo :{deleted: true, deleteDateTime: new Date(), deleteBy: user_id}
+        };
+        ration.update({projectID: datas.updateData.projectID, billsItemID:datas.updateData.ID},deleteInfo,{multi: true},(err,deleteresults)=>{
+            if(err){
+                callback(err,'');
+            }else {
+                callback(null,results);
+            }
+        });
+    }
+}
+
+
+function deleteByMultiRations(datas) {
+    return function (results,deleteCallBack) {
+        var delete_tasks = [];
+        var deleteOne=function (ration) {
+            return function (callback) {
+                ration_glj.deleteMany({projectID: ration.projectID, rationID: ration.ID},function (err,result) {
+                    if(err){
+                        callback(err,'');
+                    }else {
+                        callback(null,result);
+                    }
+                });
+            }
+        }
+        let rations = results.rations;
+        for(let i=0;i<rations.length;i++){
+            delete_tasks.push(deleteOne(rations[i]._doc));
+        }
+        async.parallel(delete_tasks,(err,results)=>{
+            if (err){
+                deleteCallBack(err,'')
+            }else {
+                deleteCallBack(null,results)
+            }
+        })
+    }
+}
+
+
+/*
+function  deleteByRation(doc) {
+    return function (callback){
+        ration_glj.deleteMany({projectID: doc.updateData.projectID, rationID: doc.updateData.ID},callback);
+    }
+}
+*/
+
+function save (user_id, datas, callback) {
+    let perations=[];
+    if(_.isArray(datas)){
+        for(let i=0;i<datas.length;i++){
+            perations.push(operationMap[datas[i].updateType](user_id,datas[i]));
+        }
+    }else {
+        perations.push(operationMap[datas.updateType](user_id,datas));
+    }
+    async.parallel(perations,function (err,results) {
+        if(err){
+            callback(err,'');
+        }else {
+            if(results.length==1){
+                callback(null,results[0])
+            }else {
+                callback(null,results)
+            }
+        }
+    })
+}
+
+function getData(projectID, callback) {
+    console.log("ration_glj getData function");
+    ration_glj.find({'projectID':projectID},(err,datas)=>{
+        if(err){
+            callback(1, '', null);
+        }else {
+            callback(0, consts.projectConst.RATION_GLJ, datas);
+        }
+    })
+
+
+}

+ 4 - 6
modules/ration_glj/models/ration_glj.js

@@ -4,13 +4,11 @@
 var mongoose = require('mongoose'),
 var mongoose = require('mongoose'),
     Schema = mongoose.Schema;
     Schema = mongoose.Schema;
 
 
-/**
- * Schema
- */
 var ration_glj = new Schema({
 var ration_glj = new Schema({
-    ID: String,
+    ID:{ type:String,unique:true},
     GLJID:Number,
     GLJID:Number,
     projectID: Number,
     projectID: Number,
+    rationID:Number,
     name:String,
     name:String,
     code:String,
     code:String,
     specs:String,
     specs:String,
@@ -25,6 +23,6 @@ var ration_glj = new Schema({
     adjustPrice:Number,
     adjustPrice:Number,
     marketPriceAdjest:Number,
     marketPriceAdjest:Number,
     isEstimate:Boolean
     isEstimate:Boolean
-});
+},{versionKey:false});
 
 
-mongoose.model('ration_glj', ration_glj);
+mongoose.model('ration_glj', ration_glj);

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

@@ -0,0 +1,49 @@
+/**
+ * Created by chen on 2017/6/29.
+ */
+let subSchema = require("../../main/models/bills_sub_schemas");
+let deleteSchema = require('../../../public/models/delete_schema');
+
+var mongoose = require('mongoose'),
+    Schema = mongoose.Schema;
+//下面是临时代码,以后删除
+
+var gljSchema =new Schema({
+    repositoryId: Number,
+    ID:Number,
+    //以下是基于已有access库
+    code: String,
+    name: String,
+    specs: String,
+    unit: String,
+    basePrice: Number,
+    gljType: Number, //这个是UI显示上的详细分类,对应gljTypeSchema
+    gljDistType: String  //人工,材料,机械
+},{versionKey:false});
+
+mongoose.model("std_ration_lib_glj_list",gljSchema,"std_ration_lib_glj_list");
+
+let rationSchema = new Schema({
+    ID: Number,
+    projectID: Number,
+    billsItemID: Number,
+    serialNo: Number,
+    libID: Number,
+    code: String,
+    name: String,
+    maskName: String,
+    unit: String,
+    quantity: String, // Decimal
+    programID: Number,
+    adjustState: String,
+    content: String,
+    rationProjName: String,
+    comments: String,
+    // 费用字段
+    fees: [subSchema.feesSchema],
+    // 标记字段
+    flags: [subSchema.flagsSchema],
+    deleteInfo: deleteSchema
+});
+
+mongoose.model("ration", rationSchema, "ration");

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

@@ -31,7 +31,7 @@ var gljSchema = mongoose.Schema({
     gljDistType: String  //人工,材料,机械
     gljDistType: String  //人工,材料,机械
 });
 });
 var gljTypeModel = db.model("std_ration_lib_glj_type",gljTypeSchema, "std_ration_lib_glj_type");
 var gljTypeModel = db.model("std_ration_lib_glj_type",gljTypeSchema, "std_ration_lib_glj_type");
-var gljItemModel = db.model("std_ration_lib_glj_list",gljSchema, "std_ration_lib_glj_list");
+var gljItemModel = mongoose.model("std_ration_lib_glj_list");
 var repositoryMap = require('./repository_map');
 var repositoryMap = require('./repository_map');
 var counter = require('../../../public/counter/counter');
 var counter = require('../../../public/counter/counter');
 
 

+ 4 - 4
modules/users/controllers/boot_controller.js

@@ -5,9 +5,10 @@
  * @date 2017/6/12
  * @date 2017/6/12
  * @version
  * @version
  */
  */
-let UserModel = require("../models/user_model");
+import UserModel from "../models/user_model";
+import BaseController from "../../common/base/base_controller";
 
 
-class BootController {
+class BootController extends BaseController {
 
 
     /**
     /**
      * 引导页
      * 引导页
@@ -28,5 +29,4 @@ class BootController {
     }
     }
 
 
 }
 }
-
-module.exports = BootController;
+export default BootController;

+ 6 - 3
modules/users/controllers/login_controller.js

@@ -5,8 +5,7 @@
  * @date 2017/6/8
  * @date 2017/6/8
  * @version
  * @version
  */
  */
-let Request = require('request');
-let UserModel = require("../models/user_model");
+import UserModel from "../models/user_model";
 
 
 class LoginController {
 class LoginController {
 
 
@@ -18,6 +17,10 @@ class LoginController {
      * @return {void}
      * @return {void}
      */
      */
     index(request, response) {
     index(request, response) {
+        let sessionUser = request.session.sessionUser;
+        if (sessionUser !== undefined && sessionUser.ssoId >= 0) {
+            return response.redirect("/pm");
+        }
         response.render('users/html/login', {});
         response.render('users/html/login', {});
     }
     }
 
 
@@ -72,4 +75,4 @@ class LoginController {
 
 
 }
 }
 
 
-module.exports = LoginController;
+export default LoginController;

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

@@ -6,8 +6,9 @@
  * @version
  * @version
  */
  */
 import UserModel from "../models/user_model";
 import UserModel from "../models/user_model";
+import BaseController from "../../common/base/base_controller";
 
 
-class UserController {
+class UserController extends BaseController {
 
 
     /**
     /**
      * 用户信息页面
      * 用户信息页面
@@ -53,6 +54,7 @@ class UserController {
             // 切换验证场景
             // 切换验证场景
             let userModel = new UserModel();
             let userModel = new UserModel();
             let condition = {email: sessionUser.email};
             let condition = {email: sessionUser.email};
+            userModel.setScene('saveInfo');
             let result = await userModel.updateUser(condition, updateData);
             let result = await userModel.updateUser(condition, updateData);
 
 
             if (result.ok !== 1) {
             if (result.ok !== 1) {

+ 29 - 0
modules/users/models/schema/user.js

@@ -0,0 +1,29 @@
+/**
+ * 用户数据结构
+ *
+ * @author CaiAoLin
+ * @date 2017/6/28
+ * @version
+ */
+let mongoose = require("mongoose");
+let Schema = mongoose.Schema;
+
+// 表名
+let collectionName = 'user';
+
+// 表结构
+let schema = {
+    username: String,
+    email: String,
+    mobile: String,
+    real_name: String,
+    company: String,
+    province: String,
+    area: Number,
+    company_type: Number,
+    company_scale: Number,
+    last_login: Number,
+    create_time: Number
+};
+
+export default mongoose.model(collectionName, new Schema(schema, {versionKey: false}));

+ 41 - 95
modules/users/models/user_model.js

@@ -1,66 +1,15 @@
 /**
 /**
- * 用户数据模型
+ * 用户业务模型
  *
  *
  * @author CaiAoLin
  * @author CaiAoLin
  * @date 2017/6/9
  * @date 2017/6/9
  * @version
  * @version
  */
  */
-let mongoose = require("mongoose");
-let dbm = require("../../../config/db/db_manager");
-let Request = require("request");
+import userSchema from "./schema/user";
+import Request from "request";
+import BaseModel from "../../common/base/base_model"
 
 
-class UserModel {
-
-    /**
-     * 模型
-     *
-     * @var {object}
-     */
-    model = null;
-
-    /**
-     * 默认结构
-     *
-     * @var {object}
-     */
-    defaultSchema = {
-        username: {
-            type: String,
-        },
-        email: {
-            type: String,
-        },
-        mobile: {
-            type: String,
-        },
-        real_name: {
-            type: String,
-        },
-        company: {
-            type: String,
-        },
-        province: {
-            type: String,
-        },
-        area: {
-            type: Number,
-        },
-        company_type: Number,
-        company_scale: Number,
-        last_login: Number,
-        create_time: Number
-    };
-
-    /**
-     * 构造函数
-     *
-     * @return {void}
-     */
-    constructor() {
-        let umDB = dbm.getCfgConnection('scConstruct');
-        let usersSchema = new mongoose.Schema(this.defaultSchema);
-        this.model = umDB.model('users', usersSchema);
-    }
+class UserModel extends BaseModel {
 
 
     /**
     /**
      * 企业所在地区
      * 企业所在地区
@@ -83,6 +32,18 @@ class UserModel {
      */
      */
     companyScale = ['1-20', '20-50', '50-100', '100+'];
     companyScale = ['1-20', '20-50', '50-100', '100+'];
 
 
+
+    /**
+     * 构造函数
+     *
+     * @return {void}
+     */
+    constructor() {
+        let parent = super();
+        parent.model = userSchema;
+        parent.init();
+    }
+
     /**
     /**
      * 根据用户名密码调用SSO接口获取信息
      * 根据用户名密码调用SSO接口获取信息
      *
      *
@@ -123,6 +84,7 @@ class UserModel {
     async markUser(userData) {
     async markUser(userData) {
         let userDataFromDb = await this.findDataByName(userData.username);
         let userDataFromDb = await this.findDataByName(userData.username);
         let result = false;
         let result = false;
+
         // 信息是否补全
         // 信息是否补全
         let info = false;
         let info = false;
         if (userDataFromDb.length <= 0) {
         if (userDataFromDb.length <= 0) {
@@ -143,30 +105,36 @@ class UserModel {
     }
     }
 
 
     /**
     /**
+     * 选择场景
+     *
+     * @param {string} scene
+     */
+    setScene(scene = '') {
+        switch (scene) {
+            case 'saveInfo':
+                this.db.model.schema.path('real_name').required(true);
+                this.db.model.schema.path('company').required(true);
+                this.db.model.schema.path('province').required(true);
+                this.db.model.schema.path('area').required(true);
+                break;
+        }
+    }
+
+    /**
      * 根据用户名查找数据
      * 根据用户名查找数据
      *
      *
      * @param {string} username
      * @param {string} username
      * @return {object}
      * @return {object}
      */
      */
     findDataByName(username) {
     findDataByName(username) {
-        let self = this;
-        return new Promise(function (resolve, reject) {
-            self.model.find({username: username}, function (error, data) {
-                if (error) {
-                    console.log(error);
-                    reject([]);
-                } else {
-                    resolve(data);
-                }
-            });
-        });
+        return this.db.model.find({username: username});
     }
     }
 
 
     /**
     /**
      * 新增用户
      * 新增用户
      *
      *
      * @param {object} userData
      * @param {object} userData
-     * @return {Promise}
+     * @return {Promise|boolean}
      */
      */
     addUser(userData) {
     addUser(userData) {
         let insertData = {
         let insertData = {
@@ -179,19 +147,10 @@ class UserModel {
             company_type: -1,
             company_type: -1,
             company_scale: -1,
             company_scale: -1,
             last_login: 0,
             last_login: 0,
-            create_time: new Date().getTime()
+            create_time: new Date().getTime(),
+            area: 0
         };
         };
-        let userModel = new this.model(insertData);
-        return new Promise(function (resolve, reject) {
-            userModel.save(function (error) {
-                if (error) {
-                    console.log(error);
-                    reject(false);
-                } else {
-                    resolve(true);
-                }
-            });
-        });
+        return this.db.create(insertData);
     }
     }
 
 
     /**
     /**
@@ -204,22 +163,9 @@ class UserModel {
         if (Object.keys(condition).length <= 0 || Object.keys(updateData).length <= 0) {
         if (Object.keys(condition).length <= 0 || Object.keys(updateData).length <= 0) {
             return null;
             return null;
         }
         }
-        let userModel = new this.model();
-        return new Promise(function(resolve, reject) {
-            // let validationError = userModel.validateSync();
-            // if (validationError) {
-            //     reject(validationError);
-            // }
-            userModel.update(condition, {$set: updateData}, function(error, result) {
-                if (error) {
-                    reject(error);
-                } else {
-                    resolve(result);
-                }
-            });
-        });
+        return this.db.update(condition, updateData);
     }
     }
 
 
 }
 }
 
 
-module.exports = UserModel;
+export default UserModel;

+ 2 - 3
modules/users/routes/boot_route.js

@@ -5,11 +5,10 @@
  * @date 2017/6/12
  * @date 2017/6/12
  * @version
  * @version
  */
  */
+import express from "express";
+import BootController from "../controllers/boot_controller";
 
 
-let express = require('express');
 let router = express.Router();
 let router = express.Router();
-let BootController = require('../controllers/boot_controller');
-
 let bootController = new BootController();
 let bootController = new BootController();
 
 
 // 引导页面
 // 引导页面

+ 4 - 2
modules/users/routes/login_route.js

@@ -5,13 +5,15 @@
  * @date 2017/6/1
  * @date 2017/6/1
  * @version
  * @version
  */
  */
-let express = require('express');
+import express from "express";
+import LoginController from "../controllers/login_controller";
+
 let router = express.Router();
 let router = express.Router();
-let LoginController = require('../controllers/login_controller');
 let loginController = new LoginController();
 let loginController = new LoginController();
 
 
 // 登录页面action
 // 登录页面action
 router.get('/login', loginController.index);
 router.get('/login', loginController.index);
+router.get('/', loginController.index);
 
 
 // 登录操作
 // 登录操作
 router.post('/login', loginController.login);
 router.post('/login', loginController.login);

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

@@ -2,6 +2,33 @@
  * Created by Tony on 2017/4/28.
  * Created by Tony on 2017/4/28.
  */
  */
 var sheetCommonObj = {
 var sheetCommonObj = {
+    // CSL.2017.06.05
+    // createSpread、initSheet 在一个Spread多个Sheet分别调用时的情况下使用。
+    // buildSheet 在一个Spread、一个Sheet的情况下使用。
+    createSpread: function(container, SheetCount){
+        var me = this;
+        var spreadBook = new GC.Spread.Sheets.Workbook(container, { sheetCount: SheetCount });
+        spreadBook.options.tabStripVisible = false;
+        spreadBook.options.showHorizontalScrollbar = false;
+        return spreadBook;
+    },
+
+    initSheet: function(sheet, setting, rowCount) {
+        var me = this;
+        var spreadNS = GC.Spread.Sheets;
+        sheet.suspendPaint();
+        sheet.suspendEvent();
+        sheet.setRowCount(1, spreadNS.SheetArea.colHeader);
+        sheet.setColumnCount(setting.header.length, spreadNS.SheetArea.viewport);
+        sheet.options.colHeaderAutoTextIndex = 1;
+        sheet.options.colHeaderAutoText = spreadNS.HeaderAutoText.numbers;
+        sheet.showRowOutline(false);
+        me.buildHeader(sheet, setting);
+        if (rowCount > 0) sheet.setRowCount(rowCount);
+        sheet.resumeEvent();
+        sheet.resumePaint();
+    },
+
     buildSheet: function(container, setting, rowCount) {
     buildSheet: function(container, setting, rowCount) {
         var me = this;
         var me = this;
         var spreadBook = new GC.Spread.Sheets.Workbook(container, { sheetCount: 1 });
         var spreadBook = new GC.Spread.Sheets.Workbook(container, { sheetCount: 1 });
@@ -65,6 +92,7 @@ var sheetCommonObj = {
         var me = this, ch = GC.Spread.Sheets.SheetArea.viewport;
         var me = this, ch = GC.Spread.Sheets.SheetArea.viewport;
         sheet.suspendPaint();
         sheet.suspendPaint();
         sheet.suspendEvent();
         sheet.suspendEvent();
+        sheet.clear(0, 0, sheet.getRowCount(), sheet.getColumnCount(), GC.Spread.Sheets.SheetArea.viewport, GC.Spread.Sheets.StorageType.data);
         for (var col = 0; col < setting.header.length; col++) {
         for (var col = 0; col < setting.header.length; col++) {
             var hAlign = "left", vAlign = "center";
             var hAlign = "left", vAlign = "center";
             if (setting.header[col].hAlign) {
             if (setting.header[col].hAlign) {

+ 6 - 3
server.js

@@ -13,7 +13,7 @@ let path = require('path');
 let session = require('express-session');
 let session = require('express-session');
 let DBStore = require('connect-mongo')(session);
 let DBStore = require('connect-mongo')(session);
 
 
-let URL = require('url')
+let URL = require('url');
 
 
 dbm.connect();
 dbm.connect();
 //这里现在只引入了定额工料机里的models,当其它模块的models修改后使用:./modules/**/models/*.js引入所有的模块
 //这里现在只引入了定额工料机里的models,当其它模块的models修改后使用:./modules/**/models/*.js引入所有的模块
@@ -76,6 +76,9 @@ app.use('/', require("./modules/users/routes/login_route"));
 app.use('/boot', require("./modules/users/routes/boot_route"));
 app.use('/boot', require("./modules/users/routes/boot_route"));
 app.use('/user', require("./modules/users/routes/user_route"));
 app.use('/user', require("./modules/users/routes/user_route"));
 
 
+// 项目工料机相关
+app.use('/glj', require("./modules/glj/routes/glj_router"));
+
 app.use('/feeRates', require('./modules/fee_rates/routes/fee_rates_route'));
 app.use('/feeRates', require('./modules/fee_rates/routes/fee_rates_route'));
 
 
 app.get('/template/bills', function (req, res) {
 app.get('/template/bills', function (req, res) {
@@ -134,7 +137,7 @@ let GLJ_Router = require('./modules/main/routes/GLJ_route');
 app.use('/project', project_Router);
 app.use('/project', project_Router);
 app.use('/bills', bills_Router);
 app.use('/bills', bills_Router);
 app.use('/ration', ration_Router);
 app.use('/ration', ration_Router);
-app.use('/glj', GLJ_Router);
+app.use('/glj_bak', GLJ_Router);
 
 
 //app.use(express.static(_rootDir+"/web"));
 //app.use(express.static(_rootDir+"/web"));
 //app.use(express.static(_rootDir+"/lib"));
 //app.use(express.static(_rootDir+"/lib"));
@@ -174,7 +177,7 @@ app.use("/report_tpl_api", rptTpl_Router);
 //-----------------
 //-----------------
 
 
 app.use(function(req, res, next) {
 app.use(function(req, res, next) {
-	res.status(404).send('404 Error');
+    res.status(404).send('404 Error');
 });
 });
 app.use(function(err, req, res, next) {
 app.use(function(err, req, res, next) {
     console.error(err.stack);
     console.error(err.stack);

+ 17 - 40
web/building_saas/main/html/main.html

@@ -129,63 +129,35 @@
                           <div class="bottom-content">
                           <div class="bottom-content">
                               <ul class="nav nav-tabs" role="tablist">
                               <ul class="nav nav-tabs" role="tablist">
                                   <li class="nav-item">
                                   <li class="nav-item">
-                                      <a class="nav-link active" data-toggle="tab" href="#gl" role="tab">工料机</a>
+                                      <a class="nav-link active" id="linkGLJ" data-toggle="tab" href="#subSpread" role="tab">工料机</a>
                                   </li>
                                   </li>
                                   <li class="nav-item">
                                   <li class="nav-item">
-                                      <a class="nav-link" data-toggle="tab" href="#fzt" role="tab">附注条件</a>
+                                      <a class="nav-link" id="linkFZTJ" data-toggle="tab" href="#subSpread" role="tab">附注条件</a>
                                   </li>
                                   </li>
                                   <li class="nav-item">
                                   <li class="nav-item">
-                                      <a class="nav-link" data-toggle="tab" href="#fzd" role="tab">辅助定额</a>
+                                      <a class="nav-link" id="linkFZDE" data-toggle="tab" href="#subSpread" role="tab">辅助定额</a>
                                   </li>
                                   </li>
                                   <li class="nav-item">
                                   <li class="nav-item">
-                                      <a class="nav-link" data-toggle="tab" href="#gc" role="tab">工程量明细</a>
+                                      <a class="nav-link" id="linkGCLMX" data-toggle="tab" href="#subSpread" role="tab">工程量明细</a>
                                   </li>
                                   </li>
                                   <li class="nav-item">
                                   <li class="nav-item">
-                                      <a class="nav-link" data-toggle="tab" href="#dj" role="tab">单价构成</a>
+                                      <a class="nav-link" id="linkJSCX" data-toggle="tab" href="#subSpread" role="tab">计算程序</a>
                                   </li>
                                   </li>
                                   <li class="nav-item">
                                   <li class="nav-item">
-                                      <a class="nav-link" data-toggle="tab" href="#fx" role="tab">分项说明</a>
+                                      <a class="nav-link" id="linkFXSM" data-toggle="tab" href="#subSpread" role="tab">分项说明</a>
                                   </li>
                                   </li>
                                   <li class="nav-item">
                                   <li class="nav-item">
-                                      <a class="nav-link" data-toggle="tab" href="#des" role="tab">定额说明</a>
+                                      <a class="nav-link" id="linkDESM" data-toggle="tab" href="#subSpread" role="tab">定额说明</a>
                                   </li>
                                   </li>
                               </ul>
                               </ul>
                               <!-- Tab panes -->
                               <!-- Tab panes -->
                               <div class="tab-content">
                               <div class="tab-content">
                                   <div class="tab-pane active" id="gl" role="tabpanel">
                                   <div class="tab-pane active" id="gl" role="tabpanel">
-                                      <div class="main-data-bottom ovf-hidden" id="gljSpread">
-                                      </div>
-                                  </div>
-                                  <div class="tab-pane" id="fzt" role="tabpanel">
-                                      <div class="warp-p2">
-                                          附注条件的内容
-                                      </div>
-                                  </div>
-                                  <div class="tab-pane" id="fzd" role="tabpanel">
-                                      <div class="warp-p2">
-                                          辅助定额的内容
-                                      </div>
-                                  </div>
-                                  <div class="tab-pane" id="gc" role="tabpanel">
-                                      <div class="warp-p2">
-                                          工程量明细的内容
-                                      </div>
-                                  </div>
-                                  <div class="tab-pane" id="dj" role="tabpanel">
-                                      <div class="warp-p2">
-                                          单价构成的内容
-                                      </div>
-                                  </div>
-                                  <div class="tab-pane" id="fx" role="tabpanel">
-                                      <div class="warp-p2">
-                                          分项说明的内容
-                                      </div>
-                                  </div>
-                                  <div class="tab-pane" id="des" role="tabpanel">
-                                      <div class="warp-p2">
-                                          定额说明的内容
+                                      <div class="main-data-bottom ovf-hidden" id="subSpread">
                                       </div>
                                       </div>
                                   </div>
                                   </div>
+
+                                  
                               </div>
                               </div>
                           </div>
                           </div>
                       </div>
                       </div>
@@ -490,12 +462,14 @@
 
 
     <script src="/lib/tether/tether.min.js"></script>
     <script src="/lib/tether/tether.min.js"></script>
     <script src="/lib/bootstrap/bootstrap.min.js"></script>
     <script src="/lib/bootstrap/bootstrap.min.js"></script>
-    <script type="text/javascript" src="/lib/bootstrap/bootstrap-select.min.js"></script>
+    <!--<script type="text/javascript" src="/lib/bootstrap/bootstrap-select.min.js"></script>-->
     <script type="text/javascript" src="/lib/jquery-contextmenu/jquery.contextMenu.js"></script>
     <script type="text/javascript" src="/lib/jquery-contextmenu/jquery.contextMenu.js"></script>
     <script type="text/javascript" src="/lib/jquery-contextmenu/jquery.ui.position.js"></script>
     <script type="text/javascript" src="/lib/jquery-contextmenu/jquery.ui.position.js"></script>
+    <script type="text/javascript" src="/lib/lodash/lodash.js"></script>
     <!-- Common -->
     <!-- Common -->
     <script type="text/javascript" src="/public/web/common_ajax.js"></script>
     <script type="text/javascript" src="/public/web/common_ajax.js"></script>
     <script type="text/javascript" src="/public/web/url_util.js"></script>
     <script type="text/javascript" src="/public/web/url_util.js"></script>
+    <script type="text/javascript" src="/public/web/sheet/sheet_common.js"></script>
     <!--报表 zTree -->
     <!--报表 zTree -->
     <script type="text/javascript" src="/lib/ztree/jquery.ztree.core.js"></script>
     <script type="text/javascript" src="/lib/ztree/jquery.ztree.core.js"></script>
     <script type="text/javascript" src="/lib/ztree/jquery.ztree.excheck.js"></script>
     <script type="text/javascript" src="/lib/ztree/jquery.ztree.excheck.js"></script>
@@ -509,6 +483,7 @@
     <script type="text/javascript" src="/web/building_saas/main/js/models/ration.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/models/ration.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/models/glj.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/models/glj.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/models/fee_rate.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/models/fee_rate.js"></script>
+    <script type="text/javascript" src="/web/building_saas/main/js/models/ration_glj.js"></script>
 
 
     <script type="text/javascript" src="/public/web/id_tree.js"></script>
     <script type="text/javascript" src="/public/web/id_tree.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/models/cache_tree.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/models/cache_tree.js"></script>
@@ -533,6 +508,8 @@
     <script type="text/javascript" src="/public/web/rpt_tpl_def.js"></script>
     <script type="text/javascript" src="/public/web/rpt_tpl_def.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/rpt/rpt_main.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/rpt/rpt_main.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/rpt/rpt_cfg_const.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/rpt/rpt_cfg_const.js"></script>
+    <script type="text/javascript" src="/web/building_saas/main/js/views/glj_view.js"></script>
+    <script type="text/javascript" src="/web/building_saas/main/js/views/sub_view.js"></script>
 
 
     <SCRIPT type="text/javascript">
     <SCRIPT type="text/javascript">
   		<!--
   		<!--
@@ -584,6 +561,6 @@
   		});
   		});
   		//-->
   		//-->
   	</SCRIPT>
   	</SCRIPT>
-    <script type="text/javascript" src="/web/building_saas/main/js/views/gljView.js"></script>
+
 </body>
 </body>
 </html>
 </html>

+ 5 - 1
web/building_saas/main/js/controllers/project_controller.js

@@ -40,10 +40,13 @@ ProjectController = {
 
 
         var selected = project.mainTree.selected;
         var selected = project.mainTree.selected;
         var newSource = null, newNode = null;
         var newSource = null, newNode = null;
-
+        if(selected==null){
+            return;
+        }
         if (selected.sourceType === project.Bills.getSourceType() && selected.source.children.length === 0) {
         if (selected.sourceType === project.Bills.getSourceType() && selected.source.children.length === 0) {
             if (std) {
             if (std) {
                 newSource = project.Ration.insertStdRation(selected.source.getID(), null, std);
                 newSource = project.Ration.insertStdRation(selected.source.getID(), null, std);
+                project.ration_glj.addRationGLJ(newSource,std);
             } else {
             } else {
                 newSource = project.Ration.insertRation(selected.source.getID());
                 newSource = project.Ration.insertRation(selected.source.getID());
             }
             }
@@ -51,6 +54,7 @@ ProjectController = {
         } else if (selected.sourceType === project.Ration.getSourceType()) {
         } else if (selected.sourceType === project.Ration.getSourceType()) {
             if (std) {
             if (std) {
                 newSource = project.Ration.insertStdRation(selected.source[project.masterField.ration], selected.source, std);
                 newSource = project.Ration.insertStdRation(selected.source[project.masterField.ration], selected.source, std);
+                project.ration_glj.addRationGLJ(newSource,std);
             } else {
             } else {
                 newSource = project.Ration.insertRation(selected.source[project.masterField.ration], selected.source);
                 newSource = project.Ration.insertRation(selected.source[project.masterField.ration], selected.source);
             }
             }

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

@@ -141,11 +141,17 @@ var Bills = {
         };
         };
         bills.prototype.deleteBills = function (node) {
         bills.prototype.deleteBills = function (node) {
             var deleteData = this.tree.getDeleteData(node);
             var deleteData = this.tree.getDeleteData(node);
-            project.beginUpdate('deleteBills');
-            project.push(ModuleNames.bills, tools.coverseTreeUpdateData(deleteData, this.project.ID()));
-            project.endUpdate();
+            var ration_glj =projectObj.project.ration_glj;
+          //  project.beginUpdate('deleteBills');
+            //project.push(ModuleNames.bills, tools.coverseTreeUpdateData(deleteData, this.project.ID()));
+            //project.endUpdate();
+            var moudles =[ModuleNames.bills,ModuleNames.ration_glj];
+            var deleteDatas=[tools.coverseTreeUpdateData(deleteData, this.project.ID()),ration_glj.getDeleteDataByBills(deleteData)];
+           // project.ration.getDeleteDataByBill(node);
+            project.pushNow('deleteBILL', moudles, deleteDatas);
 
 
-            return this.tree.delete(node);
+
+           // return this.tree.delete(node);
         };
         };
         bills.prototype.upMoveBills = function (node) {
         bills.prototype.upMoveBills = function (node) {
             var upMoveData = node.getUpMoveData();
             var upMoveData = node.getUpMoveData();

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

@@ -6,5 +6,6 @@ const ModuleNames = {
     ration: 'ration',
     ration: 'ration',
     GLJ: 'GLJ',
     GLJ: 'GLJ',
     feeRate: 'feeRate',
     feeRate: 'feeRate',
-    projectGLJ: 'projectGLJ'
+    projectGLJ: 'projectGLJ',
+    ration_glj:'ration_glj'
 };
 };

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

@@ -58,6 +58,7 @@ var PROJECT = {
             this.Bills = Bills.createNew(this);
             this.Bills = Bills.createNew(this);
             this.Ration = Ration.createNew(this);
             this.Ration = Ration.createNew(this);
             this.GLJ = GLJ.createNew(this);
             this.GLJ = GLJ.createNew(this);
+            this.ration_glj = ration_glj.createNew(this)
             this.FeeRate = FeeRate.createNew(this);
             this.FeeRate = FeeRate.createNew(this);
 
 
             this.masterField = {ration: 'billsItemID'};
             this.masterField = {ration: 'billsItemID'};

+ 6 - 1
web/building_saas/main/js/models/ration.js

@@ -148,8 +148,13 @@ var Ration = {
             updateData.push({'updateType': 'ut_delete', 'updateData': {'ID': rationData.ID, 'projectID': this.project.ID()}});
             updateData.push({'updateType': 'ut_delete', 'updateData': {'ID': rationData.ID, 'projectID': this.project.ID()}});
             return updateData;
             return updateData;
         };
         };
+        ration.prototype.getDeleteDataByBill = function (node) {
+            console.log(node);
+        };
+
         ration.prototype.delete = function (ration) {
         ration.prototype.delete = function (ration) {
-            this.project.pushNow('deleteRation', [this.getSourceType()], [this.getDeleteData(ration)]);
+            var ration_glj =projectObj.project.ration_glj;
+            this.project.pushNow('deleteRation', [this.getSourceType(),ration_glj.getSourceType()], [this.getDeleteData(ration),ration_glj.getDeleteDataByRation(ration)]);
 
 
             this.datas.splice(this.datas.indexOf(ration), 1);
             this.datas.splice(this.datas.indexOf(ration), 1);
         };
         };

+ 172 - 0
web/building_saas/main/js/models/ration_glj.js

@@ -0,0 +1,172 @@
+/**
+ * Created by Mai on 2017/4/1.
+ */
+var ration_glj = {
+    createNew: function (project) {
+        // 用户定义private方法
+        var tools = {};
+
+        // 所有通过this访问的属性,都不应在此单元外部进行写入操作
+        var ration_glj = function (proj) {
+            this.gljTree = cacheTree.createNew(this);
+           // this.project = proj;
+            this.datas = [];
+
+            var sourceType = ModuleNames.ration_glj;
+            this.getSourceType = function () {
+                return sourceType;
+            }
+            proj.registerModule(ModuleNames.ration_glj, this);
+        };
+
+        // 从后台获取数据
+        /*glj.prototype.pullData = function (){
+            this.project.pullData(
+                '/glj/getData',
+                {projectID: this.project.ID},
+                function(result){
+                    if (result.error ===0){
+                        this.loadDatas(result.data);
+                    }
+                    else {
+                        // to do: 错误处理需要细化
+                        alert(result.message);
+                    }
+                },
+                function (){}//to do: 错误处理需要细化
+            )
+        };*/
+        // prototype用于定义public方法
+        ration_glj.prototype.loadData = function (datas) {
+            this.datas = datas;
+        };
+
+        // 提交数据后返回数据处理
+        ration_glj.prototype.doAfterUpdate = function(err, data){
+            if(!err){
+                if(data.updateTpye=='ut_update'){
+                    this.refreshAfterUpdate(data);
+                }else if(data.updateTpye=='ut_delete'){
+                    this.refreshAfterDelete(data);
+                } else {
+                    this.refreshAfterSave(data);
+                }
+            }
+        };
+        ration_glj.prototype.refreshAfterSave=function(data){
+            if(projectObj.project.ration_glj.datas&&Array.isArray(projectObj.project.ration_glj.datas)){
+                projectObj.project.ration_glj.datas = projectObj.project.ration_glj.datas.concat(data);
+            }else {
+                projectObj.project.ration_glj.datas = data;
+            }
+            sheetCommonObj.showData(gljOprObj.sheet,gljOprObj.setting,data);
+            // SheetDataHelper.loadSheetData(setting, rationLibObj.sectionRationsSpread.getActiveSheet(), datas);
+        };
+        ration_glj.prototype.refreshAfterUpdate=function(data){
+            var glj_list = projectObj.project.ration_glj.datas;
+            var glj_index= _.findIndex(glj_list,(glj)=>{
+                return glj.ID==data.query.ID&&glj.projectID==data.query.projectID;
+            })
+            glj_list[glj_index].customQuantity=data.doc.customQuantity;
+            glj_list[glj_index].quantity=data.doc.quantity;
+
+            var showList = _.filter(glj_list,{'projectID':data.query.projectID,'rationID':glj_list[glj_index].rationID});
+            gljOprObj.sheetData=showList;
+           sheetCommonObj.showData(gljOprObj.sheet,gljOprObj.setting,showList);
+        };
+        ration_glj.prototype.refreshAfterDelete=function(data){
+            var glj_list = projectObj.project.ration_glj.datas;
+            _.remove(glj_list,data.query);
+            _.remove(gljOprObj.sheetData,data.query);
+            sheetCommonObj.showData(gljOprObj.sheet,gljOprObj.setting,gljOprObj.sheetData);
+        };
+        // CSL,2017.05.09
+        ration_glj.prototype.modifyQuantity = function (data, newQuantity) {
+            this.project.beginUpdate('modifyQuantity');
+            data.quantity = newQuantity;
+            data.customQuantity = newQuantity;
+            data.updateType = 'ut_update';
+            this.project.push(this.getSourceType, data);
+            this.project.endUpdate();
+        };
+
+        ration_glj.prototype.modifyPrice = function (data, newPrice) {
+            this.project.beginUpdate('modifyPrice');
+            data.price = newPrice;
+            data.updateType = 'ut_update';
+            this.project.push(this.getSourceType, data);
+            this.project.endUpdate();
+        };
+
+        ration_glj.prototype.deleteGLJ = function (data) {
+            this.project.beginUpdate('deleteGLJ');
+            data.customQuantity = 0;
+            data.quantity = 0;
+            data.rationItemQuantity = 0;
+            data.updateType = 'ut_update';
+            this.project.push(this.getSourceType, data);
+            this.project.endUpdate();
+        };
+
+        ration_glj.prototype.replaceGLJ = function (data, newGLJID) {
+            this.project.beginUpdate('replaceGLJ');
+            data.GLJID = newGLJID;
+            data.updateType = 'ut_update';
+            this.project.push(this.getSourceType, data);
+            this.project.endUpdate();
+        };
+
+        ration_glj.prototype.addRationGLJ = function (newRation,data) {
+            if(data.hasOwnProperty('rationGljList')&&data.rationGljList.length>0){
+                let criteria= {};
+                criteria.ration_glj_list = [];
+                for(let i=0;i<data.rationGljList.length;i++){
+                    let temdata = data.rationGljList[i];
+                    let newGLJ = {};
+                    newGLJ.projectID = newRation.projectID;
+                    newGLJ.GLJID = temdata.gljId;
+                    newGLJ.rationID = newRation.ID;
+                    newGLJ.rationItemQuantity= temdata.consumeAmt;
+                    newGLJ.quantity=temdata.consumeAmt;
+                    criteria.ration_glj_list.push(newGLJ)
+                }
+                criteria.updateType = 'ut_create';
+                project.pushNow('addRationGLJ',[this.getSourceType()],[criteria]);
+            }
+        };
+        ration_glj.prototype.getDeleteDataByRation=function(rationData){
+            var updateData = [];
+            updateData.push({'deleteType':'RATION','updateType': 'ut_delete', 'updateData': {'ID': rationData.ID, 'projectID': rationData.projectID}});
+            return updateData;
+        };
+        ration_glj.prototype.getDeleteDataByBills=function(datas){
+            var updateData = [];
+            datas.forEach(function (deleteData) {
+                var billData = deleteData.data;
+                updateData.push({'deleteType':'BILL','updateType': 'ut_delete', 'updateData': {'ID': billData.ID, 'projectID': billData.projectID}});
+            })
+            return updateData;
+        };
+        ration_glj.prototype.deleteByRation = function(ration){
+            var glj_list = projectObj.project.ration_glj.datas;
+            var newList =_.filter(glj_list,(glj)=>{
+               return glj.rationID!=ration.ID;
+            });
+            if(newList!=undefined){
+                projectObj.project.ration_glj.datas = newList;
+            }
+        };
+        ration_glj.prototype.updataOrdelete=function(row){
+            var updateData = [];
+            if(row.rationItemQuantity==0){
+                updateData.push({'updateType': 'ut_delete', 'query': {'ID': row.ID, 'projectID': row.projectID}});
+            }else {
+                updateData.push({'updateType': 'ut_update','query': {'ID': row.ID, 'projectID': row.projectID},'doc':{'quantity':0,'customQuantity':0}});
+            }
+            project.pushNow('addRationGLJ',[this.getSourceType()],updateData)
+        }
+
+
+        return new ration_glj(project);
+    }
+};

+ 0 - 117
web/building_saas/main/js/views/gljView.js

@@ -1,117 +0,0 @@
-/**
- * Created by CSL on 2017-05-12.
- */
-
-var gljView = {
-    spreadBook: null,
-    setting: {
-        header: [
-            {headerName: "编码", headerWidth: 60, dataCode: "ID", dataType: "String", formatter: "@"},
-            {headerName: "名称", headerWidth: 80, dataCode: "name", dataType: "String"},
-            {headerName: "规格型号", headerWidth: 80, dataCode: "specs", dataType: "String", hAlign: "center"},
-            {headerName: "单位", headerWidth: 60, dataCode: "unit", dataType: "String", hAlign: "center"},
-            {headerName: "类别", headerWidth: 50, dataCode: "gljType", dataType: "String", hAlign: "center"},
-            {headerName: "定额消耗量", headerWidth: 80, dataCode: "orgRQuantity", dataType: "String", hAlign: "right"},    // dataType: "Number", formatter: "0.00"
-            {headerName: "自定义消耗量", headerWidth: 80, dataCode: "customQuantity", dataType: "String", hAlign: "right"},
-            {headerName: "消耗量", headerWidth: 80, dataCode: "quantity", dataType: "String", hAlign: "right"},
-            {headerName: "数量", headerWidth: 80, dataCode: "rationItemQuantity", dataType: "String", hAlign: "right"},
-            {headerName: "基价单价", headerWidth: 80, dataCode: "rationPrice", dataType: "String", hAlign: "right"},
-            {headerName: "调整基价", headerWidth: 80, dataCode: "adjustPrice", dataType: "String", hAlign: "right"},
-            {headerName: "市场单价", headerWidth: 80, dataCode: "marketPrice", dataType: "String", hAlign: "right"},
-            {headerName: "市场单价调整", headerWidth: 80, dataCode: "price", dataType: "String", hAlign: "right"}
-        ],
-        view: {
-            comboBox: [{row: -1, col: 2, rowCount: -1, colCount: 1}],
-            lockedCells: [{row: -1, col: 3, rowCount: -1, colCount: 1}]
-        }
-    },
-
-    buildSheet: function (container) {
-        var me = this;
-        me.spreadBook = new GC.Spread.Sheets.Workbook(container, { sheetCount: 1 });
-        me.spreadBook.options.tabStripVisible = false;
-        me.spreadBook.options.showHorizontalScrollbar = false;
-
-        var sheet = me.spreadBook.getSheet(0);
-        sheet.suspendPaint();
-        sheet.suspendEvent();
-        var shts = GC.Spread.Sheets;
-        sheet.setRowCount(1, shts.SheetArea.colHeader);
-        sheet.setColumnCount(me.setting.header.length, shts.SheetArea.viewport);
-        sheet.options.colHeaderAutoTextIndex = 1;
-        sheet.options.colHeaderAutoText = shts.HeaderAutoText.numbers;
-        sheet.showRowOutline(false);
-
-        for (var i = 0; i < me.setting.header.length; i++) {
-            sheet.setValue(0, i, me.setting.header[i].headerName, shts.SheetArea.colHeader);
-            sheet.setColumnWidth(i, me.setting.header[i].headerWidth? me.setting.header[i].headerWidth:100);
-        }
-
-        sheet.setRowCount(20);
-        sheet.resumeEvent();
-        sheet.resumePaint();
-
-        return me.spreadBook;
-    },
-
-    showDatas: function(datas) {
-        var me = this;
-        var sheet = me.spreadBook.getSheet(0);
-        sheet.suspendPaint();
-        sheet.suspendEvent();
-        for (var col = 0; col < me.setting.header.length; col++) {
-            var hAlign = "left", vAlign = "center";
-            if (me.setting.header[col].hAlign) {
-                hAlign = me.setting.header[col].hAlign;
-            } else if (me.setting.header[col].dataType !== "String"){
-                hAlign = "right";
-            }
-            vAlign = me.setting.header[col].vAlign?me.setting.header[col].vAlign:vAlign;
-            me.setAreaAlign(sheet.getRange(-1, col, -1, 1), hAlign, vAlign);
-            if (me.setting.header[col].formatter) {
-                sheet.setFormatter(-1, col, me.setting.header[col].formatter, GC.Spread.Sheets.SheetArea.viewport);
-            }
-            for (var row = 0; row < datas.length; row++) {
-                sheet.setValue(row, col, datas[row][me.setting.header[col].dataCode], GC.Spread.Sheets.SheetArea.viewport);
-            }
-        }
-        sheet.resumeEvent();
-        sheet.resumePaint();
-    },
-
-    setAreaAlign: function(area, hAlign, vAlign){
-        if (!(hAlign) || hAlign === "left") {
-            area.hAlign(GC.Spread.Sheets.HorizontalAlign.left);
-        } else if (hAlign === "right") {
-            area.hAlign(GC.Spread.Sheets.HorizontalAlign.right);
-        } else if (hAlign === "center") {
-            area.hAlign(GC.Spread.Sheets.HorizontalAlign.center);
-        } else {
-            area.hAlign(GC.Spread.Sheets.HorizontalAlign.left);
-        }
-        if (!(vAlign) || vAlign === "center") {
-            area.vAlign(GC.Spread.Sheets.VerticalAlign.center);
-        } else if (vAlign === "top") {
-            area.vAlign(GC.Spread.Sheets.VerticalAlign.top);
-        } else if (vAlign === "bottom") {
-            area.vAlign(GC.Spread.Sheets.VerticalAlign.bottom);
-        } else {
-            area.vAlign(GC.Spread.Sheets.VerticalAlign.center);
-        }
-    }
-
-}
-
-function objTest(obj) {
-    var str = "";
-    var spr = "";
-    for (var x in obj) {
-        if (obj.hasOwnProperty(x)) {
-            if(str == ''){ spr = '' } else { spr = ', '};
-            str += spr + x + ':' + obj[x];
-        }
-    }
-    return str;
-}
-
-gljView.buildSheet($("#gljSpread")[0]);

+ 126 - 0
web/building_saas/main/js/views/glj_view.js

@@ -0,0 +1,126 @@
+/**
+ * Created by CSL on 2017-05-12.
+ */
+
+var gljOprObj = {
+    sheet: null,
+    libID: null,
+    ration: null,
+    sheetData:null,
+    setting: {
+        header: [
+            {headerName: "编码", headerWidth: 60, dataCode: "code", dataType: "String", formatter: "@"},
+            {headerName: "名称", headerWidth: 80, dataCode: "name", dataType: "String"},
+            {headerName: "规格型号", headerWidth: 80, dataCode: "specs", dataType: "String", hAlign: "center"},
+            {headerName: "单位", headerWidth: 60, dataCode: "unit", dataType: "String", hAlign: "center"},
+            {headerName: "类别", headerWidth: 50, dataCode: "gljDistType", dataType: "String", hAlign: "center"},
+            {headerName: "定额消耗量", headerWidth: 80, dataCode: "rationItemQuantity", dataType: "String", hAlign: "right"},    // dataType: "Number", formatter: "0.00"
+            {headerName: "自定义消耗量", headerWidth: 80, dataCode: "customQuantity", dataType: "String", hAlign: "right"},
+            {headerName: "消耗量", headerWidth: 80, dataCode: "quantity", dataType: "String", hAlign: "right"},
+            {headerName: "基价单价", headerWidth: 80, dataCode: "basePrice", dataType: "String", hAlign: "right"},
+            {headerName: "调整基价", headerWidth: 80, dataCode: "adjustPrice", dataType: "String", hAlign: "right"},
+            {headerName: "市场单价", headerWidth: 80, dataCode: "marketPrice", dataType: "String", hAlign: "right"},
+            {headerName: "市场单价调整", headerWidth: 80, dataCode: "price", dataType: "String", hAlign: "right"},
+            {headerName: "是否暂估", headerWidth: 80, dataCode: "isEstimate", dataType: "String", hAlign: "right"}
+        ],
+        view: {
+            comboBox: [{row: -1, col: 12, rowCount: -1, colCount: 1}],
+            lockedCells: [{row: -1, col: 3, rowCount: -1, colCount: 1}]
+        }
+    },
+
+    initSheet: function(sheet) {
+        var me = this;
+        me.sheet = sheet;
+        sheetCommonObj.initSheet(me.sheet, me.setting, 30);
+
+       // var unit = new GC.Spread.Sheets.CellTypes.ComboBox();
+        //unit.items(["米","千克"]);
+       // me.sheet.getRange(-1, 3, -1, 1).cellType(unit);
+        sheet.bind(GC.Spread.Sheets.Events.ClipboardPasting, me.onClipboardPasting);
+        sheet.bind(GC.Spread.Sheets.Events.ClipboardPasted, me.onClipboardPasted);
+        sheet.bind(GC.Spread.Sheets.Events.EditEnded, me.onEditEnded);
+        sheet.bind(GC.Spread.Sheets.Events.RangeChanged, me.onRangeChanged);
+        this.loadGLJSpreadContextMenu();
+    },
+
+    onClipboardPasting: function(sender, args) {
+        var me = gljOprObj;
+        if (!me.ration) {
+            args.cancel = true;
+        }
+    },
+
+    onClipboardPasted: function(e, info) {
+        var me = gljOprObj;
+        if (!me.ration) {return;};
+        // your code...
+    },
+
+    onEditEnded: function(sender, args){
+        var me = gljOprObj;
+        if (!me.ration) {return;};
+        // your code...
+    },
+
+    onRangeChanged: function(sender, args) {
+        if (args.action == GC.Spread.Sheets.RangeChangedAction.clear) {
+            if (!confirm(`确定要删除选中的 ${args.rowCount} 条辅助定额吗?`)){return; }
+            // your code...
+        };
+    },
+    showDataIfRationSelect:function (node) {
+        let gljList = [];
+        if(node){
+            if(this.selectedNodeId&&this.selectedNodeId==node.getID()){
+                return;
+            }else {
+                this.selectedNodeId=node.getID();
+            }
+            if(node.sourceType=="ration"){
+                let ration_glj = projectObj.project.ration_glj;
+                let ration = node.data;
+                if(ration_glj.datas&&ration_glj.datas.length>0){
+                    gljList = _.filter(ration_glj.datas,{'projectID':ration.projectID,'rationID':ration.ID})
+                }
+                sheetCommonObj.showData(this.sheet,this.setting,gljList);
+            }
+        }
+        this.selectedNodeId=null;
+        sheetCommonObj.showData(this.sheet,this.setting,gljList);
+        this.sheetData=gljList;
+    },
+    loadGLJSpreadContextMenu: function () {
+        var project =projectObj.project, spread =subSpread;
+        var selectedRow =null;
+        $.contextMenu({
+            selector: '#subSpread',
+            build: function ($trigger, e) {
+                var target = SheetDataHelper.safeRightClickSelection($trigger, e, spread);
+                selectedRow = target.row;
+                //controller.setTreeSelected(controller.tree.items[target.row]);
+                return target.hitTestType === GC.Spread.Sheets.SheetArea.viewport || target.hitTestType === GC.Spread.Sheets.SheetArea.rowHeader;
+            },
+            items: {
+                "delete_glj": {
+                    name: '删除工料机',
+                    icon: 'fa-remove',
+                    disabled: function () {
+                        //var selected = project.mainTree.selected;
+                        var disable = true;
+                        if(gljOprObj.sheetData!=null&&gljOprObj.sheetData.length>0&&selectedRow<gljOprObj.sheetData.length){
+                            disable=false
+                        }
+                        return disable;
+                    },
+                    callback: function () {
+                        var deleteRow = gljOprObj.sheetData[selectedRow];
+                        projectObj.project.ration_glj.updataOrdelete(deleteRow);
+                    }
+                }
+            }
+        });
+    }
+
+}
+

+ 13 - 1
web/building_saas/main/js/views/project_view.js

@@ -6,6 +6,7 @@ var projectObj = {
     project: null,
     project: null,
     mainSpread: null,
     mainSpread: null,
     mainController: null,
     mainController: null,
+    gljSpreed:null,
     checkMainSpread: function () {
     checkMainSpread: function () {
         if (!this.mainSpread) {
         if (!this.mainSpread) {
             this.mainSpread = SheetDataHelper.createNewSpread($('#billsSpread')[0]);
             this.mainSpread = SheetDataHelper.createNewSpread($('#billsSpread')[0]);
@@ -23,7 +24,6 @@ var projectObj = {
         this.project.loadDatas(function (err) {
         this.project.loadDatas(function (err) {
             if (!err) {
             if (!err) {
                 that.mainController = TREE_SHEET_CONTROLLER.createNew(that.project.mainTree, that.mainSpread.getActiveSheet(), BillsGridSetting);
                 that.mainController = TREE_SHEET_CONTROLLER.createNew(that.project.mainTree, that.mainSpread.getActiveSheet(), BillsGridSetting);
-
                 that.mainController.showTreeData();
                 that.mainController.showTreeData();
                 that.mainController.bind('refreshBaseActn', function (tree) {
                 that.mainController.bind('refreshBaseActn', function (tree) {
                     var setButtonValid = function (valid, btn) {
                     var setButtonValid = function (valid, btn) {
@@ -40,6 +40,17 @@ var projectObj = {
                     setButtonValid(tree.selected ? true : false, $('#delete'));
                     setButtonValid(tree.selected ? true : false, $('#delete'));
                 });
                 });
 
 
+              /*  if(!projectObj.gljSpreed){
+                    projectObj.gljSpreed = gljView.buildSheet($("#gljSpread")[0]);
+                    that.loadGLJSpreadContextMenu();
+                }*/
+
+
+                that.mainController.bind(TREE_SHEET_CONTROLLER.eventName.treeSelectedChanged, function (node) {
+                    console.log(projectObj.project);
+                    gljOprObj.showDataIfRationSelect(node);
+                });
+
                 that.loadMainSpreadContextMenu();
                 that.loadMainSpreadContextMenu();
             }
             }
             else {
             else {
@@ -146,6 +157,7 @@ $('#delete').click(function () {
             controller.delete();
             controller.delete();
         } else if (selected.sourceType === project.Ration.getSourceType()) {
         } else if (selected.sourceType === project.Ration.getSourceType()) {
             project.Ration.delete(selected.source);
             project.Ration.delete(selected.source);
+            project.ration_glj.deleteByRation(selected.source);
             controller.delete();
             controller.delete();
         };
         };
     }
     }

+ 58 - 0
web/building_saas/main/js/views/sub_view.js

@@ -0,0 +1,58 @@
+/**
+ * Created by CSL on 2017-07-04.
+ */
+
+// Tab panes 下有多个Spread时,相互之间不能正确显示。改成一个Spread下多个Sheet。
+var subSpread = sheetCommonObj.createSpread($("#subSpread")[0], 7);
+
+
+// 工料机
+gljOprObj.initSheet(subSpread.getSheet(0));
+sheetCommonObj.shieldAllCells(subSpread.getSheet(0), gljOprObj.setting);
+
+// assistOprObj.initSheet(subSpread.getSheet(1));
+// sheetCommonObj.shieldAllCells(subSpread.getSheet(1), assistOprObj.setting);
+
+
+
+$("#linkGLJ").click(function(){
+    subSpread.setActiveSheetIndex(0);
+    // for test
+    subSpread.getActiveSheet().setValue(0, 0, "工料机");
+});
+
+$("#linkFZDE").click(function(){
+    subSpread.setActiveSheetIndex(1);
+    // for test
+    subSpread.getActiveSheet().setValue(0, 0, "辅助定额");
+});
+
+$("#linkFZTJ").click(function(){
+    subSpread.setActiveSheetIndex(2);
+    // for test
+    subSpread.getActiveSheet().setValue(0, 0, "附注条件");
+});
+
+$("#linkGCLMX").click(function(){
+    subSpread.setActiveSheetIndex(3);
+    // for test
+    subSpread.getActiveSheet().setValue(0, 0, "工程量明细");
+});
+
+$("#linkJSCX").click(function(){
+    subSpread.setActiveSheetIndex(4);
+    // for test
+    subSpread.getActiveSheet().setValue(0, 0, "计算程序");
+});
+
+$("#linkFXSM").click(function(){
+    subSpread.setActiveSheetIndex(5);
+    // for test
+    subSpread.getActiveSheet().setValue(0, 0, "分项说明");
+});
+
+$("#linkDESM").click(function(){
+    subSpread.setActiveSheetIndex(6);
+    // for test
+    subSpread.getActiveSheet().setValue(0, 0, "定额说明");
+});

+ 1 - 1
web/building_saas/pm/js/pm_main.js

@@ -605,7 +605,7 @@ $('#copytoOk').click(function() {
             CommonAjax.post('/pm/api/getNewProjectID', {count: 1}, function (IDs) {
             CommonAjax.post('/pm/api/getNewProjectID', {count: 1}, function (IDs) {
                 var updateData = GetCopyUpdateData(cur, parent, next, IDs.lowID);
                 var updateData = GetCopyUpdateData(cur, parent, next, IDs.lowID);
                 Tree.maxNodeId(IDs.lowID - 1);
                 Tree.maxNodeId(IDs.lowID - 1);
-                CommonAjax.post('/pm/api/copyProjects', {user_id: userID, updateData: updateData}, function (data) {
+                CommonAjax.post('/pm/api/copyProjects', {updateData: updateData}, function (data) {
                     form.modal('hide');
                     form.modal('hide');
                     data.forEach(function (nodeData) {
                     data.forEach(function (nodeData) {
                         if (nodeData.updateType === 'copy') {
                         if (nodeData.updateType === 'copy') {

+ 14 - 0
web/glj/html/footer.html

@@ -0,0 +1,14 @@
+<!-- JS. -->
+<script src="/lib/jquery/jquery.min.js"></script>
+<script src="/lib/tether/tether.min.js"></script>
+<script src="/lib/bootstrap/bootstrap.min.js"></script>
+<script src="/web/building_saas/js/global.js"></script>
+<script src="/web/glj/js/socket.io.slim.js"></script>
+<script>GC.Spread.Sheets.LicenseKey = "559432293813965#A0y3iTOzEDOzkjMyMDN9UTNiojIklkI1pjIEJCLi4TPB9mM5AFNTd4cvZ7SaJUVy3CWKtWYXx4VVhjMpp7dYNGdx2ia9sEVlZGOTh7NRlTUwkWR9wEV4gmbjBDZ4ElR8N7cGdHVvEWVBtCOwIGW0ZmeYVWVr3mI0IyUiwCMzETN8kzNzYTM0IicfJye&Qf35VfiEzRwEkI0IyQiwiIwEjL6ByUKBCZhVmcwNlI0IiTis7W0ICZyBlIsIyNyMzM5ADI5ADNwcTMwIjI0ICdyNkIsIibj9SbvNmL4N7bjRnch56ciojIz5GRiwiI8+Y9sWY9QmZ0Jyp96uL9v6L0wap9biY9qiq95q197Wr9g+89iojIh94Wiqi";</script>
+
+</body>
+<script type="text/javascript">
+    autoFlashHeight();
+</script>
+
+</html>

+ 46 - 0
web/glj/html/glj_index.html

@@ -0,0 +1,46 @@
+<%include header.html %>
+<div class="main">
+    <div class="main-nav">
+        <ul class="nav flex-column">
+            <li><a href="zaojiashu.html">造价书</a></li>
+            <li><a href="gongliaoji.html" class="active">工料机</a></li>
+            <li><a href="baobiao.html">报表</a></li>
+            <li><a href="feilv.html">费率</a></li>
+        </ul>
+    </div>
+    <div class="content">
+        <div class="toolsbar px-1">
+            <div class="tools-btn btn-group align-top">
+                <a href="" class="btn btn-sm"><i class="fa fa-arrow-down" aria-hidden="true"></i>下移</a>
+                <a href="" class="btn btn-sm"><i class="fa fa-arrow-up" aria-hidden="true"></i>上移</a>
+                <a href="" class="btn btn-sm"><i class="fa fa-arrow-left" aria-hidden="true"></i></a>
+                <a href="" class="btn btn-sm"><i class="fa fa-arrow-right" aria-hidden="true"></i></a>
+                <a href="" class="btn btn-sm"><i class="fa fa-undo" aria-hidden="true"></i></a>
+            </div>
+        </div>
+        <div class="container-fluid">
+            <div class="row">
+                <div class="main-content col-lg-12 p-0">
+                    <div class="main-data-full" id="test">
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+<script type="text/javascript">
+    let jsonData = '<%- gljList %>';
+    let materialIdList = '<%- materialIdList %>';
+    materialIdList = materialIdList !== '' ? materialIdList.split(",") : '';
+    // 不能修改市场价格的类型id
+    let canNotChangeTypeId = '64';
+    canNotChangeTypeId = canNotChangeTypeId !== '' ? canNotChangeTypeId.split(",") : '';
+    // 自动赋值的工料机类型
+    let autoChangeGLJType = '<%- autoChangeGLJType %>';
+    autoChangeGLJType = autoChangeGLJType !== '' ? autoChangeGLJType.split(",") : '';
+    // 触发计算混凝土、砂浆、配合比、机械的市场单价的工料机类型
+    let triggerCalculateGLJType = '<%- triggerCalculateGLJType %>';
+    triggerCalculateGLJType = triggerCalculateGLJType !== '' ? triggerCalculateGLJType.split(",") : '';
+</script>
+<%include footer.html %>
+<script type="text/javascript" src="/web/glj/js/glj_index.js"></script>

+ 90 - 0
web/glj/html/header.html

@@ -0,0 +1,90 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title><%= title %>-Smartcost</title>
+    <link rel="stylesheet" href="/lib/bootstrap/css/bootstrap.min.css">
+    <link rel="stylesheet" href="/web/building_saas/css/main.css">
+    <link rel="stylesheet" href="/lib/font-awesome/font-awesome.min.css">
+    <link rel="stylesheet" href="/lib/spreadjs/sheets/css/gc.spread.sheets.excel2013white.10.0.1.css">
+    <script type="text/javascript" src="/public/web/sheet/sheet_common.js"></script>
+    <script type="text/javascript" src="/public/web/sheet/sheet_data_helper.js"></script>
+    <script src="/lib/spreadjs/sheets/gc.spread.sheets.all.10.0.1.min.js"></script>
+    <style type="text/css">
+        #chat-content {
+            border: 1px solid #000;
+            width: 500px;
+            height: 600px;
+        }
+        #notify {
+            display: none;
+        }
+    </style>
+</head>
+<body>
+<div class="header">
+    <div class="top-msg clearfix" id="notify">
+        <div class="alert alert-warning mb-0 py-0" role="alert">
+            <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+                <span aria-hidden="true">&times;</span>
+            </button>
+            <span id="message"><strong>注意!</strong> 这是一条消息通知 <a href="#">链接</a></span>
+        </div>
+    </div>
+    <nav class="navbar navbar-toggleable-lg navbar-light bg-faded p-0 justify-content-between">
+        <span class="header-logo px-2">Smartcost</span>
+        <div class="navbar-text"><a href="project-management.html">项目管理</a><i class="fa fa-angle-right fa-fw"></i>文件夹<i
+                class="fa fa-angle-right fa-fw"></i>建设项目<i class="fa fa-angle-right fa-fw"></i>单项工程<i
+                class="fa fa-angle-right fa-fw"></i>单位工程
+        </div>
+        <div class="float-lg-right navbar-text pt-0">
+            <div class="dropdown d-inline-block">
+                <button class="btn btn-link btn-sm dropdown-toggle" type="button" data-toggle="dropdown">陈特</button>
+                <div class="dropdown-menu dropdown-menu-right">
+                    <a class="dropdown-item" href="user-info.html" target="_blank">账号资料</a>
+                    <a class="dropdown-item" href="user-buy.html" target="_blank">产品购买</a>
+                    <a class="dropdown-item" href="user-set.html" target="_blank">偏好设置</a>
+                </div>
+            </div>
+            <span class="btn btn-link btn-sm new-msg">
+                  <i class="fa fa-envelope-o" aria-hidden="true"></i>&nbsp;2
+                </span>
+            <button class="btn btn-link btn-sm">注销</button>
+        </div>
+    </nav>
+    <nav class="navbar navbar-toggleable-lg justify-content-between navbar-light p-0">
+        <ul class="nav navbar-nav px-1">
+            <li class="nav-item">
+                <a class="nav-link" href="#" aria-haspopup="true" aria-expanded="false"><i class="fa fa-sliders"></i> 选项</a>
+            </li>
+            <li class="nav-item dropdown">
+                <a class="nav-link dropdown-toggle" href="#" data-toggle="dropdown" aria-haspopup="true"
+                   aria-expanded="false"><i class="fa fa-wrench"></i> 工具</a>
+                <div class="dropdown-menu">
+                    <a class="dropdown-item" href="#">定额库编辑器</a>
+                    <a class="dropdown-item" href="#">工料机库编辑器</a>
+                </div>
+            </li>
+            <li class="nav-item dropdown">
+                <a class="nav-link dropdown-toggle" href="#" data-toggle="dropdown" aria-haspopup="true"
+                   aria-expanded="false"><i class="fa fa-question-circle-o"></i> 帮助</a>
+                <div class="dropdown-menu">
+                    <a class="dropdown-item" href="#">帮助</a>
+                    <a class="dropdown-item" href="#">升级说明</a>
+                    <a class="dropdown-item" href="#">重庆市2008定额说明</a>
+                    <a class="dropdown-item" href="#">纵横官网</a>
+                    <a class="dropdown-item" href="#">动画教程</a>
+                    <a class="dropdown-item" href="#">联系客服</a>
+                    <a class="dropdown-item" href="#">关于</a>
+                </div>
+            </li>
+            <li class="nav-item">
+                <a class="nav-link" href="#" aria-haspopup="true" aria-expanded="false"><i class="fa fa-history"></i>
+                    历史记录</a>
+            </li>
+        </ul>
+        <form class="form-inline">
+            <input class="form-control form-control-sm mr-1" type="text" placeholder="告诉我你想做什么">
+        </form>
+    </nav>
+</div>

+ 344 - 0
web/glj/js/glj_index.js

@@ -0,0 +1,344 @@
+/**
+ * 聊天室相关
+ *
+ * @author CaiAoLin
+ * @date 2017/6/15
+ * @version
+ */
+let header = [];
+let sheet = null;
+$(document).ready(function () {
+    // excel
+     header = [
+        {name: '编码', field: 'code', visible: true},
+        {name: '名称', field: 'name', visible: true},
+        {name: '规格型号', field: 'unit_price.specs', visible: true},
+        {name: '单位', field: 'unit_price.unit', visible: true},
+        {name: 'ID', field: 'id', visible: false},
+        {name: '类型', field: 'unit_price.type', visible: false},
+        {name: '总消耗量', field: '', visible: true},
+        {name: '基价单价', field: "unit_price.base_price", visible: true},
+        {name: '调整基价', field: 'adjust_price', visible: true},
+        {name: '市场单价', field: "unit_price.market_price", visible: true, validator: 'number'},
+        {name: '是否暂估', field: 'is_evaluate', visible: true, cellType: new GC.Spread.Sheets.CellTypes.CheckBox(),  validator: 'boolean'},
+        {name: '供货方式', field: 'supply', visible: true},
+        {name: '甲供数量', field: 'supply_quantity', visible: true},
+        {name: '交货方式', field: 'delivery', visible: true},
+        {name: '送达地点', field: 'delivery_address', visible: true},
+        {name: '不调价', field: 'is_adjust_price', visible: true, cellType: new GC.Spread.Sheets.CellTypes.CheckBox(),  validator: 'boolean'},
+        {name: 'UID', field: 'unit_price.id', visible: false},
+    ];
+    // 数据转换格式
+    let sourceData = JSON.parse(jsonData);
+
+    let setting = {
+        header: []
+    };
+    for(let tmp of header) {
+        setting.header.push({headerName: tmp.name, headerWidth: 120});
+    }
+
+    let spread = sheetCommonObj.buildSheet(document.getElementById("test"), setting, sourceData.length);
+    spread.options.scrollbarShowMax = true;
+    spread.options.scrollbarMaxAlign = true;
+    spread.options.showHorizontalScrollbar = true;
+    sheet = spread.getActiveSheet();
+
+    // 设置表单不可编辑
+    sheet.options.isProtected = true;
+
+    // 居中样式
+    let centerStyleSetting = {hAlign: 1};
+    sheet.setStyle(-1, 10, getStyle(centerStyleSetting), GC.Spread.Sheets.SheetArea.viewport);
+    sheet.setStyle(-1, 15, getStyle(centerStyleSetting), GC.Spread.Sheets.SheetArea.viewport);
+    sheet.setStyle(-1, 3, getStyle(centerStyleSetting), GC.Spread.Sheets.SheetArea.viewport);
+
+    // 向右对齐样式
+    let rightStyleSetting = {hAlign: GC.Spread.Sheets.HorizontalAlign.right};
+    sheet.setStyle(-1, 6, getStyle(rightStyleSetting), GC.Spread.Sheets.SheetArea.viewport);
+    sheet.setStyle(-1, 7, getStyle(rightStyleSetting), GC.Spread.Sheets.SheetArea.viewport);
+    sheet.setStyle(-1, 8, getStyle(rightStyleSetting), GC.Spread.Sheets.SheetArea.viewport);
+    sheet.setStyle(-1, 9, getStyle(rightStyleSetting), GC.Spread.Sheets.SheetArea.viewport);
+
+
+    // 设置可编辑列
+    sheet.getRange(-1, 9, -1, 1).locked(false);
+    sheet.getRange(-1, 10, -1, 1).locked(false);
+    sheet.getRange(-1, 15, -1, 1).locked(false);
+
+    // 设置json数据
+    let rowCounter = 0;
+    for(let data of sourceData) {
+        let columnCounter = 0;
+        for(let columnInfo of header) {
+            // 设置是否显示
+            sheet.setColumnVisible(columnCounter, columnInfo.visible);
+
+            let dataString = columnInfo.field !== '' && columnInfo.field !== undefined ?
+                "data." + columnInfo.field : '';
+            let cellData = eval(dataString);
+
+            // 设置复选框
+            if (columnInfo.cellType !== undefined) {
+                let checkbox = new GC.Spread.Sheets.CellTypes.CheckBox();
+                sheet.setCellType(rowCounter, columnCounter, checkbox, GC.Spread.Sheets.SheetArea.viewport);
+            }
+
+            // 如果不为材料“是否暂估列”根据条件显示
+            if (columnInfo.field === 'is_evaluate' && materialIdList.indexOf(data.unit_price.type + '') < 0) {
+                let string = new GC.Spread.Sheets.CellTypes.Text();
+                sheet.setCellType(rowCounter, columnCounter, string, GC.Spread.Sheets.SheetArea.viewport);
+                cellData = '';
+                // 并且锁定该单元格
+                sheet.getRange(rowCounter, columnCounter, 1, 1).locked(true);
+            }
+
+            // 如果类型为混凝土、砂浆、配合比、机械,则市场单价不能修改
+            if (columnInfo.field === 'unit_price.market_price' && canNotChangeTypeId.indexOf(data.unit_price.type + '') >= 0) {
+                // 锁定该单元格
+                sheet.getRange(rowCounter, columnCounter, 1, 1).locked(true);
+            }
+
+            sheet.setValue(rowCounter, columnCounter, cellData, GC.Spread.Sheets.SheetArea.viewport);
+            columnCounter++;
+        }
+        rowCounter++;
+    }
+
+/*
+    let socket = io('http://notify.smartcost.com.cn:3300');
+    socket.on('connect', function () {
+        socket.emit('join', project);
+        console.log('连接成功');
+    });
+
+    // 接受到改变
+    let changeInfo = [];
+    socket.on('dataChange', function(data) {
+        data = JSON.parse(data);
+        if (data.newValue === undefined) {
+            return false;
+        }
+        changeInfo.push(data);
+        $("#message").html('基价单位已被修改,<a href="javascript:void(0);" id="load-data">点击加载</a>');
+        $("#notify").slideDown('fast');
+        initiativeChange = false;
+    });
+
+    // 是否主动更改数据
+    let initiativeChange = false;
+    $("#message").on('click', '#load-data', function() {
+        $("#notify").slideUp('fast');
+        if (changeInfo.length > 0) {
+            for (let index in changeInfo) {
+                let cell = sheet.getCell(changeInfo[index].row, changeInfo[index].col, GC.Spread.Sheets.SheetArea.viewport);
+                cell.value(changeInfo[index].newValue);
+            }
+        }
+        changeInfo = [];
+    });
+
+    // 进入单元格后设置为主动设置数据
+    sheet.bind(GC.Spread.Sheets.Events.EditEnding, function (element, info) {
+        initiativeChange = true;
+    });
+ */
+    // 绑定事件
+    let isChanging = false;
+    sheet.bind(GC.Spread.Sheets.Events.ValueChanged, function (element, info) {
+        // 获取修改的数据
+        let column = info.col;
+        let row = info.row;
+        let model = 'glj';
+        let idString = 'id';
+        let field = header[column] !== undefined && header[column].field !== undefined ?
+            header[column].field : '';
+        if (field === '') {
+            return false;
+        }
+
+        // 切割字段
+        let fieldArray = field.split('.');
+        idString = fieldArray.length > 1 ? 'unit_price.id' : idString;
+
+        // 防止快速同时提交
+        if (isChanging) {
+            return false;
+        }
+        // 校验数据
+        let validator = header[column].validator !== undefined ? header[column].validator : null;
+        let value = info.newValue;
+        if (validator && !checkData(validator, value)) {
+            alert('数据格式错误,请重新输入!');
+            sheet.setValue(row, column, info.oldValue);
+            return false;
+        }
+
+        // 获取id
+        let idColumn = getFieldColumn(header, idString);
+        if (idColumn < 0) {
+            return false;
+        }
+        let id = sheet.getValue(row, idColumn);
+
+        $.ajax({
+            url: '/glj/update',
+            type: 'post',
+            data: {id: id, field: field, value: value, model: model},
+            dataType: 'json',
+            error: function() {
+                alert('数据传输有误!');
+                isChanging = false;
+            },
+            beforeSend: function() {
+                isChanging = true;
+            },
+            success: function(response) {
+                isChanging = false;
+                // 修改失败则恢复原值
+                if (response.err !== 0) {
+                    sheet.setValue(row, column, info.oldValue);
+                    alert('更改数据失败!');
+                } else {
+                    // 成功则触发相应事件
+                    successTrigger(field, info);
+                }
+            }
+        });
+        /*
+        // 如果修改了数据且为主动修改,先存库再广播给其他页面
+        if (info.newValue !== undefined && info.oldValue !== undefined && initiativeChange) {
+            let id = sheet.getCell(info.row, 0).value();
+            $.ajax({
+                url: '/save',
+                type: 'post',
+                data: {priceValue: info.newValue, id: id},
+                error: function() {
+                    // @todo 替换为更好地错误提示
+                    alert('error');
+                },
+                beforeSend: function() {
+
+                },
+                success: function(response) {
+                    if (response.err === 0) {
+                        socket.emit('dataNotify', JSON.stringify(info));
+                    } else {
+                        // @todo 替换为更好地错误提示
+                        alert(response.msg);
+                    }
+                }
+            });
+        }
+        */
+    });
+
+    // 绑定双击事件
+    sheet.bind(GC.Spread.Sheets.Events.CellDoubleClick, function (element, info) {
+        let column = info.col;
+        let row = info.row;
+        let field = header[column] !== undefined && header[column].field !== undefined ?
+            header[column].field : '';
+
+        // 获取类型
+        let typeColumn = getFieldColumn(header, 'unit_price.type');
+        let type = sheet.getValue(row, typeColumn);
+
+        // 如果类型为混凝土、砂浆、配合比、机械,则提示
+        if (field === 'unit_price.market_price' && canNotChangeTypeId.indexOf(type + '') >= 0) {
+            alert('当前工料机的市场单价由组成物计算得出,不可直接修改');
+        }
+    });
+
+});
+
+/**
+ * 生成样式
+ *
+ * @param {object} setting
+ * @return {object}
+ */
+function getStyle(setting) {
+    let style = new GC.Spread.Sheets.Style();
+    style.locked = setting.readOnly === undefined ? true : setting.readOnly;
+    style.hAlign = setting.hAlign === undefined ? GC.Spread.Sheets.HorizontalAlign.center : setting.hAlign;
+    return style;
+}
+
+/**
+ * 查找指定字段的列index
+ *
+ * @param {object} data
+ * @param {String} field
+ * @return {Number}
+ */
+function getFieldColumn(data, field) {
+    let result = -1;
+    if (data.length <= 0) {
+        return result;
+    }
+    for (let tmp in data) {
+        if (data[tmp].field === field) {
+            result = tmp;
+            break;
+        }
+    }
+
+    return result;
+}
+
+/**
+ * 校验数据
+ *
+ * @param {string} validator
+ * @param {string} value
+ * @return {boolean}
+ */
+function checkData(validator, value) {
+    let result = false;
+    switch (validator) {
+        case 'number':
+            let regular = /^\d+(\.\d+)?$/;
+            result = regular.test(value);
+            break;
+        case 'boolean':
+            let booleanValue = [true, false];
+            result = booleanValue.indexOf(value) >= 0;
+            break;
+    }
+
+    return result;
+}
+
+/**
+ * 成功事件
+ *
+ * @param {string} field
+ * @param {object} info
+ * @return {void}
+ */
+function successTrigger(field, info) {
+    switch (field) {
+        case 'unit_price.market_price':
+            let row = info.row;
+            let basePriceColumn = getFieldColumn(header, 'unit_price.base_price');
+            let adjustPriceColumn = getFieldColumn(header, 'adjust_price');
+
+            // 获取类型
+            let typeColumn = getFieldColumn(header, 'unit_price.type');
+            let type = sheet.getValue(row, typeColumn);
+
+            // 主材、设备自动赋值基价单价=市场单价、调整基价=市场单价
+            if (autoChangeGLJType.indexOf(type + '') >= 0) {
+                sheet.setValue(info.row, basePriceColumn, info.newValue);
+                sheet.setValue(info.row, adjustPriceColumn, info.newValue);
+            }
+
+            // 人工、材料(普通材料)触发 需计算混凝土、砂浆、配合比、机械的市场单价 @todo 后续添加
+            if (triggerCalculateGLJType.indexOf(type + '') >= 0) {
+                // 计算
+                console.log('触发计算');
+            }
+            break;
+    }
+}

File diff suppressed because it is too large
+ 3 - 0
web/glj/js/socket.io.slim.js