浏览代码

1.增加索引
2.新增配合比相关代码
3.修改基类相关操作
4.修改glj schema 字段 (工料机总库id)

caiaolin 8 年之前
父节点
当前提交
ef76f8d38f

+ 12 - 4
modules/common/base/base_model.js

@@ -47,15 +47,23 @@ class BaseModel {
      * @param {Object} condition
      * @param {Object} fields
      * @param {boolean} singleData
+     * @param {String} indexBy
      * @return {Promise}
      */
-    async findDataByCondition(condition, fields = null, singleData = true) {
+    async findDataByCondition(condition, fields = null, singleData = true, indexBy = null) {
+        let result = null;
         if (Object.keys(condition).length <= 0) {
-            return null;
+            return result;
         }
 
-        let data = await singleData ? this.db.findOne(condition, fields) : this.db.find(condition, fields);
-        return data;
+        let data =  singleData ? await this.db.findOne(condition, fields) : await this.db.find(condition, fields);
+        result = data;
+        if (indexBy !== null && !singleData && data.length > 0) {
+            for(let tmp of data) {
+                result[tmp[indexBy]] = tmp;
+            }
+        }
+        return result;
     }
 
     /**

+ 28 - 0
modules/common/std/schemas/std_mix_ratio.js

@@ -0,0 +1,28 @@
+/**
+ * 配合比标准库数据模型
+ *
+ * @author CaiAoLin
+ * @date 2017/7/7
+ * @version
+ */
+import mongoose from "mongoose";
+
+let Schema = mongoose.Schema;
+let collectionName = 'std_mix_ratio';
+let modelSchema = {
+    // 编码
+    code: String,
+    // 名称
+    name: String,
+    // 消耗量
+    consumption: Number,
+    // 关联工料机的编码
+    connect_code: {
+        type: String,
+        index: true
+    },
+    // 对应的工料机总库id
+    glj_id: Number,
+};
+let model = mongoose.model(collectionName, new Schema(modelSchema, {versionKey: false, collection: collectionName}));
+export {model as default, collectionName as collectionName};

+ 13 - 0
modules/common/std/schemas/std_ration_lib_glj_list.js

@@ -0,0 +1,13 @@
+/**
+ * 定额工料机标准库数据模型
+ *
+ * @author CaiAoLin
+ * @date 2017/7/7
+ * @version
+ */
+import mongoose from "mongoose";
+
+let collectionName = 'std_ration_lib_glj_list';
+// 因为别处已初始化过,所以直接使用
+let model = mongoose.model(collectionName);
+export {model as default, collectionName as collectionName};

+ 49 - 0
modules/common/std/std_mix_ratio_model.js

@@ -0,0 +1,49 @@
+/**
+ * 配合比标准库业务模型
+ *
+ * @author CaiAoLin
+ * @date 2017/7/10
+ * @version
+ */
+import BaseModel from "../base/base_model";
+import STDMixRatioSchema from "./schemas/std_mix_ratio";
+
+class STDMixRatioModel extends BaseModel {
+
+    /**
+     * 构造函数
+     *
+     * @return {void}
+     */
+    constructor() {
+        let parent = super();
+        parent.model = STDMixRatioSchema;
+        parent.init();
+    }
+
+    /**
+     * 根据编码获取对应的组成物信息
+     *
+     * @param {String} code
+     * @return {Promise}
+     */
+    async getDataByCode(code) {
+        let result = [];
+        code = code.trim();
+        try {
+            if (code === '') {
+                throw '编码为空';
+            }
+
+            result = await this.findDataByCondition({connect_code: code}, null, false);
+        } catch (error) {
+            console.log('std_mix_ratio_model:' + error);
+            result = [];
+        }
+
+        return result;
+    }
+
+}
+
+export default STDMixRatioModel;

+ 51 - 0
modules/common/std/std_ration_lib_glj_list_model.js

@@ -0,0 +1,51 @@
+/**
+ * 工料机总库相关业务逻辑
+ *
+ * @author CaiAoLin
+ * @date 2017/7/11
+ * @version
+ */
+import BaseModel from "../base/base_model";
+import STDRationLibGLJListSchemas from "./schemas/std_ration_lib_glj_list";
+
+class STDRationLibGLJListModel extends BaseModel {
+
+    /**
+     * 构造函数
+     *
+     * @return {void}
+     */
+    constructor() {
+        let parent = super();
+        parent.model = STDRationLibGLJListSchemas;
+        parent.init();
+    }
+
+    /**
+     * 根据id获取数据
+     *
+     * @param {Number|Array} id
+     * @return {Promise}
+     */
+    async getDataById(id) {
+        let result = null;
+        try {
+            if (!id instanceof Array) {
+                id = parseInt(id);
+                if (isNaN(id)) {
+                    throw 'id有误';
+                }
+            }
+            let condition = {ID: {"$in": id}};
+            result = await this.findDataByCondition(condition, null, false);
+        } catch (error) {
+            console.log(error);
+            result = null;
+        }
+
+        return result;
+    }
+
+}
+
+export default STDRationLibGLJListModel;

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

@@ -128,6 +128,35 @@ class GLJController extends BaseController {
     }
 
     /**
+     * 加载配合比相关数据
+     *
+     * @return {void}
+     */
+    async getMixRatio(request, response) {
+        let projectGLJId = request.body.id;
+        // let projectId = request.body.project_id;
+        let projectId = 1;
+        try {
+            // 获取标段对应的单价文件id
+            let unitPriceFileModel = new UnitPriceFileModel();
+            let unitPriceFile = await unitPriceFileModel.getDataByProject(projectId);
+            if (!unitPriceFile) {
+                throw '没有对应的单价文件';
+            }
+            // 单价文件id作为同步的roomId
+            let unitPriceFileId = unitPriceFile.id;
+
+            let gljListModel = new GLJListModel();
+            let result = await gljListModel.getCompositionList(152, unitPriceFileId);
+            console.log(result);
+        } catch (error) {
+            console.log(error);
+        }
+
+        response.end('end');
+    }
+
+    /**
      * 模拟定额插入
      *
      * @param {object} request
@@ -135,24 +164,22 @@ class GLJController extends BaseController {
      * @return {void}
      */
     async test(request, response) {
-        console.log(global.test);
         // 从定额库获取的数据
         let data = {
-            glj_repository_id: 1,
+            glj_id: 54,
             project_id: 1,
-            code: '00010201',
-            name: '土石方综合工日',
-            specs: '',
-            unit: '工日',
-            type: 2,
-            base_price: '44.76',
-            market_price: '44.76'
+            code: '81040102',
+            name: '水泥白石子浆 1∶1.5',
+            specs: '1∶1.5',
+            unit: '',
+            type: GLJTypeConst.CONCRETE,
+            base_price: 479.25,
+            market_price: 479.25
         };
         try {
             let gljListModel = new GLJListModel();
             let result = await gljListModel.addList(data);
 
-            console.log(result);
         } catch (error) {
             console.log(error);
         }
@@ -169,18 +196,12 @@ class GLJController extends BaseController {
      */
     async testModify(request, response) {
         let projectId = request.query.project;
-        // // 修改数据
-        // let updateData = {
-        //     code: '00010201',
-        //     market_price: '49',
-        //     name: '土石方综合工日',
-        //     project_id: projectId
-        // };
+        // 修改数据
         let updateData = {
-            market_price: '60.00',
             code: '00010201',
-            name: '土石方综合工日',
-            project_id: 90
+            market_price: '44.42',
+            name: '土石方综合工日(1)',
+            project_id: projectId
         };
 
         try {

+ 242 - 6
modules/glj/models/glj_list_model.js

@@ -9,8 +9,12 @@ 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 STDMixRatioModel from "../../common/std/std_mix_ratio_model";
 import UnitPriceFileModel from "./unit_price_file_model";
 import GLJTypeConst from "../../common/const/glj_type_const";
+import RationGLJFacade from "../../ration_glj/facade/ration_glj_facade";
+import STDRationLibGLJListModel from "../../common/std/std_ration_lib_glj_list_model";
+import STDGLJType from "../../../public/cache/std_glj_type_util";
 
 class GLJListModel extends BaseModel {
 
@@ -43,7 +47,7 @@ class GLJListModel extends BaseModel {
         switch (scene) {
             // 新增数据的验证规则
             case 'add':
-                this.model.schema.path('glj_repository_id').required(true);
+                this.model.schema.path('glj_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);
@@ -52,7 +56,7 @@ class GLJListModel extends BaseModel {
     }
 
     /**
-     * 根据标段对应工料机数据
+     * 根据标段对应项目工料机列表
      *
      * @param {Number} projectId
      * @param {Number} unitPriceFileId
@@ -75,8 +79,26 @@ class GLJListModel extends BaseModel {
             let unitPriceModel = new UnitPriceModel();
             let unitPriceList = await unitPriceModel.getDataByFileId(unitPriceFileId);
 
-            // 组合数据
-            this.combineUnitPrice(gljData, unitPriceList);
+            // 整理获取工料机ID list
+            let gljIdList = [];
+            for(let tmp of gljData) {
+                gljIdList.push(tmp.id);
+            }
+
+            // 从定额工料机库中获取消耗量
+            condition = {
+                projectID: projectId,
+                projectGLJIDList: gljIdList
+            };
+            let quantityData = await RationGLJFacade.getQuantityByProjectGLJ(condition);
+            let quantityList = {};
+            // 整理数据
+            for (let tmp of quantityData) {
+                quantityList[tmp.projectGLJID] = tmp.quantity;
+            }
+
+            // 组合单价数据
+            this.combineData(gljData, unitPriceList, quantityList);
 
             // 排序
             gljData.sort(function (a, b) {
@@ -95,9 +117,10 @@ class GLJListModel extends BaseModel {
      *
      * @param {object} gljList
      * @param {object} unitPriceList
+     * @param {object} quantityList
      * @return {void}
      */
-    combineUnitPrice(gljList, unitPriceList) {
+    combineData(gljList, unitPriceList, quantityList) {
         // 循环组合数据
         for(let glj of gljList) {
             if (glj.code === undefined) {
@@ -108,6 +131,10 @@ class GLJListModel extends BaseModel {
             if (glj.unit_price === null) {
                 continue;
             }
+
+            // 组合消耗量
+            glj.quantity = quantityList[glj.id] !== undefined ? quantityList[glj.id] : 0;
+
             // 计算调整基价
             switch (glj.unit_price.type + '') {
                 // 人工: 调整基价=基价单价*调整系数
@@ -158,6 +185,12 @@ class GLJListModel extends BaseModel {
             }
             let unitPriceFileId = unitPriceFile.id;
 
+            // 判断类型,如果是混凝土、砂浆或者配合比则查找对应的组成物
+            if (data.type === GLJTypeConst.CONCRETE || data.type === GLJTypeConst.MORTAR ||
+                data.type === GLJTypeConst.MIX_RATIO) {
+                this.compositionInit(data.code, data.project_id, unitPriceFileId);
+            }
+
             // 新增单价文件
             let unitPriceModel = new UnitPriceModel();
             let [unitPriceInsertData, isAdd] = await unitPriceModel.addUnitPrice(data, unitPriceFileId);
@@ -188,7 +221,14 @@ class GLJListModel extends BaseModel {
         }
 
         let counterModel = new CounterModel();
-        data.id = await counterModel.getId(gljCollectionName);
+        if (data instanceof Array) {
+            // 如果是批量新增
+            for(let tmp in data) {
+                data[tmp].id = await counterModel.getId(gljCollectionName);
+            }
+        } else {
+            data.id = await counterModel.getId(gljCollectionName);
+        }
 
         this.setScene('add');
         let result = await this.db.create(data);
@@ -293,6 +333,202 @@ class GLJListModel extends BaseModel {
 
         return index;
     }
+
+    /**
+     * 工料机中组成物操作
+     *
+     * @param {String} code
+     * @param {Number} projectId
+     * @param {Number} unitPriceFileId
+     * @return {void}
+     */
+    async compositionInit(code, projectId, unitPriceFileId) {
+
+        // 查找对应组成物的项目工料机数据
+        let [projectGljList, compositionList] = await this.getCompositionGLJList(code, projectId, 'name');
+
+        // 如果已经存在则后续操作停止
+        if(projectGljList.length === compositionList.length) {
+            return;
+        }
+
+        // 插入不存在的项目工料机数据
+        let notInGLJId = [];
+        let compositionData = {};
+        for(let tmp of compositionList) {
+            compositionData[tmp.glj_id] = tmp;
+            if (projectGljList[tmp.name] !== undefined) {
+                continue;
+            }
+            // 把不存在的工料机总库id加入数组
+            notInGLJId.push(tmp.glj_id);
+        }
+
+        // 查找对应工料机总库数据
+        let stdRationLibGLJListModel = new STDRationLibGLJListModel();
+        let stdGLJData = await stdRationLibGLJListModel.getDataById(notInGLJId);
+        if (stdGLJData === null) {
+            throw '没有找到对应的工料机总库数据';
+        }
+
+        // 获取工料机类型以及整理数据
+        let gljTypeList = STDGLJType.getStdGljTypeCacheObj().toArray();
+        let gljType = {};
+        for (let tmp of gljTypeList) {
+            gljType[tmp.fullName] = tmp.ID;
+        }
+
+        // 整理插入的数据
+        let gljInsertData = [];
+        let unitPriceInsertData = [];
+        for (let tmp of stdGLJData) {
+            // 项目工料机插入的数据
+            let gljData = {
+                glj_id: tmp.ID,
+                project_id: projectId,
+                code: tmp.code,
+                name: tmp.name
+            };
+            gljInsertData.push(gljData);
+
+            // 单价文件插入的数据
+            let unitPriceData = {
+                base_price: tmp.basePrice,
+                // 初始市场价=基价
+                market_price: tmp.basePrice,
+                code: tmp.code,
+                name: tmp.name,
+                specs: tmp.specs,
+                unit: tmp.unit,
+                consumption: compositionData[tmp.ID].consumption,
+                unit_price_file_id: unitPriceFileId,
+                // 如果没有对应的工料机类型则默认设置为普通材料
+                type: gljType[tmp.unit] !== undefined ? gljType[tmp.unit] : GLJTypeConst.MAIN_MATERIAL
+            };
+            unitPriceInsertData.push(unitPriceData);
+        }
+
+        // 整理完后开始插入数据
+        let addResult = await this.add(gljInsertData);
+        if (!addResult) {
+            throw '组成物插入项目工料机失败!';
+        }
+        let unitPriceModel = new UnitPriceModel();
+        let addUnitPriceResult = await unitPriceModel.add(unitPriceInsertData);
+        if (!addUnitPriceResult) {
+            throw '组成物插入单价数据失败!';
+        }
+
+    }
+
+    /**
+     * 获取组成物具体数据
+     *
+     * @param {Number} projectGLJId
+     * @param {Number} unitPriceFileId
+     * @return {Promise}
+     */
+    async getCompositionList(projectGLJId, unitPriceFileId) {
+        let result = [];
+        try {
+            // 查找对应的项目工料机数据
+            let projectGLJData = await this.getDataById(projectGLJId);
+
+            let allowType = [GLJTypeConst.MIX_RATIO, GLJTypeConst.CONCRETE, GLJTypeConst.MORTAR];
+            if (projectGLJData.unit_price === null || allowType.indexOf(projectGLJData.unit_price.type) < 0) {
+                throw '找不到相关项目工料机';
+            }
+
+            // 查找对应的项目工料机数据
+            let [gljData, compositionList] = await this.getCompositionGLJList(projectGLJData.code, projectGLJData.project_id);
+
+            if (gljData.length <= 0) {
+                throw '没有对应的组成物项目工料机';
+            }
+
+            // 整理出code和name查找相关单价数据
+            let codeList = [];
+            let nameList = [];
+            for(let tmp of gljData) {
+                codeList.push(tmp.code);
+                nameList.push(tmp.name);
+            }
+            // 查找对应的单价数据
+            let unitPriceModel = new UnitPriceModel();
+            let condition = {code: {"$in": codeList}, name: {"$in": nameList}, unit_price_file_id: unitPriceFileId};
+            let unitPriceList = await unitPriceModel.findDataByCondition(condition, null, false);
+
+            // 整理数据
+            let unitPriceData = {};
+            for(let tmp of unitPriceList) {
+                unitPriceData[tmp.code + tmp.name] = tmp;
+            }
+
+            this.combineData(gljData, unitPriceData, []);
+
+            result = gljData;
+        } catch (error) {
+            console.log(error);
+            result = [];
+        }
+
+        return result;
+    }
+
+    /**
+     * 获取混凝土等有组成物相关工料机对应的组成物项目工料机数据
+     *
+     * @param {String} code
+     * @param {Number} projectId
+     * @param {String} indexBy
+     * @return {Promise} 返回组成物工料机数据和组成物列表数据
+     */
+    async getCompositionGLJList(code, projectId, indexBy = null) {
+        // 首先获取对应组成物列表
+        let stdMixRatioModel = new STDMixRatioModel();
+        let compositionList = await stdMixRatioModel.getDataByCode(code);
+
+        if (compositionList.length <= 0) {
+            throw '不存在对应的组成物';
+        }
+
+        let codeList = [];
+        let nameList = [];
+        for(let tmp of compositionList) {
+            codeList.push(tmp.code);
+            nameList.push(tmp.name);
+        }
+
+        // 查找对应的项目工料机数据
+        let condition = {code: {"$in": codeList}, name: {"$in": nameList}, project_id: projectId};
+        let gljData = await this.findDataByCondition(condition, null, false, indexBy);
+
+        return [gljData, compositionList];
+    }
+
+    /**
+     * 根据条件获取对应项目工料机数据
+     *
+     * @param {Number} id
+     * @return {Promise}
+     */
+    async getDataById(id) {
+
+        // 查找对应的项目工料机数据
+        let projectGLJData = await this.findDataByCondition({id: id});
+        if (projectGLJData === null) {
+            throw '没有找到对应数据';
+        }
+
+        // 查找对应的单价数据
+        let unitPriceModel = new UnitPriceModel();
+        let unitPrice = await unitPriceModel.findDataByCondition({code: projectGLJData.code, name: projectGLJData.name});
+
+        projectGLJData.unit_price = unitPrice;
+
+        return projectGLJData;
+    }
+
 }
 
 export default GLJListModel;

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

@@ -1,70 +0,0 @@
-/**
- * 工料机数据源模块
- *
- * @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;

+ 13 - 5
modules/glj/models/schemas/glj.js

@@ -13,13 +13,19 @@ let modelSchema = {
     // 自增id
     id: Number,
     // 工料机总库ID
-    glj_repository_id: Number,
+    glj_id: Number,
     // 标段ID
     project_id: Number,
     // 编码
-    code: String,
+    code: {
+        type: String,
+        index: true
+    },
     // 名称
-    name: String,
+    name: {
+        type: String,
+        index: true
+    },
     // 是否暂估 (0为否 1为是)
     is_evaluate: {
         type: Number,
@@ -56,9 +62,11 @@ let modelSchema = {
         default: 1
     },
     // 显示调整基价
-    adjust_price: String,
+    adjust_price: Number,
     // 显示关联单价文件的字段
-    unit_price: Schema.Types.Mixed
+    unit_price: Schema.Types.Mixed,
+    // 显示关联的消耗量
+    quantity: String
 };
 let model = mongoose.model(collectionName, new Schema(modelSchema, {versionKey: false}));
 

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

@@ -1,29 +0,0 @@
-/**
- * 数据结构
- *
- * @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}));

+ 15 - 4
modules/glj/models/schemas/unit_price.js

@@ -13,13 +13,19 @@ let modelSchema = {
     // 自增ID
     id: Number,
     // 基价单价
-    base_price: String,
+    base_price: Number,
     // 市场单价
-    market_price: String,
+    market_price: Number,
     // 编码
-    code: String,
+    code: {
+        type: String,
+        index: true
+    },
     // 名称
-    name: String,
+    name: {
+        type: String,
+        index: true
+    },
     // 规格型号
     specs: {
         type: String,
@@ -27,6 +33,11 @@ let modelSchema = {
     },
     // 单位
     unit: String,
+    // 消耗量(有别于总消耗,此字段记录配合比的消耗量)
+    consumption: {
+        type: Number,
+        default: 0
+    },
     // 类型
     type: Number,
     // 单价文件表id

+ 4 - 1
modules/glj/models/schemas/unit_price_file.js

@@ -13,7 +13,10 @@ let modelSchema = {
     // 自增id
     id: Number,
     // 标段id
-    project_id: Number,
+    project_id: {
+        type: Number,
+        index: true
+    },
     // 显示名称
     name: String,
 };

+ 8 - 2
modules/glj/models/unit_price_model.js

@@ -130,8 +130,14 @@ class UnitPriceModel extends BaseModel {
      */
     async add(data) {
         let counterModel = new CounterModel();
-        let unitPriceId = await counterModel.getId(collectionName);
-        data.id = unitPriceId;
+        if (data instanceof Array) {
+            // 如果是批量新增
+            for(let tmp in data) {
+                data[tmp].id = await counterModel.getId(collectionName);
+            }
+        } else {
+            data.id = await counterModel.getId(collectionName);
+        }
 
         this.setScene('add');
         return this.db.model.create(data);

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

@@ -14,6 +14,7 @@ let gljController = new GLJController();
 // action定义区域
 router.get('/', gljController.init, gljController.index);
 router.post('/update', gljController.init, gljController.updateData);
+router.get('/get-ratio', gljController.init, gljController.getMixRatio);
 
 router.get('/test', gljController.init, gljController.test);
 router.get('/testModify', gljController.init, gljController.testModify);

+ 39 - 2
web/glj/html/glj_index.html

@@ -21,7 +21,43 @@
         <div class="container-fluid">
             <div class="row">
                 <div class="main-content col-lg-12 p-0">
-                    <div class="main-data-full" id="test">
+                    <div class="top-content">
+                        <div class="main-data-top" id="project-glj">
+                        </div>
+                    </div>
+                    <div class="bottom-content">
+                        <ul class="nav nav-tabs" role="tablist">
+                            <li class="nav-item">
+                                <a class="nav-link active" data-toggle="tab" href="#de" role="tab">相关定额</a>
+                            </li>
+                            <li class="nav-item">
+                                <a class="nav-link" data-toggle="tab" href="#ph" role="tab">配合比表</a>
+                            </li>
+                            <li class="nav-item">
+                                <a class="nav-link" data-toggle="tab" href="#jx" role="tab">机械单价</a>
+                            </li>
+                        </ul>
+                        <!-- Tab panes -->
+                        <div class="tab-content">
+                            <div class="tab-pane active" id="de" role="tabpanel">
+                                <div class="main-data-bottom ovf-hidden">
+                                    相关定额
+                                </div>
+                            </div>
+                            <div class="tab-pane" id="ph" role="tabpanel">
+                                <div class="main-data-bottom" id="mix-ratio">
+                                </div>
+                            </div>
+                            <div class="tab-pane" id="jx" role="tabpanel">
+                                <div class="main-data-bottom">
+                                    <table class="table table-sm table-bordered m-0">
+                                        <thead>
+                                        <tr><th></th><th>编码</th><th>名称</th><th>单位</th><th>基价单价</th><th>调整基价</th><th>用量</th></tr>
+                                        </thead>
+                                    </table>
+                                </div>
+                            </div>
+                        </div>
                     </div>
                 </div>
             </div>
@@ -45,4 +81,5 @@
 </script>
 <%include footer.html %>
 <script type="text/javascript" src="/web/glj/js/socket.js"></script>
-<script type="text/javascript" src="/web/glj/js/glj_index.js"></script>
+<script type="text/javascript" src="/web/glj/js/glj_index.js"></script>
+<script type="text/javascript" src="/web/glj/js/mix_ratio.js"></script>

+ 180 - 138
web/glj/js/glj_index.js

@@ -6,17 +6,43 @@
  * @version
  */
 let header = [];
-let sheet = null;
+let gljSheet = null;
+let sourceData = [];
+let spread = null;
+let isChanging = false;
+let gljActiveRowIndex = 0;
 $(document).ready(function () {
-    // excel
-     header = [
+
+    // 初始化表格
+    initExcel();
+
+    // 是否主动更改数据
+    $("#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 = [];
+    });
+
+});
+
+/**
+ * 初始化表格
+ *
+ */
+function initExcel() {
+    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: 'quantity', 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'},
@@ -29,161 +55,56 @@ $(document).ready(function () {
         {name: 'UID', field: 'unit_price.id', visible: false},
     ];
     // 数据转换格式
-    let sourceData = JSON.parse(jsonData);
-
+    sourceData = JSON.parse(jsonData);
+    let columnInfo = [];
     let setting = {
         header: []
     };
     for(let tmp of header) {
         setting.header.push({headerName: tmp.name, headerWidth: 120});
+        columnInfo.push({name: tmp.field, displayName: tmp.name, visible: tmp.visible, cellType: tmp.cellType, size: 120});
     }
 
-    let spread = sheetCommonObj.buildSheet(document.getElementById("test"), setting, sourceData.length);
+    spread = sheetCommonObj.buildSheet(document.getElementById("project-glj"), setting, sourceData.length);
     spread.options.scrollbarShowMax = true;
     spread.options.scrollbarMaxAlign = true;
     spread.options.showHorizontalScrollbar = true;
-    sheet = spread.getActiveSheet();
+    gljSheet = spread.getActiveSheet();
 
     // 设置表单不可编辑
-    sheet.options.isProtected = true;
+    gljSheet.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);
+    gljSheet.setStyle(-1, 10, getStyle(centerStyleSetting), GC.Spread.Sheets.SheetArea.viewport);
+    gljSheet.setStyle(-1, 15, getStyle(centerStyleSetting), GC.Spread.Sheets.SheetArea.viewport);
+    gljSheet.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);
+    gljSheet.setStyle(-1, 6, getStyle(rightStyleSetting), GC.Spread.Sheets.SheetArea.viewport);
+    gljSheet.setStyle(-1, 7, getStyle(rightStyleSetting), GC.Spread.Sheets.SheetArea.viewport);
+    gljSheet.setStyle(-1, 8, getStyle(rightStyleSetting), GC.Spread.Sheets.SheetArea.viewport);
+    gljSheet.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);
+    gljSheet.getRange(-1, 9, -1, 1).locked(false);
+    gljSheet.getRange(-1, 10, -1, 1).locked(false);
+    gljSheet.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);
-            }
+    // 设置数据
+    gljSheet.autoGenerateColumns = false;
+    gljSheet.bindColumns(columnInfo);
+    gljSheet.setDataSource(sourceData);
 
-            // 如果不为材料“是否暂估列”根据条件显示
-            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++;
-    }
-
-
-    // 是否主动更改数据
-    $("#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 = [];
-    });
+    specialColumn(sourceData);
 
     // 绑定事件
-    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);
-                }
-            }
-        });
-    });
+    gljSheet.bind(GC.Spread.Sheets.Events.ValueChanged, updateBindEvent);
 
     // 绑定双击事件
-    sheet.bind(GC.Spread.Sheets.Events.CellDoubleClick, function (element, info) {
+    gljSheet.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 ?
@@ -191,7 +112,7 @@ $(document).ready(function () {
 
         // 获取类型
         let typeColumn = getFieldColumn(header, 'unit_price.type');
-        let type = sheet.getValue(row, typeColumn);
+        let type = gljSheet.getValue(row, typeColumn);
 
         // 如果类型为混凝土、砂浆、配合比、机械,则提示
         if (field === 'unit_price.market_price' && canNotChangeTypeId.indexOf(type) >= 0) {
@@ -199,7 +120,11 @@ $(document).ready(function () {
         }
     });
 
-});
+    // 绑定单击事件
+    gljSheet.bind(GC.Spread.Sheets.Events.CellClick, function (element, info) {
+        gljActiveRowIndex = gljSheet.getActiveRowIndex();
+    });
+}
 
 /**
  * 生成样式
@@ -272,7 +197,7 @@ function successTrigger(field, info) {
             let row = info.row;
             // 获取类型
             let typeColumn = getFieldColumn(header, 'unit_price.type');
-            let type = sheet.getValue(row, typeColumn);
+            let type = gljSheet.getValue(row, typeColumn);
 
             // 基价单价的计算
             basePriceCalculate(type, info);
@@ -288,6 +213,37 @@ function successTrigger(field, info) {
 }
 
 /**
+ * 设置特殊单元格数据
+ *
+ * @param {object} sourceData
+ * @return {void}
+ */
+function specialColumn(sourceData) {
+    let rowCounter = 0;
+    // 获取是否暂估的列号
+    let isEvaluateColumn = getFieldColumn(header, 'is_evaluate');
+    // 获取市场单价列号
+    let marketPriceColumn = getFieldColumn(header, 'unit_price.market_price');
+    for(let data of sourceData) {
+        // 只有材料才显示是否暂估
+        if (materialIdList.indexOf(data.unit_price.type + '') < 0) {
+            let string = new GC.Spread.Sheets.CellTypes.Text();
+            gljSheet.setCellType(rowCounter, isEvaluateColumn, string, GC.Spread.Sheets.SheetArea.viewport);
+            // 锁定该单元格
+            gljSheet.getRange(rowCounter, isEvaluateColumn, 1, 1).locked(true);
+            gljSheet.setValue(rowCounter, isEvaluateColumn, '');
+        }
+        // 如果类型为混凝土、砂浆、配合比、机械,则市场单价不能修改
+        if (canNotChangeTypeId.indexOf(data.unit_price.type) >= 0) {
+            // 锁定该单元格
+            gljSheet.getRange(rowCounter, marketPriceColumn, 1, 1).locked(true);
+        }
+        rowCounter++;
+    }
+}
+
+
+/**
  * 基价单价计算
  *
  * @param {Number} type
@@ -300,7 +256,7 @@ function basePriceCalculate(type, info) {
         // 主材、设备自动赋值基价单价=市场单价
         case GLJTypeConst.MAIN_MATERIAL:
         case GLJTypeConst.EQUIPMENT:
-            sheet.setValue(info.row, basePriceColumn, info.newValue);
+            gljSheet.setValue(info.row, basePriceColumn, info.newValue);
             break;
     }
 }
@@ -320,7 +276,7 @@ function adjustPriceCalculate(type, info) {
         case GLJTypeConst.MAIN_MATERIAL:
         case GLJTypeConst.EQUIPMENT:
             let basePrice = sheet.getValue(info.row, basePriceColumn);
-            sheet.setValue(info.row, adjustPriceColumn, basePrice);
+            gljSheet.setValue(info.row, adjustPriceColumn, basePrice);
             break;
 
     }
@@ -337,9 +293,95 @@ function marketPriceCalculate(type, info) {
     switch (type) {
         // 人工、材料(普通材料)触发 需计算混凝土、砂浆、配合比、机械的市场单价 @todo 后续添加
         case GLJTypeConst.LABOUR:
-        case GLJTypeConst.LABOUR:
+        case GLJTypeConst.GENERAL_MATERIAL:
             // 计算
             console.log('触发计算');
             break;
     }
+}
+
+/**
+ * 筛选数据
+ *
+ * @param {Array} typeList
+ * @return {void}
+ */
+function filterDataByType(type) {
+    sourceData = [];
+    let testData = JSON.parse(jsonData);
+    for(let tmp of testData) {
+        if (type.indexOf(tmp.unit_price.type) >= 0) {
+            sourceData.push(tmp);
+        }
+    }
+    gljSheet.setDataSource(sourceData);
+}
+
+/**
+ * 绑定事件
+ *
+ * @param {object} element
+ * @param {object} info
+ * @return {void|boolean}
+ */
+function updateBindEvent(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('数据格式错误,请重新输入!');
+        gljSheet.setValue(row, column, info.oldValue);
+        return false;
+    }
+
+    // 获取id
+    let idColumn = getFieldColumn(header, idString);
+    if (idColumn < 0) {
+        return false;
+    }
+    let id = gljSheet.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) {
+                gljSheet.setValue(row, column, info.oldValue);
+                alert('更改数据失败!');
+            } else {
+                // 成功则触发相应事件
+                successTrigger(field, info);
+            }
+        }
+    });
 }

+ 65 - 0
web/glj/js/mix_ratio.js

@@ -0,0 +1,65 @@
+/**
+ * 配合比相关
+ *
+ * @author CaiAoLin
+ * @date 2017/7/10
+ * @version
+ */
+let mixRatioHeader = [];
+let mixRatioSheet = null;
+let mixRatioSpread = null;
+$(document).ready(function() {
+
+    mixRatioHeader = [
+        {name: '编码', field: 'code', visible: true},
+        {name: '名称', field: 'name', visible: true},
+        {name: '单位', field: 'unit_price.unit', visible: true},
+        {name: 'ID', field: 'id', visible: false},
+        {name: '类型', field: 'unit_price.type', visible: false},
+        {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: 'quantity', visible: true},
+    ];
+
+    let setting = {
+        header: []
+    };
+    for(let tmp of mixRatioHeader) {
+        setting.header.push({headerName: tmp.name, headerWidth: 120});
+    }
+
+    mixRatioSpread = sheetCommonObj.buildSheet(document.getElementById("mix-ratio"), setting, 3);
+    mixRatioSpread.options.scrollbarShowMax = true;
+    mixRatioSpread.options.scrollbarMaxAlign = true;
+    mixRatioSpread.options.showHorizontalScrollbar = true;
+    mixRatioSheet = mixRatioSpread.getActiveSheet();
+
+    // 设置表单不可编辑
+    mixRatioSheet.options.isProtected = true;
+
+    // 切换tab触发refresh
+    $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
+        let tagString = $(e.target).text();
+        if (tagString === "配合比表" && mixRatioSpread !== null) {
+            // 筛选数据显示(显示混凝土、砂浆、配合比)
+            filterDataByType([GLJTypeConst.CONCRETE, GLJTypeConst.MORTAR, GLJTypeConst.MIX_RATIO]);
+
+            // 获取工料机当前选中的行号
+            console.log(gljSheet.getActiveRowIndex());
+            mixRatioSpread.refresh();
+        }
+    });
+
+
+});
+
+/**
+ * 根据id获取对应的配合比数据
+ *
+ * @param {Number} id
+ * @return {void}
+ */
+function getMixRatioData(id) {
+
+}