goods.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) {
  2. var Controller = {
  3. // 模板对象
  4. templates: {
  5. // 模板渲染工具方法
  6. render: function(template, data) {
  7. var result = template;
  8. Object.keys(data).forEach(function(key) {
  9. var regex = new RegExp('{{' + key + '}}', 'g');
  10. result = result.replace(regex, data[key] || '');
  11. });
  12. return result;
  13. },
  14. // 文本截断工具
  15. truncateText: function(text, maxLength) {
  16. if (!text || text.length <= maxLength) {
  17. return text;
  18. }
  19. return text.substring(0, maxLength) + '...';
  20. },
  21. // 安全转义HTML
  22. escapeHtml: function(text) {
  23. if (typeof Fast !== 'undefined' && Fast.api && Fast.api.escape) {
  24. return Fast.api.escape(text);
  25. }
  26. return $('<div>').text(text).html();
  27. },
  28. // 商品信息模板
  29. goodsInfo: function(row) {
  30. var template = '<div class="goods-info-container" style="display: flex; align-items: center; padding: 8px 0;">' +
  31. '<!-- 商品图片 -->' +
  32. '<div class="goods-image" style="margin-right: 15px; flex-shrink: 0;">' +
  33. '<img src="{{imageUrl}}" ' +
  34. 'style="width: 64px; height: 64px; object-fit: cover; border-radius: 6px; border: 1px solid #e1e5e9; box-shadow: 0 1px 3px rgba(0,0,0,0.1);" ' +
  35. 'onerror="this.src=\'/assets/img/goods-default.png\'" />' +
  36. '</div>' +
  37. '<!-- 商品信息 -->' +
  38. '<div class="goods-content" style="flex: 1; min-width: 0; line-height: 1.4;">' +
  39. '<!-- 商品标题 -->' +
  40. '<div class="goods-title" style="font-weight: 600; color: #495057; margin-bottom: 6px; font-size: 14px;">' +
  41. '<a href="javascript:;" style="color: #495057; text-decoration: none; word-break: break-all; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;">' +
  42. '{{title}}' +
  43. '</a>' +
  44. '{{specBadge}}' +
  45. '</div>' +
  46. '<!-- 商品描述 -->' +
  47. '{{subtitle}}' +
  48. '<!-- 商品元信息 -->' +
  49. '<div class="goods-meta" style="color: #6c757d; font-size: 11px; margin-top: 6px;">' +
  50. '<span class="goods-id">ID: {{id}}</span>' +
  51. '{{typeInfo}}' +
  52. '</div>' +
  53. '</div>' +
  54. '</div>';
  55. // 数据填充
  56. var data = {
  57. imageUrl: row.image || '/assets/img/goods-default.png',
  58. title: Controller.templates.truncateText(Controller.templates.escapeHtml(row.title || '未命名商品'), 50),
  59. id: row.id || '-',
  60. subtitle: row.subtitle ?
  61. '<div class="goods-subtitle" style="color: #6c757d; font-size: 12px; margin-bottom: 4px; line-height: 1.3; display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden;" title="' +
  62. Controller.templates.escapeHtml(row.subtitle) + '">' +
  63. Controller.templates.truncateText(Controller.templates.escapeHtml(row.subtitle), 60) +
  64. '</div>' : '',
  65. specBadge: (row.spec_type == 1 || (row.spec_type_text && row.spec_type_text === '多规格')) ?
  66. ' <span class="goods-spec-badge">多规格</span>' : '',
  67. typeInfo: row.status_text ?
  68. ' | <span class="goods-status">' + Controller.templates.escapeHtml(row.status_text) + '</span>' : ''
  69. };
  70. return Controller.templates.render(template, data);
  71. },
  72. // 分销规则状态模板
  73. commissionStatus: function(row) {
  74. if (!row.commission_goods) {
  75. return '<span class="label label-danger">不参与</span>';
  76. }
  77. var participateStatus = row.commission_goods.status;
  78. if (participateStatus == 0) {
  79. return '<span class="label label-danger">不参与</span>';
  80. }
  81. var ruleTypeList = Config.commission_goods_rule_type_list || {
  82. '0': '默认规则',
  83. '1': '独立规则',
  84. '2': '批量规则'
  85. };
  86. var colorMap = {
  87. '0': 'info',
  88. '1': 'success',
  89. '2': 'warning'
  90. };
  91. var value = row.commission_goods.rule_type;
  92. var text = ruleTypeList[value] || '默认规则';
  93. var color = colorMap[value] || 'info';
  94. return '<span class="label label-' + color + '">' + text + '</span>';
  95. },
  96. // 商品状态模板
  97. goodsStatus: function(row) {
  98. var statusMap = {
  99. '0': {text: '仓库中', color: 'default'},
  100. '1': {text: '上架中', color: 'success'},
  101. '2': {text: '已售罄', color: 'warning'},
  102. '3': {text: '已下架', color: 'danger'}
  103. };
  104. var status = statusMap[row.status] || {text: '未知', color: 'default'};
  105. return '<span class="label label-' + status.color + '">' + status.text + '</span>';
  106. }
  107. },
  108. index: function () {
  109. // 添加自定义样式
  110. Controller.addCustomStyles();
  111. // 初始化表格参数
  112. Table.api.init({
  113. extend: {
  114. index_url: 'commission/goods/index' + location.search,
  115. add_url: '',
  116. commission_url: 'commission/goods/commission',
  117. del_url: '',
  118. multi_url: '',
  119. import_url: '',
  120. table: 'shop_goods',
  121. dragsort_url: ''
  122. }
  123. });
  124. var table = $("#table");
  125. // 初始化表格
  126. table.bootstrapTable({
  127. url: $.fn.bootstrapTable.defaults.extend.index_url,
  128. pk: 'id',
  129. sortName: 'id',
  130. sortable: true,
  131. sort: 'desc',
  132. columns: [
  133. [
  134. {field: 'id', title: __('ID'), width: 80},
  135. {field: 'title', title: __('商品信息'), operate: 'LIKE', width: 400, formatter: function(value, row, index) {
  136. return Controller.templates.goodsInfo(row);
  137. }},
  138. {field: 'price', title: __('价格'), operate: 'BETWEEN', width: 100},
  139. {field: 'commission_goods.rule_type', title: __('分销规则'), width: 120, formatter: function(value, row, index) {
  140. return Controller.templates.commissionStatus(row);
  141. }},
  142. {field: 'status', title: __('商品状态'), width: 100, formatter: function(value, row, index) {
  143. return Controller.templates.goodsStatus(row);
  144. }},
  145. {field: 'operate', title: __('操作'), table: table, events: Table.api.events.operate, width: 150,
  146. buttons: [
  147. {
  148. name: 'commission',
  149. text: __('设置佣金'),
  150. title: __('设置佣金'),
  151. classname: 'btn btn-xs btn-success btn-dialog',
  152. icon: 'fa fa-cog',
  153. url: 'commission/goods/commission',
  154. callback: function(data) {
  155. // 弹窗回传回调,刷新表格
  156. table.bootstrapTable('refresh');
  157. }
  158. }
  159. ],
  160. formatter: Table.api.formatter.operate}
  161. ]
  162. ]
  163. });
  164. // 为表格绑定事件
  165. Table.api.bindevent(table);
  166. },
  167. // 添加自定义样式
  168. addCustomStyles: function() {
  169. var styles = `
  170. <style>
  171. /* 商品信息容器样式优化 */
  172. .goods-info-container:hover {
  173. background-color: #f8f9fa;
  174. border-radius: 6px;
  175. transition: background-color 0.2s ease;
  176. }
  177. .goods-image img {
  178. transition: transform 0.2s ease;
  179. }
  180. .goods-info-container:hover .goods-image img {
  181. transform: scale(1.05);
  182. }
  183. .goods-title a:hover {
  184. color: #18bc9c !important;
  185. transition: color 0.2s ease;
  186. }
  187. /* 多规格标签样式 */
  188. .goods-spec-badge {
  189. background: linear-gradient(135deg, #18bc9c, #16a085);
  190. color: white;
  191. font-size: 10px;
  192. padding: 2px 8px;
  193. border-radius: 12px;
  194. margin-left: 8px;
  195. font-weight: 500;
  196. box-shadow: 0 1px 3px rgba(24, 188, 156, 0.3);
  197. }
  198. /* 表格行间距优化 */
  199. #table .bootstrap-table .fixed-table-body .table tbody tr td {
  200. padding: 12px 8px;
  201. vertical-align: middle;
  202. border-bottom: 1px solid #e9ecef;
  203. }
  204. /* 操作按钮样式 */
  205. .btn-commission {
  206. background: linear-gradient(135deg, #18bc9c, #16a085);
  207. border: none;
  208. color: white;
  209. font-weight: 500;
  210. transition: all 0.2s ease;
  211. }
  212. .btn-commission:hover {
  213. background: linear-gradient(135deg, #1dd1a1, #18bc9c);
  214. transform: translateY(-1px);
  215. box-shadow: 0 2px 8px rgba(24, 188, 156, 0.3);
  216. }
  217. </style>
  218. `;
  219. // 添加样式到页面
  220. if (!$('#commission-goods-styles').length) {
  221. $('head').append(styles.replace('<style>', '<style id="commission-goods-styles">'));
  222. }
  223. },
  224. detail: function () {
  225. Controller.api.bindevent();
  226. },
  227. edit: function () {
  228. Controller.api.bindevent();
  229. },
  230. commission: function () {
  231. // 佣金设置页面
  232. Controller.api.bindevent();
  233. // 佣金规则类型切换
  234. $(document).on('change', 'input[name="rule_type"]', function() {
  235. var ruleType = $(this).val();
  236. Controller.updateFormState(ruleType);
  237. });
  238. // 更新表单状态的方法
  239. Controller.updateFormState = function(ruleType) {
  240. if (ruleType == '0') { // 默认规则
  241. // 只禁用高级配置项,保持"是否参与"和"分销商业绩"可编辑
  242. $('input[name="level"], input[name="self_buy"], input[name="reward_type"], input[name="reward_event"]').prop('disabled', true);
  243. // "是否参与"和"分销商业绩"保持可编辑
  244. $('input[name="status"], input[name="order_status"]').prop('disabled', false);
  245. // 显示默认规则的佣金比例
  246. $('.default-rule-value').show();
  247. $('.custom-rule-input').hide();
  248. $('.default-rule-help').show();
  249. $('.custom-rule-help').hide();
  250. // 添加部分只读样式
  251. $('.commission-form').addClass('readonly-mode');
  252. } else if (ruleType == '1' || ruleType == '2') { // 独立规则或批量规则
  253. // 启用所有配置项
  254. $('input[name="status"], input[name="order_status"], input[name="level"], input[name="self_buy"], input[name="reward_type"], input[name="reward_event"]').prop('disabled', false);
  255. // 显示自定义规则的输入框
  256. $('.default-rule-value').hide();
  257. $('.custom-rule-input').show();
  258. $('.default-rule-help').hide();
  259. $('.custom-rule-help').show();
  260. // 移除只读样式
  261. $('.commission-form').removeClass('readonly-mode');
  262. }
  263. };
  264. // 初始化规则显示状态
  265. var checkedRuleType = $('input[name="rule_type"]:checked').val() || '0';
  266. Controller.updateFormState(checkedRuleType);
  267. // 初始化已有数据
  268. if (typeof Config.commission_data !== 'undefined' && Config.commission_data) {
  269. var commissionData = Config.commission_data;
  270. // 设置规则类型
  271. if (commissionData.rule_type !== undefined) {
  272. $('input[name="rule_type"][value="' + commissionData.rule_type + '"]').prop('checked', true);
  273. }
  274. // 设置基本配置
  275. if (commissionData.status !== undefined) {
  276. $('input[name="status"][value="' + commissionData.status + '"]').prop('checked', true);
  277. }
  278. if (commissionData.order_status !== undefined) {
  279. $('input[name="order_status"][value="' + commissionData.order_status + '"]').prop('checked', true);
  280. }
  281. // 从config中获取扩展配置
  282. var config = commissionData.config || {};
  283. if (config.self_buy !== undefined) {
  284. $('input[name="self_buy"][value="' + config.self_buy + '"]').prop('checked', true);
  285. }
  286. if (config.level !== undefined) {
  287. $('input[name="level"][value="' + config.level + '"]').prop('checked', true);
  288. }
  289. if (config.reward_type !== undefined) {
  290. $('input[name="reward_type"][value="' + config.reward_type + '"]').prop('checked', true);
  291. }
  292. if (config.reward_event !== undefined) {
  293. $('input[name="reward_event"][value="' + config.reward_event + '"]').prop('checked', true);
  294. }
  295. // 最后触发状态更新
  296. Controller.updateFormState($('input[name="rule_type"]:checked').val() || '0');
  297. } else {
  298. // 没有数据时,设置默认值
  299. $('input[name="rule_type"][value="0"]').prop('checked', true);
  300. $('input[name="status"][value="0"]').prop('checked', true);
  301. $('input[name="order_status"][value="1"]').prop('checked', true);
  302. $('input[name="level"][value="3"]').prop('checked', true);
  303. $('input[name="self_buy"][value="1"]').prop('checked', true);
  304. $('input[name="reward_type"][value="pay_price"]').prop('checked', true);
  305. $('input[name="reward_event"][value="paid"]').prop('checked', true);
  306. // 触发状态更新
  307. Controller.updateFormState('0');
  308. }
  309. },
  310. api: {
  311. bindevent: function () {
  312. Form.api.bindevent($("form[role=form]"), function(data, ret) {
  313. // 表单提交成功回调
  314. Fast.api.close(ret);
  315. });
  316. // 绑定独立设置变化事件
  317. $(document).on('change', 'input[name="row[self_rules]"]', function() {
  318. var value = $(this).val();
  319. var commissionConfigContainer = $('.commission-config-container');
  320. if (value == '1') {
  321. commissionConfigContainer.show();
  322. } else {
  323. commissionConfigContainer.hide();
  324. }
  325. });
  326. }
  327. }
  328. };
  329. return Controller;
  330. });