Przeglądaj źródła

Merge branch 'master' of http://smartcost.f3322.net:3000/SmartCost/ConstructionCost

zhongzewei 7 lat temu
rodzic
commit
e3ca428608

+ 32 - 1
modules/pm/controllers/pm_controller.js

@@ -3,6 +3,8 @@
  */
 let ProjectsData = require('../models/project_model').project;
 let projType = require('../models/project_model').projType;
+const engineering = require("../../common/const/engineering");
+let EngineeringLibModel = require("../../users/models/engineering_lib_model");
 
 //统一回调函数
 let callback = function(req, res, err, message, data){
@@ -10,7 +12,6 @@ let callback = function(req, res, err, message, data){
 };
 
 
-
 module.exports = {
     checkRight: function (req, res) {
         let data = JSON.parse(req.body.data);
@@ -91,5 +92,35 @@ module.exports = {
         ProjectsData.getNewProjectID(data.count, function (err, message, data) {
             callback(req, res, err, message, data);
         });
+    },
+    // 项目管理首页
+    index: async function(request, response) {
+        // 获取编办信息
+        let sessionCompilation = request.session.sessionCompilation;
+
+
+        // 清单计价
+        let billValuation = sessionCompilation.bill_valuation !== undefined ?
+            sessionCompilation.bill_valuation : [];
+
+        // 获取标准库数据
+        let engineeringLibModel = new EngineeringLibModel();
+        billValuation = await engineeringLibModel.getLib(billValuation);
+
+        // 定额计价
+        let rationValuation = sessionCompilation.ration_valuation !== undefined ?
+            sessionCompilation.ration_valuation : [];
+        rationValuation = await engineeringLibModel.getLib(rationValuation);
+
+        let renderData = {
+            userAccount: request.session.userAccount,
+            userID: request.session.sessionUser.ssoId,
+            compilationData: sessionCompilation,
+            billValuation: JSON.stringify(billValuation),
+            rationValuation: JSON.stringify(rationValuation),
+            engineeringList: JSON.stringify(engineering.List)
+        };
+
+        response.render('building_saas/pm/html/project-management.html', renderData);
     }
 }

+ 5 - 1
modules/pm/models/project_schema.js

@@ -17,7 +17,11 @@ let ProjectSchema = new Schema({
     "recentDateTime": Date,
     "createDateTime": Date,
     "deleteInfo": deleteSchema,
-    'fullFolder': Array
+    'fullFolder': Array,
+    "property": {
+        type: Schema.Types.Mixed,
+        default: {}
+    }
 });
 
 module.exports = mongoose.model(collectionName, ProjectSchema);

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

@@ -5,28 +5,10 @@
 
 let express = require('express');
 let pmController = require('./../controllers/pm_controller');
-const engineering = require("../../common/const/engineering");
 
 module.exports = function (app) {
 
-    app.get('/pm', function(req, res){
-        // 获取编办信息
-        let sessionCompilation = req.session.sessionCompilation;
-        // 清单计价
-        let billValuation = sessionCompilation.bill_valuation !== undefined ? sessionCompilation.bill_valuation : [];
-
-        // 定额计价
-        let rationValuation = sessionCompilation.ration_valuation !== undefined ? sessionCompilation.ration_valuation : [];
-        let renderData = {
-            userAccount: req.session.userAccount,
-            userID: req.session.sessionUser.ssoId,
-            compilationData: sessionCompilation,
-            billValuation: JSON.stringify(billValuation),
-            rationValuation: JSON.stringify(rationValuation),
-            engineeringList: JSON.stringify(engineering.List)
-        };
-        res.render('building_saas/pm/html/project-management.html', renderData);
-    });
+    app.get('/pm', pmController.index);
 
     let pmRouter = express.Router();
 

+ 97 - 0
modules/users/models/engineering_lib_model.js

@@ -0,0 +1,97 @@
+/**
+ * 计价规则标准库业务逻辑
+ *
+ * @author CaiAoLin
+ * @date 2017/8/31
+ * @version
+ */
+import BaseModel from "../../common/base/base_model";
+import EngineeringLibSchema from "./schema/engineering_lib";
+
+class EngineeringLibModel extends BaseModel {
+    /**
+     * 构造函数
+     *
+     * @return {void}
+     */
+    constructor() {
+        let parent = super();
+        parent.model = EngineeringLibSchema;
+        parent.init();
+    }
+
+    /**
+     * 获取标准库数据
+     *
+     * @param {Object} data
+     * @return {Promise}
+     */
+    async getLib(data) {
+        if (data.length <= 0) {
+            return data;
+        }
+
+        let engineeringTemp = {};
+        let engineeringLibIdList = [];
+        // 整理出数据库需要查找的id,一次查找
+        for(let valuation of data) {
+            if (valuation === null) {
+                continue;
+            }
+            for(let engineering of valuation.engineering_list) {
+                if (engineeringTemp[valuation._id] === undefined) {
+                    engineeringTemp[valuation._id] = [engineering.engineering_id];
+                }else {
+                    engineeringTemp[valuation._id].push(engineering.engineering_id);
+                }
+                engineeringLibIdList.push(engineering.engineering_id);
+            }
+        }
+        // console.log(data);
+        // console.log(engineeringTemp);
+
+        // 查找对应的id数据
+        let condition = {_id: {"$in": engineeringLibIdList}};
+        let engineeringLibList = await this.findDataByCondition(condition, null, false, '_id');
+
+        // 组合计价规则id对应专业工程标准库数据
+        let engineeringLib = {};
+        for(let index in engineeringTemp) {
+            if (engineeringTemp[index].length <= 0) {
+                continue;
+            }
+            for(let libId of engineeringTemp[index]) {
+                if (engineeringLibList[libId] === undefined) {
+                    continue;
+                }
+                if (engineeringLib[index] === undefined) {
+                    engineeringLib[index] = [engineeringLibList[libId] ];
+                }else {
+                    engineeringLib[index].push(engineeringLibList[libId] );
+                }
+            }
+        }
+
+        // 替换计价规则数据
+        let valuationData = JSON.parse(JSON.stringify(data));
+        for(let valuation of valuationData) {
+            if (valuation === null) {
+                continue;
+            }
+            for(let engineering of valuation.engineering_list) {
+                if (engineering === null || engineeringLib[valuation._id] === undefined) {
+                    continue;
+                }
+                for (let tmp of engineeringLib[valuation._id]) {
+                    if (tmp._id.toString() === engineering.engineering_id.toString()) {
+                        engineering.lib = tmp;
+                    }
+                }
+            }
+        }
+        return valuationData;
+    }
+
+}
+
+module.exports = EngineeringLibModel;

+ 12 - 17
modules/users/models/schema/compilation.js

@@ -9,27 +9,22 @@ import mongoose from "mongoose";
 
 let Schema = mongoose.Schema;
 let collectionName = 'compilation';
-let childrenSchema = new Schema({
-    // 计价名称
-    name: String,
-    // 工程专业
+let engineeringListSchema = new Schema({
+    // 工程专业id
     engineering: {
-        type: Number,
-        default: ''
-    },
-    // 标准清单
-    bill_lib: {
-        type: Schema.Types.Mixed,
-        default: []
+        type: Number
     },
-    // 定额库
-    ration_lib: {
+    engineering_id: {
         type: Schema.Types.Mixed,
         default: []
-    },
-    // 工料机库
-    glj_lib: {
-        type: Schema.Types.Mixed,
+    }
+}, {_id: false});
+let childrenSchema = new Schema({
+    // 计价名称
+    name: String,
+    // 工程专业列表
+    engineering_list: {
+        type: [engineeringListSchema],
         default: []
     },
     // 是否启用

+ 47 - 0
modules/users/models/schema/engineering_lib.js

@@ -0,0 +1,47 @@
+/**
+ * 计价规则数据结构
+ *
+ * @author CaiAoLin
+ * @date 2017/8/31
+ * @version
+ */
+import mongoose from "mongoose";
+
+let Schema = mongoose.Schema;
+let collectionName = 'engineering_lib';
+let modelSchema = {
+    // 标准清单
+    bill_lib: {
+        type: Schema.Types.Mixed,
+        default: []
+    },
+    // 定额库
+    ration_lib: {
+        type: Schema.Types.Mixed,
+        default: []
+    },
+    // 工料机库
+    glj_lib: {
+        type: Schema.Types.Mixed,
+        default: []
+    },
+    // 列设置
+    main_tree_col: {
+        type: Schema.Types.Mixed,
+        default: {
+            "emptyRows":3,
+            "headRows":0,
+            "treeCol": 0,
+            "headRowHeight":[],
+            "cols":[]
+        }
+    },
+    // 费率标准库
+    fee_lib: {
+        type: Schema.Types.Mixed,
+        default: []
+    }
+};
+let model = mongoose.model(collectionName, new Schema(modelSchema, {versionKey: false, collection: collectionName}));
+export {model as default, collectionName as collectionName};
+

+ 128 - 3
public/calc_util.js

@@ -1,7 +1,7 @@
 /**
  * Created by Tony on 2017/6/21.
- * Modified by CSL, 2017-08-01
- * 引入多套计算程序、费率同步、人工系数同步、改进基数计算、费字段映射等
+ * Modified by CSL, 2017-08-01 引入多套计算程序、费率同步、人工系数同步、改进基数计算、费字段映射等。
+ * added by CSL, 2017-09-01 增加公式解析对象analyzer,用于解析用户修改公式、自定义表达式
  */
 
 let executeObj = {
@@ -39,6 +39,129 @@ let executeObj = {
     }
 };
 
+let analyzer = {
+    standard: function(expr){
+        let str = expr;
+        str = str.replace(/\s/g, "");               // 去空格、去中文空格
+        str = str.replace(/(/g, "(");              // 中文括号"("换成英文括号"("
+        str = str.replace(/)/g, ")");              // 中文括号")"换成英文括号")"
+        str = str.replace(/f/g, "F");               // f换成F
+        console.log(str);
+        return str;
+    },
+
+    analyzeCalcBase: function(expr){
+        // 前提:必须无空格、无特殊符号
+        function getCalcBase(expr){
+            let base = '',
+                iPos1 = -1, iPos2 = -1;
+            for (let i = 0; i < expr.length; i++) {
+                if (expr[i] === '['){
+                    iPos1 = i;
+                }
+                else if (iPos1 != -1 && expr[i]===']'){
+                    iPos2 = i;
+                };
+
+                if (iPos1 != -1 && iPos2 != -1){
+                    base = expr.slice(iPos1, iPos2 + 1);
+                    break;
+                }
+            };
+            return base;
+        };
+        function calcBaseToIDExpr(base){
+            // for test.
+            let id = -1;
+            if (base == '[人工费]'){
+                id = 111;
+            }
+            else if (base == '[材料费]'){
+                id = 222;
+            }
+            else if (base == '[机械费]'){
+                id = 333;
+            }
+            else id = 999;
+
+            return "@('" + id + "')";
+        };
+
+        while (expr.indexOf('[') > 0) {
+            let base = getCalcBase(expr);
+            let id = calcBaseToIDExpr(base);
+            let baseValue = base.slice(1, -1);   // []会给下面的正则带来干扰,这里去掉
+            var pattBase =new RegExp(baseValue, "g");
+            expr = expr.replace(pattBase, id);
+            expr = expr.replace(/\[@\('/g, "@('");      // [@('
+            expr = expr.replace(/'\)\]/g, "')");        // ')]
+        };
+
+        return expr;
+    },
+
+    analyzeLineRef: function(expr){
+        function isOperator(char){
+            var operator = "+-*/()";
+            return operator.indexOf(char) > -1;
+        };
+        function codeToID(code){
+            return eval(parseFloat(code)+1);
+        };
+        // 前提:必须无空格、无特殊符号、标准大写F
+        function getSection(expr){
+            let section = '',
+                iPos1 = -1, iPos2 = -1;
+            for (let i = 0; i < expr.length; i++) {
+                if (expr[i] === 'F'){
+                    iPos1 = i;
+                }
+                else if (iPos1 != -1 && isOperator(expr[i])){
+                    iPos2 = i;
+                }
+                else if (iPos1 != -1 && i == expr.length - 1){
+                    iPos2 = i + 1;
+
+                };
+                if (iPos1 != -1 && iPos2 != -1){
+                    section = expr.slice(iPos1, iPos2);
+                    break;
+                }
+            };
+            return section;
+        };
+        function sectionToIDExpr(section){
+            if (section){
+                let code = section.slice(1);
+                if (isNaN(code)){
+                    return '错误'      // 这里的返回提示不能加上section,因为会无限循环
+                }
+                else
+                    return "@('" + codeToID(code) + "')";
+            }
+            else return '';
+        };
+
+        while (expr.indexOf('F') > 0) {
+            let sec = getSection(expr);
+            let id = sectionToIDExpr(sec);
+            var pattSec =new RegExp(sec, "g");
+            expr = expr.replace(pattSec, id);
+        };
+        return expr;
+    },
+
+    analyzeUserExpr: function(expr){
+        // 标准化:处理特殊字符、中文符号、大小写
+        expr = this.standard(expr);
+        // 先换掉计算基数
+        expr = this.analyzeCalcBase(expr);
+        // 再换掉行引用
+        expr = this.analyzeLineRef(expr);
+        return expr;
+    }
+};
+
 class Calculation {
     // 先编译公用的基础数据
     compilePublics(feeRates, labourCoes, feeTypes, calcBases){
@@ -234,4 +357,6 @@ class Calculation {
             }
         }
     }
-}
+};
+
+export default analyzer;

+ 3 - 0
public/web/tree_sheet/tree_sheet_helper.js

@@ -112,6 +112,9 @@ var TREE_SHEET_HELPER = {
                 } else {
                     cell.value(getFieldText2());
                 }
+                if (colSetting.data.cellType) {
+                    cell.cellType(colSetting.data.cellType);
+                }
                 if (colSetting.readOnly) {
                     if (Object.prototype.toString.apply(colSetting.readOnly) === "[object Function]") {
                         cell.locked(colSetting.readOnly(node));

+ 13 - 0
test/calculation/test_analyzer.js

@@ -0,0 +1,13 @@
+/**
+ * Created by CSL on 2017-09-01.
+ */
+var test = require('tape');
+import analyzer from '../../public/calc_util';
+
+test('解析测试', function(t){
+    let userExpr = "12 +[人工费]*1.2+f4+ (F6+ f10) +F23+[人工费] + f6+[材料费]";
+    let rst = analyzer.analyzeUserExpr(userExpr);
+    console.log(rst);
+    t.equal(rst, "12+@('111')*1.2+@('5')+(@('7')+@('11'))+@('24')+@('111')+@('7')+@('222')");
+    t.end();
+});

+ 4 - 3
test/tmp_data/bills_grid_setting.js

@@ -102,8 +102,8 @@ var BillsGridSetting ={
             }
         },
         {
-            "width":40,
-            "readOnly":false,
+            "width":60,
+            "readOnly":'readOnly.ration',
             "head":{
                 "titleNames":[
                     "计量\n单位"
@@ -131,7 +131,8 @@ var BillsGridSetting ={
                 "field":"unit",
                 "vAlign":1,
                 "hAlign":1,
-                "font":"Arial"
+                "font":"Arial",
+                "cellType": 'cellType.unit'
             }
         },
         {

+ 8 - 0
web/building_saas/main/js/views/main_tree_col.js

@@ -43,6 +43,14 @@ let MainTreeCol = {
             return MainTreeCol.readOnly.billsParent && MainTreeCol.readOnly.non_bills;
         }
     },
+    cellType: {
+        unit: function () {
+            let combo = new GC.Spread.Sheets.CellTypes.ComboBox();
+            combo.itemHeight(10).items(['m', 'm2', 'm3', 'km', 't', 'kg', '台班', '工日', '昼夜', '元', '项', '处', '个', '件',
+                '根', '组', '系统', '台', '套', '株', '丛', '缸', '支', '只', '块', '座', '对', '份', '樘', '攒', '榀']);
+            return combo;
+        }
+    },
     getEvent: function (eventName) {
         let names = eventName.split('.');
         let event = this;

+ 4 - 0
web/building_saas/main/js/views/project_view.js

@@ -94,6 +94,10 @@ var projectObj = {
                     if (col.readOnly && Object.prototype.toString.apply(col.readOnly) === "[object String]") {
                         col.readOnly = MainTreeCol.getEvent(col.readOnly);
                     }
+                    if (col.data.cellType && Object.prototype.toString.apply(col.data.cellType) === "[object String]") {
+                        let getCellType = MainTreeCol.getEvent(col.data.cellType);
+                        col.data.cellType = getCellType();
+                    }
                     if (col.data.digit && Object.prototype.toString.apply(col.data.digit) === "[object String]") {
                         col.data.decimal = that.project.getDecimal(col.data.digit);
                         col.data.formatter = MainTreeCol.getNumberFormatter(col.data.decimal);

+ 1 - 1
web/building_saas/pm/html/project-management.html

@@ -336,7 +336,7 @@
                     </div>
                     <div class="form-group">
                         <label>费率文件</label>
-                        <select class="form-control"><option>新建费率文件</option></select>
+                        <select class="form-control" id="tender-fee-rate"><option>请选择费率文件</option></select>
                     </div>
                     <div class="form-group">
                         <label>计价方式</label>

+ 33 - 13
web/building_saas/pm/js/pm_main.js

@@ -9,6 +9,7 @@ let Tree = null;
 let movetoZTree = null;
 let copytoZTree = null;
 let engineering = [];
+let feeRateData = [];
 let projectType = {
     folder: 'Folder',
     tender: 'Tender',
@@ -165,13 +166,14 @@ $(document).ready(function() {
     $("input[name='valuation_type']").click(function() {
         let type = $(this).val();
         let targetData = type === 'bill' ? JSON.parse(billValuation) : JSON.parse(rationValuation);
+
         let html = '<option value="">请选择计划规则</option>';
 
         for(let valuation of targetData) {
             if (valuation === null) {
                 continue;
             }
-            html += '<option value="'+ valuation._id +'" data-engineering="'+ valuation.engineering +'">'+ valuation.name +'</option>';
+            html += '<option value="'+ valuation._id +'">'+ valuation.name +'</option>';
         }
         $("#valuation").html(html);
     });
@@ -228,20 +230,26 @@ $(document).ready(function() {
         }
         if (projectInfo !== null) {
             let savedProjectData = localStorage.getItem(projectInfo.data.name);
+            console.log(savedProjectData);
             savedProjectData = JSON.parse(savedProjectData);
             // 填入计价规则
             let valuationHtml = '<option value="'+ savedProjectData.valuation +'">'+ savedProjectData.valuationName +'</option>';
             $("#tender-valuation").html(valuationHtml);
 
             // 填入工程专业
-            let engineeringString = getEngineeringName(savedProjectData.engineering);
-            let engineeringHtml = '<option value="'+ savedProjectData.engineering +'">'+ engineeringString +'</option>';
+            let engineeringHtml = getEngineeringHtml(savedProjectData.engineeringList);
             $("#tender-engineering").html(engineeringHtml);
 
             $("input[name='tender_valuation_type']").attr('disabled', 'disabled').removeAttr('checked', 'checked');
             $("input[name='tender_valuation_type'][value='"+ savedProjectData.valuationType +"']")
                 .attr("checked", "checked").removeAttr('disabled', 'disabled');
 
+            // 填入费率文件
+            let feeHtml = '<option>请选择费率文件</option>';
+            // for (let fee of savedProjectData.feeLib) {
+            //     feeHtml += '<option value="'+ fee.id +'">'+ fee.name +'</option>';
+            // }
+            $("#tender-fee-rate").html(feeHtml);
         }
 
     });
@@ -523,7 +531,16 @@ function AddProject() {
     }
     let valuationName = $("#valuation").children("option:selected").text();
     let valuationType = $("input[name='valuation_type']:checked").val();
-    let engineering = $("#valuation").children("option:selected").data("engineering");
+    let engineeringList = [];
+
+    let valuationData = valuationType === 'bill' ? JSON.parse(billValuation) : JSON.parse(rationValuation);
+    for(let tmp of valuationData) {
+        if (tmp._id === valuation) {
+            engineeringList = tmp.engineering_list;
+            break;
+        }
+    }
+
     let callback = function() {
         $("#add-project-dialog").modal("hide");
         // 记录选择后的信息
@@ -531,7 +548,7 @@ function AddProject() {
             valuation: valuation,
             valuationType: valuationType,
             valuationName: valuationName,
-            engineering: engineering
+            engineeringList: engineeringList,
         };
         localStorage.setItem(name, JSON.stringify(projectInfo));
     };
@@ -875,19 +892,22 @@ function GetTargetTreeNode(zTreeObj) {
 /**
  * 根据指定id获取对应的工程专业
  *
- * @param {Number} id
+ * @param {Array} engineeringList
  * @return {String}
  */
-function getEngineeringName(id) {
-    let result = '';
-    if (engineering.length <= 0) {
+function getEngineeringHtml(engineeringList) {
+    let result = '<option>请选择对应的工程专业</option>';
+    if (engineeringList.length <= 0) {
         return result;
     }
-
+    let engineeringObject = {};
     for(let tmp of engineering) {
-        if (tmp.value === id) {
-            result = tmp.name;
-            break;
+        engineeringObject[tmp.value] = tmp.name;
+    }
+
+    for(let tmp of engineeringList) {
+        if (engineeringObject[tmp.engineering] !== undefined) {
+            result += '<option value="'+ tmp.engineering_id +'">'+ engineeringObject[tmp.engineering] +'</option>';
         }
     }