{{ row.userNickname }}
+
UID: {{ row.userUid }}
{{ row.userPhone }}
@@ -216,7 +217,7 @@
用户信息
- {{ state.orderDetail.userId }}
+ {{ state.orderDetail.userUid }}
{{ state.orderDetail.userNickname }}
{{ state.orderDetail.userPhone }}
@@ -448,7 +449,7 @@ const queryParams = reactive({
page: 1,
pageSize: 10,
orderNo: '',
- userId: '',
+ userUid: '',
orderType: undefined as string | undefined,
status: undefined as string | undefined,
payType: undefined as string | undefined,
@@ -631,8 +632,8 @@ async function loadOrderList() {
if (queryParams.orderNo) {
params.orderNo = queryParams.orderNo
}
- if (queryParams.userId) {
- params.userId = Number(queryParams.userId)
+ if (queryParams.userUid) {
+ params.userUid = queryParams.userUid
}
if (queryParams.orderType !== undefined && queryParams.orderType !== '') {
params.orderType = Number(queryParams.orderType)
@@ -701,7 +702,7 @@ function handleSearch() {
*/
function handleReset() {
queryParams.orderNo = ''
- queryParams.userId = ''
+ queryParams.userUid = ''
queryParams.orderType = undefined
queryParams.status = undefined
queryParams.payType = undefined
@@ -818,8 +819,8 @@ async function handleExport() {
if (queryParams.orderNo) {
params.orderNo = queryParams.orderNo
}
- if (queryParams.userId) {
- params.userId = Number(queryParams.userId)
+ if (queryParams.userUid) {
+ params.userUid = queryParams.userUid
}
if (queryParams.orderType !== undefined && queryParams.orderType !== '') {
params.orderType = Number(queryParams.orderType)
@@ -920,6 +921,11 @@ onMounted(() => {
color: var(--text-primary, #303133);
}
+.user-info .uid {
+ font-size: 12px;
+ color: var(--el-color-primary);
+}
+
.user-info .phone {
font-size: 12px;
color: var(--text-secondary, #909399);
diff --git a/server/MiAssessment/src/MiAssessment.Admin/admin-web/src/views/business/user/index.vue b/server/MiAssessment/src/MiAssessment.Admin/admin-web/src/views/business/user/index.vue
index a430fd2..6655fed 100644
--- a/server/MiAssessment/src/MiAssessment.Admin/admin-web/src/views/business/user/index.vue
+++ b/server/MiAssessment/src/MiAssessment.Admin/admin-web/src/views/business/user/index.vue
@@ -161,12 +161,16 @@
-
+
详情
+
+
+ 下级
+
等级
@@ -282,6 +286,64 @@
+
+
+
+
+
+
+
+ {{ row.phone || '-' }}
+
+
+
+
+
+ {{ row.userLevelName || getLevelName(row.userLevel) }}
+
+
+
+
+
+ ¥{{ formatMoney(row.balance) }}
+
+
+
+
+
+ {{ row.statusName || (row.status === 1 ? '正常' : '禁用') }}
+
+
+
+
+
+
+
+
+
+
+
({
userLevel: ''
},
levelFormLoading: false,
- exportLoading: false
+ exportLoading: false,
+ subDialogVisible: false,
+ subLoading: false,
+ subTableData: [],
+ subTotal: 0,
+ subPage: 1,
+ subPageSize: 10,
+ subParentId: 0,
+ subParentNickname: '',
+ subParentUid: ''
})
// ============ Form Rules ============
@@ -604,6 +684,37 @@ function handleViewDetail(row: UserItem) {
loadUserDetail(row.id)
}
+function handleViewSubordinates(row: UserItem) {
+ state.subParentId = row.id
+ state.subParentNickname = row.nickname
+ state.subParentUid = row.uid
+ state.subPage = 1
+ state.subDialogVisible = true
+ loadSubordinates()
+}
+
+async function loadSubordinates() {
+ state.subLoading = true
+ try {
+ const res = await getUserList({
+ page: state.subPage,
+ pageSize: state.subPageSize,
+ parentUserId: state.subParentId
+ })
+ if (res.code === 0) {
+ state.subTableData = res.data?.list || []
+ state.subTotal = res.data?.total || 0
+ } else {
+ throw new Error(res.message || '获取下级用户列表失败')
+ }
+ } catch (error) {
+ const message = error instanceof Error ? error.message : '获取下级用户列表失败'
+ ElMessage.error(message)
+ } finally {
+ state.subLoading = false
+ }
+}
+
async function handleStatusChange(row: UserItemWithLoading, status: number) {
row.statusLoading = true
try {
diff --git a/server/MiAssessment/src/MiAssessment.Core/Services/InviteService.cs b/server/MiAssessment/src/MiAssessment.Core/Services/InviteService.cs
index 8365662..07726ab 100644
--- a/server/MiAssessment/src/MiAssessment.Core/Services/InviteService.cs
+++ b/server/MiAssessment/src/MiAssessment.Core/Services/InviteService.cs
@@ -242,18 +242,47 @@ public class InviteService : IInviteService
})
.ToListAsync();
- // 获取每个下级用户贡献的佣金总额
- var userIds = invitedUsers.Select(u => u.Id).ToList();
- var commissions = await _dbContext.Commissions
+ // 获取每个下级用户贡献的佣金总额(含直接下级 + 间接下级)
+ var directUserIds = invitedUsers.Select(u => u.Id).ToList();
+
+ // 查询间接下级(下下级),并记录其直属上级的映射关系
+ var indirectUsers = await _dbContext.Users
.AsNoTracking()
- .Where(c => c.UserId == userId && userIds.Contains(c.FromUserId) && !c.IsDeleted)
- .GroupBy(c => c.FromUserId)
- .Select(g => new
+ .Where(u => u.ParentUserId.HasValue && directUserIds.Contains(u.ParentUserId.Value) && !u.IsDeleted)
+ .Select(u => new { u.Id, ParentUserId = u.ParentUserId!.Value })
+ .ToListAsync();
+
+ var indirectToDirectMap = indirectUsers.ToDictionary(u => u.Id, u => u.ParentUserId);
+ var allRelatedUserIds = directUserIds.Concat(indirectUsers.Select(u => u.Id)).ToList();
+
+ // 查询当前用户从这些下级/下下级获得的所有佣金
+ var commissionRecords = await _dbContext.Commissions
+ .AsNoTracking()
+ .Where(c => c.UserId == userId && allRelatedUserIds.Contains(c.FromUserId) && !c.IsDeleted)
+ .ToListAsync();
+
+ // 将间接下级的佣金归属到对应的直接下级名下
+ var commissions = new Dictionary();
+ foreach (var c in commissionRecords)
+ {
+ long directUserId;
+ if (directUserIds.Contains(c.FromUserId))
{
- FromUserId = g.Key,
- TotalCommission = g.Sum(c => c.CommissionAmount)
- })
- .ToDictionaryAsync(x => x.FromUserId, x => x.TotalCommission);
+ directUserId = c.FromUserId;
+ }
+ else if (indirectToDirectMap.TryGetValue(c.FromUserId, out var parentId))
+ {
+ directUserId = parentId;
+ }
+ else
+ {
+ continue;
+ }
+
+ if (!commissions.ContainsKey(directUserId))
+ commissions[directUserId] = 0;
+ commissions[directUserId] += c.CommissionAmount;
+ }
// 组装结果
var records = invitedUsers.Select(u => new InviteRecordDto
diff --git a/uniapp/pages/assessment/questions/index.vue b/uniapp/pages/assessment/questions/index.vue
index 960f676..7d9437b 100644
--- a/uniapp/pages/assessment/questions/index.vue
+++ b/uniapp/pages/assessment/questions/index.vue
@@ -286,15 +286,14 @@ onLoad((options) => {
上一题
下一题
@@ -596,6 +595,19 @@ onLoad((options) => {
color: $text-white;
}
+ &.action-disabled {
+ opacity: 0.4;
+ pointer-events: none;
+ }
+}
+
+.action-submit {
+ background-color: #FF6B60;
+
+ text {
+ color: $text-white;
+ }
+
&.btn-loading {
opacity: 0.7;
pointer-events: none;
diff --git a/uniapp/pages/invite/index.vue b/uniapp/pages/invite/index.vue
index 2ff98cf..aa451d0 100644
--- a/uniapp/pages/invite/index.vue
+++ b/uniapp/pages/invite/index.vue
@@ -28,8 +28,8 @@ const { statusBarHeight, navbarHeight, totalNavbarHeight } = useNavbar()
const WITHDRAW_STATUS = {
APPLYING: 1, // 申请中
PROCESSING: 2, // 提现中
- CANCELLED: 3, // 已取消
- COMPLETED: 4 // 已提现
+ COMPLETED: 3, // 已提现
+ CANCELLED: 4 // 已取消
}
// 页面状态
@@ -363,7 +363,7 @@ onReachBottom(() => {
onShareAppMessage(() => ({
title: '邀请您加入学业邑规划',
path: `/pages/index/index?inviterId=${userStore.userId}`,
- imageUrl: '/static/logo.png'
+ imageUrl: '/static/ic_share.png'
}))
onShow(() => {
diff --git a/uniapp/static/ic_share.png b/uniapp/static/ic_share.png
new file mode 100644
index 0000000..7551d29
Binary files /dev/null and b/uniapp/static/ic_share.png differ
diff --git a/uniapp/static/logo.png b/uniapp/static/logo.png
index 9bd6d86..437fc57 100644
Binary files a/uniapp/static/logo.png and b/uniapp/static/logo.png differ