Przeglądaj źródła

Merge branch '1.0.0_online' of http://192.168.1.12:3000/SmartCost/ConstructionCost into 1.0.0_online

TonyKang 6 lat temu
rodzic
commit
115bc89775

+ 31 - 0
modules/all_models/product.js

@@ -0,0 +1,31 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2019/3/21
+ * @version
+ */
+/*
+ * 与产品绑定的信息都可以在此设置
+ * */
+const mongoose = require('mongoose');
+const Schema = mongoose.Schema;
+const productSchema = new Schema({
+    name: {
+        type: String,
+        default: '纵横建筑计价'
+    },
+    company: {
+        type: String,
+        default: '珠海纵横创新软件有限公司'
+    },
+    icp: {
+        type: String,
+        default: '粤ICP备14032472号'
+    },
+    version: String
+}, {versionKey: false});
+
+mongoose.model('product', productSchema, 'product');

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

@@ -687,5 +687,14 @@ module.exports = {
             console.log(err);
             callback(req, res, 1, err, []);
         }
+    },
+    getProjectByGranularity: async function(req, res) {
+        try {
+            let data = JSON.parse(req.body.data);
+            let projData = await pm_facade.getProjectByGranularity(data.tenderID, data.granularity, req.session.sessionUser.id, req.session.compilationVersion);
+            callback(req, res, 0, 'success', projData);
+        } catch (err) {
+            callback(req, res, 1, err, null);
+        }
     }
 };

+ 48 - 1
modules/pm/facade/pm_facade.js

@@ -25,7 +25,8 @@ module.exports={
     prepareInitialData: prepareInitialData,
     changeFile:changeFile,
     getBasicInfo: getBasicInfo,
-    getProjectFeature: getProjectFeature
+    getProjectFeature: getProjectFeature,
+    getProjectByGranularity: getProjectByGranularity
 };
 
 
@@ -62,6 +63,7 @@ let compilationModel = mongoose.model('compilation');
 let engineeringModel = mongoose.model('engineering_lib');
 let basicInfoModel = mongoose.model('std_basic_info_lib');
 let projectFeatureModel = mongoose.model('std_project_feature_lib');
+let productModel = mongoose.model('product');
 
 let featureLibModel =  mongoose.model("std_project_feature_lib");
 let scMathUtil = require('../../../public/scMathUtil').getUtil();
@@ -1050,4 +1052,49 @@ async function getProjectFeature(valuationID, engineeringName, feeName) {
     }
     let featureLib = await projectFeatureModel.findOne({ID: engineering.feature_lib[0].id});
     return featureLib;
+}
+
+//根据单位工程,获取建设项目-单项工程-单位工程,不包含无单位工程的单项工程
+//@param {Number}tenderID(单位工程ID) {Number}granularity(颗粒度 1:建设项目 2:单项工程 3:单位工程)
+async function getProjectByGranularity(tenderID, granularity, userID, versionName) {
+    const GRANULARITY = {
+        PROJECT: 1,
+        ENGINEERING: 2,
+        TENDER: 3
+    };
+    let theTender = await projectModel.findOne({ID: tenderID});
+    if (!theTender) {
+        return null;
+    }
+    let theEngineering = await projectModel.findOne({ID: theTender.ParentID});
+    if (!theEngineering) {
+        return null;
+    }
+    let constructionProject = await projectModel.findOne({ID: theEngineering.ParentID});
+    if (!constructionProject) {
+        return null;
+    }
+    let engineerings;
+    if (granularity === GRANULARITY.PROJECT) {
+        engineerings = await projectModel.find({ParentID: constructionProject.ID, $or: notDeleted});
+        for (let eng of engineerings) {
+            eng._doc.children = await projectModel.find({ParentID: eng.ID, $or: notDeleted});
+        }
+    } else {
+        engineerings = [theEngineering];
+        if (granularity === GRANULARITY.ENGINEERING) {
+            theEngineering._doc.children = theTender;
+        } else {
+            theEngineering._doc.children = await projectModel.find({ParentID: theEngineering.ID, $or: notDeleted});
+        }
+    }
+    constructionProject._doc.children = engineerings;
+    //获取汇总信息
+    constructionProject._doc.summaryInfo = await getSummaryInfo([constructionProject.ID]);
+    //获取编制软件信息: 软件公司;软件名;版本号;授权信息; base64
+    let product = await productModel.findOne({});
+    let company = product.company || '珠海纵横创新软件有限公司',
+        version = product.version || '';
+    constructionProject._doc.softInfo = new Buffer(`${company};${versionName};${version};${userID}`).toString('base64');
+    return constructionProject;
 }

+ 9 - 0
modules/pm/models/project_model.js

@@ -813,6 +813,15 @@ ProjectsDAO.prototype.getConstructionProperty = async function (projectID) {
     return constructionProject.property;
 };
 
+ProjectsDAO.prototype.getBasicInfo = async function (projectID) {
+    //获取建设项目
+    let constructionProject = await pmFacade.getConstructionProject(projectID);
+    if(!constructionProject || !constructionProject.property || !constructionProject.property.basicInformation){
+        return null;
+    }
+    return constructionProject.property.basicInformation;
+};
+
 //恢复默认系统设置
 ProjectsDAO.prototype.defaultSettings = async function (userID, compilationId, projectID) {
     let project = await Projects.findOne({ID: projectID});

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

@@ -63,6 +63,7 @@ module.exports = function (app) {
     pmRouter.post('/changeFile', pmController.changeFile);
     pmRouter.post('/getBasicInfo', pmController.getBasicInfo);
     pmRouter.post('/getProjectFeature', pmController.getProjectFeature);
+    pmRouter.post('/getProjectByGranularity', pmController.getProjectByGranularity);
     app.use('/pm/api', pmRouter);
 };
 

web/building_saas/css/login-bgp.jpg → web/building_saas/css/login-bg.jpg


+ 1 - 0
web/building_saas/main/html/main.html

@@ -2058,6 +2058,7 @@
     <script type="text/javascript" src="/public/web/id_tree.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/models/cache_tree.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/calc/calc_fees.js"></script>
+    <script type="text/javascript" src="/web/building_saas/main/js/models/exportStandardInterface.js"></script>
     <!--<script type="text/javascript" src="/web/building_saas/main/js/calc/ration_calc.js"></script>-->
     <!--<script type="text/javascript" src="/web/building_saas/main/js/calc/bills_calc.js"></script>-->
     <!--<script type="text/javascript" src="/public/calc_util.js"></script>-->

+ 729 - 0
web/building_saas/main/js/models/exportStandardInterface.js

@@ -0,0 +1,729 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2019/3/15
+ * @version
+ */
+
+/*
+* 数据标准接口
+* 导出符合标准接口要求的xml
+* */
+
+const XMLStandard = (function () {
+    //属性类型
+    const TYPE = {
+        DATE: 1,        //日期类型YYYY-MM-DD
+        DATE_TIME: 2,   //日期类型YYY-MM-DDTHH:mm:ss
+        INT: 3,         //整数类型
+        DECIMAL: 4,     //数值类型,不限制小数位数
+        NUM2: 5,        //数值类型2:最多两位小数
+        BOOL: 6         //布尔型
+    };
+    const WHITE_SPACE = {
+        COLLAPSE: 1 //移除所有空白字符(换行、回车、空格以及制表符会被替换为空格,开头和结尾的空格会被移除,而多个连续的空格会被缩减为一个单一的空格)
+    };
+    /*
+    * 标准文件中的约束(唯一性)
+    * path为'.//'时,路径为:当前上下文中一级或多级深度
+    * path为'a/b'时,路径为: 当前上下文a节点下节点b
+    * */
+    const CONSTRAINTS = {
+        //建设项目上下文的约束
+        PROJECT: [
+            {path: './/', selector: '单项工程', field: '编号'},          //建设项目下所有单项工程,编号唯一
+            {path: './/', selector: '单位工程', field: '编号'},             //建设项目下所有单位工程,编号唯一
+        ],
+        //单位工程上下文的约束
+        TENDER: [
+            {path: './/', selector: '清单项目', field: '项目编码'},                          //单位工程下所有清单项目,项目编码唯一
+            {path: './/', selector: '公式计算措施项', field: '序号'},                        //单位工程下所有公式措施项,序号唯一
+            {path: './/', selector: '人材机', field: '代码'},                               //单位工程下所有人材机,代码唯一
+            {path: './/', selector: '暂列金额明细', field: '编号'},                          //单位工程下所有暂列金额明细,编号唯一
+            {path: './/', selector: '专业工程暂估明细', field: '编号'},                      //单位工程下所有专业工程暂估明细,编号唯一
+            {path: './/', selector: '总承包服务费费用项', field: '编号'},                    //单位工程下所有总承包服务费费用项,编号唯一
+            {path: '其他项目清单/计日工/人工', selector: '计日工项目', field: '编号'},         //单位工程/其他项目清单/计日工/人工下所有计日工项目,编号唯一
+            {path: '其他项目清单/计日工/材料', selector: '计日工项目', field: '编号'},         //单位工程/其他项目清单/计日工/材料下所有计日工项目,编号唯一
+            {path: '其他项目清单/计日工/施工机械', selector: '计日工项目', field: '编号'},     //单位工程/其他项目清单/计日工/施工机械下所有计日工项目,编号唯一
+            {path: './/', selector: '其他列项', field: '序号'},                             //单位工程下所有其他列项,序号唯一
+            {path: './/', selector: '费用项', field: '序号'},                               //单位工程下所有费用项,序号唯一
+        ]
+    };
+    /*
+    * 唯一性约束检查
+    * 无法在创建节点时就检查,需要形成完整的数据后检查
+    * @param{Object}element(节点) {Array}constraints(约束数据)
+    * */
+
+    /*
+     * 检查
+     * 创建节点时检查节点的数据
+     * 1.长度限制minLen,maxLen
+     * 2.值的限制,固定范围:enumeration
+     * @param {Array}datas(需要检查的属性数据)
+     * @return {Array}没通过的属性
+     * */
+    function check(datas) {
+        let rst = [];
+        let dateReg = /([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8])))/;
+        for (let data of datas) {
+            data.value = typeof data.value === 'undefined' || data.value === null ? '' : data.value.toString();
+            if (data.whiteSpace && data.whiteSpace === WHITE_SPACE.COLLAPSE) {
+                data.value = data.value.replace(/[\r,\n,\t]/g, ' ');
+                data.value = data.value.trim();
+                data.value = data.value.replace(/\s{1,}/g, ' ');
+            }
+            if (!data.value && !data.minLen && !data.enumeration) {  //值为空,且没有限制最小字符数,且没有限制值,则跳过
+                continue;
+            }
+            if (data.minLen && data.value.length < data.minLen){
+                rst.push(`“${data.name}”字符数不可小于${data.minLen}个`);
+            } else if (data.maxLen && data.value.length > data.maxLen) {
+                rst.push(`“${data.name}”字符数不可大于${data.maxLen}个`);
+            } else if (data.enumeration && !data.enumeration.includes(data.value)) {
+                rst.push(`“${data.name}”只能从“${data.enumeration.join(';')}”中选择`);
+            } else if (data.type && data.type === TYPE.DATE && !dateReg.test(data.value)) {
+                rst.push(`“${data.name}”日期格式必须是YYYY-MM-DD`);
+            } else if (data.type && data.type === TYPE.INT && !Number.isInteger(parseFloat(data.value))) {
+                rst.push(`“${data.name}”必须为整数`);
+            } else if (data.type && data.type === TYPE.DECIMAL && isNaN(parseFloat(data.value))) {
+                rst.push(`“${data.name}”必须为数值`)
+            } else if (data.type && data.type === TYPE.NUM2) {
+                let v = parseFloat(data.value);
+                if (isNaN(v)) {
+                    rst.push(`“${data.name}”必须为数值`);
+                } else if (data.value.split('.')[1].length > 2){
+                    rst.push(`“${data.name}”小数位数不得多于两位`);
+                }
+            } else if (data.type && data.type === TYPE.BOOL && !['true', 'false'].includes(data.value.toString())) {
+            }
+        }
+        return rst;
+    }
+    //从fees数组中获取相关费用
+    function getFee(fees, feeFields) {
+        let fields = feeFields.split('.');
+        let fee = fees.find(data => data.feeName === fields[0]);
+        if (fee) {
+            return 0;
+        }
+        return fee[fields[1]] || 0;
+    }
+    //造成导出失败
+    let failList = [];
+    /*
+     * 定义不设置一个Node方法统一进入的原因:模板化比较直观,不分开定义节点的话,调用传参也很麻烦而且不直观。
+     * 一个节点对应一个构造方法,方便其他版本开发、接收的人看起来更直观
+     * @param {String}name(节点名) {Array}attrs(节点属性数据)
+     * @return {void}
+     * */
+    function element(name, attrs) {
+        this.element = name;
+        this.attrs = attrs;
+        this.children = [];
+        this.fail = check(attrs);
+        for (let fail of this.fail) {
+            failList.push(`${name}-${fail}`);
+        }
+    }
+    //根据字段获取基本信息、工程特征
+    function getValueByKey(data, key) {
+        for (let d of data) {
+            if (d.key === key) {
+                return d.value;
+            }
+            if (d.items && d.items.length > 0) {
+                let findData = d.items.find(x => x.key === key);
+                if (findData) {
+                    return findData.value;
+                }
+            }
+        }
+        return '';
+    }
+    //建设项目定义
+    //source:来源数据
+    function Project(source) {
+        let attrs = [
+            {name: '项目编号', value: getValueByKey(source.basicInformation, 'projNumber'), minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE},
+            {name: '项目名称', value: source.name, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE},
+            {name: '建设单位', value: getValueByKey(source.basicInformation, 'constructionUnit')},
+            {name: '标准版本号', value: '3.2.2'},
+            {name: '标准名称', value: '重庆造价软件数据交换标准(清单计价)'},
+            {name: '文件类型', value: getValueByKey(source.basicInformation, 'fileKind'), enumeration: ['招标', '投标', '控制价', '结算', '其他']},
+            {name: '计税方法', value: 'todo'},
+        ];
+        element.call(this, '标段', attrs);
+    }
+    //项目信息定义
+    function ProjectInfo(source) {
+        let attrs = [
+            {name: '工程规模', value: getValueByKey(source.basicInformation, 'projectScale')},
+            {name: '工程所在地', value: getValueByKey(source.basicInformation, 'projLocation')},
+            {name: '工程地址', value: getValueByKey(source.basicInformation, 'projAddress')},
+            {name: '施工单位', value: getValueByKey(source.basicInformation, 'buildingUnit')},
+            {name: '编制单位', value: getValueByKey(source.basicInformation, 'establishmentUnit')},
+            {name: '审核单位', value: getValueByKey(source.basicInformation, 'auditUnit')},
+            {name: '编制人', value: getValueByKey(source.basicInformation, 'buildingUnitAuthor')},
+            {name: '审核人', value: 'todo'},
+            {name: '开工日期', value: getValueByKey(source.basicInformation, 'commencementDate'), type: TYPE.DATE},
+            {name: '竣工日期', value: getValueByKey(source.basicInformation, 'completionDate'), type: TYPE.DATE},
+            {name: '编制日期', value: getValueByKey(source.basicInformation, 'establishDate'), type: TYPE.DATE},
+            {name: '审核日期', value: getValueByKey(source.basicInformation, 'auditDate'), type: TYPE.DATE},
+            {name: '材料价格期', value: getValueByKey(source.basicInformation, 'materialPricePeriod')},
+            {name: '合同价类型', value: getValueByKey(source.basicInformation, 'contractPriceType')},
+
+        ];
+        element.call(this, '项目信息', attrs);
+    }
+    //招标信息定义
+    function BiddingInfo(source) {
+        let attrs = [
+            {name: '招标代理机构', value: getValueByKey(source.basicInformation, 'tenderingAgency')},
+            {name: '造价工程师', value: getValueByKey(source.basicInformation, 'tenderCostEngineer')},
+            {name: '造价工程师注册证号', value: getValueByKey(source.basicInformation, 'tenderCostEngineerNo')},
+            {name: '招标工期', value: getValueByKey(source.basicInformation, 'tenderPeriod'), type: TYPE.INT},
+            {name: '控制总价', value: source.summaryInfo.engineeringCost, type: TYPE.NUM2},
+        ];
+        element.call(this, '招标信息', attrs);
+    }
+    //投标信息定义
+    function BidInfo(source) {
+        let attrs = [
+            {name: '投标人', value: getValueByKey(source.basicInformation, 'bidder')},
+            {name: '造价工程师', value: getValueByKey(source.basicInformation, 'bidCostEngineer')},
+            {name: '造价工程师注册证号', value: getValueByKey(source.basicInformation, 'bidCostEngineerNo')},
+            {name: '项目经理', value: getValueByKey(source.basicInformation, 'projectManager')},
+            {name: '投标工期', value: getValueByKey(source.basicInformation, 'biddingPeriod')},
+            {name: '投标保证金', value: getValueByKey(source.basicInformation, 'biddingMargin'), type: TYPE.NUM2},
+            {name: '质量承诺', value: getValueByKey(source.basicInformation, 'qualityCommitment')},
+            {name: '担保类型', value: getValueByKey(source.basicInformation, 'guaranteeType')},
+            {name: '投标总价', value: source.summaryInfo.engineeringCost, type: TYPE.NUM2},
+        ];
+        element.call(this, '投标信息', attrs);
+    }
+    //编制说明定义
+    function CompilationIllustration(source) {
+        let attrs = [
+            {name: '内容', value: source.compilationIllustration},
+        ];
+        element.call(this, '编制说明', attrs);
+    }
+    //系统信息定义
+    function SystemInfo(source) {
+        let attrs = [
+            {name: 'ID1', value: source.softInfo},
+            {name: 'ID2', value: ''},
+            {name: '生成时间', value: source.generatedTime, type: TYPE.DATE_TIME},
+        ];
+        element.call(this, '系统信息', attrs);
+    }
+    //费用构成定义
+    function FeeFrom(summaryInfo) {
+        let attrs = [
+            {name: '工程费合计', value: summaryInfo.engineeringCost, type: TYPE.NUM2},
+            {name: '分部分项清单合计', value: summaryInfo.subEngineering, type: TYPE.NUM2},
+            {name: '措施项目清单合计', value: summaryInfo.measure, type: TYPE.NUM2},
+            {name: '安全文明施工专项费', value: summaryInfo.safetyConstruction, type: TYPE.NUM2},
+            {name: '其他项目清单合计', value: summaryInfo.other, type: TYPE.NUM2},
+            {name: '规费', value: summaryInfo.charge, type: TYPE.NUM2},
+            {name: '税金', value: summaryInfo.tax, type: TYPE.NUM2},
+        ];
+        element.call(this, '费用构成', attrs);
+    }
+    //单项工程定义
+    function engineering(source) {
+        let attrs = [
+            {name: '编号', value: source.code, minLen: 1, maxLen: 255},
+            {name: '名称', value: source.name, minLen: 1, maxLen: 255},
+            {name: '金额', value: source.summaryInfo.engineeringCost, type: TYPE.NUM2},
+        ];
+        element.call(this, '单项工程', attrs);
+    }
+    //单位工程定义
+    function tender(source) {
+        const TAX = {
+            1: '一般计税',
+            2: '简易计税'
+        };
+        let attrs = [
+            {name: '编号', value: source.code, minLen: 1, maxLen: 255},
+            {name: '名称', value: source.name, minLen: 1, maxLen: 255},
+            {name: '专业', value: source.property.engineering},
+            {name: '金额', value: source.summaryInfo.engineeringCost, type: TYPE.NUM2},
+            {name: '定额库编码', value: source.property.defaultRationLibCode},
+            {name: '计税方法', value: TAX[source.property.taxType]},
+        ];
+    }
+    //工程特征定义
+    function engFeature(source) {
+        let attrs = [
+            {name: '建筑分类', value: source.feature.buildingClass, },
+            {name: '工程分类', value: source.feature.projClass, },
+            {name: '建设规模', value: 'todo', },
+            {name: '工程类别', value: source.basicInformation.projectCategory} //取建设项目的工程类别
+        ];
+        element.call(this, '工程特征', attrs);
+    }
+    //特征项定义
+    function featureItem(feature) {
+        let attrs = [
+            {name: '编码', value: ''},
+            {name: '名称', value: feature.dispName},
+            {name: '内容', value: feature.value},
+        ];
+        element.call(this, '特征项', attrs);
+    }
+    //单位工程费汇总定义
+    function tenderFeeSummary() {
+        element.call(this, '单位工程费汇总', []);
+    }
+    //计价程序费用行定义
+    function dxfyRow(source) {
+        let attrs = [
+            {name: '序号', value: source.code},
+            {name: '行代号', value: source.rowCode},
+            {name: '项目名称', value: source.name},
+            {name: '计算基础表达式', value: source.calcBase},
+            {name: '计算基础说明', value: source.calcBaseAnnotation},
+            {name: '费率', value: source.feeRate},
+            {name: '金额', value: getFee(source.fees, 'common.totalFee'), type: TYPE.NUM2},
+            {name: '其中暂估价', value: getFee(source.fees, 'estimate.totalFee'), type: TYPE.NUM2},
+            {name: '费用类别', value: source.feeType, type: TYPE.INT},
+            {name: '备注', value: source.remark},
+        ];
+        element.call(this, '计价程序费用行', attrs);
+    }
+    //分部分项清单
+    function fbfxBills() {
+        element.call(this, '分部分项清单', []);
+    }
+    //清单分部定义
+    function fbBills(source) {
+        let attrs = [
+            {name: '编号', value: source.code, maxLen: 20},
+            {name: '名称', value: source.name, minLen: 1, maxLen: 255},
+            {name: '金额', value: getFee(source.fees, 'common.totalFee'), type: TYPE.NUM2},
+            {name: '其中暂估价', value: getFee(source.fees, 'estimate.totalFee')},
+            {name: '备注', value: source.remark}
+        ];
+        element.call(this, '清单分部', attrs);
+    }
+    //清单项目定义
+    function fxbills(source) {
+        let attrs = [
+            {name: '项目编码', value: source.code, minLen: 1, maxLen: 20},
+            {name: '项目名称', value: source.name, minLen: 1, maxLen: 500},
+            {name: '单位', value: source.unit, minLen: 1, maxLen: 20},
+            {name: '工程量', value: source.quantity, type: TYPE.DECIMAL},
+            {name: '综合单价', value: getFee(source.fees, 'common.unitFee'), type: TYPE.DECIMAL},
+            {name: '综合合价', value: getFee(source.fees, 'common.totalFee'), type: TYPE.NUM2},
+            {name: '其中暂估价', value: getFee(source.fees, 'estimate.totalFee'), type: TYPE.NUM2},
+            {name: '主要清单标志', value: source.mainBills, type: TYPE.BOOL},
+            {name: '暂估清单标志', value: source.isEstimate, type: TYPE.BOOL},
+            {name: '备注', value: source.remark},
+        ];
+        element.call(this, '清单项目', attrs);
+    }
+    //项目特征定义
+    function itemCharacter() {
+        element.call(this, '项目特征', []);
+    }
+    //特征定义
+    function feature(source) {
+        let attrs = [
+            {name: '特征名称', value: source.name},
+            {name: '特征描述', value: source.value},
+        ];
+        element.call(this, '特征', attrs);
+    }
+    //工程内容定义
+    function jobContent() {
+        element.call(this, '工程内容', []);
+    }
+    //内容定义
+    function content(content) {
+        let attrs = [
+            {name: '内容', value: content}
+        ];
+        element.call(this, '内容', attrs);
+    }
+    //组价内容定义
+    function priceContent() {
+        element.call(this, '组价内容', []);
+    }
+    //定额子目定义
+    function ration(source) {
+        let attrs = [
+            {name: '定额编号', value: source.viewCode, minLen: 1, maxLen: 80},
+            {name: '项目名称', value: source.viewCode, minLen: 1, maxLen: 255},
+            {name: '单位', value: source.unit, minLen: 1, maxLen: 20},
+            {name: '定额库编码', value: source.libCode},
+            {name: '原始定额编号', value: source.code, minLen: 1, maxLen: 80},
+            {name: '子目类型', value: source.code, type: TYPE.INT, enumeration: [0, 1, 2, 3, 4, 5, 6]},
+            {name: '工程量', value: source.quantity, type: TYPE.DECIMAL},
+            {name: '工程量计算式', value: source.quantityEXP},
+            {name: '定额单价', value: getFee(source.fees, 'rationUnitPrice.unitFee'), type: TYPE.DECIMAL},
+            {name: '定额合价', value: getFee(source.fees, 'rationUnitPrice.totalFee'), type: TYPE.NUM2},
+            {name: '综合单价', value: getFee(source.fees, 'common.unitFee'), type: TYPE.DECIMAL},
+            {name: '综合合价', value: getFee(source.fees, 'common.totalFee'), type: TYPE.NUM2},
+            {name: '单价构成文件ID', value: 0, type: TYPE.INT}, //todo
+            {name: '分包标志', value: source.isSubcontract, type: TYPE.BOOL},
+            {name: '备注', value: source.remark}
+        ];
+        element.call(this, '定额子目', attrs);
+    }
+    //工料分析定义
+    function gljAnalyze() {
+        element.call(this, '工料分析', []);
+    }
+    //人材机含量定义
+    function gljContent(source) {
+        let attrs = [
+            {name: '人材机代码', value: source.code, minLen: 1, maxLen: 20},
+            {name: '消耗量', value: source.quantity, type: TYPE.DECIMAL},
+            {name: '总消耗量', value: source.totalQuantity, type: TYPE.DECIMAL},
+            {name: '数量计算方式', value: 1, type: TYPE.INT},
+        ];
+        element.call(this, '人材机含量', attrs);
+    }
+    //费用组成
+    function feeContent(source) {
+        let attrs = [
+            {name: '基价人工费单价', value: getFee(source.fees, 'labour.unitFee'), type: TYPE.DECIMAL},
+            {name: '基价人工费合价', value: getFee(source.fees, 'labour.totalFee'), type: TYPE.NUM2},
+            {name: '定额人工基价调整单价', value: 0, type: TYPE.DECIMAL}, //调整价目前只有08有,默认设置成0
+            {name: '定额人工基价调整合价', value: 0, type: TYPE.NUM2},
+            {name: '基价材料费单价', value: getFee(source.fees, 'material.unitFee'), type: TYPE.DECIMAL},
+            {name: '基价材料费合价', value: getFee(source.fees, 'material.totalFee'), type: TYPE.NUM2},
+            {name: '基价机械费单价', value: getFee(source.fees, 'machine.unitFee'), type: TYPE.DECIMAL},
+            {name: '基价机械费合价', value: getFee(source.fees, 'machine.totalFee'), type: TYPE.NUM2},
+            {name: '定额机上人工基价调整单价', value: 0, type: TYPE.DECIMAL},
+            {name: '定额机上人工基价调整合价', value: 0, type: TYPE.NUM2},
+            {name: '未计材料单价', value: getFee(source.fees, 'unratedMaterial.unitFee'), type: TYPE.DECIMAL},
+            {name: '未计材料合价', value: getFee(source.fees, 'unratedMaterial.totalFee'), type: TYPE.NUM2},
+            {name: '人材机价差单价', value: getFee(source.fees, 'gljDiff.unitFee'), type: TYPE.DECIMAL},   //人材机价差通过人工、材料、机械价差相加得出
+            {name: '人材机价差合价', value: getFee(source.fees, 'gljDiff.totalFee'), type: TYPE.NUM2},
+            {name: '暂估材料单价', value: getFee(source.fees, 'estimate.unitFee'), type: TYPE.DECIMAL},
+            {name: '暂估材料合价', value: getFee(source.fees, 'estimate.totalFee'), type: TYPE.NUM2},
+            {name: '管理费单价', value: getFee(source.fees, 'manage.unitFee'), type: TYPE.DECIMAL},
+            {name: '管理费合价', value: getFee(source.fees, 'manage.totalFee'), type: TYPE.NUM2},
+            {name: '利润单价', value: getFee(source.fees, 'profit.unitFee'), type: TYPE.DECIMAL},
+            {name: '利润合价', value: getFee(source.fees, 'profit.totalFee'), type: TYPE.NUM2},
+            {name: '风险单价', value: getFee(source.fees, 'risk.unitFee'), type: TYPE.DECIMAL}, //重庆08叫风险费 重庆18叫一般风险费
+            {name: '风险合价', value: getFee(source.fees, 'risk.totalFee'), type: TYPE.NUM2},
+            {name: '一般风险单价', value: getFee(source.fees, 'risk.unitFee'), type: TYPE.DECIMAL},
+            {name: '一般风险合价', value: getFee(source.fees, 'risk.totalFee'), type: TYPE.NUM2},
+            {name: '其他风险单价', value: getFee(source.fees, 'otherRisk.unitFee'), type: TYPE.DECIMAL},
+            {name: '其他风险合价', value: getFee(source.fees, 'otherRisk.totalFee'), type: TYPE.NUM2},
+        ];
+        element.call(this, '费用组成', attrs);
+    }
+    //措施项目清单定义
+    function csxmBills(source) {
+        let attrs = [
+            {name: '金额', value: getFee(source.fees, 'common.totalFee'), type: TYPE.NUM2},
+            {name: '其中暂估价', value: getFee(source.fees, 'estimate.totalFee'), type: TYPE.NUM2},
+        ];
+        element.call(this, '措施项目清单', attrs);
+    }
+    //组织措施清单定义
+    function zzcsBills(source) {
+        let attrs = [
+            {name: '金额', value: getFee(source.fees, 'common.totalFee'), type: TYPE.NUM2},
+        ];
+        element.call(this, '组织措施清单', attrs);
+    }
+    //组织措施分类定义
+    function zzcsClass(source) {
+        let attrs = [
+            {name: '编码', value: source.code, maxLen: 20},
+            {name: '名称', value: source.name, minLen: 1, maxLen: 255},
+            {name: '金额', value: getFee(source.fees, 'common.totalFee'), type: TYPE.NUM2},
+            {name: '备注', value: source.remark}
+        ];
+        element.call(this, '组织措施分类', attrs);
+    }
+    //公式计算措施项
+    function formulaCalcMeasure(source) {
+        let attrs = [
+            {name: '序号', value: source.code, minLen: 1, maxLen:20},
+            {name: '名称', value: source.name, minLen: 1, maxLen: 255},
+            {name: '计算基础表达式', value: source.calcBase},
+            {name: '计算基础说明', value: source.calcBaseAnnotation},
+            {name: '费率', value: source.feeRate},
+            {name: '金额', value: getFee(source.fees, 'common.totalFee')},
+            {name: '金额', value: getFee(source.fees, 'common.totalFee')},
+            {name: '暂估价标志', value: getFee(source.fees, 'common.totalFee')},
+            {name: '备注', value: source.remark},
+            {name: '费用类别', value: source.feeType, enumeration: [120201, 1204, 10041, 1206]},
+        ]
+    }
+    //技术措施清单定义
+    function jscsBills(source) {
+        let attrs = [
+            {name: '技术措施清单', value: getFee(source.fees, 'common.totalFee'), type: TYPE.NUM2},
+            {name: '其中暂估价', value: getFee(source.fees, 'estimate.totalFee'), type: TYPE.NUM2},
+        ];
+        element.call(this, '技术措施清单', attrs);
+    }
+    //技术措施分类
+    function jscsClass(source) {
+        let attrs = [
+            {name: '编号', value: source.code},
+            {name: '名称', value: source.name},
+            {name: '金额', value: getFee(source.fees, 'common.totalFee'), type: TYPE.NUM2},
+            {name: '其中暂估价', value: getFee(source.fees, 'estimate.totalFee'), type: TYPE.DECIMAL},
+        ];
+        element.call(this, '技术措施分类', attrs);
+    }
+    //其他项目清单定义
+    function otherBills() {
+        element.call(this, '其他项目清单', []);
+    }
+    //暂列金额定义
+    function provisional(source) {
+        let attrs = [
+            {name: '金额', value: getFee(source.fees, 'common.totalFee'), type: TYPE.NUM2}
+        ];
+        element.call(this, '暂列金额', attrs);
+    }
+    //暂列金额明细定义
+    function provisionalDetail(source) {
+        let attrs = [
+            {name: '编号', value: source.code, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE},
+            {name: '项目名称', value: source.name, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE},
+            {name: '计量单位', value: source.unit, maxLen: 20},
+            {name: '金额', value: getFee(source.fees, 'common.totalFee'), type: TYPE.NUM2},
+            {name: '备注', value: source.remark}
+        ];
+        element.call(this, '暂列金额明细', attrs);
+    }
+    //专业工程暂估价定义
+    function engineeringEstimate(source) {
+        let attrs = [
+            {name: '金额', value: getFee(source.fees, 'common.totalFee')}
+        ];
+        element.call(this, '专业工程暂估价', attrs);
+    }
+    //专业工程暂估明细定义
+    function engineeringEstimateDetail(source) {
+        let attrs = [
+            {name: '编号', value: source.code, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE},
+            {name: '工程名称', value: source.name, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE},
+            {name: '工程内容', value: 'todo', maxLen: 2000}, //todo
+            {name: '金额', value: getFee(source.fees, 'common.totalFee'), type: TYPE.NUM2},
+            {name: '备注', value: source.remark}
+        ];
+        element.call(this, '专业工程暂估明细', attrs);
+    }
+    //计日工定义
+    function dayWork(source) {
+        let attrs = [
+            {name: '金额', value: getFee(source.fees, 'common.totalFee')}
+        ];
+        element.call(this, '', attrs);
+    }
+    //人工定义
+    function labour() {
+        element.call(this, '人工', []);
+    }
+    //计日工项目定义
+    function dayWorkItem(source) {
+        let attrs = [
+            {name: '编号', value: source.code, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE},
+            {name: '名称', value: source.name, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE},
+            {name: '单位', value: source.unit, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE},
+            {name: '数量', value: source.quantity, type: TYPE.DECIMAL},
+            {name: '综合单价', value: source.quantity, type: TYPE.DECIMAL},
+            {name: '综合合价', value: source.quantity, type: TYPE.NUM2},
+            {name: '备注', value: source.remark}
+        ];
+        element.call(this, '计日工项目', attrs);
+    }
+    //材料定义
+    function material() {
+        element.call(this, '材料', []);
+    }
+    //施工机械定义
+    function machine() {
+        element.call(this, '施工机械', []);
+    }
+    //总承包服务费定义
+    function turnKeyContract(source) {
+        let attrs = [
+            {name: '金额', value: getFee(source.fees, 'common.totalFee'), type: TYPE.NUM2}
+        ];
+        element.call(this, '总承包服务费', attrs);
+    }
+    //总承包服务费分类定义
+    function turnKeyContractClass(source) {
+        let attrs = [
+            {name:'编号', value: source.code, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE},
+            {name:'名称', value: source.name, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE},
+            {name:'备注', value: source.remark}
+        ];
+        element.call(this, '总承包服务费分类', attrs);
+    }
+    //总承包服务费费用项定义
+    function turnKeyContractItem(source) {
+        let attrs = [
+            {name: '编号', value: source.code, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE},
+            {name: '工程名称', value: source.name, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE},
+            {name: '计算基础', value: 0, type: TYPE.DECIMAL},   //todo
+            {name: '服务内容', value: '', maxLen: 255}, //todo
+            {name: '费率', value: source.feeRate, type: TYPE.DECIMAL},
+            {name: '金额', value: getFee(source.fees, 'common.totalFee'), type: TYPE.NUM2},
+            {name: '备注', value: source.remark}
+        ];
+        element.call(this, '总承包服务费费用项', attrs);
+    }
+    //其他定义
+    function other(source) {
+        let attrs = [
+            {name: '金额', value: getFee(source.fees, 'common.totalFee'), type: TYPE.NUM2}
+        ];
+        element.call(this, '其他', attrs);
+    }
+    //其他列项定义
+    function otherItem(source) {
+        let attrs = [
+            {name: '序号', value: source.code, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE},
+            {name: '名称', value: source.name, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE},
+            {name: '计算基础', value: source.calcBase,  maxLen: 255},
+            {name: '费率', value: source.feeRate, type: TYPE.DECIMAL},
+            {name: '金额', value: getFee(source.fees, 'common.totalFee'), type: TYPE.NUM2},
+            {name: '不计入合价标志', value: source.isEstimate, type: TYPE.BOOL},
+            {name: '备注', value: source.remark, maxLen: 255}
+        ];
+        element.call(this, '其他列项', attrs);
+    }
+    //规费和税金清单定义
+    function chargeTaxBills() {
+        element.call(this, '规费和税金清单', []);
+    }
+    //费用项定义
+    function feeItem(source) {
+        let attrs = [
+            {name: '序号', value: source.code, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE},
+            {name: '行代号', value: source.rowCode, maxLen: 20},
+            {name: '名称', value: source.name, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE},
+            {name: '计算基础表达式', value: source.calcBase, maxLen: 255},
+            {name: '计算基础说明', value: source.calcBaseAnnotation, maxLen: 255},
+            {name: '费率', value: source.feeRate, type: TYPE.DECIMAL},
+            {name: '金额', value: getFee(source.fees, 'common.totalFee'), type: TYPE.NUM2},
+            {name: '费用类别', value: source.feeType, enumeration: [800, 900, 9001, 9002, 9003]},
+            {name: '备注', value: source.remark, maxLen: 255}
+        ]
+    }
+    //人材机汇总定义
+    function gljSummary() {
+        element.call(this, '人材机汇总', []);
+    }
+    //人材机定义
+    function glj(source) {
+        let attrs = [
+            {name: '代码', value: source.code, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE},
+            {name: '名称', value: source.name, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE},
+            {name: '规格', value: source.spec, maxLen: 255},
+            {name: '单位', value: source.unit, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE},
+            {name: '原始代码', value: source.code, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE},
+            {name: '费用类别', value: source.feeType, enumeration: [1, 2, 3, 4]},
+            {name: '配比类别', value: '', type: TYPE.INT},  //todo
+            {name: '主要材料类别', value: '', type: TYPE.INT},  //todo
+            {name: '主要材料单位系数', value: '', type: TYPE.DECIMAL},  //todo
+            {name: '材料耗用类型', value: '', type: TYPE.INT},  //todo
+            {name: '供货方式', value: '', type: TYPE.INT},  //todo
+            {name: '暂估材料标志', value: !!source.is_evaluate, type: TYPE.BOOL},
+            {name: '不计税设备标志', value: !!source.is_adjust_price, type: TYPE.BOOL},  //todo
+            {name: '单价不从明细汇总标志', value: !!source.excludeRatio, type: TYPE.BOOL},  //todo
+            {name: '定额价', value: source.basePrice, type: TYPE.DECIMAL},
+            {name: '定额价调整', value: '', type: TYPE.DECIMAL},   //todo
+            {name: '市场价', value: source.marketPrice, type: TYPE.DECIMAL},
+            {name: '数量', value: source.quantity, type: TYPE.DECIMAL},
+            {name: '产地', value: source.originPlace, maxLen: 255},
+            {name: '厂家', value: source.vender, maxLen: 255},
+            {name: '质量等级', value: source.qualityGrace, maxLen: 255},
+            {name: '品牌', value: source.brand, maxLen: 255},
+            {name: '备注', value: source.quantity, maxLen: 255},
+        ];
+        element.call(this, '人材机', attrs);
+    }
+    //人材机配比定义
+    function gljRatio(source) {
+        let attrs = [
+            {name: '明细材料代码', value: source.code, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE},
+            {name: '数量', value: source.quantity, type: TYPE.DECIMAL}
+        ];
+        element.call(this, '人材机配比', attrs);
+    }
+    return function (granularity) {
+        this.GRANULARITY = {
+            PROJECT: 1,         //导出建设项目
+            ENGINEERING: 2,     //导出单项工程
+            TENDER: 3           //导出单位工程
+        };
+        //默认导出建设项目
+        if (!granularity || ![1, 2, 3].includes(granularity)) {
+            granularity = this.GRANULARITY.PROJECT;
+        }
+        this.failList = failList;
+        this.granularity = granularity;
+        //目前的数据
+        let curData = null;
+        //唯一性约束
+        let contraints = {};
+
+        async function loadProject(tenderID) {
+            //拉取标段数据:建设项目、单项工程、单位工程数据
+            let projectData = await ajaxPost('/pm/api/getProjectByGranularity', {user_id: userID, tenderID: tenderID, granularity: granularity});
+            if (!projectData) {
+                throw '获取项目数据错误';
+            }
+            //标段
+            let project = curData = new Project({basicInformation: projectData.property.basicInformation, name: projectData.name});
+            //项目信息
+            let projectInfo = new ProjectInfo({basicInformation: projectData.property.basicInformation});
+            project.children.push(projectInfo);
+            //招标信息
+            let biddingInfo = new BiddingInfo({basicInformation: projectData.property.basicInformation, summaryInfo: projectData.summaryInfo[projectData.ID]});
+            projectInfo.children.push(biddingInfo);
+            //投标信息
+            let bidInfo = new BidInfo({basicInformation: projectData.property.basicInformation, summaryInfo: projectData.summaryInfo[projectData.ID]});
+            projectInfo.children.push(bidInfo);
+            //编制说明
+            let compilationIll = new CompilationIllustration({compilationIllustration: projectData.property.compilationIllustration});
+            project.children.push(compilationIll);
+            //系统信息
+            let generatedTime = moment(Date.now()).format('YYYY-MM-DDTHH:mm:ss'),
+                sysInfoSource = {softInfo: projectData.softInfo, generatedTime},
+                sysInfo = new SystemInfo(sysInfoSource);
+            project.children.push(sysInfo);
+            //费用构成
+            let feeForm = new FeeFrom(projectData.summaryInfo[projectData.ID]);
+            project.children.push(feeForm);
+        }
+        /*
+        * 加载数据
+        * */
+        this.loadData = async function(tenderID) {
+            await loadProject(tenderID);
+            return curData;
+        };
+        /*
+        * 转换数据,将数据转换成可被导出成xml的结构
+        * {element: '标段', attrs: [{name: '属性1', value: 't'}], children: [...]} to
+        * {'标段': {...}, '_属性1': t}
+        * */
+
+        /*
+        * 导出数据
+        * */
+        this.toXml = function () {
+
+        }
+    }
+})();

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

@@ -2355,7 +2355,13 @@ $('#compilationIllustration').keyup(function () {
         alert('编制说明字符数不能超过255个。');
     };
 });
-$('#property_ok').click(function () {
+$('#property_ok').click(async function () {
+    //test-----
+    /*let xmlObj = new XMLStandard();
+    let testData = await xmlObj.loadData(projectObj.project.ID());
+    console.log(testData);
+    console.log(xmlObj);*/
+    //test-----
     let project = projectObj.project,
         projectID = project.ID(),
 

web/dest/css/login-bgp.jpg → web/dest/css/login-bg.jpg