require-form.js 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566
  1. define(['jquery', 'bootstrap', 'upload', 'validator', 'validator-lang'], function ($, undefined, Upload, Validator, undefined) {
  2. var Form = {
  3. config: {
  4. fieldlisttpl: '<dd class="form-inline"><input type="text" name="<%=name%>[<%=index%>][key]" class="form-control" value="<%=row.key%>" size="10" /> <input type="text" name="<%=name%>[<%=index%>][value]" class="form-control" value="<%=row.value%>" /> <span class="btn btn-sm btn-danger btn-remove"><i class="fa fa-times"></i></span> <span class="btn btn-sm btn-primary btn-dragsort"><i class="fa fa-arrows"></i></span></dd>'
  5. },
  6. events: {
  7. validator: function (form, success, error, submit) {
  8. if (!form.is("form"))
  9. return;
  10. //绑定表单事件
  11. form.validator($.extend({
  12. validClass: 'has-success',
  13. invalidClass: 'has-error',
  14. bindClassTo: '.form-group',
  15. formClass: 'n-default n-bootstrap',
  16. msgClass: 'n-right',
  17. stopOnError: true,
  18. display: function (elem) {
  19. console.log('display')
  20. return $(elem).closest('.form-group').find(".control-label").text().replace(/\:/, '');
  21. },
  22. dataFilter: function (data) {
  23. console.log('dataFilter')
  24. if (data.code === 1) {
  25. return data.msg ? {"ok": data.msg} : '';
  26. } else {
  27. return data.msg;
  28. }
  29. },
  30. target: function (input) {
  31. // console.log('target')
  32. // // 根据身份证获取 年龄 生日 性别
  33. // var idcard = $('#c-idcard').val()
  34. // console.log(idcard)
  35. // var birth= idcard.substring(6,10) + "-" + idcard.substring(10,12) + "-" + idcard.substring(12,14);
  36. // console.log(birth)
  37. // var sex = "";
  38. // if (parseInt(idcard.substr(16, 1)) % 2 == 1) {
  39. // sex = "男";
  40. // } else {
  41. // sex = "女";
  42. // }
  43. // console.log(sex);
  44. // var myDate = new Date();
  45. // var month = myDate.getMonth() + 1;
  46. // var day = myDate.getDate();
  47. // var age = myDate.getFullYear() - idcard.substring(6, 10) - 1;
  48. // if (idcard.substring(10, 12) < month || idcard.substring(10, 12) == month && idcard.substring(12, 14) <= day) {
  49. // age++;
  50. // }
  51. // console.log(age);
  52. var target = $(input).data("target");
  53. if (target && $(target).size() > 0) {
  54. return $(target);
  55. }
  56. var $formitem = $(input).closest('.form-group'),
  57. $msgbox = $formitem.find('span.msg-box');
  58. if (!$msgbox.length) {
  59. return [];
  60. }
  61. return $msgbox;
  62. },
  63. valid: function (ret) {
  64. console.log('valid')
  65. var that = this, submitBtn = $(".layer-footer [type=submit]", form);
  66. that.holdSubmit(true);
  67. submitBtn.addClass("disabled");
  68. //验证通过提交表单
  69. var submitResult = Form.api.submit($(ret), function (data, ret) {
  70. that.holdSubmit(false);
  71. submitBtn.removeClass("disabled");
  72. if (false === $(this).triggerHandler("success.form", [data, ret])) {
  73. return false;
  74. }
  75. if (typeof success === 'function') {
  76. if (false === success.call($(this), data, ret)) {
  77. return false;
  78. }
  79. }
  80. //提示及关闭当前窗口
  81. var msg = ret.hasOwnProperty("msg") && ret.msg !== "" ? ret.msg : __('Operation completed');
  82. parent.Toastr.success(msg);
  83. parent.$(".btn-refresh").trigger("click");
  84. var index = parent.Layer.getFrameIndex(window.name);
  85. parent.Layer.close(index);
  86. return false;
  87. }, function (data, ret) {
  88. that.holdSubmit(false);
  89. if (false === $(this).triggerHandler("error.form", [data, ret])) {
  90. return false;
  91. }
  92. submitBtn.removeClass("disabled");
  93. if (typeof error === 'function') {
  94. if (false === error.call($(this), data, ret)) {
  95. return false;
  96. }
  97. }
  98. }, submit);
  99. //如果提交失败则释放锁定
  100. if (!submitResult) {
  101. that.holdSubmit(false);
  102. submitBtn.removeClass("disabled");
  103. }
  104. return false;
  105. }
  106. }, form.data("validator-options") || {}));
  107. //移除提交按钮的disabled类
  108. $(".layer-footer [type=submit],.fixed-footer [type=submit],.normal-footer [type=submit]", form).removeClass("disabled");
  109. //自定义关闭按钮事件
  110. form.on("click", ".layer-close", function () {
  111. var index = parent.Layer.getFrameIndex(window.name);
  112. parent.Layer.close(index);
  113. return false;
  114. });
  115. },
  116. selectpicker: function (form) {
  117. //绑定select元素事件
  118. if ($(".selectpicker", form).size() > 0) {
  119. require(['bootstrap-select', 'bootstrap-select-lang'], function () {
  120. $('.selectpicker', form).selectpicker();
  121. $(form).on("reset", function () {
  122. setTimeout(function () {
  123. $('.selectpicker').selectpicker('refresh').trigger("change");
  124. }, 1);
  125. });
  126. });
  127. }
  128. },
  129. selectpage: function (form) {
  130. //绑定selectpage元素事件
  131. if ($(".selectpage", form).size() > 0) {
  132. require(['selectpage'], function () {
  133. $('.selectpage', form).selectPage({
  134. eAjaxSuccess: function (data) {
  135. data.list = typeof data.rows !== 'undefined' ? data.rows : (typeof data.list !== 'undefined' ? data.list : []);
  136. data.totalRow = typeof data.total !== 'undefined' ? data.total : (typeof data.totalRow !== 'undefined' ? data.totalRow : data.list.length);
  137. return data;
  138. }
  139. });
  140. });
  141. //给隐藏的元素添加上validate验证触发事件
  142. $(document).on("change", ".sp_hidden", function () {
  143. $(this).trigger("validate");
  144. });
  145. $(document).on("change", ".sp_input", function () {
  146. $(this).closest(".sp_container").find(".sp_hidden").trigger("change");
  147. });
  148. $(form).on("reset", function () {
  149. setTimeout(function () {
  150. $('.selectpage', form).selectPageClear();
  151. }, 1);
  152. });
  153. }
  154. },
  155. cxselect: function (form) {
  156. //绑定cxselect元素事件
  157. if ($("[data-toggle='cxselect']", form).size() > 0) {
  158. require(['cxselect'], function () {
  159. $.cxSelect.defaults.jsonName = 'name';
  160. $.cxSelect.defaults.jsonValue = 'value';
  161. $.cxSelect.defaults.jsonSpace = 'data';
  162. $("[data-toggle='cxselect']", form).cxSelect();
  163. });
  164. }
  165. },
  166. citypicker: function (form) {
  167. //绑定城市远程插件
  168. if ($("[data-toggle='city-picker']", form).size() > 0) {
  169. require(['citypicker'], function () {
  170. $(form).on("reset", function () {
  171. setTimeout(function () {
  172. $("[data-toggle='city-picker']").citypicker('refresh');
  173. }, 1);
  174. });
  175. });
  176. }
  177. },
  178. datetimepicker: function (form) {
  179. //绑定日期时间元素事件
  180. if ($(".datetimepicker", form).size() > 0) {
  181. require(['bootstrap-datetimepicker'], function () {
  182. var options = {
  183. format: 'YYYY-MM-DD HH:mm:ss',
  184. icons: {
  185. time: 'fa fa-clock-o',
  186. date: 'fa fa-calendar',
  187. up: 'fa fa-chevron-up',
  188. down: 'fa fa-chevron-down',
  189. previous: 'fa fa-chevron-left',
  190. next: 'fa fa-chevron-right',
  191. today: 'fa fa-history',
  192. clear: 'fa fa-trash',
  193. close: 'fa fa-remove'
  194. },
  195. showTodayButton: true,
  196. showClose: true
  197. };
  198. $('.datetimepicker', form).parent().css('position', 'relative');
  199. $('.datetimepicker', form).datetimepicker(options).on('dp.change', function (e) {
  200. $(this, document).trigger("changed");
  201. });
  202. });
  203. }
  204. },
  205. daterangepicker: function (form) {
  206. //绑定日期时间元素事件
  207. if ($(".datetimerange", form).size() > 0) {
  208. require(['bootstrap-daterangepicker'], function () {
  209. var ranges = {};
  210. ranges[__('Today')] = [Moment().startOf('day'), Moment().endOf('day')];
  211. ranges[__('Yesterday')] = [Moment().subtract(1, 'days').startOf('day'), Moment().subtract(1, 'days').endOf('day')];
  212. ranges[__('Last 7 Days')] = [Moment().subtract(6, 'days').startOf('day'), Moment().endOf('day')];
  213. ranges[__('Last 30 Days')] = [Moment().subtract(29, 'days').startOf('day'), Moment().endOf('day')];
  214. ranges[__('This Month')] = [Moment().startOf('month'), Moment().endOf('month')];
  215. ranges[__('Last Month')] = [Moment().subtract(1, 'month').startOf('month'), Moment().subtract(1, 'month').endOf('month')];
  216. var options = {
  217. timePicker: false,
  218. autoUpdateInput: false,
  219. timePickerSeconds: true,
  220. timePicker24Hour: true,
  221. autoApply: true,
  222. locale: {
  223. format: 'YYYY-MM-DD HH:mm:ss',
  224. customRangeLabel: __("Custom Range"),
  225. applyLabel: __("Apply"),
  226. cancelLabel: __("Clear"),
  227. },
  228. ranges: ranges,
  229. };
  230. var origincallback = function (start, end) {
  231. $(this.element).val(start.format(this.locale.format) + " - " + end.format(this.locale.format));
  232. $(this.element).trigger('blur');
  233. };
  234. $(".datetimerange", form).each(function () {
  235. var callback = typeof $(this).data('callback') == 'function' ? $(this).data('callback') : origincallback;
  236. $(this).on('apply.daterangepicker', function (ev, picker) {
  237. callback.call(picker, picker.startDate, picker.endDate);
  238. });
  239. $(this).on('cancel.daterangepicker', function (ev, picker) {
  240. $(this).val('').trigger('blur');
  241. });
  242. $(this).daterangepicker($.extend(true, options, $(this).data()), callback);
  243. });
  244. });
  245. }
  246. },
  247. /**
  248. * 绑定上传事件
  249. * @param form
  250. * @deprecated Use faupload instead.
  251. */
  252. plupload: function (form) {
  253. Form.events.faupload(form);
  254. },
  255. /**
  256. * 绑定上传事件
  257. * @param form
  258. */
  259. faupload: function (form) {
  260. //绑定上传元素事件
  261. if ($(".plupload,.faupload", form).size() > 0) {
  262. Upload.api.upload($(".plupload,.faupload", form));
  263. }
  264. },
  265. faselect: function (form) {
  266. //绑定fachoose选择附件事件
  267. if ($(".faselect,.fachoose", form).size() > 0) {
  268. $(".faselect,.fachoose", form).off('click').on('click', function () {
  269. var that = this;
  270. var multiple = $(this).data("multiple") ? $(this).data("multiple") : false;
  271. var mimetype = $(this).data("mimetype") ? $(this).data("mimetype") : '';
  272. var admin_id = $(this).data("admin-id") ? $(this).data("admin-id") : '';
  273. var user_id = $(this).data("user-id") ? $(this).data("user-id") : '';
  274. var url = $(this).data("url") ? $(this).data("url") : (typeof Backend !== 'undefined' ? "general/attachment/select" : "user/attachment");
  275. parent.Fast.api.open(url + "?element_id=" + $(this).attr("id") + "&multiple=" + multiple + "&mimetype=" + mimetype + "&admin_id=" + admin_id + "&user_id=" + user_id, __('Choose'), {
  276. callback: function (data) {
  277. var button = $("#" + $(that).attr("id"));
  278. var maxcount = $(button).data("maxcount");
  279. var input_id = $(button).data("input-id") ? $(button).data("input-id") : "";
  280. maxcount = typeof maxcount !== "undefined" ? maxcount : 0;
  281. if (input_id && data.multiple) {
  282. var urlArr = [];
  283. var inputObj = $("#" + input_id);
  284. var value = $.trim(inputObj.val());
  285. if (value !== "") {
  286. urlArr.push(inputObj.val());
  287. }
  288. urlArr.push(data.url)
  289. var result = urlArr.join(",");
  290. if (maxcount > 0) {
  291. var nums = value === '' ? 0 : value.split(/\,/).length;
  292. var files = data.url !== "" ? data.url.split(/\,/) : [];
  293. var remains = maxcount - nums;
  294. if (files.length > remains) {
  295. Toastr.error(__('You can choose up to %d file%s', remains));
  296. return false;
  297. }
  298. }
  299. inputObj.val(result).trigger("change").trigger("validate");
  300. } else {
  301. $("#" + input_id).val(data.url).trigger("change").trigger("validate");
  302. }
  303. }
  304. });
  305. return false;
  306. });
  307. }
  308. },
  309. fieldlist: function (form) {
  310. //绑定fieldlist
  311. if ($(".fieldlist", form).size() > 0) {
  312. require(['dragsort', 'template'], function (undefined, Template) {
  313. //刷新隐藏textarea的值
  314. var refresh = function (name) {
  315. var data = {};
  316. var textarea = $("textarea[name='" + name + "']", form);
  317. var container = $(".fieldlist[data-name='" + name + "']");
  318. var template = container.data("template");
  319. $.each($("input,select,textarea", container).serializeArray(), function (i, j) {
  320. var reg = /\[(\w+)\]\[(\w+)\]$/g;
  321. var match = reg.exec(j.name);
  322. if (!match)
  323. return true;
  324. match[1] = "x" + parseInt(match[1]);
  325. if (typeof data[match[1]] == 'undefined') {
  326. data[match[1]] = {};
  327. }
  328. data[match[1]][match[2]] = j.value;
  329. });
  330. var result = template ? [] : {};
  331. $.each(data, function (i, j) {
  332. if (j) {
  333. if (!template) {
  334. if (j.key != '') {
  335. result[j.key] = j.value;
  336. }
  337. } else {
  338. result.push(j);
  339. }
  340. }
  341. });
  342. textarea.val(JSON.stringify(result));
  343. };
  344. //监听文本框改变事件
  345. $(document).on('change keyup changed', ".fieldlist input,.fieldlist textarea,.fieldlist select", function () {
  346. refresh($(this).closest(".fieldlist").data("name"));
  347. });
  348. //追加控制
  349. $(".fieldlist", form).on("click", ".btn-append,.append", function (e, row) {
  350. var container = $(this).closest(".fieldlist");
  351. var tagName = container.data("tag") || (container.is("table") ? "tr" : "dd");
  352. var index = container.data("index");
  353. var name = container.data("name");
  354. var template = container.data("template");
  355. var data = container.data();
  356. index = index ? parseInt(index) : 0;
  357. container.data("index", index + 1);
  358. row = row ? row : {};
  359. var vars = {index: index, name: name, data: data, row: row};
  360. var html = template ? Template(template, vars) : Template.render(Form.config.fieldlisttpl, vars);
  361. $(html).attr("fieldlist-item", true).insertBefore($(tagName + ":last", container));
  362. $(this).trigger("fa.event.appendfieldlist", $(this).closest(tagName).prev());
  363. });
  364. //移除控制
  365. $(".fieldlist", form).on("click", ".btn-remove", function () {
  366. var container = $(this).closest(".fieldlist");
  367. var tagName = container.data("tag") || (container.is("table") ? "tr" : "dd");
  368. $(this).closest(tagName).remove();
  369. refresh(container.data("name"));
  370. });
  371. //渲染数据&拖拽排序
  372. $(".fieldlist", form).each(function () {
  373. var container = this;
  374. var tagName = $(this).data("tag") || ($(this).is("table") ? "tr" : "dd");
  375. $(this).dragsort({
  376. itemSelector: tagName,
  377. dragSelector: ".btn-dragsort",
  378. dragEnd: function () {
  379. refresh($(this).closest(".fieldlist").data("name"));
  380. },
  381. placeHolderTemplate: $("<" + tagName + "/>")
  382. });
  383. var textarea = $("textarea[name='" + $(this).data("name") + "']", form);
  384. if (textarea.val() == '') {
  385. return true;
  386. }
  387. var template = $(this).data("template");
  388. textarea.on("fa.event.refreshfieldlist", function () {
  389. $("[fieldlist-item]", container).remove();
  390. var json = {};
  391. try {
  392. json = JSON.parse($(this).val());
  393. } catch (e) {
  394. }
  395. $.each(json, function (i, j) {
  396. $(".btn-append,.append", container).trigger('click', template ? j : {
  397. key: i, value: j
  398. });
  399. });
  400. });
  401. textarea.trigger("fa.event.refreshfieldlist");
  402. });
  403. });
  404. }
  405. },
  406. switcher: function (form) {
  407. form.on("click", "[data-toggle='switcher']", function () {
  408. if ($(this).hasClass("disabled")) {
  409. return false;
  410. }
  411. var switcher = $.proxy(function () {
  412. var input = $(this).prev("input");
  413. input = $(this).data("input-id") ? $("#" + $(this).data("input-id")) : input;
  414. if (input.size() > 0) {
  415. var yes = $(this).data("yes");
  416. var no = $(this).data("no");
  417. if (input.val() == yes) {
  418. input.val(no);
  419. $("i", this).addClass("fa-flip-horizontal text-gray");
  420. } else {
  421. input.val(yes);
  422. $("i", this).removeClass("fa-flip-horizontal text-gray");
  423. }
  424. input.trigger('change');
  425. }
  426. }, this);
  427. if (typeof $(this).data("confirm") !== 'undefined') {
  428. Layer.confirm($(this).data("confirm"), function (index) {
  429. switcher();
  430. Layer.close(index);
  431. });
  432. } else {
  433. switcher();
  434. }
  435. return false;
  436. });
  437. },
  438. bindevent: function (form) {
  439. },
  440. slider: function (form) {
  441. if ($(".slider", form).size() > 0) {
  442. require(['bootstrap-slider'], function () {
  443. $('.slider').removeClass('hidden').css('width', function (index, value) {
  444. return $(this).parents('.form-control').width();
  445. }).slider().on('slide', function (ev) {
  446. var data = $(this).data();
  447. if (typeof data.unit !== 'undefined') {
  448. $(this).parents('.form-control').siblings('.value').text(ev.value + data.unit);
  449. }
  450. });
  451. });
  452. }
  453. }
  454. },
  455. api: {
  456. submit: function (form, success, error, submit) {
  457. if (form.size() === 0) {
  458. Toastr.error("表单未初始化完成,无法提交");
  459. return false;
  460. }
  461. if (typeof submit === 'function') {
  462. if (false === submit.call(form, success, error)) {
  463. return false;
  464. }
  465. }
  466. var type = form.attr("method") ? form.attr("method").toUpperCase() : 'GET';
  467. type = type && (type === 'GET' || type === 'POST') ? type : 'GET';
  468. url = form.attr("action");
  469. url = url ? url : location.href;
  470. //修复当存在多选项元素时提交的BUG
  471. var params = {};
  472. var multipleList = $("[name$='[]']", form);
  473. if (multipleList.size() > 0) {
  474. var postFields = form.serializeArray().map(function (obj) {
  475. return $(obj).prop("name");
  476. });
  477. $.each(multipleList, function (i, j) {
  478. if (postFields.indexOf($(this).prop("name")) < 0) {
  479. params[$(this).prop("name")] = '';
  480. }
  481. });
  482. }
  483. //调用Ajax请求方法
  484. Fast.api.ajax({
  485. type: type,
  486. url: url,
  487. data: form.serialize() + (Object.keys(params).length > 0 ? '&' + $.param(params) : ''),
  488. dataType: 'json',
  489. complete: function (xhr) {
  490. var token = xhr.getResponseHeader('__token__');
  491. if (token) {
  492. $("input[name='__token__']").val(token);
  493. }
  494. }
  495. }, function (data, ret) {
  496. $('.form-group', form).removeClass('has-feedback has-success has-error');
  497. if (data && typeof data === 'object') {
  498. //刷新客户端token
  499. if (typeof data.token !== 'undefined') {
  500. $("input[name='__token__']").val(data.token);
  501. }
  502. //调用客户端事件
  503. if (typeof data.callback !== 'undefined' && typeof data.callback === 'function') {
  504. data.callback.call(form, data);
  505. }
  506. }
  507. if (typeof success === 'function') {
  508. if (false === success.call(form, data, ret)) {
  509. return false;
  510. }
  511. }
  512. }, function (data, ret) {
  513. if (data && typeof data === 'object' && typeof data.token !== 'undefined') {
  514. $("input[name='__token__']").val(data.token);
  515. }
  516. if (typeof error === 'function') {
  517. if (false === error.call(form, data, ret)) {
  518. return false;
  519. }
  520. }
  521. });
  522. return true;
  523. },
  524. bindevent: function (form, success, error, submit) {
  525. form = typeof form === 'object' ? form : $(form);
  526. var events = Form.events;
  527. events.bindevent(form);
  528. events.validator(form, success, error, submit);
  529. events.selectpicker(form);
  530. events.daterangepicker(form);
  531. events.selectpage(form);
  532. events.cxselect(form);
  533. events.citypicker(form);
  534. events.datetimepicker(form);
  535. events.faupload(form);
  536. events.faselect(form);
  537. events.fieldlist(form);
  538. events.slider(form);
  539. events.switcher(form);
  540. },
  541. custom: {}
  542. },
  543. };
  544. return Form;
  545. });