|
@@ -16,12 +16,74 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
|
|
});
|
|
});
|
|
|
|
|
|
var table = $("#table");
|
|
var table = $("#table");
|
|
|
|
+
|
|
|
|
+ // 获取后台配置
|
|
|
|
+ var orderStatusTypes = Controller.api.parseConfigJson('commission_order_status_types', {
|
|
|
|
+ '-2': __('已扣除'),
|
|
|
|
+ '-1': __('已取消'),
|
|
|
|
+ '0': __('不计入'),
|
|
|
|
+ '1': __('已计入')
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ var rewardStatusTypes = Controller.api.parseConfigJson('commission_reward_status_types', {
|
|
|
|
+ '-2': __('已退回'),
|
|
|
|
+ '-1': __('已取消'),
|
|
|
|
+ '0': __('未结算'),
|
|
|
|
+ '1': __('已结算')
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ var displayConfig = Controller.api.parseConfigJson('commission_order_user_display_config', {
|
|
|
|
+ showAvatar: true,
|
|
|
|
+ avatarSize: 40,
|
|
|
|
+ showMobile: true,
|
|
|
|
+ showId: true,
|
|
|
|
+ defaultAvatarUrl: '/assets/img/avatar.png'
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ // 格式化订单状态
|
|
|
|
+ function formatOrderStatus(value, colorMap) {
|
|
|
|
+ var statusConfig = colorMap[value];
|
|
|
|
+ if (!statusConfig) return value;
|
|
|
|
+ return '<span class="label label-' + statusConfig.color + '">' + statusConfig.text + '</span>';
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 格式化用户信息(买家或代理商)
|
|
|
|
+ function formatUserInfo(user, userId, userType) {
|
|
|
|
+ if (!user) return '-';
|
|
|
|
+ return Controller.api.formatUserInfo(user, userId || user.id, userType, displayConfig);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 统计信息处理
|
|
|
|
+ function updateStats(data) {
|
|
|
|
+ if (data.extend && data.extend.count) {
|
|
|
|
+ var count = data.extend.count;
|
|
|
|
+
|
|
|
|
+ // 格式化数字显示
|
|
|
|
+ function formatNumber(number) {
|
|
|
|
+ return (number || 0).toFixed(2);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ $('#total-count').text(count.total || 0);
|
|
|
|
+ $('#total-amount').text(formatNumber(count.total_amount));
|
|
|
|
+ $('#total-commission').text(formatNumber(count.total_commission));
|
|
|
|
+ $('#total-pending').text(formatNumber(count.total_commission_pending));
|
|
|
|
+ $('#total-accounted').text(formatNumber(count.total_commission_accounted));
|
|
|
|
+ $('#total-back').text(formatNumber(count.total_commission_back));
|
|
|
|
+ $('#total-cancel').text(formatNumber(count.total_commission_cancel));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
// 初始化表格
|
|
// 初始化表格
|
|
table.bootstrapTable({
|
|
table.bootstrapTable({
|
|
url: $.fn.bootstrapTable.defaults.extend.index_url,
|
|
url: $.fn.bootstrapTable.defaults.extend.index_url,
|
|
pk: 'id',
|
|
pk: 'id',
|
|
sortName: 'id',
|
|
sortName: 'id',
|
|
|
|
+ fixedColumns: true, // 启用固定列功能
|
|
|
|
+ fixedRightNumber: 1, // 固定右侧最后1列(操作列)
|
|
|
|
+ responseHandler: function(res) {
|
|
|
|
+ updateStats(res);
|
|
|
|
+ return res;
|
|
|
|
+ },
|
|
columns: [
|
|
columns: [
|
|
[
|
|
[
|
|
{checkbox: true},
|
|
{checkbox: true},
|
|
@@ -32,85 +94,101 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
|
|
}
|
|
}
|
|
return '-';
|
|
return '-';
|
|
}},
|
|
}},
|
|
- {field: 'order_item.goods_title', title: __('商品名称'), operate: 'LIKE', formatter: function(value, row, index) {
|
|
|
|
- if (row.order_item && row.order_item.goods_title) {
|
|
|
|
- return '<a href="javascript:;" data-goods-id="' + row.order_item.goods_id + '" class="searchit goods-detail">' + row.order_item.goods_title + '</a>';
|
|
|
|
|
|
+ {field: 'order_item.goods_title', title: __('商品信息'), operate: 'LIKE', width: 300, formatter: function(value, row, index) {
|
|
|
|
+ if (row.order_item) {
|
|
|
|
+ var item = row.order_item;
|
|
|
|
+ var html = '<div style="display: flex; align-items: center; padding: 5px 0;">';
|
|
|
|
+
|
|
|
|
+ // 商品图片
|
|
|
|
+ var imageUrl = item.goods_image || item.image || '/assets/img/goods-default.png';
|
|
|
|
+ if (imageUrl && !imageUrl.startsWith('http') && !imageUrl.startsWith('//')) {
|
|
|
|
+ imageUrl = Fast.api.cdnurl ? Fast.api.cdnurl(imageUrl) : imageUrl;
|
|
|
|
+ }
|
|
|
|
+ html += '<div style="margin-right: 12px; flex-shrink: 0;">';
|
|
|
|
+ html += '<img src="' + imageUrl + '" style="width: 60px; height: 60px; object-fit: cover; border-radius: 4px; border: 1px solid #e9ecef;" />';
|
|
|
|
+ html += '</div>';
|
|
|
|
+
|
|
|
|
+ // 商品信息
|
|
|
|
+ html += '<div style="flex: 1; min-width: 0;">';
|
|
|
|
+
|
|
|
|
+ // 商品标题
|
|
|
|
+ var goodsTitle = item.goods_title || item.title || '-';
|
|
|
|
+ html += '<div style="color: #337ab7; font-weight: bold; margin-bottom: 4px; line-height: 1.4;">';
|
|
|
|
+ html += '<a href="javascript:;" data-goods-id="' + item.goods_id + '" class="searchit goods-detail" style="color: #337ab7; text-decoration: none;">';
|
|
|
|
+ html += goodsTitle;
|
|
|
|
+ html += '</a></div>';
|
|
|
|
+
|
|
|
|
+ // 商品规格
|
|
|
|
+ if (item.goods_sku || item.sku_name || item.specs) {
|
|
|
|
+ var specs = item.goods_sku || item.sku_name || item.specs;
|
|
|
|
+ html += '<div style="color: #6c757d; font-size: 12px; margin-bottom: 4px;">' + specs + '</div>';
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 商品价格和数量
|
|
|
|
+ var price = item.price || item.goods_price || 0;
|
|
|
|
+ var nums = item.nums || item.quantity || 1;
|
|
|
|
+ html += '<div style="color: #28a745; font-weight: bold; font-size: 14px;">';
|
|
|
|
+ html += '¥' + parseFloat(price).toFixed(2) + ' × ' + nums;
|
|
|
|
+ html += '</div>';
|
|
|
|
+
|
|
|
|
+ html += '</div></div>';
|
|
|
|
+ return html;
|
|
}
|
|
}
|
|
return '-';
|
|
return '-';
|
|
}},
|
|
}},
|
|
- {field: 'buyer.nickname', title: __('下单用户'), operate: 'LIKE'},
|
|
|
|
- {field: 'buyer.mobile', title: __('手机号'), operate: 'LIKE'},
|
|
|
|
- {field: 'agent.nickname', title: __('推广分销商'), operate: 'LIKE'},
|
|
|
|
- {field: 'agent.mobile', title: __('推广手机号'), operate: 'LIKE'},
|
|
|
|
|
|
+ {
|
|
|
|
+ field: 'buyer.nickname',
|
|
|
|
+ title: __('下单用户'),
|
|
|
|
+ operate: 'LIKE',
|
|
|
|
+ formatter: function (value, row, index) {
|
|
|
|
+ return formatUserInfo(row.buyer, row.user_id, '用户');
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ field: 'agent.nickname',
|
|
|
|
+ title: __('推广分销商'),
|
|
|
|
+ operate: 'LIKE',
|
|
|
|
+ formatter: function (value, row, index) {
|
|
|
|
+ return formatUserInfo(row.agent, row.agent_id, '分销商');
|
|
|
|
+ }
|
|
|
|
+ },
|
|
{field: 'amount', title: __('结算金额'), operate: 'BETWEEN'},
|
|
{field: 'amount', title: __('结算金额'), operate: 'BETWEEN'},
|
|
- {field: 'commission_order_status', title: __('业绩状态'), searchList: {
|
|
|
|
- "-2": __('已扣除'),
|
|
|
|
- "-1": __('已取消'),
|
|
|
|
- "0": __('不计入'),
|
|
|
|
- "1": __('已计入')
|
|
|
|
- }, formatter: function(value, row, index) {
|
|
|
|
|
|
+ {field: 'commission_order_status', title: __('业绩状态'), searchList: orderStatusTypes, formatter: function(value, row, index) {
|
|
var statusMap = {
|
|
var statusMap = {
|
|
- '-2': {text: '已扣除', color: 'danger'},
|
|
|
|
- '-1': {text: '已取消', color: 'warning'},
|
|
|
|
- '0': {text: '不计入', color: 'info'},
|
|
|
|
- '1': {text: '已计入', color: 'success'}
|
|
|
|
|
|
+ '-2': {text: orderStatusTypes['-2'] || '已扣除', color: 'danger'},
|
|
|
|
+ '-1': {text: orderStatusTypes['-1'] || '已取消', color: 'warning'},
|
|
|
|
+ '0': {text: orderStatusTypes['0'] || '不计入', color: 'info'},
|
|
|
|
+ '1': {text: orderStatusTypes['1'] || '已计入', color: 'success'}
|
|
};
|
|
};
|
|
- var status = statusMap[value] || {text: value, color: 'default'};
|
|
|
|
- return '<span class="label label-' + status.color + '">' + status.text + '</span>';
|
|
|
|
|
|
+ return formatOrderStatus(value, statusMap);
|
|
}},
|
|
}},
|
|
- {field: 'commission_reward_status', title: __('佣金状态'), searchList: {
|
|
|
|
- "-2": __('已退回'),
|
|
|
|
- "-1": __('已取消'),
|
|
|
|
- "0": __('未结算'),
|
|
|
|
- "1": __('已结算')
|
|
|
|
- }, formatter: function(value, row, index) {
|
|
|
|
|
|
+ {field: 'commission_reward_status', title: __('佣金状态'), searchList: rewardStatusTypes, formatter: function(value, row, index) {
|
|
var statusMap = {
|
|
var statusMap = {
|
|
- '-2': {text: '已退回', color: 'danger'},
|
|
|
|
- '-1': {text: '已取消', color: 'warning'},
|
|
|
|
- '0': {text: '未结算', color: 'info'},
|
|
|
|
- '1': {text: '已结算', color: 'success'}
|
|
|
|
|
|
+ '-2': {text: rewardStatusTypes['-2'] || '已退回', color: 'danger'},
|
|
|
|
+ '-1': {text: rewardStatusTypes['-1'] || '已取消', color: 'warning'},
|
|
|
|
+ '0': {text: rewardStatusTypes['0'] || '未结算', color: 'info'},
|
|
|
|
+ '1': {text: rewardStatusTypes['1'] || '已结算', color: 'success'}
|
|
};
|
|
};
|
|
- var status = statusMap[value] || {text: value, color: 'default'};
|
|
|
|
- return '<span class="label label-' + status.color + '">' + status.text + '</span>';
|
|
|
|
|
|
+ return formatOrderStatus(value, statusMap);
|
|
}},
|
|
}},
|
|
{field: 'commission_time', title: __('结算时间'), operate: 'RANGE', addclass: 'datetimerange', autocomplete: false, formatter: Table.api.formatter.datetime},
|
|
{field: 'commission_time', title: __('结算时间'), operate: 'RANGE', addclass: 'datetimerange', autocomplete: false, formatter: Table.api.formatter.datetime},
|
|
{field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate,
|
|
{field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate,
|
|
|
|
+ width: 150,
|
|
buttons: [
|
|
buttons: [
|
|
{
|
|
{
|
|
- name: 'confirm',
|
|
|
|
- text: __('结算'),
|
|
|
|
- title: __('结算佣金'),
|
|
|
|
- classname: 'btn btn-xs btn-success',
|
|
|
|
- icon: 'fa fa-check',
|
|
|
|
- visible: function (row) {
|
|
|
|
- return row.commission_reward_status == 0;
|
|
|
|
- },
|
|
|
|
- click: function (data) {
|
|
|
|
- Layer.confirm('确认结算此订单的佣金?', function(index) {
|
|
|
|
- Fast.api.ajax({
|
|
|
|
- url: 'commission/order/confirm',
|
|
|
|
- data: {commission_order_id: data.id}
|
|
|
|
- }, function(data, ret) {
|
|
|
|
- table.bootstrapTable('refresh');
|
|
|
|
- Layer.close(index);
|
|
|
|
- });
|
|
|
|
- });
|
|
|
|
- }
|
|
|
|
- },
|
|
|
|
- {
|
|
|
|
- name: 'cancel',
|
|
|
|
- text: __('取消'),
|
|
|
|
- title: __('取消佣金'),
|
|
|
|
- classname: 'btn btn-xs btn-warning',
|
|
|
|
- icon: 'fa fa-times',
|
|
|
|
|
|
+ name: 'back',
|
|
|
|
+ text: __('手动退回'),
|
|
|
|
+ title: __('手动退回佣金'),
|
|
|
|
+ classname: 'btn btn-xs btn-danger',
|
|
|
|
+ icon: 'fa fa-undo',
|
|
visible: function (row) {
|
|
visible: function (row) {
|
|
- return row.commission_reward_status == 0;
|
|
|
|
|
|
+ return row.commission_reward_status == 1;
|
|
},
|
|
},
|
|
click: function (data) {
|
|
click: function (data) {
|
|
- Layer.confirm('确认取消此订单的佣金?', function(index) {
|
|
|
|
|
|
+ Layer.confirm('确认手动退回此订单的佣金?', function(index) {
|
|
Fast.api.ajax({
|
|
Fast.api.ajax({
|
|
- url: 'commission/order/cancel',
|
|
|
|
- data: {commission_order_id: data.id}
|
|
|
|
|
|
+ url: 'commission/order/back',
|
|
|
|
+ data: {commission_order_id: data.id, deduct_order_money: 1}
|
|
}, function(data, ret) {
|
|
}, function(data, ret) {
|
|
table.bootstrapTable('refresh');
|
|
table.bootstrapTable('refresh');
|
|
Layer.close(index);
|
|
Layer.close(index);
|
|
@@ -119,24 +197,22 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
|
|
}
|
|
}
|
|
},
|
|
},
|
|
{
|
|
{
|
|
- name: 'back',
|
|
|
|
- text: __('退回'),
|
|
|
|
- title: __('退回佣金'),
|
|
|
|
- classname: 'btn btn-xs btn-danger',
|
|
|
|
- icon: 'fa fa-undo',
|
|
|
|
|
|
+ name: 'detail',
|
|
|
|
+ text: __('订单详情'),
|
|
|
|
+ title: __('查看订单详情'),
|
|
|
|
+ classname: 'btn btn-xs btn-info',
|
|
|
|
+ icon: 'fa fa-eye',
|
|
visible: function (row) {
|
|
visible: function (row) {
|
|
- return row.commission_reward_status == 1;
|
|
|
|
|
|
+ return true; // 始终显示
|
|
},
|
|
},
|
|
click: function (data) {
|
|
click: function (data) {
|
|
- Layer.confirm('确认退回此订单的佣金?', function(index) {
|
|
|
|
- Fast.api.ajax({
|
|
|
|
- url: 'commission/order/back',
|
|
|
|
- data: {commission_order_id: data.id, deduct_order_money: 1}
|
|
|
|
- }, function(data, ret) {
|
|
|
|
- table.bootstrapTable('refresh');
|
|
|
|
- Layer.close(index);
|
|
|
|
|
|
+ if (data.order_id) {
|
|
|
|
+ Fast.api.open('order/order/detail?id=' + data.order_id, '订单详情', {
|
|
|
|
+ area: ['90%', '90%']
|
|
});
|
|
});
|
|
- });
|
|
|
|
|
|
+ } else {
|
|
|
|
+ Layer.msg('订单ID不存在');
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
],
|
|
],
|
|
@@ -161,6 +237,68 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
|
|
});
|
|
});
|
|
},
|
|
},
|
|
api: {
|
|
api: {
|
|
|
|
+ // 解析Config中的JSON字符串的辅助函数
|
|
|
|
+ parseConfigJson: function(configKey, defaultValue) {
|
|
|
|
+ var configValue = Config[configKey] || defaultValue || {};
|
|
|
|
+
|
|
|
|
+ // 如果是字符串,尝试解析JSON
|
|
|
|
+ if (typeof configValue === 'string') {
|
|
|
|
+ try {
|
|
|
|
+ return JSON.parse(configValue);
|
|
|
|
+ } catch (e) {
|
|
|
|
+ return defaultValue || {};
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return configValue;
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ // 统一的用户信息展示方法
|
|
|
|
+ formatUserInfo: function(user, userId, userType, config) {
|
|
|
|
+ if (!user) return '-';
|
|
|
|
+
|
|
|
|
+ config = config || {
|
|
|
|
+ showAvatar: true,
|
|
|
|
+ avatarSize: 40,
|
|
|
|
+ showMobile: true,
|
|
|
|
+ showId: true,
|
|
|
|
+ defaultAvatarUrl: '/assets/img/avatar.png'
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ var avatar = user.avatar ? user.avatar : config.defaultAvatarUrl;
|
|
|
|
+ var nickname = user.nickname || user.username || (userType || '用户');
|
|
|
|
+ var mobile = user.mobile || '';
|
|
|
|
+
|
|
|
|
+ // 处理头像URL
|
|
|
|
+ var avatarUrl = avatar;
|
|
|
|
+ if (avatar && !avatar.startsWith('http') && !avatar.startsWith('//')) {
|
|
|
|
+ avatarUrl = Fast.api.cdnurl ? Fast.api.cdnurl(avatar) : avatar;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var typeColor = userType === '分销商' ? '#28a745' : (userType === '用户' ? '#17a2b8' : '#337ab7');
|
|
|
|
+
|
|
|
|
+ var html = '<div style="display:flex;align-items:center;">';
|
|
|
|
+
|
|
|
|
+ if (config.showAvatar) {
|
|
|
|
+ html += '<img src="' + avatarUrl + '" style="width:' + config.avatarSize + 'px;height:' + config.avatarSize + 'px;border-radius:50%;margin-right:10px;" />';
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ html += '<div>' +
|
|
|
|
+ '<div style="color:#337ab7;font-weight:bold;">' + nickname + '</div>' +
|
|
|
|
+ '<div style="color:' + typeColor + ';font-size:12px;">';
|
|
|
|
+
|
|
|
|
+ var info = [];
|
|
|
|
+ if (config.showMobile && mobile) {
|
|
|
|
+ info.push(mobile);
|
|
|
|
+ }
|
|
|
|
+ if (config.showId && userId) {
|
|
|
|
+ info.push('ID: ' + userId);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ html += info.join(' ') + '</div></div></div>';
|
|
|
|
+ return html;
|
|
|
|
+ },
|
|
|
|
+
|
|
bindevent: function () {
|
|
bindevent: function () {
|
|
Form.api.bindevent($("form[role=form]"));
|
|
Form.api.bindevent($("form[role=form]"));
|
|
}
|
|
}
|