Browse Source

导入相关

zhongzewei 6 years ago
parent
commit
4450d51be2

+ 5 - 111
modules/main/controllers/bills_controller.js

@@ -231,24 +231,11 @@ module.exports = {
                     throw 'excel没有对应数据'
                 }
                 let importData = JSON.parse(LZString.decompressFromUTF16(compressData));
-                //匹配的清单库
-                const billsLibId = fields.billsLibId !== undefined && fields.billsLibId.length > 0 && fields.billsLibId[0]? parseInt(fields.billsLibId[0]) : null;
-                let stdBills = [], stdJobs = [], stdCharacters = [];
-                if(billsLibId){
-                    stdBills = await stdBillsModel.find({billsLibId: billsLibId, deleted: false}, '-_id code jobs items engineering billsLibId ruleText');
-                    stdJobs = await stdBillJobsModel.find({billsLibId: billsLibId, deleted: false});
-                    stdCharacters = await stdBillCharacterModel.find({billsLibId: billsLibId, deleted: false});
-                }
-                let stdData = {stdBills: stdBills, stdJobs: stdJobs, stdCharacters: stdCharacters};
                 //导入表
                 let importDateA = +new Date();
-                for(let position in importData){
-                    if(importData[position].length > 0){
-                        let updateFrontData = await importSheet(position, importData[position], req.session.sessionUser.id, projectID, stdData);
-                        if(updateFrontData){
-                            responseData.data.push(updateFrontData);
-                        }
-                    }
+                let updateFrontData = await importSheet(importData, req.session.sessionUser.id, projectID);
+                if(updateFrontData){
+                    responseData.data.push(updateFrontData);
                 }
                 let importDateB = +new Date();
                 console.log(`导入时间: ${importDateB - importDateA}=========================================================================`);
@@ -274,49 +261,15 @@ module.exports = {
     }
 };
 
-async function importSheet(position, excelBills, userID, projectID, stdData){
+async function importSheet(excelBills, userID, projectID,){
     //导入位置的有固定行
-    let flag = getImportFlag(position);
-    if(!flag){
-        throw 'excel数据错误';
-    }
+    let flag = fixedFlag.ONE_SEVEN_BILLS;   //第100章至700章清单
     let fixedBill = await billsData.model.findOne({projectID: projectID, 'flags.flag': flag, deleteInfo: null});
-    let insertFixedBill = null;
-    //导入xx措施项目,若不存在此固定清单,则先插入相关固定清单
-    if(!fixedBill){
-        //分部分项工程(不可删除)应存在
-        if(flag === fixedFlag.SUB_ENGINERRING){
-            throw '项目不存在分部分项工程'
-        }
-        //措施项目是否存在
-        let csxm = await billsData.model.findOne({projectID: projectID, 'flags.flag': fixedFlag.MEASURE, deleteInfo: null});
-        if(!csxm){
-            throw '项目不存在措施项目'
-        }
-        //插入清单固定行(施工技术措施项目、施工组织措施项目可删除)
-        insertFixedBill = {projectID: projectID, name: flag === fixedFlag.CONSTRUCTION_TECH ? '施工技术措施项目' : '施工组织措施项目', code: '1',
-            ID: uuidV1(), NextSiblingID: -1, ParentID: csxm.ID, flags: [{fieldName: 'fixed', flag: flag}], type: billType.BILL};
-        //更新前节点
-        let preDatas = await billsData.model.find({projectID: projectID, ParentID: csxm.ID, deleteInfo: null});
-        for(let preData of preDatas){
-            if(preData.NextSiblingID == -1){
-                await billsData.model.update({ID: preData.ID}, {$set: {NextSiblingID: insertFixedBill.ID}});
-                break;
-            }
-        }
-        await billsData.model.create(insertFixedBill);
-        fixedBill = insertFixedBill;
-    }
-    //将excel清单数据转换成完整清单数据(设置ParentID、匹配标准清单库)
-    parseToCompleteBills(excelBills, fixedBill, stdData);
     //删除相关数据
     let deleteDatas = await billsData.deepDeleteBill([fixedBill], userID);
     //新增清单数据
     await billsData.importBills(excelBills);
     //返回数据以更新前端
-    if(insertFixedBill){
-        excelBills.push(insertFixedBill);
-    }
     return {fixedBill: fixedBill, insert: {bill: excelBills, ration: []}, remove: {bill: deleteDatas.bill, ration: deleteDatas.ration}};
 }
 
@@ -328,65 +281,6 @@ function getImportFlag(position){
 function isDef(data){
     return typeof data !== 'undefined' && data !== null && data !== '';
 }
-//将前端解析生成的清单节点数据完善(ParentID、匹配标准清单)
-function parseToCompleteBills(excelBills, fixedBills, stdData){
-    //设置清单ParentID
-    let rootID = fixedBills ? fixedBills.ID: -1;
-    for(let bills of excelBills){
-        if(bills.nodeType === 'root'){
-            rootID = bills.ID;
-            bills.ParentID = fixedBills.ID;
-        }
-        else {
-            bills.ParentID = rootID;
-        }
-        delete bills.nodeType;
-        matchStdBill(bills, stdData);
-    }
-
-    //excel数据与标准库数据匹配,根据清单前九位编码匹配,匹配成功则获取标准清单对应的工程专业、特征及内容
-    function matchStdBill(excelBill, stdData){
-        let isMatch = false;
-        let regExp = /^\d{12}$/g;
-        if(excelBill.code.length >8){
-            let nineCode = excelBill.code.substr(0, 9);
-            for(let stdBill of stdData.stdBills){
-                //set programID
-                if(nineCode == stdBill.code){
-                    isMatch = true;
-                    excelBill.programID = stdBill.engineering ? stdBill.engineering : null;
-                    excelBill.billsLibId = stdBill.billsLibId ? stdBill.billsLibId : null;
-                    excelBill.ruleText = stdBill.ruleText ? stdBill.ruleText : '';
-                    //set jobContent and itemCharacter
-                    let tempJob = [], tempCharacter = [];
-                    for(let billJob of stdBill.jobs){
-                        for(let stdJob of stdData.stdJobs) {
-                            if (billJob.id == stdJob.id) {
-                                tempJob.push({isChecked: false, serialNo: billJob.serialNo, content: stdJob.content});
-                            }
-                        }
-                    }
-                    for(let billCharacter of stdBill.items){
-                        for(let stdCharacter of stdData.stdCharacters){
-                            if(billCharacter.id == stdCharacter.id){
-                                let eigenvalue = [];
-                                for(let eValue of stdCharacter.itemValue){
-                                    eigenvalue.push({isSelected: false, value: eValue.value});
-                                }
-                                tempCharacter.push({isChecked: false, serialNo: billCharacter.serialNo, character: stdCharacter.content, eigenvalue: eigenvalue});
-                            }
-                        }
-                    }
-                    excelBill.jobContent = tempJob;
-                    excelBill.itemCharacter = tempCharacter;
-                }
-            }
-        }
-        if(!isMatch && excelBill.type === billType.FX){//分项不为空,同时在标准清单中不匹配,则识别为补项
-            excelBill.type = billType.BX;
-        }
-    }
-}
 
 async function doBillsOrRationsDelete(data) {
     let billTask = [];

+ 0 - 2
modules/main/models/bills.js

@@ -194,8 +194,6 @@ class billsModel extends baseModel {
             await rationGljModel.deleteMany({rationID: {$in: ration_ids}});
             //删除ration-coe
             await rationCoeModel.deleteMany({rationID: {$in: ration_ids}});
-            //删除ration-installation
-            await rationInstModel.deleteMany({rationID: {$in: ration_ids}});
             //删除ration-quantity_detail
             await quantityDelModel.deleteMany({rationID: {$in: ration_ids}});
         }

BIN
public/static/uploadExample.xlsx


+ 0 - 2
public/web/slideResize.js

@@ -38,8 +38,6 @@ const SlideResize = (function() {
             otherPercentWidth = otherDecimalWidth * 100 + '%';
         resize.css('width', resizePercentWidth);
         other.css('width', otherPercentWidth);
-        console.log(other)
-        console.log(otherPercentWidth)
     }
 
     let mouseMoveCount = 0;

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

@@ -87,13 +87,13 @@
                       <span id="openProjSet" class="btn btn-light btn-sm" data-toggle="tooltip" data-original-title="项目属性" data-placement="bottom">
                         <a href="javascript:void(0);"><i class="fa fa-cog"></i></a>
                     </span>
-                    <!--<span class="btn btn-light btn-sm" id="importSpan" data-toggle="tooltip" data-original-title="导入" data-placement="bottom">
-                        <a id="importDropDown" class="dropdown-toggle" href="#"><i class="fa fa-cloud-upload"></i></a>
-                        <div class="dropdown-menu">
-                            <a id="uploadLj" class="dropdown-item" href="#import" data-toggle="modal" data-target="#import">导入报表Excel清单</a>
+                    <span class="btn btn-light btn-sm" id="importSpan" data-toggle="tooltip" data-original-title="导入Excel清单" data-placement="bottom" style="display: none;">
+                        <a id="importDropDown" href="javascript:void(0);"><i class="fa fa-cloud-upload"></i></a>
+                        <!--<div class="dropdown-menu">
+                            <a id="uploadLj" class="dropdown-item" href="#import" data-toggle="modal" data-target="#import">导入工程量清单</a>
                             <a id="uploadGld" class="dropdown-item" href="#import" data-toggle="modal" data-target="#import">导入广联达算量Excel清单</a>
-                        </div>
-                    </span>-->
+                        </div>-->
+                    </span>
                     <a href="javascript:void(0)" class="btn btn-light btn-sm" id="insertRation" data-toggle="tooltip" data-placement="bottom" data-original-title="插入定额"><i class="fa fa-sign-in" aria-hidden="true"></i></a>
                     <!--2018-11-15 隐藏删除按钮   <a href="javascript:void(0)" class="btn btn-light btn-sm" id="delete" data-toggle="tooltip" data-placement="bottom" data-original-title="删除"><i class="fa fa-remove" aria-hidden="true"></i></a>-->
                     <a href="javascript:void(0)" class="btn btn-light btn-sm" id="upLevel" data-toggle="tooltip" data-placement="bottom" data-original-title="升级"><i class="fa fa-arrow-left" aria-hidden="true"></i></a>

+ 176 - 391
web/building_saas/main/js/views/importBills.js

@@ -26,430 +26,215 @@ const importBills = (function(){
     function _deNR(data) {
         return _isDef(data) ? data.toString().replace(/\r\r/g, '\r') : data;
     }
-
-    //列名对应中文字符
-    const colText = {
-        serialNo: ['序号'],
-        code: ['编码', '项目编码'],
-        name: ['名称', '项目名称'],
-        itemCharacterText: ['特征', '项目特征', '项目特征描述'],
-        unit: ['单位', '计量单位'],
-        quantity: ['工程量', '项目工程量'],
-        money: ['金额'],
-        quantityDetail: ['工程量明细'],
-        feeDetail: ['费用明细'],
-        summation: ['合计', '本页小计'],
-    };
-
-    //导入位置对应清单固定标记
-    const positionFlag = {
-        fbfx: fixedFlag.SUB_ENGINERRING,
-        jscsxm: fixedFlag.CONSTRUCTION_TECH,
-        zzcsxm: fixedFlag.CONSTRUCTION_ORGANIZATION,
-    };
-
-    //上传类型
-    const uploadType = {
-        lj: 'lj',
-        gld: 'gld',
-    };
-
-    //设置导入表内容(选择导入位置)
-    //@param {Object}workBook
-    function setImportSheetsInfo(sheets){
-        let sheetNames = [];
-        let indexMapping = {};
-        for(let sheetName in sheets){
-            indexMapping[sheets[sheetName]['index']] = sheetName;
-        }
-        let sheetsCount = Object.keys(sheets).length;
-        for(let i = 0; i < sheetsCount; i++){
-            sheetNames.push(indexMapping[i]);
-        }
-        let sheetArea = $('#uploadSheets'),
-            sheetHeader = $('#uploadSheetsHead');
-        $('#uploadSheets').height('');
-        sheetArea.empty();
-        for(let sheetName of sheetNames){
-            let sheetDiv = $(`<div style="margin-left: 5px;margin-top: 5px;" title="${sheetName}" class="input-group form-check"><label class="form-check-label" style="width:270px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis">
-                           <input class="form-check-input" type="checkbox">${sheetName}</label></div>`);
-            sheetDiv.find('input[type="checkbox"]').click(function () {
-                if($('#uploadAlert').is(':visible')){
-                    $('#uploadAlert').hide();
-                }
-            });
-            let sel = $(`<select style="margin-left: 5px; border-radius: .20rem;"><option value="fbfx">分部分项工程</option><option value="zzcsxm">施工组织措施项目</option><option value="jscsxm">施工技术措施项目</option></select>`);
-            if(sheetName.includes('分部分项工程项目清单计价表')){
-                sheetDiv.find('input[type="checkbox"]').prop('checked', true);
-                sel.find('option:eq(0)').prop('selected', true);
-            }
-            else if(sheetName.includes('施工组织措施项目清单计价表')){
-                sheetDiv.find('input[type="checkbox"]').prop('checked', true);
-                sel.find('option:eq(1)').prop('selected', true);
-            }
-            else if(sheetName.includes('施工技术措施项目清单计价表')){
-                sheetDiv.find('input[type="checkbox"]').prop('checked', true);
-                sel.find('option:eq(2)').prop('selected', true);
-            }
-            sheetDiv.append(sel);
-            sheetArea.append(sheetDiv);
-
-        }
-        if(sheetNames.length > 0){
-            sheetArea.show();
-            sheetHeader.show();
-        }
-        if($('#uploadSheets').height() > 250){
-            sheetArea.css('overflow', 'auto');
-            sheetArea.height(250);
-        }
-        else {
-            sheetArea.css('overflow', 'hidden');
+    //find 返回最后匹配
+    function findLast(datas, func) {
+        let filter = datas.filter(func);
+        if (filter.length > 0) {
+            return filter[filter.length - 1];
         }
+        return null;
     }
-
-    //获得选择导入的表信息(表索引及导入位置)
-    //@return {Object}
-    function getImportSheetsInfo(){
-        let rst = [];
-        let sheetArea = $('#uploadSheets');
-        let checkedInputs = sheetArea.find('input:checked');
-        for(let checked of checkedInputs){
-            rst.push({index: $(checked).parent().parent().index(), position: $(checked).parent().next().select().val()})
+    const fileType = {
+        gcl: 0, //工程量清单
+        qdsl: 1 //清单示例
+    };
+    //获取列字段对应
+    function getColMapping(type){
+        if (type === 0) {   //工程量清单
+            return {code: 0, name: 1, unit: 2, quantity: 4};
+        } else {    //清单示例表
+            return {code: 0, name: 1, unit: 2, quantity: 3};
         }
-        return rst;
     }
-
-    function getSheetByIndex(sheets, index){
-        for(let sheetName in sheets){
-            let sheet = sheets[sheetName];
-            if(sheet.index === index){
-                return sheet;
+    function isGCLHead(dataRow) {
+        let cell = dataRow[0];
+        return cell.value === '工程量清单';
+    }
+    //分析文件,1、工程量清单 2、清单示例表
+    function getFileType(sheetData) {
+        let dataTable = sheetData.data.dataTable,
+            rowCount = sheetData.rowCount;
+        for (let row = 0; row < rowCount; row++) {
+            if (isGCLHead(dataTable[row])) {
+                return fileType.gcl;
             }
         }
-        return null;
+        return fileType.qdsl;
     }
-
-    //提取excel表头列名与列下标映射
-    //@
-    function getColMapping(dataTable){
-        //获取表头
-        function getHeadRow(dataTable){
-            for(let rowIdx in dataTable ){
-                for(let colIdx in dataTable[rowIdx]){
-                    let cellData = dataTable[rowIdx][colIdx]['value'];
-                    if(cellData && _deESC(cellData) === colText.serialNo[0]){
-                        return dataTable[rowIdx];
+    //提取工程量清单数据
+    //层级由depth确定,表格里最顶层depth为0(表头里一清单),表格内容里数据的depth为空格数+1
+    function extractGCLDatas(sheetData, colMapping) {
+        //let colMapping = {code: 0, name: 1, unit: 2, quantity: 4};
+        let dataTable = sheetData.data.dataTable,
+            rowCount = sheetData.rowCount;
+        let rst = [];
+        for (let row = 0; row < rowCount; row++) {
+            //表格中顶层节点
+            if (isGCLHead(dataTable[row])) {
+                let rootRow = dataTable[row + 2];
+                let name = rootRow[0].value;
+                let existsRoot = findLast(rst, x => x.name === name && x.depth === 0);
+                if (!existsRoot) {
+                    let root = {ID: uuid.v1(), NextSiblingID: -1, ParentID: -1, name: name, depth: 0, parent: null};
+                    let preData = findLast(rst, x => x.depth === root.depth);
+                    if (preData) {
+                        preData.NextSiblingID = root.ID;
                     }
+                    rst.push(root);
                 }
-            }
-            return {};
-        }
-        //获取需要的表头列与列号对应关系
-        let colMapping = {};
-        let headRow = getHeadRow(dataTable);
-        for(let colIdx in headRow){
-            let cellData = headRow[colIdx]['value'];
-            if(!_isDef(cellData)){
+                row += 3;
                 continue;
             }
-            //序号
-            if(colMapping.serialNo === undefined && _deESC(cellData) === colText.serialNo[0]){
-                colMapping.serialNo = colIdx;
-            }
-            //编码
-            else if(colMapping.code === undefined && (_deESC(cellData) === colText.code[0] || _deESC(cellData) === colText.code[1])){
-                colMapping.code = colIdx;
-            }
-            //名称
-            else if(colMapping.name === undefined && (_deESC(cellData) === colText.name[0] || _deESC(cellData) === colText.name[1])){
-                colMapping.name = colIdx;
-            }
-            //项目特征
-            else if(colMapping.itemCharacterText === undefined && (_deESC(cellData) === colText.itemCharacterText[0] || _deESC(cellData) === colText.itemCharacterText[1]
-                ||  _deESC(cellData) === colText.itemCharacterText[2])){
-                colMapping.itemCharacterText = colIdx;
-            }
-            //单位
-            else if(colMapping.unit === undefined && (_deESC(cellData) === colText.unit[0] || _deESC(cellData) === colText.unit[1])){
-                colMapping.unit = colIdx;
-            }
-            //工程量
-            else if(colMapping.quantity === undefined && (_deESC(cellData) === colText.quantity[0] || _deESC(cellData) === colText.quantity[1])){
-                colMapping.quantity = colIdx;
-            }
-            //金额
-            else if(colMapping.money === undefined && _deESC(cellData).includes(colText.money[0])){
-                colMapping.money = colIdx;
-            }
-            //工程量明细
-            else if(colMapping.quantityDetail === undefined && _deESC(cellData) === colText.quantityDetail[0]){
-                colMapping.quantityDetail = colIdx;
-            }
-            //费用明细
-            else if(colMapping.feeDetail === undefined && _deESC(cellData) === colText.feeDetail[0]){
-                colMapping.feeDetail = colIdx;
-            }
-        }
-        return colMapping;
-    }
-
-    //是否是有效的表头列格式,只要含有各表需要的列就行,不严格控制多少列
-    function isValidSheet(colMapping, fileType){
-        function hasField(field, all){
-            for(let i of all){
-                if(field === i){
-                    return true;
-                }
-            }
-            return false;
-        }
-        let needFields;
-        if(fileType === uploadType.lj){
-            //09表:序号、项目编码、项目名称、项目特征、计量单位、工程量、金额
-            needFields = ['serialNo', 'code', 'name', 'money'];
-        }
-        else {
-            //广联达表:序号、项目编码、项目名称、项目特征、计量单位、工程量、工程量明细、费用明细
-            needFields = ['serialNo', 'code', 'name', 'itemCharacterText', 'unit', 'quantity', 'quantityDetail', 'feeDetail'];
-        }
-        let hasFieldCount = 0;
-        for(let attr in colMapping){
-            if(hasField(attr, needFields)){
-                hasFieldCount++;
-            }
-        }
-        return hasFieldCount === needFields.length;
-    }
-
-    //获取要无效和有效导入表
-    //@param {Array}importSheetInfo 勾选要导入的表
-    function getImportSheets(sheets, sheetsInfo, fileType){
-        let rst = {invalidSheets: [], validSheets: {fbfx: [], jscsxm: [], zzcsxm: []}};
-
-        for(let sheetInfo of sheetsInfo){
-            let sheet = getSheetByIndex(sheets, sheetInfo.index);
-            if(!sheet){
-                continue;
-            }
-            //没有数据
-            if(!sheet.data.dataTable){
-                rst.invalidSheets.push(sheet.name);
+            let code = dataTable[row][colMapping.code] ? dataTable[row][colMapping.code].value : null,
+                name = dataTable[row][colMapping.name] ? dataTable[row][colMapping.name].value : null,
+                unit = dataTable[row][colMapping.unit] ? dataTable[row][colMapping.unit].value : null,
+                quantity = dataTable[row][colMapping.quantity] ? dataTable[row][colMapping.quantity].value : null;
+            if (!code && !name || /合计/.test(code)) {   //过滤掉同时没有编号和名称的、过滤合计行
                 continue;
             }
-            //获取表的列设置确定导入的格式是否合法(09、广联达)
-            let colMapping = getColMapping(sheet.data.dataTable);
-            if(!isValidSheet(colMapping, fileType)){
-                rst.invalidSheets.push(sheet.name);
-                continue;
-            }
-            //合法的表
-            sheet.colMapping = colMapping;
-            //将合法的表按导入位置分类当做一个表来处理
-            if(rst.validSheets[sheetInfo.position] !== undefined){
-                rst.validSheets[sheetInfo.position].push(sheet)
+            //表格内的数据
+            let depth = getDepth(code);
+            let data = {ID: uuid.v1(), NextSiblingID: -1, ParentID: -1, code: code, name: name, unit: unit, quantity: quantity, depth: depth};
+            let lastData = rst[rst.length - 1];
+            //获取data的父节点链,成为兄弟节点,只能在父链里找前兄弟(不能跨父链)
+            let parents = getParents(lastData);
+            let preData = findLast(parents, x => x.depth === depth);
+            if (preData) {
+                preData.NextSiblingID = data.ID;
+                data.ParentID = preData.ParentID;
+                data.parent = preData.parent;
+            } else {
+                data.ParentID = lastData.ID;
+                data.parent = lastData;
+            }
+            rst.push(data);
+
+        }
+        console.log(rst);
+        return rst;
+        function getDepth(code) {
+            if (!code) {
+                return 1;
             }
+            let match = code.match(/\s/g);
+            return match ? match.length + 1 : 1;
         }
-        return rst;
     }
 
-    //行存在数据
-    function rowExistData(rowData){
-        for(let colIdx in rowData){
-            let colData = rowData[colIdx]['value'];
-            if(_isDef(colData)){
-                return true;
-            }
+    function getParents(data) {
+        let rst = [];
+        let parent = data.parent;
+        while (parent) {
+            rst.push(parent);
+            parent = parent.parent;
         }
-        return false;
+        rst.push(data);
+        return rst;
     }
 
-    //提取excel表数据中的有效数据(去表头表尾,提取其中的excel数据)(根据fixedBill获取栏头占行数)
-    function getValidImportData(colMapping, sheetData){
-        let withingD = false;
-        let validData = [];
-        function isHead(rData){
-            return rData[colMapping.serialNo] && _deESC(rData[colMapping.serialNo]['value']) === colText.serialNo[0];
-        }
-        function isTail(rowData){
-            for(let colIdx in rowData){
-                let colData = rowData[colIdx]['value'];
-                if(colData){
-                    let trimColData= _deESC(colData);
-                    if(trimColData === colText.summation[0] || trimColData === colText.summation[1]){
-                        return true;
-                    }
-                }
-            }
-            return false;
-        }
-        for(let rowIdx in sheetData){
-            let rowData = sheetData[rowIdx];
-            if(isHead(rowData)){
-                withingD = true;
-                continue;
-            }
-            else if(isTail(rowData)){
-                withingD = false;
-            }
-            if(withingD && rowExistData(rowData)){
-                validData.push(rowData);
-            }
+    //获取编号前缀: 101-1 => 101   101-1-1 => 101-1
+    function getPrefix(v) {
+        if (!v) {
+            return null;
         }
-        return validData;
+        let reg = /(.*)-/;
+        let match = reg.exec(v);
+        return match ? match[1] : null;
     }
 
-    //excel数据转换成清单数据
-    function parseToBillData(validData, colMapping, flag, projectID){
+    //提取清单示例数据
+    function extractSLDatas(sheetData) {
+        let colMapping = {code: 0, name: 1, unit: 2, quantity: 3};
+        let dataTable = sheetData.data.dataTable,
+            rowCount = sheetData.rowCount;
         let rst = [];
-        let billIdx = {};
-        let preRootID = -1,
-            preLeafID = -1,
-            preID = -1;
-        //父节点:1.无序号 2有编码
-        function isRoot(rData){
-            //序号和编码去除转义字符(有的表格单元格看起来是没数据,实际含有\r,\n等数据)
-            let serialNo = rData[colMapping.serialNo] ? _deESC(rData[colMapping.serialNo]['value']) : '';
-            let code = rData[colMapping.code] ? _deESC(rData[colMapping.code]['value']) : '';
-            return !_isDef(serialNo) && _isDef(code);
-        }
-        //子节点:有序号
-        function isLeaf(rData){
-            let serialNo = rData[colMapping.serialNo] ? _deESC(rData[colMapping.serialNo]['value']) : '';
-            return _isDef(serialNo);
-        }
-        //续数据:1. 前数据有效 2.无序号 3.无编码 4.有名称或特征
-        function isExtend(preData, rData){
-            let serialNo = rData[colMapping.serialNo] ? _deESC(rData[colMapping.serialNo]['value']) : '';
-            let code = rData[colMapping.code] ? _deESC(rData[colMapping.code]['value']) : '';
-            let name = rData[colMapping.name] ? _deESC(rData[colMapping.name]['value']) : '';
-            let itemCharacterText = rData[colMapping.itemCharacterText] ? _deESC(rData[colMapping.itemCharacterText]['value']) : '';
-            return _isDef(preData) && (isRoot(preData) || isLeaf(preData)) && !_isDef(serialNo) && !_isDef(code) && (_isDef(name) || _isDef(itemCharacterText));
-        }
-        function getBillType(rData, flag){
-            if(flag === fixedFlag.CONSTRUCTION_TECH || flag === fixedFlag.CONSTRUCTION_ORGANIZATION){
-                return billType.BILL;
-            }
-            else if(flag === fixedFlag.SUB_ENGINERRING){
-                return isLeaf(rData) ? billType.FX : billType.FB;
-            }
-            return null;
-        }
-        let preData = null;
-        for(let r = 0; r < validData.length; r++){
-            let rData = validData[r];
-            if(flag == fixedFlag.CONSTRUCTION_TECH && rData[colMapping.name] && rData[colMapping.name]['value'] === '施工技术措施项目'
-                || flag == fixedFlag.CONSTRUCTION_ORGANIZATION && rData[colMapping.name] && rData[colMapping.name]['value'] === '施工组织措施项目'){
-                continue;
-            }
-            //过滤无效数据
-            if(!isRoot(rData) && !isLeaf(rData) && !isExtend(preData, rData)){
-                continue;
-            }
-            if(isExtend(preData, rData)){
-                let preBill = billIdx[preID];
-                if(preBill){
-                    //合并续数据
-                    preBill.code += rData[colMapping.code] && rData[colMapping.code]['value'] && _isDef(_deESC(rData[colMapping.code]['value'])) ? rData[colMapping.code]['value'] : '';
-                    preBill.name += rData[colMapping.name] && rData[colMapping.name]['value'] && _isDef(_deESC(rData[colMapping.name]['value'])) ? rData[colMapping.name]['value'] : '';
-                    preBill.itemCharacterText += rData[colMapping.itemCharacterText] && rData[colMapping.itemCharacterText]['value'] && _isDef(_deESC(rData[colMapping.itemCharacterText]['value']))
-                        ? '\n' + _deNR(rData[colMapping.itemCharacterText]['value']) : '';
-                    preBill.unit += rData[colMapping.unit] && rData[colMapping.unit]['value'] && _isDef(_deESC(rData[colMapping.unit]['value'])) ? rData[colMapping.unit]['value'] : '';
-                    preBill.quantity += rData[colMapping.quantity] && rData[colMapping.quantity]['value'] && _isDef(_deESC(rData[colMapping.quantity]['value'])) ? rData[colMapping.quantity]['value'] : '';
+        let curRoot = null;
+        for (let row = 0; row < rowCount; row++) {
+            let code = dataTable[row][colMapping.code] ? dataTable[row][colMapping.code].value : null,
+                name = dataTable[row][colMapping.name] ? dataTable[row][colMapping.name].value : null,
+                unit = dataTable[row][colMapping.unit] ? dataTable[row][colMapping.unit].value : null,
+                quantity = dataTable[row][colMapping.quantity] ? dataTable[row][colMapping.quantity].value : null;
+            if (!code) {    //没有编号的数据,名称必须为:清单 第xx章,认为新的表根节点
+                if (name && /清单 第\d+章/.test(name)) {
+                    curRoot = {code: null, name: name, ID: uuid.v1(), ParentID: -1, NextSiblingID: -1, parent: null};
+                    rst.push(curRoot);
+                } else {
+                    curRoot = null;
                 }
-            }
-            else {
-                let newID = uuid.v1();
-                let pID = -1;
-                let preBill = null;
-                let preRoot = null,
-                    preLeaf = null;
-                let nodeType = 'root';//后端以此标记来设置ParentID
-                let preSerialBill = billIdx[preID];
-                if(isRoot(rData)){
-                    //pID = 'fixedBillID';
-                    preBill = billIdx[preRootID];
-                    preRoot = billIdx[preRootID];
-                }
-                else if(isLeaf(rData)){
-                    nodeType = 'leaf';
-                    //pID = preRootID !== -1 ? preRootID : fixedBill.ID;
-                    preBill = billIdx[preLeafID];
-                    preLeaf = billIdx[preLeafID];
-                }
-                //set bill data
-                billIdx[newID] = {
-                    nodeType: nodeType,
-                    ID: newID, ParentID: pID, NextSiblingID: -1,
-                    code: rData[colMapping.code] && rData[colMapping.code]['value'] ? _deESC(rData[colMapping.code]['value']) : '',
-                    name: rData[colMapping.name] && rData[colMapping.name]['value'] ? _deESC(rData[colMapping.name]['value']) : '',
-                    itemCharacterText: rData[colMapping.itemCharacterText] && rData[colMapping.itemCharacterText]['value'] ? _deNR(rData[colMapping.itemCharacterText]['value']) : '',
-                    itemCharacter: [],
-                    jobContentText: '',
-                    jobContent: [],
-                    programID: null,
-                    unit: rData[colMapping.unit] && rData[colMapping.unit]['value'] ? _deESC(rData[colMapping.unit]['value']) : '',
-                    quantity: rData[colMapping.quantity] && rData[colMapping.quantity]['value'] ? _deESC(rData[colMapping.quantity]['value']) : '',
-                    quantityEXP: rData[colMapping.quantity] && rData[colMapping.quantity]['value'] ? _deESC(rData[colMapping.quantity]['value']) : '',
-                    //安全文明
-                    flags: flag === fixedFlag.CONSTRUCTION_ORGANIZATION && (rData[colMapping.name] && (rData[colMapping.name]['value'] === '安全文明施工专项费用' || rData[colMapping.name]['value'] === '安全文明施工费')) ?
-                        [{fieldName: 'fixed', flag: fixedFlag.SAFETY_CONSTRUCTION}] : [],
-                    fees: [],
-                    projectID: projectID,
-                    type: getBillType(rData, flag)};
-                //update preBill NextSibling
-                if(nodeType === 'root' && preRoot){
-                    preRoot.NextSiblingID = newID;
+            } else if (!curRoot) {  //根节点为无效根节点,其下子数据全部过滤掉
+                continue;
+            } else {
+                //有code且有有效表根节点
+                let prefix = getPrefix(code);
+                let data = {
+                    code: code,
+                    name: name,
+                    unit: unit,
+                    quantity: quantity,
+                    ID: uuid.v1(),
+                    NextSiblingID: -1,
+                };
+                let lastData = rst[rst.length - 1];
+                let parents = getParents(lastData);
+                //某数据编号为此数据的前缀,则某数据为此数据的父节点
+                let parentData = findLast(parents, x => prefix === x.code);
+                if (!parentData && prefix === '') { // -x的数据,在父链上找不到编号与prefix相同的数据时,父链上-x的数据,则这两数据为兄弟节点,没有则上一行数据为其父节点
+                    let samePrefixData = findLast(parents, x => getPrefix(x.code) === prefix);
+                    parentData = samePrefixData ? samePrefixData.parent : lastData;
+                } else if (!parentData && prefix !== '') {  //不是-x的数据,在父链上找不到编号与prefix相同的数据时,表根节点为其父节点
+                    parentData = curRoot;
                 }
-                else if(nodeType === 'leaf' && preLeaf && preSerialBill && preSerialBill.nodeType === preLeaf.nodeType){
-                    preLeaf.NextSiblingID = newID;
+                data.ParentID = parentData.ID;
+                data.parent = parentData;
+                let preData = findLast(parents, x => x.ParentID === data.ParentID);
+                if (preData) {
+                    preData.NextSiblingID = data.ID;
                 }
-               /* if(preBill){
-                    preBill.NextSiblingID = newID;
-                }*/
-                //set new preID
-                preID = newID;
-                preRootID = isRoot(rData) ? newID : preRootID;
-                preLeafID = isLeaf(rData) ? newID : preLeafID;
+                rst.push(data);
             }
-            preData = rData;
-        }
-        for(let i in billIdx){
-            rst.push(billIdx[i]);
         }
+        console.log(rst);
         return rst;
     }
-
-    function getImportData(validSheets, projectID){
-        let rst = {fbfx: [], jscsxm: [], zzcsxm: []};
-        let validSheetsDatas = [];
-        for(let uploadPosition in validSheets){
-            let validExcelData = [];
-            for(let uSheet of validSheets[uploadPosition]){
-                validExcelData = validExcelData.concat(getValidImportData(uSheet.colMapping, uSheet.data.dataTable));
-            }
-            if(validSheets[uploadPosition].length > 0){
-                validSheetsDatas.push({position: uploadPosition, colMapping: validSheets[uploadPosition][0].colMapping, validExcelData: validExcelData});
-            }
-        }
-        for(let validSheetData of validSheetsDatas){
-            if(validSheetData.validExcelData.length > 0){
-                rst[validSheetData.position] = parseToBillData(validSheetData.validExcelData, validSheetData.colMapping, positionFlag[validSheetData.position], projectID);
-            }
+    
+    function extactDatas(sheets) {
+        let rst = [];
+        for (let sheetName in sheets) {
+            let sheetData = sheets[sheetName];
+            let sheetType = getFileType(sheetData);
+            let colMapping = getColMapping(sheetType);
+            let datas = sheetType === fileType.gcl ? extractGCLDatas(sheetData, colMapping) : extractSLDatas(sheetData, colMapping);
+            rst = rst.concat(datas);
+        }
+        //编号去除空格 清除多余数据 设置数据
+        for (let data of rst) {
+            if (data.code && typeof data.code === 'string') {
+                data.code = data.code.replace(/\s/g, '');
+            }
+            if (data.unit === '㎡') {
+                data.unit = 'm2';
+            } else if (data.unit === 'm³') {
+                data.unit = 'm3';
+            }
+            data.projectID = projectObj.project.ID();
+            data.type = billType.BILL;
+            delete data.parent;
+            delete data.depth;
+        }
+        //将表根节点的ParentID设置成第100章至700章清单的ID
+        let fixedBill = projectObj.project.Bills.tree.roots.find(node => node.data &&
+            node.data.flagsIndex && node.data.flagsIndex.fixed && node.data.flagsIndex.fixed.flag === fixedFlag.ONE_SEVEN_BILLS);
+        let rootDatas = rst.filter(data => data.ParentID === -1);
+        for (let root of rootDatas) {
+            root.ParentID = fixedBill.data.ID;
+        }
+        //清单 第100章 总则清单需要加上固定ID
+        let oneHundredBills = rootDatas.find(data => data.name && /第100章/.test(data.name));
+        if (oneHundredBills) {
+            oneHundredBills.flags = [{flag: fixedFlag.ONE_HUNDRED_BILLS, fieldName: 'fixed'}];
         }
         return rst;
     }
 
-    function excelHasValidBills(importBillsData){
-        for(let i in importBillsData){
-            if(importBillsData[i].length > 0){
-                return true;
-            }
-        }
-        return false;
-    }
-
-
-
-    return {setImportSheetsInfo, getImportSheetsInfo, getImportSheets, getImportData, excelHasValidBills}
+    return {extactDatas}
 })();

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

@@ -28,6 +28,10 @@ var projectInfoObj = {
     },
     showProjectInfo: function (data) {
         if (data) {
+            //如果是工程量清单项目,则显示导入功能
+            if (data.property.valuationType === 'ration') {
+                $('#importSpan').show();
+            }
             if(!data.engineeringInfo.billsGuidance_lib || data.engineeringInfo.billsGuidance_lib.length === 0){
                 $('#stdBillsGuidanceTab').addClass('disabled');
             } else {

+ 5 - 41
web/building_saas/main/js/views/project_view.js

@@ -2116,14 +2116,7 @@ let displayLevel = function(nodes, depth, type){
 //导入下拉
 $('#importSpan').click(function () {
     $('[data-toggle="tooltip"]').tooltip('hide');
-    let toggle = $('#importDropDown').attr('data-toggle');
-    if (toggle) {
-        $('#importDropDown').removeAttr('data-toggle');
-    }
-    $('#importDropDown').dropdown('toggle');
-    setTimeout(function () {
-        $('#importDropDown').attr('data-toggle', 'dropdown');
-    }, 100);
+    $('#import').modal('show');
 });
 $('#importDropDown').click(function () {
     $('[data-toggle="tooltip"]').tooltip('hide');
@@ -2679,17 +2672,6 @@ function canInsertRationNode(selected) {//判断是否能插入定额、量价
     }
 }
 
-//导入类型(09表、广联达)
-const uploadType = {lj: 'lj', gld: 'gld'};
-let fileType = uploadType.lj;
-
-$('#uploadLj').click(function () {
-    fileType = uploadType.lj;
-});
-$('#uploadGld').click(function () {
-   fileType = uploadType.gld;
-});
-
 let importJson = null;
 //选择导入的excel文件
 $('#customFile').change(function () {
@@ -2716,8 +2698,6 @@ $('#customFile').change(function () {
        excelIo.open(excelFile, function (json) {
            importJson = json;
            console.log(json);
-           //读取各个表及表名
-           importBills.setImportSheetsInfo(importJson.sheets);
            console.log(`解析Excel文件时间:${+new Date() - sDate}`);
            $.bootstrapLoading.end();
        }, function (e) {
@@ -2746,21 +2726,8 @@ $('#importConfirm').click(function () {
         }
         let sDate = +new Date();
         formData.append('projectID', projectID);
-        //要去匹配的清单库(第一个)
-        let matchBillLibId = projectObj.project.projectInfo.engineeringInfo.bill_lib.length > 0 ? projectObj.project.projectInfo.engineeringInfo.bill_lib[0].id : null;
-        formData.append('billsLibId', matchBillLibId);
-        //选择的表及导入位置
-        let importSheetsInfo = importBills.getImportSheetsInfo();
-        if(importSheetsInfo.length === 0){
-            throw '请勾选要导入的表';
-        }
-        let importSheets = importBills.getImportSheets(importJson.sheets, importSheetsInfo, fileType);
-        console.log(`importSheets`);
-        console.log(importSheets);
-        let invalidSheetsInfo = importSheets.invalidSheets.join('、');
-        //获取同类表的有效数据
-        let importBillsData = importBills.getImportData(importSheets.validSheets, projectID);
-        if(!importBills.excelHasValidBills(importBillsData)){
+        let importBillsData = importBills.extactDatas(importJson.sheets);
+        if(importBillsData.length === 0){
             throw 'excel无有效数据'
         }
         let compressData = LZString.compressToUTF16(JSON.stringify(importBillsData));
@@ -2776,9 +2743,6 @@ $('#importConfirm').click(function () {
             processData: false,
             success: function(response){
                 if (response.err === 0) {
-                    if(invalidSheetsInfo !== ''){
-                        alert(`${invalidSheetsInfo},导入失败。`);
-                    }
                     // 成功则关闭窗体
                     $('#import').modal("hide");
                     //更新前端
@@ -2895,8 +2859,8 @@ function doAfterImportPosition(positionData){
 //导入后更新操作
 function doAfterImport(resData){
     if(resData && resData.length > 0){
-        for(let positionData of resData){
-            doAfterImportPosition(positionData);
+        for(let data of resData){
+            doAfterImportPosition(data);
         }
         //如果清单未锁定,导入后锁定清单
         /*if(!projectObj.project.projectInfo.property.lockBills){