提交
This commit is contained in:
8
.idea/data_source_mapping.xml
generated
Normal file
8
.idea/data_source_mapping.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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/users.js" value="5c67c46f-1d09-4751-a201-e01d3162c9fe" />
|
||||
<file url="file://$PROJECT_DIR$/services/transferService.js" value="5c67c46f-1d09-4751-a201-e01d3162c9fe" />
|
||||
</component>
|
||||
</project>
|
||||
1272
routes/agents.js
1272
routes/agents.js
File diff suppressed because it is too large
Load Diff
@@ -369,35 +369,31 @@ router.get('/:id/merchants', authenticateAdmin, async (req, res) => {
|
||||
const offset = (pageNum - 1) * limitNum;
|
||||
|
||||
// 检查代理是否存在
|
||||
const agentResult = await db.query('SELECT * FROM regional_agents WHERE id = ?', [id]);
|
||||
const agentResult = await db.query(`SELECT * FROM users WHERE id = ? AND (user_type='agent' OR user_type='agent_directly')`, [id]);
|
||||
if (!agentResult || agentResult.length === 0) {
|
||||
return res.status(404).json({ success: false, message: '代理不存在' });
|
||||
}
|
||||
|
||||
// 查询代理的商户列表
|
||||
const merchantsQuery = `
|
||||
SELECT
|
||||
u.id,
|
||||
u.real_name,
|
||||
u.phone,
|
||||
u.created_at,
|
||||
am.created_at as joined_at,
|
||||
COUNT(mo.id) as match_count,
|
||||
COUNT(CASE WHEN mo.status = 'completed' THEN 1 END) as completed_matches
|
||||
FROM agent_merchants am
|
||||
JOIN users u ON am.merchant_id = u.id
|
||||
LEFT JOIN matching_orders mo ON u.id = mo.initiator_id
|
||||
WHERE am.agent_id = ?
|
||||
GROUP BY u.id, am.created_at
|
||||
ORDER BY am.created_at DESC
|
||||
LIMIT ${limitNum} OFFSET ${offset}
|
||||
SELECT u.id,
|
||||
u.real_name,
|
||||
u.phone,
|
||||
u.created_at,
|
||||
u.created_at as joined_at
|
||||
FROM users u
|
||||
WHERE u.inviter = ${id}
|
||||
GROUP BY u.id, u.created_at
|
||||
ORDER BY u.created_at
|
||||
DESC
|
||||
LIMIT ${limitNum} OFFSET ${offset}
|
||||
`;
|
||||
|
||||
const merchants = await db.query(merchantsQuery, [id]);
|
||||
|
||||
// 查询总数
|
||||
const totalResult = await db.query(
|
||||
'SELECT COUNT(*) as total FROM agent_merchants WHERE agent_id = ?',
|
||||
'SELECT COUNT(*) as total FROM users WHERE inviter = ?',
|
||||
[id]
|
||||
);
|
||||
const total = totalResult && totalResult.length > 0 ? totalResult[0].total : 0;
|
||||
@@ -475,13 +471,13 @@ router.get('/:id/merchant-transfers', authenticateAdmin, async (req, res) => {
|
||||
const offset = (pageNum - 1) * limitNum;
|
||||
|
||||
// 检查代理是否存在
|
||||
const agentResult = await db.query('SELECT * FROM regional_agents WHERE id = ?', [id]);
|
||||
if (!agentResult || agentResult.length === 0) {
|
||||
return res.status(404).json({ success: false, message: '代理不存在' });
|
||||
}
|
||||
const agentResult = await db.query(`SELECT * FROM users WHERE id = ? AND (user_type='agent' OR user_type='agent_directly')`, [id]);
|
||||
if (!agentResult || agentResult.length === 0) {
|
||||
return res.status(404).json({ success: false, message: '代理不存在' });
|
||||
}
|
||||
|
||||
// 构建查询条件
|
||||
let whereConditions = ['am.agent_id = ?'];
|
||||
let whereConditions = ['am.inviter = ?'];
|
||||
let queryParams = [id];
|
||||
|
||||
if (merchant_id) {
|
||||
@@ -493,36 +489,35 @@ router.get('/:id/merchant-transfers', authenticateAdmin, async (req, res) => {
|
||||
|
||||
// 查询商户转账记录
|
||||
const transfersQuery = `
|
||||
SELECT
|
||||
t.id,
|
||||
t.from_user_id,
|
||||
t.to_user_id,
|
||||
t.amount,
|
||||
t.status,
|
||||
t.transfer_type,
|
||||
t.description,
|
||||
t.created_at,
|
||||
t.confirmed_at,
|
||||
from_user.real_name as from_real_name,
|
||||
CONCAT(SUBSTRING(from_user.phone, 1, 3), '****', SUBSTRING(from_user.phone, -4)) as from_phone_masked,
|
||||
to_user.real_name as to_real_name,
|
||||
CONCAT(SUBSTRING(to_user.phone, 1, 3), '****', SUBSTRING(to_user.phone, -4)) as to_phone_masked
|
||||
FROM agent_merchants am
|
||||
JOIN transfers t ON am.merchant_id = t.from_user_id
|
||||
LEFT JOIN users from_user ON t.from_user_id = from_user.id
|
||||
LEFT JOIN users to_user ON t.to_user_id = to_user.id
|
||||
WHERE ${whereClause}
|
||||
ORDER BY t.created_at DESC
|
||||
LIMIT ${limitNum} OFFSET ${offset}
|
||||
SELECT t.id,
|
||||
t.from_user_id,
|
||||
t.to_user_id,
|
||||
t.amount,
|
||||
t.status,
|
||||
t.transfer_type,
|
||||
t.description,
|
||||
t.created_at,
|
||||
t.confirmed_at,
|
||||
from_user.real_name as from_real_name,
|
||||
CONCAT(SUBSTRING(from_user.phone, 1, 3), '****', SUBSTRING(from_user.phone, -4)) as from_phone_masked,
|
||||
to_user.real_name as to_real_name,
|
||||
CONCAT(SUBSTRING(to_user.phone, 1, 3), '****', SUBSTRING(to_user.phone, -4)) as to_phone_masked
|
||||
FROM users as am
|
||||
JOIN transfers t ON am.id = t.from_user_id
|
||||
LEFT JOIN users from_user ON t.from_user_id = from_user.id
|
||||
LEFT JOIN users to_user ON t.to_user_id = to_user.id
|
||||
WHERE ${whereClause}
|
||||
ORDER BY t.created_at DESC
|
||||
LIMIT ${limitNum} OFFSET ${offset}
|
||||
`;
|
||||
|
||||
console.log(transfersQuery,queryParams);
|
||||
const transfers = await db.query(transfersQuery, queryParams);
|
||||
|
||||
// 查询总数
|
||||
const totalQuery = `
|
||||
SELECT COUNT(*) as total
|
||||
FROM agent_merchants am
|
||||
JOIN transfers t ON am.merchant_id = t.from_user_id
|
||||
FROM users am
|
||||
JOIN transfers t ON am.id = t.from_user_id
|
||||
WHERE ${whereClause}
|
||||
`;
|
||||
const totalResult = await db.query(totalQuery, queryParams);
|
||||
|
||||
@@ -31,7 +31,37 @@ router.post('/register', async (req, res) => {
|
||||
if (!captchaId || !captchaText) {
|
||||
return res.status(400).json({success: false, message: '图形验证码不能为空'});
|
||||
}
|
||||
const storedCaptcha = global.captchaStore.get(captchaId);
|
||||
console.log(storedCaptcha);
|
||||
|
||||
if (!storedCaptcha) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '验证码不存在或已过期'
|
||||
});
|
||||
}
|
||||
|
||||
// 检查是否过期
|
||||
if (Date.now() > storedCaptcha.expires) {
|
||||
global.captchaStore.delete(captchaId);
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '验证码已过期'
|
||||
});
|
||||
}
|
||||
|
||||
// 验证验证码(不区分大小写)
|
||||
const isValid = storedCaptcha.text === captchaText.toLowerCase();
|
||||
|
||||
// 删除已验证的验证码
|
||||
global.captchaStore.delete(captchaId);
|
||||
|
||||
if (!isValid) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '验证码错误'
|
||||
});
|
||||
}
|
||||
if (!smsCode) {
|
||||
return res.status(400).json({success: false, message: '短信验证码不能为空'});
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ function generateSMSCode() {
|
||||
router.post('/send', async (req, res) => {
|
||||
try {
|
||||
const { phone } = req.body
|
||||
|
||||
console.log(phone)
|
||||
// 验证手机号格式
|
||||
const phoneRegex = /^1[3-9]\d{9}$/
|
||||
if (!phoneRegex.test(phone)) {
|
||||
@@ -141,6 +141,11 @@ 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,
|
||||
|
||||
@@ -341,59 +341,7 @@ router.post('/confirm-not-received',
|
||||
}
|
||||
);
|
||||
|
||||
// 触发返还转账逻辑
|
||||
async function triggerReturnTransfers(db, user_id, total_amount) {
|
||||
// 将总金额分成3笔随机金额
|
||||
const amounts = generateRandomAmounts(total_amount, 3);
|
||||
const batch_id = `return_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
|
||||
// 获取公户ID
|
||||
const [publicAccount] = await db.execute(`
|
||||
SELECT u.id
|
||||
FROM users u
|
||||
WHERE u.username = 'public_account'
|
||||
`);
|
||||
|
||||
if (publicAccount.length === 0) {
|
||||
throw new Error('公户不存在');
|
||||
}
|
||||
|
||||
const public_user_id = publicAccount[0].id;
|
||||
|
||||
// 创建3笔返还转账记录
|
||||
for (let i = 0; i < amounts.length; i++) {
|
||||
await db.execute(`
|
||||
INSERT INTO transfers (from_user_id, to_user_id, amount, transfer_type, description, batch_id, status)
|
||||
VALUES (?, ?, ?, 'return', ?, ?, 'pending')
|
||||
`, [
|
||||
public_user_id,
|
||||
user_id,
|
||||
amounts[i],
|
||||
`返还转账 ${i + 1}/3`,
|
||||
batch_id
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// 生成随机金额分配
|
||||
function generateRandomAmounts(total, count) {
|
||||
const amounts = [];
|
||||
let remaining = parseFloat(total);
|
||||
|
||||
for (let i = 0; i < count - 1; i++) {
|
||||
// 确保每笔至少1元,最多不超过剩余金额的80%
|
||||
const min = 1;
|
||||
const max = Math.max(min, remaining * 0.8);
|
||||
const amount = Math.round((Math.random() * (max - min) + min) * 100) / 100;
|
||||
amounts.push(amount);
|
||||
remaining -= amount;
|
||||
}
|
||||
|
||||
// 最后一笔是剩余金额
|
||||
amounts.push(Math.round(remaining * 100) / 100);
|
||||
|
||||
return amounts;
|
||||
}
|
||||
|
||||
// 获取用户转账记录
|
||||
router.get('/user/:userId', authenticateToken, async (req, res) => {
|
||||
@@ -413,7 +361,7 @@ router.get('/user/:userId', authenticateToken, async (req, res) => {
|
||||
const limitNum = Math.max(1, Math.min(100, parseInt(limit) || 10));
|
||||
const offset = Math.max(0, (pageNum - 1) * limitNum);
|
||||
|
||||
let whereClause = 'WHERE (t.from_user_id = ? OR t.to_user_id = ?)';
|
||||
let whereClause = `WHERE source_type='manual' AND (t.from_user_id = ? OR t.to_user_id = ?)`;
|
||||
const userIdInt = parseInt(userId);
|
||||
let listParams = [userIdInt, userIdInt];
|
||||
let countParams = [userIdInt, userIdInt];
|
||||
|
||||
@@ -1547,7 +1547,7 @@ router.post('/:id/deduct-service-fee', auth, async (req, res) => {
|
||||
);
|
||||
distributeUser = distributeUser[0]
|
||||
if (distributeUser.user_type == 'agent') {
|
||||
//给代理添加2980融豆的70%
|
||||
//给代理添加2980融豆的70% 增加区域保护
|
||||
await db.execute(
|
||||
'UPDATE users SET balance = balance - ? WHERE id = ?',
|
||||
[serviceFee * 0.7, distributeUser.id]
|
||||
@@ -1578,7 +1578,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 (?, ?, ?,?,?,?,?)',
|
||||
[userId, distributeUser.id, 'user_to_agent', 'received', serviceFee * 0.5, '用户服务费返现', 'agent']
|
||||
[userId, distributeUser.id, 'user_to_agent', 'received', serviceFee * 0.5, '用户服务费返现', 'agent_operated']
|
||||
);
|
||||
//记录平台利润
|
||||
await db.execute(
|
||||
@@ -1603,7 +1603,7 @@ router.post('/:id/deduct-service-fee', auth, async (req, res) => {
|
||||
);
|
||||
orderCount = orderCount[0]
|
||||
if (orderCount.total <= 5) {
|
||||
//给直营代理20%融豆给平台50%融豆给用户30%
|
||||
//给直营代理20%融豆给平台50% 融豆给用户30%
|
||||
await db.execute(
|
||||
'UPDATE users SET balance = balance - ? WHERE id = ?',
|
||||
[serviceFee * 0.2, distributeUser.inviter]
|
||||
@@ -1643,12 +1643,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 (?, ?, ?,?,?,?,?)',
|
||||
[userId, distributeUser.inviter, 'user_to_agent', 'received', serviceFee * 0.2, '用户服务费返现', 'operated_agent']
|
||||
[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 (?, ?, ?,?,?,?,?)',
|
||||
[userId, distributeUser.id, 'user_to_operated', 'received', serviceFee * 0.3, '用户服务费返现', 'directly_operated']
|
||||
[userId, distributeUser.id, 'user_to_operated', 'received', serviceFee * 0.35, '用户服务费返现', 'directly_operated']
|
||||
);
|
||||
//记录平台利润
|
||||
await db.execute(
|
||||
@@ -1670,12 +1670,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 (?, ?, ?,?,?,?,?)',
|
||||
[userId, distributeUser.inviter, 'user_to_agent', 'received', serviceFee * 0.2, '用户服务费返现', 'operated_agent']
|
||||
[userId, distributeUser.inviter, 'user_to_agent', 'received', serviceFee * 0.1, '用户服务费返现', 'agent_operated']
|
||||
);
|
||||
//记录直营利润
|
||||
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_operated', 'received', serviceFee * 0.3, '用户服务费返现', 'directly_operated']
|
||||
[userId, distributeUser.id, 'user_to_operated', 'received', serviceFee * 0.4, '用户服务费返现', 'directly_operated']
|
||||
);
|
||||
//记录平台利润
|
||||
await db.execute(
|
||||
@@ -1714,12 +1714,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 (?, ?, ?,?,?,?,?)',
|
||||
[userId, distributeUser.id, 'user_to_user', 'received', serviceFee * 0.2, '用户服务费返现', 'manual']
|
||||
[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 (?, ?, ?,?,?,?,?)',
|
||||
[userId, userUpInfo.id, 'user_to_agent', 'received', serviceFee * 0.5, '用户服务费返现', 'manual']
|
||||
[userId, userUpInfo.id, 'user_to_agent', 'received', serviceFee * 0.5, '用户服务费返现', 'agent']
|
||||
);
|
||||
//记录平台利润
|
||||
await db.execute(
|
||||
@@ -1735,7 +1735,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 (?, ?, ?,?,?,?,?)',
|
||||
[userId, distributeUser.id, 'user_to_agent', 'received', serviceFee * 0.2, '用户服务费返现', 'manual']
|
||||
[userId, distributeUser.id, 'user_to_user', 'received', serviceFee * 0.2, '用户服务费返现', 'operated']
|
||||
);
|
||||
//记录平台利润
|
||||
await db.execute(
|
||||
@@ -1762,7 +1762,7 @@ router.post('/:id/deduct-service-fee', auth, async (req, res) => {
|
||||
//给代理分成5%
|
||||
await db.execute(
|
||||
'INSERT INTO transfers (from_user_id, to_user_id, transfer_type,status,amount,description,source_type) VALUES (?, ?, ?,?,?,?,?)',
|
||||
[userId, agentUser[0].user_id, 'user_to_regional', 'received', serviceFee * 0.05, '用户服务费返现', 'agent']
|
||||
[userId, agentUser[0].user_id, 'user_to_regional', 'received', serviceFee * 0.05, '区域保护服务费返现', 'agent']
|
||||
)
|
||||
//记录平台利润
|
||||
await db.execute(
|
||||
|
||||
@@ -1046,9 +1046,9 @@ class MatchingService {
|
||||
}
|
||||
|
||||
// 确保至少有最小笔数
|
||||
if (allocations.length < minTransfers) {
|
||||
throw new Error(`无法生成足够的分配:需要至少${minTransfers}笔,但只能生成${allocations.length}笔`);
|
||||
}
|
||||
// if (allocations.length < minTransfers) {
|
||||
// throw new Error(`无法生成足够的分配:需要至少${minTransfers}笔,但只能生成${allocations.length}笔`);
|
||||
// }
|
||||
|
||||
// 精确控制总金额,避免超出预期
|
||||
const currentTotal = allocations.reduce((sum, a) => sum + a.amount, 0);
|
||||
|
||||
@@ -363,7 +363,7 @@ class TransferService {
|
||||
}
|
||||
}
|
||||
|
||||
async getTransfersHistory(filters = {}, pagination = {}, user_type = 'user_to_user') {
|
||||
async getTransfersHistory(filters = {}, pagination = {}, user_type = 'manual') {
|
||||
const db = getDB();
|
||||
const {page = 1, limit = 10, sort = 'created_at', order = 'desc'} = pagination;
|
||||
const pageNum = parseInt(page, 10) || 1;
|
||||
@@ -372,7 +372,7 @@ class TransferService {
|
||||
|
||||
let whereClause = 'WHERE 1=1 ';
|
||||
const params = [];
|
||||
whereClause += `AND transfer_type != '${user_type}'`;
|
||||
whereClause += `AND source_type != '${user_type}'`;
|
||||
// 构建查询条件
|
||||
if (filters.user_id) {
|
||||
whereClause += ' AND (from_user_id = ? OR to_user_id = ?)';
|
||||
|
||||
Reference in New Issue
Block a user