Selaa lähdekoodia

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

TonyKang 6 vuotta sitten
vanhempi
commit
9a396b160f

+ 486 - 0
lib/json/json2.js

@@ -0,0 +1,486 @@
+/**
+ * Created by zhang on 2018/9/4.
+ */
+/*
+ http://www.JSON.org/json2.js
+ 2010-03-20
+
+ Public Domain.
+
+ NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
+
+ See http://www.JSON.org/js.html
+
+
+ This code should be minified before deployment.
+ See http://javascript.crockford.com/jsmin.html
+
+ USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
+ NOT CONTROL.
+
+
+ This file creates a global JSON object containing two methods: stringify
+ and parse.
+
+ JSON.stringify(value, replacer, space)
+ value       any JavaScript value, usually an object or array.
+
+ replacer    an optional parameter that determines how object
+ values are stringified for objects. It can be a
+ function or an array of strings.
+
+ space       an optional parameter that specifies the indentation
+ of nested structures. If it is omitted, the text will
+ be packed without extra whitespace. If it is a number,
+ it will specify the number of spaces to indent at each
+ level. If it is a string (such as '\t' or ' '),
+ it contains the characters used to indent at each level.
+
+ This method produces a JSON text from a JavaScript value.
+
+ When an object value is found, if the object contains a toJSON
+ method, its toJSON method will be called and the result will be
+ stringified. A toJSON method does not serialize: it returns the
+ value represented by the name/value pair that should be serialized,
+ or undefined if nothing should be serialized. The toJSON method
+ will be passed the key associated with the value, and this will be
+ bound to the value
+
+ For example, this would serialize Dates as ISO strings.
+
+ Date.prototype.toJSON = function (key) {
+ function f(n) {
+ // Format integers to have at least two digits.
+ return n < 10 ? '0' + n : n;
+ }
+
+ return this.getUTCFullYear()   + '-' +
+ f(this.getUTCMonth() + 1) + '-' +
+ f(this.getUTCDate())      + 'T' +
+ f(this.getUTCHours())     + ':' +
+ f(this.getUTCMinutes())   + ':' +
+ f(this.getUTCSeconds())   + 'Z';
+ };
+
+ You can provide an optional replacer method. It will be passed the
+ key and value of each member, with this bound to the containing
+ object. The value that is returned from your method will be
+ serialized. If your method returns undefined, then the member will
+ be excluded from the serialization.
+
+ If the replacer parameter is an array of strings, then it will be
+ used to select the members to be serialized. It filters the results
+ such that only members with keys listed in the replacer array are
+ stringified.
+
+ Values that do not have JSON representations, such as undefined or
+ functions, will not be serialized. Such values in objects will be
+ dropped; in arrays they will be replaced with null. You can use
+ a replacer function to replace those with JSON values.
+ JSON.stringify(undefined) returns undefined.
+
+ The optional space parameter produces a stringification of the
+ value that is filled with line breaks and indentation to make it
+ easier to read.
+
+ If the space parameter is a non-empty string, then that string will
+ be used for indentation. If the space parameter is a number, then
+ the indentation will be that many spaces.
+
+ Example:
+
+ text = JSON.stringify(['e', {pluribus: 'unum'}]);
+ // text is '["e",{"pluribus":"unum"}]'
+
+
+ text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
+ // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
+
+ text = JSON.stringify([new Date()], function (key, value) {
+ return this[key] instanceof Date ?
+ 'Date(' + this[key] + ')' : value;
+ });
+ // text is '["Date(---current time---)"]'
+
+
+ JSON.parse(text, reviver)
+ This method parses a JSON text to produce an object or array.
+ It can throw a SyntaxError exception.
+
+ The optional reviver parameter is a function that can filter and
+ transform the results. It receives each of the keys and values,
+ and its return value is used instead of the original value.
+ If it returns what it received, then the structure is not modified.
+ If it returns undefined then the member is deleted.
+
+ Example:
+
+ // Parse the text. Values that look like ISO date strings will
+ // be converted to Date objects.
+
+ myData = JSON.parse(text, function (key, value) {
+ var a;
+ if (typeof value === 'string') {
+ a =
+ /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
+ if (a) {
+ return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+ +a[5], +a[6]));
+ }
+ }
+ return value;
+ });
+
+ myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
+ var d;
+ if (typeof value === 'string' &&
+ value.slice(0, 5) === 'Date(' &&
+ value.slice(-1) === ')') {
+ d = new Date(value.slice(5, -1));
+ if (d) {
+ return d;
+ }
+ }
+ return value;
+ });
+
+
+ This is a reference implementation. You are free to copy, modify, or
+ redistribute.
+ */
+
+/*jslint evil: true, strict: false */
+
+/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
+ call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
+ getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
+ lastIndex, length, parse, prototype, push, replace, slice, stringify,
+ test, toJSON, toString, valueOf
+ */
+
+
+// Create a JSON object only if one does not already exist. We create the
+// methods in a closure to avoid creating global variables.
+
+if (!this.JSON) {
+    this.JSON = {};
+}
+
+(function () {
+
+    function f(n) {
+        // Format integers to have at least two digits.
+        return n < 10 ? '0' + n : n;
+    }
+
+    if (typeof Date.prototype.toJSON !== 'function') {
+
+        Date.prototype.toJSON = function (key) {
+
+            return isFinite(this.valueOf()) ?
+                this.getUTCFullYear()   + '-' +
+                f(this.getUTCMonth() + 1) + '-' +
+                f(this.getUTCDate())      + 'T' +
+                f(this.getUTCHours())     + ':' +
+                f(this.getUTCMinutes())   + ':' +
+                f(this.getUTCSeconds())   + 'Z' : null;
+        };
+
+        String.prototype.toJSON =
+            Number.prototype.toJSON =
+                Boolean.prototype.toJSON = function (key) {
+                    return this.valueOf();
+                };
+    }
+
+    var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+        escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+        gap,
+        indent,
+        meta = {    // table of character substitutions
+            '\b': '\\b',
+            '\t': '\\t',
+            '\n': '\\n',
+            '\f': '\\f',
+            '\r': '\\r',
+            '"' : '\\"',
+            '\\': '\\\\'
+        },
+        rep;
+
+
+    function quote(string) {
+
+// If the string contains no control characters, no quote characters, and no
+// backslash characters, then we can safely slap some quotes around it.
+// Otherwise we must also replace the offending characters with safe escape
+// sequences.
+
+        escapable.lastIndex = 0;
+        return escapable.test(string) ?
+            '"' + string.replace(escapable, function (a) {
+                var c = meta[a];
+                return typeof c === 'string' ? c :
+                    '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+            }) + '"' :
+            '"' + string + '"';
+    }
+
+
+    function str(key, holder) {
+
+// Produce a string from holder[key].
+
+        var i,          // The loop counter.
+            k,          // The member key.
+            v,          // The member value.
+            length,
+            mind = gap,
+            partial,
+            value = holder[key];
+
+// If the value has a toJSON method, call it to obtain a replacement value.
+
+        if (value && typeof value === 'object' &&
+            typeof value.toJSON === 'function') {
+            value = value.toJSON(key);
+        }
+
+// If we were called with a replacer function, then call the replacer to
+// obtain a replacement value.
+
+        if (typeof rep === 'function') {
+            value = rep.call(holder, key, value);
+        }
+
+// What happens next depends on the value's type.
+
+        switch (typeof value) {
+            case 'string':
+                return quote(value);
+
+            case 'number':
+
+// JSON numbers must be finite. Encode non-finite numbers as null.
+
+                return isFinite(value) ? String(value) : 'null';
+
+            case 'boolean':
+            case 'null':
+
+// If the value is a boolean or null, convert it to a string. Note:
+// typeof null does not produce 'null'. The case is included here in
+// the remote chance that this gets fixed someday.
+
+                return String(value);
+
+// If the type is 'object', we might be dealing with an object or an array or
+// null.
+
+            case 'object':
+
+// Due to a specification blunder in ECMAScript, typeof null is 'object',
+// so watch out for that case.
+
+                if (!value) {
+                    return 'null';
+                }
+
+// Make an array to hold the partial results of stringifying this object value.
+
+                gap += indent;
+                partial = [];
+
+// Is the value an array?
+
+                if (Object.prototype.toString.apply(value) === '[object Array]') {
+
+// The value is an array. Stringify every element. Use null as a placeholder
+// for non-JSON values.
+
+                    length = value.length;
+                    for (i = 0; i < length; i += 1) {
+                        partial[i] = str(i, value) || 'null';
+                    }
+
+// Join all of the elements together, separated with commas, and wrap them in
+// brackets.
+
+                    v = partial.length === 0 ? '[]' :
+                        gap ? '[\n' + gap +
+                            partial.join(',\n' + gap) + '\n' +
+                            mind + ']' :
+                            '[' + partial.join(',') + ']';
+                    gap = mind;
+                    return v;
+                }
+
+// If the replacer is an array, use it to select the members to be stringified.
+
+                if (rep && typeof rep === 'object') {
+                    length = rep.length;
+                    for (i = 0; i < length; i += 1) {
+                        k = rep[i];
+                        if (typeof k === 'string') {
+                            v = str(k, value);
+                            if (v) {
+                                partial.push(quote(k) + (gap ? ': ' : ':') + v);
+                            }
+                        }
+                    }
+                } else {
+
+// Otherwise, iterate through all of the keys in the object.
+
+                    for (k in value) {
+                        if (Object.hasOwnProperty.call(value, k)) {
+                            v = str(k, value);
+                            if (v) {
+                                partial.push(quote(k) + (gap ? ': ' : ':') + v);
+                            }
+                        }
+                    }
+                }
+
+// Join all of the member texts together, separated with commas,
+// and wrap them in braces.
+
+                v = partial.length === 0 ? '{}' :
+                    gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
+                        mind + '}' : '{' + partial.join(',') + '}';
+                gap = mind;
+                return v;
+        }
+    }
+
+// If the JSON object does not yet have a stringify method, give it one.
+
+    if (typeof JSON.stringify !== 'function') {
+        JSON.stringify = function (value, replacer, space) {
+
+// The stringify method takes a value and an optional replacer, and an optional
+// space parameter, and returns a JSON text. The replacer can be a function
+// that can replace values, or an array of strings that will select the keys.
+// A default replacer method can be provided. Use of the space parameter can
+// produce text that is more easily readable.
+
+            var i;
+            gap = '';
+            indent = '';
+
+// If the space parameter is a number, make an indent string containing that
+// many spaces.
+
+            if (typeof space === 'number') {
+                for (i = 0; i < space; i += 1) {
+                    indent += ' ';
+                }
+
+// If the space parameter is a string, it will be used as the indent string.
+
+            } else if (typeof space === 'string') {
+                indent = space;
+            }
+
+// If there is a replacer, it must be a function or an array.
+// Otherwise, throw an error.
+
+            rep = replacer;
+            if (replacer && typeof replacer !== 'function' &&
+                (typeof replacer !== 'object' ||
+                typeof replacer.length !== 'number')) {
+                throw new Error('JSON.stringify');
+            }
+
+// Make a fake root object containing our value under the key of ''.
+// Return the result of stringifying the value.
+
+            return str('', {'': value});
+        };
+    }
+
+
+// If the JSON object does not yet have a parse method, give it one.
+
+    if (typeof JSON.parse !== 'function') {
+        JSON.parse = function (text, reviver) {
+
+// The parse method takes a text and an optional reviver function, and returns
+// a JavaScript value if the text is a valid JSON text.
+
+            var j;
+
+            function walk(holder, key) {
+
+// The walk method is used to recursively walk the resulting structure so
+// that modifications can be made.
+
+                var k, v, value = holder[key];
+                if (value && typeof value === 'object') {
+                    for (k in value) {
+                        if (Object.hasOwnProperty.call(value, k)) {
+                            v = walk(value, k);
+                            if (v !== undefined) {
+                                value[k] = v;
+                            } else {
+                                delete value[k];
+                            }
+                        }
+                    }
+                }
+                return reviver.call(holder, key, value);
+            }
+
+
+// Parsing happens in four stages. In the first stage, we replace certain
+// Unicode characters with escape sequences. JavaScript handles many characters
+// incorrectly, either silently deleting them, or treating them as line endings.
+
+            text = String(text);
+            cx.lastIndex = 0;
+            if (cx.test(text)) {
+                text = text.replace(cx, function (a) {
+                    return '\\u' +
+                        ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+                });
+            }
+
+// In the second stage, we run the text against regular expressions that look
+// for non-JSON patterns. We are especially concerned with '()' and 'new'
+// because they can cause invocation, and '=' because it can cause mutation.
+// But just to be safe, we want to reject all unexpected forms.
+
+// We split the second stage into 4 regexp operations in order to work around
+// crippling inefficiencies in IE's and Safari's regexp engines. First we
+// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
+// replace all simple value tokens with ']' characters. Third, we delete all
+// open brackets that follow a colon or comma or that begin the text. Finally,
+// we look to see that the remaining characters are only whitespace or ']' or
+// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
+
+            if (/^[\],:{}\s]*$/.
+                test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
+                replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
+                replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
+
+// In the third stage we use the eval function to compile the text into a
+// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
+// in JavaScript: it can begin a block or an object literal. We wrap the text
+// in parens to eliminate the ambiguity.
+
+                j = eval('(' + text + ')');
+
+// In the optional fourth stage, we recursively walk the new structure, passing
+// each name/value pair to a reviver function for possible transformation.
+
+                return typeof reviver === 'function' ?
+                    walk({'': j}, '') : j;
+            }
+
+// If the text is not JSON parseable, then a SyntaxError is thrown.
+
+            throw new SyntaxError('JSON.parse');
+        };
+    }
+}());
+

+ 5 - 0
modules/all_models/engineering_lib.js

@@ -53,6 +53,11 @@ let modelSchema = {
         type: Schema.Types.Mixed,
         default: []
     },
+    //工程特征库
+    feature_lib:{
+        type: Schema.Types.Mixed,
+        default: []
+    },
     //设置人材机显示列
     glj_col:{
         showAdjustPrice:Boolean//是否显示调整价列

+ 9 - 1
modules/all_models/stdGlj_glj.js

@@ -8,7 +8,11 @@ const Schema = mongoose.Schema;
 const std_gljComponent = new Schema(
     {
         ID: Number,
-        consumeAmt: Number
+        consumeAmt: Number,
+        consumeAmtProperty: {
+            type: Schema.Types.Mixed,
+            default: {}
+        }
     },
     {_id: false},
     {versionKey: false}
@@ -22,6 +26,10 @@ const std_glj = new Schema({
     name: String,
     specs: String,
     basePrice: Number,
+    priceProperty: {
+        type: Schema.Types.Mixed,
+        default: {}
+    },
     gljClass: Number,
     gljType: Number,
     shortName: String,

+ 1 - 0
modules/ration_repository/controllers/ration_repository_controller.js

@@ -205,6 +205,7 @@ class RationRepositoryController extends baseController {
                 response.json(responseData);
             }
             catch (error){
+                console.log(error);
                 if(uploadFullName && fs.existsSync(uploadFullName)){
                     fs.unlink(uploadFullName);
                 }

+ 26 - 1
modules/ration_repository/models/ration_item.js

@@ -376,7 +376,13 @@ rationItemDAO.prototype.updateRationBasePrc = function (basePrcArr, callback) {
                                         gljArr.push({gljId: theGlj.ID, basePrice: adjBasePrice, gljParentType: gljParentType});
                                     }
                                     else {
-                                        gljArr.push({gljId: theGlj.ID, basePrice: parseFloat(theGlj.basePrice), gljParentType: gljParentType});
+                                        if(theGlj.priceProperty && Object.keys(theGlj.priceProperty).length > 0){
+                                            let priceKeys = Object.keys(theGlj.priceProperty);
+                                            gljArr.push({gljId: theGlj.ID, basePrice: parseFloat(theGlj.priceProperty[priceKeys[0]]), gljParentType: gljParentType});
+                                        }
+                                        else {
+                                            gljArr.push({gljId: theGlj.ID, basePrice: parseFloat(theGlj.basePrice), gljParentType: gljParentType});
+                                        }
                                     }
                                 }
                             }
@@ -849,12 +855,31 @@ rationItemDAO.prototype.batchAddFromExcel = async function(rationRepId, data) {
     const existCodeList = await this.getRationItemByCondition(condition, ['code'], 'code');
     // 过滤插入数据
     let insertData = [];
+    //已存在定额,则更新价格及rationGLjList字段
+    let updateData = [];
     for (const ration of rationData) {
         if (existCodeList[ration.code] !== undefined) {
+            updateData.push(ration);
             continue;
         }
         insertData.push(ration);
     }
+    //更新定额
+    let updateBulk = [];
+    for(let ration of updateData){
+        this.calcForRation(stdGLJListByID, ration);
+        updateBulk.push({
+            updateOne: {
+                filter: {rationRepId: rationRepId, code: ration.code},
+                update: {$set: {rationGljList: ration.rationGljList, labourPrice: ration.labourPrice, materialPrice: ration.materialPrice,
+                    machinePrice: ration.machinePrice, basePrice: ration.basePrice}}
+            }
+        });
+    }
+    //更新数据库
+    if(updateBulk.length > 0){
+        await rationItemModel.bulkWrite(updateBulk);
+    }
     // 如果都已经存在,直接返回
     if (insertData.length <= 0) {
         return true;

+ 9 - 2
modules/std_glj_lib/controllers/viewsController.js

@@ -8,6 +8,7 @@ import mongoose from 'mongoose';
 const compilationModel = mongoose.model('compilation');
 const stdGljLibModel = mongoose.model('std_glj_lib_map');
 let config = require("../../../config/config.js");
+const fs = require('fs');
 class ViewsController extends BaseController{
     redirectMain(req, res){
         res.render('maintain/std_glj_lib/html/main.html',
@@ -18,15 +19,21 @@ class ViewsController extends BaseController{
     async redirectGlj(req, res){
         let overWriteUrl = null;
         let stdGljLib = await stdGljLibModel.findOne({ID: req.query.gljLibId, deleted: false});
+        let priceProperties = [],
+            consumeAmtProperties = [];
         if(stdGljLib){
            let compilation = await compilationModel.findOne({_id: mongoose.Types.ObjectId(stdGljLib.compilationId)});
-           overWriteUrl = stdGljLib.compilationId === '5b4d581023a924000b760f2d' ? null : compilation.overWriteUrl;
-           console.log(overWriteUrl);
+           priceProperties = compilation.priceProperties ? compilation.priceProperties : [];
+           consumeAmtProperties = compilation.consumeAmtProperties ? compilation.consumeAmtProperties : [];
+           let absoluteUrl = compilation.overWriteUrl ? req.app.locals.rootDir + compilation.overWriteUrl : req.app.locals.rootDir;
+           overWriteUrl = fs.existsSync(absoluteUrl) && fs.statSync(absoluteUrl).isFile()? compilation.overWriteUrl : null;
         }
         res.render('maintain/std_glj_lib/html/gongliao.html',
         {
             userAccount: req.session.managerData.username,
             LicenseKey:config.getLicenseKey(process.env.NODE_ENV),
+            priceProperties: JSON.stringify(priceProperties),
+            consumeAmtProperties: JSON.stringify(consumeAmtProperties),
             overWriteUrl: overWriteUrl
         });
     }

+ 23 - 2
modules/users/controllers/compilation_controller.js

@@ -21,7 +21,9 @@ import STDCalcProgramModel from "../../common/std/std_calc_program_model";
 const billsGuidanceFc = require('../../std_billsGuidance_lib/facade/facades');
 import mainColFacade from "../../main_col_lib/facade/main_col_facade";
 import billTemplateFacade from "../../bills_template_lib/facade/bills_template_facade";
+import projectFeatureFacade from "../../project_feature_lib/facade/project_feature_facade";
 let config = require("../../../config/config.js");
+const fs = require('fs');
 
 class CompilationController extends BaseController {
 
@@ -174,7 +176,7 @@ class CompilationController extends BaseController {
         let section = request.params.section;
         let selectedCompilation = request.session.selectedCompilation;
 
-        let compilationList = [],billList = [], rationList = [], gljList = [],feeRateList = [], libData = {}, billsTemplateData = [];
+        let compilationList = [],billList = [], rationList = [], gljList = [],feeRateList = [], libData = {}, billsTemplateData = [],featureList = [];
         let valuationData = {}, valuationList = {}, artificialCoefficientList = [], calculationList = [], billsGuidanceList = [], mainTreeColList = [];
         let billTemplateList = [];
         try {
@@ -228,6 +230,9 @@ class CompilationController extends BaseController {
             //获取清单指引数据
             billsGuidanceList = await billsGuidanceFc.getBillsGuideLibs({compilationId: selectedCompilation._id, $or: [{deleted: null}, {deleted: false}]});
 
+            //获取工程特征库
+            featureList = await projectFeatureFacade.findByCondition({},null,false);
+
         } catch (error) {
             console.log(error);
         }
@@ -249,6 +254,7 @@ class CompilationController extends BaseController {
             gljCol:JSON.stringify(libData.glj_col),
             calculationList: JSON.stringify(calculationList),
             billsGuidanceList: JSON.stringify(billsGuidanceList),
+            featureList:JSON.stringify(featureList),
             layout: 'users/views/layout/layout',
             LicenseKey:config.getLicenseKey(process.env.NODE_ENV)
         };
@@ -518,10 +524,25 @@ class CompilationController extends BaseController {
         let overWriteUrl = request.body.overWriteUrl;
         try{
             let compilationModel = new CompilationModel();
-            await compilationModel.setOverWriteUrl(compilationId, overWriteUrl);
+            //绝对路径
+            let absoluteUrl = request.app.locals.rootDir + overWriteUrl;
+            //文件是否存在
+            let fileExists = fs.existsSync(absoluteUrl);
+            let pricePropertiesTemplate = [],
+                consumeAmtPropertiesTemplate = [];
+            if(fileExists && fs.statSync(absoluteUrl).isFile()){
+                //读取配置文件并赋值
+                let overWriteExports = require(absoluteUrl);
+                if(overWriteExports){
+                    pricePropertiesTemplate = overWriteExports.pricePropertiesTemplate ? overWriteExports.pricePropertiesTemplate : [];
+                    consumeAmtPropertiesTemplate = overWriteExports.consumeAmtPropertiesTemplate ? overWriteExports.consumeAmtPropertiesTemplate : [];
+                }
+            }
+            await compilationModel.setOverWriteUrl(compilationId, overWriteUrl, pricePropertiesTemplate, consumeAmtPropertiesTemplate);
             response.json({err: 0, msg: '', data: null});
         }
         catch (err){
+            console.log(err);
             response.json({err: 1, msg: err, data: null});
         }
     }

+ 2 - 2
modules/users/models/compilation_model.js

@@ -91,8 +91,8 @@ class CompilationModel extends BaseModel {
     /*
         设置代码覆盖路径
      */
-    async setOverWriteUrl(compilationId, overWriteUrl){
-        return await this.updateById(compilationId, {overWriteUrl: overWriteUrl});
+    async setOverWriteUrl(compilationId, overWriteUrl, priceProp, consumeAmtProp){
+        return await this.updateById(compilationId, {overWriteUrl: overWriteUrl, priceProperties: priceProp, consumeAmtProperties: consumeAmtProp});
     }
 
     /**

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

@@ -160,6 +160,9 @@ class EngineeringLibModel extends BaseModel {
         // 判断人工系数
         data.artificial_lib = this._validLib(data.artificial_lib);
 
+        //判断工程特征库
+        data.feature_lib = this._validLib(data.feature_lib);
+
         //计税方式组合
         data.tax_group = this._validLib(data.tax_group);
 

+ 0 - 1
modules/users/routes/compilation_route.js

@@ -10,7 +10,6 @@ import CompilationController from "../controllers/compilation_controller";
 
 const router = Express.Router();
 const compilationController = new CompilationController();
-
 module.exports = function (app) {
     // action定义区域
     router.get('/', compilationController.auth, compilationController.init, compilationController.index);

+ 40 - 2
web/maintain/billsGuidance_lib/js/billsGuidance.js

@@ -9,6 +9,10 @@
  */
 
 const billsGuidance = (function () {
+    function _isDef(v) {
+        return typeof v !== 'undefined' && v !== null;
+    }
+
     //自执行函数全局变量定义
     const libID = getQueryString('libID');
     const bills = {
@@ -313,19 +317,40 @@ const billsGuidance = (function () {
             return;
         }
         bills.tree.selected = node;
+
         if(!node.guidance.tree){
             getItemsByBills(libID, node.data.ID, function (rstData) {
                 initTree(node.guidance, guideSheet, guideItem.treeSetting, rstData);
+                //设置底色
+                setNodesColor(guideSheet, node.guidance.tree.items);
                 //项目指引初始焦点
                 guideItemInitSel(guideSheet.getActiveRowIndex() ? guideSheet.getActiveRowIndex() : 0);
             });
         }
         else{
             node.guidance.controller.showTreeData();
+            //设置底色
+            setNodesColor(guideSheet, node.guidance.tree.items);
             //项目指引初始焦点
             guideItemInitSel(guideSheet.getActiveRowIndex() ? guideSheet.getActiveRowIndex() : 0);
         }
     }
+    //根据奇偶层级设置节点底色,奇数层为蓝色(树节点深度为偶数)
+    function setNodesColor(sheet, nodes) {
+        const color = '#DFE8F9';
+        renderSheetFunc(sheet, function () {
+            for(let node of nodes){
+                let style = new GC.Spread.Sheets.Style();
+                style.borderLeft = new GC.Spread.Sheets.LineBorder("#D4D4D4", GC.Spread.Sheets.LineStyle.thin);
+                style.borderTop = new GC.Spread.Sheets.LineBorder("#D4D4D4", GC.Spread.Sheets.LineStyle.thin);
+                style.borderRight = new GC.Spread.Sheets.LineBorder("#D4D4D4", GC.Spread.Sheets.LineStyle.thin);
+                style.borderBottom = new GC.Spread.Sheets.LineBorder("#D4D4D4", GC.Spread.Sheets.LineStyle.thin);
+                let nDepth = node.depth();
+                style.backColor = nDepth % 2 == 0 && _isDef(node.data.type) && node.data.type === itemType.job ? color : 'White';
+                sheet.setStyle(node.serialNo(), -1, style);
+            }
+        });
+    }
     //选中的节点是否全是同层节点
     //@param {Object}sheet {Array}items @return {Boolean}
     function itemsSameDepth(sheet, items) {
@@ -584,7 +609,8 @@ const billsGuidance = (function () {
         let sectionSheet = section.workBook.getActiveSheet();
         CommonAjax.post('/rationRepository/api/getRationTree', {rationLibId: rationLibId}, function (sectionDatas) {
             //获取所有定额数据
-            CommonAjax.post('/rationRepository/api/getRationItemsByLib', {rationLibId: rationLibId, showHint: true, returnFields: '-_id code ID sectionId name unit basePrice rationGljList'}, function (rstData) {
+            let reqEntity = {rationLibId: rationLibId, showHint: true, returnFields: '-_id code ID sectionId name unit basePrice rationGljList jobContent annotation'};
+            CommonAjax.post('/rationRepository/api/getRationItemsByLib', reqEntity, function (rstData) {
                 section.cache = sectionDatas;
                 initTree(section, section.workBook.getActiveSheet(), section.treeSetting, sectionDatas);
                 //初始焦点在第一行(切换库)
@@ -744,6 +770,8 @@ const billsGuidance = (function () {
             if(callback){
                 callback();
             }
+            setNodesColor(sheet, bills.tree.selected.guidance.tree.items);
+            guideItem.workBook.focus(true);
             $.bootstrapLoading.end();
         });
     }
@@ -766,7 +794,9 @@ const billsGuidance = (function () {
         updateGuideItems(updateDatas, function () {
             controller.delete();
             refreshBtn(bills.tree.selected.guidance.tree.selected);
+            setNodesColor(guideItem.workBook.getActiveSheet(), bills.tree.selected.guidance.tree.items);
             $.bootstrapLoading.end();
+            guideItem.workBook.focus(true)
         });
     }
     //项目指引升级
@@ -789,7 +819,9 @@ const billsGuidance = (function () {
         updateGuideItems(updateDatas, function () {
             controller.upLevel();
             refreshBtn(bills.tree.selected.guidance.tree.selected);
+            setNodesColor(guideItem.workBook.getActiveSheet(), bills.tree.selected.guidance.tree.items);
             $.bootstrapLoading.end();
+            guideItem.workBook.focus(true)
         });
     }
     //项目指引降级
@@ -811,7 +843,9 @@ const billsGuidance = (function () {
         updateGuideItems(updateDatas, function () {
             controller.downLevel();
             refreshBtn(bills.tree.selected.guidance.tree.selected);
+            setNodesColor(guideItem.workBook.getActiveSheet(), bills.tree.selected.guidance.tree.items);
             $.bootstrapLoading.end();
+            guideItem.workBook.focus(true)
         });
     }
     //项目指引上移
@@ -832,7 +866,9 @@ const billsGuidance = (function () {
         updateGuideItems(updateDatas, function () {
             controller.upMove();
             refreshBtn(bills.tree.selected.guidance.tree.selected);
+            setNodesColor(guideItem.workBook.getActiveSheet(), bills.tree.selected.guidance.tree.items);
             $.bootstrapLoading.end();
+            guideItem.workBook.focus(true)
         });
     }
     //项目指引下移
@@ -853,7 +889,9 @@ const billsGuidance = (function () {
         updateGuideItems(updateDatas, function () {
             controller.downMove();
             refreshBtn(bills.tree.selected.guidance.tree.selected);
+            setNodesColor(guideItem.workBook.getActiveSheet(), bills.tree.selected.guidance.tree.items);
             $.bootstrapLoading.end();
+            guideItem.workBook.focus(true)
         });
     }
     //获取定额类型的项目指引名称,通过定额转换
@@ -970,7 +1008,7 @@ const billsGuidance = (function () {
             else{
                 let reg = new RegExp(searchStr, 'i');
                 ration.cache = _.filter(ration.datas, function (data) {
-                    return reg.test(data.code);
+                    return reg.test(data.code) || reg.test(data.name);
                 });
             }
             $('.top-content').hide();

+ 2 - 0
web/maintain/material_replace_lib/js/material_replace_edit.js

@@ -125,6 +125,7 @@ let materialOjb = {
         }else {
             this.billsList = this.allBills;
         }
+        this.billsList = _.sortBy(this.billsList,'code');
     },
     getMateriaList:async function () {
         let billsItemID =  this.getCurrentBillsID();
@@ -139,6 +140,7 @@ let materialOjb = {
         this.refreshMaterialSheet();
     },
     refreshMaterialSheet:function () {
+        this.materialList = _.sortBy(this.materialList,'code');
         sheetCommonObj.showData(this.materialSheet,this.materialSetting,this.materialList);
         this.materialSheet.setRowCount(this.materialList.length + 30);
     },

+ 7 - 11
web/maintain/project_feature_lib/html/edit.html

@@ -10,15 +10,15 @@
     <div class="content" >
         <div class="container-fluid" >
         <div class=" col-lg-12 p-0">
-            <!--<nav class="navbar sticky-top navbar-toggleable-md navbar-light bg-faded tools-bar">
+            <nav class="navbar sticky-top navbar-toggleable-md navbar-light bg-faded tools-bar">
                 <div class="collapse navbar-collapse" id="navbarNav">
                     <div class="tools-btn btn-group align-top">
-                        <a href="javascript:void(0)" class="btn btn-sm" id="insert"><i class="fa fa-sign-in" aria-hidden="true"></i> 插入</a>
-                        <a href="javascript:void(0)" class="btn btn-sm" id="delete"><i class="fa fa-remove" aria-hidden="true"></i> 删除</a>
+                        <a href="javascript:void(0)" class="btn btn-sm" id="format"><i class="fa fa-list-alt" aria-hidden="true"></i> 校验格式</a>
+                        <a href="javascript:void(0)" class="btn btn-sm" id="save"><i class="fa fa-floppy-o" aria-hidden="true"></i> 保存</a>
                     </div>
                 </div>
-            </nav>-->
-            <div class="main-data" id="featureSpread"></div>
+            </nav>
+            <textarea class="form-control" id="featureList" rows="38"></textarea>
         </div>
         </div>
         <input type="hidden" id="libID" value="<%= libID %>">
@@ -29,12 +29,8 @@
 
 <script type="text/javascript">
     //自适应高度
-    $(".main-data").height($(window).height()-$(".header").height()-$(".navbar").height());//-$(".tools-bar").height()
-    let billsList = '<%- featureList %>';
+    let featureList = '<%- featureList %>';
 
 </script>
-<script type="text/javascript" src="/lib/jquery-contextmenu/jquery.contextMenu.js"></script>
-<script type="text/javascript" src="/public/web/sheet/sheet_common.js"></script>
-<script type="text/javascript" src="/public/web/sheet/sheet_data_helper.js"></script>
-
+<script type="text/javascript" src="/lib/json/json2.js"></script>
 <script type="text/javascript" src="/web/maintain/project_feature_lib/js/project_feature_edit.js"></script>

+ 28 - 28
web/maintain/project_feature_lib/js/project_feature_edit.js

@@ -2,36 +2,36 @@
  * Created by zhang on 2018/9/3.
  */
 featureObj = {
-    featureSpread:null,
-    featureSheet:null,
-    setting:{
-        header: [
-            {headerName: "显示名称", headerWidth: 180, dataCode: "dispName", dataType: "String",formatter: "@"},
-            {headerName: "取值属性", headerWidth: 240, dataCode: "key", dataType: "String"},
-            {headerName: "单元格类型", headerWidth: 240, dataCode: "type", dataType: "String"}
-            //{headerName: "规则", headerWidth: 150, dataCode: "rule", hAlign: "left", dataType: "String",cellType:'comboBox',editorValueType:true,options:[{text:"规则1",value:1},{text:"规则2",value:2}]}
-        ],
-        view: {
-            lockColumns: []
-        },
-        headerHeight:45
-    },
-    initSpread:function () {
-        if(!this.featureSpread){
-            this.featureSpread = SheetDataHelper.createNewSpread($("#featureSpread")[0]);
-        }
-        this.featureSheet = this.featureSpread .getSheet(0);
-        sheetCommonObj.initSheet(this.featureSheet,this.setting, 30);
-        this.billsSheet.name('billsSheet');
-        this.billsSheet.bind(GC.Spread.Sheets.Events.ValueChanged, this.onBillsValueChange);
-        this.billsSheet.bind(GC.Spread.Sheets.Events.SelectionChanged,this.onBillsSelectionChange);
-        this.billsSheet.bind(GC.Spread.Sheets.Events.RangeChanged, this.onBillsRangeChange);
 
-        //this.initRightClick("billsSpread",this.billsSpread);
+};
 
+$(document).ready(function () {
+   $("#featureList").val(JSON.stringify(JSON.parse(featureList),null,4));
+
+   $("#format").click( function() {
+       try {
+           let jsonText =  $("#featureList").val();
+           $("#featureList").val(JSON.stringify(JSON.parse(jsonText),null,4));
+       }catch (err){
+           console.log(err);
+           alert("输入的JSON格式有误,请重新输入!");
+       }
+
+   })
+    $("#save").click(async function() {
+        try {
+            let libID = $("#libID").val();
+            let jsonText =  $("#featureList").val();
+            let newFeature = await ajaxPost("/projectFeature/saveLib",{query:{ID:libID},data:{feature:JSON.parse(jsonText)}});
+            console.log(newFeature);
+        }catch (err){
+            console.log(err);
+            alert("保存失败,请查看输入数据");
+        }
+
+    })
 
 
-    }
-};
 
-featureObj.initSpread();
+});
+//featureObj.initSpread();

+ 10 - 2
web/maintain/ration_repository/js/ration.js

@@ -139,7 +139,10 @@ let rationOprObj = {
             for (let j = 0; j < cacheSection.length; j++) {
                 if (updateArr[i]["ID"] && cacheSection[j]["ID"]) {
                     if (cacheSection[j]["ID"] == updateArr[i]["ID"]) {
-                        updateArr[i]['rationGljList'] = rationGLJOprObj.cache['_GLJ_' + cacheSection[j]['ID']] ? rationGLJOprObj.cache['_GLJ_' + cacheSection[j]['ID']] : [];
+                        updateArr[i]['rationGljList'] = rationGLJOprObj.cache['_GLJ_' + cacheSection[j]['ID']] ?
+                                                            rationGLJOprObj.cache['_GLJ_' + cacheSection[j]['ID']] :
+                                                        cacheSection[j]['rationGljList'] ?
+                                                            cacheSection[j]['rationGljList'] : [];
                         updateArr[i]['rationCoeList'] = cacheSection[j]['rationCoeList'] ? cacheSection[j]['rationCoeList'] : [];
                         updateArr[i]['rationAssList'] = cacheSection[j]['rationAssList'];
                         updateArr[i]['rationInstList'] = cacheSection[j]['rationInstList'];
@@ -147,7 +150,10 @@ let rationOprObj = {
                     }
                 } else {
                     if (cacheSection[j][me.setting.header[0].dataCode] == updateArr[i][me.setting.header[0].dataCode]) {
-                        updateArr[i]['rationGljList'] = rationGLJOprObj.cache['_GLJ_' + cacheSection[j]['ID']] ? rationGLJOprObj.cache['_GLJ_' + cacheSection[j]['ID']] : [];
+                        updateArr[i]['rationGljList'] = rationGLJOprObj.cache['_GLJ_' + cacheSection[j]['ID']] ?
+                                                            rationGLJOprObj.cache['_GLJ_' + cacheSection[j]['ID']] :
+                                                        cacheSection[j]['rationGljList'] ?
+                                                            cacheSection[j]['rationGljList'] : [];
                         updateArr[i]['rationCoeList'] = cacheSection[j]['rationCoeList'] ? cacheSection[j]['rationCoeList'] : [];
                         updateArr[i]['rationAssList'] = cacheSection[j]['rationAssList'];
                         updateArr[i]['rationInstList'] = cacheSection[j]['rationInstList'];
@@ -436,6 +442,7 @@ let rationOprObj = {
     },
     //todo: overwrite?
     onClipboardPasted: function(e, info) {
+        console.log('cp');
         let me = rationOprObj;
         let cacheSection = me.getCache();
         let updateArr = [], addArr = [];
@@ -510,6 +517,7 @@ let rationOprObj = {
             }
         };
          if (updateArr.length > 0 || addArr.length > 0) {
+             console.log(updateArr);
              me.mixUpdate = 1;
             me.mixUpdateRequest(updateArr, addArr, []);
         }

+ 10 - 1
web/maintain/std_glj_lib/html/gongliao.html

@@ -18,6 +18,10 @@
     </style>
     <!--zTree-->
   	<link rel="stylesheet" href="/lib/ztree/css/zTreeStyle.css" type="text/css">
+    <script type="text/javascript">
+        let priceProperties = JSON.parse('<%- priceProperties %>');
+        let consumeAmtProperties = JSON.parse('<%- consumeAmtProperties %>');
+    </script>
 </head>
 
 <body>
@@ -214,7 +218,9 @@
     <script type="text/javascript" src="/public/web/sheet/sheet_common.js"></script>
     <script type="text/javascript" src="/web/maintain/std_glj_lib/js/sheetsOpr.js"></script>
     <script type="text/javascript" src="/public/web/storageUtil.js"></script>
+    <% if(overWriteUrl){ %>
     <script type="text/javascript" src="<%= overWriteUrl %>"></script>
+    <% } %>
     <SCRIPT type="text/javascript">
         let userAccount = '<%=userAccount %>';
         let gljSetting = {
@@ -293,7 +299,10 @@
             }
         };
         $(document).ready(function(){
-            console.log(scMathUtil.roundTo(268.89472, -2));
+            let a = {a: 1, b: 2};
+            let b = {b:2, a: 1};
+            console.log(_.isEqual(a, b));
+            console.log(Object.keys(a));
             //解决spreadjs sheet初始化没高度宽度
             $('#modalCon').width($(window).width()*0.5);
             $('#componentTreeDiv').height($(window).height() - 300);

+ 8 - 8
web/over_write/js/chongqing_2018.js

@@ -3,30 +3,30 @@
  */
 //允许使用的工料机类型:人工、普通材料、混凝土、砂浆、配合比、商品混凝土、商品砂浆、其他材料费、机械台班、机上人工、机械组成物、仪器仪表、燃料动力费、折旧费、
 // 检修费、维护费、安拆费及场外运费、校验费、其他费用、其他施工机具使用费、主材、企业管理费、利润、一般风险费
-if(allowGljType){
+if(typeof allowGljType !== 'undefined'){
     allowGljType = [1, 201, 202, 203, 204, 205, 206, 207, 301, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 4, 6, 7, 8];
 }
-if(allowComponent){
+if(typeof allowComponent !== 'undefined'){
     //允许含有组成物的工料机类型:混凝土、砂浆、配合比、机械台班、仪器仪表、主材
     allowComponent = [202, 203, 204, 301, 304, 4];
 }
-if(componentType){
+if(typeof componentType !== 'undefined'){
     //可以作为组成物的工料机类型:普通材料、机械组成物、机上人工、燃料动力费、折旧费、检修费、维护费、安拆费及场外运费、校验费、其他费用、主材
     componentType = [201, 303, 305, 306, 307, 308, 309, 310, 311, 4];
 }
-if(machineAllowComponent){
+if(typeof machineAllowComponent !== 'undefined'){
     //允许含有组成物的机械工料机类型:机械台班、仪器仪表
     machineAllowComponent = [301, 304];
 }
-if(machineComponent){
+if(typeof machineComponent !== 'undefined'){
     //可以作为机械工料机组成物的工料机类型:机械组成物、机上人工、燃料动力费、折旧费、检修费、维护费、安拆费及场外运费、校验费、其他费用
     machineComponent = [303, 305, 306, 307, 308, 309, 310, 311];
 }
-if(materialAllowComponent){
+if(typeof materialAllowComponent !== 'undefined'){
     //允许含有组成物的材料工料机类型:混凝土、砂浆、配合比
     materialAllowComponent = [202, 203, 204];
 }
-if(materialComponent){
+if(typeof materialComponent !== 'undefined'){
     //可以作为材料工料机组成物的工料机类型:普通材料
     materialComponent = [201];
-}
+}

+ 28 - 11
web/users/js/compilation.js

@@ -60,7 +60,7 @@ $(document).ready(function() {
                     return false;
                 }
 
-                let removeHtml = '<a class="pull-right text-danger remove-lib" data-model="bill" ' +
+                let removeHtml = '<a class="pull-right text-danger remove-lib" data-model="'+model+'" ' +
                     'title="移除"><span class="glyphicon glyphicon-remove"></span></a>';
                 let tmpHtml = '<p class="form-control-static">' + removeHtml + addLib.name +
                     '<input type="hidden" data-id="'+ addLib.id +'" name=\'' + model + '_lib\' value=\'' + JSON.stringify(addLib) + '\'>' + '</p>';
@@ -194,6 +194,10 @@ $(document).ready(function() {
                 $("#program-area").show();
                 $("#add-compilation-title").text('添加计算程序');
                 break;
+            case 'feature':
+                $("#feature-area").show();
+                $("#add-compilation-title").text('添加工程特征');
+                break;
         }
         $("#addcompilation").modal('show');
     });
@@ -210,7 +214,7 @@ $(document).ready(function() {
     });
 
     // 移除操作
-    $(".bill-list, .ration-list, .glj-list, .fee-list, .artificial-list, .program-list, .billsGuidance-list").on("click", ".remove-lib", function() {
+    $(".bill-list, .ration-list, .glj-list, .fee-list, .artificial-list, .program-list, .billsGuidance-list,.feature-list").on("click", ".remove-lib", function() {
         $(this).parent().remove();
     });
 
@@ -356,6 +360,7 @@ function initCompilation() {
     let billsGuidanceData = billsGuidanceList === undefined ? [] : JSON.parse(billsGuidanceList);
     let billTemplateData = billTemplateList == undefined ? [] : JSON.parse(billTemplateList);
     let mainTreeColData= mainTreeColList == undefined ? [] : JSON.parse(mainTreeColList);
+    let featureData = featureList == undefined?[]: JSON.parse(featureList);
     /*mainTreeCol = mainTreeCol !== '' ? mainTreeCol.replace(/\n/g, '\\n') : mainTreeCol;
     billsTemplateData = billsTemplateData.replace(/\n/g, '\\n');
 
@@ -446,6 +451,14 @@ function initCompilation() {
         html += tmpHtml;
     }
     $("select[name='fee_lib']").children("option").first().after(html);
+
+    //工程特征库
+    html = '';
+    for(let tmp of featureData){
+        let tmpHtml = '<option value="' + tmp.ID + '">' + tmp.name + '</option>';
+        html += tmpHtml;
+    }
+    $("select[name='feature_lib']").children("option").first().after(html);
 }
 
 /**
@@ -459,10 +472,12 @@ function getAndValidData(model) {
     let standardBill = $("select[name='standard_bill']").children("option:selected").val();
     let rationLib = $("select[name='ration_lib']").children("option:selected").val();
     let gljLib = $("select[name='glj_lib']").children("option:selected").val();
-    let feeLib = $("select[name='fee_lib']").children("option:selected").val();
+   // let feeLib = $("select[name='fee_lib']").children("option:selected").val();
     let artificialLib = $("select[name='artificial_lib']").children("option:selected").val();
     let programLib = $("select[name='program_lib']").children("option:selected").val();
     let billsGuidanceLib = $("select[name='billsGuidance_lib']").children("option:selected").val();
+    let featureLib = $("select[name='feature_lib']").children("option:selected").val();
+
 
     if (name === '' && model === 'all') {
         throw '编办名字不能为空';
@@ -480,12 +495,8 @@ function getAndValidData(model) {
         throw '请选择人材机库';
     }
 
-    if (model === 'fee' && (feeLib === '' || feeLib === undefined)) {
-        throw '请选择费率标准';
-    }
-
     if (model === 'artificial' && (artificialLib === '' || artificialLib === undefined)) {
-        throw '请选择费率库';
+        throw '请选择人工系数库';
     }
 
     if (model === 'program' && (programLib === '' || programLib === undefined)) {
@@ -499,10 +510,12 @@ function getAndValidData(model) {
     let standardBillString = $("select[name='standard_bill']").children("option:selected").text();
     let rationLibString = $("select[name='ration_lib']").children("option:selected").text();
     let gljLibString = $("select[name='glj_lib']").children("option:selected").text();
-    let feeLibString = $("select[name='fee_lib']").children("option:selected").text();
+  //  let feeLibString = $("select[name='fee_lib']").children("option:selected").text();
     let artificialString = $("select[name='artificial_lib']").children("option:selected").text();
     let programString = $("select[name='program_lib']").children("option:selected").text();
     let billsGuidanceString = $("select[name='billsGuidance_lib']").children("option:selected").text();
+    let featrueString = $("select[name='feature_lib']").children("option:selected").text();
+
 
     let result = {
         name: name,
@@ -518,10 +531,10 @@ function getAndValidData(model) {
             id: gljLib,
             name: gljLibString
         },
-        fee: {
+      /*  fee: {
             id: feeLib,
             name: feeLibString
-        },
+        },*/
         artificial: {
             id: artificialLib,
             name: artificialString
@@ -533,6 +546,10 @@ function getAndValidData(model) {
         billsGuidance: {
             id: billsGuidanceLib,
             name: billsGuidanceString
+        },
+        feature:{
+            id:featureLib,
+            name:featrueString
         }
     };
     return result;

+ 20 - 1
web/users/views/compilation/engineering.html

@@ -11,7 +11,7 @@
     <div class="content-wrap">
         <div class="c-header" style="padding:0">
             <ul class="nav nav-tabs">
-                <li role="presentation" class="active"><a href="javascript:void(0);"><%= libData.name %></a></li>
+                <li role="presentation" class="active"><a href="javascript:void(0);"><%= libData.name %> - <%= libData.feeName %></a></li>
             </ul>
         </div>
         <div class="c-body">
@@ -106,7 +106,25 @@
                                 </div>
                                 <a href="#" class="btn btn-link btn-sm add-compilation" data-model="artificial">添加</a>
                             </div>
+                            <div class="form-group col-md-3">
+                                <label>工程特征</label>
+                                <div class="feature-list">
+                                    <% if (Object.keys(libData).length > 0 && libData.feature_lib && libData.feature_lib.length > 0) { %>
+                                    <% libData.feature_lib.forEach(function (feature, index){ %>
+                                    <p class="form-control-static">
+                                        <a class="pull-right text-danger remove-lib" data-model="feature" title="移除" data-id="<%= feature.id %>">
+                                            <span class="glyphicon glyphicon-remove"></span>
+                                        </a>
+                                        <input type="hidden" name="feature_lib" data-id="<%= feature.id %>" value="<%= JSON.stringify({id: feature.id, name: feature.name}) %>">
+                                        <% if (index === 0) {%><i class="glyphicon glyphicon-flag"></i>&nbsp;<% } %><%= feature.name %>
+                                    </p>
+                                    <% }) %>
+                                    <% } %>
+                                </div>
+                                <a href="#" class="btn btn-link btn-sm add-compilation" data-model="feature">添加</a>
+                            </div>
                     </div>
+
                     <div class="col-md-12">
                         <a data-toggle="modal" data-target="#other_setting" class="btn btn-primary btn-sm " style="margin-right:5px">显示设置</a>
                     </div>
@@ -194,6 +212,7 @@
     let gljCol = '<%- gljCol %>';
     let billTemplateList = '<%- billTemplateList %>';
     let mainTreeColList = '<%- mainTreeColList %>';
+    let featureList = '<%- featureList %>';
     let colSpread = null;
     let colEditSpread = null;
 </script>

+ 5 - 5
web/users/views/compilation/modal.html

@@ -51,16 +51,16 @@
                         </div>
                     </div>
                 </div>
-         <!--       <div class="form-group" id="fee-area">
-                    <label>费率标准</label>
+                <div class="form-group" id="feature-area">
+                    <label>工程特征</label>
                     <div class="row">
                         <div class="col-xs-12">
-                            <select class="form-control" name="fee_lib">
-                                <option value="">请选择费率库</option>
+                            <select class="form-control" name="feature_lib">
+                                <option value="">请选择工程特征库</option>
                             </select>
                         </div>
                     </div>
-                </div>-->
+                </div>
                 <div class="form-group" id="artificial-area">
                     <label>人工系数</label>
                     <div class="row">