order.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) {
  2. var Controller = {
  3. index: function () {
  4. // 初始化表格参数
  5. Table.api.init({
  6. extend: {
  7. index_url: 'commission/order/index' + location.search,
  8. add_url: '',
  9. edit_url: 'commission/order/edit',
  10. del_url: 'commission/order/del',
  11. multi_url: 'commission/order/multi',
  12. import_url: 'commission/order/import',
  13. table: 'commission_order',
  14. }
  15. });
  16. var table = $("#table");
  17. // 获取后台配置
  18. var orderStatusTypes = Controller.api.parseConfigJson('commission_order_status_types', {
  19. '-2': __('已扣除'),
  20. '-1': __('已取消'),
  21. '0': __('不计入'),
  22. '1': __('已计入')
  23. });
  24. var rewardStatusTypes = Controller.api.parseConfigJson('commission_reward_status_types', {
  25. '-2': __('已退回'),
  26. '-1': __('已取消'),
  27. '0': __('未结算'),
  28. '1': __('已结算')
  29. });
  30. var displayConfig = Controller.api.parseConfigJson('commission_order_user_display_config', {
  31. showAvatar: true,
  32. avatarSize: 40,
  33. showMobile: true,
  34. showId: true,
  35. defaultAvatarUrl: '/assets/img/avatar.png'
  36. });
  37. // 格式化订单状态
  38. function formatOrderStatus(value, colorMap) {
  39. var statusConfig = colorMap[value];
  40. if (!statusConfig) return value;
  41. return '<span class="label label-' + statusConfig.color + '">' + statusConfig.text + '</span>';
  42. }
  43. // 格式化用户信息(买家或代理商)
  44. function formatUserInfo(user, userId, userType) {
  45. if (!user) return '-';
  46. return Controller.api.formatUserInfo(user, userId || user.id, userType, displayConfig);
  47. }
  48. // 统计信息处理
  49. function updateStats(data) {
  50. if (data.extend && data.extend.count) {
  51. var count = data.extend.count;
  52. // 格式化数字显示
  53. function formatNumber(number) {
  54. return (number || 0).toFixed(2);
  55. }
  56. $('#total-count').text(count.total || 0);
  57. $('#total-amount').text(formatNumber(count.total_amount));
  58. $('#total-commission').text(formatNumber(count.total_commission));
  59. $('#total-pending').text(formatNumber(count.total_commission_pending));
  60. $('#total-accounted').text(formatNumber(count.total_commission_accounted));
  61. $('#total-back').text(formatNumber(count.total_commission_back));
  62. $('#total-cancel').text(formatNumber(count.total_commission_cancel));
  63. }
  64. }
  65. // 初始化表格
  66. table.bootstrapTable({
  67. url: $.fn.bootstrapTable.defaults.extend.index_url,
  68. pk: 'id',
  69. sortName: 'id',
  70. fixedColumns: true, // 启用固定列功能
  71. fixedRightNumber: 1, // 固定右侧最后1列(操作列)
  72. responseHandler: function(res) {
  73. updateStats(res);
  74. return res;
  75. },
  76. columns: [
  77. [
  78. {checkbox: true},
  79. {field: 'id', title: __('ID'), width: 60},
  80. {field: 'order.order_sn', title: __('订单号'), operate: 'LIKE', formatter: function(value, row, index) {
  81. if (row.order && row.order.order_sn) {
  82. return '<a href="javascript:;" data-order-id="' + row.order_id + '" class="searchit order-detail">' + row.order.order_sn + '</a>';
  83. }
  84. return '-';
  85. }},
  86. {field: 'order_item.goods_title', title: __('商品信息'), operate: 'LIKE', width: 300, formatter: function(value, row, index) {
  87. if (row.order_item) {
  88. var item = row.order_item;
  89. var html = '<div style="display: flex; align-items: center; padding: 5px 0;">';
  90. // 商品图片
  91. var imageUrl = item.goods_image || item.image || '/assets/img/goods-default.png';
  92. if (imageUrl && !imageUrl.startsWith('http') && !imageUrl.startsWith('//')) {
  93. imageUrl = Fast.api.cdnurl ? Fast.api.cdnurl(imageUrl) : imageUrl;
  94. }
  95. html += '<div style="margin-right: 12px; flex-shrink: 0;">';
  96. html += '<img src="' + imageUrl + '" style="width: 60px; height: 60px; object-fit: cover; border-radius: 4px; border: 1px solid #e9ecef;" />';
  97. html += '</div>';
  98. // 商品信息
  99. html += '<div style="flex: 1; min-width: 0;">';
  100. // 商品标题
  101. var goodsTitle = item.goods_title || item.title || '-';
  102. html += '<div style="color: #337ab7; font-weight: bold; margin-bottom: 4px; line-height: 1.4;">';
  103. html += '<a href="javascript:;" data-goods-id="' + item.goods_id + '" class="searchit goods-detail" style="color: #337ab7; text-decoration: none;">';
  104. html += goodsTitle;
  105. html += '</a></div>';
  106. // 商品规格
  107. if (item.goods_sku || item.sku_name || item.specs) {
  108. var specs = item.goods_sku || item.sku_name || item.specs;
  109. html += '<div style="color: #6c757d; font-size: 12px; margin-bottom: 4px;">' + specs + '</div>';
  110. }
  111. // 商品价格和数量
  112. var price = item.price || item.goods_price || 0;
  113. var nums = item.nums || item.quantity || 1;
  114. html += '<div style="color: #28a745; font-weight: bold; font-size: 14px;">';
  115. html += '¥' + parseFloat(price).toFixed(2) + ' × ' + nums;
  116. html += '</div>';
  117. html += '</div></div>';
  118. return html;
  119. }
  120. return '-';
  121. }},
  122. {
  123. field: 'buyer.nickname',
  124. title: __('下单用户'),
  125. operate: 'LIKE',
  126. formatter: function (value, row, index) {
  127. return formatUserInfo(row.buyer, row.user_id, '用户');
  128. }
  129. },
  130. {
  131. field: 'agent.nickname',
  132. title: __('推广分销商'),
  133. operate: 'LIKE',
  134. formatter: function (value, row, index) {
  135. return formatUserInfo(row.agent, row.agent_id, '分销商');
  136. }
  137. },
  138. {field: 'amount', title: __('结算金额'), operate: 'BETWEEN'},
  139. {field: 'commission_order_status', title: __('业绩状态'), searchList: orderStatusTypes, formatter: function(value, row, index) {
  140. var statusMap = {
  141. '-2': {text: orderStatusTypes['-2'] || '已扣除', color: 'danger'},
  142. '-1': {text: orderStatusTypes['-1'] || '已取消', color: 'warning'},
  143. '0': {text: orderStatusTypes['0'] || '不计入', color: 'info'},
  144. '1': {text: orderStatusTypes['1'] || '已计入', color: 'success'}
  145. };
  146. return formatOrderStatus(value, statusMap);
  147. }},
  148. {field: 'commission_reward_status', title: __('佣金状态'), searchList: rewardStatusTypes, formatter: function(value, row, index) {
  149. var statusMap = {
  150. '-2': {text: rewardStatusTypes['-2'] || '已退回', color: 'danger'},
  151. '-1': {text: rewardStatusTypes['-1'] || '已取消', color: 'warning'},
  152. '0': {text: rewardStatusTypes['0'] || '未结算', color: 'info'},
  153. '1': {text: rewardStatusTypes['1'] || '已结算', color: 'success'}
  154. };
  155. return formatOrderStatus(value, statusMap);
  156. }},
  157. {field: 'commission_time', title: __('结算时间'), operate: 'RANGE', addclass: 'datetimerange', autocomplete: false, formatter: Table.api.formatter.datetime},
  158. {field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate,
  159. width: 150,
  160. buttons: [
  161. {
  162. name: 'back',
  163. text: __('手动退回'),
  164. title: __('手动退回佣金'),
  165. classname: 'btn btn-xs btn-danger',
  166. icon: 'fa fa-undo',
  167. visible: function (row) {
  168. return row.commission_reward_status == 1;
  169. },
  170. click: function (data) {
  171. Layer.confirm('确认手动退回此订单的佣金?', function(index) {
  172. Fast.api.ajax({
  173. url: 'commission/order/back',
  174. data: {commission_order_id: data.id, deduct_order_money: 1}
  175. }, function(data, ret) {
  176. table.bootstrapTable('refresh');
  177. Layer.close(index);
  178. });
  179. });
  180. }
  181. },
  182. {
  183. name: 'detail',
  184. text: __('订单详情'),
  185. title: __('查看订单详情'),
  186. classname: 'btn btn-xs btn-info',
  187. icon: 'fa fa-eye',
  188. visible: function (row) {
  189. return true; // 始终显示
  190. },
  191. click: function (data) {
  192. if (data.order_id) {
  193. Fast.api.open('order/order/detail?id=' + data.order_id, '订单详情', {
  194. area: ['90%', '90%']
  195. });
  196. } else {
  197. Layer.msg('订单ID不存在');
  198. }
  199. }
  200. }
  201. ],
  202. formatter: Table.api.formatter.operate}
  203. ]
  204. ]
  205. });
  206. // 为表格绑定事件
  207. Table.api.bindevent(table);
  208. // 绑定订单详情点击事件
  209. $(document).on('click', '.order-detail', function() {
  210. var orderId = $(this).data('order-id');
  211. Fast.api.open('order/order/detail?id=' + orderId, '订单详情');
  212. });
  213. // 绑定商品详情点击事件
  214. $(document).on('click', '.goods-detail', function() {
  215. var goodsId = $(this).data('goods-id');
  216. Fast.api.open('goods/goods/detail?id=' + goodsId, '商品详情');
  217. });
  218. },
  219. api: {
  220. // 解析Config中的JSON字符串的辅助函数
  221. parseConfigJson: function(configKey, defaultValue) {
  222. var configValue = Config[configKey] || defaultValue || {};
  223. // 如果是字符串,尝试解析JSON
  224. if (typeof configValue === 'string') {
  225. try {
  226. return JSON.parse(configValue);
  227. } catch (e) {
  228. return defaultValue || {};
  229. }
  230. }
  231. return configValue;
  232. },
  233. // 统一的用户信息展示方法
  234. formatUserInfo: function(user, userId, userType, config) {
  235. if (!user) return '-';
  236. config = config || {
  237. showAvatar: true,
  238. avatarSize: 40,
  239. showMobile: true,
  240. showId: true,
  241. defaultAvatarUrl: '/assets/img/avatar.png'
  242. };
  243. var avatar = user.avatar ? user.avatar : config.defaultAvatarUrl;
  244. var nickname = user.nickname || user.username || (userType || '用户');
  245. var mobile = user.mobile || '';
  246. // 处理头像URL
  247. var avatarUrl = avatar;
  248. if (avatar && !avatar.startsWith('http') && !avatar.startsWith('//')) {
  249. avatarUrl = Fast.api.cdnurl ? Fast.api.cdnurl(avatar) : avatar;
  250. }
  251. var typeColor = userType === '分销商' ? '#28a745' : (userType === '用户' ? '#17a2b8' : '#337ab7');
  252. var html = '<div style="display:flex;align-items:center;">';
  253. if (config.showAvatar) {
  254. html += '<img src="' + avatarUrl + '" style="width:' + config.avatarSize + 'px;height:' + config.avatarSize + 'px;border-radius:50%;margin-right:10px;" />';
  255. }
  256. html += '<div>' +
  257. '<div style="color:#337ab7;font-weight:bold;">' + nickname + '</div>' +
  258. '<div style="color:' + typeColor + ';font-size:12px;">';
  259. var info = [];
  260. if (config.showMobile && mobile) {
  261. info.push(mobile);
  262. }
  263. if (config.showId && userId) {
  264. info.push('ID: ' + userId);
  265. }
  266. html += info.join(' ') + '</div></div></div>';
  267. return html;
  268. },
  269. bindevent: function () {
  270. Form.api.bindevent($("form[role=form]"));
  271. }
  272. }
  273. };
  274. return Controller;
  275. });