feat(split): 添加分账手动指定接收方功能

- 实现SplitManualService服务类,支持手动覆盖分账明细
- 新增SplitManual和SplitManualLog数据模型
- 修改SplitCalculator优先使用手动覆盖数据进行分账计算
- 添加分账记录手动指定接收方的数据库表结构
- 集成手动分账到汇付分账流程中,支持失败重试机制
- 添加商品详情内容更新SQL脚本用于汇付审核
```
这个提交包含在:
可乐加冰
2026-10-22 22:38:35 +08:00
父节点 b5142ff780
当前提交 af08af8d47
共有 11 个文件被更改,包括 1301 次插入 和 11 次删除

查看文件

@@ -18,9 +18,38 @@ define(['jquery', 'bootstrap', 'backend', 'form'], function ($, undefined, Backe
status: '',
channel: ''
},
splitHuifuOnly: !!(typeof Config !== 'undefined' && Config.splitHuifuOnly)
splitHuifuOnly: !!(typeof Config !== 'undefined' && Config.splitHuifuOnly),
manualDialogVisible: false,
manualLoading: false,
manualSaving: false,
manualRow: null,
manualContext: {
order_sn: '',
confirm_base: 0,
max_split_amount: 0,
has_manual: false,
original_items: [],
receiver_options: []
},
manualForm: {
items: [],
remark: ''
},
historyDrawerVisible: false,
historyLoading: false,
historyList: [],
historyRow: null
};
},
computed: {
manualItemsTotal() {
var sum = 0;
(this.manualForm.items || []).forEach(function (it) {
sum += parseFloat(it.amount) || 0;
});
return sum;
}
},
mounted() {
this.getList();
},
@@ -71,6 +100,18 @@ define(['jquery', 'bootstrap', 'backend', 'form'], function ($, undefined, Backe
var n = parseFloat(v);
return isNaN(n) ? '0.00' : n.toFixed(2);
},
roleTypeLabel(type) {
var map = { platform: '平台', promoter: '推广员', regional_agent: '区域公司' };
return map[type] || type || '接收方';
},
formatManualItemLine(it) {
if (!it) return '—';
var name = it.receiver_name || ('#' + (it.role_id || ''));
var account = it.receiver_account || '';
var amt = this.formatMoney(it.amount);
var role = this.roleTypeLabel(it.role_type);
return role + ' ' + name + (account ? ' (' + account + ')' : '') + ' ¥' + amt;
},
scrollCellWheel(e) {
var el = e.currentTarget;
if (!el || el.scrollWidth <= el.clientWidth) {
@@ -85,6 +126,155 @@ define(['jquery', 'bootstrap', 'backend', 'form'], function ($, undefined, Backe
if (!orderId) return;
Fast.api.open('shopro/order/order/detail?id=' + orderId, '订单详情');
},
openManualDialog(row) {
this.manualRow = row;
this.manualDialogVisible = true;
this.manualLoading = true;
this.manualForm.remark = '';
Fast.api.ajax({
url: 'shopro/split/order/manualReceivers',
type: 'GET',
data: { split_order_id: row.id }
}, (ret, res) => {
var ctx = (res && res.data) ? res.data : {};
this.manualContext = ctx;
this.manualForm.items = this.cloneManualItems(ctx.current_items || []);
if (!this.manualForm.items.length) {
this.addManualRow();
}
this.manualLoading = false;
return false;
}, () => {
this.manualLoading = false;
this.manualDialogVisible = false;
});
},
cloneManualItems(items) {
return (items || []).map(function (it) {
return {
receiver_id: it.receiver_id || 0,
role_type: it.role_type || 'promoter',
amount: parseFloat(it.amount) || 0,
description: it.description || '手动指定'
};
});
},
addManualRow() {
this.manualForm.items.push({
receiver_id: 0,
role_type: 'promoter',
amount: 0,
description: '手动指定'
});
},
removeManualRow(index) {
this.manualForm.items.splice(index, 1);
},
onReceiverChange(row) {
var opt = (this.manualContext.receiver_options || []).find(function (o) {
return o.id === row.receiver_id;
});
if (opt) {
row.role_type = opt.role_type || row.role_type;
}
},
validateManualForm() {
var items = this.manualForm.items || [];
if (!items.length) {
Layer.msg('请至少添加一行分账明细');
return false;
}
for (var i = 0; i < items.length; i++) {
if (!items[i].receiver_id) {
Layer.msg('第 ' + (i + 1) + ' 行请选择接收方');
return false;
}
if (!items[i].amount || parseFloat(items[i].amount) <= 0) {
Layer.msg('第 ' + (i + 1) + ' 行金额须大于 0');
return false;
}
}
var max = parseFloat(this.manualContext.max_split_amount) || 0;
if (max > 0 && this.manualItemsTotal > max + 0.001) {
Layer.msg('合计超过上限 ¥' + this.formatMoney(max));
return false;
}
var base = parseFloat(this.manualContext.confirm_base) || 0;
if (base > 0 && this.manualItemsTotal > base + 0.001) {
Layer.msg('合计超过确认基数 ¥' + this.formatMoney(base));
return false;
}
return true;
},
saveManual(andRetry) {
if (!this.manualRow || !this.validateManualForm()) {
return;
}
var url = andRetry
? 'shopro/split/order/saveManualAndRetry'
: 'shopro/split/order/saveManual';
var tip = andRetry
? '保存后将向汇付重新发起分账,是否继续?'
: '仅保存覆盖配置,不会立即重试,是否继续?';
var self = this;
Layer.confirm(tip, { title: '确认', btn: ['确定', '取消'] }, function () {
self.manualSaving = true;
Fast.api.ajax({
url: url,
type: 'POST',
data: {
split_order_id: self.manualRow.id,
items: self.manualForm.items,
remark: self.manualForm.remark
}
}, () => {
self.manualSaving = false;
self.manualDialogVisible = false;
self.getList();
}, () => {
self.manualSaving = false;
});
});
},
clearManualOverride() {
if (!this.manualRow) return;
var self = this;
Layer.confirm('清除后将恢复自动计算明细,是否继续?', { title: '清除手动指定', btn: ['清除', '取消'] }, function () {
self.manualSaving = true;
Fast.api.ajax({
url: 'shopro/split/order/clearManual',
type: 'POST',
data: {
split_order_id: self.manualRow.id,
remark: self.manualForm.remark
}
}, () => {
self.manualSaving = false;
self.manualDialogVisible = false;
self.getList();
}, () => {
self.manualSaving = false;
});
});
},
openHistoryDrawer(row) {
this.historyRow = row;
this.historyDrawerVisible = true;
this.historyLoading = true;
this.historyList = [];
Fast.api.ajax({
url: 'shopro/split/order/manualHistory',
type: 'GET',
data: { order_id: row.order_id, limit: 50 }
}, (ret, res) => {
var data = (res && res.data) ? res.data : {};
this.historyList = data.rows || [];
this.historyLoading = false;
return false;
}, () => {
this.historyLoading = false;
});
},
retry(row) {
var tip = this.splitHuifuOnly
? '将向汇付重新发起该笔分账。若订单资金仍被冻结,请先发货/确认收货或按文档处理 FREEZE。'