require-form.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, Upload, Validator) {
  2. var Form = {
  3. config: {
  4. },
  5. events: {
  6. validator: function (form, success, error, submit) {
  7. if (!form.is("form"))
  8. return;
  9. //绑定表单事件
  10. form.validator($.extend({
  11. validClass: 'has-success',
  12. invalidClass: 'has-error',
  13. bindClassTo: '.form-group',
  14. formClass: 'n-default n-bootstrap',
  15. msgClass: 'n-right',
  16. stopOnError: true,
  17. display: function (elem) {
  18. return $(elem).closest('.form-group').find(".control-label").text().replace(/\:/, '');
  19. },
  20. dataFilter: function (data) {
  21. if (data.code === 1) {
  22. return "";
  23. } else {
  24. return data.msg;
  25. }
  26. },
  27. target: function (input) {
  28. var $formitem = $(input).closest('.form-group'),
  29. $msgbox = $formitem.find('span.msg-box');
  30. if (!$msgbox.length) {
  31. return [];
  32. }
  33. return $msgbox;
  34. },
  35. valid: function (ret) {
  36. var that = this, submitBtn = $(".layer-footer [type=submit]", form);
  37. that.holdSubmit();
  38. $(".layer-footer [type=submit]", form).addClass("disabled");
  39. //验证通过提交表单
  40. Form.api.submit($(ret), function (data, ret) {
  41. that.holdSubmit(false);
  42. submitBtn.removeClass("disabled");
  43. if (false === $(this).triggerHandler("success.form", [data, ret])) {
  44. return false;
  45. }
  46. if (typeof success === 'function') {
  47. if (false === success.call($(this), data, ret)) {
  48. return false;
  49. }
  50. }
  51. //提示及关闭当前窗口
  52. var msg = ret.hasOwnProperty("msg") && ret.msg !== "" ? ret.msg : __('Operation completed');
  53. parent.Toastr.success(msg);
  54. parent.$(".btn-refresh").trigger("click");
  55. var index = parent.Layer.getFrameIndex(window.name);
  56. parent.Layer.close(index);
  57. return false;
  58. }, function (data, ret) {
  59. that.holdSubmit(false);
  60. if (false === $(this).triggerHandler("error.form", [data, ret])) {
  61. return false;
  62. }
  63. submitBtn.removeClass("disabled");
  64. if (typeof error === 'function') {
  65. if (false === error.call($(this), data, ret)) {
  66. return false;
  67. }
  68. }
  69. }, submit);
  70. return false;
  71. }
  72. }, form.data("validator-options") || {}));
  73. //移除提交按钮的disabled类
  74. $(".layer-footer [type=submit],.fixed-footer [type=submit],.normal-footer [type=submit]", form).removeClass("disabled");
  75. },
  76. selectpicker: function (form) {
  77. //绑定select元素事件
  78. if ($(".selectpicker", form).size() > 0) {
  79. require(['bootstrap-select', 'bootstrap-select-lang'], function () {
  80. $('.selectpicker', form).selectpicker();
  81. });
  82. }
  83. },
  84. selectpage: function (form) {
  85. //绑定selectpage元素事件
  86. if ($(".selectpage", form).size() > 0) {
  87. require(['selectpage'], function () {
  88. $('.selectpage', form).selectPage({
  89. eAjaxSuccess: function (data) {
  90. data.list = typeof data.rows !== 'undefined' ? data.rows : (typeof data.list !== 'undefined' ? data.list : []);
  91. data.totalRow = typeof data.total !== 'undefined' ? data.total : (typeof data.totalRow !== 'undefined' ? data.totalRow : data.list.length);
  92. return data;
  93. }
  94. });
  95. });
  96. //给隐藏的元素添加上validate验证触发事件
  97. $(document).on("change", ".sp_hidden", function () {
  98. $(this).trigger("validate");
  99. });
  100. $(document).on("change", ".sp_input", function () {
  101. $(this).closest(".sp_container").find(".sp_hidden").trigger("change");
  102. });
  103. $(form).on("reset", function () {
  104. setTimeout(function () {
  105. $('.selectpage', form).selectPageClear();
  106. }, 1);
  107. });
  108. }
  109. },
  110. cxselect: function (form) {
  111. //绑定cxselect元素事件
  112. if ($("[data-toggle='cxselect']", form).size() > 0) {
  113. require(['cxselect'], function () {
  114. $.cxSelect.defaults.jsonName = 'name';
  115. $.cxSelect.defaults.jsonValue = 'value';
  116. $.cxSelect.defaults.jsonSpace = 'data';
  117. $("[data-toggle='cxselect']", form).cxSelect();
  118. });
  119. }
  120. },
  121. citypicker: function (form) {
  122. //绑定城市远程插件
  123. if ($("[data-toggle='city-picker']", form).size() > 0) {
  124. require(['citypicker'], function () {});
  125. }
  126. },
  127. datetimepicker: function (form) {
  128. //绑定日期时间元素事件
  129. if ($(".datetimepicker", form).size() > 0) {
  130. require(['bootstrap-datetimepicker'], function () {
  131. var options = {
  132. format: 'YYYY-MM-DD HH:mm:ss',
  133. icons: {
  134. time: 'fa fa-clock-o',
  135. date: 'fa fa-calendar',
  136. up: 'fa fa-chevron-up',
  137. down: 'fa fa-chevron-down',
  138. previous: 'fa fa-chevron-left',
  139. next: 'fa fa-chevron-right',
  140. today: 'fa fa-history',
  141. clear: 'fa fa-trash',
  142. close: 'fa fa-remove'
  143. },
  144. showTodayButton: true,
  145. showClose: true
  146. };
  147. $('.datetimepicker', form).parent().css('position', 'relative');
  148. $('.datetimepicker', form).datetimepicker(options);
  149. });
  150. }
  151. },
  152. daterangepicker: function (form) {
  153. //绑定日期时间元素事件
  154. if ($(".datetimerange", form).size() > 0) {
  155. require(['bootstrap-daterangepicker'], function () {
  156. var ranges = {};
  157. ranges[__('Today')] = [Moment().startOf('day'), Moment().endOf('day')];
  158. ranges[__('Yesterday')] = [Moment().subtract(1, 'days').startOf('day'), Moment().subtract(1, 'days').endOf('day')];
  159. ranges[__('Last 7 Days')] = [Moment().subtract(6, 'days').startOf('day'), Moment().endOf('day')];
  160. ranges[__('Last 30 Days')] = [Moment().subtract(29, 'days').startOf('day'), Moment().endOf('day')];
  161. ranges[__('This Month')] = [Moment().startOf('month'), Moment().endOf('month')];
  162. ranges[__('Last Month')] = [Moment().subtract(1, 'month').startOf('month'), Moment().subtract(1, 'month').endOf('month')];
  163. var options = {
  164. timePicker: false,
  165. autoUpdateInput: false,
  166. timePickerSeconds: true,
  167. timePicker24Hour: true,
  168. autoApply: true,
  169. locale: {
  170. format: 'YYYY-MM-DD HH:mm:ss',
  171. customRangeLabel: __("Custom Range"),
  172. applyLabel: __("Apply"),
  173. cancelLabel: __("Clear"),
  174. },
  175. ranges: ranges,
  176. };
  177. var origincallback = function (start, end) {
  178. $(this.element).val(start.format(options.locale.format) + " - " + end.format(options.locale.format));
  179. $(this.element).trigger('blur');
  180. };
  181. $(".datetimerange", form).each(function () {
  182. var callback = typeof $(this).data('callback') == 'function' ? $(this).data('callback') : origincallback;
  183. $(this).on('apply.daterangepicker', function (ev, picker) {
  184. callback.call(picker, picker.startDate, picker.endDate);
  185. });
  186. $(this).on('cancel.daterangepicker', function (ev, picker) {
  187. $(this).val('').trigger('blur');
  188. });
  189. $(this).daterangepicker($.extend({}, options, $(this).data()), callback);
  190. });
  191. });
  192. }
  193. },
  194. plupload: function (form) {
  195. //绑定plupload上传元素事件
  196. if ($(".plupload", form).size() > 0) {
  197. Upload.api.plupload($(".plupload", form));
  198. }
  199. },
  200. faselect: function (form) {
  201. //绑定fachoose选择附件事件
  202. if ($(".fachoose", form).size() > 0) {
  203. $(".fachoose", form).on('click', function () {
  204. var that = this;
  205. var multiple = $(this).data("multiple") ? $(this).data("multiple") : false;
  206. var mimetype = $(this).data("mimetype") ? $(this).data("mimetype") : '';
  207. parent.Fast.api.open("general/attachment/select?element_id=" + $(this).attr("id") + "&multiple=" + multiple + "&mimetype=" + mimetype, __('Choose'), {
  208. callback: function (data) {
  209. var button = $("#" + $(that).attr("id"));
  210. var maxcount = $(button).data("maxcount");
  211. var input_id = $(button).data("input-id") ? $(button).data("input-id") : "";
  212. maxcount = typeof maxcount !== "undefined" ? maxcount : 0;
  213. if (input_id && data.multiple) {
  214. var urlArr = [];
  215. var inputObj = $("#" + input_id);
  216. var value = $.trim(inputObj.val());
  217. if (value !== "") {
  218. urlArr.push(inputObj.val());
  219. }
  220. urlArr.push(data.url)
  221. var result = urlArr.join(",");
  222. if (maxcount > 0) {
  223. var nums = value === '' ? 0 : value.split(/\,/).length;
  224. var files = data.url !== "" ? data.url.split(/\,/) : [];
  225. var remains = maxcount - nums;
  226. if (files.length > remains) {
  227. Toastr.error(__('You can choose up to %d file%s', remains));
  228. return false;
  229. }
  230. }
  231. inputObj.val(result).trigger("change");
  232. } else {
  233. $("#" + input_id).val(data.url).trigger("change");
  234. }
  235. }
  236. });
  237. return false;
  238. });
  239. }
  240. },
  241. fieldlist: function (form) {
  242. if ($(".fieldlist", form).size() > 0) {
  243. $(".fieldlist", form).on("click", ".append", function () {
  244. var rel = parseInt($(this).closest("dl").attr("rel")) + 1;
  245. var name = $(this).closest("dl").data("name");
  246. $(this).closest("dl").attr("rel", rel);
  247. $('<dd class="form-inline"><input type="text" name="' + name + '[field][' + rel + ']" class="form-control" value="" size="10" /> <input type="text" name="' + name + '[value][' + rel + ']" class="form-control" value="" size="40" /> <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>').insertBefore($(this).parent());
  248. });
  249. $(".fieldlist", form).on("click", "dd .btn-remove", function () {
  250. $(this).parent().remove();
  251. });
  252. //拖拽排序
  253. require(['dragsort'], function () {
  254. //绑定拖动排序
  255. $("dl.fieldlist", form).dragsort({
  256. itemSelector: 'dd',
  257. dragSelector: ".btn-dragsort",
  258. dragEnd: function () {
  259. },
  260. placeHolderTemplate: "<dd></dd>"
  261. });
  262. });
  263. }
  264. },
  265. bindevent: function (form) {
  266. }
  267. },
  268. api: {
  269. submit: function (form, success, error, submit) {
  270. if (form.size() === 0)
  271. return Toastr.error("表单未初始化完成,无法提交");
  272. if (typeof submit === 'function') {
  273. if (false === submit.call(form)) {
  274. return false;
  275. }
  276. }
  277. var type = form.attr("method").toUpperCase();
  278. type = type && (type === 'GET' || type === 'POST') ? type : 'GET';
  279. url = form.attr("action");
  280. url = url ? url : location.href;
  281. //修复当存在多选项元素时提交的BUG
  282. var params = {};
  283. var multipleList = $("[name$='[]']", form);
  284. if (multipleList.size() > 0) {
  285. var postFields = form.serializeArray().map(function (obj) {
  286. return $(obj).prop("name");
  287. });
  288. $.each(multipleList, function (i, j) {
  289. if (postFields.indexOf($(this).prop("name")) < 0) {
  290. params[$(this).prop("name")] = '';
  291. }
  292. });
  293. }
  294. //调用Ajax请求方法
  295. Fast.api.ajax({
  296. type: type,
  297. url: url,
  298. data: form.serialize() + (Object.keys(params).length > 0 ? '&' + $.param(params) : ''),
  299. dataType: 'json',
  300. complete: function (xhr) {
  301. var token = xhr.getResponseHeader('__token__');
  302. if (token) {
  303. $("input[name='__token__']", form).val(token);
  304. }
  305. }
  306. }, function (data, ret) {
  307. $('.form-group', form).removeClass('has-feedback has-success has-error');
  308. if (data && typeof data === 'object') {
  309. //刷新客户端token
  310. if (typeof data.token !== 'undefined') {
  311. $("input[name='__token__']", form).val(data.token);
  312. }
  313. //调用客户端事件
  314. if (typeof data.callback !== 'undefined' && typeof data.callback === 'function') {
  315. data.callback.call(form, data);
  316. }
  317. }
  318. if (typeof success === 'function') {
  319. if (false === success.call(form, data, ret)) {
  320. return false;
  321. }
  322. }
  323. }, function (data, ret) {
  324. if (data && typeof data === 'object' && typeof data.token !== 'undefined') {
  325. $("input[name='__token__']", form).val(data.token);
  326. }
  327. if (typeof error === 'function') {
  328. if (false === error.call(form, data, ret)) {
  329. return false;
  330. }
  331. }
  332. });
  333. return false;
  334. },
  335. bindevent: function (form, success, error, submit) {
  336. form = typeof form === 'object' ? form : $(form);
  337. var events = Form.events;
  338. events.bindevent(form);
  339. events.validator(form, success, error, submit);
  340. events.selectpicker(form);
  341. events.daterangepicker(form);
  342. events.selectpage(form);
  343. events.cxselect(form);
  344. events.citypicker(form);
  345. events.datetimepicker(form);
  346. events.plupload(form);
  347. events.faselect(form);
  348. events.fieldlist(form);
  349. },
  350. custom: {}
  351. },
  352. };
  353. return Form;
  354. });