邀请佣金.
This commit is contained in:
parent
bbaf345509
commit
2e90b3e4b2
|
|
@ -195,8 +195,16 @@
|
||||||
<span class="value">{{ userDetails.invitations.totalInvites }}</span>
|
<span class="value">{{ userDetails.invitations.totalInvites }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-item">
|
<div class="stat-item">
|
||||||
<span class="label">累计奖励</span>
|
<span class="label">已付费人数</span>
|
||||||
<span class="value primary">¥{{ parseFloat(userDetails.invitations.totalRewards || 0).toFixed(2) }}</span>
|
<span class="value success">{{ userDetails.invitations.paidInvites || 0 }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="label">累计奖励(¥)</span>
|
||||||
|
<span class="value primary">¥{{ parseFloat(userDetails.invitations.totalRewardsRmb || userDetails.invitations.totalRewards || 0).toFixed(2) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item" v-if="parseFloat(userDetails.invitations.totalRewardsPeso || 0) > 0">
|
||||||
|
<span class="label">累计奖励(₱)</span>
|
||||||
|
<span class="value primary">₱{{ parseFloat(userDetails.invitations.totalRewardsPeso || 0).toFixed(2) }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
@ -247,12 +255,100 @@
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Invited Users Details -->
|
||||||
|
<div class="invited-users-section" v-if="userDetails.invitedUsers && userDetails.invitedUsers.length > 0">
|
||||||
|
<h4>邀请用户记录</h4>
|
||||||
|
<el-table :data="userDetails.invitedUsers" stripe border size="small" max-height="400">
|
||||||
|
<el-table-column prop="user.nickname" label="用户昵称" width="120">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ row.user?.nickname || '-' }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="user.uid" label="UID" width="100">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ row.user?.uid || '-' }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="orderCount" label="订单数" width="80" align="center">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-tag :type="row.orderCount > 0 ? 'success' : 'info'" size="small">
|
||||||
|
{{ row.orderCount }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="累计奖励" width="180">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<div>
|
||||||
|
<span v-if="parseFloat(row.totalCommissionRmb) > 0" class="reward-amount">¥{{ row.totalCommissionRmb }}</span>
|
||||||
|
<span v-if="parseFloat(row.totalCommissionPeso) > 0" class="reward-amount peso">₱{{ row.totalCommissionPeso }}</span>
|
||||||
|
<span v-if="parseFloat(row.totalCommissionRmb) === 0 && parseFloat(row.totalCommissionPeso) === 0">-</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="注册时间" width="160">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ formatDate(row.user?.registeredAt) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="操作" width="100" align="center">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-button type="primary" link size="small" @click="showOrderDetails(row)" :disabled="row.orderCount === 0">
|
||||||
|
查看订单
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<el-button @click="detailsDialogVisible = false">关闭</el-button>
|
<el-button @click="detailsDialogVisible = false">关闭</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- Order Details Dialog -->
|
||||||
|
<el-dialog
|
||||||
|
v-model="orderDetailsDialogVisible"
|
||||||
|
title="订单详情"
|
||||||
|
width="700px"
|
||||||
|
destroy-on-close
|
||||||
|
>
|
||||||
|
<div class="order-details" v-if="selectedInvitedUser">
|
||||||
|
<el-descriptions :column="2" border size="small">
|
||||||
|
<el-descriptions-item label="用户昵称">{{ selectedInvitedUser.user?.nickname || '-' }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="UID">{{ selectedInvitedUser.user?.uid || '-' }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="订单数">{{ selectedInvitedUser.orderCount }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="累计奖励">
|
||||||
|
<span v-if="parseFloat(selectedInvitedUser.totalCommissionRmb) > 0">¥{{ selectedInvitedUser.totalCommissionRmb }}</span>
|
||||||
|
<span v-if="parseFloat(selectedInvitedUser.totalCommissionPeso) > 0"> ₱{{ selectedInvitedUser.totalCommissionPeso }}</span>
|
||||||
|
</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
|
||||||
|
<h4 style="margin: 16px 0 12px;">订单记录</h4>
|
||||||
|
<el-table :data="selectedInvitedUser.orders" stripe border size="small" max-height="300">
|
||||||
|
<el-table-column prop="orderNo" label="订单号" width="160" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="paymentTime" label="支付时间" width="160">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ formatDate(row.paymentTime || row.createdAt) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="支付金额" width="100" align="right">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ row.currency === 'PHP' ? '₱' : '¥' }}{{ row.paymentAmount }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="奖励金额" width="100" align="right">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<span class="reward-text">{{ row.currency === 'PHP' ? '₱' : '¥' }}{{ row.commissionAmount }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="orderDetailsDialogVisible = false">关闭</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -286,6 +382,10 @@ const detailsDialogVisible = ref(false)
|
||||||
const detailsLoading = ref(false)
|
const detailsLoading = ref(false)
|
||||||
const userDetails = ref(null)
|
const userDetails = ref(null)
|
||||||
|
|
||||||
|
// Order details dialog state
|
||||||
|
const orderDetailsDialogVisible = ref(false)
|
||||||
|
const selectedInvitedUser = ref(null)
|
||||||
|
|
||||||
// Fetch user list
|
// Fetch user list
|
||||||
async function fetchUsers() {
|
async function fetchUsers() {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
|
|
@ -380,6 +480,12 @@ function handleViewDetails(row) {
|
||||||
fetchUserDetails(row.id)
|
fetchUserDetails(row.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Show order details for invited user
|
||||||
|
function showOrderDetails(invitedUser) {
|
||||||
|
selectedInvitedUser.value = invitedUser
|
||||||
|
orderDetailsDialogVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
// Handle toggle status
|
// Handle toggle status
|
||||||
async function handleToggleStatus(row) {
|
async function handleToggleStatus(row) {
|
||||||
const newStatus = row.status === 'active' ? 'suspended' : 'active'
|
const newStatus = row.status === 'active' ? 'suspended' : 'active'
|
||||||
|
|
@ -568,10 +674,37 @@ onMounted(() => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.invited-users-section {
|
||||||
|
margin-top: 20px;
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
color: #303133;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reward-amount {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #409eff;
|
||||||
|
margin-right: 8px;
|
||||||
|
|
||||||
|
&.peso {
|
||||||
|
color: #67c23a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.balance {
|
.balance {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #409eff;
|
color: #409eff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.order-details {
|
||||||
|
.reward-text {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #67c23a;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,38 @@ const getMyCommissionStats = async (req, res) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get invited users with their commission details
|
||||||
|
* GET /api/v1/commissions/invited-users
|
||||||
|
*/
|
||||||
|
const getInvitedUsers = async (req, res) => {
|
||||||
|
try {
|
||||||
|
const userId = req.user.id;
|
||||||
|
const { page, limit } = req.query;
|
||||||
|
|
||||||
|
const result = await commissionService.getInvitedUsersWithCommissions(userId, {
|
||||||
|
page,
|
||||||
|
limit,
|
||||||
|
});
|
||||||
|
|
||||||
|
return res.status(200).json({
|
||||||
|
success: true,
|
||||||
|
data: result,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
return res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
error: {
|
||||||
|
code: 'GET_INVITED_USERS_ERROR',
|
||||||
|
message: 'Failed to get invited users',
|
||||||
|
details: error.message,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
getMyCommissions,
|
getMyCommissions,
|
||||||
getMyCommissionStats,
|
getMyCommissionStats,
|
||||||
|
getInvitedUsers,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -22,4 +22,11 @@ router.get('/', authenticateUser, commissionController.getMyCommissions);
|
||||||
*/
|
*/
|
||||||
router.get('/stats', authenticateUser, commissionController.getMyCommissionStats);
|
router.get('/stats', authenticateUser, commissionController.getMyCommissionStats);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @route GET /api/v1/commissions/invited-users
|
||||||
|
* @desc Get invited users with their commission details
|
||||||
|
* @access Private (User)
|
||||||
|
*/
|
||||||
|
router.get('/invited-users', authenticateUser, commissionController.getInvitedUsers);
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ const Appointment = require('../models/Appointment');
|
||||||
const Invitation = require('../models/Invitation');
|
const Invitation = require('../models/Invitation');
|
||||||
const Withdrawal = require('../models/Withdrawal');
|
const Withdrawal = require('../models/Withdrawal');
|
||||||
const LoginHistory = require('../models/LoginHistory');
|
const LoginHistory = require('../models/LoginHistory');
|
||||||
|
const Commission = require('../models/Commission');
|
||||||
|
const PaymentOrder = require('../models/PaymentOrder');
|
||||||
const { Op } = require('sequelize');
|
const { Op } = require('sequelize');
|
||||||
const { Parser } = require('json2csv');
|
const { Parser } = require('json2csv');
|
||||||
|
|
||||||
|
|
@ -152,21 +154,118 @@ const getUserDetails = async (userId) => {
|
||||||
appointmentCounts.total += parseInt(stat.count);
|
appointmentCounts.total += parseInt(stat.count);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get invitation statistics
|
// Get invitation statistics from Commission table (more accurate)
|
||||||
const invitationStats = await Invitation.findAll({
|
const commissions = await Commission.findAll({
|
||||||
where: { inviterId: userId },
|
where: { inviterId: userId, status: 'credited' },
|
||||||
attributes: [
|
attributes: ['commissionAmount', 'currency'],
|
||||||
[require('sequelize').fn('COUNT', require('sequelize').col('id')), 'totalInvites'],
|
|
||||||
[require('sequelize').fn('SUM', require('sequelize').col('reward_amount')), 'totalRewards'],
|
|
||||||
],
|
|
||||||
raw: true,
|
raw: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let totalRewardsRmb = 0;
|
||||||
|
let totalRewardsPeso = 0;
|
||||||
|
commissions.forEach(c => {
|
||||||
|
const amount = parseFloat(c.commissionAmount || 0);
|
||||||
|
if (c.currency === 'PHP') {
|
||||||
|
totalRewardsPeso += amount;
|
||||||
|
} else {
|
||||||
|
totalRewardsRmb += amount;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get invited users count
|
||||||
|
const invitedUsersCount = await User.count({
|
||||||
|
where: { invitedBy: userId },
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get paid invites count
|
||||||
|
const paidInvitesCount = await Commission.count({
|
||||||
|
where: { inviterId: userId, status: 'credited' },
|
||||||
|
distinct: true,
|
||||||
|
col: 'invitee_id',
|
||||||
|
});
|
||||||
|
|
||||||
const invitationCounts = {
|
const invitationCounts = {
|
||||||
totalInvites: parseInt(invitationStats[0]?.totalInvites || 0),
|
totalInvites: invitedUsersCount,
|
||||||
totalRewards: parseFloat(invitationStats[0]?.totalRewards || 0),
|
paidInvites: paidInvitesCount,
|
||||||
|
totalRewards: totalRewardsRmb,
|
||||||
|
totalRewardsRmb: totalRewardsRmb,
|
||||||
|
totalRewardsPeso: totalRewardsPeso,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Get invited users with their commission details
|
||||||
|
const invitedUsers = await User.findAll({
|
||||||
|
where: { invitedBy: userId },
|
||||||
|
attributes: ['id', 'uid', 'nickname', 'avatar', 'createdAt'],
|
||||||
|
order: [['createdAt', 'DESC']],
|
||||||
|
limit: 50,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get commission details for each invited user
|
||||||
|
const invitedUsersWithCommissions = await Promise.all(
|
||||||
|
invitedUsers.map(async (invitee) => {
|
||||||
|
const userCommissions = await Commission.findAll({
|
||||||
|
where: {
|
||||||
|
inviterId: userId,
|
||||||
|
inviteeId: invitee.id,
|
||||||
|
status: 'credited'
|
||||||
|
},
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: PaymentOrder,
|
||||||
|
as: 'paymentOrder',
|
||||||
|
attributes: ['id', 'orderNo', 'serviceContent', 'paymentTime', 'amountRmb', 'amountPeso'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
order: [['createdAt', 'DESC']],
|
||||||
|
});
|
||||||
|
|
||||||
|
let userTotalRmb = 0;
|
||||||
|
let userTotalPeso = 0;
|
||||||
|
let userPaymentRmb = 0;
|
||||||
|
let userPaymentPeso = 0;
|
||||||
|
|
||||||
|
const orders = userCommissions.map(c => {
|
||||||
|
const commissionAmount = parseFloat(c.commissionAmount);
|
||||||
|
const paymentAmount = parseFloat(c.paymentAmount);
|
||||||
|
|
||||||
|
if (c.currency === 'PHP') {
|
||||||
|
userTotalPeso += commissionAmount;
|
||||||
|
userPaymentPeso += paymentAmount;
|
||||||
|
} else {
|
||||||
|
userTotalRmb += commissionAmount;
|
||||||
|
userPaymentRmb += paymentAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: c.id,
|
||||||
|
orderNo: c.paymentOrder?.orderNo || '-',
|
||||||
|
serviceContent: c.paymentOrder?.serviceContent || '-',
|
||||||
|
paymentTime: c.paymentOrder?.paymentTime || c.createdAt,
|
||||||
|
paymentAmount: paymentAmount.toFixed(2),
|
||||||
|
commissionAmount: commissionAmount.toFixed(2),
|
||||||
|
currency: c.currency || 'RMB',
|
||||||
|
createdAt: c.createdAt,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
user: {
|
||||||
|
id: invitee.id,
|
||||||
|
uid: invitee.uid,
|
||||||
|
nickname: invitee.nickname,
|
||||||
|
avatar: invitee.avatar,
|
||||||
|
registeredAt: invitee.createdAt,
|
||||||
|
},
|
||||||
|
orderCount: orders.length,
|
||||||
|
orders,
|
||||||
|
totalPaymentRmb: userPaymentRmb.toFixed(2),
|
||||||
|
totalPaymentPeso: userPaymentPeso.toFixed(2),
|
||||||
|
totalCommissionRmb: userTotalRmb.toFixed(2),
|
||||||
|
totalCommissionPeso: userTotalPeso.toFixed(2),
|
||||||
|
};
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
// Get withdrawal statistics
|
// Get withdrawal statistics
|
||||||
const withdrawalStats = await Withdrawal.findAll({
|
const withdrawalStats = await Withdrawal.findAll({
|
||||||
where: { userId },
|
where: { userId },
|
||||||
|
|
@ -207,6 +306,7 @@ const getUserDetails = async (userId) => {
|
||||||
inviter,
|
inviter,
|
||||||
appointments: appointmentCounts,
|
appointments: appointmentCounts,
|
||||||
invitations: invitationCounts,
|
invitations: invitationCounts,
|
||||||
|
invitedUsers: invitedUsersWithCommissions,
|
||||||
withdrawals: withdrawalCounts,
|
withdrawals: withdrawalCounts,
|
||||||
loginHistory,
|
loginHistory,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -125,19 +125,20 @@ const getCommissionsByInviter = async (inviterId, options = {}) => {
|
||||||
|
|
||||||
const records = rows.map(commission => ({
|
const records = rows.map(commission => ({
|
||||||
id: commission.id,
|
id: commission.id,
|
||||||
invitee: {
|
invitee: commission.invitee ? {
|
||||||
id: commission.invitee.id,
|
id: commission.invitee.id,
|
||||||
uid: commission.invitee.uid,
|
uid: commission.invitee.uid,
|
||||||
nickname: commission.invitee.nickname,
|
nickname: commission.invitee.nickname,
|
||||||
avatar: commission.invitee.avatar,
|
avatar: commission.invitee.avatar,
|
||||||
},
|
} : null,
|
||||||
paymentOrder: {
|
paymentOrder: commission.paymentOrder ? {
|
||||||
id: commission.paymentOrder.id,
|
id: commission.paymentOrder.id,
|
||||||
orderNo: commission.paymentOrder.orderNo,
|
orderNo: commission.paymentOrder.orderNo,
|
||||||
serviceContent: commission.paymentOrder.serviceContent,
|
serviceContent: commission.paymentOrder.serviceContent,
|
||||||
paymentTime: commission.paymentOrder.paymentTime,
|
paymentTime: commission.paymentOrder.paymentTime,
|
||||||
},
|
} : null,
|
||||||
paymentAmount: parseFloat(commission.paymentAmount).toFixed(2),
|
paymentAmount: parseFloat(commission.paymentAmount).toFixed(2),
|
||||||
|
currency: commission.currency || 'RMB',
|
||||||
commissionRate: `${(parseFloat(commission.commissionRate) * 100).toFixed(2)}%`,
|
commissionRate: `${(parseFloat(commission.commissionRate) * 100).toFixed(2)}%`,
|
||||||
commissionAmount: parseFloat(commission.commissionAmount).toFixed(2),
|
commissionAmount: parseFloat(commission.commissionAmount).toFixed(2),
|
||||||
createdAt: commission.createdAt,
|
createdAt: commission.createdAt,
|
||||||
|
|
@ -154,6 +155,104 @@ const getCommissionsByInviter = async (inviterId, options = {}) => {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get invited users with their commission details (grouped by user)
|
||||||
|
* @param {string} inviterId - Inviter user ID
|
||||||
|
* @param {Object} options - Query options (page, limit)
|
||||||
|
* @returns {Object} Invited users with commission details
|
||||||
|
*/
|
||||||
|
const getInvitedUsersWithCommissions = async (inviterId, options = {}) => {
|
||||||
|
const { page = 1, limit = 20 } = options;
|
||||||
|
const offset = (page - 1) * limit;
|
||||||
|
|
||||||
|
// Get all invited users
|
||||||
|
const { count, rows: invitedUsers } = await User.findAndCountAll({
|
||||||
|
where: { invitedBy: inviterId },
|
||||||
|
attributes: ['id', 'uid', 'nickname', 'avatar', 'createdAt'],
|
||||||
|
order: [['createdAt', 'DESC']],
|
||||||
|
limit: parseInt(limit),
|
||||||
|
offset: parseInt(offset),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get commission records for each invited user
|
||||||
|
const usersWithCommissions = await Promise.all(
|
||||||
|
invitedUsers.map(async (user) => {
|
||||||
|
// Get all commissions for this invitee
|
||||||
|
const commissions = await Commission.findAll({
|
||||||
|
where: {
|
||||||
|
inviterId,
|
||||||
|
inviteeId: user.id,
|
||||||
|
status: 'credited'
|
||||||
|
},
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: PaymentOrder,
|
||||||
|
as: 'paymentOrder',
|
||||||
|
attributes: ['id', 'orderNo', 'serviceContent', 'paymentTime', 'amountRmb', 'amountPeso'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
order: [['createdAt', 'DESC']],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Calculate totals by currency
|
||||||
|
let totalCommissionRmb = 0;
|
||||||
|
let totalCommissionPeso = 0;
|
||||||
|
let totalPaymentRmb = 0;
|
||||||
|
let totalPaymentPeso = 0;
|
||||||
|
|
||||||
|
const orders = commissions.map(c => {
|
||||||
|
const amount = parseFloat(c.commissionAmount);
|
||||||
|
const paymentAmount = parseFloat(c.paymentAmount);
|
||||||
|
|
||||||
|
if (c.currency === 'PHP') {
|
||||||
|
totalCommissionPeso += amount;
|
||||||
|
totalPaymentPeso += paymentAmount;
|
||||||
|
} else {
|
||||||
|
totalCommissionRmb += amount;
|
||||||
|
totalPaymentRmb += paymentAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: c.id,
|
||||||
|
orderNo: c.paymentOrder?.orderNo || '-',
|
||||||
|
serviceContent: c.paymentOrder?.serviceContent || '-',
|
||||||
|
paymentTime: c.paymentOrder?.paymentTime || c.createdAt,
|
||||||
|
paymentAmount: paymentAmount.toFixed(2),
|
||||||
|
commissionAmount: amount.toFixed(2),
|
||||||
|
currency: c.currency || 'RMB',
|
||||||
|
createdAt: c.createdAt,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
user: {
|
||||||
|
id: user.id,
|
||||||
|
uid: user.uid,
|
||||||
|
nickname: user.nickname,
|
||||||
|
avatar: user.avatar,
|
||||||
|
registeredAt: user.createdAt,
|
||||||
|
},
|
||||||
|
orderCount: orders.length,
|
||||||
|
orders,
|
||||||
|
totalPaymentRmb: totalPaymentRmb.toFixed(2),
|
||||||
|
totalPaymentPeso: totalPaymentPeso.toFixed(2),
|
||||||
|
totalCommissionRmb: totalCommissionRmb.toFixed(2),
|
||||||
|
totalCommissionPeso: totalCommissionPeso.toFixed(2),
|
||||||
|
};
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
records: usersWithCommissions,
|
||||||
|
pagination: {
|
||||||
|
page: parseInt(page),
|
||||||
|
limit: parseInt(limit),
|
||||||
|
total: count,
|
||||||
|
totalPages: Math.ceil(count / limit),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate invitation code
|
* Generate invitation code
|
||||||
* @returns {string} Invitation code
|
* @returns {string} Invitation code
|
||||||
|
|
@ -331,6 +430,7 @@ const getPlatformCommissionStats = async () => {
|
||||||
module.exports = {
|
module.exports = {
|
||||||
calculateCommission,
|
calculateCommission,
|
||||||
getCommissionsByInviter,
|
getCommissionsByInviter,
|
||||||
|
getInvitedUsersWithCommissions,
|
||||||
getCommissionStats,
|
getCommissionStats,
|
||||||
getAllCommissions,
|
getAllCommissions,
|
||||||
getPlatformCommissionStats,
|
getPlatformCommissionStats,
|
||||||
|
|
|
||||||
|
|
@ -206,7 +206,7 @@ If you have privacy questions, please contact us through the application.`
|
||||||
withdrawApplication: 'Withdraw Application',
|
withdrawApplication: 'Withdraw Application',
|
||||||
enterAmount: 'Please enter withdraw amount',
|
enterAmount: 'Please enter withdraw amount',
|
||||||
enterPlaceholder: 'Please enter',
|
enterPlaceholder: 'Please enter',
|
||||||
amountHint: 'Minimum 1 yuan per time, available 99 yuan',
|
amountHint: 'Minimum 1 yuan per time',
|
||||||
nextStep: 'Next Step',
|
nextStep: 'Next Step',
|
||||||
selectPaymentMethod: 'Please select payment method',
|
selectPaymentMethod: 'Please select payment method',
|
||||||
wechat: 'WeChat',
|
wechat: 'WeChat',
|
||||||
|
|
|
||||||
|
|
@ -206,7 +206,7 @@ Si tiene preguntas sobre privacidad, contáctenos a través de la aplicación.`
|
||||||
withdrawApplication: 'Solicitud de Retiro',
|
withdrawApplication: 'Solicitud de Retiro',
|
||||||
enterAmount: 'Por favor, ingrese el monto del retiro',
|
enterAmount: 'Por favor, ingrese el monto del retiro',
|
||||||
enterPlaceholder: 'Por favor, ingrese',
|
enterPlaceholder: 'Por favor, ingrese',
|
||||||
amountHint: 'Mínimo 1 yuan por vez, disponible 99 yuan',
|
amountHint: 'Mínimo 1 yuan por vez',
|
||||||
nextStep: 'Siguiente Paso',
|
nextStep: 'Siguiente Paso',
|
||||||
selectPaymentMethod: 'Por favor, seleccione el método de pago',
|
selectPaymentMethod: 'Por favor, seleccione el método de pago',
|
||||||
wechat: 'WeChat',
|
wechat: 'WeChat',
|
||||||
|
|
|
||||||
|
|
@ -222,7 +222,7 @@ export default {
|
||||||
withdrawApplication: '提现申请',
|
withdrawApplication: '提现申请',
|
||||||
enterAmount: '请输入提现金额',
|
enterAmount: '请输入提现金额',
|
||||||
enterPlaceholder: '请输入',
|
enterPlaceholder: '请输入',
|
||||||
amountHint: '每次最低1元,待提现99元',
|
amountHint: '每次最低1元',
|
||||||
nextStep: '下一步',
|
nextStep: '下一步',
|
||||||
selectPaymentMethod: '请选择收款方式',
|
selectPaymentMethod: '请选择收款方式',
|
||||||
wechat: '微信',
|
wechat: '微信',
|
||||||
|
|
|
||||||
|
|
@ -235,7 +235,7 @@
|
||||||
:placeholder="$t('invite.enterPlaceholder')" />
|
:placeholder="$t('invite.enterPlaceholder')" />
|
||||||
<text class="currency-text">{{ withdrawCurrency === 'CNY' ? '¥' : '₱' }}</text>
|
<text class="currency-text">{{ withdrawCurrency === 'CNY' ? '¥' : '₱' }}</text>
|
||||||
</view>
|
</view>
|
||||||
<text class="amount-hint">{{ $t('invite.amountHint') }}</text>
|
<text class="amount-hint">{{ $t('invite.amountHint') }},{{ withdrawCurrency === 'PHP' ? '₱' : '¥' }}{{ currentAvailableBalance }}</text>
|
||||||
|
|
||||||
<view class="apply-btn" @click="nextStep">
|
<view class="apply-btn" @click="nextStep">
|
||||||
<text class="apply-btn-text">{{ $t('invite.nextStep') }}</text>
|
<text class="apply-btn-text">{{ $t('invite.nextStep') }}</text>
|
||||||
|
|
@ -360,6 +360,13 @@
|
||||||
return 'overflow: hidden;'
|
return 'overflow: hidden;'
|
||||||
}
|
}
|
||||||
return ''
|
return ''
|
||||||
|
},
|
||||||
|
// 当前选择货币的可用余额
|
||||||
|
currentAvailableBalance() {
|
||||||
|
if (this.withdrawCurrency === 'PHP') {
|
||||||
|
return this.commissionStats.availableBalancePeso || '0.00'
|
||||||
|
}
|
||||||
|
return this.commissionStats.availableBalanceRmb || this.commissionStats.availableBalance || '0.00'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onLoad() {
|
onLoad() {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user