skuTable.js 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793
  1. /*
  2. * Name: skuTable
  3. * Author: cshaptx4869
  4. * Project: https://github.com/cshaptx4869/skuTable
  5. */
  6. layui.define(['jquery', 'form', 'upload', 'layer', 'sortable'], function (exports) {
  7. "use strict";
  8. var $ = layui.jquery,
  9. form = layui.form,
  10. upload = layui.upload,
  11. layer = layui.layer,
  12. sortable = layui.sortable,
  13. MOD_NAME = 'skuTable';
  14. //工具类
  15. class Util {
  16. static config = {
  17. shade: [0.02, '#000'],
  18. time: 2000
  19. };
  20. static msg = {
  21. // 成功消息
  22. success: function (msg, callback = null) {
  23. return layer.msg(msg, {
  24. icon: 1,
  25. shade: Util.config.shade,
  26. scrollbar: false,
  27. time: Util.config.time,
  28. shadeClose: true
  29. }, callback);
  30. },
  31. // 失败消息
  32. error: function (msg, callback = null) {
  33. return layer.msg(msg, {
  34. icon: 2,
  35. shade: Util.config.shade,
  36. scrollbar: false,
  37. time: Util.config.time,
  38. shadeClose: true
  39. }, callback);
  40. },
  41. // 警告消息框
  42. alert: function (msg, callback = null) {
  43. return layer.alert(msg, {end: callback, scrollbar: false});
  44. },
  45. // 对话框
  46. confirm: function (msg, ok, no) {
  47. var index = layer.confirm(msg, {title: '操作确认', btn: ['确认', '取消']}, function () {
  48. typeof ok === 'function' && ok.call(this);
  49. }, function () {
  50. typeof no === 'function' && no.call(this);
  51. Util.msg.close(index);
  52. });
  53. return index;
  54. },
  55. // 消息提示
  56. tips: function (msg, callback = null) {
  57. return layer.msg(msg, {
  58. time: Util.config.time,
  59. shade: Util.config.shade,
  60. end: callback,
  61. shadeClose: true
  62. });
  63. },
  64. // 加载中提示
  65. loading: function (msg, callback = null) {
  66. return msg ? layer.msg(msg, {
  67. icon: 16,
  68. scrollbar: false,
  69. shade: Util.config.shade,
  70. time: 0,
  71. end: callback
  72. }) : layer.load(2, {time: 0, scrollbar: false, shade: Util.config.shade, end: callback});
  73. },
  74. // 输入框
  75. prompt: function (option, callback = null) {
  76. return layer.prompt(option, callback);
  77. },
  78. // 关闭消息框
  79. close: function (index) {
  80. return layer.close(index);
  81. }
  82. };
  83. static request = {
  84. post: function (option, ok, no, ex) {
  85. return Util.request.ajax('post', option, ok, no, ex);
  86. },
  87. get: function (option, ok, no, ex) {
  88. return Util.request.ajax('get', option, ok, no, ex);
  89. },
  90. ajax: function (type, option, ok, no, ex) {
  91. type = type || 'get';
  92. option.url = option.url || '';
  93. option.data = option.data || {};
  94. option.statusName = option.statusName || 'code';
  95. option.statusCode = option.statusCode || 200;
  96. ok = ok || function (res) {
  97. };
  98. no = no || function (res) {
  99. var msg = res.msg == undefined ? '返回数据格式有误' : res.msg;
  100. Util.msg.error(msg);
  101. return false;
  102. };
  103. ex = ex || function (res) {
  104. };
  105. if (option.url == '') {
  106. Util.msg.error('请求地址不能为空');
  107. return false;
  108. }
  109. //var index = Util.msg.loading('加载中');
  110. $.ajax({
  111. url: option.url,
  112. type: type,
  113. contentType: "application/x-www-form-urlencoded; charset=UTF-8",
  114. dataType: "json",
  115. data: option.data,
  116. timeout: 60000,
  117. success: function (res) {
  118. //Util.msg.close(index);
  119. /*
  120. if (res[option.statusName] == option.statusCode) {
  121. return ok(res);
  122. } else {
  123. return no(res);
  124. }*/
  125. return ok(res);
  126. },
  127. error: function (xhr, textstatus, thrown) {
  128. Util.msg.error('Status:' + xhr.status + ',' + xhr.statusText + ',请稍后再试!', function () {
  129. ex(xhr);
  130. });
  131. return false;
  132. }
  133. });
  134. }
  135. };
  136. static tool = {
  137. uuid: function uuid(randomLength = 8) {
  138. return Number(Math.random().toString().substr(2, randomLength) + Date.now()).toString(36)
  139. }
  140. }
  141. }
  142. class SkuTable {
  143. options = {
  144. show : 1,//显示的选项,1是全显示,2是只显示单规格,3是只显示多规格
  145. isAttributeValue: 1, //规格类型 0统一规格 1多规格
  146. isAttributeElemId: 'fairy-is-attribute', //规格类型容器id
  147. specTableElemId: 'fairy-spec-table', //规格表容器id
  148. skuTableElemId: 'fairy-sku-table', //SKU表容器id
  149. rowspan: false, //是否开启SKU行合并,
  150. sortable: false, //规格拖拽排序
  151. skuIcon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDY3IDc5LjE1Nzc0NywgMjAxNS8wMy8zMC0yMzo0MDo0MiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjczN0RFNzU1MTk1RTExRTlBMEQ5OEEwMEM5NDNFOEE4IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjczN0RFNzU2MTk1RTExRTlBMEQ5OEEwMEM5NDNFOEE4Ij4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NzM3REU3NTMxOTVFMTFFOUEwRDk4QTAwQzk0M0U4QTgiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NzM3REU3NTQxOTVFMTFFOUEwRDk4QTAwQzk0M0U4QTgiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz5NHmJUAAAA+0lEQVR42pySPwsBYRzH7zk3KIP34CVIKSOrELLJdpuymyzew90kIwMZvACDsCldWZTFn5WQpPN5rlPXlXJ39en7/J57fn+fR9i2rYT5NNM0B2gC3n/6qHBQDMOwZNYg4LOQ3vcQld40/w6lC13Xbd/eHElC3G1JqL4DFWSNprz7BMpAFJ6YkW+jThaosuxAD/rY6R9lCmeq8IAmtKBA1A1OW9YjtIS9QvPYRZkcXo43EzqjF/mDQ5an7ALShTFk4eQOsgFTWeoNKl4nt68J0oYc1LHLbmtDp1IyLgPe4QCuMkIsyAWSuYbs5HD29DML8OTkHR9F2Ef+EWAAdwmkvBAtw94AAAAASUVORK5CYII=',
  152. uploadUrl: '',
  153. requestSuccessCode: 1, //请求成功返回状态码值
  154. specDataDelete: false, //开启规格删除
  155. productId: '', //商品id 配合specDataUrl和skuDataUrl使用
  156. specData: [], //规格数据
  157. specDataUrl: '', //优先级大于specData
  158. skuData: {}, //SKU数据
  159. skuDataUrl: '', //优先级大于skuDataUrl
  160. skuNameType: 0,
  161. skuNameDelimiter: '-',
  162. //统一规格配置项
  163. singleSkuTableConfig: {
  164. thead: [
  165. {title: '销售价(元)', icon: 'layui-icon-cols'},
  166. {title: '市场价(元)', icon: 'layui-icon-cols'},
  167. {title: '成本价(元)', icon: 'layui-icon-cols'},
  168. {title: '库存', icon: 'layui-icon-cols'},
  169. {title: '状态', icon: ''},
  170. ],
  171. tbody: [
  172. {type: 'input', field: 'price', value: '', verify: 'required|number', reqtext: '销售价不能为空'},
  173. {type: 'input', field: 'market_price', value: '0', verify: 'required|number', reqtext: '市场价不能为空'},
  174. {type: 'input', field: 'cost_price', value: '0', verify: 'required|number', reqtext: '成本价不能为空'},
  175. {type: 'input', field: 'stock', value: '0', verify: 'required|number', reqtext: '库存不能为空'},
  176. {type: 'select', field: 'status', option: [{key: '启用', value: '1'}, {key: '禁用', value: '0'}], verify: 'required', reqtext: '状态不能为空'},
  177. ]
  178. },
  179. //多规格配置项
  180. multipleSkuTableConfig: {
  181. thead: [
  182. {title: '图片', icon: ''},
  183. {title: '销售价(元)', icon: 'layui-icon-cols'},
  184. {title: '市场价(元)', icon: 'layui-icon-cols'},
  185. {title: '成本价(元)', icon: 'layui-icon-cols'},
  186. {title: '库存', icon: 'layui-icon-cols'},
  187. {title: '状态', icon: ''},
  188. ],
  189. tbody: [
  190. {type: 'image', field: 'picture', value: '', verify: '', reqtext: ''},
  191. {type: 'input', field: 'price', value: '', verify: 'required|number', reqtext: '销售价不能为空'},
  192. {type: 'input', field: 'market_price', value: '0', verify: 'required|number', reqtext: '市场价不能为空'},
  193. {type: 'input', field: 'cost_price', value: '0', verify: 'required|number', reqtext: '成本价不能为空'},
  194. {type: 'input', field: 'stock', value: '0', verify: 'required|number', reqtext: '库存不能为空'},
  195. {
  196. type: 'select',
  197. field: 'status',
  198. option: [{key: '启用', value: '1'}, {key: '禁用', value: '0'}],
  199. verify: '',
  200. reqtext: ''
  201. },
  202. ]
  203. }
  204. };
  205. constructor(options) {
  206. this.options = $.extend(this.options, options);
  207. if (this.options.skuDataUrl && this.options.productId) {
  208. Util.request.get({
  209. url: this.options.skuDataUrl,
  210. data: {
  211. product_id: this.options.productId
  212. },
  213. statusCode: this.options.requestSuccessCode
  214. }, (res) => {
  215. if (!res.data) {
  216. res.data = [];
  217. }
  218. this.options.skuData = res.data;
  219. this.css();
  220. this.render();
  221. this.listen();
  222. });
  223. } else {
  224. this.css();
  225. this.render();
  226. this.listen();
  227. }
  228. }
  229. css() {
  230. $('head').append(`<style>
  231. ${this.options.sortable ? `#${this.options.specTableElemId} tbody tr {cursor: move;transition:unset;-webkit-transition:unset;}` : ''}
  232. #${this.options.specTableElemId} tbody tr td:first-child > i.layui-icon-delete {
  233. margin-left:3px;
  234. }
  235. #${this.options.specTableElemId} tbody tr td:last-child > i.layui-icon-delete {
  236. margin-right:15px;
  237. margin-left:-7px;
  238. vertical-align: top;
  239. }
  240. #${this.options.specTableElemId} tbody tr td div.fairy-spec-value-create,
  241. #${this.options.specTableElemId} tfoot tr td div.fairy-spec-create {
  242. display: inline-block;
  243. color: #1E9FFF;
  244. vertical-align: middle;
  245. padding: 4px 6px;
  246. }
  247. #${this.options.specTableElemId} tfoot tr td div.layui-form-checkbox {
  248. margin-top: 0;
  249. }
  250. #${this.options.specTableElemId} tfoot tr td div.layui-form-checkbox > span{
  251. color: #1E9FFF;
  252. }
  253. #${this.options.skuTableElemId} tbody tr td > img.fairy-sku-img{
  254. width: 16px;
  255. height: 16px;
  256. padding: 6px;
  257. border: 1px solid #eceef1;
  258. vertical-align: middle;
  259. }
  260. #${this.options.specTableElemId} tbody tr td > i.layui-icon-delete,
  261. #${this.options.specTableElemId} tbody tr td div.fairy-spec-value-create,
  262. #${this.options.specTableElemId} tfoot tr td div.fairy-spec-create,
  263. #${this.options.skuTableElemId} thead tr th > i.layui-icon,
  264. #${this.options.skuTableElemId} tbody tr td > img.fairy-sku-img {
  265. cursor: pointer;
  266. }
  267. </style>`
  268. );
  269. }
  270. listen() {
  271. var that = this;
  272. /**
  273. * 监听规格类型选择
  274. */
  275. form.on('radio(fairy-is-attribute)', function (data) {
  276. that.options.isAttributeValue = data.value;
  277. that.render();
  278. });
  279. /**
  280. * 监听所选规格值的变化
  281. */
  282. form.on('checkbox(fairy-spec-filter)', function (data) {
  283. var specData = [];
  284. $.each($(`#${that.options.specTableElemId} tbody tr`), function () {
  285. var child = [];
  286. $.each($(this).find('input[type=checkbox]'), function () {
  287. child.push({id: $(this).val(), title: $(this).attr('title'), checked: $(this).is(':checked') ? '1' : '0'});
  288. });
  289. var specItem = {
  290. id: $(this).find('td').eq(0).data('spec-id'),
  291. title: $(this).find('td').eq(0).text(),
  292. child: child
  293. };
  294. specData.push(specItem);
  295. });
  296. that.options.specData = specData;
  297. //that.options.skuData = $.extend(that.options.skuData, that.getFormSkuData());
  298. that.resetRender(that.options.skuTableElemId);
  299. that.renderMultipleSkuTable();
  300. });
  301. /**
  302. * 监听批量赋值
  303. */
  304. $(document).on('click', `#${this.options.skuTableElemId} thead tr th i`, function () {
  305. var thisI = this;
  306. Util.msg.prompt({title: $(thisI).parent().text().trim() + '批量赋值'}, function (value, index, elem) {
  307. $.each($(`#${that.options.skuTableElemId} tbody tr`), function () {
  308. var index = that.options.rowspan ?
  309. $(thisI).parent().index() - ($(`#${that.options.skuTableElemId} thead th.fairy-spec-name`).length - $(this).children('td.fairy-spec-value').length) :
  310. $(thisI).parent().index();
  311. $(this).find('td').eq(index).children('input').val(value);
  312. });
  313. Util.msg.close(index);
  314. });
  315. });
  316. /**
  317. * 监听添加规格
  318. */
  319. $(document).on('click', `#${this.options.specTableElemId} .fairy-spec-create`, function () {
  320. layer.prompt({title: '添加规格'}, function (value, index, elem) {
  321. var specTitleArr = [];
  322. $.each(that.options.specData, function (k, v) {
  323. specTitleArr.push(v.title)
  324. })
  325. if (specTitleArr.includes(value)) {
  326. Util.msg.error('规格名已存在');
  327. } else {
  328. that.options.specData.push({id: Util.tool.uuid(), title: value, child: []});
  329. that.resetRender(that.options.specTableElemId);
  330. that.renderSpecTable();
  331. }
  332. Util.msg.close(index);
  333. });
  334. });
  335. /**
  336. * 监听添加规格值
  337. */
  338. $(document).on('click', `#${this.options.specTableElemId} .fairy-spec-value-create`, function () {
  339. var specId = $(this).parent('td').prev().data('spec-id');
  340. layer.prompt({title: '添加规格值'}, function (value, index, elem) {
  341. that.options.specData.forEach(function (v, i) {
  342. if (v.id == specId) {
  343. v.child.push({id: Util.tool.uuid(), title: value, checked: '0'});
  344. }
  345. });
  346. that.resetRender(that.options.specTableElemId);
  347. that.renderSpecTable();
  348. Util.msg.close(index);
  349. });
  350. });
  351. /**
  352. * 监听删除规格/规格值
  353. */
  354. $(document).on('click', `#${this.options.specTableElemId} i.layui-icon-delete`, function () {
  355. if (typeof $(this).attr('data-spec-index') !== "undefined") {
  356. that.options.specData.splice($(this).data('spec-index'), 1);
  357. that.resetRender([that.options.specTableElemId, that.options.skuTableElemId]);
  358. that.renderSpecTable();
  359. that.renderMultipleSkuTable();
  360. } else if (typeof $(this).attr('data-spec-value-index') !== "undefined") {
  361. var [i, ii] = $(this).data('spec-value-index').split('-');
  362. that.options.specData[i].child.splice(ii, 1);
  363. that.resetRender([that.options.specTableElemId, that.options.skuTableElemId]);
  364. that.renderSpecTable();
  365. that.renderMultipleSkuTable();
  366. }
  367. });
  368. /**
  369. * 监听规格表是否开启删除
  370. */
  371. form.on('checkbox(fairy-spec-delete-filter)', function (data) {
  372. that.options.specDataDelete = data.elem.checked;
  373. if (data.elem.checked) {
  374. $(`#${that.options.specTableElemId} tbody tr i.layui-icon-delete`).removeClass('layui-hide');
  375. } else {
  376. $(`#${that.options.specTableElemId} tbody tr i.layui-icon-delete`).addClass('layui-hide')
  377. }
  378. });
  379. /**
  380. * 图片移入放大/移出恢复
  381. */
  382. var imgLayerIndex = null;
  383. $(document).on('mouseenter', '.fairy-sku-img', function () {
  384. imgLayerIndex = layer.tips('<img src="' + $(this).attr('src') + '" style="max-width:200px;" alt=""/>', this, {
  385. tips: [2, 'rgba(41,41,41,.5)'],
  386. time: 0
  387. });
  388. }).on('mouseleave', '.fairy-sku-img', function () {
  389. layer.close(imgLayerIndex);
  390. })
  391. }
  392. /**
  393. * 渲染
  394. */
  395. render() {
  396. this.resetRender();
  397. this.renderIsAttribute(this.options.isAttributeValue);
  398. if (this.options.isAttributeValue == '2') {
  399. if (this.options.specDataUrl && this.options.productId) {
  400. Util.request.get({
  401. url: this.options.specDataUrl,
  402. productId: this.options.productId,
  403. statusCode: this.options.requestSuccessCode
  404. }, (res) => {
  405. if (!res.data) {
  406. res.data = [];
  407. }
  408. this.options.specData = res.data;
  409. this.renderSpecTable();
  410. this.renderMultipleSkuTable();
  411. });
  412. } else {
  413. this.renderSpecTable();
  414. this.renderMultipleSkuTable();
  415. }
  416. } else {
  417. this.renderSingleSkuTable();
  418. }
  419. }
  420. /**
  421. * 重新渲染
  422. * @param targets
  423. */
  424. resetRender(targets) {
  425. if (typeof targets === 'string') {
  426. $(`#${targets}`).parents('.dever_sku').replaceWith(`<div id="${targets}"></div>`);
  427. } else if ($.isArray(targets) && targets.length) {
  428. targets.forEach((item) => {
  429. $(`#${item}`).parents('.dever_sku').replaceWith(`<div id="${item}"></div>`);
  430. })
  431. } else {
  432. $(`#${this.options.isAttributeElemId}`).parents('.dever_sku').replaceWith(`<div id="${this.options.isAttributeElemId}"></div>`);
  433. $(`#${this.options.specTableElemId}`).parents('.dever_sku').replaceWith(`<div id="${this.options.specTableElemId}"></div>`);
  434. $(`#${this.options.skuTableElemId}`).parents('.dever_sku').replaceWith(`<div id="${this.options.skuTableElemId}"></div>`);
  435. }
  436. }
  437. /**
  438. * 渲染规格类型
  439. * @param checkedValue
  440. */
  441. renderIsAttribute(checkedValue) {
  442. var html = '';
  443. if (this.options.show == 1 || this.options.show == 2) {
  444. html += `<input type="radio" name="update_spec_type" title="单规格" value="1" lay-filter="fairy-is-attribute" ${checkedValue == '1' ? 'checked' : ''}>`;
  445. }
  446. if (this.options.show == 1 || this.options.show == 3) {
  447. html += `<input type="radio" name="update_spec_type" title="多规格" value="2" lay-filter="fairy-is-attribute" ${checkedValue == '2' ? 'checked' : ''}>`;
  448. }
  449. this.renderFormItem('规格类型', html, this.options.isAttributeElemId);
  450. }
  451. renderSingleSkuTable() {
  452. var that = this,
  453. table = `<table class="layui-table" id="${this.options.skuTableElemId}">`;
  454. table += '<thead>';
  455. table += '<tr>';
  456. this.options.singleSkuTableConfig.thead.forEach((item) => {
  457. table += `<th>${item.title}</th>`;
  458. });
  459. table += '</tr>';
  460. table += '</thead>';
  461. table += '<tbody>';
  462. table += '<tr>';
  463. that.options.singleSkuTableConfig.tbody.forEach(function (item) {
  464. switch (item.type) {
  465. case "select":
  466. table += '<td>';
  467. table += `<select style="width: 100%;" name="skus[-1][${item.field}]" lay-verify="${item.verify}" lay-reqtext="${item.reqtext}">`;
  468. item.option.forEach(function (o) {
  469. table += `<option value="${o.id}" ${that.options.skuData && that.options.skuData[-1] && that.options.skuData[-1][item.field] && that.options.skuData[item.field] == o.id ? 'selected' : ''}>${o.name}</option>`;
  470. });
  471. table += '</select>';
  472. table += '</td>';
  473. break;
  474. case "input":
  475. default:
  476. table += '<td>';
  477. table += `<input type="text" style="width: 100%;" name="skus[-1][${item.field}]" value="${that.options.skuData && that.options.skuData[-1] && that.options.skuData[-1][item.field] ? that.options.skuData[-1][item.field] : item.value}" class="layui-input" lay-verify="${item.verify}" lay-reqtext="${item.reqtext}">`;
  478. table += '</td>';
  479. break;
  480. }
  481. });
  482. table += '</tr>';
  483. table += '<tbody>';
  484. table += '</table>';
  485. this.renderFormItem('SKU', table, this.options.skuTableElemId);
  486. }
  487. /**
  488. * 渲染规格表
  489. */
  490. renderSpecTable() {
  491. var that = this,
  492. table = `<input type="hidden" name="spec" id="spec" value=""/><table class="layui-table" id="${this.options.specTableElemId}"><thead><tr><th>规格名</th><th>规格值</th></tr></thead><colgroup><col width="140"></colgroup><tbody>`;
  493. if (this.options.specData.length > 0) {
  494. $.each(this.options.specData, function (index, item) {
  495. table += that.options.sortable ? `<tr data-id="${item.id}">` : '<tr>';
  496. table += `<td data-spec-id="${item.id}">${item.title}<i class="layui-icon layui-icon-delete layui-anim layui-anim-scale ${that.options.specDataDelete ? '' : 'layui-hide'}" data-spec-index="${index}"></i></td>`;
  497. table += '<td>';
  498. if (item.child) {
  499. $.each(item.child, function (key, value) {
  500. table += `<input type="checkbox" title="${value.title}" lay-filter="fairy-spec-filter" value="${value.id}" ${value.checked == '1' ? 'checked' : ''} /><i class="layui-icon layui-icon-delete layui-anim layui-anim-scale ${that.options.specDataDelete ? '' : 'layui-hide'}" data-spec-value-index="${index}-${key}"></i> `;
  501. });
  502. }
  503. table += '<div class="fairy-spec-value-create"><i class="layui-icon layui-icon-addition"></i>添加规格值</div>'
  504. table += '</td>';
  505. table += '</tr>';
  506. });
  507. }
  508. table += '</tbody>';
  509. table += '<tfoot><tr><td colspan="2">';
  510. table += `<input type="checkbox" title="开启删除" lay-skin="primary" lay-filter="fairy-spec-delete-filter" ${that.options.specDataDelete ? 'checked' : ''}/>`;
  511. table += `<div class="fairy-spec-create"><i class="layui-icon layui-icon-addition"></i>添加规格</div>`;
  512. table += '</td></tr></tfoot>';
  513. table += '</table>';
  514. this.renderFormItem('商品规格', table, this.options.specTableElemId);
  515. if (this.options.specData.length > 0) {
  516. $('#spec').val(JSON.stringify(this.options.specData));
  517. }
  518. if (this.options.sortable) {
  519. /**
  520. * 拖拽
  521. */
  522. var sortableObj = sortable.create($(`#${this.options.specTableElemId} tbody`)[0], {
  523. animation: 1000,
  524. onEnd: (evt) => {
  525. //获取拖动后的排序
  526. var sortArr = sortableObj.toArray(),
  527. sortSpecData = [];
  528. this.options.specData.forEach((item) => {
  529. sortSpecData[sortArr.indexOf(String(item.id))] = item;
  530. });
  531. this.options.specData = sortSpecData;
  532. this.resetRender(that.options.skuTableElemId);
  533. this.renderMultipleSkuTable();
  534. },
  535. });
  536. }
  537. }
  538. /**
  539. * 渲染sku表
  540. */
  541. renderMultipleSkuTable() {
  542. var that = this, table = `<table class="layui-table" id="${this.options.skuTableElemId}">`;
  543. if ($(`#${this.options.specTableElemId} tbody input[type=checkbox]:checked`).length) {
  544. var prependThead = [], prependTbody = [];
  545. if (this.options.specData.length > 0) {
  546. $.each(this.options.specData, function (index, item) {
  547. var isShow = item.child.some(function (value, index, array) {
  548. return value.checked == '1' ? true : false;
  549. });
  550. if (isShow) {
  551. prependThead.push(item.title);
  552. var prependTbodyItem = [];
  553. if (item.child) {
  554. $.each(item.child, function (key, value) {
  555. if (value.checked == '1') {
  556. prependTbodyItem.push({id: value.id, title: value.title});
  557. }
  558. });
  559. }
  560. prependTbody.push(prependTbodyItem);
  561. }
  562. });
  563. $('#spec').val(JSON.stringify(that.options.specData));
  564. }
  565. table += '<colgroup>' + '<col width="70">'.repeat(prependThead.length + 1) + '</colgroup>';
  566. table += '<thead>';
  567. if (prependThead.length > 0) {
  568. var theadTr = '<tr>';
  569. theadTr += prependThead.map(function (t, i, a) {
  570. return '<th class="fairy-spec-name">' + t + '</th>';
  571. }).join('');
  572. this.options.multipleSkuTableConfig.thead.forEach(function (item) {
  573. theadTr += '<th>' + item.title + (item.icon ? ' <i class="layui-icon ' + item.icon + '"></i>' : '') + '</th>';
  574. });
  575. theadTr += '</tr>';
  576. table += theadTr;
  577. }
  578. table += '</thead>';
  579. if (this.options.rowspan) {
  580. var skuRowspanArr = [];
  581. prependTbody.forEach(function (v, i, a) {
  582. var num = 1, index = i;
  583. while (index < a.length - 1) {
  584. num *= a[index + 1].length;
  585. index++;
  586. }
  587. skuRowspanArr.push(num);
  588. });
  589. }
  590. var prependTbodyTrs = [];
  591. prependTbody.reduce(function (prev, cur, index, array) {
  592. var tmp = [];
  593. if (cur.length > 0) {
  594. prev.forEach(function (a) {
  595. cur.forEach(function (b) {
  596. tmp.push({id: a.id + that.options.skuNameDelimiter + b.id, title: a.title + that.options.skuNameDelimiter + b.title});
  597. })
  598. });
  599. } else {
  600. prev.forEach(function (a) {
  601. tmp.push({id: a.id, title: a.title});
  602. });
  603. }
  604. return tmp;
  605. }).forEach(function (item, index, array) {
  606. var tr = '<tr>';
  607. tr += item.title.split(that.options.skuNameDelimiter).map(function (t, i, a) {
  608. if (that.options.rowspan) {
  609. if (index % skuRowspanArr[i] === 0 && skuRowspanArr[i] > 1) {
  610. return '<td class="fairy-spec-value" rowspan="' + skuRowspanArr[i] + '">' + t + '</td>';
  611. } else if (skuRowspanArr[i] === 1) {
  612. return '<td class="fairy-spec-value">' + t + '</td>';
  613. } else {
  614. return '';
  615. }
  616. } else {
  617. return '<td>' + t + '</td>';
  618. }
  619. }).join('');
  620. that.options.multipleSkuTableConfig.tbody.forEach(function (c) {
  621. switch (c.type) {
  622. case "image":
  623. var skuValue = that.getSkuData(that.options.skuData, item, c);
  624. tr += '<td><input type="hidden" name="' + that.makeSkuName(item, c) + '" value="' + (skuValue ? skuValue : c.value) + '" lay-verify="' + c.verify + '" lay-reqtext="' + c.reqtext + '"><img class="fairy-sku-img" src="' + (skuValue ? skuValue : that.options.skuIcon) + '" alt="' + c.field + '图片"></td>';
  625. break;
  626. case "select":
  627. var skuValue = that.getSkuData(that.options.skuData, item, c);
  628. tr += '<td><select style="width: 100%;" name="' + that.makeSkuName(item, c) + '" lay-verify="' + c.verify + '" lay-reqtext="' + c.reqtext + '">';
  629. c.option.forEach(function (o) {
  630. tr += '<option value="' + o.id + '" ' + (skuValue && skuValue == o.id ? 'selected' : '') + '>' + o.name + '</option>';
  631. });
  632. tr += '</select></td>';
  633. break;
  634. case "input":
  635. default:
  636. var skuValue = that.getSkuData(that.options.skuData, item, c);
  637. tr += '<td><input style="width: 100%;" type="text" name="' + that.makeSkuName(item, c) + '" value="' + (skuValue ? skuValue : c.value) + '" class="layui-input" lay-verify="' + c.verify + '" lay-reqtext="' + c.reqtext + '"></td>';
  638. break;
  639. }
  640. });
  641. tr += '</tr>';
  642. tr && prependTbodyTrs.push(tr);
  643. });
  644. table += '<tbody>';
  645. if (prependTbodyTrs.length > 0) {
  646. table += prependTbodyTrs.join('');
  647. }
  648. table += '</tbody>';
  649. } else {
  650. table += '<thead></thead><tbody></tbody><tfoot><tr><td>请先选择规格值</td></tr></tfoot>';
  651. }
  652. table += '</table>';
  653. this.renderFormItem('SKU', table, this.options.skuTableElemId);
  654. //上传
  655. if (this.options.uploadUrl) {
  656. upload.render({
  657. elem: '.fairy-sku-img',
  658. url: this.options.uploadUrl,
  659. exts: 'png|jpg|ico|jpeg|gif',
  660. accept: 'images',
  661. acceptMime: 'image/*',
  662. multiple: false,
  663. xhr:xhrOnProgress,
  664. done: function (res) {
  665. if (res.status === that.options.requestSuccessCode) {
  666. var url = res.url;
  667. $(this.item).attr('src', url).prev().val(url);
  668. //Util.msg.success(res.msg);
  669. } else {
  670. var msg = res.msg == undefined ? '返回数据格式有误' : res.msg;
  671. Util.msg.error(msg);
  672. }
  673. return false;
  674. }
  675. });
  676. }
  677. }
  678. /**
  679. * 渲染表单项
  680. * @param label 标题
  681. * @param content 内容
  682. * @param target id
  683. * @param isRequired
  684. */
  685. renderFormItem(label, content, target, isRequired = true) {
  686. var html = '';
  687. html += '<div class="layui-form-item dever_sku">';
  688. html += `<label class="layui-form-label ${isRequired ? 'required' : ''}">${label.length ? label : ''}</label>`;
  689. html += '<div class="layui-input-block">';
  690. html += content;
  691. html += '</div>';
  692. html += '</div>';
  693. $(`#${target}`).replaceWith(html);
  694. form.render();
  695. }
  696. makeSkuName(sku, conf) {
  697. return 'skus[' + (this.options.skuNameType === 0 ? sku.id : sku.title) + '][' + conf.field + ']';
  698. }
  699. getSkuData(data, sku, conf) {
  700. if (data[(this.options.skuNameType === 0 ? sku.id : sku.title)]) {
  701. return data[(this.options.skuNameType === 0 ? sku.id : sku.title)][conf.field];
  702. } else {
  703. return false;
  704. }
  705. }
  706. getSpecData() {
  707. return this.options.specData;
  708. }
  709. getFormFilter() {
  710. var fariyForm = $('form.layui-form');
  711. if (!fariyForm.attr('lay-filter')) {
  712. fariyForm.attr('lay-filter', 'fairy-form-filter');
  713. }
  714. return fariyForm.attr('lay-filter');
  715. }
  716. getFormSkuData() {
  717. var skuData = {};
  718. console.info(this.getFormFilter(), form.val(this.getFormFilter()));
  719. $.each(form.val(this.getFormFilter()), function (key, value) {
  720. if (key.startsWith('skus')) {
  721. skuData[key] = value;
  722. }
  723. });
  724. return skuData;
  725. }
  726. }
  727. exports(MOD_NAME, {
  728. render: function (options) {
  729. return new SkuTable(options);
  730. }
  731. })
  732. });