Forráskód Böngészése

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

zhangweicheng 8 éve
szülő
commit
f7790d0754

+ 2 - 2
modules/pm/controllers/new_proj_controller.js

@@ -9,12 +9,12 @@ let async = require('async');
 import BillsTemplateModel from "../models/templates/bills_template_model";
 
 module.exports = {
-    copyTemplateData: async function (valuationId, newProjID, callback) {
+    copyTemplateData: async function (property, newProjID, callback) {
         async.parallel([
             async function (cb) {
                 // 获取清单模板数据
                 let billsTemplateModel = new BillsTemplateModel();
-                let templateData = JSON.stringify(await billsTemplateModel.getTemplateDataForNewProj(valuationId));
+                let templateData = JSON.stringify(await billsTemplateModel.getTemplateDataForNewProj(property.valuation, property.engineering));
                 let billsDatas = JSON.parse(templateData);
                 billsDatas.forEach(function (template) {
                     template.projectID = newProjID;

+ 23 - 3
modules/pm/controllers/pm_controller.js

@@ -45,9 +45,9 @@ module.exports = {
             }
         });
     },
-    updateProjects: function (req, res) {
+    updateProjects: async function (req, res) {
         let data = JSON.parse(req.body.data);
-        ProjectsData.updateUserProjects(req.session.sessionUser.ssoId, data.updateData, function (err, message, data) {
+        await ProjectsData.updateUserProjects(req.session.sessionUser.ssoId, data.updateData, function (err, message, data) {
             if (err === 0) {
                 callback(req, res, err, message, data);
             } else {
@@ -122,5 +122,25 @@ module.exports = {
         };
 
         response.render('building_saas/pm/html/project-management.html', renderData);
+    },
+    // 获取项目的属性
+    getProjectProperty: async function(request, response) {
+        let data = request.body.data;
+        try {
+            data = JSON.parse(data);
+            let id = data.id !== undefined ? data.id : 0;
+            if (isNaN(id) && id <= 0) {
+                throw 'id数据有误!';
+            }
+            let property = await ProjectsData.getProjectProperty(id);
+
+            if (Object.keys(property).length <= 0) {
+                throw '操作失败';
+            }
+            callback(request, response, 0, '', property);
+        } catch (error) {
+            callback(request, response, 1, error, null);
+        }
+
     }
-}
+};

+ 38 - 4
modules/pm/models/project_model.js

@@ -36,8 +36,8 @@ ProjectsDAO.prototype.getUserProject = function (userId, ProjId, callback) {
     });
 }
 
-ProjectsDAO.prototype.updateUserProjects = function(userId, datas, callback){
-    let data, project, updateLength = 0, hasError = false, deleteInfo = null, valuationId = "599256ba700b1b340c03805e", i, newProject;
+ProjectsDAO.prototype.updateUserProjects = async function(userId, datas, callback){
+    let data, project, updateLength = 0, hasError = false, deleteInfo = null, i, newProject;
     let updateAll = function (err) {
             if (!err){
                 updateLength += 1;
@@ -53,15 +53,23 @@ ProjectsDAO.prototype.updateUserProjects = function(userId, datas, callback){
     if (datas){
         for (i = 0; i < datas.length && !hasError; i++){
             data = datas[i];
+            data.updateData.name = data.updateData.name !== undefined ? data.updateData.name.trim() : null;
             if (data.updateType === 'update') {
                 Projects.update({userID: userId, ID: data.updateData.ID}, data.updateData, updateAll)
             } else if (data.updateType === 'new') {
                 data.updateData['userID'] = userId;
                 data.updateData['createDateTime'] = new Date();
                 newProject = new Projects(data.updateData);
+                // 查找同级是否存在同名数据
+                let exist = await this.isExist(data.updateData.name, data.updateData.ParentID);
+                if (exist) {
+                    callback(1, '同级目录已存在相同名称数据.', null);
+                    return;
+                }
+
                 newProject.save(function (err, result) {
                     if (!err && result._doc.projType === projectType.tender) {
-                        newProjController.copyTemplateData(valuationId, newProject.ID, updateAll);
+                        newProjController.copyTemplateData(data.updateData.property, newProject.ID, updateAll);
                     } else {
                         updateAll(err);
                     }
@@ -93,7 +101,6 @@ ProjectsDAO.prototype.copyUserProjects = function (userId, datas, callback) {
             callback(1, '提交数据出错.', null);
         }
     };
-    console.log(datas);
     if (datas) {
         for (i = 0; i < datas.length && !hasError; i++) {
             data = datas[i];
@@ -165,6 +172,33 @@ ProjectsDAO.prototype.getProject = function (key, callback) {
     }
 };
 
+/**
+ * 获取项目属性
+ *
+ * @param {Number} id
+ * @return {Promise}
+ */
+ProjectsDAO.prototype.getProjectProperty = async function(id) {
+    let projectData = await Projects.findOne({ID: id});
+    return projectData !== null && projectData.property !== undefined ? projectData.property : {};
+};
+
+/**
+ * 整理工程专业对应标准库数据
+ *
+ * @param {Object} data
+ * @return {Boolean}
+ */
+ProjectsDAO.prototype.isExist = async function(name, parentID) {
+    parentID = parseInt(parentID);
+    if (name === '' || isNaN(parentID)) {
+        return true;
+    }
+    let count = await Projects.count({ParentID: parentID, name: name});
+
+    return count > 0;
+};
+
 module.exports ={
     project: new ProjectsDAO(),
     projType: projectType

+ 6 - 4
modules/pm/models/templates/bills_template_model.js

@@ -20,12 +20,13 @@ class BillsTemplateModel extends BaseModel {
     /**
      * 获取计价类别对应的清单模板
      * @param valuationId
+     * @param engineering
      * @returns {*}
      */
-    async getTemplateData (valuationId) {
+    async getTemplateData (valuationId, engineering) {
         // 筛选字段
         let field = {_id: 1, valuationId: 1, ID: 1, ParentID: 1, NextSiblingID: 1, code: 1, name: 1, unit: 1, flags: 1};
-        let data = await this.findDataByCondition({valuationId: valuationId}, field, false);
+        let data = await this.findDataByCondition({valuationId: valuationId, engineering: engineering}, field, false);
 
         return data === null ? [] : data;
     }
@@ -33,12 +34,13 @@ class BillsTemplateModel extends BaseModel {
     /**
      * 新建项目时,获取计价类别对应的清单模板
      * @param valuationId
+     * @param engineering
      * @returns {*}
      */
-    async getTemplateDataForNewProj (valuationId) {
+    async getTemplateDataForNewProj (valuationId, engineering) {
         // 筛选字段
         let field = {_id: 0, ID: 1, ParentID: 1, NextSiblingID: 1, code: 1, name: 1, unit: 1, flags: 1};
-        let data = await this.findDataByCondition({valuationId: valuationId}, field, false);
+        let data = await this.findDataByCondition({valuationId: valuationId, engineering: engineering}, field, false);
 
         return data === null ? [] : data;
     }

+ 3 - 1
modules/pm/models/templates/schemas/bills_template.js

@@ -28,7 +28,9 @@ let BillsTemplateSchema = {
         default: []
     },
     // 所属计价ID
-    valuationId: String
+    valuationId: String,
+    // 工程专业
+    engineering: Number
 };
 
 let model = mongoose.model(collectionName, new Schema(BillsTemplateSchema, {versionKey: false, collection: collectionName}));

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

@@ -40,6 +40,7 @@ module.exports = function (app) {
     pmRouter.post('/beforeOpenProject', pmController.beforeOpenProject);
     pmRouter.post('/getProject', pmController.getProject);
     pmRouter.post('/getNewProjectID', pmController.getNewProjectID);
+    pmRouter.post('/getProjectProperty', pmController.getProjectProperty);
 
     app.use('/pm/api', pmRouter);
 };

+ 28 - 18
modules/reports/controllers/rpt_controller.js

@@ -29,7 +29,7 @@ let callback = function(req, res, err, data){
     }
 };
 
-function getAllPagesCommonOrg(rpt_id, pageSize, cb) {
+function getAllPagesCommonOrg(rpt_id, pageSize, option, cb) {
     let rptTpl = null;
     rptTplFacade.getRptTemplate(rpt_id).then(function(rst) {
         rptTpl = rst;
@@ -49,8 +49,9 @@ function getAllPagesCommonOrg(rpt_id, pageSize, cb) {
                 let printCom = JpcEx.createNew();
                 rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_PAGE_SIZE] = pageSize;
                 let defProperties = rptUtil.getReportDefaultCache();
+                let dftOption = option||JV.PAGING_OPTION_NORMAL;
                 printCom.initialize(rptTpl);
-                printCom.analyzeData(rptTpl, tplData, defProperties);
+                printCom.analyzeData(rptTpl, tplData, defProperties, dftOption);
                 let maxPages = printCom.totalPages;
                 let pageRst = printCom.outputAsSimpleJSONPageArray(rptTpl, tplData, 1, maxPages, defProperties);
                 if (pageRst) {
@@ -113,7 +114,7 @@ module.exports = {
     getReportAllPages: function(req, res){
         let rpt_id = req.body.ID;
         let pageSize = req.body.pageSize;
-        getAllPagesCommonOrg(rpt_id, pageSize, function(err, pageRst){
+        getAllPagesCommonOrg(rpt_id, pageSize, JV.PAGING_OPTION_NORMAL, function(err, pageRst){
             //fs.writeFileSync('D:/GitHome/ConstructionOperation/tmp/testRpt.js', JSON.stringify(pageRst));
             callback(req, res, err, pageRst);
         })
@@ -122,32 +123,41 @@ module.exports = {
         let rpt_id = req.params.id,
             pageSize = req.params.size,
             rptName = req.params.rptName,
-            isOneSheet = req.params.isOneSheet;
+            isOneSheet = req.params.isOneSheet,
+            option = req.params.option;
         ;
-        getAllPagesCommonOrg(rpt_id, pageSize, function(err, pageRst){
-            rpt_xl_util.exportExcel(pageRst, pageSize, rptName, isOneSheet, null, function(newName){
-                res.setHeader('Content-Type', 'application/vnd.openxmlformats');
-                res.setHeader("Content-Disposition", "attachment; filename=" + strUtil.getPinYinCamelChars(rptName) + ".xlsx");
-                let filestream = fs.createReadStream(__dirname.slice(0, __dirname.length - 28) + '/tmp/' + newName + '.xlsx');
-                filestream.on('data', function(chunk) {
-                    res.write(chunk);
-                });
-                filestream.on('end', function() {
-                    res.end();
+        let dftOption = option||JV.PAGING_OPTION_NORMAL;
+        getAllPagesCommonOrg(rpt_id, pageSize, dftOption, function(err, pageRst){
+            fs.writeFileSync('D:/GitHome/ConstructionOperation/tmp/testRpt.js', JSON.stringify(pageRst));
+            try {
+                rpt_xl_util.exportExcel(pageRst, pageSize, rptName, isOneSheet, null, function(newName){
+                    res.setHeader('Content-Type', 'application/vnd.openxmlformats');
+                    res.setHeader("Content-Disposition", "attachment; filename=" + strUtil.getPinYinCamelChars(rptName) + ".xlsx");
+                    let filestream = fs.createReadStream(__dirname.slice(0, __dirname.length - 28) + '/tmp/' + newName + '.xlsx');
+                    filestream.on('data', function(chunk) {
+                        res.write(chunk);
+                    });
+                    filestream.on('end', function() {
+                        res.end();
+                    });
                 });
-            });
+            } catch (e) {
+                console.log(e);
+            }
         })
     },
     getExcelInOneBook: function(req, res) {
         let rpt_ids = req.params.ids.split(','),
             pageSize = req.params.size,
-            rptName = req.params.rptName;
+            rptName = req.params.rptName,
+            option = req.params.option;
         ;
         let parallelFucs = [];
+        let dftOption = option||JV.PAGING_OPTION_NORMAL;
         for (let id of rpt_ids) {
             parallelFucs.push((function (rpt_id) {
                 return function (cb) {
-                    getAllPagesCommonOrg(rpt_id, pageSize, function (err, pageRst) {
+                    getAllPagesCommonOrg(rpt_id, pageSize, dftOption, function (err, pageRst) {
                         if(err){
                             cb(err);
                         }
@@ -182,7 +192,7 @@ module.exports = {
             pageSize = req.params.size,
             rptName = req.params.rptName;
 
-        getAllPagesCommonOrg(rpt_id, pageSize, function(err, pageRst){
+        getAllPagesCommonOrg(rpt_id, pageSize, JV.PAGING_OPTION_NORMAL, function(err, pageRst){
             rpt_pdf_util.export_pdf_file(pageRst, pageSize, rptName,function (newName) {
                 res.setHeader('Content-Type', 'application/vnd.openxmlformats');
                 res.setHeader("Content-Disposition", "attachment; filename=" + strUtil.getPinYinCamelChars(rptName) + ".pdf");

+ 2 - 2
modules/reports/routes/report_router.js

@@ -19,8 +19,8 @@ module.exports =function (app) {
     });
     rptRouter.post('/getReport', reportController.getReportAllPages);
 
-    rptRouter.get('/getExcel/:id/:size/:rptName/:isOneSheet', reportController.getExcel);
-    rptRouter.get('/getExcelInOneBook/:ids/:size/:rptName', reportController.getExcelInOneBook);
+    rptRouter.get('/getExcel/:id/:size/:rptName/:isOneSheet/:option', reportController.getExcel);
+    rptRouter.get('/getExcelInOneBook/:ids/:size/:rptName/:option', reportController.getExcelInOneBook);
 
     rptRouter.get('/getPDF/:id/:size/:rptName', reportController.getPDF);//2/A4/07-1表
     app.use("/report_api", rptRouter);

+ 24 - 0
modules/reports/rpt_component/helper/jpc_helper_band.js

@@ -82,6 +82,30 @@ let JpcBandHelper = {
                 }
             }
         }
+    },
+    resetBandPos: function (bandCollection, bands, contentBand, offsetY) {
+        let orgY = contentBand.Bottom;
+        function chkAndResetPos(targetBand) {
+            let band = bands[targetBand.Name];
+            if (band) {
+                if (band === contentBand) {
+                    band.Bottom += offsetY;
+                } else {
+                    if (band.Top >= orgY) {
+                        band.Top += offsetY;
+                        band.Bottom += offsetY;
+                    }
+                }
+                if (targetBand[JV.BAND_PROP_SUB_BANDS]) {
+                    for (let i = 0; i < targetBand[JV.BAND_PROP_SUB_BANDS].length; i++) {
+                        chkAndResetPos(targetBand[JV.BAND_PROP_SUB_BANDS][i]);
+                    }
+                }
+            }
+        }
+        for (let i = 0; i < bandCollection.length; i++) {
+            chkAndResetPos(bandCollection[i]);
+        }
     }
 };
 

+ 23 - 4
modules/reports/rpt_component/helper/jpc_helper_flow_tab.js

@@ -3,12 +3,12 @@ let JpcCommonHelper = require('./jpc_helper_common');
 
 let JpcFlowTabHelper = {
     getMaxRowsPerPage: function(bands, rptTpl) {
-        let me = this, rst = 1;
+        let rst = 1;
         let tab = rptTpl[JV.NODE_FLOW_INFO][JV.NODE_FLOW_CONTENT];
         let band = bands[tab[JV.PROP_BAND_NAME]];
         if (band) {
             let maxFieldMeasure = 1.0;
-            if (JV.CAL_TYPE_ABSTRACT == JpcCommonHelper.getPosCalculationType(tab[JV.PROP_CALCULATION])) {
+            if (JV.CAL_TYPE_ABSTRACT === JpcCommonHelper.getPosCalculationType(tab[JV.PROP_CALCULATION])) {
                 let unitFactor = JpcCommonHelper.getUnitFactor(rptTpl);
                 maxFieldMeasure = 1.0 * rptTpl[JV.NODE_FLOW_INFO][JV.NODE_FLOW_CONTENT][JV.PROP_CMN_HEIGHT] * unitFactor;
             } else {
@@ -18,6 +18,25 @@ let JpcFlowTabHelper = {
         }
         return rst;
     },
+    getActualContentAreaHeight: function(bands, rptTpl, segments, page) {
+        let rst = 1;
+        let tab = rptTpl[JV.NODE_FLOW_INFO][JV.NODE_FLOW_CONTENT];
+        let band = bands[tab[JV.PROP_BAND_NAME]];
+        if (band) {
+            let maxFieldMeasure = 1.0;
+            if (JV.CAL_TYPE_ABSTRACT === JpcCommonHelper.getPosCalculationType(tab[JV.PROP_CALCULATION])) {
+                let unitFactor = JpcCommonHelper.getUnitFactor(rptTpl);
+                maxFieldMeasure = 1.0 * rptTpl[JV.NODE_FLOW_INFO][JV.NODE_FLOW_CONTENT][JV.PROP_CMN_HEIGHT] * unitFactor;
+            } else {
+                maxFieldMeasure = (band.Bottom - band.Top) * rptTpl[JV.NODE_FLOW_INFO][JV.NODE_FLOW_CONTENT][JV.PROP_CMN_HEIGHT] / JV.HUNDRED_PERCENT;
+            }
+            //rst = Math.floor((band.Bottom - band.Top) / maxFieldMeasure);
+            if (segments.length >= page) {
+                rst = segments[page - 1].length * maxFieldMeasure;
+            }
+        }
+        return rst;
+    },
     chkSegEnd: function (bands, rptTpl, sortedSequence, segIdx, preRec, nextRec) {
         let me = this, rst = true;
         let remainAmt = preRec + nextRec - sortedSequence[segIdx].length;
@@ -30,10 +49,10 @@ let JpcFlowTabHelper = {
         let unitFactor = JpcCommonHelper.getUnitFactor(rptTpl);
         let tab = rptTpl[JV.NODE_FLOW_INFO][JV.NODE_FLOW_CONTENT];
         let band = bands[tab[JV.PROP_BAND_NAME]];
-        if (band != null && band != undefined) {
+        if (band !== null && band !== undefined) {
             measurement = 1.0 * tab[JV.PROP_CMN_HEIGHT] * unitFactor;
             let spareHeight = measurement * remainAmt;
-            let douH = 1.0 * (band.Bottom - band.Top);
+            let douH = band.Bottom - band.Top;
             rst = (spareHeight >= douH) || (spareHeight - douH <= douDiffForCompare);
         }
         return rst;

+ 2 - 2
modules/reports/rpt_component/jpc_cross_tab.js

@@ -226,8 +226,8 @@ JpcCrossTabSrv.prototype.createNew = function(){
 
         }
     };
-    JpcCrossTabResult.preSetupPages = function(rptTpl, defProperties) {
-        let rst = 0, me = this;
+    JpcCrossTabResult.preSetupPages = function(rptTpl, defProperties, option) {
+        let rst = 0, me = this, dftPagingOption = option||JV.PAGING_OPTION_NORMAL;
         //1. original initialize
         let maxRowRec = 1, maxColRec = 1, counterRowRec = 0, counterColRec = 0, pageIdx = 0, segCnt = me.sortedContentSequence.length;
         let pageStatus = [true, true, false, true, false, false, false, false];

+ 21 - 13
modules/reports/rpt_component/jpc_ex.js

@@ -109,8 +109,8 @@ JpcExSrv.prototype.createNew = function(){
         me.formulas = JpcFunc.createNew(rptTpl);
     };
 
-    JpcResult.analyzeData = function(rptTpl, dataObj, defProperties) {
-        let me = this;
+    JpcResult.analyzeData = function(rptTpl, dataObj, defProperties, option) {
+        let me = this, dftPagingOption = option||JV.PAGING_OPTION_NORMAL;
         //1. data object
         let dataHelper = JpcData.createNew();
         dataHelper.analyzeData(rptTpl, dataObj);
@@ -131,17 +131,17 @@ JpcExSrv.prototype.createNew = function(){
         //3. formulas
         me.executeFormulas(JV.RUN_TYPE_BEFORE_PAGING, rptTpl, dataObj, me);
         //4. paging
-        me.paging(rptTpl, dataObj, defProperties);
+        me.paging(rptTpl, dataObj, defProperties, dftPagingOption);
         //alert('analyzeData was completed!');
         //for garbage collection:
         dataHelper = null;
     };
-    JpcResult.paging = function(rptTpl, dataObj, defProperties) {
-        let me = this;
+    JpcResult.paging = function(rptTpl, dataObj, defProperties, option) {
+        let me = this, dftPagingOption = option||JV.PAGING_OPTION_NORMAL;
         if (me.flowTab) {
-            me.totalPages = me.flowTab.preSetupPages(rptTpl, dataObj, defProperties);
+            me.totalPages = me.flowTab.preSetupPages(rptTpl, dataObj, defProperties, dftPagingOption);
             if (me.flowTabEx) {
-                me.exTotalPages = me.flowTabEx.preSetupPages(rptTpl, dataObj, defProperties);
+                me.exTotalPages = me.flowTabEx.preSetupPages(rptTpl, dataObj, defProperties, dftPagingOption);
                 //console.log('ad-hoc flow pages: ' + me.exTotalPages);
             }
             me.totalPages += me.exTotalPages;
@@ -166,9 +166,9 @@ JpcExSrv.prototype.createNew = function(){
     JpcResult.outputAsSimpleJSONPageArray = function(rptTpl, dataObj, startPage, endPage, defProperties) {
         let me = this, rst = {};
         if ((startPage > 0) && (startPage <= endPage) && (endPage <= me.totalPages)) {
-            rst[JV.NODE_CONTROL_COLLECTION] = private_buildDftControls(rptTpl, (defProperties == null)?null:defProperties.ctrls);
-            rst[JV.NODE_STYLE_COLLECTION] = private_buildDftStyles(rptTpl, (defProperties == null)?null:defProperties.styles);
-            rst[JV.NODE_FONT_COLLECTION] = private_buildDftFonts(rptTpl, (defProperties == null)?null:defProperties.fonts);
+            rst[JV.NODE_CONTROL_COLLECTION] = private_buildDftControls(rptTpl, (defProperties === null)?null:defProperties.ctrls);
+            rst[JV.NODE_STYLE_COLLECTION] = private_buildDftStyles(rptTpl, (defProperties === null)?null:defProperties.styles);
+            rst[JV.NODE_FONT_COLLECTION] = private_buildDftFonts(rptTpl, (defProperties === null)?null:defProperties.fonts);
             rst[JV.NODE_PAGE_INFO] = {};
             rst[JV.NODE_PAGE_INFO][JV.NODE_MAIN_INFO_RPT_NAME] = rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MAIN_INFO_RPT_NAME];
             rst[JV.NODE_PAGE_INFO][JV.NODE_PAGE_SIZE] = JpcCommonHelper.getPageSize(rptTpl);
@@ -204,11 +204,19 @@ JpcExSrv.prototype.createNew = function(){
             rst = {};
             rst[JV.PROP_PAGE_SEQ] = page;
             //rst.cells = [];
+            let adHocMergePos = null;
             if (me.flowTab) {
                 if (me.totalPages - me.exTotalPages >= page) {
-                    rst.cells = me.flowTab.outputAsSimpleJSONPage(rptTpl, dataObj, page, bands, controls, me);
+                    if (me.flowTab.paging_option === JV.PAGING_OPTION_INFINITY_VERTICAL) {
+                        adHocMergePos = {};
+                    }
+                    rst.cells = me.flowTab.outputAsSimpleJSONPage(rptTpl, dataObj, page, bands, controls, adHocMergePos, me);
+                    if (adHocMergePos) {
+                        adHocMergePos[JV.NODE_PAGE_SIZE] = JpcCommonHelper.getPageSize(rptTpl);
+                        rst[JV.PAGE_SPECIAL_MERGE_POS] = adHocMergePos;
+                    }
                 } else {
-                    rst.cells = me.flowTabEx.outputAsSimpleJSONPage(rptTpl, dataObj, page - (me.totalPages - me.exTotalPages), bands, controls, me);
+                    rst.cells = me.flowTabEx.outputAsSimpleJSONPage(rptTpl, dataObj, page - (me.totalPages - me.exTotalPages), bands, controls, adHocMergePos, me);
                 }
             } else if (me.crossTab) {
                 rst.cells = me.crossTab.outputAsSimpleJSONPage(rptTpl, dataObj, page, bands, controls, me);
@@ -220,6 +228,6 @@ JpcExSrv.prototype.createNew = function(){
     };
     //JpcEx.rte.currentRptObj = JpcResult;
     return JpcResult;
-}
+};
 
 module.exports = new JpcExSrv();

+ 114 - 59
modules/reports/rpt_component/jpc_flow_tab.js

@@ -28,6 +28,7 @@ JpcFlowTabSrv.prototype.createNew = function(){
     JpcFlowTabResult.initialize = function(isEx) {
         let me = this;
         me.isEx = isEx;
+        me.paging_option = JV.PAGING_OPTION_NORMAL;
         me.segments = [];
         me.dispValueIdxLst = [];
         me.page_seg_map = [];
@@ -73,69 +74,123 @@ JpcFlowTabSrv.prototype.createNew = function(){
 
         }
     };
-    JpcFlowTabResult.preSetupPages = function (rptTpl, dataOjb, defProperties) {
-        let rst = 0, me = this, counterRowRec = 0, maxRowRec = 1, pageIdx = 0;
+    JpcFlowTabResult.preSetupPages = function (rptTpl, dataOjb, defProperties, option) {
+        let me = this, rst = 1, counterRowRec = 0, maxRowRec = 1, pageIdx = 0;
+        me.paging_option = option||JV.PAGING_OPTION_NORMAL;
         let CURRENT_FLOW_INFO = (me.isEx)?JV.NODE_FLOW_INFO_EX:JV.NODE_FLOW_INFO;
         JpcFieldHelper.findAndPutDataFieldIdx(rptTpl, rptTpl[CURRENT_FLOW_INFO][JV.NODE_FLOW_CONTENT][JV.PROP_FLOW_FIELDS], null, me.disp_fields_idx, me.isEx);
-        let bands = JpcBand.createNew(rptTpl, defProperties);
-        let pageStatus = [true, true, false, false, false, false, false, false];
-        if (me.isEx) {
-            pageStatus[JV.STATUS_REPORT_START] = false;
-        }
-        if (rptTpl[CURRENT_FLOW_INFO][JV.PROP_MULTI_COLUMN]) {
-            me.multiCols = 1 * rptTpl[CURRENT_FLOW_INFO][JV.PROP_MULTI_COLUMN];
-        }
-        function private_resetBandArea() {
-            JpcBandHelper.setBandArea(bands, rptTpl, pageStatus, !me.isEx, me.isEx);
-            maxRowRec = JpcFlowTabHelper.getMaxRowsPerPage(bands, rptTpl);
-        }
-        for (let segIdx = 0; segIdx < me.segments.length; segIdx++) {
-            private_resetBandArea();
-            let orgMaxRowRec = maxRowRec;
-            let rowSplitCnt = Math.ceil(1.0 * me.segments[segIdx].length / orgMaxRowRec);
-            pageStatus[JV.STATUS_SEGMENT_END] = true;
-            private_resetBandArea();
-            let hasAdHocRow = !JpcFlowTabHelper.chkSegEnd(bands, rptTpl, me.segments, segIdx, (rowSplitCnt - 1) * orgMaxRowRec, maxRowRec);
-            if (hasAdHocRow) rowSplitCnt++;
-            if (rowSplitCnt % me.multiCols > 0) {
-                rowSplitCnt++
-            }
-            for (let rowIdx = 0; rowIdx < rowSplitCnt; rowIdx++) {
-                pageStatus[JV.STATUS_SEGMENT_END] = rowIdx == (rowSplitCnt - 1)?true:false;
-                if (pageIdx > 0) pageStatus[JV.STATUS_REPORT_START] = false;
-                private_resetBandArea();
+        if (me.paging_option === JV.PAGING_OPTION_INFINITY_VERTICAL) {
+            rst = me.segments.length;
+            let pageStatus = [true, true, false, true, true, true, false, false];
+            for (let segIdx = 0; segIdx < me.segments.length; segIdx++) {
+                if (segIdx === me.segments.length - 1) {
+                    pageStatus[JV.STATUS_REPORT_END] = true;
+                }
+                if (segIdx > 0) {
+                    pageStatus[JV.STATUS_REPORT_START] = false;
+                }
                 me.pageStatusLst.push(pageStatus.slice(0));
                 pageIdx++;
-                counterRowRec = orgMaxRowRec * rowIdx;
-                private_addPageValue(me.dispValueIdxLst, me.segments[segIdx], counterRowRec, maxRowRec,me.page_seg_map, segIdx, pageIdx);
+                private_addPageValue(me.dispValueIdxLst, me.segments[segIdx], 0, me.segments[segIdx].length, me.page_seg_map, segIdx, pageIdx);
+            }
+        } else {
+            let bands = JpcBand.createNew(rptTpl, defProperties);
+            let pageStatus = [true, true, false, true, false, false, false, false];
+            if (me.isEx) {
+                pageStatus[JV.STATUS_REPORT_START] = false;
+            }
+            if (rptTpl[CURRENT_FLOW_INFO][JV.PROP_MULTI_COLUMN]) {
+                me.multiCols = 1 * rptTpl[CURRENT_FLOW_INFO][JV.PROP_MULTI_COLUMN];
+            }
+            function private_resetBandArea() {
+                JpcBandHelper.setBandArea(bands, rptTpl, pageStatus, !me.isEx, me.isEx);
+                maxRowRec = JpcFlowTabHelper.getMaxRowsPerPage(bands, rptTpl);
             }
-            pageStatus[JV.STATUS_SEGMENT_END] = false;
-            pageStatus[JV.STATUS_REPORT_START] = false;
+            for (let segIdx = 0; segIdx < me.segments.length; segIdx++) {
+                private_resetBandArea();
+                let orgMaxRowRec = maxRowRec;
+                let rowSplitCnt = Math.ceil(1.0 * me.segments[segIdx].length / orgMaxRowRec);
+                pageStatus[JV.STATUS_SEGMENT_END] = true;
+                private_resetBandArea();
+                let hasAdHocRow = !JpcFlowTabHelper.chkSegEnd(bands, rptTpl, me.segments, segIdx, (rowSplitCnt - 1) * orgMaxRowRec, maxRowRec);
+                if (hasAdHocRow) rowSplitCnt++;
+                if (rowSplitCnt % me.multiCols > 0) {
+                    rowSplitCnt++
+                }
+                for (let rowIdx = 0; rowIdx < rowSplitCnt; rowIdx++) {
+                    pageStatus[JV.STATUS_SEGMENT_END] = (rowIdx === (rowSplitCnt - 1));
+                    if (pageIdx > 0) pageStatus[JV.STATUS_REPORT_START] = false;
+                    private_resetBandArea();
+                    me.pageStatusLst.push(pageStatus.slice(0));
+                    pageIdx++;
+                    counterRowRec = orgMaxRowRec * rowIdx;
+                    private_addPageValue(me.dispValueIdxLst, me.segments[segIdx], counterRowRec, maxRowRec,me.page_seg_map, segIdx, pageIdx);
+                }
+                pageStatus[JV.STATUS_SEGMENT_END] = false;
+                pageStatus[JV.STATUS_REPORT_START] = false;
+            }
+            rst = Math.ceil(pageIdx / me.multiCols);
         }
-        rst = Math.ceil(1.0 * pageIdx / me.multiCols);
         me.pagesAmt = rst;
         return rst;
     };
-    JpcFlowTabResult.outputAsSimpleJSONPage = function (rptTpl, dataObj, page, bands, controls, $CURRENT_RPT) {
+    JpcFlowTabResult.outputAsSimpleJSONPage = function (rptTpl, dataObj, page, bands, controls, adHocMergePos, $CURRENT_RPT) {
         let me = this, rst = [], tabRstLst = [];
         let FLOW_NODE_STR = me.isEx?JV.NODE_FLOW_INFO_EX:JV.NODE_FLOW_INFO;
-        let segIdx = JpcCommonHelper.getSegIdxByPageIdx(page, me.page_seg_map);
-        //1 calculate the band position
-        JpcBandHelper.setBandArea(bands, rptTpl, me.pageStatusLst[page - 1], !me.isEx, me.isEx);
-        //2. start to output detail-part
         let unitFactor = JpcCommonHelper.getUnitFactor(rptTpl);
-        for (let pi = 0; pi < me.multiCols; pi++) {
-            let actualPage = (page - 1) * me.multiCols + pi + 1;
-            //2.1 Content-Tab
-            tabRstLst.push(me.outputContent(rptTpl, dataObj, actualPage, bands, unitFactor, controls, pi, $CURRENT_RPT));
-            //2.2 Column tab
-            tabRstLst.push(me.outputColumn(rptTpl, dataObj, actualPage, segIdx, bands, unitFactor, controls, pi));
-            //2.3 Sum Seg
-            tabRstLst.push(me.outputSegSum(rptTpl, dataObj, actualPage, segIdx, bands, unitFactor, controls));
-            //2.4 Sum Page
-            //2.5 Discrete
-            if (pi == 0) {
-                tabRstLst.push(JpcDiscreteHelper.outputDiscreteInfo(rptTpl[FLOW_NODE_STR][JV.NODE_DISCRETE_INFO], bands, dataObj, unitFactor, me.pageStatusLst[actualPage - 1], segIdx, 1, pi, $CURRENT_RPT));
+        if (me.paging_option === JV.PAGING_OPTION_INFINITY_VERTICAL) {
+            let segIdx = page - 1;
+            //1 calculate the band position
+            JpcBandHelper.setBandArea(bands, rptTpl, me.pageStatusLst[page - 1], !me.isEx, me.isEx);
+            //2. then reset the band height
+            let tab = rptTpl[JV.NODE_FLOW_INFO][JV.NODE_FLOW_CONTENT];
+            let flowContentBand = bands[tab[JV.PROP_BAND_NAME]];
+            let actH = JpcFlowTabHelper.getActualContentAreaHeight(bands, rptTpl, me.segments, page);
+            let offsetY = actH - (flowContentBand.Bottom - flowContentBand.Top);
+            JpcBandHelper.resetBandPos(rptTpl[JV.NODE_BAND_COLLECTION], bands, flowContentBand, offsetY);
+
+            tabRstLst.push(me.outputContent(rptTpl, dataObj, page, bands, unitFactor, controls, 0, $CURRENT_RPT));
+            // 2.2 Column tab
+            tabRstLst.push(me.outputColumn(rptTpl, dataObj, page, segIdx, bands, unitFactor, controls, 0));
+            // 2.3 Sum Seg
+            tabRstLst.push(me.outputSegSum(rptTpl, dataObj, page, segIdx, bands, unitFactor, controls));
+            // 2.4 Sum Page
+            // 2.5 Discrete
+            tabRstLst.push(JpcDiscreteHelper.outputDiscreteInfo(rptTpl[FLOW_NODE_STR][JV.NODE_DISCRETE_INFO], bands, dataObj, unitFactor, me.pageStatusLst[page - 1], segIdx, 1, 0, $CURRENT_RPT));
+            //3. reset merge band position
+            if (bands[JV.BAND_PROP_MERGE_BAND] && adHocMergePos) {
+                let mergedBand = bands[JV.BAND_PROP_MERGE_BAND];
+                let arr = [];
+                arr.push(parseInt(mergedBand[JV.PROP_LEFT].toFixed(0)));
+                adHocMergePos[JV.PROP_LEFT] = arr;
+                arr = [];
+                arr.push(parseInt(mergedBand[JV.PROP_RIGHT].toFixed(0)));
+                adHocMergePos[JV.PROP_RIGHT] = arr;
+                arr = [];
+                arr.push(parseInt(mergedBand[JV.PROP_TOP].toFixed(0)));
+                adHocMergePos[JV.PROP_TOP] = arr;
+                arr = [];
+                arr.push(parseInt((mergedBand[JV.PROP_BOTTOM] + offsetY).toFixed(0)));
+                adHocMergePos[JV.PROP_BOTTOM] = arr;
+            }
+        } else {
+            let segIdx = JpcCommonHelper.getSegIdxByPageIdx(page, me.page_seg_map);
+            //1 calculate the band position
+            JpcBandHelper.setBandArea(bands, rptTpl, me.pageStatusLst[page - 1], !me.isEx, me.isEx);
+            //2. start to output detail-part
+            for (let pi = 0; pi < me.multiCols; pi++) {
+                let actualPage = (page - 1) * me.multiCols + pi + 1;
+                //2.1 Content-Tab
+                tabRstLst.push(me.outputContent(rptTpl, dataObj, actualPage, bands, unitFactor, controls, pi, $CURRENT_RPT));
+                //2.2 Column tab
+                tabRstLst.push(me.outputColumn(rptTpl, dataObj, actualPage, segIdx, bands, unitFactor, controls, pi));
+                //2.3 Sum Seg
+                tabRstLst.push(me.outputSegSum(rptTpl, dataObj, actualPage, segIdx, bands, unitFactor, controls));
+                //2.4 Sum Page
+                //2.5 Discrete
+                if (pi === 0) {
+                    tabRstLst.push(JpcDiscreteHelper.outputDiscreteInfo(rptTpl[FLOW_NODE_STR][JV.NODE_DISCRETE_INFO], bands, dataObj, unitFactor, me.pageStatusLst[actualPage - 1], segIdx, 1, pi, $CURRENT_RPT));
+                }
             }
         }
         for (let i = 0; i < tabRstLst.length; i++) {
@@ -151,14 +206,14 @@ JpcFlowTabSrv.prototype.createNew = function(){
         let band = bands[tab[JV.PROP_BAND_NAME]];
         if (band) {
             let pageStatus = me.pageStatusLst[page - 1];
-            if (pageStatus[band[JV.BAND_PROP_DISPLAY_TYPE]] == true) {
+            if (pageStatus[band[JV.BAND_PROP_DISPLAY_TYPE]]) {
                 let tab_fields = tab[JV.PROP_FLOW_FIELDS];
                 let data_details = me.isEx?dataObj[JV.DATA_DETAIL_DATA_EX]:dataObj[JV.DATA_DETAIL_DATA];
                 let contentValuesIdx = me.dispValueIdxLst[page - 1];
                 for (let i = 0; i < tab_fields.length; i++) {
                     let tab_field = tab_fields[i];
                     let data_field = null;
-                    if (me.disp_fields_idx[i] != JV.BLANK_FIELD_INDEX) {
+                    if (me.disp_fields_idx[i] !== JV.BLANK_FIELD_INDEX) {
                         data_field = data_details[me.disp_fields_idx[i]];
                     } else {
                         data_field = JE.F(tab_field[JV.PROP_FIELD_ID], $CURRENT_RPT);
@@ -183,7 +238,7 @@ JpcFlowTabSrv.prototype.createNew = function(){
         let band = bands[tab[JV.PROP_BAND_NAME]];
         if (band) {
             let pageStatus = me.pageStatusLst[page - 1];
-            if (pageStatus[band[JV.BAND_PROP_DISPLAY_TYPE]] == true) {
+            if (pageStatus[band[JV.BAND_PROP_DISPLAY_TYPE]]) {
                 if (tab[JV.PROP_TEXT]) {
                     rst.push(JpcTextHelper.outputText(tab[JV.PROP_TEXT], band, unitFactor, 1, 0, 1, 0, me.multiCols, multiColIdx));
                 }
@@ -206,7 +261,7 @@ JpcFlowTabSrv.prototype.createNew = function(){
         let band = bands[tab[JV.PROP_BAND_NAME]];
         if (band) {
             let pageStatus = me.pageStatusLst[page - 1];
-            if (pageStatus[band[JV.BAND_PROP_DISPLAY_TYPE]] == true) {
+            if (pageStatus[band[JV.BAND_PROP_DISPLAY_TYPE]]) {
                 let tab_fields = me.seg_sum_tab_fields;
                 for (let i = 0; i < tab_fields.length; i++) {
                     let cellItem = JpcCommonOutputHelper.createCommonOutput(tab_fields[i], me.segSumValLst[segIdx][i], controls);
@@ -229,13 +284,13 @@ JpcFlowTabSrv.prototype.createNew = function(){
         return rst;
     };
     JpcFlowTabResult.outputTabField = function (band, tab_field, data_field, valueIdx, serialIdx, rows, rowIdx, cols, colIdx, unitFactor, isRow, controls, multiColIdx) {
-        let me = this, rst = null;
-        rst = JpcCommonOutputHelper.createCommonOutput(tab_field, JpcFieldHelper.getValue(data_field, valueIdx), controls);
+        let me = this,
+            rst = JpcCommonOutputHelper.createCommonOutput(tab_field, JpcFieldHelper.getValue(data_field, valueIdx), controls);
         rst[JV.PROP_AREA] = JpcAreaHelper.outputArea(tab_field[JV.PROP_AREA], band, unitFactor, rows, rowIdx, cols, colIdx, me.multiCols, multiColIdx, true, false);
         return rst;
-    }
+    };
 
     return JpcFlowTabResult;
-}
+};
 
 module.exports = new JpcFlowTabSrv();

+ 13 - 2
modules/reports/util/rpt_excel_util.js

@@ -794,6 +794,9 @@ function writeSheet(pageData, sheetData, paperSize, sharedStrList, stylesObj){
         pStr = 'paperSize="' + JV.PAGES_SIZE_IDX[paperSizeIdx] + '"';
     }
     let orientationStr = (pageData[JV.NODE_PAGE_INFO][JV.NODE_PAGE_SIZE][0] > pageData[JV.NODE_PAGE_INFO][JV.NODE_PAGE_SIZE][1])?'landscape':'portrait';
+    if (currentPageMergePos) {
+        orientationStr = (currentPageMergePos[JV.NODE_PAGE_SIZE][0] > currentPageMergePos[JV.NODE_PAGE_SIZE][1])?'landscape':'portrait';
+    }
     rst.push('<pageSetup ' + pStr + ' fitToWidth="0" fitToHeight="0" orientation="' + orientationStr + '" />');
     rst.push('<headerFooter alignWithMargins="0"/>');
     rst.push('</worksheet>');
@@ -941,8 +944,15 @@ module.exports = {
 
                 for (let j = 0; j < pageDataArray[i].items.length; j++) {
                     let maxY = 0, minY = 100000;
-                    mergeBand[JV.PROP_TOP].push(pageDataArray[i][JV.BAND_PROP_MERGE_BAND][JV.PROP_TOP] + offsetY);
-                    mergeBand[JV.PROP_BOTTOM].push(pageDataArray[i][JV.BAND_PROP_MERGE_BAND][JV.PROP_BOTTOM] + offsetY);
+                    if (pageDataArray[i].items[j][JV.PAGE_SPECIAL_MERGE_POS]) {
+                        let pos = pageDataArray[i].items[j][JV.PAGE_SPECIAL_MERGE_POS][JV.PROP_TOP][0] + offsetY;
+                        mergeBand[JV.PROP_TOP].push(pos);
+                        pos = pageDataArray[i].items[j][JV.PAGE_SPECIAL_MERGE_POS][JV.PROP_BOTTOM][0] + offsetY;
+                        mergeBand[JV.PROP_BOTTOM].push(pos);
+                    } else {
+                        mergeBand[JV.PROP_TOP].push(pageDataArray[i][JV.BAND_PROP_MERGE_BAND][JV.PROP_TOP] + offsetY);
+                        mergeBand[JV.PROP_BOTTOM].push(pageDataArray[i][JV.BAND_PROP_MERGE_BAND][JV.PROP_BOTTOM] + offsetY);
+                    }
                     for (let k = 0; k < pageDataArray[i].items[j].cells.length; k++) {
                         if (maxY < pageDataArray[i].items[j].cells[k][JV.PROP_AREA][JV.PROP_BOTTOM]) {
                             maxY = pageDataArray[i].items[j].cells[k][JV.PROP_AREA][JV.PROP_BOTTOM];
@@ -967,6 +977,7 @@ module.exports = {
                         pageItem[JV.PROP_CELLS].push(pageDataArray[i].items[j].cells[k]);
                     }
                 }
+                newPagePos[i][JV.NODE_PAGE_SIZE] = pageDataArray[i][JV.NODE_PAGE_INFO][JV.NODE_PAGE_SIZE];
                 pageItem[JV.PAGE_SPECIAL_MERGE_POS] = newPagePos[i];
                 newPageData.items.push(pageItem);
             }

+ 29 - 14
public/calc_util.js

@@ -41,6 +41,7 @@ let executeObj = {
 
 let analyzer = {
     calcTemplate: null,
+    success: true,
 
     standard: function(expr){
         let str = expr;
@@ -72,7 +73,7 @@ let analyzer = {
             return base;
         };
         function calcBaseToIDExpr(base){
-            // for test.
+            /*// for test. 公路模式,基数到ID
             let id = -1;
             if (base == '[人工费]'){
                 id = 111;
@@ -85,7 +86,9 @@ let analyzer = {
             }
             else id = "错误";
 
-            return "@('" + id + "')";
+            return "@('" + id + "')";*/
+            let baseValue = base.slice(1, -1);
+            return "base('" + baseValue + "')";
         };
 
         while (expr.indexOf('[') > 0) {
@@ -94,7 +97,7 @@ let analyzer = {
             let baseValue = base.slice(1, -1);   // []会给下面的正则带来干扰,这里去掉
             var pattBase =new RegExp(baseValue, "g");
             expr = expr.replace(pattBase, id);
-            expr = expr.replace(/\[@\('/g, "@('");      // [@('
+            expr = expr.replace(/\[base\('/g, "base('");      // [@('       [base('
             expr = expr.replace(/'\)\]/g, "')");        // ')]
         };
 
@@ -102,12 +105,20 @@ let analyzer = {
     },
 
     analyzeLineRef: function(expr){
+        let me = this;
         function isOperator(char){
             var operator = "+-*/()";
             return operator.indexOf(char) > -1;
         };
-        function codeToID(code){
-            return eval(parseFloat(code)+1);
+        function lineNumToID(lineNum){
+            if (lineNum > me.calcTemplate.calcItems.length){
+                me.success = false;
+                return '越界';
+            }
+            else{
+                let id = me.calcTemplate.calcItems[lineNum - 1].ID;
+                return id;
+            }
         };
         // 前提:必须无空格、无特殊符号、标准大写F
         function getSection(expr){
@@ -133,12 +144,13 @@ let analyzer = {
         };
         function sectionToIDExpr(section){
             if (section){
-                let code = section.slice(1);
-                if (isNaN(code)){
-                    return '错误'      // 这里的返回提示不能加上section,因为会无限循环
+                let lineNum = section.slice(1);
+                if (isNaN(lineNum)){
+                    me.success = false;
+                    return '错误';      // 这里的返回提示不能加上section,因为会无限循环
                 }
                 else
-                    return "@('" + codeToID(code) + "')";
+                    return "@('" + lineNumToID(lineNum) + "')";
             }
             else return '';
         };
@@ -153,16 +165,18 @@ let analyzer = {
     },
 
     analyzeUserExpr: function(calcTemplate, calcItem){
-        this.calcTemplate = calcTemplate;
+        let me = this;
+        me.calcTemplate = calcTemplate;
         let expr = calcItem.dispExpr;
         // 标准化:处理特殊字符、中文符号、大小写
-        expr = this.standard(expr);
+        expr = me.standard(expr);
         calcItem.dispExpr = expr;
         // 先换掉计算基数
-        expr = this.analyzeCalcBase(expr);
+        expr = me.analyzeCalcBase(expr);
         // 再换掉行引用
-        expr = this.analyzeLineRef(expr);
+        expr = me.analyzeLineRef(expr);
         calcItem.expression = expr;
+        return me.success;
     }
 };
 
@@ -363,4 +377,5 @@ class Calculation {
     }
 };
 
-//export default analyzer;
+/*
+export default analyzer;*/

+ 5 - 0
public/web/rpt_value_define.js

@@ -195,6 +195,11 @@ let JV = {
     PROP_PAGE_SEQ: "page_seq",
     PROP_CELLS: "cells",
 
+    PAGING_OPTION_NORMAL: 'normal',
+    PAGING_OPTION_INFINITY_HORIZON: 'infinity_horizon',
+    PAGING_OPTION_INFINITY_VERTICAL: 'infinity_vertical',
+    PAGING_OPTION_INFINITY_BOTH: 'infinity_both',
+
     PAGE_SELF_DEFINE: "自定义",
     PAGE_SPECIAL_MERGE_POS: "page_merge_pos",
 

+ 22 - 21
test/calculation/test_analyzer.js

@@ -10,7 +10,7 @@ test('解析测试', function(t){
         name: "建筑工程",
         calcItems: [
             {
-                ID: "1",
+                ID: "101",
                 code: "1",
                 name: "基价直接工程费",
                 fieldName: "baseDirect",
@@ -20,7 +20,7 @@ test('解析测试', function(t){
                 statement: "基价人工费+基价材料费+基价机械费+未计价材料费"
             },
             {
-                ID: "2",
+                ID: "102",
                 code: "1.1",
                 name: "基价人工费",
                 fieldName: "baseLabour",
@@ -30,7 +30,7 @@ test('解析测试', function(t){
                 statement: "定额基价人工费+定额人工单价(基价)调整"
             },
             {
-                ID: "3",
+                ID: "103",
                 code: "1.1.1",
                 name: "定额基价人工费",
                 fieldName: "rationBaseLabour",
@@ -40,7 +40,7 @@ test('解析测试', function(t){
                 statement: "定额基价人工费"
             },
             {
-                ID: "4",
+                ID: "104",
                 code: "1.1.2",
                 name: "定额人工单价(基价)调整",
                 fieldName: "rationLabourFixed",
@@ -52,7 +52,7 @@ test('解析测试', function(t){
                 memo: "渝建发(2013)51"
             },
             {
-                ID: "5",
+                ID: "105",
                 code: "1.2",
                 name: "基价材料费",
                 fieldName: "baseMaterial",
@@ -62,7 +62,7 @@ test('解析测试', function(t){
                 statement: "定额基价材料费"
             },
             {
-                ID: "6",
+                ID: "106",
                 code: "1.3",
                 name: "基价机械费",
                 fieldName: "baseMachine",
@@ -72,7 +72,7 @@ test('解析测试', function(t){
                 statement: "定额基价机械费+定额机上人工单价(基价)调整"
             },
             {
-                ID: "7",
+                ID: "107",
                 code: "1.3.1",
                 name: "定额基价机械费",
                 fieldName: "rationBaseMachine",
@@ -82,7 +82,7 @@ test('解析测试', function(t){
                 statement: "定额基价机械费"
             },
             {
-                ID: "8",
+                ID: "108",
                 code: "1.3.1.1",
                 name: "其中:定额基价机上人工费",
                 fieldName: "rationBaseMachineLabour",
@@ -92,7 +92,7 @@ test('解析测试', function(t){
                 statement: "定额基价机上人工费"
             },
             {
-                ID: "9",
+                ID: "109",
                 code: "1.3.2",
                 name: "定额机上人工单价(基价)调整",
                 fieldName: "rationBaseMachineLabourFixed",
@@ -103,7 +103,7 @@ test('解析测试', function(t){
                 statement: "定额基价机上人工费*[定额机上人工单价(基价)调整系数-1]"
             },
             {
-                ID: "10",
+                ID: "110",
                 code: "1.4",
                 name: "未计价材料费",
                 fieldName: "unPriceMaterial",
@@ -113,7 +113,7 @@ test('解析测试', function(t){
                 statement: "主材费+设备费"
             },
             {
-                ID: "11",
+                ID: "111",
                 code: "2",
                 name: "企业管理费",
                 fieldName: "manageFee",
@@ -125,7 +125,7 @@ test('解析测试', function(t){
                 memo: "渝建发[2014]27号"
             },
             {
-                ID: "12",
+                ID: "112",
                 code: "3",
                 name: "利润",
                 fieldName: "profit",
@@ -136,7 +136,7 @@ test('解析测试', function(t){
                 statement: "定额基价人工费"
             },
             {
-                ID: "13",
+                ID: "113",
                 code: "4",
                 name: "风险因素",
                 fieldName: "risk",
@@ -148,7 +148,7 @@ test('解析测试', function(t){
                 memo: "同定额包干费"
             },
             {
-                ID: "14",
+                ID: "114",
                 code: "5",
                 name: "人材机价差",
                 fieldName: "lmmDiff",
@@ -158,7 +158,7 @@ test('解析测试', function(t){
                 statement: "人工费价差+材料费价差+机械费价差"
             },
             {
-                ID: "15",
+                ID: "115",
                 code: "5.1",
                 name: "人工费价差",
                 fieldName: "labourDiff",
@@ -168,7 +168,7 @@ test('解析测试', function(t){
                 statement: "市场价格人工费-调整后的定额人工费(基价)"
             },
             {
-                ID: "16",
+                ID: "116",
                 code: "5.2",
                 name: "材料费价差",
                 fieldName: "materialDiff",
@@ -178,7 +178,7 @@ test('解析测试', function(t){
                 statement: "市场价格材料费-定额基价材料费"
             },
             {
-                ID: "17",
+                ID: "117",
                 code: "5.3",
                 name: "机械费价差",
                 fieldName: "machineDiff",
@@ -188,7 +188,7 @@ test('解析测试', function(t){
                 statement: "市场价格机械费-调整后的定额基价机械费(基价)"
             },
             {
-                ID: "18",
+                ID: "118",
                 code: "6",
                 name: "综合单价",
                 fieldName: "common",
@@ -199,9 +199,10 @@ test('解析测试', function(t){
             }
         ]
     };
-    let calcItem = {dispExpr: "12 +[人工费]*1.2+f4+ (F6+ f10) +F23+[人工费] + f6+[材料费]"};
-    let target = "12+@('111')*1.2+@('5')+(@('7')+@('11'))+@('24')+@('111')+@('7')+@('222')";
-    analyzer.analyzeUserExpr(calcTemplate, calcItem);
+    let calcItem = {dispExpr: "12 +[人工费]*1.2+f13+ (F6+ f10) +F16+[人工费] + f6+[材料费]"};
+    let target = "12+base('人工费')*1.2+@('113')+(@('106')+@('110'))+@('116')+base('人工费')+@('106')+base('材料费')";
+    let rst = analyzer.analyzeUserExpr(calcTemplate, calcItem);
+    console.log('用户表达式是否正确:' + rst);
     console.log(calcItem.dispExpr);
     console.log(calcItem.expression);
     t.equal(calcItem.expression, target);

+ 4 - 12
web/building_saas/main/html/main.html

@@ -16,8 +16,6 @@
     <link rel="stylesheet" href="/lib/spreadjs/views/gc.spread.views.dataview.10.0.0.css">
     <!-- jquery.contextmenu -->
     <link rel="stylesheet" href="/lib/jquery-contextmenu/jquery.contextMenu.css" type="text/css">
-
-
     <script src="/lib/jquery/jquery.min.js"></script>
     <script src="/web/building_saas/js/global.js"></script>
     <script>
@@ -161,18 +159,12 @@
                               <!-- Tab panes -->
                               <div class="tab-content">
                                   <div class="tab-pane active" id="gl" role="tabpanel">
-                                      <div class="main-data-bottom ovf-hidden" id="subSpread">
+                                      <div class="main-data-bottom ovf-hidden" id="subSpread" style="display: none">
                                       </div>
-                                      <div id="tzjnrCon" class="row" style="display: none">
-                                          <div class="col-6">
-                                              <div class="row">
-                                                  <div class="main-data-bottom ovf-hidden col-5" id="jobSpread">
-                                                  </div>
-                                                  <div class="main-data-bottom ovf-hidden col-7" id="itemSpread">
-                                                  </div>
-                                              </div>
+                                      <div id="tzjnrCon" class="main-data-bottom">
+                                          <div class="main-data-bottom ovf-hidden" style="width: 40%; float: left;" id="jobSpread">
                                           </div>
-                                          <div class="col-6">
+                                          <div class="main-data-bottom ovf-hidden" style="width: 60%; float: left;" id="itemSpread">
                                           </div>
                                       </div>
                                   </div>

+ 7 - 5
web/building_saas/main/js/views/sub_view.js

@@ -3,14 +3,16 @@
  */
 //modified by zhong on 2017-08-30
 // Tab panes 下有多个Spread时,相互之间不能正确显示。改成一个Spread下多个Sheet。
-var subSpread = sheetCommonObj.createSpread($("#subSpread")[0], 7);
-subSpread.getSheet(4).name('JSCX');
-
 //特征及内容spread,解决不能正确显示spread
-$("#jobSpread").width($("#subSpread").width() *0.5* 0.4);
-$("#itemSpread").width($("#subSpread").width() *0.5 - $("#jobSpread").width()-20);
 contentOprObj.buildSheet($("#jobSpread")[0]);
 characterOprObj.buildSheet($("#itemSpread")[0]);
+$("#tzjnrCon").hide();
+$("#subSpread").show();
+
+var subSpread = sheetCommonObj.createSpread($("#subSpread")[0], 7);
+subSpread.getSheet(4).name('JSCX');
+
+
 pageCCOprObj.active = false;
 
 // 工料机

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

@@ -120,9 +120,9 @@
                 <div class="col-lg-10">
                 <div class="toolsbar">
                     <div class="tools-btn btn-group align-top">
-                        <a href="javascript:void(0);" class="btn btn-sm" id="add-project-btn">新建 <i class="fa fa-cubes"></i> 建设项目</a>
-                        <a href="javascript:void(0);" class="btn btn-sm" id="add-engineering-btn">新建 <i class="fa fa-cube"></i> 单项工程</a>
-                        <a href="javascript:void(0);" class="btn btn-sm" id="add-tender-btn">新建 <i class="fa fa-sticky-note-o"></i> 单位工程</a>
+                        <a href="javascript:void(0);" class="btn btn-sm" id="add-project-btn"><i class="fa fa-cubes"></i>&nbsp;新建建设项目</a>
+                        <a href="javascript:void(0);" class="btn btn-sm" id="add-engineering-btn"><i class="fa fa-cube"></i>&nbsp;新建单项工程</a>
+                        <a href="javascript:void(0);" class="btn btn-sm" id="add-tender-btn"><i class="fa fa-sticky-note-o"></i>&nbsp;新建单位工程</a>
                         <a href="javascript:void(0);" class="btn btn-sm" id="add-folder-btn"><i class="fa fa-folder-o"></i>&nbsp;新建文件夹</a>
                         <a href="javascript:void(0);" class="btn btn-sm" id="rename-btn">重命名</a>
                         <a href="javascript:void(0);" class="btn btn-sm" id="del-btn">删除</a>
@@ -247,7 +247,7 @@
     <div class="modal-dialog" role="document">
         <div class="modal-content">
             <div class="modal-header">
-                <h5 class="modal-title">新建 <i class="fa fa-cubes"></i> 建设项目</h5>
+                <h5 class="modal-title"><i class="fa fa-cubes"></i>&nbsp;新建建设项目</h5>
                 <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                     <span aria-hidden="true">&times;</span>
                 </button>
@@ -292,7 +292,7 @@
     <div class="modal-dialog" role="document">
         <div class="modal-content">
             <div class="modal-header">
-                <h5 class="modal-title">新建 <i class="fa fa-cube"></i> 单项工程</h5>
+                <h5 class="modal-title"><i class="fa fa-cube"></i>&nbsp;新建单项工程</h5>
                 <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                     <span aria-hidden="true">&times;</span>
                 </button>
@@ -318,7 +318,7 @@
     <div class="modal-dialog" role="document">
         <div class="modal-content">
             <div class="modal-header">
-                <h5 class="modal-title">新建 <i class="fa fa-sticky-note-o"></i> 单位工程</h5>
+                <h5 class="modal-title"><i class="fa fa-sticky-note-o"></i>&nbsp;新建单位工程</h5>
                 <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                     <span aria-hidden="true">&times;</span>
                 </button>

+ 132 - 47
web/building_saas/pm/js/pm_main.js

@@ -10,6 +10,8 @@ let movetoZTree = null;
 let copytoZTree = null;
 let engineering = [];
 let feeRateData = [];
+let isSaving = false;
+let projectProperty = [];
 let projectType = {
     folder: 'Folder',
     tender: 'Tender',
@@ -166,7 +168,6 @@ $(document).ready(function() {
     $("input[name='valuation_type']").click(function() {
         let type = $(this).val();
         let targetData = type === 'bill' ? JSON.parse(billValuation) : JSON.parse(rationValuation);
-
         let html = '<option value="">请选择计划规则</option>';
 
         for(let valuation of targetData) {
@@ -229,27 +230,9 @@ $(document).ready(function() {
             projectInfo = selectedItem !== null && selectedItem.parent !== undefined ? selectedItem.parent : null;
         }
         if (projectInfo !== null) {
-            let savedProjectData = localStorage.getItem(projectInfo.data.name);
-            console.log(savedProjectData);
-            savedProjectData = JSON.parse(savedProjectData);
-            // 填入计价规则
-            let valuationHtml = '<option value="'+ savedProjectData.valuation +'">'+ savedProjectData.valuationName +'</option>';
-            $("#tender-valuation").html(valuationHtml);
-
-            // 填入工程专业
-            let engineeringHtml = getEngineeringHtml(savedProjectData.engineeringList);
-            $("#tender-engineering").html(engineeringHtml);
-
-            $("input[name='tender_valuation_type']").attr('disabled', 'disabled').removeAttr('checked', 'checked');
-            $("input[name='tender_valuation_type'][value='"+ savedProjectData.valuationType +"']")
-                .attr("checked", "checked").removeAttr('disabled', 'disabled');
-
-            // 填入费率文件
-            let feeHtml = '<option>请选择费率文件</option>';
-            // for (let fee of savedProjectData.feeLib) {
-            //     feeHtml += '<option value="'+ fee.id +'">'+ fee.name +'</option>';
-            // }
-            $("#tender-fee-rate").html(feeHtml);
+            let parentID = projectInfo.data.ID;
+            // 获取当前的数据属性
+            getProperty(parentID);
         }
 
     });
@@ -402,7 +385,7 @@ $(document).ready(function() {
                 updateType: 'update',
                 projectType: null
             };
-            updateData = GetUpdateData(parent, next, '', Tree.selected().id(), typeInfo);
+            updateData = GetUpdateData(parent, next, '', null, Tree.selected().id(), typeInfo);
             UpdateProjectData(updateData, function (data) {
                 dialog.modal('hide');
                 Tree.move(Tree.selected(), parent, next);
@@ -466,7 +449,7 @@ $(document).ready(function() {
                     updateType: 'copy',
                     projType: cur.data.projectType
                 };
-                let updateData = GetUpdateData(parent, next, cur.data.name, IDs.lowID, typeInfo);
+                let updateData = GetUpdateData(parent, next, cur.data.name, cur.data.property, IDs.lowID, typeInfo);
                 updateData['srcProjectId'] = cur.id();
                 pre = GetNeedUpdatePreNode(parent, next);
                 if (pre) {
@@ -490,6 +473,34 @@ $(document).ready(function() {
             });
         }
     });
+
+    // 选择工程专业后动态更改费率文件等数据
+    $("#tender-engineering").change(function() {
+        if (projectProperty.engineeringList === undefined || projectProperty.engineeringList.length <= 0) {
+            return false;
+        }
+        let selectedEngineering = $(this).val();
+        selectedEngineering = parseInt(selectedEngineering);
+        let currentLib = {};
+        for(let engineering of projectProperty.engineeringList) {
+            if (engineering.engineering === selectedEngineering) {
+                currentLib = engineering.lib;
+            }
+        }
+
+        if (Object.keys(currentLib).length <= 0) {
+            return false;
+        }
+        // 输出数据到页面
+        let feeHtml = '<option>请选择费率文件</option>';
+        if (currentLib.fee_lib !== undefined && currentLib.fee_lib.length > 0) {
+            for (let fee of currentLib.fee_lib) {
+                feeHtml += '<option value="'+ fee.id +'">'+ fee.name +'</option>';
+            }
+        }
+        $("#tender-fee-rate").html(feeHtml);
+
+    });
 });
 
 /**
@@ -540,24 +551,26 @@ function AddProject() {
             break;
         }
     }
+    let projectInfo = {
+        valuation: valuation,
+        valuationType: valuationType,
+        valuationName: valuationName,
+        engineeringList: engineeringList
+    };
 
     let callback = function() {
         $("#add-project-dialog").modal("hide");
-        // 记录选择后的信息
-        let projectInfo = {
-            valuation: valuation,
-            valuationType: valuationType,
-            valuationName: valuationName,
-            engineeringList: engineeringList,
-        };
-        localStorage.setItem(name, JSON.stringify(projectInfo));
+        $("#project-name").val('');
+        $("input[name='valuation_type']").removeAttr('checked');
+        $("#valuation").children("option").not(":eq(0)").remove();
     };
     let selectedItem = Tree.selected();
+
     // 如果选择的是建设项目则新增同级数据
     if (selectedItem !== null && selectedItem.data.projType === projectType.project) {
-        AddSiblingsItem(name, projectType.project, callback);
+        AddSiblingsItem(name, projectInfo, projectType.project, callback);
     } else {
-        AddChildrenItem(name, projectType.project, callback);
+        AddChildrenItem(name, projectInfo, projectType.project, callback);
     }
 }
 
@@ -569,7 +582,7 @@ function AddProject() {
  * @param {function} callback
  * @return {void}
  */
-function AddChildrenItem(name, type, callback) {
+function AddChildrenItem(name, property, type, callback) {
     let parent = Tree.selected() ? Tree.selected() : Tree._root;
     let next = Tree.selected() ? Tree.selected().firstChild() : Tree.firstNode();
     GetNewProjectId(function(IDs) {
@@ -577,7 +590,7 @@ function AddChildrenItem(name, type, callback) {
             updateType: 'new',
             projectType: type
         };
-        let updateData = GetUpdateData(parent, next, name, IDs.lowID, typeInfo);
+        let updateData = GetUpdateData(parent, next, name, property, IDs.lowID, typeInfo);
         Tree.maxNodeId(IDs.lowID - 1);
         UpdateProjectData(updateData, function(datas){
             datas.forEach(function (data) {
@@ -598,7 +611,7 @@ function AddChildrenItem(name, type, callback) {
  * @param {function} callback
  * @return {void}
  */
-function AddSiblingsItem(name, type, callback) {
+function AddSiblingsItem(name, property, type, callback) {
     let selected = Tree.selected();
     let parent = selected ? selected.parent : Tree._root;
     let next = selected ? selected.nextSibling : Tree.firstNode();
@@ -607,7 +620,7 @@ function AddSiblingsItem(name, type, callback) {
             updateType: 'new',
             projectType: type
         };
-        let updateData = GetUpdateData(parent, next, name, IDs.lowID, typeInfo);
+        let updateData = GetUpdateData(parent, next, name, property, IDs.lowID, typeInfo);
         Tree.maxNodeId(IDs.lowID - 1);
         UpdateProjectData(updateData, function(datas){
             datas.forEach(function (data) {
@@ -633,13 +646,14 @@ function AddEngineering() {
     }
     let callback = function() {
         $("#add-engineering-dialog").modal("hide");
+        $("#engineering-name").val('');
     };
     let selectedItem = Tree.selected();
     // 如果选择的是单项工程则新增同级数据
     if (selectedItem !== null && selectedItem.data.projType === projectType.engineering) {
-        AddSiblingsItem(name, projectType.engineering, callback);
+        AddSiblingsItem(name, null, projectType.engineering, callback);
     } else {
-        AddChildrenItem(name, projectType.engineering, callback);
+        AddChildrenItem(name, null, projectType.engineering, callback);
     }
 }
 
@@ -654,15 +668,32 @@ function AddTender() {
         alert('请填写单位工程名称');
         return false;
     }
+
+    let valuation = $("#tender-valuation").val();
+    let valuationName = $("#tender-valuation").children("option:selected").text();
+    let valuationType = $("input[name='tender_valuation_type']:checked").val();
+    let engineering = $("#tender-engineering").val();
+    let engineeringName = $('#tender-engineering').children("option:selected").text();
+
     let callback = function() {
         $("#add-tender-dialog").modal("hide");
+        $('#tender-name').val('');
+        $("#tender-fee-rate").children("option").removeAttr("selected");
+        $("#tender-engineering").children("option").removeAttr("selected");
     };
     let selectedItem = Tree.selected();
+    let tenderInfo = {
+        valuation: valuation,
+        valuationType: valuationType,
+        valuationName: valuationName,
+        engineering: engineering,
+        engineeringName: engineeringName
+    };
     // 如果选择的是单项工程则新增同级数据
     if (selectedItem !== null && selectedItem.data.projType === projectType.tender) {
-        AddSiblingsItem(name, projectType.tender, callback);
+        AddSiblingsItem(name, tenderInfo, projectType.tender, callback);
     } else {
-        AddChildrenItem(name, projectType.tender, callback);
+        AddChildrenItem(name, tenderInfo, projectType.tender, callback);
     }
 }
 
@@ -686,11 +717,11 @@ function AddFolder() {
             alert("文件夹不能超过3层");
             return false;
         }
-        AddChildrenItem(name, projectType.folder, function() {
+        AddChildrenItem(name, null, projectType.folder, function() {
             $("#add-folder-dialog").modal("hide");
         });
     } else {
-        AddSiblingsItem(name, projectType.folder, function() {
+        AddSiblingsItem(name, null, projectType.folder, function() {
             $("#add-folder-dialog").modal("hide");
         });
     }
@@ -705,7 +736,7 @@ function AddFolder() {
  * @param {Object} type
  * @return {Object}
  */
-function GetUpdateData(parent, next, name, newId, type) {
+function GetUpdateData(parent, next, name, property, newId, type) {
     let data = [];
     let updateData = {};
     updateData['updateType'] = type.updateType === undefined ? 'new' : type.updateType;
@@ -718,6 +749,9 @@ function GetUpdateData(parent, next, name, newId, type) {
     if (name !== '') {
         updateData['updateData']['name'] = name;
     }
+    if (property !== undefined) {
+        updateData['updateData']['property'] = property;
+    }
     if (type !== null && type.projectType !== null) {
         updateData['updateData']['projType'] = type.projectType !== undefined ? type.projectType : 'Tender';
     }
@@ -897,7 +931,7 @@ function GetTargetTreeNode(zTreeObj) {
  */
 function getEngineeringHtml(engineeringList) {
     let result = '<option>请选择对应的工程专业</option>';
-    if (engineeringList.length <= 0) {
+    if (Object.keys(engineeringList).length <= 0) {
         return result;
     }
     let engineeringObject = {};
@@ -907,9 +941,60 @@ function getEngineeringHtml(engineeringList) {
 
     for(let tmp of engineeringList) {
         if (engineeringObject[tmp.engineering] !== undefined) {
-            result += '<option value="'+ tmp.engineering_id +'">'+ engineeringObject[tmp.engineering] +'</option>';
+            result += '<option value="'+ tmp.engineering +'">'+ engineeringObject[tmp.engineering] +'</option>';
         }
     }
 
     return result;
 }
+
+/**
+ * 远程获取项目属性数据
+ *
+ * @param {Number} id
+ * @return {Object}
+ */
+function getProperty(id) {
+    if (isSaving) {
+        return false;
+    }
+    id = parseInt(id);
+    if (isNaN(id) || id <= 0) {
+        return {};
+    }
+
+    $.ajax({
+        url: '/pm/api/getProjectProperty',
+        type: 'post',
+        data: {data: JSON.stringify({user_id: userID, id: id})},
+        dataType: 'json',
+        timeout: 5000,
+        error: function() {
+            isSaving = false;
+            alert('操作失败!');
+        },
+        beforeSend: function() {
+            isSaving = true;
+        },
+        success: function(response) {
+            if (response.error === 0) {
+                projectProperty = response.data;
+                // 写入专业工程相关
+                let engineeringHtml = getEngineeringHtml(projectProperty.engineeringList);
+                $("#tender-engineering").html(engineeringHtml);
+
+                // 填入计价规则
+                let valuationHtml = '<option value="'+ projectProperty.valuation +'">'+ projectProperty.valuationName +'</option>';
+                $("#tender-valuation").html(valuationHtml);
+
+                // 选中计价方式
+                $("input[name='tender_valuation_type']").attr('disabled', 'disabled').removeAttr('checked', 'checked');
+                $("input[name='tender_valuation_type'][value='"+ projectProperty.valuationType +"']")
+                    .attr("checked", "checked").removeAttr('disabled', 'disabled');
+
+            } else {
+                alert(response.message);
+            }
+        }
+    });
+}