生成招标文件的项目小结

  这是一次失败的、苦恼的编程经历。

  去年用户找到我,说开发一个简单的程序,基本上一两个星期就可以搞定,用于生成Word形式的招标文件。

  听说这个需求,只是用一两个星期,我很惊讶,这个程序说简单也的确不难,掌握一些操作Word的API即可,说复杂也挺复杂的,我开发过试题库系统,对这些还是比较熟悉。

  最终的需求没有定下来,用户说了开发时间,一两个星期就可以完工,为了不服输,一个星期写好了,程序可以正常使用。

  可惜用户没有使用,可能也是因为时间的缘故。

  用户说现在都是网页形式,Windows窗口程序使用不方便。

  刚好我也在学Web开发,就答应下来,尽快完成。我也想快速掌握这方面的开发技能。

  使用的是LayUI+PHP+AXAJ+JSON,数据库开始使用MySQL8,后面换成了MS SQL 

Server2014。 

 

  这个程序花了整整一个月,都是晚上写,可能是我把需求复杂化了。

  现在实在写不下去了,用户的需求也变了,原先是招标文件很长,一般60多页,只是替换里面的一些内容,有列表、单选、多选、手工输入、插入图片、插入Word文件、二选一(选择一个就有内容需要完善)等,刚好Powerbuilder的数据窗口可以有丰富的显示样式,对于内容替换,则是使用书签的方式进行,即书签名称+00XX,这就可以完成多次的替换(XX表示次数)。

  现在用户需求变成招标文件只有7页纸,主要是多种样式的文字,还有表格。为了满足这些样式,我设定了多种输入对应:

  1、系统函数:自动执行,输出结果;

  2、单词:预定义好的词汇;

  3、单选列表:选择了输出一个结果;

  4、多选列表:选择了输出多种结果,可以分行和不分行输出;

  5、二选一:有两种方式,一种是输出单选结果,另外一种是输出方框,前面打不√;

  6、手工输入:有简单文字(一行,不弹出输入窗口),有数字、日期、文字(对于数字和日期需要验证,可以限定范围比如最大值和最小值等),多行文字(弹出输入窗口),有长度限制。

  写着写着就有了鸡肋的感觉,食之无味,弃之可惜,被这个程序拖住了。

  将有用的代码记录下来:

  1、在表格的一行里应用radio

  主要是使用name和id来区分,name一样,id不一样,这样每行的radio单独起作用。

  使用模板语法生成radio

			case '二选一':
				optionList=d.c18.split('|'); 
				if(d.c19==optionList[0]){
					strPSP = "<div class='layui-input-inline'><input type='radio' name='Dc"+rowIDStr+"' id='DcA"+rowIDStr+"' value='"+optionList[0]+"' title='"+optionList[0]+"' lay-filter='Dcradio' checked='checked'>  <input type='radio' name='Dc"+rowIDStr+"' id='DcB"+rowIDStr+"' value='"+optionList[1]+"' title='"+optionList[1]+"'></div>"; 
				}else{
					strPSP = "<div class='layui-input-inline'><input type='radio' name='Dc"+rowIDStr+"' id='DcA"+rowIDStr+"' value='"+optionList[0]+"' title='"+optionList[0]+"' lay-filter='Dcradio'>  <input type='radio' name='Dc"+rowIDStr+"' id='DcB"+rowIDStr+"' value='"+optionList[1]+"' title='"+optionList[1]+"'  checked='checked'></div>";
				}
				return strPSP;
				break;

  监听操作:

		form.on('radio', function(obj){
			setTimeout(function(){					
					if(selectRowNum>=0){
							let selectInfo;
							let srcSelect=table.cache.projectEditInfo[selectRowNum].c18.split('|');						
							if(srcSelect[1]==obj.value){
									selectInfo=$("#projectEditInfo").next().find("tbody tr[data-index='" +selectRowNum +"'] td[data-field='c19'] div").html();
									if(selectInfo=='' || selectInfo==srcSelect[0]){
											selectInfo=table.cache.projectEditInfo[selectRowNum].c17;
									}
								    layer.prompt({
											formType: 2,
											title: '请填写〖'+obj.value+'〗的相关信息',
											value: selectInfo,
											area: ['500px', '300px']
								    }, function(value, index){
											layer.close(index);
											$("#projectEditInfo").next().find("tbody tr[data-index='" +selectRowNum +"'] td[data-field='c19'] div").html(value);
								    });						
							}else{
								$("#projectEditInfo").next().find("tbody tr[data-index='" +selectRowNum +"'] td[data-field='c19'] div").html(srcSelect[0]);
							}
					}
			},500);
			return false;
		});

  2、在表格中使用下拉列表

  使用模板语法生成下拉列表:

			case '列表':
				selectList=d.c17.split('|');
				strPSP="<div class='layui-input-inline' style='width: 300px;'><select lay-filter='DCselect' id='DCselect'+rowIDStr>";
				for (var i=0 ; i<selectList.length ; i++ ) {
					if(d.c19==selectList[i]){
						strPSP = strPSP + "<option value='" + selectList[i] + "' layui-this selected>" + selectList[i] + "</option>" ; 
					}else{
						strPSP = strPSP + "<option value='" + selectList[i] + "'>" + selectList[i] + "</option>" ; 
					}
				}
				strPSP=strPSP+"</select></div>";
				return strPSP;
				break;

  监听操作:

		form.on('select(DCselect)', function(obj){
				if(selectRowNum){
						let sTemp='';
						let tempList;
						tempList=selectRowObj['data']['c17'].split('|');
						switch(selectRowObj['data']['c18']){
							case '单选':
									sTemp=obj.value;
									break;
							case '全列|方框标识':
									for (var i=0 ; i<tempList.length ; i++ ) {
										if(obj.value==tempList[i]){
											sTemp=sTemp+"  √"+tempList[i]; 
										}else{
											sTemp=sTemp+"  □"+tempList[i];
										}
									}
									break;
							case '全列|方框标识|一项一行':
									for (var i=0 ; i<tempList.length ; i++ ) {
										if(obj.value==tempList[i]){
											sTemp=sTemp+"  √"+tempList[i]+"\r\n"; 
										}else{
											sTemp=sTemp+"  □"+tempList[i]+"\r\n"; 
										}
									}							
									break;
						}
						$("#projectEditInfo").next().find("tbody tr[data-index='" +selectRowNum +"'] td[data-field='c19'] div").html(sTemp);
				}			
				return false;
		});

  3、在表格中使用手工输入

  使用模板语法定义输入样式:

			case '手工输入':
				let inputType='';
				let additionalClass='';
				if(d.c04=='数字'){
					inputType='number';
				}else{
					inputType='text';
				}
				if(d.c04=='日期'){
						additionalClass='laydate';
						laydateInput.push('Dcinput'+rowIDStr);
				}
				strPSP="<div class='layui-input-inline' style='width: 300px;'><input type='"+inputType+"' id='Dcinput"+rowIDStr+"'  value='"+strContent+"' class='layui-input "+additionalClass+"' lay-filter='DCinput' onkeypress='keyboardInput(event)'></div>";				
				return strPSP;
				break;

  监听操作:

	function keyboardInput(event){
		let inputId=event.srcElement['id'];
		if(event.keyCode==13){
			let inputVal=document.getElementById(inputId).value;
			if(selectRowNum){
				layui.$("#projectEditInfo").next().find("tbody tr[data-index='" +selectRowNum +"'] td[data-field='c19'] div").html(inputVal);//改变值
			}
		}
	}

  如果双击,判断是多行文本,弹出输入框。

//监听行双击事件
table.on('rowDouble(projectEditInfoFilter)', function (obj) {
		selectRowObj=obj;
		selectRowNum=obj.tr[0].rowIndex;
		if(selectRowObj['data']['c04']=='多行文本'){
				let elemID;
				let tempRowID=selectRowNum + 1
				elemID='Dcinput'+'0'.repeat(4 - tempRowID.toString().length)+tempRowID.toString();
				let c19Value=$("#projectEditInfo").next().find("tbody tr[data-index='" +selectRowNum +"'] td[data-field='c19'] div").html();
				layer.prompt({
						formType: 2,
						title: '请填写 〖 '+selectRowObj['data']['c06']+' 〗 的相关信息',
						value: c19Value,								
						area: ['500px', '300px']
				}, function(value, index){
						document.getElementById(elemID).value=value;
						$("#projectEditInfo").next().find("tbody tr[data-index='" +selectRowNum +"'] td[data-field='c19'] div").html(value);
						layer.close(index);
				});												
		}
});

  4、在表格中使用日期控件

  在初始化的时候将日期型的输入控件放到一个数组里,然后一次性完成控件的渲染。

for(let i=0;i<laydateInput.length;i++){
	let elemID="#"+laydateInput[i];
	let tempRowID=parseInt(laydateInput[i].substr(7,4)) - 1;
	let dbDate=initEditData['data'][tempRowID]['c19'];
	laydate.render({
		elem:elemID,//指定元素
		type:'date',
		format:'yyyy年MM月dd日',
		trigger: 'click',
		showBottom:false,
		value:dbDate,
		done:function(value,date,endDate){													
			$("#projectEditInfo").next().find("tbody tr[data-index='" +tempRowID +"'] td[data-field='c19'] div").html(value);//改变值
		}
	});			
}	

  5、表格初始化后要加上下面的代码

$(".layui-table-body, .layui-table-box, .layui-table-cell").css('overflow', 'visible');
form.render('select');
form.render('radio');

  6、下载文件

  方式有很多,我简单化,隐藏一个a标签,动态更改下载地址,模拟点击。

$.ajax({
		url:'XXXX.php',
		data:{
			"OP":"download",
			"Year":selectPorjectRowObj['data']['c01'],
			"Project":selectPorjectRowObj['data']['c02'],
			"ProjectChild":selectPorjectRowObj['data']['c14']																								
			},
		type:'POST',
		async:false,
		success:function (data) {
			document.getElementById('DL').href="http://1.2.3.4/"+data['data'];
			document.getElementById('DL').click();	
		}																			
});			

  在开发过程中,被一个存储折腾了很长时间,也是我想复杂了,就是如何记住用户的操作。

  开始使用image字段,记录用户操作的html内容,结果折腾了一个星期,各种奇葩问题不断,因为涉及编码和汉字,后面使用模板语法,避免了这些麻烦。

  这是个教训,不要总是把简单问题复杂化!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值