前言
两年前在力控的时候就想做一个类似的功能,当时思路大家都讨论好了,诸多原因最终还是夭折了。没想到两年多后再这有重新提出要写一个绘制表单的功能。对此也是有点小激动呢?总共用时8.5天的时间基本功能也就实现了,当然再者中间也借用了网上的一些资料,公司前端也没有帮忙处理,所以样式和部分功能还没有更好地得到处理,github上出的code只有前端脚本,至于后端的处理,会在博客中体现出来。
1.工作前准备
1.1.实现的思路
思路一:
(1)ueditor添加自定义按钮
(2)绘制表单(控件会触发的脚步【暂时考虑范围】)【每个控件均需添加控件名称和创建名称】
(3)保存表单时建立数据库表(无需存储表信息),并保存html字符串
(4)修改表单需同时修改数据库
(5)表单发起获取数据封装成json,进行后台保存。
思路二:
(1)jquery 拖动自定义标签,在指定区域进行绘制
(2)表单属性设置相应的表单属性和表单基本布局
(3)设置每个控件的属性值
(4)把表单信息和控件以json的形式传入后台进行保存
(5)从后台获取数据json对象用jquery 绘制表单页面
(6)创建一张表(F-F200)把表单数据存入表单中。
最终选择的是【思路二】,原因是富文本编辑器绘制起来有很多自动生成的标签,让人感觉很是不爽。当然可以对ueditor进行处理(这个也是两年前的思路)。
1.2.实现过程的确定
整个的过程从借鉴开始网上有些类似的功能,从中得到很多帮助在这就不一一鸣谢了。然后就是没羞没臊的3天脚本修改工作【现在基本完成不过还在持续中】。后台数据的处理完全没有什么可说的,中间用的了一些缓存问题,本来说是用redis呢,结果商量一些说不用难部署(难部署???好吧一脸懵逼),就用了c#的CacheHelper。
2.具体实现
绘制表单预览与保存
2.1.脚本
以上是表单创建的js脚本。
就是上边那个图片的实现。
html重要分左中右三部分。左边是页面上所用到的标签区域,中间是展示区域,右边是表单和控件属性的设置区域。htnl 脚本如下:
以上脚本中主要的操作就是拖动,设置每个控件的时候改变对应json的值。至于样式的变化这里没绘制表单的时候复杂一些。如果那位哥们要用这个模板稍微看一下代码即可你只要修改一下地方即可:
复制代码 代码如下:
var M={FRMNM:"表单名称",DESC:"",LANG:"cn",LBLAL:"T",CFMTYP:"T",CFMMSG:"提交成功。",SDMAIL:"0",CAPTCHA:"1",IPLMT:"0",SCHACT:"0",INSTR:"0",ISPUB:"1"}
var F=[];
其中M是表单信息json串,F是所用控件数据集字符串。所以在绘制的后保存的时候把这两个值传到后台保存即可,只有修改的货在页面初始加载的时候进行赋值就行啦。
2.2后台代码(MVC)
[HttpGet]
public ActionResult FormView(string formData, string parameterData)
{
ViewBag.FormInfo = Session["formData"];
ViewBag.FormParameter = Session["parameterData"];
return View();
}
///
/// 页面预览
///
/// 表单信息
/// 表单控件信息
///
[HttpPost]
//[ValidateInput(false)]
public ActionResult FormView(string formData, string parameterData)
{
Session["formData"] = formData;
Session["parameterData"] = parameterData;
return pageHelper.OpenTab("FormDesignDetail", "预览", "/CustomFrom/FormDesign/FormDesignDetail");
}
页面预览操作。不保存只是在页面上显示而已。因为绘制表单不处理样式的,所以最终样式以预览的样式为标准,所见即所得。
///
/// 保存表单信息
///
/// {表单信息,表单字段信息}
///
[HttpPost]
[ValidateInput(false)]
public ActionResult FormSave(string formData, string parameterData)
{
try
{
ActionResult result = base.AddExecuteScript();
if (result != null)
return result;
string strGUID = Guid.NewGuid().ToString(); //直接返回字符串类型
JavaScriptSerializer js = new JavaScriptSerializer();
List fclist = js.Deserialize>(parameterData);
FormDesign model = js.Deserialize(formData);
model.FormInfo = formData;
model.Form_Guid = strGUID;
model.ZhuangTai = "0";
model.LuRuRen = userHelper.GetUser().UName;
model.LuRuRen = DateTime.Now.ToString("yyyy-MM-dd");
var flag = bll.AddFormDesign(model, fclist);
return flag ? pageHelper.CloseOpenTab("FormDesignAdd", "FormDesignDetail" + strGUID, "表单信息详情", "/CustomFrom/FormDesign/FormDesignDetail?formgid=" + strGUID) : pageHelper.ExtAlert("新增失败!");
}
catch (Exception ex)
{
return null;
}
}
页面保存信息,把json信息的元素都进行存储。表单信息和表单控件信息外键关联用的是guid。
注:代码请忽略一些细节和我们框架有关
预览脚本
3.脚本要不要说一下???
[中午吃饭的时候写的,周末抽时间详细描述一下哈]
function createFields() {
var b,
//标签对其方式
a = $('#fields').empty();
if ('L' === M.LBLAL) {
a.addClass('leftLabel')
} else {
if ('R' === M.LBLAL) {
a.addClass('leftLabel labelRight')
}
}
var mwith = 0;
//循环数据 typ="text" min="2323" max="432" reqd="1" uniq="1" def="默认值"
$.each(F, function (d, c) {
if (!c) {
return true
}
b = $(DEFFLD.field_li);
b.attr('id', M.GID + d);
b.attr("typ", c.TYP);
if (c.min != undefined && c.min != "") {
b.attr("min", c.min)
};
if (c.max != undefined && c.max != "") {
b.attr("max", c.max)
}
;
if (c.reqd != undefined && c.reqd != "0") {
b.attr("reqd", c.reqd)
};
if (c.uniq != undefined && c.uniq != "0") {
b.attr("uniq", c.uniq)
};
if (c.def != undefined && c.def != "") {
b.attr("def", c.def)
};
//布局非单行布局的时候,div宽度增加。
if (c.LAYOUT != undefined && c.LAYOUT != "") {
b.addClass(c.LAYOUT)
mwith += 200;
}
if (c.INSTR != undefined && c.INSTR != "") {
b.addClass("fieldInstruct");
}
createField(b, c, d + 1)
a.append(b);
});
if ($.isEmptyObject(F)) {
$('#nofields').show();
$('#formButtons').hide()
}
if (M.GID != "") {
a.append(DEFFLD['form_but'].html);
}
}
首先页面的布局是这样的
其中控件的属性值主要是在li特定属性中进行控制。上边代码就是根据json字符串进行对li进行赋值的。当表单如果要两行布局的时候宽度会进行增加
function createField(r, q, num) {
if (!q) {
return
}
var p,
o,
l,
m;
// r.removeClass('one two three oneByOne fieldInstruct');
// r.attr('title', '点击编辑,拖动排序');
r.empty();
$('#nofields').hide();
$('#formButtons').show();
l = $(DEFFLD[q.TYP].html);
//l.attr("name","F"+num);
if ('goods' == q.TYP && '1' == q.NOIMG) {
l = $(DEFFLD.goodsnoimg.html)
}
if (q.TYP === 'html' || q.TYP === 'section') {
p = l.find('label.desc');
m = l.find('div.content')
} else {
p = l.filter('label.desc');
m = l.filter('div.content')
}
if (q.TYP === 'likert') {
p = m.find('label.desc')
}
o = p.find('span');
if (q.REQD === '1') {
o.removeClass('hide')
}
p.text(q.LBL);
p.append(o);
if (q.TYP === 'text' && '1' == q.QRINPUT) {
m.find('i.qrinput').removeClass('hide')
m.find('text').attr('name', 'F' + num);
} else {
if (q.TYP === 'phone' && q.FMT) {
m.html(DEFFLD[$.format('phone_{0}_{1}', q.FMT, M.LANG)]);
'1' == q.AUTH ? m.find('.sendcode').show() : m.find('.sendcode').hide();
'1' == q.AUTH ? $('#signcnt').show() : $('#signcnt').hide()
} else {
if (q.TYP === 'date' && q.FMT) {
m.html(DEFFLD[$.format('date_{0}', q.FMT)])
} else {
if (q.TYP === 'name' && q.FMT) {
if (q.FMT === 'short') {
m.html(DEFFLD.name_short)
} else {
m.html(DEFFLD[$.format('name_{0}_{1}', q.FMT, M.LANG)])
}
} else {
if (q.TYP === 'address') {
m.html(DEFFLD[$.format('address_{0}', M.LANG)]);
if (q.DEF) {
var g = q.DEF.split('-');
m.find('select.province').empty().append($.format('{0} ', g[0] || '省/自治区/直辖市'));
m.find('select.city').empty().append($.format('{0} ', g[1] || '市'));
m.find('select.zip').empty().append($.format('{0} ', g[2] || '区/县'))
}
} else {
if (q.TYP === 'radio') {
createRadioItemsPreview(q, m)
} else {
if (q.TYP === 'checkbox') {
m.empty();
var b;
var a;
var i = false;
$.each(q.ITMS, function (j, c) {
if (c.IMG) {
i = true;
return false
}
});
$.each(q.ITMS, function (j, c) {
b = $(DEFFLD.item_checkbox_f);
b.find('label').text(c.VAL);
b.find(':checkbox').prop('checked', c.CHKED === '1');
if (i) {
if (c.IMG) {
a = $('')
} else {
a = $('')
}
m.append(a)
} else {
m.append(b)
}
})
} else {
if (q.TYP === 'image') {
m.find('img').attr('src', q.IMG ? IMAGESURL + q.IMG : '/rs/images/defaultimg.png')
//m.find('img').attr('name','F'+num);
} else {
if (q.TYP === 'goods') {
createGoodsItemsPreView(q, m)
} else {
if (q.TYP === 'section') {
m.html($.enterToBr((q.SECDESC || '')))
} else {
if (q.TYP === 'html') {
m.html($.encodeScript(q.HTML || ''))
} else {
if (q.TYP === 'likert') {
createLikertPreview(q, l)
} else {
if (q.TYP === 'dropdown2') {
var d = q.pN || '2';
if (d !== '2') {
d = parseInt(d);
m.find('select').remove();
for (var f = 0; f < d; f++) {
m.append(' ')
}
m.find('select').css({
width: (100 / d - 1) + '%',
'margin-right': '1%'
})
}
for (var e = 0; e < q.ITMS.length; e++) {
if (q.ITMS[e].CHKED === '1') {
m.find('select:first').empty().append($.format('{0} ', q.ITMS[e].VAL));
break
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
if (q.TYP === 'dropdown') {
$.each(q.ITMS, function (j, c) {
if (c.CHKED === '1' && c.VAL) {
m.find('select').append($.tmpl('${$data} ', c.VAL));
// return false
}
else {
m.find('select').append($.format('{0} ', c.VAL));
}
})
}
if (q.DEF) {
var s = [
'text',
'textarea',
'number',
'ulr',
'email',
'money',
'phone'
];
if ($.inArray(q.TYP, s) >= 0) {
if (q.TYP === 'phone' && q.FMT === 'tel') {
$.each(q.DEF.split('-'), function (j, c) {
m.find(':text:eq(' + j + ')').val(c)
})
} else {
l.find(':input').val(q.DEF)
}
}
}
if (q.FLDSZ) {
m.find(':text,textarea,select').removeClass('s m xxl').addClass(q.FLDSZ)
}
var h = $(DEFFLD.instruct);
if (q.INSTR) {
h.text(q.INSTR)
}
r.append(DEFFLD.icon).append(l).append(h).append(DEFFLD.fieldActions);
if (isInstruct(q.TYP)) {
r.addClass('fieldInstruct')
}
if (q.LAY) {
r.addClass(q.LAY)
}
if (q.SCU == 'pri') {
r.addClass('private')
}
m.find(':text,textarea,select,img,hidden').attr('name', 'F' + num);
}
根据不同的控件类型进行不同空间的绘制,其中DEFFLD变量初始化了所需控件html脚本,可以下载源码查看。
总结: 一次后台程序员写前端脚本的过程,完成了2年前留下的遗憾。
源码:https://github.com/kmonkey9006/FormDesign
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。