Parcourir la source

提交配合比相关操作

caiaolin il y a 8 ans
Parent
commit
d05c147b5c

+ 8 - 6
modules/common/base/base_model.js

@@ -51,17 +51,19 @@ class BaseModel {
      * @return {Promise}
      */
     async findDataByCondition(condition, fields = null, singleData = true, indexBy = null) {
-        let result = null;
+        let result = [];
         if (Object.keys(condition).length <= 0) {
             return result;
         }
 
-        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;
+        result = singleData ? await this.db.findOne(condition, fields) : await this.db.find(condition, fields);
+
+        if (indexBy !== null && !singleData && result.length > 0) {
+            let tmpResult = {};
+            for(let tmp of result) {
+                tmpResult[tmp[indexBy]] = tmp;
             }
+            result = tmpResult;
         }
         return result;
     }

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

@@ -34,7 +34,6 @@ class STDMixRatioModel extends BaseModel {
             if (code === '') {
                 throw '编码为空';
             }
-
             result = await this.findDataByCondition({connect_code: code}, null, false);
         } catch (error) {
             console.log('std_mix_ratio_model:' + error);

+ 49 - 12
modules/glj/controllers/glj_controller.js

@@ -10,6 +10,7 @@ import GLJTypeConst from "../../common/const/glj_type_const";
 import GLJListModel from "../models/glj_list_model";
 import UnitPriceModel from "../models/unit_price_model";
 import UnitPriceFileModel from "../models/unit_price_file_model";
+import MixRatioModel from "../models/mix_ratio_model";
 
 class GLJController extends BaseController {
 
@@ -55,6 +56,7 @@ class GLJController extends BaseController {
             let renderData = {
                 gljList: JSON.stringify(gljList),
                 materialIdList: gljListModel.materialIdList,
+                ownCompositionTypes: gljListModel.ownCompositionTypes,
                 hostname: request.hostname,
                 roomId: unitPriceFileId,
                 GLJTypeConst: JSON.stringify(GLJTypeConst)
@@ -86,7 +88,7 @@ class GLJController extends BaseController {
         };
         try {
             // 可编辑的字段
-            let editableField = ['is_evaluate', 'unit_price.market_price', 'is_adjust_price'];
+            let editableField = ['is_evaluate', 'unit_price.market_price', 'is_adjust_price', 'mix_ratio.consumption'];
             if (editableField.indexOf(field) < 0) {
                 throw '对应字段不能编辑';
             }
@@ -112,7 +114,34 @@ class GLJController extends BaseController {
                 case 'unit_price':
                     model = new UnitPriceModel();
                     // 更新数据
-                    result = await model.updatePriceById(id, updateData);
+                    result = await model.updatePrice({id: id}, updateData);
+                    break;
+                case 'mix_ratio':
+                    let marketPrice = request.body.market_price;
+                    let basePrice = request.body.base_price;
+
+                    model = new MixRatioModel();
+                    result = await model.updateById(id, updateData);
+
+                    if (result && marketPrice && basePrice) {
+                        // 修改后更新父节点的项目工料机市场单价
+                        let mixRatioData = await model.findDataByCondition({id: id});
+                        if (mixRatioData.length <= 0) {
+                            break;
+                        }
+                        // 更新市场单价和基价单价
+                        let condition = {code: mixRatioData.connect_code, unit_price_file_id: mixRatioData.unit_price_file_id};
+                        let unitPriceUpdate = {
+                            base_price: basePrice,
+                            market_price: marketPrice
+                        };
+                        let unitPriceModel = new UnitPriceModel();
+                        let unitPriceResult = await unitPriceModel.updatePrice(condition, unitPriceUpdate);
+                        if (!unitPriceResult) {
+                            throw '更新单价数据失败';
+                        }
+                    }
+
                     break;
             }
 
@@ -134,8 +163,11 @@ class GLJController extends BaseController {
      */
     async getMixRatio(request, response) {
         let projectGLJId = request.body.id;
-        // let projectId = request.body.project_id;
-        let projectId = 1;
+        let projectId = request.body.project_id;
+        let responseData = {
+            err: 0,
+            data: null
+        };
         try {
             // 获取标段对应的单价文件id
             let unitPriceFileModel = new UnitPriceFileModel();
@@ -147,13 +179,18 @@ class GLJController extends BaseController {
             let unitPriceFileId = unitPriceFile.id;
 
             let gljListModel = new GLJListModel();
-            let result = await gljListModel.getCompositionList(152, unitPriceFileId);
-            console.log(result);
+            let result = await gljListModel.getCompositionList(projectGLJId, unitPriceFileId);
+            if (result.length <= 0) {
+                throw '没有找到数据';
+            }
+
+            responseData.data = JSON.stringify(result);
         } catch (error) {
             console.log(error);
+            responseData.err = 1;
         }
 
-        response.end('end');
+        response.json(responseData);
     }
 
     /**
@@ -166,15 +203,15 @@ class GLJController extends BaseController {
     async test(request, response) {
         // 从定额库获取的数据
         let data = {
-            glj_id: 54,
+            glj_id: 801,
             project_id: 1,
             code: '81040102',
-            name: '水泥白石子浆 1∶1.5',
-            specs: '1∶1.5',
+            name: 'C15特细砂干硬性混凝土',
+            specs: 'C15',
             unit: 'm³',
             type: GLJTypeConst.CONCRETE,
-            base_price: 479.25,
-            market_price: 479.25
+            base_price: 323.25,
+            market_price: 323.25
         };
         try {
             let gljListModel = new GLJListModel();

+ 85 - 11
modules/glj/models/glj_list_model.js

@@ -15,6 +15,7 @@ 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";
+import MixRatioModel from "./mix_ratio_model";
 
 class GLJListModel extends BaseModel {
 
@@ -27,6 +28,14 @@ class GLJListModel extends BaseModel {
         GLJTypeConst.COMMERCIAL_CONCRETE, GLJTypeConst.COMMERCIAL_MORTAR];
 
     /**
+     * 拥有组成物的工料机类型id
+     *
+     * @var {Array}
+     */
+    ownCompositionTypes = [GLJTypeConst.CONCRETE, GLJTypeConst.MORTAR, GLJTypeConst.MIX_RATIO,
+        GLJTypeConst.COMMERCIAL_CONCRETE, GLJTypeConst.COMMERCIAL_MORTAR];
+
+    /**
      * 构造函数
      *
      * @return {void}
@@ -81,8 +90,14 @@ class GLJListModel extends BaseModel {
 
             // 整理获取工料机ID list
             let gljIdList = [];
+            // 整理获取有组成物的项目工料机编码
+            let projectGLJCode = [];
             for(let tmp of gljData) {
                 gljIdList.push(tmp.id);
+                // 有组成物的类型才入数组
+                if (this.ownCompositionTypes.indexOf(tmp.type)) {
+                    projectGLJCode.push(tmp.code);
+                }
             }
 
             // 从定额工料机库中获取消耗量
@@ -97,8 +112,21 @@ class GLJListModel extends BaseModel {
                 quantityList[tmp.projectGLJID] = tmp.quantity;
             }
 
+            // 查找组成物的消耗量
+            let totalComposition = {};
+            if (projectGLJCode.length > 0) {
+                let mixRatioModel = new MixRatioModel();
+                condition = {connect_code: {"$in": projectGLJCode}, unit_price_file_id: unitPriceFileId};
+                let mixRatioList = await mixRatioModel.findDataByCondition(condition, null, false);
+                for (let tmp of mixRatioList) {
+                    totalComposition[tmp.connect_code] = totalComposition[tmp.connect_code] === undefined ? tmp.consumption :
+                        totalComposition[tmp.connect_code] + tmp.consumption;
+                    totalComposition[tmp.connect_code] = Number(totalComposition[tmp.connect_code].toFixed(2));
+                }
+            }
+
             // 组合单价数据
-            this.combineData(gljData, unitPriceList, quantityList);
+            this.combineData(gljData, unitPriceList, quantityList, [], totalComposition);
 
             // 排序
             gljData.sort(function (a, b) {
@@ -118,9 +146,11 @@ class GLJListModel extends BaseModel {
      * @param {object} gljList
      * @param {object} unitPriceList
      * @param {object} quantityList
+     * @param {object} mixRatioData 组合物明细数据
+     * @param {object} totalComposition 组合物父工料机统计数据
      * @return {void}
      */
-    combineData(gljList, unitPriceList, quantityList) {
+    combineData(gljList, unitPriceList, quantityList = {}, mixRatioData = {}, totalComposition = {}) {
         // 循环组合数据
         for(let glj of gljList) {
             if (glj.code === undefined) {
@@ -132,8 +162,14 @@ class GLJListModel extends BaseModel {
                 continue;
             }
 
-            // 组合消耗量
+            // 消耗量赋值
             glj.quantity = quantityList[glj.id] !== undefined ? quantityList[glj.id] : 0;
+            glj.quantity = totalComposition[glj.code] !== undefined ? totalComposition[glj.code] : glj.quantity;
+
+            // 组成物消耗量
+            let gljId = glj.glj_id + '';
+            glj.consumption = mixRatioData[gljId] !== undefined ? mixRatioData[gljId].consumption : 0;
+            glj.mix_ratio_id = mixRatioData[gljId] !== undefined ? mixRatioData[gljId].id : 0;
 
             // 计算调整基价
             switch (glj.unit_price.type + '') {
@@ -167,6 +203,7 @@ class GLJListModel extends BaseModel {
             }
             // 首先查找是否有同编码同名称的工料机数据
             let projectGljData = await this.findDataByCondition({code: data.code, project_id: data.project_id});
+            let isAddProjectGLJ = false;
             // 如果找不到数据则新增
             if (!projectGljData) {
                 // 新增单条记录 (两个操作本来应该是事务操作,然而mongodb事务支持比较弱,就当作是都可以顺利执行)
@@ -174,6 +211,7 @@ class GLJListModel extends BaseModel {
                 if (!gljInsertData) {
                     throw '新增项目工料机失败!';
                 }
+                isAddProjectGLJ = true;
                 projectGljData = gljInsertData;
             }
 
@@ -185,9 +223,9 @@ class GLJListModel extends BaseModel {
             }
             let unitPriceFileId = unitPriceFile.id;
 
-            // 判断类型,如果是混凝土、砂浆或者配合比则查找对应的组成物
-            if (data.type === GLJTypeConst.CONCRETE || data.type === GLJTypeConst.MORTAR ||
-                data.type === GLJTypeConst.MIX_RATIO) {
+            // 判断类型,如果是混凝土、砂浆或者配合比则查找对应的组成物(前提是没有对应的项目工料机数据)
+            if (isAddProjectGLJ && (data.type === GLJTypeConst.CONCRETE || data.type === GLJTypeConst.MORTAR ||
+                data.type === GLJTypeConst.MIX_RATIO)) {
                 this.compositionInit(data.code, data.project_id, unitPriceFileId);
             }
 
@@ -336,6 +374,7 @@ class GLJListModel extends BaseModel {
 
     /**
      * 工料机中组成物操作
+     * 该方法只在确保没有对应项目工料机的时候才会调用
      *
      * @param {String} code
      * @param {Number} projectId
@@ -343,10 +382,30 @@ class GLJListModel extends BaseModel {
      * @return {void}
      */
     async compositionInit(code, projectId, unitPriceFileId) {
-
         // 查找对应组成物的项目工料机数据
         let [projectGljList, compositionList] = await this.getCompositionGLJList(code, projectId, 'name');
 
+        // 整理配合比待插入数据
+        let mixRatioInsertData = [];
+        for (let tmp of compositionList) {
+            // 配合比数据插入
+            let mixRatioData = {
+                consumption: tmp.consumption,
+                glj_id: tmp.glj_id,
+                unit_price_file_id: unitPriceFileId,
+                connect_code: tmp.connect_code
+            };
+            mixRatioInsertData.push(mixRatioData);
+        }
+
+        // 插入配合比表
+        // 因为有可能项目工料机与单价数据已存在,但配合比数据不存在,所以先插入配合比,后续判断如果存在项目工料机则可以省下数据库操作
+        let mixRatioModel = new MixRatioModel();
+        let addMixRatioResult = await mixRatioModel.add(mixRatioInsertData);
+        if (!addMixRatioResult) {
+            throw '组成物插入单价数据失败!';
+        }
+
         // 如果已经存在则后续操作停止
         if(projectGljList.length === compositionList.length) {
             return;
@@ -400,19 +459,22 @@ class GLJListModel extends BaseModel {
                 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) {
@@ -449,14 +511,22 @@ class GLJListModel extends BaseModel {
             // 整理出code和name查找相关单价数据
             let codeList = [];
             let nameList = [];
+            let gljIdList = [];
             for(let tmp of gljData) {
                 codeList.push(tmp.code);
                 nameList.push(tmp.name);
+                gljIdList.push(tmp.glj_id);
             }
+
             // 查找对应的单价数据
             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 unitPriceList = await unitPriceModel.findDataByCondition(condition, {_id: 0}, false);
+
+            // 查找对应的配合比数据
+            let mixRatioModel = new MixRatioModel();
+            condition = {glj_id: {"$in": gljIdList}, connect_code: projectGLJData.code, unit_price_file_id: unitPriceFileId};
+            let mixRatioData = await mixRatioModel.findDataByCondition(condition, {_id: 0}, false, 'glj_id');
 
             // 整理数据
             let unitPriceData = {};
@@ -464,8 +534,12 @@ class GLJListModel extends BaseModel {
                 unitPriceData[tmp.code + tmp.name] = tmp;
             }
 
-            this.combineData(gljData, unitPriceData, []);
+            this.combineData(gljData, unitPriceData, [], mixRatioData);
 
+            // 排序
+            gljData.sort(function (a, b) {
+                return parseInt(a.code) - parseInt(b.code);
+            });
             result = gljData;
         } catch (error) {
             console.log(error);
@@ -501,7 +575,7 @@ class GLJListModel extends BaseModel {
 
         // 查找对应的项目工料机数据
         let condition = {code: {"$in": codeList}, name: {"$in": nameList}, project_id: projectId};
-        let gljData = await this.findDataByCondition(condition, null, false, indexBy);
+        let gljData = await this.findDataByCondition(condition, {_id: 0}, false, indexBy);
 
         return [gljData, compositionList];
     }

+ 83 - 0
modules/glj/models/mix_ratio_model.js

@@ -0,0 +1,83 @@
+/**
+ * 配合比业务模型
+ *
+ * @author CaiAoLin
+ * @date 2017/7/12
+ * @version
+ */
+import BaseModel from "../../common/base/base_model";
+import {default as MixRatioSchema, collectionName as collectionName} from "./schemas/mix_ratio";
+import CounterModel from "./counter_model"
+
+class MixRatioModel extends BaseModel {
+
+    /**
+     * 构造函数
+     *
+     * @return {void}
+     */
+    constructor() {
+        let parent = super();
+        parent.model = MixRatioSchema;
+        parent.init();
+    }
+
+    /**
+     * 设置场景
+     *
+     * @param {string} scene
+     * @return {void}
+     */
+    setScene(scene = '') {
+        switch (scene) {
+            // 新增数据的验证规则
+            case 'add':
+                this.model.schema.path('glj_id').required(true);
+                this.model.schema.path('consumption').required(true);
+                this.model.schema.path('unit_price_file_id').required(true);
+                this.model.schema.path('connect_code').required(true);
+                break;
+        }
+    }
+
+    /**
+     * 新增配合比数据(自动判断是否存在)
+     *
+     * @param {object} data
+     * @return {Promise}
+     */
+    async add(data) {
+        let counterModel = new CounterModel();
+        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);
+    }
+
+    /**
+     * 更新数据
+     *
+     * @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 MixRatioModel;

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

@@ -66,7 +66,11 @@ let modelSchema = {
     // 显示关联单价文件的字段
     unit_price: Schema.Types.Mixed,
     // 显示关联的消耗量
-    quantity: String
+    quantity: Number,
+    // 显示组成物的消耗量
+    consumption: Number,
+    // 显示关联配合比的id
+    mix_ratio_id: Number
 };
 let model = mongoose.model(collectionName, new Schema(modelSchema, {versionKey: false}));
 

+ 34 - 0
modules/glj/models/schemas/mix_ratio.js

@@ -0,0 +1,34 @@
+/**
+ * 配合比数据结构
+ *
+ * @author CaiAoLin
+ * @date 2017/7/12
+ * @version
+ */
+import mongoose from "mongoose";
+
+let Schema = mongoose.Schema;
+let collectionName = 'mix_ratio';
+let modelSchema = {
+    // 自增id
+    id: Number,
+    // 消耗量(有别于总消耗,此字段记录配合比的消耗量)
+    consumption: {
+        type: Number,
+        default: 0
+    },
+    // 工料机总库对应id (关联用)
+    glj_id: {
+        type: Number,
+        index: true
+    },
+    // 单价文件表id (因为选择单价文件后配合比数据也需要同步,所以记录单价文件id)
+    unit_price_file_id: Number,
+    // 关联项目工料机的code 不能关联id,因为单价文件导入别的项目后项目工料机id不同
+    connect_code: {
+        type: String,
+        index: true
+    },
+};
+let model = mongoose.model(collectionName, new Schema(modelSchema, {versionKey: false, collection: collectionName}));
+export {model as default, collectionName as collectionName};

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

@@ -33,11 +33,6 @@ let modelSchema = {
     },
     // 单位
     unit: String,
-    // 消耗量(有别于总消耗,此字段记录配合比的消耗量)
-    consumption: {
-        type: Number,
-        default: 0
-    },
     // 类型
     type: Number,
     // 单价文件表id

+ 6 - 7
modules/glj/models/unit_price_model.js

@@ -168,17 +168,16 @@ class UnitPriceModel extends BaseModel {
     /**
      * 更新市场单价
      *
-     * @param {Number} id
+     * @param {Object} condition
      * @param {Object} updateData
      * @return {Promise}
      */
-    async updatePriceById(id, updateData) {
-        id = parseInt(id);
-        if (isNaN(id) || id <= 0 || Object.keys(updateData).length <= 0) {
+    async updatePrice(condition, updateData) {
+        if (Object.keys(condition).length <= 0 || Object.keys(updateData).length <= 0) {
             return false;
         }
         // 首先查找相应的数据判断工料机类型
-        let unitPriceData = await this.findDataByCondition({id: id});
+        let unitPriceData = await this.findDataByCondition(condition);
         if (!unitPriceData) {
             throw '找不到对应的单价数据';
         }
@@ -192,8 +191,8 @@ class UnitPriceModel extends BaseModel {
                 break;
         }
 
-        let result = await this.updateById(id, updateData);
-        return result;
+        let result = await this.db.update(condition, updateData);
+        return result.ok !== undefined && result.ok === 1;
     }
 
 }

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

@@ -14,7 +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.post('/get-ratio', gljController.init, gljController.getMixRatio);
 
 router.get('/test', gljController.init, gljController.test);
 router.get('/testModify', gljController.init, gljController.testModify);

+ 6 - 4
web/glj/html/glj_index.html

@@ -28,13 +28,13 @@
                     <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>
+                                <a class="nav-link active" data-toggle="tab" data-name="ration" href="#de" role="tab">相关定额</a>
                             </li>
                             <li class="nav-item">
-                                <a class="nav-link" data-toggle="tab" href="#ph" role="tab">配合比表</a>
+                                <a class="nav-link" data-toggle="tab" data-name="mix-ratio" href="#ph" role="tab">配合比表</a>
                             </li>
                             <li class="nav-item">
-                                <a class="nav-link" data-toggle="tab" href="#jx" role="tab">机械单价</a>
+                                <a class="nav-link" data-toggle="tab" data-name="" href="#jx" role="tab">机械单价</a>
                             </li>
                         </ul>
                         <!-- Tab panes -->
@@ -76,10 +76,12 @@
     GLJTypeConst = JSON.parse(GLJTypeConst);
 
     // 混凝土、砂浆、配合比、机械 市场单价不能修改
-    let canNotChangeTypeId = [GLJTypeConst.CONCRETE, GLJTypeConst.MORTAR, GLJTypeConst.MIX_RATIO, GLJTypeConst.MACHINE];
+    let canNotChangeTypeId = '<- ownCompositionTypes %>';
+    canNotChangeTypeId = canNotChangeTypeId !== '' ? canNotChangeTypeId.split(",") : '';
 
 </script>
 <%include footer.html %>
 <script type="text/javascript" src="/web/glj/js/socket.js"></script>
+<script type="text/javascript" src="/web/glj/js/spread_common.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>

+ 56 - 63
web/glj/js/glj_index.js

@@ -14,7 +14,7 @@ let gljActiveRowIndex = 0;
 $(document).ready(function () {
 
     // 初始化表格
-    initExcel();
+    initGLJExcel();
 
     // 是否主动更改数据
     $("#message").on('click', '#load-data', function() {
@@ -34,7 +34,7 @@ $(document).ready(function () {
  * 初始化表格
  *
  */
-function initExcel() {
+function initGLJExcel() {
     header = [
         {name: '编码', field: 'code', visible: true},
         {name: '名称', field: 'name', visible: true},
@@ -122,66 +122,13 @@ function initExcel() {
 
     // 绑定单击事件
     gljSheet.bind(GC.Spread.Sheets.Events.CellClick, function (element, info) {
-        gljActiveRowIndex = gljSheet.getActiveRowIndex();
-    });
-}
-
-/**
- * 生成样式
- *
- * @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;
+        if (currentTag === 'mix-ratio') {
+            let projectGLJId = getActiveProjectGLJId();
+            // 获取数据
+            getMixRatioData(projectGLJId);
         }
-    }
-
-    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;
+    });
 }
 
 /**
@@ -328,7 +275,6 @@ 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 : '';
@@ -363,7 +309,7 @@ function updateBindEvent(element, info) {
     $.ajax({
         url: '/glj/update',
         type: 'post',
-        data: {id: id, field: field, value: value, model: model},
+        data: {id: id, field: field, value: value},
         dataType: 'json',
         error: function() {
             alert('数据传输有误!');
@@ -384,4 +330,51 @@ function updateBindEvent(element, info) {
             }
         }
     });
-}
+}
+
+/**
+ * 获取当前行的项目工料机id
+ *
+ * @param {Number} activeRow
+ * @return {Number}
+ */
+function getActiveProjectGLJId() {
+    let activeGLJRow = gljSheet.getActiveRowIndex();
+    // 获取当前行的工料机id
+    let gljIdColumn = getFieldColumn(header, 'id');
+    let gljId = gljSheet.getValue(activeGLJRow, gljIdColumn);
+    return gljId;
+}
+
+/**
+ * 设置总消耗量
+ *
+ * @param {Number} row
+ * @param {Number} change
+ * @return {void}
+ */
+function setGLJQuantity(row, change) {
+    let quantityColumn = getFieldColumn(header, 'quantity');
+    let oldValue = gljSheet.getValue(row, quantityColumn);
+
+    change = Number((oldValue + change).toFixed(2));
+    gljSheet.setValue(row, quantityColumn, change);
+}
+
+/**
+ * 设置对应字段数值
+ *
+ * @param {Number} row
+ * @param {String} field
+ * @param {Number} value
+ * @param {boolean} appendMode
+ * @return {void}
+ */
+function setGLJCellByField(row, field, value, appendMode) {
+    let columnIndex = getFieldColumn(header, field);
+    if (appendMode) {
+        let oldValue = gljSheet.getValue(row, columnIndex);
+        value = Number((oldValue + value).toFixed(2));
+    }
+    gljSheet.setValue(row, columnIndex, value);
+}

+ 197 - 15
web/glj/js/mix_ratio.js

@@ -8,8 +8,35 @@
 let mixRatioHeader = [];
 let mixRatioSheet = null;
 let mixRatioSpread = null;
+let currentTag = '';
 $(document).ready(function() {
 
+    initMixRatioExcel();
+
+    // 切换tab触发refresh
+    $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
+        currentTag = $(e.target).data('name');
+        if (currentTag === "mix-ratio" && mixRatioSpread !== null) {
+            // 筛选数据显示(显示混凝土、砂浆、配合比)
+            filterDataByType([GLJTypeConst.CONCRETE, GLJTypeConst.MORTAR, GLJTypeConst.MIX_RATIO]);
+
+            // 获取工料机当前选中的行号
+            let projectGLJId = getActiveProjectGLJId();
+
+            // 获取数据
+            getMixRatioData(projectGLJId);
+        }
+    });
+
+
+});
+
+/**
+ * 初始化excel
+ *
+ * @return {void}
+ */
+function initMixRatioExcel() {
     mixRatioHeader = [
         {name: '编码', field: 'code', visible: true},
         {name: '名称', field: 'name', visible: true},
@@ -18,15 +45,18 @@ $(document).ready(function() {
         {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},
+        {name: '市场单价', field: "unit_price.market_price", visible: true},
+        {name: '消耗量', field: 'consumption', visible: true, validator: 'number'},
+        {name: 'CID', field: 'mix_ratio_id', visible: false},
     ];
 
     let setting = {
         header: []
     };
+    let columnInfo = [];
     for(let tmp of mixRatioHeader) {
         setting.header.push({headerName: tmp.name, headerWidth: 120});
+        columnInfo.push({name: tmp.field, displayName: tmp.name, visible: tmp.visible, cellType: tmp.cellType, size: 120});
     }
 
     mixRatioSpread = sheetCommonObj.buildSheet(document.getElementById("mix-ratio"), setting, 3);
@@ -35,31 +65,183 @@ $(document).ready(function() {
     mixRatioSpread.options.showHorizontalScrollbar = true;
     mixRatioSheet = mixRatioSpread.getActiveSheet();
 
+    // 编码列号
+    let codeColumn = getFieldColumn(mixRatioHeader, 'code');
+    // 单位列号
+    let unitColumn = getFieldColumn(mixRatioHeader, 'unit_price.unit');
+    // 消耗量列号
+    let consumptionColumn = getFieldColumn(mixRatioHeader, 'consumption');
+
+    // 居中样式
+    let centerStyleSetting = {hAlign: 1};
+    mixRatioSheet.setStyle(-1, codeColumn, getStyle(centerStyleSetting), GC.Spread.Sheets.SheetArea.viewport);
+    mixRatioSheet.setStyle(-1, unitColumn, getStyle(centerStyleSetting), GC.Spread.Sheets.SheetArea.viewport);
+
     // 设置表单不可编辑
     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]);
+    // 设置可编辑列
+    mixRatioSheet.getRange(-1, consumptionColumn, -1, 1).locked(false);
 
-            // 获取工料机当前选中的行号
-            console.log(gljSheet.getActiveRowIndex());
-            mixRatioSpread.refresh();
+    // 绑定数据格式
+    mixRatioSheet.autoGenerateColumns = false;
+    mixRatioSheet.bindColumns(columnInfo);
+
+    // 绑定事件
+    mixRatioSheet.bind(GC.Spread.Sheets.Events.ValueChanged, updateConsumption);
+
+}
+
+/**
+ * 根据项目工料机id获取对应的配合比数据
+ *
+ * @param {Number} projectGLJid
+ * @return {void}
+ */
+function getMixRatioData(projectGLJid) {
+    $.ajax({
+        url: '/glj/get-ratio',
+        type: 'post',
+        data: {id: projectGLJid, project_id: 1},
+        error: function() {
+            alert('服务器有误');
+        },
+        beforeSend: function() {
+
+        },
+        success: function(response) {
+            if (response.err === 0) {
+                response.data = JSON.parse(response.data);
+                // 设置数据
+                mixRatioSheet.setDataSource(response.data);
+                mixRatioSpread.refresh();
+            } else {
+                alert('获取失败');
+            }
         }
     });
+}
+
+/**
+ * 更新消耗量
+ *
+ * @param {object} element
+ * @param {object} info
+ * @return {void|boolean}
+ */
+function updateConsumption(element, info) {
+    // 获取修改的数据
+    let column = info.col;
+    let row = info.row;
+    let field = mixRatioHeader[column] !== undefined && mixRatioHeader[column].field !== undefined ?
+        mixRatioHeader[column].field : '';
+    if (field === '') {
+        return false;
+    }
+    // 防止快速同时提交
+    if (isChanging) {
+        return false;
+    }
+    // 校验数据
+    let validator = mixRatioHeader[column].validator !== undefined ? mixRatioHeader[column].validator : null;
+    let value = info.newValue;
+    if (validator && !checkData(validator, value)) {
+        alert('数据格式错误,请重新输入!');
+        mixRatioSheet.setValue(row, column, info.oldValue);
+        return false;
+    }
 
+    // 获取id
+    let idColumn = getFieldColumn(mixRatioHeader, 'mix_ratio_id');
+    if (idColumn < 0) {
+        return false;
+    }
+    let id = mixRatioSheet.getValue(row, idColumn);
 
-});
+    // 计算父级3个价格
+    let maxRow = mixRatioSheet.getRowCount();
+    // 获取对应列的列号
+    let marketPriceColumn = getFieldColumn(mixRatioHeader, 'unit_price.market_price');
+    let consumptionColumn = getFieldColumn(mixRatioHeader, 'consumption');
+    let basePriceColumn = getFieldColumn(mixRatioHeader, 'unit_price.base_price');
+
+    let parentMarketPrice = 0;
+    let parentBasePrice = 0;
+    for(let i = 0; i < maxRow; i++) {
+        // 获取市场单价
+        let marketPrice = mixRatioSheet.getValue(i, marketPriceColumn);
+        // 获取基价单价
+        let basePrice = mixRatioSheet.getValue(i, basePriceColumn);
+        // 获取消耗量(如果是当前修改的行则替换数据)
+        let consumption = row === i ? info.newValue : mixRatioSheet.getValue(i, consumptionColumn);
+
+        parentMarketPrice += consumption * marketPrice;
+        parentBasePrice += consumption * basePrice;
+    }
+    parentMarketPrice = Number(parentMarketPrice.toFixed(2));
+    parentBasePrice = Number(parentBasePrice.toFixed(2));
 
+    $.ajax({
+        url: '/glj/update',
+        type: 'post',
+        data: {id: id, field: 'mix_ratio.' + field, value: value, market_price: parentMarketPrice, base_price: parentBasePrice},
+        dataType: 'json',
+        error: function() {
+            alert('数据传输有误!');
+            isChanging = false;
+            mixRatioSheet.setValue(row, column, info.oldValue);
+        },
+        beforeSend: function() {
+            isChanging = true;
+        },
+        success: function(response) {
+            isChanging = false;
+            // 修改失败则恢复原值
+            if (response.err !== 0) {
+                mixRatioSheet.setValue(row, column, info.oldValue);
+                alert('更改数据失败!');
+            } else {
+                mixRatioSuccess(field, info);
+            }
+        }
+    });
+}
 /**
- * 根据id获取对应的配合比数据
+ * 成功事件
  *
- * @param {Number} id
+ * @param {string} field
+ * @param {object} info
  * @return {void}
  */
-function getMixRatioData(id) {
+function mixRatioSuccess(field, info) {
+    // 成功则对相应的总消耗量进行设置
+    let activeGLJRow = gljSheet.getActiveRowIndex();
+    let change = Number((info.newValue - info.oldValue).toFixed(2));
+    setGLJCellByField(activeGLJRow, 'quantity', change, true);
 
+    // 计算父级3个价格
+    let maxRow = mixRatioSheet.getRowCount();
+    // 获取对应列的列号
+    let marketPriceColumn = getFieldColumn(mixRatioHeader, 'unit_price.market_price');
+    let consumptionColumn = getFieldColumn(mixRatioHeader, 'consumption');
+    let basePriceColumn = getFieldColumn(mixRatioHeader, 'unit_price.base_price');
+
+    let parentMarketPrice = 0;
+    let parentBasePrice = 0;
+    for(let i = 0; i < maxRow; i++) {
+        // 获取市场单价
+        let marketPrice = mixRatioSheet.getValue(i, marketPriceColumn);
+        // 获取基价单价
+        let basePrice = mixRatioSheet.getValue(i, basePriceColumn);
+        // 获取消耗量
+        let consumption = mixRatioSheet.getValue(i, consumptionColumn);
+
+        parentMarketPrice += consumption * marketPrice;
+        parentBasePrice += consumption * basePrice;
+    }
+    parentMarketPrice = Number(parentMarketPrice.toFixed(2));
+    parentBasePrice = Number(parentBasePrice.toFixed(2));
+    setGLJCellByField(activeGLJRow, 'unit_price.market_price', parentMarketPrice, false);
+    setGLJCellByField(activeGLJRow, 'unit_price.base_price', parentBasePrice, false);
+    setGLJCellByField(activeGLJRow, 'adjust_price', parentBasePrice, false);
 }

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

@@ -0,0 +1,65 @@
+/**
+ * spread 公用函数
+ *
+ * @author CaiAoLin
+ * @date 2017/7/12
+ * @version
+ */
+
+/**
+ * 校验数据
+ *
+ * @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;
+}
+
+/**
+ * 查找指定字段的列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 {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;
+}