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

必填信息相关

zhongzewei 6 éve
szülő
commit
fc489de4be

+ 25 - 0
modules/all_models/basic_info_lib.js

@@ -0,0 +1,25 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2019/3/5
+ * @version
+ */
+//建设项目基本信息库
+const mongoose = require('mongoose');
+const Schema = mongoose.Schema;
+const oprSchema = require('../all_schemas/opr_schema');
+const basicInfoLib = new Schema({
+    ID: {type: String, index: true},
+    name: String,
+    creator: String,
+    createDate: Number,
+    recentOpr: [oprSchema],
+    info: {
+        type: Schema.Types.Mixed,
+        default: []
+    }
+});
+mongoose.model('std_basic_info_lib', basicInfoLib, 'std_basic_info_lib');

+ 5 - 0
modules/all_models/engineering_lib.js

@@ -57,6 +57,11 @@ let modelSchema = {
         type: Schema.Types.Mixed,
         default: []
     },
+    //基本信息库
+    info_lib: {
+        type: Schema.Types.Mixed,
+        default: []
+    },
     //设置人材机显示列
     glj_col:{
         showAdjustPrice:Boolean//是否显示调整价列

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

@@ -650,5 +650,33 @@ module.exports = {
             console.log(err);
             callback(req, res, 1, err, null);
         }
+    },
+    getBasicInfo: async function(req, res) {
+        try {
+            let infoLib = await pm_facade.getBasicInfo(req.session.sessionCompilation._id);
+            callback(req, res, 0, 'success', infoLib ? infoLib.info : []);
+        } catch (err) {
+            console.log(err);
+            callback(req, res, 1, err, []);
+        }
+    },
+    getProjectFeature: async function(req, res) {
+        try {
+            let data = JSON.parse(req.body.data);
+            let featureLib = await pm_facade.getProjectFeature(data.valuationID, data.engineeringName, data.feeName);
+            //工程专业设置为费用标准名称
+            if (featureLib) {
+                let engData = featureLib.feature.find(function (d) {
+                    return d.key === 'engineering';
+                });
+                if (engData) {
+                    engData.value = data.feeName;
+                }
+            }
+            callback(req, res, 0, 'success', featureLib ? featureLib.feature : []);
+        } catch (err) {
+            console.log(err);
+            callback(req, res, 1, err, []);
+        }
     }
 };

+ 37 - 12
modules/pm/facade/pm_facade.js

@@ -17,7 +17,6 @@ module.exports={
     getTendersFeeInfo: getTendersFeeInfo,
     getConstructionProject: getConstructionProject,
     getFullPath: getFullPath,
-    getProjectFeature:getProjectFeature,
     projectType: projectType,
     getPosterityProjects: getPosterityProjects,
     isShare: isShare,
@@ -25,6 +24,8 @@ module.exports={
     getShareInfo: getShareInfo,
     prepareInitialData: prepareInitialData,
     changeFile:changeFile,
+    getBasicInfo: getBasicInfo,
+    getProjectFeature: getProjectFeature
 };
 
 
@@ -57,6 +58,10 @@ let rationTemplateModel = mongoose.model('ration_template');
 let userModel = mongoose.model('user');
 let compleGljSectionModel = mongoose.model('complementary_glj_section');
 let compleGljSectionTModel = mongoose.model('complementary_glj_section_templates');
+let compilationModel = mongoose.model('compilation');
+let engineeringModel = mongoose.model('engineering_lib');
+let basicInfoModel = mongoose.model('std_basic_info_lib');
+let projectFeatureModel = mongoose.model('std_project_feature_lib');
 
 let featureLibModel =  mongoose.model("std_project_feature_lib");
 let scMathUtil = require('../../../public/scMathUtil').getUtil();
@@ -876,17 +881,6 @@ async function getFullPath(projectID) {
     }
 }
 
-async function getProjectFeature(libID,feeStandardName){
-    let lib = await featureLibModel.findOne({'ID':libID})
-    if(lib){
-        let eng = _.find(lib.feature,{'key':'engineering'})
-        if(eng) eng.value = feeStandardName;
-        return lib.feature;
-    }else {
-        return [];
-    }
-}
-
 //获取projectIDs文件下所有子项目(不包括projectIDs本身)
 async function getPosterityProjects(projectIDs) {
     let rst = [];
@@ -1025,4 +1019,35 @@ async function changeFile(datas,userID,fileID,name,from,type){//from 费率或
     }
     await project_facade.markProjectsToChange(projectIDs,projectUpdateType)//项目标记为待刷新状态
 
+}
+
+async function getBasicInfo(compilationID) {
+    let compilation = await compilationModel.findOne({_id: mongoose.Types.ObjectId(compilationID)});
+    if (!compilation) {
+        return null;
+    }
+    let billValuation = compilation.bill_valuation.find(function (data) {
+        return data.enable;
+    });
+    if (!billValuation) {
+        return null;
+    }
+    let engineerings = await engineeringModel.find({valuationID: billValuation.id});
+    let engineering = engineerings.find(function (data) {
+        return data.info_lib && data.info_lib.length > 0;
+    });
+    if (!engineering || !engineering.info_lib || !engineering.info_lib[0]) {
+        return null;
+    }
+    let infoLib = await basicInfoModel.findOne({ID: engineering.info_lib[0].id});
+    return infoLib;
+}
+
+async function getProjectFeature(valuationID, engineeringName, feeName) {
+    let engineering = await engineeringModel.findOne({valuationID: valuationID, name: engineeringName, feeName: feeName});
+    if (!engineering || !engineering.feature_lib || !engineering.feature_lib[0]) {
+        return null;
+    }
+    let featureLib = await projectFeatureModel.findOne({ID: engineering.feature_lib[0].id});
+    return featureLib;
 }

+ 2 - 13
modules/pm/models/project_model.js

@@ -138,10 +138,10 @@ ProjectsDAO.prototype.updateUserProjects = async function (userId, compilationId
                 data.updateData['compilation'] = compilationId;
                 data.updateData['createDateTime'] = new Date();
                 data.updateData['fileVer'] = G_FILE_VER;
-                if(data.updateData.projType === projectType.project){
+                /*if(data.updateData.projType === projectType.project){
                     //设置建设项目基本信息,多个单位工程共用
                     data.updateData.property = {basicInformation: basicInformation};
-                }
+                }*/
                 // 如果没有选中单价文件则新增单价文件
                 if (data.updateData.projType === projectType.tender && data.updateData.property !== null &&
                     Object.keys(data.updateData.property.unitPriceFile).length > 0 &&
@@ -168,17 +168,6 @@ ProjectsDAO.prototype.updateUserProjects = async function (userId, compilationId
                     data.updateData.property.decimal = defaultDecimal;
                     //清单工程量精度
                     data.updateData.property.billsQuantityDecimal = billsQuantityDecimal;
-                    //基本信息-挪到建设项目下,多个单位工程共用
-                    //basicInformation[0]['items'][1]['value'] = data.updateData.property.engineeringName || '';
-                    //data.updateData.property.basicInformation = basicInformation;
-                    //工程特征
-                    if(data.updateData.property.featureLibID){
-                        //工程专业显示费用定额的名称
-                        data.updateData.property.projectFeature = await pmFacade.getProjectFeature(data.updateData.property.featureLibID, data.updateData.property.feeStandardName);
-                    }
-                    /*projectFeature[0]['value'] = data.updateData.property.engineeringName || '';
-                    data.updateData.property.projectFeature = projectFeature;*/
-
                     //呈现选项
                     data.updateData.property.displaySetting = displaySetting;
 

+ 0 - 1
modules/pm/models/project_property_template.js

@@ -80,7 +80,6 @@ const billsQuantityDecimal = [
 const basicInformation = [
     {dispName: '基本信息', key: 'basicInfo', items: [
         {dispName: '合同号', key: 'contractNum', value: ''},
-       // {dispName: '工程专业', key: 'engineering', value: ''},//只读,用户新建单位工程时选择的值
         {dispName: '建设地点', key: 'constructionPlace', value: ''},
         {dispName: '质量标准', key: 'qualityStandard', value: ''},
         {dispName: '工程类别', key: 'projectCategory', value: ''},

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

@@ -61,7 +61,8 @@ module.exports = function (app) {
     pmRouter.post('/share', pmController.share);
     pmRouter.post('/receiveProjects', pmController.receiveProjects);
     pmRouter.post('/changeFile', pmController.changeFile);
-
+    pmRouter.post('/getBasicInfo', pmController.getBasicInfo);
+    pmRouter.post('/getProjectFeature', pmController.getProjectFeature);
     app.use('/pm/api', pmRouter);
 };
 

+ 47 - 23
web/building_saas/main/js/views/project_property_basicInfo.js

@@ -19,10 +19,10 @@ let basicInfoView = {
             allowUserDragFill: false,
             scrollbarMaxAlign : true
         },
-        dateRows: [5, 18],
-        numRows: [7],
+        dateRows: [],
+        numRows: [],
         locked: {
-            rows: [0, 19, 23, 27],
+            rows: [],
             cols: [0]
         }
     },
@@ -70,6 +70,8 @@ let basicInfoView = {
             for(let i = 0, len = headers.length; i < len; i++){
                 sheet.setValue(0, i, headers[i].name, GC.Spread.Sheets.SheetArea.colHeader);
                 sheet.setColumnWidth(i, headers[i].width, GC.Spread.Sheets.SheetArea.colHeader);
+                sheet.getRange(-1, i, -1, 1).hAlign(GC.Spread.Sheets.HorizontalAlign[headers[i]['hAlign']]);
+                sheet.getRange(-1, i, -1, 1).vAlign(GC.Spread.Sheets.VerticalAlign[headers[i]['vAlign']]);
             }
         };
         me.renderSheetFuc(sheet, fuc);
@@ -91,6 +93,7 @@ let basicInfoView = {
         let sheet = workBook.getActiveSheet();
         sheet.bind(_events.EditStarting, this.onEditStarting);
         sheet.bind(_events.EditEnded, this.onEditEnded);
+        sheet.bind(_events.EnterCell, this.onEnterCell);
         sheet.bind(_events.ClipboardPasting, this.onClipboardPasting);
         sheet.bind(_events.ClipboardPasted, this.onClipboardPasted);
     },
@@ -102,15 +105,28 @@ let basicInfoView = {
         let fuc = function () {
             sheet.setRowCount(datas.length);
             me.initTree(sheet, true, datas);
-            me.setDatePicker(sheet, me.setting.dateRows);
             sheet.setFormatter(-1, 1, '@');
-            for(let col = 0, cLen = cols.length; col < cLen; col++){
-                sheet.getRange(-1, col, -1, 1).hAlign(GC.Spread.Sheets.HorizontalAlign[cols[col]['hAlign']]);
-                sheet.getRange(-1, col, -1, 1).vAlign(GC.Spread.Sheets.VerticalAlign[cols[col]['vAlign']]);
-                for(let row = 0, rLen = datas.length; row < rLen; row++){
+            //兼容旧数据,旧数据可能没有设置cellType
+            let compatNumKeys = ['grossArea'],
+                compatDateKeys = ['constructionDate', 'establishDate'];
+            for(let row = 0;row < datas.length ; row ++){
+                if(datas[row].cellType == 'number' || compatNumKeys.includes(datas[row].key)){
+                    me.setting.numRows.push(row);
+                } else if (datas[row].cellType === 'date' || compatDateKeys.includes(datas[row].key)) {
+                    me.setting.dateRows.push(row);
+                } else if(datas[row].cellType === 'comboBox'){
+                    let options = datas[row].options ? datas[row].options.split("@") : [];
+                    projFeatureView.setCombo(sheet, row, options);
+                }
+                let readOnly = typeof datas[row].readOnly === 'string' ? JSON.parse(datas[row].readOnly) : datas[row].readOnly;
+                if (readOnly || datas[row].items) {
+                    me.setting.locked.rows.push(row);
+                }
+                for(let col = 0;col < cols.length;col++){
                     sheet.setValue(row, col, datas[row][cols[col]['dataCode']]);
                 }
             }
+            me.setDatePicker(sheet, me.setting.dateRows);
         };
         this.renderSheetFuc(sheet, fuc);
     },
@@ -120,8 +136,7 @@ let basicInfoView = {
         if(args.col === 0){
             args.cancel = true;
         }
-        //工程专业
-        if(args.col === 1 && me.setting.locked.rows.indexOf(args.row) !== -1){
+        if(me.setting.locked.rows.indexOf(args.row) !== -1){
             args.cancel = true;
         }
     },
@@ -130,8 +145,12 @@ let basicInfoView = {
         let me = basicInfoView;
         let v =  args.editingText ? args.editingText.toString().trim() : '';
         if(args.row < me.datas.length){
+            let required = typeof me.datas[args.row].required === 'string' ? JSON.parse(me.datas[args.row].required) : me.datas[args.row].required;
             //date
-            if(me.setting.dateRows.indexOf(args.row) !== -1){
+            if (required && !v) {
+                v = me.datas[args.row].value;
+                args.sheet.setValue(args.row, args.col, v);
+            } else if(me.setting.dateRows.indexOf(args.row) !== -1){
                 if(v.length > 0){
                     v = formatDate(new Date(v), 'yyyy-MM-dd');
                     v = me.filtDate(v);
@@ -141,8 +160,7 @@ let basicInfoView = {
                         return;
                     }
                 }
-            }
-            else if(me.setting.numRows.indexOf(args.row) !== -1){//控制数值
+            } else if(me.setting.numRows.indexOf(args.row) !== -1){//控制数值
                 if(!me.isNum(v)){
                     alert('只能输入数值');
                     v = me.datas[args.row].value && me.isNum(me.datas[args.row].value) ? me.datas[args.row].value : '';
@@ -153,6 +171,10 @@ let basicInfoView = {
         }
     },
 
+    onEnterCell: function (sender, args) {
+        args.sheet.repaint();
+    },
+
     onClipboardPasting: function (sender, args) {
         let me = basicInfoView;
         if(args.cellRange.col === 0){
@@ -166,23 +188,25 @@ let basicInfoView = {
         let recRows = [];
         for(let i = 0, len = items.length; i < len; i++){
             let row = i + args.cellRange.row;
+            let comboItems = projFeatureView.getComboItemsByRow.call(me, row);
+            let required = typeof me.datas[row].required === 'string' ? JSON.parse(me.datas[row].required) : me.datas[row].required;
             if(me.setting.locked.rows.indexOf(row) !== -1){
                 recRows.push(row);
-            }
-            else if(me.setting.dateRows.indexOf(row) !== -1){
+            } else if(comboItems && !comboItems.includes(items[i].value)){//粘贴下拉框数据过滤
+                recRows.push(row);
+            } else if(me.setting.dateRows.indexOf(row) !== -1){
                 items[i].value = me.filtDate(items[i].value);
                 if(!me.isDef(items[i].value)){
                     recRows.push(row);
-                }
-                else {
+                } else {
                     me.datas[row].value = items[i].value;
                 }
-            }
-            else if(me.setting.numRows.indexOf(row) !== -1 && !me.isNum(items[i].value)){
+            } else if(me.setting.numRows.indexOf(row) !== -1 && !me.isNum(items[i].value)){
                 recRows.push(row);
-            }
-            else {
-                me.datas[row].value = items[i].value;
+            } else if (required && !items[i].value) {
+                recRows.push(row);
+            } else
+                {me.datas[row].value = items[i].value;
             }
         }
         if(recRows.length > 0){
@@ -191,7 +215,7 @@ let basicInfoView = {
                     let staticV = me.datas[recRows[i]].value || '';
                     args.sheet.setValue(recRows[i], args.cellRange.col, staticV);
                 }
-            })
+            });
         }
     },
 

+ 69 - 20
web/building_saas/main/js/views/project_property_projFeature.js

@@ -20,10 +20,10 @@ let projFeatureView = {
             allowUserDragFill: false,
             scrollbarMaxAlign : true
         },
-        numRows: [],//6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+        numRows: [],
         dateRows: [],
         locked: {
-            rows: [0, 1],
+            rows: [],
             cols: [0]
         }
     },
@@ -50,12 +50,14 @@ let projFeatureView = {
     },
 
     getComboItemsByRow: function (row) {
-        for(let i = 0, len = this.setting.combos.length; i < len; i++){
-            if(this.setting.combos[i].row === row){
-                return this.setting.combos[i].items;
-            }
+        let data = this.datas[row];
+        if (!data) {
+            return null;
         }
-        return null;
+        if (!data.cellType || data.cellType !== 'comboBox') {
+            return null;
+        }
+        return data.options ? data.options.split('@') : [];
     },
 
     buildHeader: function (sheet, headers) {
@@ -104,17 +106,38 @@ let projFeatureView = {
             sheet.setRowCount(datas.length);
             me.initTree(sheet, true, datas);
             sheet.setFormatter(-1, 1, '@');
-           for(let row = 0;row < datas.length ; row ++){
-               if(datas[row].cellType == 'comboBox'){
-                   let options = datas[row].options?datas[row].options.split("@"):[];
-                   me.setCombo(sheet, row, options);
-               }else if(datas[row].cellType == 'number'){
-                   me.setting.numRows.push(row);
-               }
-               for(let col = 0;col < cols.length;col++){
-                   sheet.setValue(row, col, datas[row][cols[col]['dataCode']]);
-               }
-           }
+            //兼容旧数据
+            let compatLockedKeys = ['engineering'],
+                compatNumKeys = [
+                    'buildingArea',
+                    'basementBuildingArea',
+                    'totalFloors',
+                    'basementFloors',
+                    'buildingFloors',
+                    'buildingHeight',
+                    'basementHeight',
+                    'firstFloorHeight',
+                    'podiumBuildingHeight',
+                    'standardFloorHeight'
+                ];
+            for(let row = 0;row < datas.length ; row ++){
+                if(datas[row].cellType == 'comboBox'){
+                    let options = datas[row].options?datas[row].options.split("@"):[];
+                    me.setCombo(sheet, row, options);
+                } else if(datas[row].cellType == 'number' || compatNumKeys.includes(datas[row].key)){
+                    me.setting.numRows.push(row);
+                } else if (datas[row].cellType === 'date') {
+                    me.setting.dateRows.push(row);
+                }
+                let readOnly = typeof datas[row].readOnly === 'string' ? JSON.parse(datas[row].readOnly) : datas[row].readOnly;
+                if (readOnly || datas[row].items || compatLockedKeys.includes(datas[row].key)) {
+                    me.setting.locked.rows.push(row);
+                }
+                for(let col = 0;col < cols.length;col++){
+                    sheet.setValue(row, col, datas[row][cols[col]['dataCode']]);
+                }
+            }
+            basicInfoView.setDatePicker(sheet, me.setting.dateRows);
         };
         this.renderSheetFuc(sheet, fuc);
     },
@@ -133,12 +156,26 @@ let projFeatureView = {
         let me = projFeatureView;
         let v =  args.editingText ? args.editingText.toString().trim() : '';
         if(args.row < me.datas.length){
-            if(me.setting.numRows.indexOf(args.row) !== -1){//控制数值
+            let required = typeof me.datas[args.row].required === 'string' ? JSON.parse(me.datas[args.row].required) : me.datas[args.row].required;
+            if (required && !v) {
+                v = me.datas[args.row].value;
+                args.sheet.setValue(args.row, args.col, v);
+            } else if(me.setting.numRows.indexOf(args.row) !== -1){//控制数值
                 if(!me.isNum(v)){
                     alert('只能输入数值');
                     v = me.datas[args.row].value && me.isNum(me.datas[args.row].value) ? me.datas[args.row].value : '';
                     args.sheet.setValue(args.row, args.col, v);
                 }
+            } else if(me.setting.dateRows.indexOf(args.row) !== -1){
+                if(v.length > 0){
+                    v = formatDate(new Date(v), 'yyyy-MM-dd');
+                    v = basicInfoView.filtDate(v);
+                    if(!v){
+                        alert('请输入正确的日期格式yyyy-mm-dd');
+                        args.sheet.setValue(args.row, args.col, me.datas[args.row].value ? me.datas[args.row].value : '');
+                        return;
+                    }
+                }
             }
             me.datas[args.row].value = v;
         }
@@ -165,16 +202,28 @@ let projFeatureView = {
         for(let i = 0, len = items.length; i < len; i++){
             let row = i + args.cellRange.row;
             let comboItems = me.getComboItemsByRow(row);
+            let required = typeof me.datas[row].required === 'string' ? JSON.parse(me.datas[row].required) : me.datas[row].required;
             if(me.setting.locked.rows.indexOf(row) !== -1){
                 recRows.push(row);
             }
+            else if (required && !items[i].value) {
+                recRows.push(row);
+            }
             //粘贴下拉框数据过滤
-            else if(comboItems && comboItems.indexOf(items[i].value) !== -1){
+            else if(comboItems && !comboItems.includes(items[i].value)){
                 recRows.push(row);
             }
             else if(me.setting.numRows.indexOf(row) !== -1 && !me.isNum(items[i].value)){
                 recRows.push(row);
             }
+            else if(me.setting.dateRows.indexOf(row) !== -1){
+                items[i].value = basicInfoView.filtDate(items[i].value);
+                if(!me.isDef(items[i].value)){
+                    recRows.push(row);
+                } else {
+                    me.datas[row].value = items[i].value;
+                }
+            }
             else {
                 me.datas[row].value = items[i].value;
             }

+ 11 - 4
web/building_saas/pm/html/project-management.html

@@ -225,16 +225,20 @@
                 </button>
             </div>
             <div class="modal-body">
-                <form>
+                <form id="projFirstStep">
                     <div class="form-group">
                         <label>建设项目</label>
                         <input type="text" class="form-control" placeholder="输入建设项目名称" id="project-name">
                         <span class="form-text text-danger" id="project-name-info" style="display: none;">已存在 “建筑工程1”</span>
                     </div>
                 </form>
+                <form id="projInfoStep" class="hidden-area"></form>
+                <p id="project-required-warn" class="text-muted hidden-area"><i class="fa fa-warning text-warning"></i> 注:为响应重庆地区指标采集标准数据要求,以上工程信息及特征必填项为必填项,请正确填写。</p>
             </div>
             <div class="modal-footer">
-                <a href="javascript:void(0);" class="btn btn-primary" id="addProjOk">确定</a>
+                <a href="javascript:void(0);" class="btn btn-primary hidden-area" id="add-proj-prev">上一步</a>
+                <a href="javascript:void(0);" class="btn btn-primary" id="add-proj-next">下一步</a>
+                <a href="javascript:void(0);" class="btn btn-primary hidden-area" id="addProjOk">确定</a>
                 <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
             </div>
         </div>
@@ -272,7 +276,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" id="add-tender-title"><i class="fa fa-sticky-note-o"></i>新建单位工程</h5>
                 <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                     <span aria-hidden="true">&times;</span>
                 </button>
@@ -397,10 +401,13 @@
                     </div>
                     <span class="form-text text-danger" id="calcProgram-info" style="display: none;">请选择计算程序</span>
                 </form>
+                <form id="infoStep" style="display: none"></form>
+                <form id="featureStep" style="display: none"></form>
+                <p id="tender-required-warn" class="text-muted hidden-area"><i class="fa fa-warning text-warning"></i> 注:为响应重庆地区指标采集标准数据要求,以上工程信息及特征必填项为必填项,请正确填写。</p>
             </div>
             <div class="modal-footer">
-                <a href="javascript:void(0);" class="btn btn-primary" id="add-tender-next">下一步</a>
                 <a href="javascript:void(0);" class="btn btn-primary" id="add-tender-prev" style="display: none">上一步</a>
+                <a href="javascript:void(0);" class="btn btn-primary" id="add-tender-next">下一步</a>
                 <a href="javascript:void(0);" class="btn btn-primary" style="display: none" id="add-tender-confirm">确定</a>
                 <button type="button" class="btn btn-secondary" data-dismiss="modal" id="add-tender-cancel" style="display: none;">取消</button>
             </div>

+ 383 - 119
web/building_saas/pm/js/pm_newMain.js

@@ -50,7 +50,7 @@ function delayKeyup(callback) {
         }
     }, delayTime);
 }
-
+const addPath = {p_e_t: 'p_e_t', e_t: 'e_t', t: 't'};
 const projTreeObj = {
     tree: null,
     workBook: null,
@@ -1525,7 +1525,6 @@ const projTreeObj = {
         this.refreshProjectData(projectID);
     }
 };
-
 $(document).ready(function() {
     $('#sideTab').find('li').click(function () {
        //消除tooltip
@@ -1575,26 +1574,122 @@ $(document).ready(function() {
             });
         }
     });
+
     //绑定新建建设项目、新建单项工程、新建文件夹、重命名Enter键事件
     bindInputs($('#project-name'), $('#engineering-name'), $('#folder-name'), $('#rename-name'));
 
     //绑定新建建设项目、新建单项工程、新建文件夹、重命名弹窗隐藏事件
     bindModalsHidden($('#add-project-dialog'), $('#add-engineering-dialog'), $('#add-folder-dialog'), $('#rename-dialog'));
 
-    // 新增建设项目点击
-    /*$('#add-project-btn').click(function () {
-        let selectedItem = projTreeObj.tree.selected;
-        $('#add-project-dialog').modal('show');
-        setTimeout(function () {
-            $('#project-name')[0].focus();
-        }, 300);
-    });*/
-
     // 新增建设项目操作
     $('#addProjOk').click(function () {
+        if (!validRequiredData($('#projInfoStep'))) {
+            return;
+        }
+        if (infoData && Array.isArray(infoData)) {
+            updateRequiredData($('#projInfoStep'), infoData);
+        }
         AddProject();
     });
+    //新建建设项目-下一步
+    $('#add-proj-next').click(function () {
+        let name = $('#project-name').val().trim();
+        if (!name) {
+            setDangerInfo($('#project-name-info'), '请填写建设项目名称');
+            return false;
+        }
+        if (!validProjectName(name)) {
+            setDangerInfo($('#project-name-info'), `已存在“${name}”`);
+            return false;
+        }
+        //建设项目基本信息
+        showProjInfoStep();
+    });
+    //新建建设项目-上一步
+    $('#add-proj-prev').click(function () {
+        setDangerInfo($('#project-name-info'), '', false);
+        showProjFirstStep();
+    });
+    //显示新建建设项目第一步内容
+    function showProjFirstStep() {
+        $('#add-project-dialog').find('.modal-title').html('<i class="fa fa-cubes"></i> 新建建设项目');
+        $('#projInfoStep').hide();
+        $('#addProjOk').hide();
+        $('#project-required-warn').hide();
+        $('#add-proj-prev').hide();
+        $('#add-proj-next').show();
+        $('#projFirstStep').show();
+    }
+    //显示新建建设项目-建设项目基本信息内容
+    async function showProjInfoStep() {
+        $('#add-project-dialog').find('.modal-title').html('建设项目基本信息');
+        $('#projFirstStep').hide();
+        $('#add-proj-next').hide();
+        $('#add-proj-prev').show();
+        $('#addProjOk').show();
+        $('#projInfoStep').show();
+        $('#project-required-warn').show();
+        if (!infoData) {
+            try {
+                infoData = await ajaxPost('/pm/api/getBasicInfo', {user_id: userID});
+                showRequiredInfo($('#projInfoStep'), infoData);
+            } catch (err) {
+                $('#add-project-dialog').modal('hide');
+            }
+        }
+    }
+
+    //新建建设项目、新建单项工程、新建文件夹、重命名弹窗隐藏事件
+    function bindModalsHidden(projDialog, engDialog, folderDialog, renameDialog){
+        projDialog.on('hidden.bs.modal', function () {
+            setDangerInfo($('#project-name-info'), '', false);
+            $('#project-name').val('');
+        });
+        projDialog.on('show.bs.modal', function () {
+            infoData = null;
+            showProjFirstStep();
+        });
+        engDialog.on('hidden.bs.modal', function () {
+            setDangerInfo($('#engineering-name-info'), '', false);
+            $('#engineering-name').val('');
+        });
+        folderDialog.on('hidden.bs.modal', function () {
+            setDangerInfo($('#folder-name-info'), '', false);
+            $('#folder-name').val('');
+        });
+        renameDialog.on('hidden.bs.modal', function () {
+            setDangerInfo($('#rename-name-info'), '', false);
+            $('#rename-name').val('');
+        });
+    }
 
+    //绑定新建建设项目、新建单项工程、新建文件夹、重命名回车键功能
+    function bindInputs(projInput, engInput, foldInput, renameInput){
+        projInput.bind('keypress', function (event) {
+            if(event.keyCode === 13){
+                $('#add-proj-next').click();
+                return false;
+            }
+        });
+        engInput.bind('keypress', function (event) {
+            if(event.keyCode === 13){
+                $('#add-engineering-confirm').click();
+                return false;
+            }
+        });
+        foldInput.bind('keypress', function (event) {
+            if(event.keyCode === 13){
+                $('#add-folder-confirm').click();
+                return false;
+            }
+        });
+        renameInput.bind('keypress', function (event) {
+            if(event.keyCode === 13){
+                $('#rename-confirm').click();
+                return false;
+            }
+        });
+    }
     // 选择计价方式
     $("input[name='valuation_type']").click(function() {
         let type = $(this).val();
@@ -1632,34 +1727,11 @@ $(document).ready(function() {
     });
 
 
-    // 新增单项项目点击
-   /* $("#add-engineering-btn").click(function() {
-        let selectedItem = projTreeObj.tree.selected;
-        try {
-            if(selectedItem !== null  && selectedItem.data.projType !== projectType.folder){
-                $("#add-engineering-dialog").modal("show");
-                setTimeout(function () {
-                    $('#engineering-name')[0].focus();
-                }, 300);
-            }
-
-        } catch (error) {
-            alert(error);
-        }
-    });*/
-
     // 新增单项工程操作
     $("#add-engineering-confirm").click(function() {
         AddEngineering();
     });
 
-    // 新增单位工程点击
-    /*$("#add-tender-btn").click(function() {
-        //弹出新建单位工程之前,判断当前使用版本,且当前使用单位工程数是否已到最大值
-        let selectedItem = projTreeObj.tree.selected;
-        $("#add-tender-dialog").modal("show");
-    });*/
-
     //新建单位工程-建设项目提示
     $('#poj-name').keyup(function () {
         let pojName = $('#poj-name').val().trim();
@@ -1754,10 +1826,12 @@ $(document).ready(function() {
             $('#regionDiv').find('select').append($opt);
         }
     }
-
     // 新增单位工程弹层改变
     $('#add-tender-dialog').on('show.bs.modal', function() {
         //clear info
+        curStep = 1; //当前在第几步
+        infoData = null; //建设项目基本信息数据
+        featureData = null; //工程特征数据
         $('#poj-name-info').hide();
         $('#eng-name-info').hide();
         $('#tender-name-info').hide();
@@ -1784,47 +1858,251 @@ $(document).ready(function() {
             $('#tender-name')[0].focus();
         }, 300);
     });
-
     //新建单位工程-下一步
-    $('#add-tender-next').click(function() {
-        let projName = $("#poj-name").val().trim();
-        if(projName === ''){
-            replaceClass($('#poj-name-info'), 'text-info', 'text-danger');
-            setDangerInfo($('#poj-name-info'), '请填写建设项目名称');
-            return false;
-        }
-        let engName = $("#eng-name").val().trim();
-        if(engName === ''){
-            replaceClass($('#eng-name-info'), 'text-info', 'text-danger');
-            setDangerInfo($('#eng-name-info'), '请填写单项工程名称');
-            return false;
-        }
+    $('#add-tender-next').click(async function() {
+        if (curStep === 1) {
+            let projName = $("#poj-name").val().trim();
+            if(projName === ''){
+                replaceClass($('#poj-name-info'), 'text-info', 'text-danger');
+                setDangerInfo($('#poj-name-info'), '请填写建设项目名称');
+                return false;
+            }
+            let engName = $("#eng-name").val().trim();
+            if(engName === ''){
+                replaceClass($('#eng-name-info'), 'text-info', 'text-danger');
+                setDangerInfo($('#eng-name-info'), '请填写单项工程名称');
+                return false;
+            }
 
-        let tenderName = $('#tender-name').val();
-        if (tenderName === '') {
-            setDangerInfo($('#tender-name-info'), '请填写单位工程名称');
-            return false;
+            let tenderName = $('#tender-name').val();
+            if (tenderName === '') {
+                setDangerInfo($('#tender-name-info'), '请填写单位工程名称');
+                return false;
+            }
+            let selected = projTreeObj.tree.selected;
+            let isExist = hasTender(selected, projName, engName, tenderName);
+            if (isExist) {
+                return false;
+            }
+            showSecondStep();
+        } else if (curStep === 2) {
+            let valuation = $("#valuation").val();
+            if(!valuation || valuation === ''){
+                setDangerInfo($('#valuation-info'), '请选择计价规则');
+                return false;
+            }
+
+            let engineeringName = $("#tender-engineering").val();
+            if (!engineeringName || engineeringName === '') {
+                setDangerInfo($('#engineering-info'), '请选择工程专业');
+                return false;
+            }
+            let feeName = $('#tender-feeStandard').val();
+            if(!feeName || feeName === ''){
+                setDangerInfo($('#feeStandard-info'), '请选择费用标准');
+                return false;
+            }
+
+            let taxType = $("#taxType").val();
+            let IDGroup = $("#tender-calcProgram").val();
+            if (!IDGroup || IDGroup === '') {
+                setDangerInfo($('#calcProgram-info'), '请选择计算程序');
+                return false;
+            }
+            let path = getAddPath();
+            if (path === addPath.p_e_t) {
+                showInfoStep();
+            } else {
+                showFeatureStep();
+            }
+        } else if (curStep === 3) {
+            if (!validRequiredData($('#infoStep'))) {
+                return;
+            }
+            showFeatureStep();
         }
-        $('#firstStep').hide();
-        $('#secondStep').show();
-        $(this).hide();
-        $('#add-tender-prev').show();
-        $('#add-tender-confirm').show();
-        $('#add-tender-cancel').show();
+        curStep++;
     });
+    //新建单位工程-上一步
+    $('#add-tender-prev').click(function () {
+        if (curStep === 2) {
+            showFirstStep();
+        } else if (curStep === 3) { //建设项目基本信息或工程特征
+            showSecondStep();
+        } else if (curStep === 4) { //工程特征
+            $('#featureStep').hide();
+            $('#add-tender-confirm').hide();
+            $('#add-tender-next').show();
+            $('#infoStep').show();
+        }
+        curStep--;
+    });
+    //显示第一步的内容
     function showFirstStep() {
+        $('#add-tender-title').html(`<i class="fa fa-sticky-note-o"></i>新建单位工程`);
+        $('#featureStep').hide();
+        $('#infoStep').hide();
         $('#secondStep').hide();
+        $('#tender-required-warn').hide();
         $('#firstStep').show();
         $('#add-tender-prev').hide();
         $('#add-tender-next').show();
         $('#add-tender-confirm').hide();
         $('#add-tender-cancel').hide();
     }
-    //新建单位工程-上一步
-    $('#add-tender-prev').click(showFirstStep);
+    //显示第二步内容
+    function showSecondStep() {
+        $('#add-tender-title').html(`<i class="fa fa-sticky-note-o"></i>新建单位工程`);
+        $('#add-tender-confirm').hide();
+        $('#featureStep').hide();
+        $('#infoStep').hide();
+        $('#firstStep').hide();
+        $('#tender-required-warn').hide();
+        $('#secondStep').show();
+        $('#add-tender-prev').show();
+        $('#add-tender-next').show();
+        $('#add-tender-cancel').show();
+    }
+    //显示新建单位工程-建设项目基本信息内容
+    async function showInfoStep() {
+        $('#add-tender-title').html('建设项目基本信息');
+        $('#secondStep').hide();
+        $('#infoStep').show();
+        $('#tender-required-warn').show();
+        if (!infoData) {
+            try {
+                infoData = await ajaxPost('/pm/api/getBasicInfo', {user_id: userID});
+                showRequiredInfo($('#infoStep'), infoData);
+            } catch (err) {
+                $('#add-tender-dialog').modal('hide');
+            }
+        }
+    }
+    //显示新建单位工程-工厂特征内容
+    async function showFeatureStep() {
+        $('#add-tender-next').hide();
+        $('#add-tender-confirm').show();
+        $('#add-tender-title').html('工程特征');
+        $('#secondStep').hide();
+        $('#infoStep').hide();
+        $('#featureStep').show();
+        $('#tender-required-warn').show();
+        if (!featureData) {
+            let valuation = $("#valuation").val();
+            let engineeringName = $("#tender-engineering").val();
+            let feeName = $('#tender-feeStandard').val();
+            try {
+                featureData = await ajaxPost('/pm/api/getProjectFeature',
+                    {user_id: userID, valuationID: valuation, engineeringName: engineeringName, feeName: feeName});
+                showRequiredInfo($('#featureStep'), featureData);
+            } catch (err) {
+                $('#add-tender-dialog').modal('hide');
+            }
+        }
+    }
+    //显示必填信息(建设项目基本信息、单位工程工程特征)
+    //必填信息:标记了必填required且不只读!readOnly
+    function showRequiredInfo($form, datas) {
+        $form.empty();
+        let requiredDatas = [];
+        function getRequired(datas) {
+            for (let data of datas) {
+                let required = typeof data.required === 'string' ? JSON.parse(data.required) : data.required,
+                    readOnly = typeof data.readOnly === 'string' ? JSON.parse(data.readOnly) : data.readOnly;
+                if (required && !readOnly) {
+                    requiredDatas.push(data);
+                }
+                if (data.items && data.items.length > 0) {
+                    getRequired(data.items);
+                }
+            }
+        }
+        getRequired(datas);
+        for (let data of requiredDatas) {
+            $form.append(getFormRow(data));
+        }
+    }
+    //根据基本信息、工程特征数据获取对应节点
+    function getFormRow(data) {
+        let cellType = data.cellType ? data.cellType : 'text';
+        let $label = $(`<label for="staticEmail" class="col-3 col-form-label col-form-label-sm">${data.dispName}</label>`),
+            $cell;
+        if (cellType === 'comboBox') {
+            let opts = data.options.split('@');
+            $cell = $(`<select name="${data.key}" class="form-control form-control-sm"><option>请选择</option></select>`);
+            for (let opt of opts) {
+                $cell.append($(`<option value="${opt}">${opt}</option>`));
+            }
+        } else {
+            $cell = $(`<input type="${cellType}" ${cellType === 'number' ? 'min="0"' : ''} name="${data.key}" class="form-control form-control-sm" placeholder="请输入">`);
+        }
+        let $row = $(`<div class="form-group row"></div>`),
+            $col = $(`<div class="col"></div>`);
+        $col.append($cell);
+        $row.append($label);
+        $row.append($col);
+        return $row;
+    }
+
+    //验证必填信息
+    function validRequiredData($form) {
+        let eles = $form.find('input, select');
+        for (let ele of eles) {
+            let v = $(ele).val().trim();
+            if (!v || v === '请选择') {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    //根据用户填的值,更新基本信息、工程特征数据
+    function updateRequiredData($form, fullData) {
+        let eles = $form.find('input, select');
+        for (let ele of eles) {
+            let key = $(ele).attr('name');
+            if (!key) {
+                continue;
+            }
+            let data = findRequiredByKey(key, fullData);
+            if (data) {
+                data.value = $(ele).val();
+                if (data.cellType === 'date') {
+                    data.value = data.value.replace('/\//g', '-');
+                }
+            }
+        }
+    }
+    //根据key获取基本信息/工程特征数据
+    function findRequiredByKey(key, data) {
+        function findItem(k, data) {
+            for (let d of data) {
+                if (d.key === k) {
+                    return d;
+                }
+                if (d.items && d.items.length > 0) {
+                    let target = findItem(k, d.items);
+                    if (target) {
+                        return target;
+                    }
+                }
+            }
+            return null;
+        }
+        return findItem(key, data);
+    }
 
     // 新增单位工程
     $("#add-tender-confirm").click(function() {
+        if (!validRequiredData($('#featureStep'))) {
+            return;
+        }
+        if (infoData && Array.isArray(infoData)) {
+            updateRequiredData($('#infoStep'), infoData);
+        }
+        if (featureData && Array.isArray(featureData)) {
+            updateRequiredData($('#featureStep'), featureData);
+        }
         let suc = AddTender();
         if(suc === false){
             $('#add-tender-confirm').removeClass('disabled');
@@ -2018,6 +2296,7 @@ $(document).ready(function() {
     });
 
     function changeEngineering(){
+        featureData = null;
         $('#engineering-info').hide();
         initFeeStandardSel();
     }
@@ -2063,6 +2342,7 @@ $(document).ready(function() {
     }
 
     function changeFeeStandard() {
+        featureData = null;
         let currentEngLib = getEngineeringLib($('#tender-engineering').val() + $('#tender-feeStandard').val(), getEngineeringList());
         changeFeeRate(currentEngLib);
         setTaxGroupHtml();
@@ -2241,70 +2521,24 @@ function AddProject() {
      (3)、当前定位在建设项目,新建建设项目为其后兄弟。
      (4)、当前定位在单项工程或单位工程,新建项目为当前所属建设项目的后兄弟。
      * */
+    let property = {basicInformation: infoData ? infoData : []};
     if(!selectedItem){
-        AddSiblingsItem(selectedItem, name, null, projectType.project, existCallback, sucCallback);
+        AddSiblingsItem(selectedItem, name, property, projectType.project, existCallback, sucCallback);
     }
     else {
         if(selectedItem.data.projType === projectType.project){
-            AddSiblingsItem(selectedItem, name, null, projectType.project, existCallback, sucCallback);
+            AddSiblingsItem(selectedItem, name, property, projectType.project, existCallback, sucCallback);
         }
         else if(selectedItem.data.projType === projectType.engineering || selectedItem.data.projType === projectType.tender){
             let proj = selectedItem.parent.data.projType === projectType.project ? selectedItem.parent : selectedItem.parent.parent;
-            AddSiblingsItem(proj, name, null, projectType.project, existCallback, sucCallback);
+            AddSiblingsItem(proj, name, property, projectType.project, existCallback, sucCallback);
         }
         else if(selectedItem.data.projType === projectType.folder){
-            AddChildrenItem(selectedItem, name, null, projectType.project, existCallback, sucCallback);
+            AddChildrenItem(selectedItem, name, property, projectType.project, existCallback, sucCallback);
         }
     }
 }
 
-//新建建设项目、新建单项工程、新建文件夹、重命名弹窗隐藏事件
-function bindModalsHidden(projDialog, engDialog, folderDialog, renameDialog){
-    projDialog.on('hidden.bs.modal', function () {
-        setDangerInfo($('#project-name-info'), '', false);
-        $('#project-name').val('');
-    });
-    engDialog.on('hidden.bs.modal', function () {
-        setDangerInfo($('#engineering-name-info'), '', false);
-        $('#engineering-name').val('');
-    });
-    folderDialog.on('hidden.bs.modal', function () {
-        setDangerInfo($('#folder-name-info'), '', false);
-        $('#folder-name').val('');
-    });
-    renameDialog.on('hidden.bs.modal', function () {
-        setDangerInfo($('#rename-name-info'), '', false);
-        $('#rename-name').val('');
-    });
-}
-
-//绑定新建建设项目、新建单项工程、新建文件夹、重命名回车键功能
-function bindInputs(projInput, engInput, foldInput, renameInput){
-    projInput.bind('keypress', function (event) {
-        if(event.keyCode === 13){
-            $('#addProjOk').click();
-            return false;
-        }
-    });
-    engInput.bind('keypress', function (event) {
-        if(event.keyCode === 13){
-            $('#add-engineering-confirm').click();
-            return false;
-        }
-    });
-    foldInput.bind('keypress', function (event) {
-        if(event.keyCode === 13){
-            $('#add-folder-confirm').click();
-            return false;
-        }
-    });
-    renameInput.bind('keypress', function (event) {
-        if(event.keyCode === 13){
-            $('#rename-confirm').click();
-            return false;
-        }
-    });
-}
 //新建建设项目、单项工程、文件夹、重命名提示(文本改变,暂时不需要)
 function getChangedFunc(input, nameInfo){
     return function () {
@@ -2340,8 +2574,26 @@ function setInitSummaryData(data) {
     data.perCost = '';
 }
 
+function getAddPath() {
+    let projName = $("#poj-name").val().trim(),
+        engName = $("#eng-name").val().trim(),
+        selected = projTreeObj.tree.selected;
+    let tempProjs = getProjs(selected);
+    let tempProj = getNodeByName(projName, tempProjs);
+    let tempEng;
+    if(tempProj){
+        tempEng = getNodeByName(engName, tempProj.children);
+        if(tempEng){
+           return addPath.t;
+        } else {
+            return addPath.e_t
+        }
+    } else {
+        return addPath.p_e_t;
+    }
+}
+
 function AddTenderItems(selected, projName, engName, tenderName, property, callback){
-    const addPath = {p_e_t: 'p_e_t', e_t: 'e_t', t: 't'};
     let path, updateDatas = [];
     let tempProjs = getProjs(selected);
     let tempProj = getNodeByName(projName, tempProjs);
@@ -2378,7 +2630,7 @@ function AddTenderItems(selected, projName, engName, tenderName, property, callb
                 pre = selectedProj;
                 next = selectedProj ? selectedProj.nextSibling : projTreeObj.tree.firstNode();
             }
-            let updateProjs = GetUpdateData(pre, parent, next, projName, null, projID, {updateType: 'new', projectType: projectType.project});
+            let updateProjs = GetUpdateData(pre, parent, next, projName, {basicInformation: infoData ? infoData : []}, projID, {updateType: 'new', projectType: projectType.project});
             let updateEng = {updateType: 'new', updateData: {ID: engID, ParentID: projID, NextSiblingID: -1, name: engName, projType: projectType.engineering}};
             property.rootProjectID = projID;
             let updateTender = {updateType: 'new', updateData: {ID: tenderID, ParentID: engID, NextSiblingID: -1, shareInfo: [], name: tenderName, projType: projectType.tender, property: property}};
@@ -2618,6 +2870,21 @@ function getNodeByName(name, nodes){
     return null;
 }
 
+//建设项目名称是否有效的
+function validProjectName(name) {
+    let selected = projTreeObj.tree.selected,
+        parent = null;
+    if (selected && selected.data.projType === projectType.folder) {
+        parent = selected ? selected : projTreeObj.tree._root;
+    } else {
+        if ([projectType.tender, projectType.engineering].includes(selected.data.projType)) {
+            selected = selected.parent.data.projType === projectType.project ? selected.parent : selected.parent.parent;
+        }
+        parent = selected ? selected.parent : projTreeObj.tree._root;
+    }
+    return !existName(name, parent.children);
+}
+
 //同级是否重名,文件夹与建设项目可以同名
 function existName(name , nodes, projType = null){
     for(let i = 0, len = nodes.length; i < len; i++){
@@ -2925,10 +3192,6 @@ function AddTender() {
         }
 
         let taxType = $("#taxType").val();
-        /*if(!taxType || taxType ===""){
-            return false;
-        }*/
-
         let IDGroup = $("#tender-calcProgram").val();
         if (!IDGroup || IDGroup === '') {
             setDangerInfo($('#calcProgram-info'), '请选择计算程序');
@@ -3005,7 +3268,8 @@ function AddTender() {
             templateLibID:templateLibID,
             colLibID:colLibID,
             featureLibID:featureLibID,
-            region: region
+            region: region,
+            projectFeature: featureData ? featureData : []
         };
         AddTenderItems(selectedItem, projName, engName, tenderName, tenderInfo, callback);
 

BIN
web/dest/css/img/work.png