提交
This commit is contained in:
3
.idea/data_source_mapping.xml
generated
3
.idea/data_source_mapping.xml
generated
@@ -2,7 +2,10 @@
|
||||
<project version="4">
|
||||
<component name="DataSourcePerFileMappings">
|
||||
<file url="file://$PROJECT_DIR$/database.js" value="5c67c46f-1d09-4751-a201-e01d3162c9fe" />
|
||||
<file url="file://$PROJECT_DIR$/routes/matching.js" value="5c67c46f-1d09-4751-a201-e01d3162c9fe" />
|
||||
<file url="file://$PROJECT_DIR$/routes/transfers.js" value="5c67c46f-1d09-4751-a201-e01d3162c9fe" />
|
||||
<file url="file://$PROJECT_DIR$/routes/users.js" value="5c67c46f-1d09-4751-a201-e01d3162c9fe" />
|
||||
<file url="file://$PROJECT_DIR$/services/matchingService.js" value="5c67c46f-1d09-4751-a201-e01d3162c9fe" />
|
||||
<file url="file://$PROJECT_DIR$/services/transferService.js" value="5c67c46f-1d09-4751-a201-e01d3162c9fe" />
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/sqldialects.xml
generated
6
.idea/sqldialects.xml
generated
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="SqlDialectMappings">
|
||||
<file url="PROJECT" dialect="MySQL" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -310,7 +310,7 @@ router.post('/confirm-allocation/:allocationId', auth, async (req, res) => {
|
||||
}
|
||||
|
||||
// 调用服务层方法,传递完整的转账信息
|
||||
const transferId = await matchingService.confirmAllocation(
|
||||
const transferId = matchingService.confirmAllocation(
|
||||
allocationId,
|
||||
userId,
|
||||
transferAmount,
|
||||
@@ -324,11 +324,11 @@ router.post('/confirm-allocation/:allocationId', auth, async (req, res) => {
|
||||
data: { transferId }
|
||||
});
|
||||
|
||||
axios.post('http://localhost:5000/ocr',{
|
||||
id: allocationId
|
||||
}).then(res => {
|
||||
console.log(res.data)
|
||||
})
|
||||
// axios.post('http://localhost:5000/ocr',{
|
||||
// id: allocationId
|
||||
// }).then(res => {
|
||||
// console.log(res.data)
|
||||
// })
|
||||
|
||||
} catch (error) {
|
||||
console.error('确认分配失败:', error);
|
||||
|
||||
@@ -141,11 +141,6 @@ router.post('/send', async (req, res) => {
|
||||
// 生产环境发送真实短信
|
||||
try {
|
||||
console.log(code);
|
||||
res.json({
|
||||
success: true,
|
||||
message: '验证码发送成功'
|
||||
})
|
||||
return
|
||||
const sendSmsRequest = new Dysmsapi20170525.SendSmsRequest({
|
||||
phoneNumbers: phone,
|
||||
signName: SMS_CONFIG.signName,
|
||||
|
||||
@@ -12,6 +12,48 @@ const dayjs = require('dayjs');
|
||||
const router = express.Router();
|
||||
|
||||
|
||||
// router.get('/tmp', async (req, res) => {
|
||||
// const db = getDB();
|
||||
// // 1. 查询所有转账记录,按 id 升序
|
||||
// let [transfers] = await db.execute(`
|
||||
// SELECT *
|
||||
// FROM transfers
|
||||
// WHERE status='received' or status='confirmed'
|
||||
// ORDER BY id ASC`);
|
||||
//
|
||||
// // 2. 用对象维护每个用户的最新余额
|
||||
// const userBalances = {};
|
||||
//
|
||||
// // 3. 遍历每条转账记录,计算余额
|
||||
// for (const trx of transfers) {
|
||||
// const fromId = trx.from_user_id;
|
||||
// const toId = trx.to_user_id;
|
||||
// const amount = Number(trx.amount);
|
||||
//
|
||||
// if (!(fromId in userBalances)) userBalances[fromId] = 0;
|
||||
// if (!(toId in userBalances)) userBalances[toId] = 0;
|
||||
//
|
||||
// const fromBalance = userBalances[fromId] - amount;
|
||||
// const toBalance = userBalances[toId] + amount;
|
||||
//
|
||||
// userBalances[fromId] = fromBalance;
|
||||
// userBalances[toId] = toBalance;
|
||||
//
|
||||
// const balanceDiff = toBalance - fromBalance;
|
||||
//
|
||||
// // 4. 更新当前行的字段
|
||||
// await db.execute(
|
||||
// `UPDATE transfers
|
||||
// SET from_user_balance = ?,
|
||||
// to_user_balance = ?,
|
||||
// balance_diff = ?
|
||||
// WHERE id = ?`,
|
||||
// [fromBalance, toBalance, amount, trx.id]
|
||||
// );
|
||||
//
|
||||
// }
|
||||
// res.json('更新成功')
|
||||
// })
|
||||
router.get('/',
|
||||
authenticateToken,
|
||||
validateQuery(transferSchemas.query),
|
||||
@@ -342,7 +384,6 @@ router.post('/confirm-not-received',
|
||||
);
|
||||
|
||||
|
||||
|
||||
// 获取用户转账记录
|
||||
router.get('/user/:userId', authenticateToken, async (req, res) => {
|
||||
try {
|
||||
@@ -387,7 +428,8 @@ router.get('/user/:userId', authenticateToken, async (req, res) => {
|
||||
${whereClause}
|
||||
ORDER BY t.created_at
|
||||
DESC
|
||||
LIMIT ${limitNum} OFFSET ${offset}
|
||||
LIMIT ${limitNum}
|
||||
OFFSET ${offset}
|
||||
`, countParams);
|
||||
|
||||
const [countResult] = await db.execute(`
|
||||
@@ -470,17 +512,17 @@ router.get('/stats', authenticateToken, async (req, res) => {
|
||||
(
|
||||
COALESCE((SELECT SUM(amount)
|
||||
FROM transfers
|
||||
WHERE DATE(created_at) = ?
|
||||
WHERE DATE (created_at) = ?
|
||||
AND to_user_id IN (SELECT id FROM users WHERE is_system_account = 1)
|
||||
AND status = 'received'), 0) -
|
||||
COALESCE((SELECT SUM(amount)
|
||||
FROM transfers
|
||||
WHERE DATE(created_at) = ?
|
||||
WHERE DATE (created_at) = ?
|
||||
AND from_user_id IN (SELECT id FROM users WHERE is_system_account = 1)
|
||||
AND status = 'received'), 0)
|
||||
) as today_amount
|
||||
FROM transfers
|
||||
WHERE DATE(created_at) = ?
|
||||
WHERE DATE (created_at) = ?
|
||||
`, [todayStr, todayStr, todayStr]);
|
||||
|
||||
const [monthlyStats] = await db.execute(`
|
||||
@@ -488,8 +530,8 @@ router.get('/stats', authenticateToken, async (req, res) => {
|
||||
SUM(CASE WHEN status = 'received' THEN amount ELSE 0 END) as monthly_amount,
|
||||
SUM(CASE WHEN source_type IN ('system') THEN amount END) as monthly_participated_transfers
|
||||
FROM transfers
|
||||
WHERE YEAR(created_at) = ?
|
||||
AND MONTH(created_at) = ?
|
||||
WHERE YEAR (created_at) = ?
|
||||
AND MONTH (created_at) = ?
|
||||
`, [currentYear, currentMonth]);
|
||||
|
||||
// 获取上月统计数据用于对比
|
||||
@@ -501,8 +543,8 @@ router.get('/stats', authenticateToken, async (req, res) => {
|
||||
SUM(CASE WHEN status = 'confirmed' THEN amount ELSE 0 END) as last_monthly_amount,
|
||||
SUM(CASE WHEN source_type IN ('system') THEN amount END) as last_monthly_participated_transfers
|
||||
FROM transfers
|
||||
WHERE YEAR(created_at) = ?
|
||||
AND MONTH(created_at) = ?
|
||||
WHERE YEAR (created_at) = ?
|
||||
AND MONTH (created_at) = ?
|
||||
`, [lastMonthYear, lastMonth]);
|
||||
|
||||
stats = {
|
||||
@@ -524,9 +566,9 @@ router.get('/stats', authenticateToken, async (req, res) => {
|
||||
return_amount: parseFloat(totalStats[0].return_amount || 0),
|
||||
user_to_user_amount: parseFloat(totalStats[0].user_to_user_amount || 0),
|
||||
participated_transfers: totalStats[0].participated_transfers || 0,
|
||||
total_user_balance:totalStats[0].total_user_balance || 0,
|
||||
agent_total:totalStats[0].agent_total || 0,//代理收入
|
||||
operated_agent_total:totalStats[0].operated_agent_total || 0,//直营代理收入
|
||||
total_user_balance: totalStats[0].total_user_balance || 0,
|
||||
agent_total: totalStats[0].agent_total || 0,//代理收入
|
||||
operated_agent_total: totalStats[0].operated_agent_total || 0,//直营代理收入
|
||||
},
|
||||
today: {
|
||||
transfers: todayStats[0].today_transfers || 0,
|
||||
@@ -565,7 +607,7 @@ router.get('/stats', authenticateToken, async (req, res) => {
|
||||
SUM(CASE WHEN status = 'confirmed' AND to_user_id = ? THEN amount ELSE 0 END) as today_received
|
||||
FROM transfers
|
||||
WHERE (from_user_id = ? OR to_user_id = ?)
|
||||
AND DATE(created_at) = ?
|
||||
AND DATE (created_at) = ?
|
||||
`, [userId, userId, userId, userId, todayStr]);
|
||||
|
||||
stats = {
|
||||
@@ -706,8 +748,8 @@ router.get('/trend', authenticateToken, async (req, res) => {
|
||||
|
||||
// 首先获取数据库中最早和最晚的转账日期
|
||||
const [dateRange] = await db.execute(`
|
||||
SELECT MIN(DATE(created_at)) as min_date,
|
||||
MAX(DATE(created_at)) as max_date,
|
||||
SELECT MIN(DATE (created_at)) as min_date,
|
||||
MAX(DATE (created_at)) as max_date,
|
||||
COUNT(*) as total_count
|
||||
FROM transfers
|
||||
`);
|
||||
@@ -737,13 +779,13 @@ router.get('/trend', authenticateToken, async (req, res) => {
|
||||
|
||||
// 获取指定天数内的转账趋势(从最大日期往前推)
|
||||
const [trendData] = await db.execute(`
|
||||
SELECT DATE(created_at) as date,
|
||||
COUNT(*) as count,
|
||||
SUM(amount) as amount
|
||||
SELECT DATE (created_at) as date, COUNT (*) as count, SUM (amount) as amount
|
||||
FROM transfers
|
||||
WHERE DATE(created_at) >= DATE_SUB(?, INTERVAL ? DAY)
|
||||
AND status IN ('confirmed', 'received')
|
||||
GROUP BY DATE(created_at)
|
||||
WHERE DATE (created_at) >= DATE_SUB(?
|
||||
, INTERVAL ? DAY)
|
||||
AND status IN ('confirmed'
|
||||
, 'received')
|
||||
GROUP BY DATE (created_at)
|
||||
ORDER BY date ASC
|
||||
`, [dateRange[0].max_date, daysNum - 1]);
|
||||
|
||||
@@ -1024,7 +1066,8 @@ router.get('/pending-allocations',
|
||||
JOIN matching_orders mo ON oa.id = mo.id
|
||||
${whereClause}
|
||||
ORDER BY oa.${sortField} ${sortOrder}
|
||||
LIMIT ${parseInt(limit)} OFFSET ${parseInt(offset)}
|
||||
LIMIT ${parseInt(limit)}
|
||||
OFFSET ${parseInt(offset)}
|
||||
`;
|
||||
|
||||
const [allocations] = queryParams.length > 0
|
||||
@@ -1145,14 +1188,11 @@ router.get('/daily-stats',
|
||||
u.real_name,
|
||||
u.phone,
|
||||
u.balance,
|
||||
COALESCE(yesterday_out.amount, 0) as yesterday_out_amount,
|
||||
COALESCE(yesterday_out.amount, 0) -
|
||||
COALESCE(yesterday_system_num.amount, 0) as yesterday_out_amount,
|
||||
COALESCE(today_in.amount, 0) as today_in_amount,
|
||||
COALESCE(confirmed_from.confirmed_amount, 0) as confirmed_from_amount,
|
||||
CASE
|
||||
WHEN (COALESCE(u.balance, 0) + COALESCE(confirmed_from.confirmed_amount, 0)) > ABS(u.balance)
|
||||
THEN ABS(u.balance)
|
||||
ELSE (COALESCE(u.balance, 0) + COALESCE(confirmed_from.confirmed_amount, 0))
|
||||
END as balance_needed
|
||||
COALESCE(u.balance, 0) + COALESCE(confirmed_from.confirmed_amount, 0) as balance_needed
|
||||
FROM users u
|
||||
LEFT JOIN (SELECT from_user_id,
|
||||
SUM(amount) as amount
|
||||
@@ -1161,6 +1201,15 @@ router.get('/daily-stats',
|
||||
AND created_at <= ?
|
||||
AND status IN ('confirmed', 'received')
|
||||
GROUP BY from_user_id) yesterday_out ON u.id = yesterday_out.from_user_id
|
||||
LEFT JOIN (SELECT to_user_id,
|
||||
SUM(amount) as amount
|
||||
FROM transfers
|
||||
WHERE created_at >= ?
|
||||
AND created_at <= ?
|
||||
AND transfer_type != 'user_to_user'
|
||||
AND status IN ('received')
|
||||
GROUP BY to_user_id) yesterday_system_num
|
||||
ON u.id = yesterday_system_num.to_user_id
|
||||
LEFT JOIN (SELECT to_user_id,
|
||||
SUM(amount) as amount
|
||||
FROM transfers
|
||||
@@ -1171,17 +1220,17 @@ router.get('/daily-stats',
|
||||
left join (select from_user_id,
|
||||
sum(amount) as confirmed_amount
|
||||
from transfers
|
||||
where status = 'received'
|
||||
and created_at >= ?
|
||||
and created_at <= ?
|
||||
group by from_user_id) as confirmed_from on u.id = confirmed_from.from_user_id
|
||||
WHERE u.role != 'admin'
|
||||
WHERE status IN ('confirmed', 'received')
|
||||
AND created_at >= ?
|
||||
AND created_at <= ?
|
||||
GROUP BY from_user_id) as confirmed_from on u.id = confirmed_from.from_user_id
|
||||
WHERE u.role != 'admin' AND u.user_type !='directly_operated'
|
||||
AND u.is_system_account != 1
|
||||
AND yesterday_out.amount > 0
|
||||
AND u.balance < 0
|
||||
ORDER BY balance_needed DESC, yesterday_out_amount DESC
|
||||
`, [yesterdayStartStr, yesterdayEndStr, todayStartStr, todayEndStr, todayStartStr, todayEndStr]);
|
||||
// userStats = userStats.filter(item=>item.balance_needed >= 100)
|
||||
`, [yesterdayStartStr, yesterdayEndStr, yesterdayStartStr, yesterdayEndStr,todayStartStr, todayEndStr, todayStartStr, todayEndStr]);
|
||||
// userStats = userStats.filter(item=>item.balance_needed > 100)
|
||||
userStats.forEach(item => {
|
||||
item.balance_needed = Math.abs(item.balance_needed)
|
||||
})
|
||||
|
||||
@@ -51,54 +51,6 @@ const multiUpload = multer({
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /upload/image:
|
||||
* post:
|
||||
* summary: 上传图片
|
||||
* tags: [Upload]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* multipart/form-data:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* file:
|
||||
* type: string
|
||||
* format: binary
|
||||
* description: 要上传的图片文件
|
||||
* type:
|
||||
* type: string
|
||||
* enum: [avatar, product, document]
|
||||
* default: document
|
||||
* description: 上传文件类型
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 图片上传成功
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* success:
|
||||
* type: boolean
|
||||
* example: true
|
||||
* url:
|
||||
* type: string
|
||||
* description: 上传后的文件URL
|
||||
* filename:
|
||||
* type: string
|
||||
* description: 上传后的文件名
|
||||
* 400:
|
||||
* description: 请求参数错误
|
||||
* 401:
|
||||
* description: 未授权
|
||||
* 500:
|
||||
* description: 服务器错误
|
||||
*/
|
||||
router.post('/image', authenticateToken, (req, res) => {
|
||||
upload.single('file')(req, res, async (err) => {
|
||||
if (err instanceof multer.MulterError) {
|
||||
|
||||
140
routes/users.js
140
routes/users.js
@@ -215,7 +215,7 @@ router.get('/', auth, adminAuth, async (req, res) => {
|
||||
|
||||
// 确保参数为有效数字
|
||||
const pageNum = Math.max(1, parseInt(page) || 1);
|
||||
const limitNum = Math.max(1, Math.min(100, parseInt(limit) || 10));
|
||||
const limitNum = Math.max(1, parseInt(limit) || 10);
|
||||
const offset = Math.max(0, (pageNum - 1) * limitNum);
|
||||
|
||||
let whereConditions = [];
|
||||
@@ -504,7 +504,10 @@ router.get('/stats', auth, async (req, res) => {
|
||||
|
||||
// 活跃用户数(有订单的用户)
|
||||
const [activeUsers] = await db.execute(
|
||||
'SELECT COUNT(DISTINCT from_user_id) as count FROM transfers'
|
||||
`SELECT
|
||||
COUNT(DISTINCT from_user_id) AS count
|
||||
FROM transfers
|
||||
WHERE YEARWEEK(created_at, 1) = YEARWEEK(CURDATE() - INTERVAL 1 WEEK, 1)`
|
||||
);
|
||||
const [weekUsers] = await db.execute(`
|
||||
SELECT COUNT(DISTINCT from_user_id) as count
|
||||
@@ -1546,7 +1549,37 @@ router.post('/:id/deduct-service-fee', auth, async (req, res) => {
|
||||
[distribute.inviter]
|
||||
);
|
||||
distributeUser = distributeUser[0]
|
||||
//分销是代理
|
||||
if (distributeUser.user_type == 'agent') {
|
||||
let [agentUser] = await db.execute(`
|
||||
SELECT r.*
|
||||
FROM regional_agents as r
|
||||
LEFT JOIN users au on r.user_id = au.id
|
||||
WHERE au.user_type = 'agent'
|
||||
AND r.status = 'active'
|
||||
AND r.region_id = ${user.district_id}
|
||||
`)
|
||||
if (agentUser.length > 0 && agentUser[0].user_id !== distributeUser.id) {
|
||||
//增加区域保护
|
||||
await db.execute(`
|
||||
UPDATE users
|
||||
SET balance = balance - ?
|
||||
WHERE id = ?
|
||||
`, [serviceFee * 0.05, agentUser[0].user_id])
|
||||
await db.execute(
|
||||
'INSERT INTO transfers (to_user_id,from_user_id , transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
[userId, agentUser[0].user_id, 'user_to_agent', 'received', serviceFee * 0.05, '区域保护服务费返现', 'agent']
|
||||
);
|
||||
await db.execute(
|
||||
'UPDATE users SET balance = balance - ? WHERE id = ?',
|
||||
[serviceFee * 0.65, distributeUser.id]
|
||||
);
|
||||
//记录转账记录
|
||||
await db.execute(
|
||||
'INSERT INTO transfers (to_user_id,from_user_id , transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
[userId, distributeUser.id, 'user_to_agent', 'received', serviceFee * 0.65, '用户服务费返现', 'agent']
|
||||
);
|
||||
} else {
|
||||
//给代理添加2980融豆的70% 增加区域保护
|
||||
await db.execute(
|
||||
'UPDATE users SET balance = balance - ? WHERE id = ?',
|
||||
@@ -1554,12 +1587,14 @@ router.post('/:id/deduct-service-fee', auth, async (req, res) => {
|
||||
);
|
||||
//记录转账记录
|
||||
await db.execute(
|
||||
'INSERT INTO transfers (from_user_id, to_user_id, transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
'INSERT INTO transfers (to_user_id,from_user_id , transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
[userId, distributeUser.id, 'user_to_agent', 'received', serviceFee * 0.7, '用户服务费返现', 'agent']
|
||||
);
|
||||
}
|
||||
|
||||
//记录平台利润
|
||||
await db.execute(
|
||||
'INSERT INTO transfers (from_user_id, to_user_id, transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
'INSERT INTO transfers (to_user_id,from_user_id , transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
[userId, 3512, 'user_to_system', 'received', serviceFee * 0.3, '用户服务费返现', 'system']
|
||||
);
|
||||
//记录服务费
|
||||
@@ -1577,12 +1612,12 @@ router.post('/:id/deduct-service-fee', auth, async (req, res) => {
|
||||
);
|
||||
//记录转账记录
|
||||
await db.execute(
|
||||
'INSERT INTO transfers (from_user_id, to_user_id, transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
'INSERT INTO transfers (to_user_id,from_user_id , transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
[userId, distributeUser.id, 'user_to_agent', 'received', serviceFee * 0.5, '用户服务费返现', 'agent_operated']
|
||||
);
|
||||
//记录平台利润
|
||||
await db.execute(
|
||||
'INSERT INTO transfers (from_user_id, to_user_id, transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
'INSERT INTO transfers (to_user_id , from_user_id, transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
[userId, 3512, 'user_to_system', 'received', serviceFee * 0.5, '用户服务费返现', 'system']
|
||||
);
|
||||
//记录服务费
|
||||
@@ -1615,17 +1650,17 @@ router.post('/:id/deduct-service-fee', auth, async (req, res) => {
|
||||
);
|
||||
//记录转账记录
|
||||
await db.execute(
|
||||
'INSERT INTO transfers (from_user_id, to_user_id, transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
'INSERT INTO transfers (to_user_id,from_user_id , transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
[userId, distributeUser.inviter, 'user_to_agent', 'received', serviceFee * 0.2, '用户服务费返现', 'operated_agent']
|
||||
);
|
||||
//记录直营利润
|
||||
await db.execute(
|
||||
'INSERT INTO transfers (from_user_id, to_user_id, transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
'INSERT INTO transfers (to_user_id, from_user_id , transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
[userId, distributeUser.id, 'user_to_operated', 'received', serviceFee * 0.3, '用户服务费返现', 'directly_operated']
|
||||
);
|
||||
//记录平台利润
|
||||
await db.execute(
|
||||
'INSERT INTO transfers (from_user_id, to_user_id, transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
'INSERT INTO transfers (to_user_id , from_user_id, transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
[userId, 3512, 'user_to_system', 'received', serviceFee * 0.5, '用户服务费返现', 'system']
|
||||
);
|
||||
}
|
||||
@@ -1642,17 +1677,17 @@ router.post('/:id/deduct-service-fee', auth, async (req, res) => {
|
||||
);
|
||||
//记录转账记录
|
||||
await db.execute(
|
||||
'INSERT INTO transfers (from_user_id, to_user_id, transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
'INSERT INTO transfers (to_user_id , from_user_id, transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
[userId, distributeUser.inviter, 'user_to_agent', 'received', serviceFee * 0.15, '用户服务费返现', 'agent_operated']
|
||||
);
|
||||
//记录直营利润
|
||||
await db.execute(
|
||||
'INSERT INTO transfers (from_user_id, to_user_id, transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
'INSERT INTO transfers (to_user_id , from_user_id, transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
[userId, distributeUser.id, 'user_to_operated', 'received', serviceFee * 0.35, '用户服务费返现', 'directly_operated']
|
||||
);
|
||||
//记录平台利润
|
||||
await db.execute(
|
||||
'INSERT INTO transfers (from_user_id, to_user_id, transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
'INSERT INTO transfers (to_user_id,from_user_id , transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
[userId, 3512, 'user_to_system', 'received', serviceFee * 0.5, '用户服务费返现', 'system']
|
||||
);
|
||||
}
|
||||
@@ -1669,7 +1704,7 @@ router.post('/:id/deduct-service-fee', auth, async (req, res) => {
|
||||
);
|
||||
//记录转账记录
|
||||
await db.execute(
|
||||
'INSERT INTO transfers (from_user_id, to_user_id, transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
'INSERT INTO transfers (to_user_id ,from_user_id , transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
[userId, distributeUser.inviter, 'user_to_agent', 'received', serviceFee * 0.1, '用户服务费返现', 'agent_operated']
|
||||
);
|
||||
//记录直营利润
|
||||
@@ -1679,7 +1714,7 @@ router.post('/:id/deduct-service-fee', auth, async (req, res) => {
|
||||
);
|
||||
//记录平台利润
|
||||
await db.execute(
|
||||
'INSERT INTO transfers (from_user_id, to_user_id, transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
'INSERT INTO transfers (to_user_id , from_user_id, transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
[userId, 3512, 'user_to_system', 'received', serviceFee * 0.5, '用户服务费返现', 'system']
|
||||
);
|
||||
}
|
||||
@@ -1701,29 +1736,61 @@ router.post('/:id/deduct-service-fee', auth, async (req, res) => {
|
||||
userUpInfo = userUpInfo[0]
|
||||
//判断用户上级是否是代理
|
||||
if (userUpInfo && userUpInfo.user_type === 'agent') {
|
||||
//给用户分配
|
||||
let [agentUser] = await db.execute(`
|
||||
SELECT r.*
|
||||
FROM regional_agents as r
|
||||
LEFT JOIN users au on r.user_id = au.id
|
||||
WHERE au.user_type = 'agent'
|
||||
AND r.status = 'active'
|
||||
AND r.region_id = ${user.district_id}
|
||||
`)
|
||||
if (agentUser.length > 0 && agentUser[0].user_id !== distributeUser.id) {
|
||||
//增加区域保护
|
||||
await db.execute(`
|
||||
UPDATE users
|
||||
SET balance = balance - ?
|
||||
WHERE id = ?
|
||||
`, [serviceFee * 0.05, agentUser[0].user_id])
|
||||
await db.execute(
|
||||
'INSERT INTO transfers (to_user_id,from_user_id , transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
[userId, agentUser[0].user_id, 'user_to_agent', 'received', serviceFee * 0.05, '区域保护服务费返现', 'agent']
|
||||
);
|
||||
//给代理分配
|
||||
await db.execute(
|
||||
'UPDATE users SET balance = balance - ? WHERE id = ?',
|
||||
[serviceFee * 0.2, distributeUser.id]
|
||||
[serviceFee * 0.45, userUpInfo.id]
|
||||
);
|
||||
//记录代理转账信息
|
||||
await db.execute(
|
||||
'INSERT INTO transfers (to_user_id , from_user_id, transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
[userId, userUpInfo.id, 'user_to_agent', 'received', serviceFee * 0.45, '用户服务费返现', 'agent']
|
||||
);
|
||||
}else {
|
||||
//给代理分配
|
||||
await db.execute(
|
||||
'UPDATE users SET balance = balance - ? WHERE id = ?',
|
||||
[serviceFee * 0.5, userUpInfo.id]
|
||||
);
|
||||
//记录用户转账信息
|
||||
await db.execute(
|
||||
'INSERT INTO transfers (from_user_id, to_user_id, transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
[userId, distributeUser.id, 'user_to_user', 'received', serviceFee * 0.2, '用户服务费返现', 'operated']
|
||||
);
|
||||
//记录代理转账信息
|
||||
await db.execute(
|
||||
'INSERT INTO transfers (from_user_id, to_user_id, transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
'INSERT INTO transfers (to_user_id , from_user_id, transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
[userId, userUpInfo.id, 'user_to_agent', 'received', serviceFee * 0.5, '用户服务费返现', 'agent']
|
||||
);
|
||||
}
|
||||
//给用户分配
|
||||
await db.execute(
|
||||
'UPDATE users SET balance = balance - ? WHERE id = ?',
|
||||
[serviceFee * 0.2, distributeUser.id]
|
||||
);
|
||||
//记录用户转账信息
|
||||
await db.execute(
|
||||
'INSERT INTO transfers (to_user_id ,from_user_id , transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
[userId, distributeUser.id, 'user_to_user', 'received', serviceFee * 0.2, '用户服务费返现', 'operated']
|
||||
);
|
||||
|
||||
//记录平台利润
|
||||
await db.execute(
|
||||
'INSERT INTO transfers (from_user_id, to_user_id, transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
'INSERT INTO transfers (to_user_id,from_user_id , transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
[userId, 3512, 'user_to_system', 'received', serviceFee * 0.3, '用户服务费返现', 'system']
|
||||
);
|
||||
} else {
|
||||
@@ -1734,12 +1801,12 @@ router.post('/:id/deduct-service-fee', auth, async (req, res) => {
|
||||
);
|
||||
//记录转账记录
|
||||
await db.execute(
|
||||
'INSERT INTO transfers (from_user_id, to_user_id, transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
'INSERT INTO transfers (to_user_id,from_user_id , transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
[userId, distributeUser.id, 'user_to_user', 'received', serviceFee * 0.2, '用户服务费返现', 'operated']
|
||||
);
|
||||
//记录平台利润
|
||||
await db.execute(
|
||||
'INSERT INTO transfers (from_user_id, to_user_id, transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
'INSERT INTO transfers (to_user_id ,from_user_id , transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
[userId, 3512, 'user_to_system', 'received', serviceFee * 0.8, '用户服务费返现', 'system']
|
||||
);
|
||||
|
||||
@@ -1754,25 +1821,34 @@ router.post('/:id/deduct-service-fee', auth, async (req, res) => {
|
||||
} else {
|
||||
//判断用户此区域是否有代理
|
||||
let [agentUser] = await db.execute(`
|
||||
SELECT user_id
|
||||
FROM regional_agents
|
||||
WHERE region_id = ?
|
||||
`, [users[0].district_id])
|
||||
SELECT rg.user_id
|
||||
FROM regional_agents as rg
|
||||
LEFT JOIN users ag ON ag.id = rg.user_id
|
||||
WHERE rg.region_id = ?
|
||||
AND rg.status = 'active'
|
||||
AND ag.user_type = 'agent'
|
||||
`, [user.district_id])
|
||||
if (agentUser.length > 0) {
|
||||
//给区域代理分区域保护
|
||||
await db.execute(`
|
||||
UPDATE users
|
||||
SET balance = balance - ?
|
||||
WHERE id = ?
|
||||
`, [serviceFee * 0.05, agentUser[0].user_id])
|
||||
//给代理分成5%
|
||||
await db.execute(
|
||||
'INSERT INTO transfers (from_user_id, to_user_id, transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
'INSERT INTO transfers (to_user_id ,from_user_id , transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
[userId, agentUser[0].user_id, 'user_to_regional', 'received', serviceFee * 0.05, '区域保护服务费返现', 'agent']
|
||||
)
|
||||
//记录平台利润
|
||||
await db.execute(
|
||||
'INSERT INTO transfers (from_user_id, to_user_id, transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
'INSERT INTO transfers (to_user_id , from_user_id, transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
[userId, 3512, 'user_to_system', 'received', serviceFee * 0.95, '用户服务费返现', 'system']
|
||||
);
|
||||
} else {
|
||||
//记录平台利润
|
||||
await db.execute(
|
||||
'INSERT INTO transfers (from_user_id, to_user_id, transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
'INSERT INTO transfers (to_user_id ,from_user_id , transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
[userId, 3512, 'user_to_system', 'received', serviceFee, '用户服务费返现', 'system']
|
||||
);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { getDB } = require('../database');
|
||||
const {getDB} = require('../database');
|
||||
const timeoutService = require('./timeoutService');
|
||||
const dayjs = require('dayjs');
|
||||
|
||||
@@ -117,9 +117,6 @@ class MatchingService {
|
||||
// 立即生成智能分配
|
||||
const allocations = await this.generateSmartAllocationsWithDB(orderId, userId);
|
||||
|
||||
// 检查并触发系统账户反向匹配
|
||||
// await this.checkAndTriggerSystemMatching();
|
||||
|
||||
return {
|
||||
orderId,
|
||||
matchingType,
|
||||
@@ -146,7 +143,8 @@ class MatchingService {
|
||||
const [negativeBalanceResult] = await db.execute(`
|
||||
SELECT SUM(ABS(balance)) as total_deficit
|
||||
FROM users
|
||||
WHERE is_system_account = FALSE AND balance < 0
|
||||
WHERE is_system_account = FALSE
|
||||
AND balance < 0
|
||||
`);
|
||||
|
||||
const totalDeficit = negativeBalanceResult[0].total_deficit || 0;
|
||||
@@ -156,7 +154,8 @@ class MatchingService {
|
||||
SELECT SUM(oa.amount) as total_pending
|
||||
FROM transfers oa
|
||||
JOIN users u ON oa.from_user_id = u.id
|
||||
WHERE oa.status = 'pending' AND u.is_system_account = FALSE
|
||||
WHERE oa.status = 'pending'
|
||||
AND u.is_system_account = FALSE
|
||||
`);
|
||||
|
||||
const totalPendingPayments = pendingPaymentsResult[0].total_pending || 0;
|
||||
@@ -187,8 +186,10 @@ class MatchingService {
|
||||
try {
|
||||
// 获取可用的系统账户
|
||||
const [systemAccounts] = await db.execute(`
|
||||
SELECT id, balance FROM users
|
||||
WHERE is_system_account = TRUE AND balance > 1000
|
||||
SELECT id, balance
|
||||
FROM users
|
||||
WHERE is_system_account = TRUE
|
||||
AND balance > 1000
|
||||
ORDER BY balance DESC
|
||||
LIMIT 1
|
||||
`);
|
||||
@@ -240,7 +241,8 @@ class MatchingService {
|
||||
const [negativeUsers] = await db.execute(`
|
||||
SELECT id, balance, ABS(balance) as deficit
|
||||
FROM users
|
||||
WHERE is_system_account = FALSE AND balance < 0
|
||||
WHERE is_system_account = FALSE
|
||||
AND balance < 0
|
||||
ORDER BY deficit DESC
|
||||
LIMIT 10
|
||||
`);
|
||||
@@ -342,7 +344,9 @@ class MatchingService {
|
||||
`SELECT SUM(oa.amount) as total_outbound
|
||||
FROM transfers oa
|
||||
JOIN users u ON oa.from_user_id = u.id
|
||||
WHERE DATE(oa.outbound_date) = ? AND oa.status = 'confirmed' AND u.is_system_account = FALSE`,
|
||||
WHERE DATE(oa.outbound_date) = ?
|
||||
AND oa.status = 'confirmed'
|
||||
AND u.is_system_account = FALSE`,
|
||||
[yesterdayStr]
|
||||
);
|
||||
|
||||
@@ -353,7 +357,9 @@ class MatchingService {
|
||||
`SELECT DISTINCT oa.amount
|
||||
FROM transfers oa
|
||||
JOIN users u ON oa.from_user_id = u.id
|
||||
WHERE DATE(oa.outbound_date) = ? AND oa.status = 'confirmed' AND u.is_system_account = FALSE`,
|
||||
WHERE DATE(oa.outbound_date) = ?
|
||||
AND oa.status = 'confirmed'
|
||||
AND u.is_system_account = FALSE`,
|
||||
[yesterdayStr]
|
||||
);
|
||||
|
||||
@@ -398,13 +404,21 @@ class MatchingService {
|
||||
const db = getDB();
|
||||
|
||||
try {
|
||||
await db.query('START TRANSACTION');
|
||||
// 获取订单总金额
|
||||
const [orderResult] = await db.execute(
|
||||
'SELECT amount FROM matching_orders WHERE id = ?',
|
||||
'SELECT amount FROM matching_orders WHERE id = ? FOR UPDATE',
|
||||
[orderId]
|
||||
);
|
||||
//获取用户余额
|
||||
const [user] = await db.execute(`
|
||||
SELECT balance
|
||||
FROM users
|
||||
WHERE id = ${initiatorId}
|
||||
`)
|
||||
|
||||
if (orderResult.length === 0) {
|
||||
await db.query('ROLLBACK');
|
||||
throw new Error('匹配订单不存在');
|
||||
}
|
||||
|
||||
@@ -414,12 +428,14 @@ class MatchingService {
|
||||
const allocations = await this.generateSmartAllocations(totalAmount, initiatorId);
|
||||
|
||||
if (allocations.length === 0) {
|
||||
await db.query('ROLLBACK');
|
||||
throw new Error('无法生成有效的分配方案');
|
||||
}
|
||||
|
||||
// 验证总金额(简化版验证)
|
||||
const totalAllocated = allocations.reduce((sum, allocation) => sum + allocation.amount, 0);
|
||||
if (Math.abs(totalAllocated - totalAmount) > 0.01) {
|
||||
await db.query('ROLLBACK');
|
||||
throw new Error(`分配金额不匹配:期望${totalAmount}元,实际分配${totalAllocated}元`);
|
||||
}
|
||||
|
||||
@@ -427,16 +443,16 @@ class MatchingService {
|
||||
|
||||
// 创建分配记录
|
||||
const createdAllocations = [];
|
||||
let from_user_balance = user[0].balance
|
||||
for (let i = 0; i < allocations.length; i++) {
|
||||
const allocation = allocations[i];
|
||||
|
||||
from_user_balance -= allocation.amount
|
||||
// 设置出款日期为今天,可回款时间为明天的00:00:00
|
||||
const today = dayjs();
|
||||
const tomorrow = dayjs().add(1, 'day').startOf('day');
|
||||
|
||||
const [result] = await db.execute(
|
||||
'INSERT INTO transfers (matching_order_id, from_user_id, to_user_id, amount, cycle_number, status, outbound_date, can_return_after) VALUES (?, ?, ?, ?, 1, "pending", CURDATE(), ?)',
|
||||
[orderId, initiatorId, allocation.userId, allocation.amount, tomorrow.format('YYYY-MM-DD HH:mm:ss')]
|
||||
'INSERT INTO transfers (matching_order_id, from_user_id, to_user_id, amount, cycle_number, status, outbound_date, can_return_after,from_user_balance,to_user_balance) VALUES (?, ?, ?, ?, 1, "pending", CURDATE(), ?,?,?)',
|
||||
[orderId, initiatorId, allocation.userId, allocation.amount, tomorrow.format('YYYY-MM-DD HH:mm:ss'), from_user_balance, Number(allocation.currentBalance) + Number(allocation.amount)]
|
||||
);
|
||||
|
||||
// 添加分配ID到结果中
|
||||
@@ -452,9 +468,11 @@ class MatchingService {
|
||||
|
||||
console.log(`创建智能分配: ${allocation.amount}元 从用户${initiatorId} 到用户${allocation.userId}(${allocation.username}) [${allocation.userType}]`);
|
||||
}
|
||||
await db.query('COMMIT');
|
||||
|
||||
return createdAllocations;
|
||||
} catch (error) {
|
||||
await db.query('ROLLBACK');
|
||||
console.error('生成智能分配失败:', error);
|
||||
throw error;
|
||||
}
|
||||
@@ -558,7 +576,8 @@ class MatchingService {
|
||||
const [yesterdayPayersResult] = await db.execute(
|
||||
`SELECT DISTINCT oa.from_user_id
|
||||
FROM transfers oa
|
||||
WHERE DATE(oa.outbound_date) = ? AND oa.status = 'confirmed'`,
|
||||
WHERE DATE(oa.outbound_date) = ?
|
||||
AND oa.status = 'confirmed'`,
|
||||
[yesterdayStr]
|
||||
);
|
||||
const yesterdayPayers = yesterdayPayersResult.map(row => row.from_user_id);
|
||||
@@ -600,15 +619,20 @@ class MatchingService {
|
||||
// 第一优先级:最早成为负数且通过前面检查的普通用户
|
||||
// 使用最早的转出记录时间作为成为负数的参考时间
|
||||
const [earliestNegativeUsers] = await db.execute(
|
||||
`SELECT u.id, u.balance,
|
||||
(SELECT MIN(t.created_at) FROM transfers t
|
||||
WHERE t.from_user_id = u.id AND t.status IN ('confirmed', 'received')) as first_transfer_time
|
||||
`SELECT u.id,
|
||||
u.balance,
|
||||
(SELECT MIN(t.created_at)
|
||||
FROM transfers t
|
||||
WHERE t.from_user_id = u.id
|
||||
AND t.status IN ('confirmed', 'received')) as first_transfer_time
|
||||
FROM users u
|
||||
WHERE u.id NOT IN (${placeholders})
|
||||
AND u.is_system_account = FALSE
|
||||
AND u.balance < 0
|
||||
AND (SELECT COUNT(*) FROM transfers t
|
||||
WHERE t.from_user_id = u.id AND t.status IN ('confirmed', 'received')) > 0
|
||||
AND (SELECT COUNT(*)
|
||||
FROM transfers t
|
||||
WHERE t.from_user_id = u.id
|
||||
AND t.status IN ('confirmed', 'received')) > 0
|
||||
ORDER BY first_transfer_time ASC, u.balance ASC, RAND()
|
||||
LIMIT 1`,
|
||||
excludeList
|
||||
@@ -643,7 +667,8 @@ class MatchingService {
|
||||
|
||||
// 第三优先级:其他负余额普通用户(余额为负数说明他们给其他用户转过钱,钱还没收回来)
|
||||
const [negativeBalanceUsers] = await db.execute(
|
||||
`SELECT id FROM users
|
||||
`SELECT id
|
||||
FROM users
|
||||
WHERE id NOT IN (${placeholders})
|
||||
AND is_system_account = FALSE
|
||||
AND balance < 0
|
||||
@@ -658,8 +683,10 @@ class MatchingService {
|
||||
|
||||
// 最后优先级:虚拟用户(系统账户)
|
||||
const [systemUsers] = await db.execute(
|
||||
`SELECT id FROM users
|
||||
WHERE is_system_account = TRUE AND id NOT IN (${placeholders})
|
||||
`SELECT id
|
||||
FROM users
|
||||
WHERE is_system_account = TRUE
|
||||
AND id NOT IN (${placeholders})
|
||||
ORDER BY balance DESC, RAND()
|
||||
LIMIT 1`,
|
||||
excludeList
|
||||
@@ -700,7 +727,9 @@ class MatchingService {
|
||||
try {
|
||||
// 首先获取当前用户的城市、省份和区域信息
|
||||
const [currentUserResult] = await db.execute(
|
||||
`SELECT city, province, district_id FROM users WHERE id = ?`,
|
||||
`SELECT city, province, district_id
|
||||
FROM users
|
||||
WHERE id = ?`,
|
||||
[excludeUserId]
|
||||
);
|
||||
|
||||
@@ -710,8 +739,7 @@ class MatchingService {
|
||||
|
||||
// 获取负余额用户,按区县、城市、省份优先级排序
|
||||
let [userBalanceResult] = await db.execute(
|
||||
`SELECT
|
||||
u.id as user_id,
|
||||
`SELECT u.id as user_id,
|
||||
u.balance as current_balance,
|
||||
u.city,
|
||||
u.province,
|
||||
@@ -725,15 +753,14 @@ class MatchingService {
|
||||
AND u.user_type != 'directly_operated'
|
||||
AND u.payment_status = 'paid'
|
||||
AND u.province = ?
|
||||
ORDER BY
|
||||
CASE
|
||||
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,currentUserProvince, currentUserCity, currentUserDistrictId, currentUserCity, currentUserProvince]
|
||||
[excludeUserId, currentUserProvince, currentUserCity, currentUserDistrictId, currentUserCity, currentUserProvince]
|
||||
);
|
||||
|
||||
// 处理查询到的负余额用户
|
||||
@@ -748,8 +775,7 @@ class MatchingService {
|
||||
|
||||
// 查询用户的分配订单金额统计
|
||||
const [orderStatusResult] = await db.execute(
|
||||
`SELECT
|
||||
SUM(CASE WHEN status = 'pending' THEN amount ELSE 0 END) as pending_amount
|
||||
`SELECT SUM(CASE WHEN status = 'pending' THEN amount ELSE 0 END) as pending_amount
|
||||
FROM transfers
|
||||
WHERE to_user_id = ?`,
|
||||
[user.user_id]
|
||||
@@ -757,40 +783,30 @@ class MatchingService {
|
||||
|
||||
// 查询用户的分配订单金待确认金额统计
|
||||
const [orderStatusConfirmedResult] = await db.execute(
|
||||
`SELECT
|
||||
SUM(CASE WHEN status = 'confirmed' THEN amount ELSE 0 END) as confirmed_amount
|
||||
`SELECT SUM(CASE WHEN status = 'confirmed' THEN amount ELSE 0 END) as confirmed_amount
|
||||
FROM transfers
|
||||
WHERE to_user_id = ?`,
|
||||
[user.user_id]
|
||||
);
|
||||
//查询用户给其他用户已确认的金额统计(要减去,因为款项还没回来)
|
||||
const [orderStatusConfirmedResultFrom] = await db.execute(
|
||||
`SELECT
|
||||
SUM(CASE WHEN status = 'confirmed' THEN amount ELSE 0 END) as confirmed_amount
|
||||
FROM transfers
|
||||
WHERE from_user_id = ?`,
|
||||
[user.user_id]
|
||||
);
|
||||
// 查询用户当天在matching_orders表中打出去的款项
|
||||
const today = getLocalDateString();
|
||||
const [todayOutflowResult] = await db.execute(
|
||||
`SELECT
|
||||
SUM(amount) as today_outflow
|
||||
FROM matching_orders
|
||||
WHERE initiator_id = ? AND DATE(updated_at) = ?`,
|
||||
`SELECT SUM(amount) as today_outflow
|
||||
FROM transfers
|
||||
WHERE from_user_id = ?
|
||||
AND DATE(created_at) = ?
|
||||
AND status != 'cancelled' `,
|
||||
[user.user_id, today]
|
||||
);
|
||||
|
||||
// 添加分配金额信息到用户对象
|
||||
const orderStatus = orderStatusResult[0] || { pending_amount: 0 };
|
||||
const todayOutflow = todayOutflowResult[0] || { today_outflow: 0 };
|
||||
const orderStatusConfirmedFrom = orderStatusConfirmedResultFrom[0] || { confirmed_amount: 0 };
|
||||
const orderStatusConfirmed = orderStatusConfirmedResult[0] || { confirmed_amount: 0 };
|
||||
const orderStatus = orderStatusResult[0] || {pending_amount: 0};
|
||||
const todayOutflow = todayOutflowResult[0] || {today_outflow: 0};
|
||||
const orderStatusConfirmed = orderStatusConfirmedResult[0] || {confirmed_amount: 0};
|
||||
user.today_outflow = parseFloat(todayOutflow.today_outflow) || 0;
|
||||
user.pending_amount = parseFloat(orderStatus.pending_amount) || 0;
|
||||
user.confirmed_amount = parseFloat(orderStatusConfirmed.confirmed_amount) || 0;
|
||||
user.has_active_allocations = user.current_balance + user.pending_amount + user.confirmed_amount + user.today_outflow - orderStatusConfirmedFrom.confirmed_amount;
|
||||
|
||||
user.has_active_allocations = user.current_balance + user.pending_amount + user.confirmed_amount + user.today_outflow;
|
||||
|
||||
|
||||
// 所有查询到的用户都是负余额用户,直接添加到可用列表
|
||||
@@ -834,7 +850,8 @@ class MatchingService {
|
||||
|
||||
// 第三步:获取虚拟用户作为备选
|
||||
const [virtualUsersResult] = await db.execute(
|
||||
`SELECT id, username, balance FROM users
|
||||
`SELECT id, username, balance
|
||||
FROM users
|
||||
WHERE is_system_account = TRUE
|
||||
ORDER BY balance DESC, RAND()`
|
||||
);
|
||||
@@ -884,7 +901,7 @@ class MatchingService {
|
||||
const bonus = Math.floor(Math.random() * bonusRange * 0.3); // 使用30%的bonus范围
|
||||
maxUserAllocation += bonus;
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
maxUserAllocation = maxRandomAllocation
|
||||
}
|
||||
|
||||
@@ -902,9 +919,6 @@ class MatchingService {
|
||||
amount: maxUserAllocation,
|
||||
userType: 'priority_user',
|
||||
currentBalance: user.current_balance,
|
||||
historicalNetBalance: user.historical_net_balance,
|
||||
totalPendingInflow: user.total_pending_inflow,
|
||||
availableForAllocation: user.available_for_allocation,
|
||||
todayOutflow: user.today_outflow,
|
||||
has_active_allocations: user.has_active_allocations
|
||||
});
|
||||
@@ -948,7 +962,7 @@ class MatchingService {
|
||||
let remainingToDistribute = remainingAmount;
|
||||
|
||||
for (let i = 0; i < userCapacities.length; i++) {
|
||||
const { allocation, capacity } = userCapacities[i];
|
||||
const {allocation, capacity} = userCapacities[i];
|
||||
|
||||
// 计算本次可分配的金额
|
||||
let amountToAdd = 0;
|
||||
@@ -1032,7 +1046,8 @@ class MatchingService {
|
||||
username: virtualUser.username,
|
||||
amount: randomAmounts[i],
|
||||
userType: 'virtual',
|
||||
balance: virtualUser.balance
|
||||
balance: virtualUser.balance,
|
||||
currentBalance: virtualUser.balance,
|
||||
});
|
||||
|
||||
remainingAmount -= randomAmounts[i];
|
||||
@@ -1053,30 +1068,24 @@ class MatchingService {
|
||||
// 精确控制总金额,避免超出预期
|
||||
const currentTotal = allocations.reduce((sum, a) => sum + a.amount, 0);
|
||||
console.log('剩余金额处理前:', remainingAmount, '当前总分配金额:', currentTotal, '期望总金额:', totalAmount);
|
||||
|
||||
if (remainingAmount > 0 && allocations.length > 0) {
|
||||
// 检查是否会超出总金额
|
||||
if (currentTotal + remainingAmount <= totalAmount) {
|
||||
console.log('将剩余金额', remainingAmount, '加到最后一笔分配');
|
||||
allocations[allocations.length - 1].amount += remainingAmount;
|
||||
} else {
|
||||
// 如果会超出,只加到刚好等于总金额的部分
|
||||
const allowedAmount = totalAmount - currentTotal;
|
||||
if (allowedAmount > 0) {
|
||||
|
||||
console.log('调整最后一笔分配,增加', allowedAmount, '元以达到精确总金额');
|
||||
allocations[allocations.length - 1].amount += allowedAmount;
|
||||
}
|
||||
}
|
||||
remainingAmount = 0; // 重置剩余金额
|
||||
}
|
||||
|
||||
console.log(`智能分配完成: 总金额${totalAmount}元,分配${allocations.length}笔`);
|
||||
console.log('分配详情:', allocations.map(a =>
|
||||
`${a.amount}元 -> 用户${a.userId}(${a.username}) [${a.userType}]`
|
||||
).join(', '));
|
||||
|
||||
//检查每个用户的匹配到的数量不能超过自身
|
||||
let checking = allocations.filter(item => item.userType !== 'virtual')
|
||||
let is_checking = true
|
||||
for (const user of checking) {
|
||||
if (Math.abs(user.has_active_allocations) < user.amount) {
|
||||
is_checking = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is_checking) {
|
||||
return allocations;
|
||||
}
|
||||
return []
|
||||
|
||||
|
||||
} catch (error) {
|
||||
console.error('智能分配失败:', error);
|
||||
@@ -1263,7 +1272,8 @@ class MatchingService {
|
||||
|
||||
// 检查是否存在相关的超时转账记录
|
||||
const [timeoutTransfers] = await db.execute(
|
||||
`SELECT COUNT(*) as count FROM transfers
|
||||
`SELECT COUNT(*) as count
|
||||
FROM transfers
|
||||
WHERE (from_user_id = ? OR to_user_id = ?)
|
||||
AND is_overdue = 1
|
||||
AND description LIKE ?`,
|
||||
@@ -1281,7 +1291,11 @@ class MatchingService {
|
||||
const transferDescription = description || `匹配订单 ${allocation.matching_order_id} 第 ${allocation.cycle_number} 轮转账`;
|
||||
const [transferResult] = await db.execute(
|
||||
`UPDATE transfers
|
||||
SET status = "confirmed", description = ?, deadline_at = ?, confirmed_at = NOW(), voucher_url = ?
|
||||
SET status = "confirmed",
|
||||
description = ?,
|
||||
deadline_at = ?,
|
||||
confirmed_at = NOW(),
|
||||
voucher_url = ?
|
||||
WHERE id = ?`,
|
||||
[
|
||||
transferDescription,
|
||||
@@ -1372,11 +1386,10 @@ class MatchingService {
|
||||
const offset = (parseInt(page) - 1) * parseInt(limit);
|
||||
|
||||
|
||||
|
||||
try {
|
||||
// 获取用户发起的订单
|
||||
const [orders] = await db.execute(
|
||||
`SELECT mo.*, u.username as initiator_name,u.real_name as initiator_real_name
|
||||
`SELECT mo.*, u.username as initiator_name, u.real_name as initiator_real_name
|
||||
FROM matching_orders mo
|
||||
JOIN users u ON mo.initiator_id = u.id
|
||||
WHERE mo.initiator_id = ?
|
||||
@@ -1391,7 +1404,8 @@ class MatchingService {
|
||||
FROM matching_orders mo
|
||||
JOIN users u ON mo.initiator_id = u.id
|
||||
JOIN transfers oa ON mo.id = oa.id
|
||||
WHERE mo.is_system_reverse = TRUE AND oa.to_user_id = ?
|
||||
WHERE mo.is_system_reverse = TRUE
|
||||
AND oa.to_user_id = ?
|
||||
ORDER BY mo.created_at DESC
|
||||
LIMIT ${parseInt(limit)} OFFSET ${parseInt(offset)}`,
|
||||
[userId]
|
||||
@@ -1406,7 +1420,10 @@ class MatchingService {
|
||||
// 为每个订单获取分配信息
|
||||
for (let order of allOrders) {
|
||||
const [allocations] = await db.execute(
|
||||
`SELECT * FROM transfers WHERE matching_order_id = ? ORDER BY cycle_number, created_at`,
|
||||
`SELECT *
|
||||
FROM transfers
|
||||
WHERE matching_order_id = ?
|
||||
ORDER BY cycle_number, created_at`,
|
||||
[order.id]
|
||||
);
|
||||
order.allocations = allocations;
|
||||
@@ -1420,7 +1437,6 @@ class MatchingService {
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 获取用户待处理的分配
|
||||
async getUserPendingAllocations(userId) {
|
||||
const db = getDB();
|
||||
@@ -1459,7 +1475,8 @@ class MatchingService {
|
||||
for (const allocation of allocations) {
|
||||
// 检查是否存在相关的超时转账记录
|
||||
const [timeoutTransfers] = await db.execute(
|
||||
`SELECT COUNT(*) as count FROM transfers
|
||||
`SELECT COUNT(*) as count
|
||||
FROM transfers
|
||||
WHERE (from_user_id = ? OR to_user_id = ?)
|
||||
AND is_overdue = 1
|
||||
AND description LIKE ?`,
|
||||
|
||||
@@ -241,7 +241,7 @@ class TransferService {
|
||||
// 获取转账列表
|
||||
async getTransfers(filters = {}, pagination = {}, user_type = 'user_to_user') {
|
||||
const db = getDB();
|
||||
const {page = 1, limit = 10, sort = 'created_at', order = 'desc'} = pagination;
|
||||
const {page = 1, limit = 10, sort = 'id', order = 'desc'} = pagination;
|
||||
const pageNum = parseInt(page, 10) || 1;
|
||||
const limitNum = parseInt(limit, 10) || 10;
|
||||
const offset = (pageNum - 1) * limitNum;
|
||||
@@ -283,7 +283,7 @@ class TransferService {
|
||||
|
||||
// 构建排序子句
|
||||
const validSortFields = ['id', 'amount', 'created_at', 'updated_at', 'status'];
|
||||
const sortField = validSortFields.includes(sort) ? sort : 'created_at';
|
||||
const sortField = validSortFields.includes(sort) ? sort : 'id';
|
||||
const sortOrder = order && order.toLowerCase() === 'asc' ? 'ASC' : 'DESC';
|
||||
|
||||
const orderClause = `ORDER BY t.${sortField} ${sortOrder}`;
|
||||
@@ -304,6 +304,8 @@ class TransferService {
|
||||
`SELECT t.*,
|
||||
fu.username as from_username,
|
||||
fu.real_name as from_real_name,
|
||||
fu.balance as from_balance,
|
||||
tu.balance as to_balance,
|
||||
tu.username as to_username,
|
||||
tu.real_name as to_real_name,
|
||||
f_p.name as from_province,
|
||||
@@ -322,7 +324,7 @@ class TransferService {
|
||||
LEFT JOIN china_regions t_c ON t_c.code = tu.city
|
||||
LEFT JOIN china_regions t_d ON t_d.code = tu.district_id
|
||||
${whereClause} ${orderClause}
|
||||
LIMIT ${limitNum}`,
|
||||
LIMIT ${limitNum} OFFSET ${offset}`,
|
||||
params
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user