提交
This commit is contained in:
@@ -26,7 +26,17 @@ class MatchingService {
|
||||
|
||||
// 检查用户审核状态、必要信息和余额
|
||||
const [userResult] = await db.execute(
|
||||
'SELECT audit_status, balance, wechat_qr, alipay_qr, unionpay_qr, bank_card, business_license, id_card_front, id_card_back FROM users WHERE id = ?',
|
||||
`SELECT audit_status,
|
||||
balance,
|
||||
wechat_qr,
|
||||
alipay_qr,
|
||||
unionpay_qr,
|
||||
bank_card,
|
||||
business_license,
|
||||
id_card_front,
|
||||
id_card_back
|
||||
FROM users
|
||||
WHERE id = ?`,
|
||||
[userId]
|
||||
);
|
||||
|
||||
@@ -79,8 +89,8 @@ class MatchingService {
|
||||
maxCycles = 1;
|
||||
} else if (matchingType === 'large') {
|
||||
// 大额匹配:用户自定义金额(最高5万)
|
||||
if (!customAmount || customAmount < 5000 || customAmount > 50000) {
|
||||
throw new Error('大额匹配金额必须在5000-50000之间');
|
||||
if (!customAmount || customAmount < 3000 || customAmount > 50000) {
|
||||
throw new Error('大额匹配金额必须在3000-50000之间');
|
||||
}
|
||||
totalAmount = customAmount;
|
||||
maxCycles = 1;
|
||||
@@ -688,19 +698,41 @@ class MatchingService {
|
||||
const maxTransfers = 10;
|
||||
|
||||
try {
|
||||
// 获取负余额用户
|
||||
// 首先获取当前用户的城市、省份和区域信息
|
||||
const [currentUserResult] = await db.execute(
|
||||
`SELECT city, province, district_id FROM users WHERE id = ?`,
|
||||
[excludeUserId]
|
||||
);
|
||||
|
||||
const currentUserCity = currentUserResult[0]?.city;
|
||||
const currentUserProvince = currentUserResult[0]?.province;
|
||||
const currentUserDistrictId = currentUserResult[0]?.district_id;
|
||||
|
||||
// 获取负余额用户,按区县、城市、省份优先级排序
|
||||
let [userBalanceResult] = await db.execute(
|
||||
`SELECT
|
||||
u.id as user_id,
|
||||
u.balance as current_balance
|
||||
u.balance as current_balance,
|
||||
u.city,
|
||||
u.province,
|
||||
u.district_id
|
||||
FROM users u
|
||||
WHERE u.is_system_account = FALSE
|
||||
AND u.is_distribute = TRUE
|
||||
AND u.id != ?
|
||||
AND u.balance < -100
|
||||
AND u.audit_status = 'approved'
|
||||
ORDER BY u.balance ASC`,
|
||||
[excludeUserId]
|
||||
AND u.user_type != 'directly_operated'
|
||||
AND u.payment_status = 'paid'
|
||||
ORDER BY
|
||||
CASE
|
||||
WHEN u.city = ? AND u.district_id = ? THEN 1 -- 相同城市且相同区县排第一
|
||||
WHEN u.city = ? THEN 2 -- 相同城市但不同区县排第二
|
||||
WHEN u.province = ? THEN 3 -- 相同省份但不同城市排第三
|
||||
ELSE 4 -- 其他省份排第四
|
||||
END,
|
||||
u.balance ASC`,
|
||||
[excludeUserId, currentUserCity, currentUserDistrictId, currentUserCity, currentUserProvince]
|
||||
);
|
||||
|
||||
// 处理查询到的负余额用户
|
||||
@@ -765,7 +797,7 @@ class MatchingService {
|
||||
userBalanceResult = userBalanceResult.filter(user => user.has_active_allocations < -100);
|
||||
userBalanceResult = userBalanceResult.sort((a, b) => a.has_active_allocations - b.has_active_allocations);
|
||||
for (const user of userBalanceResult) {
|
||||
if ( maxTransfers > availableUsers.length + 1) {
|
||||
if (maxTransfers > availableUsers.length + 1) {
|
||||
if (minTransfers === 3 && availableUsers.length < 3) {
|
||||
availableUsers.push(user);
|
||||
}
|
||||
@@ -820,21 +852,26 @@ class MatchingService {
|
||||
if (range <= 0) {
|
||||
maxUserAllocation = minAmount;
|
||||
} else {
|
||||
// 使用更均匀的分配策略
|
||||
const randomFactor = Math.random(); // 使用均匀分布
|
||||
if (maxRandomAllocation > 1000) {
|
||||
// 使用更均匀的分配策略
|
||||
const randomFactor = Math.random(); // 使用均匀分布
|
||||
|
||||
// 基础分配:在整个范围内更均匀分布,减少偏向性
|
||||
const baseOffset = Math.floor(range * 0.15); // 降低到15%的基础偏移
|
||||
const adjustedRange = range - baseOffset;
|
||||
maxUserAllocation = Math.floor(randomFactor * adjustedRange) + minAmount + baseOffset;
|
||||
// 基础分配:在整个范围内更均匀分布,减少偏向性
|
||||
const baseOffset = Math.floor(range * 0.15); // 降低到15%的基础偏移
|
||||
const adjustedRange = range - baseOffset;
|
||||
maxUserAllocation = Math.floor(randomFactor * adjustedRange) + minAmount + baseOffset;
|
||||
|
||||
// 进一步减少额外增量的影响
|
||||
const bonusRange = Math.min(range * 0.1, maxRandomAllocation - maxUserAllocation); // 降低到10%
|
||||
if (bonusRange > 0 && Math.random() > 0.7) { // 30%概率获得额外增量,进一步降低
|
||||
const bonus = Math.floor(Math.random() * bonusRange * 0.3); // 使用30%的bonus范围
|
||||
maxUserAllocation += bonus;
|
||||
// 进一步减少额外增量的影响
|
||||
const bonusRange = Math.min(range * 0.1, maxRandomAllocation - maxUserAllocation); // 降低到10%
|
||||
if (bonusRange > 0 && Math.random() > 0.7) { // 30%概率获得额外增量,进一步降低
|
||||
const bonus = Math.floor(Math.random() * bonusRange * 0.3); // 使用30%的bonus范围
|
||||
maxUserAllocation += bonus;
|
||||
}
|
||||
}else{
|
||||
maxUserAllocation = maxRandomAllocation
|
||||
}
|
||||
|
||||
|
||||
// 确保不超过最大限制
|
||||
maxUserAllocation = Math.min(maxUserAllocation, maxRandomAllocation);
|
||||
}
|
||||
@@ -852,7 +889,7 @@ class MatchingService {
|
||||
totalPendingInflow: user.total_pending_inflow,
|
||||
availableForAllocation: user.available_for_allocation,
|
||||
todayOutflow: user.today_outflow,
|
||||
has_active_allocations:user.has_active_allocations
|
||||
has_active_allocations: user.has_active_allocations
|
||||
});
|
||||
remainingAmount -= maxUserAllocation;
|
||||
}
|
||||
@@ -864,7 +901,7 @@ class MatchingService {
|
||||
// 如果有剩余金额,优先检查现有非虚拟用户是否还能消化
|
||||
if (remainingAmount > 0) {
|
||||
// 筛选出非虚拟用户分配记录
|
||||
|
||||
|
||||
if (allocations.length > 0) {
|
||||
let totalAvailableCapacity = 0;
|
||||
const userCapacities = [];
|
||||
@@ -874,7 +911,7 @@ class MatchingService {
|
||||
// 获取用户当前的实际余额状态(使用has_active_allocations作为实际可分配余额)
|
||||
const maxSafeAmount = Math.abs(allocation.has_active_allocations);
|
||||
const remainingCapacity = maxSafeAmount - allocation.amount;
|
||||
|
||||
|
||||
if (remainingCapacity > 0) {
|
||||
userCapacities.push({
|
||||
allocation,
|
||||
@@ -887,7 +924,7 @@ class MatchingService {
|
||||
console.log(`现有用户剩余容量: ${totalAvailableCapacity}, 待分配金额: ${remainingAmount}`);
|
||||
|
||||
// 如果现有用户能够消化剩余金额
|
||||
if (totalAvailableCapacity >= remainingAmount && userCapacities.length > 0) {
|
||||
if (totalAvailableCapacity >= remainingAmount && userCapacities.length > 0 && allocations.length >= 3) {
|
||||
// 按平均分配给这些用户,但需要检查每个用户的分配上限
|
||||
const averageAmount = Math.floor(remainingAmount / userCapacities.length);
|
||||
let distributedAmount = 0;
|
||||
@@ -895,10 +932,10 @@ class MatchingService {
|
||||
|
||||
for (let i = 0; i < userCapacities.length; i++) {
|
||||
const { allocation, capacity } = userCapacities[i];
|
||||
|
||||
|
||||
// 计算本次可分配的金额
|
||||
let amountToAdd = 0;
|
||||
|
||||
|
||||
if (i === userCapacities.length - 1) {
|
||||
// 最后一个用户分配剩余的所有金额,但不能超过其容量
|
||||
amountToAdd = Math.min(remainingToDistribute, capacity);
|
||||
@@ -914,15 +951,15 @@ class MatchingService {
|
||||
console.log(`为用户${allocation.userId}追加分配${amountToAdd}元,总分配${allocation.amount}元,剩余容量${capacity - amountToAdd}元`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 更新实际分配的剩余金额
|
||||
remainingAmount = remainingToDistribute;
|
||||
|
||||
if (remainingAmount === 0) {
|
||||
console.log('剩余金额已全部分配给现有用户');
|
||||
} else {
|
||||
console.log(`部分剩余金额已分配给现有用户,仍有${remainingAmount}元未分配`);
|
||||
}
|
||||
remainingAmount = remainingToDistribute;
|
||||
|
||||
if (remainingAmount === 0) {
|
||||
console.log('剩余金额已全部分配给现有用户');
|
||||
} else {
|
||||
console.log(`部分剩余金额已分配给现有用户,仍有${remainingAmount}元未分配`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -931,17 +968,17 @@ class MatchingService {
|
||||
if (remainingAmount > 0) {
|
||||
// 获取已分配的用户ID列表
|
||||
const allocatedUserIds = new Set(allocations.map(a => a.userId));
|
||||
|
||||
|
||||
// 从原始用户列表中找到未分配的用户
|
||||
const unallocatedUsers = priorityUsers.filter(user => !allocatedUserIds.has(user.user_id));
|
||||
|
||||
const unallocatedUsers = userBalanceResult.filter(user => !allocatedUserIds.has(user.user_id));
|
||||
|
||||
if (unallocatedUsers.length > 0) {
|
||||
console.log(`发现${unallocatedUsers.length}个未分配的用户,剩余金额: ${remainingAmount}`);
|
||||
|
||||
|
||||
// 查找可分配金额大于剩余金额的用户
|
||||
for (const user of unallocatedUsers) {
|
||||
const maxSafeAmount = Math.abs(user.has_active_allocations);
|
||||
|
||||
|
||||
if (maxSafeAmount >= remainingAmount) {
|
||||
// 找到合适的用户,分配剩余金额
|
||||
allocations.push({
|
||||
@@ -952,7 +989,7 @@ class MatchingService {
|
||||
currentBalance: user.current_balance,
|
||||
availableForAllocation: user.has_active_allocations
|
||||
});
|
||||
|
||||
|
||||
console.log(`为未分配用户${user.user_id}分配剩余金额${remainingAmount}元`);
|
||||
remainingAmount = 0;
|
||||
break;
|
||||
@@ -1045,17 +1082,17 @@ class MatchingService {
|
||||
|
||||
// 使用更均匀的分配策略
|
||||
const amounts = [];
|
||||
|
||||
|
||||
// 首先为每笔分配最小金额
|
||||
for (let i = 0; i < transferCount; i++) {
|
||||
amounts.push(minAmount);
|
||||
}
|
||||
|
||||
|
||||
let remainingToDistribute = totalAmount - (minAmount * transferCount);
|
||||
|
||||
|
||||
// 计算平均每笔应该额外分配的金额
|
||||
const averageExtra = Math.floor(remainingToDistribute / transferCount);
|
||||
|
||||
|
||||
// 为每笔添加平均额外金额,但加入一些随机性
|
||||
for (let i = 0; i < transferCount && remainingToDistribute > 0; i++) {
|
||||
// 计算这笔最多还能增加多少(不超过maxAmount)
|
||||
@@ -1063,20 +1100,20 @@ class MatchingService {
|
||||
maxAmount - amounts[i],
|
||||
remainingToDistribute
|
||||
);
|
||||
|
||||
|
||||
if (maxPossibleIncrease > 0) {
|
||||
// 在平均值附近随机分配,但控制在更小的范围内以保证更均匀
|
||||
const baseIncrease = Math.min(averageExtra, maxPossibleIncrease);
|
||||
const randomVariation = Math.floor(baseIncrease * 0.15); // 减少到15%的随机变化
|
||||
const minIncrease = Math.max(0, baseIncrease - randomVariation);
|
||||
const maxIncrease = Math.min(maxPossibleIncrease, baseIncrease + randomVariation);
|
||||
|
||||
|
||||
const increase = Math.floor(Math.random() * (maxIncrease - minIncrease + 1)) + minIncrease;
|
||||
amounts[i] += increase;
|
||||
remainingToDistribute -= increase;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 如果还有剩余金额,尽量均匀分配给还能接受的笔数
|
||||
while (remainingToDistribute > 0) {
|
||||
const availableIndices = [];
|
||||
@@ -1085,45 +1122,45 @@ class MatchingService {
|
||||
availableIndices.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (availableIndices.length === 0) {
|
||||
break; // 无法继续分配
|
||||
}
|
||||
|
||||
|
||||
// 计算每个可用位置应该分配多少
|
||||
const perIndexAmount = Math.floor(remainingToDistribute / availableIndices.length);
|
||||
const remainder = remainingToDistribute % availableIndices.length;
|
||||
|
||||
|
||||
// 为每个可用位置分配相等的金额
|
||||
for (let i = 0; i < availableIndices.length && remainingToDistribute > 0; i++) {
|
||||
const index = availableIndices[i];
|
||||
const maxIncrease = Math.min(maxAmount - amounts[index], remainingToDistribute);
|
||||
|
||||
|
||||
if (maxIncrease > 0) {
|
||||
// 基础分配金额
|
||||
let increase = Math.min(perIndexAmount, maxIncrease);
|
||||
|
||||
|
||||
// 如果是前几个位置,额外分配余数
|
||||
if (i < remainder) {
|
||||
increase = Math.min(increase + 1, maxIncrease);
|
||||
}
|
||||
|
||||
|
||||
amounts[index] += increase;
|
||||
remainingToDistribute -= increase;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 如果所有位置都已达到最大值,退出循环
|
||||
if (perIndexAmount === 0 && remainder === 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 如果还有剩余金额无法分配,返回空数组表示失败
|
||||
if (remainingToDistribute > 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
return amounts;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user