佣金
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
18631081161 2026-03-26 00:30:15 +08:00
parent 3ae1f99374
commit 301ade0fe6
5 changed files with 156 additions and 21 deletions

View File

@ -47,13 +47,9 @@
<el-table-column prop="sort" label="排序" width="80" align="center" sortable="custom" />
<el-table-column label="状态" width="100" align="center">
<template #default="{ row }">
<el-switch
v-model="row.status"
:active-value="1"
:inactive-value="0"
@change="handleStatusChange(row)"
v-permission="'planner:update'"
/>
<el-tag :type="row.status === 1 ? 'success' : 'info'">
{{ row.status === 1 ? '启用' : '禁用' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间" width="170" />
@ -105,7 +101,7 @@
<el-input-number v-model="formData.sort" :min="0" :max="9999" controls-position="right" style="width: 200px" />
</el-form-item>
<el-form-item label="状态" prop="status">
<DictRadio v-model="formData.status" dict-type="common_status" />
<DictRadio v-model="formData.status" type="common_status" />
</el-form-item>
</el-form>
<template #footer>
@ -246,7 +242,7 @@ const handleAdd = () => {
tags: '',
price: 0,
sort: 0,
status: 1
status: '1'
})
dialogVisible.value = true
}
@ -263,7 +259,7 @@ const handleEdit = (row: PlannerItem) => {
tags: row.tags,
price: row.price,
sort: row.sort,
status: row.status
status: String(row.status)
})
dialogVisible.value = true
}

View File

@ -24,21 +24,21 @@ public class OrderService : IOrderService
private readonly MiAssessmentDbContext _dbContext;
private readonly ILogger<OrderService> _logger;
private readonly IWechatPayService _wechatPayService;
private readonly IConfigService _configService;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="dbContext">数据库上下文</param>
/// <param name="logger">日志记录器</param>
/// <param name="wechatPayService">微信支付服务</param>
public OrderService(
MiAssessmentDbContext dbContext,
ILogger<OrderService> logger,
IWechatPayService wechatPayService)
IWechatPayService wechatPayService,
IConfigService configService)
{
_dbContext = dbContext;
_logger = logger;
_wechatPayService = wechatPayService;
_configService = configService;
}
/// <inheritdoc />
@ -336,10 +336,148 @@ public class OrderService : IOrderService
await _dbContext.SaveChangesAsync();
// 佣金分配Requirements 3.8.3
try
{
await CreateCommissionsAsync(order);
}
catch (Exception ex)
{
// 佣金分配失败不影响订单状态,记录日志后续补偿
_logger.LogError(ex, "佣金分配异常orderId: {OrderId},需人工处理", order.Id);
}
_logger.LogInformation("订单支付状态更新成功orderNo: {OrderNo}, orderId: {OrderId}", orderNo, order.Id);
return true;
}
/// <summary>
/// 支付成功后创建佣金记录
/// 规则:
/// - 有直接上级和间接上级直接上级30%间接上级10%
/// - 只有直接上级无间接上级直接上级40%
/// - 无上级:不产生佣金
/// </summary>
private async Task CreateCommissionsAsync(MiAssessment.Model.Entities.Order order)
{
if (order.PayAmount <= 0)
{
_logger.LogDebug("订单实付金额为0跳过佣金分配orderId: {OrderId}", order.Id);
return;
}
// 获取下单用户
var user = await _dbContext.Users
.AsNoTracking()
.FirstOrDefaultAsync(u => u.Id == order.UserId && !u.IsDeleted);
if (user == null || !user.ParentUserId.HasValue)
{
_logger.LogDebug("用户无上级跳过佣金分配userId: {UserId}", order.UserId);
return;
}
// 读取佣金比例配置
var directRateStr = await _configService.GetConfigValueAsync("commission_rate_direct");
var indirectRateStr = await _configService.GetConfigValueAsync("commission_rate_indirect");
var directRate = decimal.TryParse(directRateStr, out var dr) ? dr : 0.30m;
var indirectRate = decimal.TryParse(indirectRateStr, out var ir) ? ir : 0.10m;
// 查找直接上级
var parentUser = await _dbContext.Users
.FirstOrDefaultAsync(u => u.Id == user.ParentUserId.Value && !u.IsDeleted);
if (parentUser == null)
{
_logger.LogDebug("直接上级用户不存在跳过佣金分配parentUserId: {ParentUserId}", user.ParentUserId);
return;
}
// 查找间接上级(上上级)
MiAssessment.Model.Entities.User? grandParentUser = null;
if (parentUser.ParentUserId.HasValue)
{
grandParentUser = await _dbContext.Users
.FirstOrDefaultAsync(u => u.Id == parentUser.ParentUserId.Value && !u.IsDeleted);
}
var now = DateTime.Now;
if (grandParentUser != null)
{
// 有间接上级直接上级30%间接上级10%
var directCommission = Math.Round(order.PayAmount * directRate, 2);
var indirectCommission = Math.Round(order.PayAmount * indirectRate, 2);
// 直接上级佣金
_dbContext.Commissions.Add(new MiAssessment.Model.Entities.Commission
{
UserId = parentUser.Id,
FromUserId = user.Id,
OrderId = order.Id,
OrderAmount = order.PayAmount,
CommissionRate = directRate * 100,
CommissionAmount = directCommission,
Level = 1,
Status = 1,
CreateTime = now,
UpdateTime = now
});
parentUser.Balance += directCommission;
parentUser.TotalIncome += directCommission;
parentUser.UpdateTime = now;
// 间接上级佣金
_dbContext.Commissions.Add(new MiAssessment.Model.Entities.Commission
{
UserId = grandParentUser.Id,
FromUserId = user.Id,
OrderId = order.Id,
OrderAmount = order.PayAmount,
CommissionRate = indirectRate * 100,
CommissionAmount = indirectCommission,
Level = 2,
Status = 1,
CreateTime = now,
UpdateTime = now
});
grandParentUser.Balance += indirectCommission;
grandParentUser.TotalIncome += indirectCommission;
grandParentUser.UpdateTime = now;
_logger.LogInformation("佣金分配完成:直接上级{ParentId}获得{DirectAmount},间接上级{GrandParentId}获得{IndirectAmount}orderId: {OrderId}",
parentUser.Id, directCommission, grandParentUser.Id, indirectCommission, order.Id);
}
else
{
// 无间接上级:直接上级获得 directRate + indirectRate
var totalRate = directRate + indirectRate;
var commission = Math.Round(order.PayAmount * totalRate, 2);
_dbContext.Commissions.Add(new MiAssessment.Model.Entities.Commission
{
UserId = parentUser.Id,
FromUserId = user.Id,
OrderId = order.Id,
OrderAmount = order.PayAmount,
CommissionRate = totalRate * 100,
CommissionAmount = commission,
Level = 1,
Status = 1,
CreateTime = now,
UpdateTime = now
});
parentUser.Balance += commission;
parentUser.TotalIncome += commission;
parentUser.UpdateTime = now;
_logger.LogInformation("佣金分配完成:直接上级{ParentId}获得{Amount}无间接上级orderId: {OrderId}",
parentUser.Id, commission, order.Id);
}
await _dbContext.SaveChangesAsync();
}
/// <inheritdoc />
/// <summary>
/// 创建订单

View File

@ -196,7 +196,8 @@ public class ServiceModule : Module
var dbContext = c.Resolve<MiAssessmentDbContext>();
var logger = c.Resolve<ILogger<OrderService>>();
var wechatPayService = c.Resolve<IWechatPayService>();
return new OrderService(dbContext, logger, wechatPayService);
var configService = c.Resolve<Core.Interfaces.IConfigService>();
return new OrderService(dbContext, logger, wechatPayService, configService);
}).As<Core.Interfaces.IOrderService>().InstancePerLifetimeScope();
// ========== 小程序业务详情模块服务注册 ==========

View File

@ -5,15 +5,15 @@
const ENV = {
development: {
API_BASE_URL: 'http://localhost:5238/api',
STATIC_BASE_URL: 'http://localhost:5238',
SIGNALR_URL: 'ws://api.nxt.shhmkjgs.cn/hubs/chat'
},
production: {
API_BASE_URL: 'https://api.nxt.shhmkjgs.cn/api',
STATIC_BASE_URL: 'https://api.nxt.shhmkjgs.cn',
SIGNALR_URL: 'ws://api.nxt.shhmkjgs.cn/hubs/chat'
},
production: {
API_BASE_URL: 'https://your-domain.com/api',
STATIC_BASE_URL: 'https://your-domain.com',
SIGNALR_URL: 'wss://your-domain.com/hubs/chat'
}
}
// 当前环境

View File

@ -463,7 +463,7 @@ onMounted(() => { userStore.restoreFromStorage() })
<view class="record-row" v-for="record in recordList" :key="record.id">
<text class="col-name">{{ record.nickname || '用户' }}</text>
<text class="col-uid">{{ record.uid || '--' }}</text>
<text class="col-date">{{ formatDate(record.registerTime) }}</text>
<text class="col-date">{{ record.registerDate || '--' }}</text>
<text class="col-commission commission-text">¥{{ formatAmount(record.commission) }}</text>
</view>
<Loading type="more" :loading="loading && recordList.length > 0" :noMore="noMore" noMoreText="没有更多记录了" />