zhongzewei 6 anni fa
parent
commit
9b4dca2d0a

+ 2 - 2
modules/pm/facade/pm_facade.js

@@ -1478,10 +1478,10 @@ async function setupStdData(tenderData) {
         if (stdGLJ) {
             pGLJ.glj_id = stdGLJ.ID;
             if (pGLJ.type !== stdGLJ.gljType) { //更新组成物connect_key
-                let keyStr = [pGLJ.code, pGLJ.name, pGLJ.specs, pGLJ.unit, pGLJ.type].join('|-|');
+                let keyStr = [pGLJ.code || 'null', pGLJ.name || 'null', pGLJ.specs || 'null', pGLJ.unit || 'null', pGLJ.type].join('|-|');
                 let ratios = tenderData.mixRatio.filter(ratio =>
                     ratio.connect_key === keyStr);
-                let newKeyStr = [pGLJ.code, pGLJ.name, pGLJ.specs, pGLJ.unit, stdGLJ.gljType].join('|-|');
+                let newKeyStr = [pGLJ.code || 'null', pGLJ.name || 'null', pGLJ.specs || 'null', pGLJ.unit || 'null', stdGLJ.gljType || 'null'].join('|-|');
                 ratios.forEach(ratio => ratio.connect_key = newKeyStr);
             }
             pGLJ.type = stdGLJ.gljType;  //更新类型,标准的数据类型更准确,导入的类型数据有细分识别不了

+ 2 - 1
public/web/PerfectLoad.js

@@ -91,7 +91,8 @@ const SCComponent = (() => {
     * 假滚动条,0 - 80% 快, 80% - 95%很慢,95%开始停住,直到调用end方法
     * */
     const InitProgressBar = (() => {
-        function ProgressBar($modal, $title, $content, $bar) {
+        function ProgressBar($modal = $('#progress'), $title = $('#progress-title'),
+                             $content = $('#progress-content'), $bar = $('#progressBar')) {
             this.$modal = $modal;
             this.$title = $title;
             this.$content = $content;

+ 4 - 0
web/building_saas/css/custom.css

@@ -324,4 +324,8 @@ input.text-right{
 }
 .border_bottom{
     border-bottom:  1px solid #ccc
+}
+.export-check{
+    overflow: auto;
+    height: 400px;
 }

+ 3 - 3
web/building_saas/main/html/main.html

@@ -2024,9 +2024,9 @@
                 <!--检测提醒-->
                 <div class="card">
                     <div class="card-body">
-                        <h5 class="card-title">Card title</h5>
-                        <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
-                        <a id="exportCheck" href="javascript:void(0);" class="btn btn-primary">自检</a>
+                        <h5 class="card-title">导出重庆市电子招投标数据接口文件</h5>
+                        <p class="card-text">导出之前,建议您执行项目自检功能,避免出现错误。</p>
+                        <a id="export-check" href="javascript:void(0);" class="btn btn-primary">自检</a>
                     </div>
                 </div>
                 <!--招标-->

+ 176 - 70
web/building_saas/main/js/models/exportStandardInterface.js

@@ -181,15 +181,17 @@ const XMLStandard = (function () {
             exportKind = ExportKind.Tender;
         }
         this.exportKind = exportKind;
+        this.fileDatas = [];
         /*
          * 检查
          * 创建节点时检查节点的数据
          * 1.长度限制minLen,maxLen
          * 2.值的限制,固定范围:enumeration
+         * @param {String}eleName(节点名称)
          * @param {Array}datas(需要检查的属性数据)
          * @return {Object} failHints没通过的属性提示 filterAttrs过滤后的属性数据(失败提示在属性是必须的时候才提示,如果该属性失败了,但是是非必要属性,那么该属性不显示)
          * */
-        function check(datas) {
+        function check(eleName, datas) {
             let rst = {failHints: [], filterAttrs: []};
             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) {
@@ -207,34 +209,52 @@ const XMLStandard = (function () {
                     tempFail = '';
                 if (data.minLen && data.value.length < data.minLen){
                     isFail = true;
-                    tempFail = `“${data.name}”字符数不可小于${data.minLen}个`;
+                    tempFail = data.failHint
+                        ? `${data.failHint}字符数不可小于${data.minLen}个。`
+                        :`${eleName}-“${data.name}”字符数不可小于${data.minLen}个。`;
                 } else if (data.maxLen && data.value.length > data.maxLen) {
                     isFail = true;
-                    tempFail = `“${data.name}”字符数不可大于${data.maxLen}个`;
+                    tempFail = data.failHint
+                        ? `${data.failHint}字符数不可大于${data.maxLen}个。`
+                        : `${eleName}-“${data.name}”字符数不可大于${data.maxLen}个。`;
                 } else if (data.enumeration && !data.enumeration.includes(data.value)) {
                     isFail = true;
-                    tempFail = `“${data.name}”只能从“${data.enumeration.join(';')}”中选择`;
+                    let enumerationHint = data.enumerationHint
+                        ? data.enumerationHint.join(';')
+                        : data.enumeration.join(';');
+                    tempFail = data.failHint
+                        ? `${data.failHint}只能从“${enumerationHint}”中选择。`
+                        : `${eleName}-“${data.name}”只能从“${enumerationHint}”中选择。`;
                 } else if (data.type && data.type === TYPE.DATE && !dateReg.test(data.value)) {
                     isFail = true;
-                    tempFail = `“${data.name}”日期格式必须是YYYY-MM-DD`;
+                    tempFail = data.failHint
+                        ? `${data.failHint}日期格式必须是YYYY-MM-DD。`
+                        : `${eleName}-“${data.name}”日期格式必须是YYYY-MM-DD。`;
                 } else if (data.type && data.type === TYPE.INT && !Number.isInteger(parseFloat(data.value))) {
                     isFail = true;
-                    tempFail = `“${data.name}”必须为整数`;
+                    tempFail = data.failHint
+                        ? `${data.failHint}必须为整数。`
+                        : `${eleName}-“${data.name}”必须为整数。`;
                 } else if (data.type && data.type === TYPE.DECIMAL && isNaN(parseFloat(data.value))) {
                     isFail = true;
-                    tempFail = `“${data.name}”必须为数值`;
+                    tempFail = data.failHint
+                        ? `${data.failHint}必须为数值。`
+                        : `${eleName}-“${data.name}”必须为数值。`;
                 } else if (data.type && data.type === TYPE.NUM2) {
                     let v = parseFloat(data.value);
                     if (isNaN(v)) {
                         isFail = true;
-                        tempFail = `“${data.name}”必须为数值`;
-                        rst.failHints.push(`“${data.name}”必须为数值`);
+                        tempFail = data.failHint
+                            ? `${data.failHint}必须为数值。`
+                            : `${eleName}-“${data.name}”必须为数值。`;
                     } else if (!data.value.length || (data.value.split('.').length > 1 && data.value.split('.')[1].length > 2)){
                         isFail = true;
                     }
                 } else if (data.type && data.type === TYPE.BOOL && !['true', 'false'].includes(data.value.toString())) {
                     isFail = true;
-                    tempFail = `“${data.name}”必须为true或false`;
+                    tempFail = data.failHint
+                        ? `${data.failHint}必须为true或false。`
+                        : `${eleName}-“${data.name}”必须为true或false。`;
                 }
                 if (!isFail || data.required) {
                     rst.filterAttrs.push(data);
@@ -283,13 +303,11 @@ const XMLStandard = (function () {
          * */
         function element(name, attrs) {
             this.name = name;
-            let checkData = check(attrs);
+            let checkData = check(name, attrs);
             this.fail = checkData.failHints;
             this.attrs = checkData.filterAttrs;
             this.children = [];
-            for (let fail of this.fail) {
-                failList.push(`${name}-${fail}`);
-            }
+            failList.push(...this.fail);
         }
         //建设项目定义
         //source:来源数据
@@ -487,7 +505,9 @@ const XMLStandard = (function () {
                 {name: '金额', value: exportKind === ExportKind.Tender ? getFee(source.fees, 'common.totalFee') : '0', type: TYPE.NUM2},
                 {name: '其中暂估价', value: exportKind === ExportKind.Tender ? getFee(source.fees, 'estimate.totalFee') : '0', type: TYPE.NUM2},
                 {name: '费用类别', value: source.feeType, type: TYPE.INT, required: true,
-                    enumeration: ['1100', '1200', '1204', '1300', '800', '900', '1800', '1']},
+                    enumeration: ['1100', '1200', '1204', '1300', '800', '900', '1800', '1'],
+                    failHint: `第${source.row}行清单-“费用类别”`
+                },
                 {name: '备注', value: source.remark},
             ];
             element.call(this, '计价程序费用行', attrs);
@@ -499,8 +519,10 @@ const XMLStandard = (function () {
         //清单分部定义
         function FBBills(source) {
             let attrs = [
-                {name: '编号', value: source.code, required: true, maxLen: 20},
-                {name: '名称', value: source.name, required: true, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE},
+                {name: '编号', value: source.code, required: true, maxLen: 20,
+                    failHint: `第${source.row}行清单分部-“编码”`},
+                {name: '名称', value: source.name, required: true, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE,
+                    failHint: `第${source.row}行清单分部-“名称”`},
                 {name: '金额', value: exportKind === ExportKind.Tender ? getFee(source.fees, 'common.totalFee') : '0', required: true, type: TYPE.NUM2},
                 {name: '其中暂估价', value: exportKind === ExportKind.Tender ? getFee(source.fees, 'estimate.totalFee') : '0', required: true},
                 {name: '备注', value: source.remark}
@@ -510,16 +532,23 @@ const XMLStandard = (function () {
         //清单项目定义
         function FXbills(source) {
             let attrs = [
-                {name: '项目编码', value: source.code, required: true, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE},
-                {name: '项目名称', value: source.name, required: true, minLen: 1, maxLen: 500, whiteSpace: WHITE_SPACE.COLLAPSE},
-                {name: '单位', value: source.unit, required: true, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE},
-                {name: '工程量', value: source.quantity, required: true, type: TYPE.DECIMAL},
+                {name: '项目编码', value: source.code, required: true, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE,
+                    failHint: `第${source.row}行清单分项-“编码”`},
+                {name: '项目名称', value: source.name, required: true, minLen: 1, maxLen: 500, whiteSpace: WHITE_SPACE.COLLAPSE,
+                    failHint: `第${source.row}行清单分项-“名称”`},
+                {name: '单位', value: source.unit, required: true, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE,
+                    failHint: `第${source.row}行清单分项-“单位”`},
+                {name: '工程量', value: source.quantity, required: true, type: TYPE.DECIMAL,
+                    failHint: `第${source.row}行清单分项-“工程量”`},
                 {name: '综合单价', value: exportKind === ExportKind.Tender ? getFee(source.fees, 'common.unitFee') : '0', required: true, type: TYPE.DECIMAL},
                 {name: '综合合价', value: exportKind === ExportKind.Tender ? getFee(source.fees, 'common.totalFee') : '0', required: true, type: TYPE.NUM2},
                 {name: '其中暂估价', value: exportKind === ExportKind.Tender ? getFee(source.fees, 'estimate.totalFee') : '0', required: true, type: TYPE.NUM2},
-                {name: '主要清单标志', value: !!source.mainBills, type: TYPE.BOOL},
-                {name: '暂估清单标志', value: !!source.isEstimate, type: TYPE.BOOL},
-                {name: '最高限价', value: exportKind === ExportKind.Control ? source.maxPrice : '0', type: TYPE.NUM2},
+                {name: '主要清单标志', value: !!source.mainBills, type: TYPE.BOOL,
+                    failHint: `第${source.row}行清单分项-“主要清单标志”`},
+                {name: '暂估清单标志', value: !!source.isEstimate, type: TYPE.BOOL,
+                    failHint: `第${source.row}行清单分项-“暂估清单标志”`},
+                {name: '最高限价', value: exportKind === ExportKind.Control ? source.maxPrice : '0', type: TYPE.NUM2,
+                    failHint: `第${source.row}行清单分项-“最高限价”`},
                 {name: '备注', value: source.remark},
             ];
             element.call(this, '清单项目', attrs);
@@ -554,20 +583,25 @@ const XMLStandard = (function () {
         //定额子目定义
         function Ration(source) {
             let attrs = [
-                {name: '定额编号', value: source.viewCode, required: true, minLen: 1, maxLen: 80, whiteSpace: WHITE_SPACE.COLLAPSE},
-                {name: '项目名称', value: source.name, required: true, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE},
-                {name: '单位', value: source.unit, required: true, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE},
+                {name: '定额编号', value: source.viewCode, required: true, minLen: 1, maxLen: 80, whiteSpace: WHITE_SPACE.COLLAPSE,
+                    failHint: `第${source.row}行定额-“编码”`},
+                {name: '项目名称', value: source.name, required: true, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE,
+                    failHint: `第${source.row}行定额-“名称”`},
+                {name: '单位', value: source.unit, required: true, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE,
+                    failHint: `第${source.row}行定额-“单位”`},
                 {name: '定额库编码', value: source.libCode, required: true},
                 {name: '原始定额编号', value: source.code, minLen: 1, maxLen: 80, whiteSpace: WHITE_SPACE.COLLAPSE},
                 {name: '子目类型', value: source.subType, required: true, type: TYPE.INT, enumeration: ['0', '1', '2', '3', '4', '5', '6']},
-                {name: '工程量', value: source.quantity, required: true, type: TYPE.DECIMAL},
+                {name: '工程量', value: source.quantity, required: true, type: TYPE.DECIMAL,
+                    failHint: `第${source.row}行定额-“工程量”`},
                 {name: '工程量计算式', value: source.quantityEXP},
                 {name: '定额单价', value: getFee(source.fees, 'rationUnitPrice.unitFee'), required: true, type: TYPE.DECIMAL},
                 {name: '定额合价', value: getFee(source.fees, 'rationUnitPrice.totalFee'), required: true, type: TYPE.NUM2},
                 {name: '综合单价', value: getFee(source.fees, 'common.unitFee'), required: true, type: TYPE.DECIMAL},
                 {name: '综合合价', value: getFee(source.fees, 'common.totalFee'), required: true, type: TYPE.NUM2},
                 {name: '单价构成文件ID', value: source.programID, required: true, type: TYPE.INT},
-                {name: '分包标志', value: !!source.isSubcontract, type: TYPE.BOOL},
+                {name: '分包标志', value: !!source.isSubcontract, type: TYPE.BOOL,
+                    failHint: `第${source.row}行定额-“分包标志”`},
                 {name: '备注', value: source.remark}
             ];
             element.call(this, '定额子目', attrs);
@@ -642,8 +676,10 @@ const XMLStandard = (function () {
         //组织措施分类定义
         function ZZCSClass(source) {
             let attrs = [
-                {name: '编码', value: source.code, maxLen: 20, required: true},
-                {name: '名称', value: source.name, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE, required: true},
+                {name: '编码', value: source.code, maxLen: 20, required: true,
+                    failHint: `第${source.row}行组织措施清单-“编码”`},
+                {name: '名称', value: source.name, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE, required: true,
+                    failHint: `第${source.row}行组织措施清单-“名称”`},
                 {name: '金额', value: exportKind === ExportKind.Tender ? getFee(source.fees, 'common.totalFee') : '0', type: TYPE.NUM2, required: true},
                 {name: '备注', value: source.remark}
             ];
@@ -652,15 +688,19 @@ const XMLStandard = (function () {
         //公式计算措施项
         function FormulaCalcMeasure(source) {
             let attrs = [
-                {name: '序号', value: source.code, minLen: 1, maxLen:20, whiteSpace: WHITE_SPACE.COLLAPSE, required: true},
-                {name: '名称', value: source.name, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE, required: true},
+                {name: '序号', value: source.code, minLen: 1, maxLen:20, whiteSpace: WHITE_SPACE.COLLAPSE, required: true,
+                    failHint: `第${source.row}行清单-“编码”`},
+                {name: '名称', value: source.name, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE, required: true,
+                    failHint: `第${source.row}行清单-“名称”`},
                 {name: '计算基础表达式', value: source.calcBase, required: true},
                 {name: '计算基础说明', value: source.calcBaseState},
                 {name: '费率', value: exportKind === ExportKind.Tender ? source.feeRate : '100', required: true},
                 {name: '金额', value: exportKind === ExportKind.Tender ? getFee(source.fees, 'common.totalFee') : '0', required: true},
                 {name: '暂估价标志', value: !!source.isEstimate, type: TYPE.BOOL},
                 {name: '备注', value: source.remark},
-                {name: '费用类别', value: source.feeType, enumeration: ['120201', '1204', '10041', '1206'], required: true},
+                {name: '费用类别', value: source.feeType, enumeration: ['120201', '1204', '10041', '1206'], required: true,
+                    enumerationHint: ['组织措施费', '安全文明施工专项费', '建设工程竣工档案编制费', '住宅工程质量分户验收费'],
+                    failHint: `第${source.row}行清单-“固定费用类别”`},
             ];
             element.call(this, '公式计算措施项', attrs);
         }
@@ -696,9 +736,12 @@ const XMLStandard = (function () {
         //暂列金额明细定义
         function ProvisionalDetail(source) {
             let attrs = [
-                {name: '编号', value: source.code, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE, required: true},
-                {name: '项目名称', value: source.name, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE, required: true},
-                {name: '计量单位', value: source.unit, maxLen: 20, required: true},
+                {name: '编号', value: source.code, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE, required: true,
+                    failHint: `第${source.row}行暂列金额清单-“编码”`},
+                {name: '项目名称', value: source.name, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE, required: true,
+                    failHint: `第${source.row}行暂列金额清单-“名称”`},
+                {name: '计量单位', value: source.unit, maxLen: 20, required: true,
+                    failHint: `第${source.row}行暂列金额清单-“单位”`},
                 {name: '金额', value: exportKind === ExportKind.Tender ? getFee(source.fees, 'common.totalFee') : '0', type: TYPE.NUM2, required: true},
                 {name: '备注', value: source.remark, required: true}
             ];
@@ -714,9 +757,12 @@ const XMLStandard = (function () {
         //专业工程暂估明细定义
         function EngEstimateDetail(source) {
             let attrs = [
-                {name: '编号', value: source.code, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE, required: true},
-                {name: '工程名称', value: source.name, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE, required: true},
-                {name: '工程内容', value: source.engineeringContent, maxLen: 2000, required: true},
+                {name: '编号', value: source.code, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE, required: true,
+                    failHint: `第${source.row}行专业工程暂估清单-“编码”`},
+                {name: '工程名称', value: source.name, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE, required: true,
+                    failHint: `第${source.row}行专业工程暂估清单-“名称”`},
+                {name: '工程内容', value: source.engineeringContent, maxLen: 2000, required: true,
+                    failHint: `第${source.row}行专业工程暂估清单-“工程内容”`},
                 {name: '金额', value: exportKind === ExportKind.Tender ? getFee(source.fees, 'common.totalFee') : '0', type: TYPE.NUM2, required: true},
                 {name: '备注', value: source.remark, required: true}
             ];
@@ -744,9 +790,12 @@ const XMLStandard = (function () {
         //计日工项目定义
         function DayWorkItem(source) {
             let attrs = [
-                {name: '编号', value: source.code, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE, required: true},
-                {name: '名称', value: source.name, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE, required: true},
-                {name: '单位', value: source.unit, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE, required: true},
+                {name: '编号', value: source.code, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE, required: true,
+                    failHint: `第${source.row}行计日工清单-“编码”`},
+                {name: '名称', value: source.name, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE, required: true,
+                    failHint: `第${source.row}行计日工清单-“名称”`},
+                {name: '单位', value: source.unit, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE, required: true,
+                    failHint: `第${source.row}行计日工清单-“单位”`},
                 {name: '数量', value: source.quantity, type: TYPE.DECIMAL, required: true},
                 {name: '综合单价', value: exportKind === ExportKind.Tender ? getFee(source.fees, 'common.unitFee') : '0', type: TYPE.DECIMAL, required: true},
                 {name: '综合合价', value: exportKind === ExportKind.Tender ? getFee(source.fees, 'common.totalFee') : '0', type: TYPE.NUM2, required: true},
@@ -764,8 +813,10 @@ const XMLStandard = (function () {
         //总承包服务费分类定义
         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, required: true},
+                {name:'编号', value: source.code, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE,
+                    failHint: `第${source.row}行承包服务费清单-“编码”`},
+                {name:'名称', value: source.name, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE, required: true,
+                    failHint: `第${source.row}行承包服务费清单-“名称”`},
                 {name:'备注', value: source.remark}
             ];
             element.call(this, '总承包服务费分类', attrs);
@@ -773,10 +824,13 @@ const XMLStandard = (function () {
         //总承包服务费费用项定义
         function TurnKeyContractItem(source) {
             let attrs = [
-                {name: '编号', value: source.code, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE, required: true},
-                {name: '工程名称', value: source.name, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE, required: true},
+                {name: '编号', value: source.code, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE, required: true,
+                    failHint: `第${source.row}行承包服务费清单-“编码”`},
+                {name: '工程名称', value: source.name, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE, required: true,
+                    failHint: `第${source.row}行承包服务费清单-“名称”`},
                 {name: '计算基础', value: exportKind === ExportKind.Tender ? source.calcBaseValue : '', type: TYPE.DECIMAL, required: true},
-                {name: '服务内容', value: source.serviceContent, maxLen: 255, required: true},
+                {name: '服务内容', value: source.serviceContent, maxLen: 255, required: true,
+                    failHint: `第${source.row}行承包服务费清单-“服务内容”`},
                 {name: '费率', value: exportKind === ExportKind.Tender ? source.feeRate : '100', type: TYPE.DECIMAL, required: true},
                 {name: '金额', value: exportKind === ExportKind.Tender ? getFee(source.fees, 'common.totalFee') : '0', type: TYPE.NUM2, required: true},
                 {name: '备注', value: source.remark}
@@ -806,9 +860,12 @@ const XMLStandard = (function () {
         //其他列项定义
         function OtherItem(source) {
             let attrs = [
-                {name: '序号', value: source.code, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE, required: true},
-                {name: '名称', value: source.name, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE, required: true},
-                {name: '计算基础', value: exportKind === ExportKind.Tender ? source.calcBase : '',  maxLen: 255},
+                {name: '序号', value: source.code, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE, required: true,
+                    failHint: `第${source.row}行清单-“编码”`},
+                {name: '名称', value: source.name, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE, required: true,
+                    failHint: `第${source.row}行清单-“名称”`},
+                {name: '计算基础', value: exportKind === ExportKind.Tender ? source.calcBase : '',  maxLen: 255,
+                    failHint: `第${source.row}行清单-“计算基础”`},
                 {name: '费率', value: exportKind === ExportKind.Tender ? source.feeRate : '100', type: TYPE.DECIMAL},
                 {name: '金额', value: exportKind === ExportKind.Tender ? source.commonTotalFee : '0', type: TYPE.NUM2, required: true},
                 {name: '不计入合价标志', value: source.notSummray, type: TYPE.BOOL},
@@ -824,14 +881,19 @@ const XMLStandard = (function () {
         //费用项定义
         function FeeItem(source) {
             let attrs = [
-                {name: '序号', value: source.code, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE, required: true},
+                {name: '序号', value: source.code, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE, required: true,
+                    failHint: `第${source.row}行清单-“编号”`},
                 {name: '行代号', value: source.rowCode, maxLen: 20, required: true},
-                {name: '名称', value: source.name, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE, required: true},
-                {name: '计算基础表达式', value: exportKind === ExportKind.Tender ? source.calcBase : '', maxLen: 255, required: true},
+                {name: '名称', value: source.name, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE, required: true,
+                    failHint: `第${source.row}行清单-“名称”`},
+                {name: '计算基础表达式', value: exportKind === ExportKind.Tender ? source.calcBase : '', maxLen: 255, required: true,
+                    failHint: `第${source.row}行清单-“计算基础表达式”`},
                 {name: '计算基础说明', value: exportKind === ExportKind.Tender ? source.calcBaseState : '', maxLen: 255},
                 {name: '费率', value: exportKind === ExportKind.Tender ? source.feeRate : '100', type: TYPE.DECIMAL, required: true},
                 {name: '金额', value: exportKind === ExportKind.Tender ? getFee(source.fees, 'common.totalFee') : '0', type: TYPE.NUM2, required: true},
-                {name: '费用类别', value: source.feeType, enumeration: ['800', '900', '9001', '9002', '9003'], required: true},
+                {name: '费用类别', value: source.feeType, enumeration: ['800', '900', '9001', '9002', '9003'], required: true,
+                    enumerationHint: ['规费', '税金', '增值税', '附加税', '环境保护税'],
+                    failHint: `第${source.row}行清单-“固定费用类别”`},
                 {name: '备注', value: source.remark, maxLen: 255}
             ];
             element.call(this, '费用项', attrs);
@@ -843,8 +905,8 @@ const XMLStandard = (function () {
         //承包人材料差额法明细
         function DifferentiaGljDetail(source) {
             let attrs = [
-                {name: '关联材料号', value: source.code, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE, required: true},
-                {name: '名称', value: source.code, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE, required: true},
+                {name: '关联材料号', value: getGljCode(source.id), minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE, required: true},
+                {name: '名称', value: source.name, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE, required: true},
                 {name: '规格', value: source.specs, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE},
                 {name: '单位', value: source.unit, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE, required: true},
                 {name: '数量', value: source.quantity, type: TYPE.DECIMAL, required: true},
@@ -852,7 +914,8 @@ const XMLStandard = (function () {
                 {name: '基准单价', value: source.standardPrice, type: TYPE.DECIMAL, require: true},
                 {name: '投标单价', value: source.marketPrice, type: TYPE.DECIMAL},
                 {name: '确认单价', value: '0', type: TYPE.DECIMAL},
-                {name: '备注', value: source.remark, maxLen: 255},
+                {name: '备注', value: source.remark, maxLen: 255,
+                    failHint: `承包人材料${source.code}-“备注”`},
             ];
             element.call(this, '承包人材料差额法明细', attrs);
         }
@@ -863,13 +926,14 @@ const XMLStandard = (function () {
         //承包人材料指数法明细
         function ExponentialGljDetail(source) {
             let attrs = [
-                {name: '关联材料号', value: source.code, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE, required: true},
-                {name: '名称', value: source.code, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE, required: true},
+                {name: '关联材料号', value: getGljCode(source.id), minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE, required: true},
+                {name: '名称', value: source.name, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE, required: true},
                 {name: '规格', value: source.specs, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE},
                 {name: '变值权重B', value: source.varWeight, type: TYPE.DECIMAL, required: true},
                 {name: '基本价格指数', value: source.FO, type: TYPE.DECIMAL, require: true},
                 {name: '现行价格指数', value: source.FI, type: TYPE.DECIMAL, require: true},
-                {name: '备注', value: source.remark, maxLen: 255},
+                {name: '备注', value: source.remark, maxLen: 255,
+                    failHint: `承包人材料${source.code}-“备注”`},
             ];
             element.call(this, '承包人材料指数法明细', attrs);
         }
@@ -880,10 +944,14 @@ const XMLStandard = (function () {
         //人材机定义
         function Glj(source) {
             let attrs = [
-                {name: '代码', value: source.code, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE, required: true},
-                {name: '名称', value: source.name, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE, required: true},
-                {name: '规格', value: source.specs, maxLen: 255},
-                {name: '单位', value: source.unit, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE, required: true},
+                {name: '代码', value: source.code, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE, required: true,
+                    failHint: `人材机${source.orgCode}-“编码”`},
+                {name: '名称', value: source.name, minLen: 1, maxLen: 255, whiteSpace: WHITE_SPACE.COLLAPSE, required: true,
+                    failHint: `人材机${source.orgCode}-“名称”`},
+                {name: '规格', value: source.specs, maxLen: 255,
+                    failHint: `人材机${source.orgCode}-“规格”`},
+                {name: '单位', value: source.unit, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE, required: true,
+                    failHint: `人材机${source.orgCode}-“单位”`},
                 {name: '原始代码', value: source.orgCode, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE},
                 {name: '费用类别', value: source.feeType, enumeration: ['1', '2', '3', '4'], required: true},
                 {name: '配比类别', value: source.ratioType, type: TYPE.INT},
@@ -898,11 +966,16 @@ const XMLStandard = (function () {
                 {name: '定额价调整', value: source.adjPrice, type: TYPE.DECIMAL, required: true},
                 {name: '市场价', value: source.marketPrice, type: TYPE.DECIMAL, required: true},
                 {name: '数量', value: source.quantity, type: TYPE.DECIMAL, required: true},
-                {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.remark, maxLen: 255},
+                {name: '产地', value: source.originPlace, maxLen: 255,
+                    failHint: `人材机${source.orgCode}-“产地”`},
+                {name: '厂家', value: source.vender, maxLen: 255,
+                    failHint: `人材机${source.orgCode}-“厂家”`},
+                {name: '质量等级', value: source.qualityGrace, maxLen: 255,
+                    failHint: `人材机${source.orgCode}-“质量等级”`},
+                {name: '品牌', value: source.brand, maxLen: 255,
+                    failHint: `人材机${source.orgCode}-“品牌”`},
+                {name: '备注', value: source.remark, maxLen: 255,
+                    failHint: `人材机${source.orgCode}-“备注”`},
             ];
             element.call(this, '人材机', attrs);
         }
@@ -1329,7 +1402,13 @@ const XMLStandard = (function () {
                 if (!tenderDetailMap[tenderData.ID]) {
                     await setTimeoutSync(() => {},TIMEOUT_TIME);
                 }
+                //方便用户看错误来自哪个单位工程
+                failList.push(`<span style="font-weight: bold">单位工程“${tenderData.name}”下:</span>`);
+                let orgLen = failList.length;
                 let tender = await loadTender(summaryInfo, tenderData);
+                if (failList.length === orgLen) {    //只有上方的提示,说明该单位工程没有报错
+                    failList.pop();
+                }
                 tenderGljs = [];    //清空单位工程内所有的人材机(ID)
                 engineering.children.push(tender);
             }
@@ -1471,6 +1550,7 @@ const XMLStandard = (function () {
                     serialNo = mainTreeNode ? mainTreeNode.serialNo() + 1 : 1;
                 let flag = getNodeFlag(node) || 0;
                 let source = {
+                    row: serialNo,
                     code: node.data.code,
                     rowCode: `F${serialNo}`,
                     name: node.data.name,
@@ -1495,6 +1575,7 @@ const XMLStandard = (function () {
                 allRationGlj = detail.ration_glj.datas,
                 decimal = detail.projectInfo.property.decimal;
             let source = {
+                row: detail.mainTree.nodes[detail.mainTree.prefix + node.data.ID].serialNo() + 1,
                 code: node.data.code,
                 name: node.data.name,
                 unit: node.data.unit,
@@ -1619,7 +1700,9 @@ const XMLStandard = (function () {
                 } else if (rationData.type === rationType.volumePrice) {
                     subType = '6';
                 }
+                let rNode = detail.mainTree.nodes[detail.mainTree.prefix + rationData.ID];
                 let rationSource = {
+                    row: rNode ? rNode.serialNo() + 1 : -1,
                     viewCode: viewCode,
                     name: rationData.name,
                     unit: rationData.unit,
@@ -1695,6 +1778,7 @@ const XMLStandard = (function () {
                     }
                     //创建清单分部节点
                     let fbSource = {
+                        row: detail.mainTree.nodes[detail.mainTree.prefix + node.data.ID].serialNo() + 1,
                         code: node.data.code,
                         name: node.data.name,
                         fees: node.data.fees,
@@ -1751,6 +1835,7 @@ const XMLStandard = (function () {
                 for (let node of nodes) {
                     if (node.children.length > 0) {    //组织措施分类
                         let classSource = {
+                            row: detail.mainTree.nodes[detail.mainTree.prefix + node.data.ID].serialNo() + 1,
                             code: node.data.code,
                             name: node.data.name,
                             fees: node.data.fees,
@@ -1761,6 +1846,7 @@ const XMLStandard = (function () {
                         loadZZCS(zzcsClass, node.children);
                     } else {    //公式计算措施项
                         let source = {
+                            row: detail.mainTree.nodes[detail.mainTree.prefix + node.data.ID].serialNo() + 1,
                             code: node.data.code,
                             name: node.data.name,
                             calcBase: transformCalcBase(detail, node),
@@ -1952,6 +2038,7 @@ const XMLStandard = (function () {
             //加载计日工项目
             function loadDayWorkItem(node, constraints, hint) {
                 let source = {
+                    row: detail.mainTree.nodes[detail.mainTree.prefix + node.data.ID].serialNo() + 1,
                     code: node.data.code,
                     name: node.data.name,
                     unit: node.data.unit,
@@ -1967,6 +2054,7 @@ const XMLStandard = (function () {
                 for (let node of nodes) {
                     if (node.children.length > 0) {    //总承包服务费分类
                         let classSource = {
+                            row: detail.mainTree.nodes[detail.mainTree.prefix + node.data.ID].serialNo() + 1,
                             code: node.data.code,
                             name: node.data.name,
                             remark: node.data.remark
@@ -1976,6 +2064,7 @@ const XMLStandard = (function () {
                         loadService(tkcClass, node.children);
                     } else {    //总承包服务费费用项
                         let source = {
+                            row: detail.mainTree.nodes[detail.mainTree.prefix + node.data.ID].serialNo() + 1,
                             code: node.data.code,
                             name: node.data.name,
                             serviceContent: node.data.serviceContent,
@@ -2013,6 +2102,7 @@ const XMLStandard = (function () {
                     let totalFee = getFee(node.data.fees, 'common.totalFee');
                     summaryFee = scMathUtil.roundForObj(summaryFee + totalFee, curPMData.tender.property.decimal.bills.totalPrice);
                     let otherItemEle = new OtherItem({
+                        row: detail.mainTree.nodes[detail.mainTree.prefix + node.data.ID].serialNo() + 1,
                         code: node.data.code,
                         name: node.data.name,
                         calcBase: transformCalcBase(detail, node),
@@ -2051,6 +2141,7 @@ const XMLStandard = (function () {
                 let mainTreeNode = detail.mainTree.getNodeByID(node.data.ID),
                     serialNo = mainTreeNode ? mainTreeNode.serialNo() + 1 : 1;
                 let source = {
+                    row: detail.mainTree.nodes[detail.mainTree.prefix + node.data.ID].serialNo() + 1,
                     code: node.data.code,
                     rowCode: `F${serialNo}`,
                     name: node.data.name,
@@ -2330,8 +2421,23 @@ const XMLStandard = (function () {
             //格式化
             xmlStr = formatXml(xmlStr);
             let blob = new Blob([xmlStr], {type: 'text/plain;charset=utf-8'});
+            failList = [];
+            this.fileDatas.push({blob: blob, fileName: `重庆标准交换数据(${FILE_KIND[exportKind]}).QTF`});
             return blob;
             saveAs(blob, '重庆标准交换数据.QTF');
         }
+        //导出文件
+        this.exportFile = async function () {
+            if (this.fileDatas.length === 1) {  //导出文件
+                saveAs(this.fileDatas[0].blob, this.fileDatas[0].fileName);
+            } else if (this.fileDatas.length > 1) { //导出压缩包
+                let zip = new JSZip();
+                for (let file of this.fileDatas) {
+                    zip.file(file.fileName, file.blob, {binary: true});
+                }
+                let zipFile = await zip.generateAsync({type: 'blob'});
+                saveAs(zipFile, '重庆标准交换数据.zip');
+            }
+        }
     }
 })();

+ 1 - 1
web/building_saas/main/js/models/importStandardInterface.js

@@ -1336,7 +1336,7 @@ const ImportXML = (() => {
                         ratio.name = matchData ? matchData.name : '';
                         ratio.specs = matchData ? matchData.specs : '';
                         ratio.type = matchData ? matchData.type : 1;
-                        ratio.connect_key = [pGLJ.original_code, pGLJ.name, pGLJ.specs, pGLJ.unit, pGLJ.type].join('|-|');
+                        ratio.connect_key = [pGLJ.original_code || 'null', pGLJ.name || 'null', pGLJ.specs || 'null', pGLJ.unit || 'null', pGLJ.type].join('|-|');
                         rst.mixRatio.push(ratio);
                     });
                     delete pGLJ.ratios;

+ 65 - 28
web/building_saas/main/js/views/project_view.js

@@ -3318,45 +3318,82 @@ $('#menu_calc_program_manage').click(function () {
 });
 $('#menu_index_info').click(function () {
     $('#tab_index').click();
-});//导出接口,如果选中多个文件,导出压缩包
-$('#export-confirm').click(async function () {
+});
+
+let xmlObj = null;
+//导出接口-项目自检
+$('#export-check').click(async function () {
     let checkedDatas = $('#export input[type="checkbox"]:checked');
     if (!checkedDatas.length) {
         return;
     }
-    $('#export').modal('hide');
-    let pr = new SCComponent.InitProgressBar($('#progress'), $('#progress-title'), $('#progress-content'), $('#progressBar'));
-    pr.start('导出数据接口', '正在导出文件,请稍候……');
-    let xmlObj = new XMLStandard(userID, 1),
-        exportData = [],
-        fileKindMap = {
-            1: '投标',
-            2: '招标',
-            3: '控制价'
-        };
+    let pr = new SCComponent.InitProgressBar();
+    pr.start('导出数据接口', '正在自检,请稍候……')
     try {
-        for (let checkedData of checkedDatas) {
-            let fileKind = $(checkedData).val();
-            exportData.push({
-                blob: await xmlObj.toXml(projectObj.project.ID(), fileKind),
-                fileName: `重庆标准交换数据(${fileKindMap[fileKind]}).QTF`
-            });
+        if (!xmlObj || !xmlObj.fileDatas.length) {
+            xmlObj = new XMLStandard(userID, 1);
+            for (let checkedData of checkedDatas) {
+                let fileKind = $(checkedData).val();
+                await xmlObj.toXml(projectObj.project.ID(), fileKind);
+            }
+        }
+        //设置提示弹窗
+        if (xmlObj.failList.length * 16 > 400) {
+            $('#hintBox_caption').addClass('export-check');
+        }
+        if (xmlObj.failList.length) {
+            throw xmlObj.failList.join('<br/>');
         }
-        if (exportData.length === 1) {  //导出文件
-            saveAs(exportData[0].blob, exportData[0].fileName);
-        } else if (exportData.length > 1) { //导出压缩包
-            let zip = new JSZip();
-            for (let expr of exportData) {
-                zip.file(expr.fileName, expr.blob, {binary: true});
+    } catch (err) {
+        alert(err);
+    }
+    pr.end();
+});
+
+//导出接口,如果选中多个文件,导出压缩包
+$('#export-confirm').click(async function () {
+    let checkedDatas = $('#export input[type="checkbox"]:checked');
+    if (!checkedDatas.length) {
+        return;
+    }
+    let pr = new SCComponent.InitProgressBar();
+    pr.start('导出数据接口', '正在导出文件,请稍候……')
+    try {
+        if (!xmlObj || !xmlObj.fileDatas.length) {
+            xmlObj = new XMLStandard(userID, 1);
+            for (let checkedData of checkedDatas) {
+                let fileKind = $(checkedData).val();
+                await xmlObj.toXml(projectObj.project.ID(), fileKind);
             }
-            let zipFile = await zip.generateAsync({type: 'blob'});
-            saveAs(zipFile, '重庆标准交换数据.zip');
         }
+        //设置提示弹窗
+        if (xmlObj.failList.length * 16 > 400) {
+            $('#hintBox_caption').addClass('export-check');
+        }
+        if (xmlObj.failList.length) {
+            throw xmlObj.failList.join('<br/>');
+        }
+        //可能先执行过自检了,已经有组装好的数据了,可以直接导出
+        pr.end();
+        await xmlObj.exportFile();
+        console.log(xmlObj);
+        $('#export').modal('hide');
     } catch (err) {
         console.log(err);
+        pr.end();
         alert(err);
     }
-    console.log(xmlObj);
+});
+
+$('#export').on('show.bs.modal', function () {
+    xmlObj = null;
+});
+$('#export').on('hide.bs.modal', function() {
+    xmlObj = null;
+    //恢复设置提示弹窗 因为是共用的alert
+    $('#hintBox_caption').removeClass('export-check');
+    $('#export input[type="checkbox"]').prop('checked', false);
+});
+$('#export input[type="checkbox"]').click(function () {
     xmlObj = null;
-    pr.end();
 });