diff --git a/server/MiAssessment/src/MiAssessment.Admin.Business/Services/DashboardService.cs b/server/MiAssessment/src/MiAssessment.Admin.Business/Services/DashboardService.cs
index b2cdaf6..06db92b 100644
--- a/server/MiAssessment/src/MiAssessment.Admin.Business/Services/DashboardService.cs
+++ b/server/MiAssessment/src/MiAssessment.Admin.Business/Services/DashboardService.cs
@@ -36,7 +36,7 @@ public class DashboardService : IDashboardService
// 今日注册用户数
var todayRegistrations = await _dbContext.Users
- .CountAsync(u => u.CreatedAt >= today && u.CreatedAt < tomorrow);
+ .CountAsync(u => u.CreateTime >= today && u.CreateTime < tomorrow);
// 总用户数
var totalUsers = await _dbContext.Users.CountAsync();
diff --git a/server/MiAssessment/src/MiAssessment.Api/Controllers/AddressController.cs b/server/MiAssessment/src/MiAssessment.Api/Controllers/AddressController.cs
deleted file mode 100644
index 59fbd44..0000000
--- a/server/MiAssessment/src/MiAssessment.Api/Controllers/AddressController.cs
+++ /dev/null
@@ -1,350 +0,0 @@
-using System.Security.Claims;
-using MiAssessment.Core.Interfaces;
-using MiAssessment.Model.Base;
-using MiAssessment.Model.Models.Address;
-using Microsoft.AspNetCore.Authorization;
-using Microsoft.AspNetCore.Mvc;
-
-namespace MiAssessment.Api.Controllers;
-
-///
-/// 地址控制器 - 处理用户收货地址相关功能
-///
-///
-/// 提供地址的增删改查、设置默认地址等功能
-/// Requirements: 1.1-1.7
-///
-[ApiController]
-[Route("api")]
-public class AddressController : ControllerBase
-{
- private readonly IAddressService _addressService;
- private readonly ILogger _logger;
-
- public AddressController(IAddressService addressService, ILogger logger)
- {
- _addressService = addressService;
- _logger = logger;
- }
-
- ///
- /// 添加收货地址
- ///
- ///
- /// POST /api/addAddress
- ///
- /// 每位用户最多只能添加10条收货地址
- /// Requirements: 1.1
- ///
- [HttpPost("addAddress")]
- [Authorize]
- [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)]
- public async Task> AddAddress([FromBody] AddAddressRequest request)
- {
- var userId = GetCurrentUserId();
- if (userId == null)
- {
- return ApiResponse.Unauthorized();
- }
-
- // 参数验证
- if (string.IsNullOrWhiteSpace(request.ReceiverName))
- {
- return ApiResponse.Fail("请输入收货人姓名");
- }
- if (string.IsNullOrWhiteSpace(request.ReceiverPhone))
- {
- return ApiResponse.Fail("请输入收货人电话");
- }
- if (!IsValidMobile(request.ReceiverPhone))
- {
- return ApiResponse.Fail("请输入正确的手机号");
- }
- if (string.IsNullOrWhiteSpace(request.DetailedAddress))
- {
- return ApiResponse.Fail("请输入详细地址");
- }
-
- try
- {
- var address = await _addressService.AddAddressAsync(userId.Value, request);
- return ApiResponse.Success(address, "添加成功");
- }
- catch (InvalidOperationException ex)
- {
- _logger.LogWarning("Add address failed: UserId={UserId}, Error={Error}", userId, ex.Message);
- return ApiResponse.Fail(ex.Message);
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Failed to add address: UserId={UserId}", userId);
- return ApiResponse.Fail("添加失败");
- }
- }
-
- ///
- /// 更新收货地址
- ///
- ///
- /// POST /api/updateAddress
- /// Requirements: 1.2
- ///
- [HttpPost("updateAddress")]
- [Authorize]
- [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)]
- public async Task> UpdateAddress([FromBody] UpdateAddressRequest request)
- {
- var userId = GetCurrentUserId();
- if (userId == null)
- {
- return ApiResponse.Unauthorized();
- }
-
- // 参数验证
- if (request.Id <= 0)
- {
- return ApiResponse.Fail("请选择要修改的地址");
- }
- if (string.IsNullOrWhiteSpace(request.ReceiverName))
- {
- return ApiResponse.Fail("请输入收货人姓名");
- }
- if (string.IsNullOrWhiteSpace(request.ReceiverPhone))
- {
- return ApiResponse.Fail("请输入收货人电话");
- }
- if (!IsValidMobile(request.ReceiverPhone))
- {
- return ApiResponse.Fail("请输入正确的手机号");
- }
- if (string.IsNullOrWhiteSpace(request.DetailedAddress))
- {
- return ApiResponse.Fail("请输入详细地址");
- }
-
- try
- {
- var address = await _addressService.UpdateAddressAsync(userId.Value, request);
- return ApiResponse.Success(address, "修改成功");
- }
- catch (InvalidOperationException ex)
- {
- _logger.LogWarning("Update address failed: UserId={UserId}, Error={Error}", userId, ex.Message);
- return ApiResponse.Fail(ex.Message);
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Failed to update address: UserId={UserId}", userId);
- return ApiResponse.Fail("修改失败");
- }
- }
-
- ///
- /// 获取默认收货地址
- ///
- ///
- /// GET /api/getDefaultAddress
- /// Requirements: 1.3
- ///
- [HttpGet("getDefaultAddress")]
- [Authorize]
- [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)]
- public async Task> GetDefaultAddress()
- {
- var userId = GetCurrentUserId();
- if (userId == null)
- {
- return ApiResponse.Unauthorized();
- }
-
- try
- {
- var address = await _addressService.GetDefaultAddressAsync(userId.Value);
- return ApiResponse.Success(address, "获取成功");
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Failed to get default address: UserId={UserId}", userId);
- return ApiResponse.Fail("获取失败");
- }
- }
-
-
- ///
- /// 获取收货地址列表
- ///
- ///
- /// GET /api/getAddressList
- /// Requirements: 1.4
- ///
- [HttpGet("getAddressList")]
- [Authorize]
- [ProducesResponseType(typeof(ApiResponse>), StatusCodes.Status200OK)]
- public async Task>> GetAddressList()
- {
- var userId = GetCurrentUserId();
- if (userId == null)
- {
- return ApiResponse>.Unauthorized();
- }
-
- try
- {
- var addresses = await _addressService.GetAddressListAsync(userId.Value);
- return ApiResponse>.Success(addresses, "获取成功");
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Failed to get address list: UserId={UserId}", userId);
- return ApiResponse>.Fail("获取失败");
- }
- }
-
- ///
- /// 删除收货地址
- ///
- ///
- /// POST /api/deleteAddress
- /// Requirements: 1.5
- ///
- [HttpPost("deleteAddress")]
- [Authorize]
- [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)]
- public async Task DeleteAddress([FromBody] AddressIdRequest request)
- {
- var userId = GetCurrentUserId();
- if (userId == null)
- {
- return ApiResponse.Unauthorized();
- }
-
- if (request.Id <= 0)
- {
- return ApiResponse.Fail("请选择要删除的地址");
- }
-
- try
- {
- await _addressService.DeleteAddressAsync(userId.Value, request.Id);
- return ApiResponse.Success("删除成功");
- }
- catch (InvalidOperationException ex)
- {
- _logger.LogWarning("Delete address failed: UserId={UserId}, Error={Error}", userId, ex.Message);
- return ApiResponse.Fail(ex.Message);
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Failed to delete address: UserId={UserId}", userId);
- return ApiResponse.Fail("删除失败");
- }
- }
-
- ///
- /// 设置默认收货地址
- ///
- ///
- /// POST /api/setDefaultAddress
- /// Requirements: 1.6
- ///
- [HttpPost("setDefaultAddress")]
- [Authorize]
- [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)]
- public async Task SetDefaultAddress([FromBody] AddressIdRequest request)
- {
- var userId = GetCurrentUserId();
- if (userId == null)
- {
- return ApiResponse.Unauthorized();
- }
-
- if (request.Id <= 0)
- {
- return ApiResponse.Fail("请选择要设为默认的地址");
- }
-
- try
- {
- await _addressService.SetDefaultAddressAsync(userId.Value, request.Id);
- return ApiResponse.Success("设置成功");
- }
- catch (InvalidOperationException ex)
- {
- _logger.LogWarning("Set default address failed: UserId={UserId}, Error={Error}", userId, ex.Message);
- return ApiResponse.Fail(ex.Message);
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Failed to set default address: UserId={UserId}", userId);
- return ApiResponse.Fail("设置失败");
- }
- }
-
- ///
- /// 获取地址详情
- ///
- ///
- /// GET /api/getAddressDetail
- /// Requirements: 1.7
- ///
- [HttpGet("getAddressDetail")]
- [Authorize]
- [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)]
- public async Task> GetAddressDetail([FromQuery] int id)
- {
- var userId = GetCurrentUserId();
- if (userId == null)
- {
- return ApiResponse.Unauthorized();
- }
-
- if (id <= 0)
- {
- return ApiResponse.Fail("请选择要查看的地址");
- }
-
- try
- {
- var address = await _addressService.GetAddressDetailAsync(userId.Value, id);
- if (address == null)
- {
- return ApiResponse.Fail("地址不存在");
- }
- return ApiResponse.Success(address, "获取成功");
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Failed to get address detail: UserId={UserId}, AddressId={AddressId}", userId, id);
- return ApiResponse.Fail("获取失败");
- }
- }
-
- #region Private Helper Methods
-
- ///
- /// 获取当前登录用户ID
- ///
- private int? GetCurrentUserId()
- {
- var userIdClaim = User.FindFirst(ClaimTypes.NameIdentifier);
- if (userIdClaim == null || !int.TryParse(userIdClaim.Value, out var userId))
- {
- return null;
- }
- return userId;
- }
-
- ///
- /// 验证手机号格式
- ///
- private static bool IsValidMobile(string mobile)
- {
- if (string.IsNullOrWhiteSpace(mobile))
- return false;
-
- // 中国大陆手机号:11位数字,以1开头
- return mobile.Length == 11 && mobile.StartsWith("1") && mobile.All(char.IsDigit);
- }
-
- #endregion
-}
diff --git a/server/MiAssessment/src/MiAssessment.Api/Controllers/NotifyController.cs b/server/MiAssessment/src/MiAssessment.Api/Controllers/NotifyController.cs
index 9c39ca4..830ba70 100644
--- a/server/MiAssessment/src/MiAssessment.Api/Controllers/NotifyController.cs
+++ b/server/MiAssessment/src/MiAssessment.Api/Controllers/NotifyController.cs
@@ -13,16 +13,13 @@ namespace MiAssessment.Api.Controllers;
public class NotifyController : ControllerBase
{
private readonly IPaymentNotifyService _paymentNotifyService;
- private readonly IPaymentOrderService _paymentOrderService;
private readonly ILogger _logger;
public NotifyController(
IPaymentNotifyService paymentNotifyService,
- IPaymentOrderService paymentOrderService,
ILogger logger)
{
_paymentNotifyService = paymentNotifyService;
- _paymentOrderService = paymentOrderService;
_logger = logger;
}
@@ -67,48 +64,6 @@ public class NotifyController : ControllerBase
_logger.LogInformation("微信支付回调处理完成: Success={Success}, Message={Message}",
result.Success, result.Message);
- // 如果回调处理成功且有订单号和支付数据,调用 PaymentOrderService 处理支付成功
- if (result.Success && !string.IsNullOrEmpty(result.OrderNo) && result.NotifyData != null)
- {
- try
- {
- // 从回调数据中获取交易号和支付金额(分转元)
- var transactionId = result.NotifyData.TransactionId;
- var payAmount = result.NotifyData.TotalFee / 100m;
-
- _logger.LogInformation("开始处理支付订单: OrderNo={OrderNo}, TransactionId={TransactionId}, PayAmount={PayAmount}",
- result.OrderNo, transactionId, payAmount);
-
- // 调用 PaymentOrderService 处理支付成功(更新 PaymentOrder 状态并触发奖励发放)
- var paymentResult = await _paymentOrderService.HandlePaymentSuccessAsync(
- result.OrderNo,
- transactionId,
- payAmount);
-
- if (paymentResult)
- {
- _logger.LogInformation("支付订单处理成功: OrderNo={OrderNo}", result.OrderNo);
-
- // 更新 OrderNotify 状态为处理成功
- await _paymentNotifyService.UpdateNotifyStatusAsync(result.OrderNo, 1, "处理成功");
- }
- else
- {
- _logger.LogWarning("支付订单处理失败: OrderNo={OrderNo}", result.OrderNo);
-
- // 更新 OrderNotify 状态为处理失败
- await _paymentNotifyService.UpdateNotifyStatusAsync(result.OrderNo, 2, "支付订单处理失败");
- }
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "处理支付订单异常: OrderNo={OrderNo}", result.OrderNo);
-
- // 更新 OrderNotify 状态为处理失败
- await _paymentNotifyService.UpdateNotifyStatusAsync(result.OrderNo, 2, $"处理异常: {ex.Message}");
- }
- }
-
// 根据回调版本返回对应格式的响应
if (!string.IsNullOrEmpty(result.JsonResponse))
{
diff --git a/server/MiAssessment/src/MiAssessment.Core/Interfaces/IAddressService.cs b/server/MiAssessment/src/MiAssessment.Core/Interfaces/IAddressService.cs
deleted file mode 100644
index 1c32b31..0000000
--- a/server/MiAssessment/src/MiAssessment.Core/Interfaces/IAddressService.cs
+++ /dev/null
@@ -1,63 +0,0 @@
-using MiAssessment.Model.Models.Address;
-
-namespace MiAssessment.Core.Interfaces;
-
-///
-/// 地址服务接口
-///
-public interface IAddressService
-{
- ///
- /// 添加收货地址
- ///
- /// 用户ID
- /// 添加地址请求
- /// 新创建的地址
- Task AddAddressAsync(int userId, AddAddressRequest request);
-
- ///
- /// 更新收货地址
- ///
- /// 用户ID
- /// 更新地址请求
- /// 更新后的地址
- Task UpdateAddressAsync(int userId, UpdateAddressRequest request);
-
- ///
- /// 获取默认收货地址
- ///
- /// 用户ID
- /// 默认地址,如果没有则返回最新的一条
- Task GetDefaultAddressAsync(int userId);
-
- ///
- /// 获取收货地址列表
- ///
- /// 用户ID
- /// 地址列表
- Task> GetAddressListAsync(int userId);
-
- ///
- /// 删除收货地址
- ///
- /// 用户ID
- /// 地址ID
- /// 是否删除成功
- Task DeleteAddressAsync(int userId, int addressId);
-
- ///
- /// 设置默认收货地址
- ///
- /// 用户ID
- /// 地址ID
- /// 是否设置成功
- Task SetDefaultAddressAsync(int userId, int addressId);
-
- ///
- /// 获取地址详情
- ///
- /// 用户ID
- /// 地址ID
- /// 地址详情
- Task GetAddressDetailAsync(int userId, int addressId);
-}
diff --git a/server/MiAssessment/src/MiAssessment.Core/Interfaces/IPaymentOrderService.cs b/server/MiAssessment/src/MiAssessment.Core/Interfaces/IPaymentOrderService.cs
deleted file mode 100644
index bc22a9f..0000000
--- a/server/MiAssessment/src/MiAssessment.Core/Interfaces/IPaymentOrderService.cs
+++ /dev/null
@@ -1,72 +0,0 @@
-using MiAssessment.Model.Entities;
-using MiAssessment.Model.Models;
-using MiAssessment.Model.Models.Payment;
-
-namespace MiAssessment.Core.Interfaces;
-
-///
-/// 通用支付订单服务接口
-///
-public interface IPaymentOrderService
-{
- ///
- /// 创建支付订单
- ///
- /// 创建订单请求
- /// 创建的支付订单
- Task CreateOrderAsync(CreatePaymentOrderRequest request);
-
- ///
- /// 根据订单号获取订单详情
- ///
- /// 订单号
- /// 支付订单,如果不存在则返回null
- Task GetOrderByNoAsync(string orderNo);
-
- ///
- /// 根据订单ID获取订单详情
- ///
- /// 订单ID
- /// 支付订单,如果不存在则返回null
- Task GetOrderByIdAsync(int orderId);
-
- ///
- /// 处理支付成功
- ///
- /// 订单号
- /// 第三方交易号
- /// 实付金额
- /// 是否处理成功
- Task HandlePaymentSuccessAsync(string orderNo, string transactionId, decimal payAmount);
-
- ///
- /// 处理奖励发放
- ///
- /// 订单号
- /// 是否处理成功
- Task ProcessRewardAsync(string orderNo);
-
- ///
- /// 获取用户订单列表
- ///
- /// 用户ID
- /// 查询请求
- /// 分页订单列表
- Task> GetUserOrdersAsync(int userId, PaymentOrderQueryRequest request);
-
- ///
- /// 取消订单
- ///
- /// 订单号
- /// 用户ID(用于验证权限)
- /// 是否取消成功
- Task CancelOrderAsync(string orderNo, int userId);
-
- ///
- /// 更新订单状态
- ///
- /// 订单号
- /// 新状态
- /// 是否更新成功
- Task UpdateOrderStatusAsync(string orderNo, byte status);
-}
diff --git a/server/MiAssessment/src/MiAssessment.Core/Interfaces/IPaymentRewardDispatcher.cs b/server/MiAssessment/src/MiAssessment.Core/Interfaces/IPaymentRewardDispatcher.cs
deleted file mode 100644
index dd7bb41..0000000
--- a/server/MiAssessment/src/MiAssessment.Core/Interfaces/IPaymentRewardDispatcher.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-using MiAssessment.Model.Entities;
-
-namespace MiAssessment.Core.Interfaces;
-
-///
-/// 支付奖励分发器接口
-/// 负责根据订单类型查找并调用对应的奖励处理器
-///
-public interface IPaymentRewardDispatcher
-{
- ///
- /// 根据订单类型获取对应的奖励处理器
- ///
- /// 订单类型
- /// 奖励处理器,如果未找到则返回 null
- IPaymentRewardHandler? GetHandler(string orderType);
-
- ///
- /// 检查是否存在指定订单类型的处理器
- ///
- /// 订单类型
- /// 是否存在处理器
- bool HasHandler(string orderType);
-
- ///
- /// 获取所有已注册的订单类型
- ///
- /// 已注册的订单类型列表
- IReadOnlyCollection GetRegisteredOrderTypes();
-
- ///
- /// 处理奖励发放
- /// 根据订单类型查找对应的处理器并执行奖励发放
- ///
- /// 支付订单
- /// 奖励处理结果
- Task ProcessRewardAsync(PaymentOrder order);
-}
diff --git a/server/MiAssessment/src/MiAssessment.Core/Interfaces/IPaymentRewardHandler.cs b/server/MiAssessment/src/MiAssessment.Core/Interfaces/IPaymentRewardHandler.cs
deleted file mode 100644
index ceef69c..0000000
--- a/server/MiAssessment/src/MiAssessment.Core/Interfaces/IPaymentRewardHandler.cs
+++ /dev/null
@@ -1,71 +0,0 @@
-using MiAssessment.Model.Entities;
-
-namespace MiAssessment.Core.Interfaces;
-
-///
-/// 支付奖励处理器接口
-/// 用于处理支付成功后的奖励发放逻辑
-///
-public interface IPaymentRewardHandler
-{
- ///
- /// 处理的订单类型
- ///
- string OrderType { get; }
-
- ///
- /// 处理奖励发放
- ///
- /// 支付订单
- /// 奖励处理结果
- Task ProcessRewardAsync(PaymentOrder order);
-}
-
-///
-/// 奖励处理结果
-///
-public class RewardResult
-{
- ///
- /// 是否成功
- ///
- public bool Success { get; set; }
-
- ///
- /// 消息(成功时为空,失败时为错误原因)
- ///
- public string? Message { get; set; }
-
- ///
- /// 奖励数据(JSON格式)
- ///
- public string? RewardData { get; set; }
-
- ///
- /// 创建成功结果
- ///
- /// 奖励数据
- /// 成功结果
- public static RewardResult Ok(string? rewardData = null)
- {
- return new RewardResult
- {
- Success = true,
- RewardData = rewardData
- };
- }
-
- ///
- /// 创建失败结果
- ///
- /// 错误消息
- /// 失败结果
- public static RewardResult Fail(string message)
- {
- return new RewardResult
- {
- Success = false,
- Message = message
- };
- }
-}
diff --git a/server/MiAssessment/src/MiAssessment.Core/Interfaces/IPaymentService.cs b/server/MiAssessment/src/MiAssessment.Core/Interfaces/IPaymentService.cs
deleted file mode 100644
index b1f2753..0000000
--- a/server/MiAssessment/src/MiAssessment.Core/Interfaces/IPaymentService.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-using MiAssessment.Model.Models.Payment;
-
-namespace MiAssessment.Core.Interfaces;
-
-///
-/// 支付服务接口
-/// 提供基础的支付相关功能,具体业务逻辑由业务模块扩展
-///
-public interface IPaymentService
-{
- ///
- /// 验证用户余额是否充足
- ///
- /// 用户ID
- /// 需要的金额
- /// 是否充足
- Task ValidateBalanceAsync(int userId, decimal amount);
-
- ///
- /// 获取用户余额
- ///
- /// 用户ID
- /// 用户余额
- Task GetUserBalanceAsync(int userId);
-}
diff --git a/server/MiAssessment/src/MiAssessment.Core/Services/AddressService.cs b/server/MiAssessment/src/MiAssessment.Core/Services/AddressService.cs
deleted file mode 100644
index fd42f0a..0000000
--- a/server/MiAssessment/src/MiAssessment.Core/Services/AddressService.cs
+++ /dev/null
@@ -1,221 +0,0 @@
-using MiAssessment.Core.Interfaces;
-using MiAssessment.Model.Data;
-using MiAssessment.Model.Entities;
-using MiAssessment.Model.Models.Address;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.Extensions.Logging;
-
-namespace MiAssessment.Core.Services;
-
-///
-/// 地址服务实现
-///
-public class AddressService : IAddressService
-{
- private readonly MiAssessmentDbContext _dbContext;
- private readonly ILogger _logger;
- private const int MaxAddressCount = 10;
-
- public AddressService(MiAssessmentDbContext dbContext, ILogger logger)
- {
- _dbContext = dbContext;
- _logger = logger;
- }
-
- ///
- public async Task AddAddressAsync(int userId, AddAddressRequest request)
- {
- // 检查地址数量限制
- var addressCount = await _dbContext.UserAddresses
- .CountAsync(a => a.UserId == userId && a.IsDeleted == 0);
-
- if (addressCount >= MaxAddressCount)
- {
- throw new InvalidOperationException("最多只能添加10个收货地址");
- }
-
- var now = DateTime.Now;
- var address = new UserAddress
- {
- UserId = userId,
- ReceiverName = request.ReceiverName,
- ReceiverPhone = request.ReceiverPhone,
- DetailedAddress = request.DetailedAddress,
- IsDefault = (byte)(request.IsDefault == 1 ? 1 : 0),
- IsDeleted = 0,
- CreatedAt = now,
- UpdatedAt = now
- };
-
- // 如果设置为默认地址,将其他地址设为非默认
- if (address.IsDefault == 1)
- {
- await SetOtherAddressNotDefaultAsync(userId);
- }
-
- // 如果是第一个地址,自动设为默认
- if (addressCount == 0)
- {
- address.IsDefault = 1;
- }
-
- _dbContext.UserAddresses.Add(address);
- await _dbContext.SaveChangesAsync();
-
- _logger.LogInformation("Address added: UserId={UserId}, AddressId={AddressId}", userId, address.Id);
- return MapToDto(address);
- }
-
-
- ///
- public async Task UpdateAddressAsync(int userId, UpdateAddressRequest request)
- {
- var address = await _dbContext.UserAddresses
- .FirstOrDefaultAsync(a => a.Id == request.Id && a.UserId == userId && a.IsDeleted == 0);
-
- if (address == null)
- {
- throw new InvalidOperationException("地址不存在");
- }
-
- address.ReceiverName = request.ReceiverName;
- address.ReceiverPhone = request.ReceiverPhone;
- address.DetailedAddress = request.DetailedAddress;
- address.UpdatedAt = DateTime.Now;
-
- // 处理默认地址设置
- if (request.IsDefault.HasValue && request.IsDefault.Value == 1 && address.IsDefault != 1)
- {
- await SetOtherAddressNotDefaultAsync(userId, address.Id);
- address.IsDefault = 1;
- }
-
- await _dbContext.SaveChangesAsync();
-
- _logger.LogInformation("Address updated: UserId={UserId}, AddressId={AddressId}", userId, address.Id);
- return MapToDto(address);
- }
-
- ///
- public async Task GetDefaultAddressAsync(int userId)
- {
- // 先查找默认地址
- var address = await _dbContext.UserAddresses
- .FirstOrDefaultAsync(a => a.UserId == userId && a.IsDefault == 1 && a.IsDeleted == 0);
-
- // 如果没有默认地址,返回最新添加的一条
- if (address == null)
- {
- address = await _dbContext.UserAddresses
- .Where(a => a.UserId == userId && a.IsDeleted == 0)
- .OrderByDescending(a => a.Id)
- .FirstOrDefaultAsync();
- }
-
- return address != null ? MapToDto(address) : null;
- }
-
- ///
- public async Task> GetAddressListAsync(int userId)
- {
- var addresses = await _dbContext.UserAddresses
- .Where(a => a.UserId == userId && a.IsDeleted == 0)
- .OrderByDescending(a => a.IsDefault)
- .ThenByDescending(a => a.Id)
- .ToListAsync();
-
- return addresses.Select(MapToDto).ToList();
- }
-
- ///
- public async Task DeleteAddressAsync(int userId, int addressId)
- {
- var address = await _dbContext.UserAddresses
- .FirstOrDefaultAsync(a => a.Id == addressId && a.UserId == userId && a.IsDeleted == 0);
-
- if (address == null)
- {
- throw new InvalidOperationException("地址不存在");
- }
-
- // 软删除
- address.IsDeleted = 1;
- address.UpdatedAt = DateTime.Now;
- await _dbContext.SaveChangesAsync();
-
- _logger.LogInformation("Address deleted: UserId={UserId}, AddressId={AddressId}", userId, addressId);
- return true;
- }
-
- ///
- public async Task SetDefaultAddressAsync(int userId, int addressId)
- {
- var address = await _dbContext.UserAddresses
- .FirstOrDefaultAsync(a => a.Id == addressId && a.UserId == userId && a.IsDeleted == 0);
-
- if (address == null)
- {
- throw new InvalidOperationException("地址不存在");
- }
-
- // 已经是默认地址
- if (address.IsDefault == 1)
- {
- return true;
- }
-
- // 将其他地址设为非默认
- await SetOtherAddressNotDefaultAsync(userId);
-
- // 设置当前地址为默认
- address.IsDefault = 1;
- address.UpdatedAt = DateTime.Now;
- await _dbContext.SaveChangesAsync();
-
- _logger.LogInformation("Default address set: UserId={UserId}, AddressId={AddressId}", userId, addressId);
- return true;
- }
-
- ///
- public async Task GetAddressDetailAsync(int userId, int addressId)
- {
- var address = await _dbContext.UserAddresses
- .FirstOrDefaultAsync(a => a.Id == addressId && a.UserId == userId && a.IsDeleted == 0);
-
- return address != null ? MapToDto(address) : null;
- }
-
- ///
- /// 将其他地址设为非默认
- ///
- private async Task SetOtherAddressNotDefaultAsync(int userId, int? exceptId = null)
- {
- var query = _dbContext.UserAddresses
- .Where(a => a.UserId == userId && a.IsDefault == 1 && a.IsDeleted == 0);
-
- if (exceptId.HasValue)
- {
- query = query.Where(a => a.Id != exceptId.Value);
- }
-
- await query.ExecuteUpdateAsync(s => s.SetProperty(a => a.IsDefault, (byte)0));
- }
-
- ///
- /// 将实体映射为DTO
- ///
- private static AddressDto MapToDto(UserAddress address)
- {
- return new AddressDto
- {
- Id = address.Id,
- UserId = address.UserId,
- ReceiverName = address.ReceiverName,
- ReceiverPhone = address.ReceiverPhone,
- DetailedAddress = address.DetailedAddress,
- IsDefault = address.IsDefault ?? 0,
- CreateTime = address.CreatedAt.ToString("yyyy-MM-dd HH:mm:ss"),
- UpdateTime = address.UpdatedAt.ToString("yyyy-MM-dd HH:mm:ss")
- };
- }
-}
diff --git a/server/MiAssessment/src/MiAssessment.Core/Services/AuthService.cs b/server/MiAssessment/src/MiAssessment.Core/Services/AuthService.cs
index 331b671..8085f17 100644
--- a/server/MiAssessment/src/MiAssessment.Core/Services/AuthService.cs
+++ b/server/MiAssessment/src/MiAssessment.Core/Services/AuthService.cs
@@ -392,37 +392,25 @@ public class AuthService : IAuthService
// 获取客户端IP(这里使用空字符串作为占位符,实际IP应从Controller传入)
var clientIp = deviceInfo ?? string.Empty;
- // 6.2 解析IP地址获取地理位置
- IpLocationResult? locationResult = null;
- if (!string.IsNullOrWhiteSpace(clientIp))
- {
- locationResult = await _ipLocationService.GetLocationAsync(clientIp);
- }
-
- var now = DateTime.UtcNow;
- var today = DateOnly.FromDateTime(now);
+ var now = DateTime.Now;
// 6.1 记录登录日志
var loginLog = new UserLoginLog
{
UserId = userId,
- LoginDate = today,
- LoginTime = now,
- LastLoginTime = now,
- Device = device,
- Ip = clientIp,
- Location = locationResult?.Success == true
- ? $"{locationResult.Province}{locationResult.City}"
- : null,
- Year = now.Year,
- Month = now.Month,
- Week = GetWeekOfYear(now)
+ LoginType = "wechat",
+ LoginIp = clientIp,
+ UserAgent = device,
+ Platform = "miniprogram",
+ Status = 1,
+ CreateTime = now
};
await _dbContext.UserLoginLogs.AddAsync(loginLog);
// 更新用户最后登录时间
user.LastLoginTime = now;
+ user.LastLoginIp = clientIp;
_dbContext.Users.Update(user);
await _dbContext.SaveChangesAsync();
@@ -434,7 +422,7 @@ public class AuthService : IAuthService
{
Uid = user.Uid,
Nickname = user.Nickname,
- Headimg = user.HeadImg
+ Headimg = user.Avatar
};
}
catch (Exception ex)
@@ -802,7 +790,7 @@ public class AuthService : IAuthService
{
mobileUser.UnionId = currentUser.UnionId;
}
- mobileUser.UpdatedAt = DateTime.UtcNow;
+ mobileUser.UpdateTime = DateTime.Now;
_dbContext.Users.Update(mobileUser);
// 删除当前用户
diff --git a/server/MiAssessment/src/MiAssessment.Core/Services/DefaultPaymentRewardHandler.cs b/server/MiAssessment/src/MiAssessment.Core/Services/DefaultPaymentRewardHandler.cs
deleted file mode 100644
index e69de78..0000000
--- a/server/MiAssessment/src/MiAssessment.Core/Services/DefaultPaymentRewardHandler.cs
+++ /dev/null
@@ -1,85 +0,0 @@
-using MiAssessment.Core.Interfaces;
-using MiAssessment.Model.Entities;
-using Microsoft.Extensions.Logging;
-
-namespace MiAssessment.Core.Services;
-
-///
-/// 默认支付奖励处理器示例
-/// 用于演示如何实现自定义奖励处理器
-///
-/// 使用方法:
-/// 1. 创建一个新类实现 IPaymentRewardHandler 接口
-/// 2. 设置 OrderType 属性为要处理的订单类型
-/// 3. 在 ProcessRewardAsync 方法中实现奖励发放逻辑
-/// 4. 在 ServiceModule.cs 中注册处理器
-///
-/// 注册示例:
-///
-/// builder.RegisterType<MyRewardHandler>()
-/// .As<IPaymentRewardHandler>()
-/// .InstancePerLifetimeScope();
-///
-///
-///
-/// 实现钻石充值奖励处理器示例:
-///
-/// public class DiamondRechargeRewardHandler : IPaymentRewardHandler
-/// {
-/// public string OrderType => "diamond_recharge";
-///
-/// public async Task<RewardResult> ProcessRewardAsync(PaymentOrder order)
-/// {
-/// // 1. 解析业务数据
-/// var bizData = JsonSerializer.Deserialize<DiamondRechargeData>(order.BizData);
-///
-/// // 2. 发放钻石
-/// await _userService.AddDiamondsAsync(order.UserId, bizData.DiamondAmount);
-///
-/// // 3. 返回结果
-/// return RewardResult.Ok(JsonSerializer.Serialize(new { diamonds = bizData.DiamondAmount }));
-/// }
-/// }
-///
-///
-public class DefaultPaymentRewardHandler : IPaymentRewardHandler
-{
- private readonly ILogger _logger;
-
- ///
- /// 处理的订单类型
- /// 默认处理器使用 "default" 类型,实际项目中应替换为具体的业务类型
- ///
- public string OrderType => "default";
-
- public DefaultPaymentRewardHandler(ILogger logger)
- {
- _logger = logger;
- }
-
- ///
- /// 处理奖励发放
- /// 默认实现仅记录日志,实际项目中应实现具体的奖励逻辑
- ///
- /// 支付订单
- /// 奖励处理结果
- public Task ProcessRewardAsync(PaymentOrder order)
- {
- _logger.LogInformation(
- "默认奖励处理器被调用: OrderNo={OrderNo}, UserId={UserId}, Amount={Amount}, BizData={BizData}",
- order.OrderNo,
- order.UserId,
- order.Amount,
- order.BizData);
-
- // 默认处理器直接返回成功
- // 实际项目中应根据 order.BizData 中的业务数据执行具体的奖励逻辑
- var rewardData = System.Text.Json.JsonSerializer.Serialize(new
- {
- message = "默认奖励处理完成",
- processedAt = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
- });
-
- return Task.FromResult(RewardResult.Ok(rewardData));
- }
-}
diff --git a/server/MiAssessment/src/MiAssessment.Core/Services/InviteService.cs b/server/MiAssessment/src/MiAssessment.Core/Services/InviteService.cs
index 5dab55c..b1e3ec3 100644
--- a/server/MiAssessment/src/MiAssessment.Core/Services/InviteService.cs
+++ b/server/MiAssessment/src/MiAssessment.Core/Services/InviteService.cs
@@ -75,7 +75,7 @@ public class InviteService : IInviteService
// 统计邀请人数(直属下级)
var inviteCount = await _dbContext.Users
.AsNoTracking()
- .CountAsync(u => u.Pid == userId);
+ .CountAsync(u => u.ParentUserId == userId);
// 计算待提现金额(可提现余额)
var pendingAmount = user.Balance;
@@ -166,23 +166,23 @@ public class InviteService : IInviteService
// 查询直属下级用户(Pid = userId)
var query = _dbContext.Users
.AsNoTracking()
- .Where(u => u.Pid == userId);
+ .Where(u => u.ParentUserId == userId);
// 获取总数
var total = await query.CountAsync();
// 分页查询下级用户
var invitedUsers = await query
- .OrderByDescending(u => u.CreatedAt)
+ .OrderByDescending(u => u.CreateTime)
.Skip((page - 1) * pageSize)
.Take(pageSize)
.Select(u => new
{
u.Id,
u.Nickname,
- u.HeadImg,
+ u.Avatar,
u.Uid,
- u.CreatedAt
+ u.CreateTime
})
.ToListAsync();
@@ -204,9 +204,9 @@ public class InviteService : IInviteService
{
UserId = u.Id,
Nickname = u.Nickname ?? "未设置昵称",
- Avatar = u.HeadImg ?? string.Empty,
+ Avatar = u.Avatar ?? string.Empty,
Uid = u.Uid,
- RegisterDate = u.CreatedAt.ToString("yyyy-MM-dd"),
+ RegisterDate = u.CreateTime.ToString("yyyy-MM-dd"),
Commission = commissions.TryGetValue(u.Id, out var commission) ? commission : 0
}).ToList();
@@ -398,7 +398,7 @@ public class InviteService : IInviteService
// 扣减用户余额 (Requirement 13.1)
user.Balance = afterBalance;
- user.UpdatedAt = DateTime.Now;
+ user.UpdateTime = DateTime.Now;
// 保存更改
await _dbContext.SaveChangesAsync();
diff --git a/server/MiAssessment/src/MiAssessment.Core/Services/PaymentNotifyService.cs b/server/MiAssessment/src/MiAssessment.Core/Services/PaymentNotifyService.cs
index 18caea1..95d1a9e 100644
--- a/server/MiAssessment/src/MiAssessment.Core/Services/PaymentNotifyService.cs
+++ b/server/MiAssessment/src/MiAssessment.Core/Services/PaymentNotifyService.cs
@@ -367,7 +367,7 @@ public class PaymentNotifyService : IPaymentNotifyService
existingNotify.PayTime = DateTime.Now;
existingNotify.PayAmount = notifyData.TotalFee / 100m;
existingNotify.RawData = null; // 可选:存储原始XML
- existingNotify.UpdatedAt = DateTime.Now;
+ existingNotify.UpdateTime = DateTime.Now;
}
else
{
@@ -383,8 +383,8 @@ public class PaymentNotifyService : IPaymentNotifyService
Attach = notifyData.Attach,
OpenId = notifyData.OpenId,
RawData = null,
- CreatedAt = DateTime.Now,
- UpdatedAt = DateTime.Now
+ CreateTime = DateTime.Now,
+ UpdateTime = DateTime.Now
};
_dbContext.OrderNotifies.Add(notify);
@@ -412,7 +412,7 @@ public class PaymentNotifyService : IPaymentNotifyService
{
notify.Status = status;
notify.ErrorMessage = message;
- notify.UpdatedAt = DateTime.Now;
+ notify.UpdateTime = DateTime.Now;
await _dbContext.SaveChangesAsync();
return true;
}
diff --git a/server/MiAssessment/src/MiAssessment.Core/Services/PaymentOrderService.cs b/server/MiAssessment/src/MiAssessment.Core/Services/PaymentOrderService.cs
deleted file mode 100644
index a828a71..0000000
--- a/server/MiAssessment/src/MiAssessment.Core/Services/PaymentOrderService.cs
+++ /dev/null
@@ -1,389 +0,0 @@
-using MiAssessment.Core.Interfaces;
-using MiAssessment.Model.Data;
-using MiAssessment.Model.Entities;
-using MiAssessment.Model.Models;
-using MiAssessment.Model.Models.Payment;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.Extensions.Logging;
-
-namespace MiAssessment.Core.Services;
-
-///
-/// 通用支付订单服务实现
-///
-public class PaymentOrderService : IPaymentOrderService
-{
- private readonly MiAssessmentDbContext _dbContext;
- private readonly IEnumerable _rewardHandlers;
- private readonly ILogger _logger;
-
- public PaymentOrderService(
- MiAssessmentDbContext dbContext,
- IEnumerable rewardHandlers,
- ILogger logger)
- {
- _dbContext = dbContext;
- _rewardHandlers = rewardHandlers;
- _logger = logger;
- }
-
- ///
- public async Task CreateOrderAsync(CreatePaymentOrderRequest request)
- {
- if (request == null)
- throw new ArgumentNullException(nameof(request));
-
- if (request.UserId <= 0)
- throw new ArgumentException("用户ID无效", nameof(request));
-
- if (string.IsNullOrWhiteSpace(request.OrderType))
- throw new ArgumentException("订单类型不能为空", nameof(request));
-
- if (request.Amount <= 0)
- throw new ArgumentException("订单金额必须大于0", nameof(request));
-
- // 生成唯一订单号
- var orderNo = GenerateOrderNo();
-
- var order = new PaymentOrder
- {
- OrderNo = orderNo,
- UserId = request.UserId,
- OrderType = request.OrderType,
- Title = request.Title ?? string.Empty,
- Amount = request.Amount,
- PayAmount = request.PayAmount ?? request.Amount,
- PayMethod = request.PayMethod,
- Status = 0, // 待支付
- BizId = request.BizId,
- BizData = request.BizData,
- RewardStatus = 0, // 未发放
- CreatedAt = DateTime.Now,
- UpdatedAt = DateTime.Now
- };
-
- _dbContext.PaymentOrders.Add(order);
- await _dbContext.SaveChangesAsync();
-
- _logger.LogInformation("创建支付订单成功: OrderNo={OrderNo}, UserId={UserId}, OrderType={OrderType}, Amount={Amount}",
- orderNo, request.UserId, request.OrderType, request.Amount);
-
- return order;
- }
-
- ///
- public async Task GetOrderByNoAsync(string orderNo)
- {
- if (string.IsNullOrWhiteSpace(orderNo))
- return null;
-
- return await _dbContext.PaymentOrders
- .FirstOrDefaultAsync(o => o.OrderNo == orderNo);
- }
-
- ///
- public async Task GetOrderByIdAsync(int orderId)
- {
- if (orderId <= 0)
- return null;
-
- return await _dbContext.PaymentOrders
- .FirstOrDefaultAsync(o => o.Id == orderId);
- }
-
- ///
- public async Task HandlePaymentSuccessAsync(string orderNo, string transactionId, decimal payAmount)
- {
- if (string.IsNullOrWhiteSpace(orderNo))
- {
- _logger.LogWarning("处理支付成功失败: 订单号为空");
- return false;
- }
-
- var order = await GetOrderByNoAsync(orderNo);
- if (order == null)
- {
- _logger.LogWarning("处理支付成功失败: 订单不存在, OrderNo={OrderNo}", orderNo);
- return false;
- }
-
- // 幂等性检查:如果订单已支付,直接返回成功
- if (order.Status == 1)
- {
- _logger.LogInformation("订单已支付,跳过重复处理: OrderNo={OrderNo}", orderNo);
- return true;
- }
-
- // 只有待支付状态的订单才能处理
- if (order.Status != 0)
- {
- _logger.LogWarning("订单状态不正确,无法处理支付成功: OrderNo={OrderNo}, Status={Status}", orderNo, order.Status);
- return false;
- }
-
- // 更新订单状态
- order.Status = 1; // 已支付
- order.PaidAt = DateTime.Now;
- order.TransactionId = transactionId;
- order.PayAmount = payAmount;
- order.UpdatedAt = DateTime.Now;
-
- await _dbContext.SaveChangesAsync();
-
- _logger.LogInformation("订单支付成功: OrderNo={OrderNo}, TransactionId={TransactionId}, PayAmount={PayAmount}",
- orderNo, transactionId, payAmount);
-
- // 触发奖励发放
- await ProcessRewardAsync(orderNo);
-
- return true;
- }
-
- ///
- public async Task ProcessRewardAsync(string orderNo)
- {
- if (string.IsNullOrWhiteSpace(orderNo))
- {
- _logger.LogWarning("处理奖励失败: 订单号为空");
- return false;
- }
-
- var order = await GetOrderByNoAsync(orderNo);
- if (order == null)
- {
- _logger.LogWarning("处理奖励失败: 订单不存在, OrderNo={OrderNo}", orderNo);
- return false;
- }
-
- // 只有已支付且未发放奖励的订单才能处理
- if (order.Status != 1)
- {
- _logger.LogWarning("订单未支付,无法发放奖励: OrderNo={OrderNo}, Status={Status}", orderNo, order.Status);
- return false;
- }
-
- if (order.RewardStatus == 1)
- {
- _logger.LogInformation("奖励已发放,跳过重复处理: OrderNo={OrderNo}", orderNo);
- return true;
- }
-
- // 查找对应的奖励处理器
- var handler = _rewardHandlers.FirstOrDefault(h => h.OrderType == order.OrderType);
- if (handler == null)
- {
- _logger.LogInformation("未找到订单类型对应的奖励处理器: OrderNo={OrderNo}, OrderType={OrderType}",
- orderNo, order.OrderType);
- // 没有处理器不算失败,可能该订单类型不需要奖励
- return true;
- }
-
- try
- {
- _logger.LogInformation("开始处理奖励: OrderNo={OrderNo}, OrderType={OrderType}, Handler={Handler}",
- orderNo, order.OrderType, handler.GetType().Name);
-
- var result = await handler.ProcessRewardAsync(order);
-
- if (result.Success)
- {
- order.RewardStatus = 1; // 已发放
- order.RewardData = result.RewardData;
- order.RewardAt = DateTime.Now;
- order.UpdatedAt = DateTime.Now;
-
- await _dbContext.SaveChangesAsync();
-
- _logger.LogInformation("奖励发放成功: OrderNo={OrderNo}, RewardData={RewardData}",
- orderNo, result.RewardData);
-
- return true;
- }
- else
- {
- order.RewardStatus = 2; // 发放失败
- order.RewardData = result.Message;
- order.UpdatedAt = DateTime.Now;
-
- await _dbContext.SaveChangesAsync();
-
- _logger.LogWarning("奖励发放失败: OrderNo={OrderNo}, Message={Message}",
- orderNo, result.Message);
-
- return false;
- }
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "奖励发放异常: OrderNo={OrderNo}", orderNo);
-
- order.RewardStatus = 2; // 发放失败
- order.RewardData = ex.Message;
- order.UpdatedAt = DateTime.Now;
-
- await _dbContext.SaveChangesAsync();
-
- return false;
- }
- }
-
- ///
- public async Task> GetUserOrdersAsync(int userId, PaymentOrderQueryRequest request)
- {
- if (userId <= 0)
- throw new ArgumentException("用户ID无效", nameof(userId));
-
- request ??= new PaymentOrderQueryRequest();
-
- // 确保分页参数有效
- if (request.Page < 1) request.Page = 1;
- if (request.PageSize < 1) request.PageSize = 10;
- if (request.PageSize > 100) request.PageSize = 100;
-
- var query = _dbContext.PaymentOrders
- .Where(o => o.UserId == userId);
-
- // 按订单类型筛选
- if (!string.IsNullOrWhiteSpace(request.OrderType))
- {
- query = query.Where(o => o.OrderType == request.OrderType);
- }
-
- // 按状态筛选
- if (request.Status.HasValue)
- {
- query = query.Where(o => o.Status == request.Status.Value);
- }
-
- // 按时间范围筛选
- if (request.StartTime.HasValue)
- {
- query = query.Where(o => o.CreatedAt >= request.StartTime.Value);
- }
-
- if (request.EndTime.HasValue)
- {
- query = query.Where(o => o.CreatedAt <= request.EndTime.Value);
- }
-
- // 获取总数
- var total = await query.CountAsync();
-
- // 分页查询
- var orders = await query
- .OrderByDescending(o => o.CreatedAt)
- .Skip((request.Page - 1) * request.PageSize)
- .Take(request.PageSize)
- .Select(o => new PaymentOrderDto
- {
- Id = o.Id,
- OrderNo = o.OrderNo,
- UserId = o.UserId,
- OrderType = o.OrderType,
- Title = o.Title,
- Amount = o.Amount,
- PayAmount = o.PayAmount,
- PayMethod = o.PayMethod,
- Status = o.Status,
- PaidAt = o.PaidAt,
- TransactionId = o.TransactionId,
- BizId = o.BizId,
- BizData = o.BizData,
- RewardStatus = o.RewardStatus,
- RewardData = o.RewardData,
- RewardAt = o.RewardAt,
- CreatedAt = o.CreatedAt,
- UpdatedAt = o.UpdatedAt
- })
- .ToListAsync();
-
- var lastPage = (int)Math.Ceiling((double)total / request.PageSize);
-
- return new PageResponse
- {
- Data = orders,
- Total = total,
- Page = request.Page,
- PageSize = request.PageSize,
- LastPage = lastPage
- };
- }
-
- ///
- public async Task CancelOrderAsync(string orderNo, int userId)
- {
- if (string.IsNullOrWhiteSpace(orderNo))
- {
- _logger.LogWarning("取消订单失败: 订单号为空");
- return false;
- }
-
- var order = await GetOrderByNoAsync(orderNo);
- if (order == null)
- {
- _logger.LogWarning("取消订单失败: 订单不存在, OrderNo={OrderNo}", orderNo);
- return false;
- }
-
- // 验证用户权限
- if (order.UserId != userId)
- {
- _logger.LogWarning("取消订单失败: 用户无权限, OrderNo={OrderNo}, UserId={UserId}, OrderUserId={OrderUserId}",
- orderNo, userId, order.UserId);
- return false;
- }
-
- // 只有待支付状态的订单才能取消
- if (order.Status != 0)
- {
- _logger.LogWarning("取消订单失败: 订单状态不正确, OrderNo={OrderNo}, Status={Status}", orderNo, order.Status);
- return false;
- }
-
- order.Status = 2; // 已取消
- order.UpdatedAt = DateTime.Now;
-
- await _dbContext.SaveChangesAsync();
-
- _logger.LogInformation("订单取消成功: OrderNo={OrderNo}, UserId={UserId}", orderNo, userId);
-
- return true;
- }
-
- ///
- public async Task UpdateOrderStatusAsync(string orderNo, byte status)
- {
- if (string.IsNullOrWhiteSpace(orderNo))
- {
- _logger.LogWarning("更新订单状态失败: 订单号为空");
- return false;
- }
-
- var order = await GetOrderByNoAsync(orderNo);
- if (order == null)
- {
- _logger.LogWarning("更新订单状态失败: 订单不存在, OrderNo={OrderNo}", orderNo);
- return false;
- }
-
- order.Status = status;
- order.UpdatedAt = DateTime.Now;
-
- await _dbContext.SaveChangesAsync();
-
- _logger.LogInformation("订单状态更新成功: OrderNo={OrderNo}, Status={Status}", orderNo, status);
-
- return true;
- }
-
- ///
- /// 生成唯一订单号
- /// 格式: yyyyMMddHHmmss + 6位随机数
- ///
- private static string GenerateOrderNo()
- {
- var timestamp = DateTime.Now.ToString("yyyyMMddHHmmss");
- var random = Random.Shared.Next(100000, 999999);
- return $"{timestamp}{random}";
- }
-}
diff --git a/server/MiAssessment/src/MiAssessment.Core/Services/PaymentRewardDispatcher.cs b/server/MiAssessment/src/MiAssessment.Core/Services/PaymentRewardDispatcher.cs
deleted file mode 100644
index 3690615..0000000
--- a/server/MiAssessment/src/MiAssessment.Core/Services/PaymentRewardDispatcher.cs
+++ /dev/null
@@ -1,136 +0,0 @@
-using MiAssessment.Core.Interfaces;
-using MiAssessment.Model.Entities;
-using Microsoft.Extensions.Logging;
-
-namespace MiAssessment.Core.Services;
-
-///
-/// 支付奖励分发器
-/// 负责根据订单类型查找并调用对应的奖励处理器
-///
-public class PaymentRewardDispatcher : IPaymentRewardDispatcher
-{
- private readonly IEnumerable _handlers;
- private readonly ILogger _logger;
- private readonly Dictionary _handlerMap;
-
- public PaymentRewardDispatcher(
- IEnumerable handlers,
- ILogger logger)
- {
- _handlers = handlers ?? throw new ArgumentNullException(nameof(handlers));
- _logger = logger ?? throw new ArgumentNullException(nameof(logger));
-
- // 构建处理器映射表,提高查找效率
- _handlerMap = new Dictionary(StringComparer.OrdinalIgnoreCase);
- foreach (var handler in _handlers)
- {
- if (!string.IsNullOrWhiteSpace(handler.OrderType))
- {
- if (_handlerMap.ContainsKey(handler.OrderType))
- {
- _logger.LogWarning("发现重复的奖励处理器: OrderType={OrderType}, 已存在={ExistingHandler}, 新处理器={NewHandler}",
- handler.OrderType,
- _handlerMap[handler.OrderType].GetType().Name,
- handler.GetType().Name);
- }
- else
- {
- _handlerMap[handler.OrderType] = handler;
- _logger.LogDebug("注册奖励处理器: OrderType={OrderType}, Handler={Handler}",
- handler.OrderType, handler.GetType().Name);
- }
- }
- }
-
- _logger.LogInformation("奖励分发器初始化完成,已注册 {Count} 个处理器", _handlerMap.Count);
- }
-
- ///
- public IPaymentRewardHandler? GetHandler(string orderType)
- {
- if (string.IsNullOrWhiteSpace(orderType))
- {
- _logger.LogWarning("获取处理器失败: 订单类型为空");
- return null;
- }
-
- if (_handlerMap.TryGetValue(orderType, out var handler))
- {
- _logger.LogDebug("找到奖励处理器: OrderType={OrderType}, Handler={Handler}",
- orderType, handler.GetType().Name);
- return handler;
- }
-
- _logger.LogInformation("未找到订单类型对应的奖励处理器: OrderType={OrderType}", orderType);
- return null;
- }
-
- ///
- public bool HasHandler(string orderType)
- {
- if (string.IsNullOrWhiteSpace(orderType))
- return false;
-
- return _handlerMap.ContainsKey(orderType);
- }
-
- ///
- public IReadOnlyCollection GetRegisteredOrderTypes()
- {
- return _handlerMap.Keys.ToList().AsReadOnly();
- }
-
- ///
- public async Task ProcessRewardAsync(PaymentOrder order)
- {
- if (order == null)
- {
- _logger.LogWarning("处理奖励失败: 订单为空");
- return RewardResult.Fail("订单不能为空");
- }
-
- if (string.IsNullOrWhiteSpace(order.OrderType))
- {
- _logger.LogWarning("处理奖励失败: 订单类型为空, OrderNo={OrderNo}", order.OrderNo);
- return RewardResult.Fail("订单类型不能为空");
- }
-
- var handler = GetHandler(order.OrderType);
- if (handler == null)
- {
- // 没有处理器不算失败,可能该订单类型不需要奖励
- _logger.LogInformation("订单类型无需奖励处理: OrderNo={OrderNo}, OrderType={OrderType}",
- order.OrderNo, order.OrderType);
- return RewardResult.Ok();
- }
-
- try
- {
- _logger.LogInformation("开始处理奖励: OrderNo={OrderNo}, OrderType={OrderType}, Handler={Handler}",
- order.OrderNo, order.OrderType, handler.GetType().Name);
-
- var result = await handler.ProcessRewardAsync(order);
-
- if (result.Success)
- {
- _logger.LogInformation("奖励处理成功: OrderNo={OrderNo}, OrderType={OrderType}, RewardData={RewardData}",
- order.OrderNo, order.OrderType, result.RewardData);
- }
- else
- {
- _logger.LogWarning("奖励处理失败: OrderNo={OrderNo}, OrderType={OrderType}, Message={Message}",
- order.OrderNo, order.OrderType, result.Message);
- }
-
- return result;
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "奖励处理异常: OrderNo={OrderNo}, OrderType={OrderType}, Handler={Handler}",
- order.OrderNo, order.OrderType, handler.GetType().Name);
-
- return RewardResult.Fail($"奖励处理异常: {ex.Message}");
- }
- }
-}
diff --git a/server/MiAssessment/src/MiAssessment.Core/Services/PaymentService.cs b/server/MiAssessment/src/MiAssessment.Core/Services/PaymentService.cs
deleted file mode 100644
index f3ad244..0000000
--- a/server/MiAssessment/src/MiAssessment.Core/Services/PaymentService.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-using MiAssessment.Core.Interfaces;
-using MiAssessment.Model.Data;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.Extensions.Logging;
-
-namespace MiAssessment.Core.Services;
-
-///
-/// 支付服务实现
-/// 提供基础的支付相关功能,具体业务逻辑由业务模块扩展
-/// 注意:余额相关字段已移至 UserDetail 扩展表,此处返回默认值
-///
-public class PaymentService : IPaymentService
-{
- private readonly MiAssessmentDbContext _dbContext;
- private readonly ILogger _logger;
-
- public PaymentService(
- MiAssessmentDbContext dbContext,
- ILogger logger)
- {
- _dbContext = dbContext;
- _logger = logger;
- }
-
- ///
- ///
- /// 余额字段已从 User 实体移除,此方法需要在业务层重新实现
- /// 当前返回 false,表示不支持余额支付
- ///
- public async Task ValidateBalanceAsync(int userId, decimal amount)
- {
- var user = await _dbContext.Users.FindAsync(userId);
- if (user == null)
- return false;
-
- // 余额字段已移至 UserDetail 扩展表
- // 业务层需要实现具体的余额验证逻辑
- _logger.LogWarning("ValidateBalanceAsync: 余额字段已移至 UserDetail 扩展表,请在业务层实现具体逻辑");
- return false;
- }
-
- ///
- ///
- /// 余额字段已从 User 实体移除,此方法需要在业务层重新实现
- /// 当前返回 0
- ///
- public async Task GetUserBalanceAsync(int userId)
- {
- var user = await _dbContext.Users.FindAsync(userId);
- if (user == null)
- return 0;
-
- // 余额字段已移至 UserDetail 扩展表
- // 业务层需要实现具体的余额查询逻辑
- _logger.LogWarning("GetUserBalanceAsync: 余额字段已移至 UserDetail 扩展表,请在业务层实现具体逻辑");
- return 0;
- }
-}
diff --git a/server/MiAssessment/src/MiAssessment.Core/Services/UserService.cs b/server/MiAssessment/src/MiAssessment.Core/Services/UserService.cs
index 43a1e32..b225775 100644
--- a/server/MiAssessment/src/MiAssessment.Core/Services/UserService.cs
+++ b/server/MiAssessment/src/MiAssessment.Core/Services/UserService.cs
@@ -50,7 +50,7 @@ public class UserService : BaseService, IUserService
if (string.IsNullOrWhiteSpace(mobile))
return null;
- return await _dbSet.FirstOrDefaultAsync(u => u.Mobile == mobile);
+ return await _dbSet.FirstOrDefaultAsync(u => u.Phone == mobile);
}
///
@@ -66,15 +66,15 @@ public class UserService : BaseService, IUserService
{
OpenId = dto.OpenId ?? string.Empty,
UnionId = dto.UnionId,
- Mobile = dto.Mobile,
+ Phone = dto.Mobile,
Uid = uid,
Nickname = dto.Nickname ?? $"User{Random.Shared.Next(1000, 9999)}",
- HeadImg = dto.Headimg ?? string.Empty,
- Pid = dto.Pid,
+ Avatar = dto.Headimg ?? string.Empty,
+ ParentUserId = dto.Pid,
Status = 1,
IsTest = 0,
- CreatedAt = DateTime.UtcNow,
- UpdatedAt = DateTime.UtcNow
+ CreateTime = DateTime.Now,
+ UpdateTime = DateTime.Now
};
await _dbSet.AddAsync(user);
@@ -99,15 +99,15 @@ public class UserService : BaseService, IUserService
user.Nickname = dto.Nickname;
if (!string.IsNullOrWhiteSpace(dto.Headimg))
- user.HeadImg = dto.Headimg;
+ user.Avatar = dto.Headimg;
if (!string.IsNullOrWhiteSpace(dto.Mobile))
- user.Mobile = dto.Mobile;
+ user.Phone = dto.Mobile;
if (!string.IsNullOrWhiteSpace(dto.UnionId))
user.UnionId = dto.UnionId;
- user.UpdatedAt = DateTime.UtcNow;
+ user.UpdateTime = DateTime.Now;
_dbSet.Update(user);
await _dbContext.SaveChangesAsync();
@@ -122,17 +122,17 @@ public class UserService : BaseService, IUserService
if (user == null)
return null;
- var registrationDays = (int)(DateTime.UtcNow - user.CreatedAt).TotalDays;
+ var registrationDays = (int)(DateTime.Now - user.CreateTime).TotalDays;
- var maskedMobile = MaskMobileNumber(user.Mobile);
- var mobileIs = string.IsNullOrWhiteSpace(user.Mobile) ? 0 : 1;
+ var maskedMobile = MaskMobileNumber(user.Phone);
+ var mobileIs = string.IsNullOrWhiteSpace(user.Phone) ? 0 : 1;
return new UserInfoDto
{
Id = user.Id,
Uid = user.Uid,
Nickname = user.Nickname,
- Headimg = user.HeadImg,
+ Headimg = user.Avatar,
Mobile = maskedMobile,
MobileIs = mobileIs,
Money = 0, // 业务字段已移除,返回默认值
diff --git a/server/MiAssessment/src/MiAssessment.Core/Services/WechatPayService.cs b/server/MiAssessment/src/MiAssessment.Core/Services/WechatPayService.cs
index abd4241..1df1f44 100644
--- a/server/MiAssessment/src/MiAssessment.Core/Services/WechatPayService.cs
+++ b/server/MiAssessment/src/MiAssessment.Core/Services/WechatPayService.cs
@@ -299,8 +299,8 @@ public class WechatPayService : IWechatPayService
RetryCount = 0,
Attach = attach,
OpenId = openId,
- CreatedAt = DateTime.Now,
- UpdatedAt = DateTime.Now
+ CreateTime = DateTime.Now,
+ UpdateTime = DateTime.Now
};
_dbContext.OrderNotifies.Add(orderNotify);
diff --git a/server/MiAssessment/src/MiAssessment.Core/Services/WechatPayV3Service.cs b/server/MiAssessment/src/MiAssessment.Core/Services/WechatPayV3Service.cs
index 196ccc3..708cea7 100644
--- a/server/MiAssessment/src/MiAssessment.Core/Services/WechatPayV3Service.cs
+++ b/server/MiAssessment/src/MiAssessment.Core/Services/WechatPayV3Service.cs
@@ -882,8 +882,8 @@ public class WechatPayV3Service : IWechatPayV3Service
RetryCount = 0,
Attach = attach,
OpenId = openId,
- CreatedAt = DateTime.Now,
- UpdatedAt = DateTime.Now
+ CreateTime = DateTime.Now,
+ UpdateTime = DateTime.Now
};
_dbContext.OrderNotifies.Add(orderNotify);
diff --git a/server/MiAssessment/src/MiAssessment.Core/Services/WechatService.cs b/server/MiAssessment/src/MiAssessment.Core/Services/WechatService.cs
index 7cee6e6..ba3adba 100644
--- a/server/MiAssessment/src/MiAssessment.Core/Services/WechatService.cs
+++ b/server/MiAssessment/src/MiAssessment.Core/Services/WechatService.cs
@@ -540,9 +540,8 @@ public class WechatService : IWechatService
RetryCount = 0,
Attach = request.Attach,
OpenId = request.OpenId,
- Extend = JsonSerializer.Serialize(new { orderType = request.Attach, title = title }),
- CreatedAt = DateTime.UtcNow,
- UpdatedAt = DateTime.UtcNow
+ CreateTime = DateTime.Now,
+ UpdateTime = DateTime.Now
};
_dbContext.OrderNotifies.Add(orderNotify);
diff --git a/server/MiAssessment/src/MiAssessment.Infrastructure/Modules/ServiceModule.cs b/server/MiAssessment/src/MiAssessment.Infrastructure/Modules/ServiceModule.cs
index b4a9653..9f91d87 100644
--- a/server/MiAssessment/src/MiAssessment.Infrastructure/Modules/ServiceModule.cs
+++ b/server/MiAssessment/src/MiAssessment.Infrastructure/Modules/ServiceModule.cs
@@ -58,16 +58,6 @@ public class ServiceModule : Module
return new AuthService(dbContext, userService, jwtService, wechatService, ipLocationService, redisService, jwtSettings, logger);
}).As().InstancePerLifetimeScope();
- // ========== 用户管理系统服务注册 ==========
-
- // 注册地址服务
- builder.Register(c =>
- {
- var dbContext = c.Resolve();
- var logger = c.Resolve>();
- return new AddressService(dbContext, logger);
- }).As().InstancePerLifetimeScope();
-
// ========== 支付系统服务注册 ==========
// 注册微信支付配置服务(从Admin库读取配置)
@@ -105,15 +95,7 @@ public class ServiceModule : Module
return new WechatPayService(dbContext, httpClientFactory.CreateClient(), logger, configService, wechatService, redisService, settings, appSettings, v3ServiceLazy);
}).As().InstancePerLifetimeScope();
- // 注册支付服务
- builder.Register(c =>
- {
- var dbContext = c.Resolve();
- var logger = c.Resolve>();
- return new PaymentService(dbContext, logger);
- }).As().InstancePerLifetimeScope();
-
- // 注册支付回调服务
+ // ========== 配置系统服务注册 ==========
builder.Register(c =>
{
var dbContext = c.Resolve();
@@ -124,33 +106,6 @@ public class ServiceModule : Module
return new PaymentNotifyService(dbContext, wechatPayService, wechatPayV3Service, wechatPayConfigService, logger);
}).As().InstancePerLifetimeScope();
- // 注册支付订单服务
- builder.Register(c =>
- {
- var dbContext = c.Resolve();
- var rewardHandlers = c.Resolve>();
- var logger = c.Resolve>();
- return new PaymentOrderService(dbContext, rewardHandlers, logger);
- }).As().InstancePerLifetimeScope();
-
- // 注册奖励分发器
- builder.Register(c =>
- {
- var rewardHandlers = c.Resolve>();
- var logger = c.Resolve>();
- return new PaymentRewardDispatcher(rewardHandlers, logger);
- }).As().SingleInstance();
-
- // ========== 奖励处理器注册 ==========
- // 注册默认奖励处理器(示例)
- // 实际项目中可以注册多个处理器,每个处理器处理不同的订单类型
- // 例如:DiamondRechargeRewardHandler, VipPurchaseRewardHandler 等
- builder.Register(c =>
- {
- var logger = c.Resolve>();
- return new DefaultPaymentRewardHandler(logger);
- }).As().InstancePerLifetimeScope();
-
// ========== 配置系统服务注册 ==========
// 注册配置服务
diff --git a/server/MiAssessment/src/MiAssessment.Model/Data/MiAssessmentDbContext.cs b/server/MiAssessment/src/MiAssessment.Model/Data/MiAssessmentDbContext.cs
index 59fd272..1fd0ae0 100644
--- a/server/MiAssessment/src/MiAssessment.Model/Data/MiAssessmentDbContext.cs
+++ b/server/MiAssessment/src/MiAssessment.Model/Data/MiAssessmentDbContext.cs
@@ -16,20 +16,9 @@ public partial class MiAssessmentDbContext : DbContext
{
}
- // ==================== Admin 基础表 ====================
- public virtual DbSet Admins { get; set; }
-
- public virtual DbSet AdminLoginLogs { get; set; }
-
- public virtual DbSet AdminOperationLogs { get; set; }
-
// ==================== 用户基础表 ====================
public virtual DbSet Users { get; set; }
- public virtual DbSet UserDetails { get; set; }
-
- public virtual DbSet UserAddresses { get; set; }
-
public virtual DbSet UserRefreshTokens { get; set; }
public virtual DbSet UserLoginLogs { get; set; }
@@ -39,12 +28,6 @@ public partial class MiAssessmentDbContext : DbContext
public virtual DbSet OrderNotifies { get; set; }
- public virtual DbSet PaymentOrders { get; set; }
-
- public virtual DbSet Pictures { get; set; }
-
- public virtual DbSet Deliveries { get; set; }
-
// ==================== 小程序业务表 ====================
public virtual DbSet Banners { get; set; }
@@ -86,131 +69,6 @@ public partial class MiAssessmentDbContext : DbContext
{
modelBuilder.UseCollation("Chinese_PRC_CI_AS");
- // ==================== Admin 基础表配置 ====================
- modelBuilder.Entity(entity =>
- {
- entity.HasKey(e => e.Id).HasName("pk_admins");
-
- entity.ToTable("admins", tb => tb.HasComment("管理员表,存储后台管理员信息"));
-
- entity.HasIndex(e => e.Status, "ix_admins_status");
-
- entity.HasIndex(e => e.Token, "ix_admins_token");
-
- entity.HasIndex(e => e.Username, "ix_admins_username");
-
- entity.Property(e => e.Id)
- .HasComment("主键ID")
- .HasColumnName("id");
- entity.Property(e => e.AdminId)
- .HasComment("上级管理员ID")
- .HasColumnName("admin_id");
- entity.Property(e => e.CreatedAt)
- .HasDefaultValueSql("(getdate())")
- .HasComment("创建时间")
- .HasColumnName("created_at");
- entity.Property(e => e.GetTime)
- .HasDefaultValueSql("(getdate())")
- .HasComment("获取时间")
- .HasColumnName("get_time");
- entity.Property(e => e.Nickname)
- .HasMaxLength(20)
- .HasComment("昵称")
- .HasColumnName("nickname");
- entity.Property(e => e.Password)
- .HasMaxLength(40)
- .HasComment("密码(加密)")
- .HasColumnName("password");
- entity.Property(e => e.Qid)
- .HasComment("权限组ID")
- .HasColumnName("qid");
- entity.Property(e => e.Random)
- .HasMaxLength(20)
- .HasComment("随机字符串")
- .HasColumnName("random");
- entity.Property(e => e.Status)
- .HasDefaultValue(0)
- .HasComment("状态:0-正常")
- .HasColumnName("status");
- entity.Property(e => e.Token)
- .HasMaxLength(100)
- .HasComment("登录令牌")
- .HasColumnName("token");
- entity.Property(e => e.UpdatedAt)
- .HasDefaultValueSql("(getdate())")
- .HasComment("更新时间")
- .HasColumnName("updated_at");
- entity.Property(e => e.Username)
- .HasMaxLength(20)
- .HasComment("用户名")
- .HasColumnName("username");
- });
-
- modelBuilder.Entity(entity =>
- {
- entity.HasKey(e => e.Id).HasName("pk_admin_login_logs");
-
- entity.ToTable("admin_login_logs", tb => tb.HasComment("管理员登录日志表,记录管理员登录信息(仅结构,不迁移历史数据)"));
-
- entity.HasIndex(e => e.AdminId, "ix_admin_login_logs_admin_id");
-
- entity.HasIndex(e => e.CreatedAt, "ix_admin_login_logs_created_at");
-
- entity.HasIndex(e => e.Ip, "ix_admin_login_logs_ip");
-
- entity.Property(e => e.Id)
- .HasComment("主键ID")
- .HasColumnName("id");
- entity.Property(e => e.AdminId)
- .HasComment("管理员ID")
- .HasColumnName("admin_id");
- entity.Property(e => e.CreatedAt)
- .HasDefaultValueSql("(getdate())")
- .HasComment("登录时间")
- .HasColumnName("created_at");
- entity.Property(e => e.Ip)
- .HasMaxLength(50)
- .HasComment("登录IP地址")
- .HasColumnName("ip");
- });
-
- modelBuilder.Entity(entity =>
- {
- entity.HasKey(e => e.Id).HasName("pk_admin_operation_logs");
-
- entity.ToTable("admin_operation_logs", tb => tb.HasComment("管理员操作日志表,记录管理员操作信息(仅结构,不迁移历史数据)"));
-
- entity.HasIndex(e => e.AdminId, "ix_admin_operation_logs_admin_id");
-
- entity.HasIndex(e => e.CreatedAt, "ix_admin_operation_logs_created_at");
-
- entity.HasIndex(e => e.Ip, "ix_admin_operation_logs_ip");
-
- entity.HasIndex(e => e.Operation, "ix_admin_operation_logs_operation");
-
- entity.Property(e => e.Id)
- .HasComment("主键ID")
- .HasColumnName("id");
- entity.Property(e => e.AdminId)
- .HasComment("管理员ID")
- .HasColumnName("admin_id");
- entity.Property(e => e.Content)
- .HasComment("操作内容详情")
- .HasColumnName("content");
- entity.Property(e => e.CreatedAt)
- .HasDefaultValueSql("(getdate())")
- .HasComment("操作时间")
- .HasColumnName("created_at");
- entity.Property(e => e.Ip)
- .HasMaxLength(50)
- .HasComment("操作IP地址")
- .HasColumnName("ip");
- entity.Property(e => e.Operation)
- .HasMaxLength(255)
- .HasComment("操作名称")
- .HasColumnName("operation");
- });
-
// ==================== 用户基础表配置 ====================
modelBuilder.Entity(entity =>
{
@@ -218,178 +76,75 @@ public partial class MiAssessmentDbContext : DbContext
entity.ToTable("users", tb => tb.HasComment("用户主表,存储用户基本信息"));
- entity.HasIndex(e => e.CreatedAt, "ix_users_created_at");
-
- entity.HasIndex(e => e.Mobile, "ix_users_mobile").HasFilter("([mobile] IS NOT NULL)");
-
+ entity.HasIndex(e => e.CreateTime, "ix_users_created_at");
+ entity.HasIndex(e => e.Phone, "ix_users_mobile").HasFilter("([Phone] IS NOT NULL)");
entity.HasIndex(e => e.OpenId, "ix_users_open_id");
-
- entity.HasIndex(e => e.Pid, "ix_users_pid");
-
+ entity.HasIndex(e => e.ParentUserId, "ix_users_pid");
entity.HasIndex(e => e.Status, "ix_users_status");
-
entity.HasIndex(e => e.Uid, "uk_users_uid").IsUnique();
entity.Property(e => e.Id)
- .HasComment("主键ID")
- .HasColumnName("id");
- entity.Property(e => e.CreatedAt)
- .HasDefaultValueSql("(getdate())")
- .HasComment("创建时间")
- .HasColumnName("created_at");
- entity.Property(e => e.GzhOpenId)
- .HasMaxLength(255)
- .HasComment("公众号openid")
- .HasColumnName("gzh_open_id");
- entity.Property(e => e.HeadImg)
- .HasMaxLength(255)
- .HasComment("头像URL")
- .HasColumnName("head_img");
- entity.Property(e => e.IsTest)
- .HasComment("是否测试账号: 0否 1是")
- .HasColumnName("is_test");
- entity.Property(e => e.LastLoginTime)
- .HasComment("最后登录时间")
- .HasColumnName("last_login_time");
- entity.Property(e => e.LastLoginIp)
- .HasMaxLength(50)
- .HasComment("最后登录IP")
- .HasColumnName("last_login_ip");
- entity.Property(e => e.Mobile)
- .HasMaxLength(15)
- .HasComment("手机号")
- .HasColumnName("mobile");
- entity.Property(e => e.Nickname)
- .HasMaxLength(255)
- .HasComment("昵称")
- .HasColumnName("nickname");
+ .HasComment("主键ID");
+ entity.Property(e => e.Uid)
+ .HasMaxLength(6)
+ .HasComment("用户唯一标识");
entity.Property(e => e.OpenId)
+ .HasMaxLength(64)
+ .HasComment("微信openid");
+ entity.Property(e => e.UnionId)
+ .HasMaxLength(64)
+ .HasComment("微信unionid");
+ entity.Property(e => e.GzhOpenId)
+ .HasMaxLength(64)
+ .HasComment("公众号openid");
+ entity.Property(e => e.Phone)
+ .HasMaxLength(20)
+ .HasComment("手机号");
+ entity.Property(e => e.Nickname)
.HasMaxLength(50)
- .HasComment("微信openid")
- .HasColumnName("open_id");
- entity.Property(e => e.Password)
- .HasMaxLength(40)
- .HasComment("密码")
- .HasColumnName("password");
- entity.Property(e => e.Pid)
- .HasComment("推荐人ID")
- .HasColumnName("pid");
+ .HasComment("昵称");
+ entity.Property(e => e.Avatar)
+ .HasMaxLength(500)
+ .HasComment("头像URL");
entity.Property(e => e.UserLevel)
.HasDefaultValue(1)
- .HasComment("用户等级:1普通用户 2合伙人 3渠道合伙人")
- .HasColumnName("user_level");
+ .HasComment("用户等级:1普通用户 2合伙人 3渠道合伙人");
+ entity.Property(e => e.ParentUserId)
+ .HasComment("推荐人用户ID");
entity.Property(e => e.InviteCode)
.HasMaxLength(10)
- .HasComment("用户专属邀请码")
- .HasColumnName("invite_code");
+ .HasComment("用户专属邀请码");
entity.Property(e => e.Balance)
.HasDefaultValue(0m)
.HasComment("可提现余额")
- .HasColumnType("decimal(10, 2)")
- .HasColumnName("balance");
+ .HasColumnType("decimal(10, 2)");
entity.Property(e => e.TotalIncome)
.HasDefaultValue(0m)
.HasComment("累计收益")
- .HasColumnType("decimal(10, 2)")
- .HasColumnName("total_income");
+ .HasColumnType("decimal(10, 2)");
entity.Property(e => e.WithdrawnAmount)
.HasDefaultValue(0m)
.HasComment("已提现金额")
- .HasColumnType("decimal(10, 2)")
- .HasColumnName("withdrawn_amount");
+ .HasColumnType("decimal(10, 2)");
entity.Property(e => e.Status)
- .HasDefaultValue((byte)1)
- .HasComment("状态: 1正常 0禁用")
- .HasColumnName("status");
- entity.Property(e => e.Uid)
- .HasMaxLength(16)
- .HasComment("用户唯一标识")
- .HasColumnName("uid");
- entity.Property(e => e.UnionId)
- .HasMaxLength(255)
- .HasComment("微信unionid")
- .HasColumnName("union_id");
- entity.Property(e => e.UpdatedAt)
- .HasDefaultValueSql("(getdate())")
- .HasComment("更新时间")
- .HasColumnName("updated_at");
- });
-
- modelBuilder.Entity(entity =>
- {
- entity.HasKey(e => e.Id).HasName("pk_user_details");
-
- entity.ToTable("user_details", tb => tb.HasComment("用户详情扩展表,用于存储业务扩展字段(余额、积分、等级等)"));
-
- entity.HasIndex(e => e.UserId, "uk_user_details_user_id").IsUnique();
-
- entity.Property(e => e.Id)
- .HasComment("主键ID")
- .HasColumnName("id");
- entity.Property(e => e.UserId)
- .HasComment("用户ID(唯一)")
- .HasColumnName("user_id");
- entity.Property(e => e.CreatedAt)
- .HasDefaultValueSql("(getdate())")
- .HasComment("创建时间")
- .HasColumnName("created_at");
- entity.Property(e => e.UpdatedAt)
- .HasDefaultValueSql("(getdate())")
- .HasComment("更新时间")
- .HasColumnName("updated_at");
-
- // 配置与 User 的一对一关系
- entity.HasOne(e => e.User)
- .WithOne(u => u.UserDetail)
- .HasForeignKey(e => e.UserId)
- .OnDelete(DeleteBehavior.Cascade)
- .HasConstraintName("fk_user_details_users");
- });
-
- modelBuilder.Entity(entity =>
- {
- entity.HasKey(e => e.Id).HasName("pk_user_addresses");
-
- entity.ToTable("user_addresses", tb => tb.HasComment("用户收货地址表,存储用户的收货地址信息"));
-
- entity.HasIndex(e => new { e.UserId, e.IsDefault }, "ix_user_addresses_is_default").HasFilter("([is_deleted]=(0))");
-
- entity.HasIndex(e => e.UserId, "ix_user_addresses_user_id");
-
- entity.Property(e => e.Id)
- .HasComment("主键ID")
- .HasColumnName("id");
- entity.Property(e => e.CreatedAt)
- .HasDefaultValueSql("(getdate())")
- .HasComment("创建时间")
- .HasColumnName("created_at");
- entity.Property(e => e.DetailedAddress)
- .HasMaxLength(255)
- .HasComment("详细地址")
- .HasColumnName("detailed_address");
- entity.Property(e => e.IsDefault)
- .HasDefaultValue((byte)0)
- .HasComment("是否默认地址: 0否 1是")
- .HasColumnName("is_default");
- entity.Property(e => e.IsDeleted)
- .HasDefaultValue((byte)0)
- .HasComment("是否删除: 0否 1是")
- .HasColumnName("is_deleted");
- entity.Property(e => e.ReceiverName)
+ .HasDefaultValue(1)
+ .HasComment("状态: 1正常 0禁用");
+ entity.Property(e => e.IsTest)
+ .HasComment("是否测试账号: 0否 1是");
+ entity.Property(e => e.LastLoginTime)
+ .HasComment("最后登录时间");
+ entity.Property(e => e.LastLoginIp)
.HasMaxLength(50)
- .HasComment("收货人姓名")
- .HasColumnName("receiver_name");
- entity.Property(e => e.ReceiverPhone)
- .HasMaxLength(20)
- .HasComment("收货人电话")
- .HasColumnName("receiver_phone");
- entity.Property(e => e.UpdatedAt)
+ .HasComment("最后登录IP");
+ entity.Property(e => e.CreateTime)
.HasDefaultValueSql("(getdate())")
- .HasComment("更新时间")
- .HasColumnName("updated_at");
- entity.Property(e => e.UserId)
- .HasComment("用户ID")
- .HasColumnName("user_id");
+ .HasComment("创建时间");
+ entity.Property(e => e.UpdateTime)
+ .HasDefaultValueSql("(getdate())")
+ .HasComment("更新时间");
+ entity.Property(e => e.IsDeleted)
+ .HasDefaultValue(false)
+ .HasComment("软删除标记");
});
modelBuilder.Entity(entity =>
@@ -403,37 +158,28 @@ public partial class MiAssessmentDbContext : DbContext
entity.HasIndex(e => e.ExpiresAt, "ix_user_refresh_tokens_expires_at");
entity.Property(e => e.Id)
- .HasComment("主键ID")
- .HasColumnName("id");
+ .HasComment("主键ID");
entity.Property(e => e.UserId)
- .HasComment("用户ID")
- .HasColumnName("user_id");
+ .HasComment("用户ID");
entity.Property(e => e.TokenHash)
.HasMaxLength(256)
- .HasComment("Token 哈希值(SHA256)")
- .HasColumnName("token_hash");
+ .HasComment("Token 哈希值(SHA256)");
entity.Property(e => e.ExpiresAt)
- .HasComment("过期时间")
- .HasColumnName("expires_at");
+ .HasComment("过期时间");
entity.Property(e => e.CreatedAt)
.HasDefaultValueSql("(getdate())")
- .HasComment("创建时间")
- .HasColumnName("created_at");
+ .HasComment("创建时间");
entity.Property(e => e.CreatedByIp)
.HasMaxLength(50)
- .HasComment("创建时的 IP 地址")
- .HasColumnName("created_by_ip");
+ .HasComment("创建时的 IP 地址");
entity.Property(e => e.RevokedAt)
- .HasComment("撤销时间")
- .HasColumnName("revoked_at");
+ .HasComment("撤销时间");
entity.Property(e => e.RevokedByIp)
.HasMaxLength(50)
- .HasComment("撤销时的 IP 地址")
- .HasColumnName("revoked_by_ip");
+ .HasComment("撤销时的 IP 地址");
entity.Property(e => e.ReplacedByToken)
.HasMaxLength(256)
- .HasComment("被替换的新 Token 哈希值")
- .HasColumnName("replaced_by_token");
+ .HasComment("被替换的新 Token 哈希值");
entity.HasOne(e => e.User)
.WithMany()
@@ -446,54 +192,35 @@ public partial class MiAssessmentDbContext : DbContext
{
entity.HasKey(e => e.Id).HasName("pk_user_login_logs");
- entity.ToTable("user_login_logs", tb => tb.HasComment("用户登录日志表,记录用户每次登录的时间、设备和位置信息"));
-
- entity.HasIndex(e => e.LoginDate, "ix_user_login_logs_login_date");
-
- entity.HasIndex(e => e.LoginTime, "ix_user_login_logs_login_time");
+ entity.ToTable("user_login_logs", tb => tb.HasComment("用户登录日志表,记录用户每次登录信息"));
entity.HasIndex(e => e.UserId, "ix_user_login_logs_user_id");
- entity.HasIndex(e => e.Year, "ix_user_login_logs_year");
-
- entity.HasIndex(e => new { e.Year, e.Month }, "ix_user_login_logs_year_month");
-
entity.Property(e => e.Id)
- .HasComment("主键ID")
- .HasColumnName("id");
- entity.Property(e => e.Device)
- .HasMaxLength(50)
- .HasComment("设备类型")
- .HasColumnName("device");
- entity.Property(e => e.Ip)
- .HasMaxLength(50)
- .HasComment("登录IP")
- .HasColumnName("ip");
- entity.Property(e => e.LastLoginTime)
- .HasComment("最后登录时间")
- .HasColumnName("last_login_time");
- entity.Property(e => e.Location)
- .HasMaxLength(100)
- .HasComment("登录位置")
- .HasColumnName("location");
- entity.Property(e => e.LoginDate)
- .HasComment("登录日期")
- .HasColumnName("login_date");
- entity.Property(e => e.LoginTime)
- .HasComment("登录时间")
- .HasColumnName("login_time");
- entity.Property(e => e.Month)
- .HasComment("月份")
- .HasColumnName("month");
+ .HasComment("主键ID");
entity.Property(e => e.UserId)
- .HasComment("用户ID")
- .HasColumnName("user_id");
- entity.Property(e => e.Week)
- .HasComment("周数")
- .HasColumnName("week");
- entity.Property(e => e.Year)
- .HasComment("年份")
- .HasColumnName("year");
+ .HasComment("用户ID");
+ entity.Property(e => e.LoginType)
+ .HasMaxLength(20)
+ .HasComment("登录类型");
+ entity.Property(e => e.LoginIp)
+ .HasMaxLength(50)
+ .HasComment("登录IP");
+ entity.Property(e => e.UserAgent)
+ .HasMaxLength(500)
+ .HasComment("用户代理");
+ entity.Property(e => e.Platform)
+ .HasMaxLength(20)
+ .HasComment("平台");
+ entity.Property(e => e.Status)
+ .HasDefaultValue(1)
+ .HasComment("状态:1成功 0失败");
+ entity.Property(e => e.FailReason)
+ .HasMaxLength(200)
+ .HasComment("失败原因");
+ entity.Property(e => e.CreateTime)
+ .HasDefaultValueSql("(getdate())")
+ .HasComment("创建时间");
});
// ==================== 系统基础表配置 ====================
@@ -501,22 +228,36 @@ public partial class MiAssessmentDbContext : DbContext
{
entity.HasKey(e => e.Id).HasName("pk_configs");
- entity.ToTable("configs", tb => tb.HasComment("系统配置表,存储系统各项配置信息"));
+ entity.ToTable("configs", tb => tb.HasComment("业务配置表,存储业务相关配置信息"));
entity.HasIndex(e => e.ConfigKey, "ix_configs_key");
entity.HasIndex(e => e.ConfigKey, "uk_configs_key").IsUnique();
entity.Property(e => e.Id)
- .HasComment("主键ID")
- .HasColumnName("id");
+ .HasComment("主键ID");
entity.Property(e => e.ConfigKey)
- .HasMaxLength(255)
- .HasComment("配置键名")
- .HasColumnName("config_key");
+ .HasMaxLength(100)
+ .HasComment("配置键名");
entity.Property(e => e.ConfigValue)
- .HasComment("配置值(JSON格式)")
- .HasColumnName("config_value");
+ .HasComment("配置值(JSON格式)");
+ entity.Property(e => e.ConfigType)
+ .HasMaxLength(50)
+ .HasComment("配置类型");
+ entity.Property(e => e.Description)
+ .HasMaxLength(500)
+ .HasComment("描述");
+ entity.Property(e => e.Sort)
+ .HasComment("排序");
+ entity.Property(e => e.CreateTime)
+ .HasDefaultValueSql("(getdate())")
+ .HasComment("创建时间");
+ entity.Property(e => e.UpdateTime)
+ .HasDefaultValueSql("(getdate())")
+ .HasComment("更新时间");
+ entity.Property(e => e.IsDeleted)
+ .HasDefaultValue(false)
+ .HasComment("软删除标记");
});
modelBuilder.Entity(entity =>
@@ -531,212 +272,50 @@ public partial class MiAssessmentDbContext : DbContext
entity.HasIndex(e => e.Status, "ix_order_notifies_status");
- entity.HasIndex(e => e.CreatedAt, "ix_order_notifies_created_at");
+ entity.HasIndex(e => e.CreateTime, "ix_order_notifies_created_at");
entity.Property(e => e.Id)
- .HasComment("主键ID")
- .HasColumnName("id");
+ .HasComment("主键ID");
entity.Property(e => e.OrderNo)
.HasMaxLength(64)
- .HasComment("商户订单号")
- .HasColumnName("order_no");
+ .HasComment("商户订单号");
entity.Property(e => e.TransactionId)
.HasMaxLength(64)
- .HasComment("微信支付订单号")
- .HasColumnName("transaction_id");
+ .HasComment("微信支付订单号");
entity.Property(e => e.NotifyUrl)
- .HasMaxLength(255)
- .HasComment("回调通知URL")
- .HasColumnName("notify_url");
+ .HasMaxLength(500)
+ .HasComment("回调通知URL");
entity.Property(e => e.NonceStr)
.HasMaxLength(64)
- .HasComment("随机字符串")
- .HasColumnName("nonce_str");
+ .HasComment("随机字符串");
entity.Property(e => e.PayTime)
- .HasComment("支付时间")
- .HasColumnName("pay_time");
+ .HasComment("支付时间");
entity.Property(e => e.PayAmount)
.HasComment("支付金额")
- .HasColumnType("decimal(10, 2)")
- .HasColumnName("pay_amount");
+ .HasColumnType("decimal(10, 2)");
entity.Property(e => e.Status)
- .HasDefaultValue((byte)0)
- .HasComment("处理状态:0=待处理,1=处理成功,2=处理失败")
- .HasColumnName("status");
+ .HasDefaultValue(0)
+ .HasComment("处理状态:0=待处理,1=处理成功,2=处理失败");
entity.Property(e => e.RetryCount)
.HasDefaultValue(0)
- .HasComment("重试次数")
- .HasColumnName("retry_count");
+ .HasComment("重试次数");
entity.Property(e => e.Attach)
- .HasMaxLength(128)
- .HasComment("附加数据(订单类型)")
- .HasColumnName("attach");
+ .HasMaxLength(100)
+ .HasComment("附加数据(订单类型)");
entity.Property(e => e.OpenId)
- .HasMaxLength(64)
- .HasComment("用户OpenId")
- .HasColumnName("open_id");
+ .HasMaxLength(100)
+ .HasComment("用户OpenId");
entity.Property(e => e.RawData)
- .HasComment("原始回调数据")
- .HasColumnName("raw_data");
+ .HasComment("原始回调数据");
entity.Property(e => e.ErrorMessage)
.HasMaxLength(500)
- .HasComment("错误信息")
- .HasColumnName("error_message");
- entity.Property(e => e.CreatedAt)
+ .HasComment("错误信息");
+ entity.Property(e => e.CreateTime)
.HasDefaultValueSql("(getdate())")
- .HasComment("创建时间")
- .HasColumnName("created_at");
- entity.Property(e => e.UpdatedAt)
+ .HasComment("创建时间");
+ entity.Property(e => e.UpdateTime)
.HasDefaultValueSql("(getdate())")
- .HasComment("更新时间")
- .HasColumnName("updated_at");
- });
-
- modelBuilder.Entity(entity =>
- {
- entity.HasKey(e => e.Id).HasName("pk_payment_orders");
-
- entity.ToTable("payment_orders", tb => tb.HasComment("通用支付订单表,支持多种订单类型和奖励发放机制"));
-
- entity.HasIndex(e => e.OrderNo, "uk_payment_orders_order_no").IsUnique();
-
- entity.HasIndex(e => e.UserId, "ix_payment_orders_user_id");
-
- entity.HasIndex(e => e.OrderType, "ix_payment_orders_order_type");
-
- entity.HasIndex(e => e.Status, "ix_payment_orders_status");
-
- entity.HasIndex(e => e.CreatedAt, "ix_payment_orders_created_at");
-
- entity.Property(e => e.Id)
- .HasComment("主键ID")
- .HasColumnName("id");
- entity.Property(e => e.OrderNo)
- .HasMaxLength(64)
- .HasComment("订单号(唯一)")
- .HasColumnName("order_no");
- entity.Property(e => e.UserId)
- .HasComment("用户ID")
- .HasColumnName("user_id");
- entity.Property(e => e.OrderType)
- .HasMaxLength(50)
- .HasComment("订单类型(如:diamond_recharge, vip_purchase 等)")
- .HasColumnName("order_type");
- entity.Property(e => e.Title)
- .HasMaxLength(100)
- .HasComment("订单标题")
- .HasColumnName("title");
- entity.Property(e => e.Amount)
- .HasComment("订单金额(单位:元)")
- .HasColumnType("decimal(10, 2)")
- .HasColumnName("amount");
- entity.Property(e => e.PayAmount)
- .HasComment("实付金额(单位:元)")
- .HasColumnType("decimal(10, 2)")
- .HasColumnName("pay_amount");
- entity.Property(e => e.PayMethod)
- .HasMaxLength(20)
- .HasComment("支付方式(如:wechat, alipay 等)")
- .HasColumnName("pay_method");
- entity.Property(e => e.Status)
- .HasDefaultValue((byte)0)
- .HasComment("状态:0-待支付 1-已支付 2-已取消 3-已退款")
- .HasColumnName("status");
- entity.Property(e => e.PaidAt)
- .HasComment("支付时间")
- .HasColumnName("paid_at");
- entity.Property(e => e.TransactionId)
- .HasMaxLength(64)
- .HasComment("第三方交易号")
- .HasColumnName("transaction_id");
- entity.Property(e => e.BizId)
- .HasComment("业务关联ID")
- .HasColumnName("biz_id");
- entity.Property(e => e.BizData)
- .HasComment("业务扩展数据(JSON格式)")
- .HasColumnName("biz_data");
- entity.Property(e => e.RewardStatus)
- .HasDefaultValue((byte)0)
- .HasComment("奖励状态:0-未发放 1-已发放 2-发放失败")
- .HasColumnName("reward_status");
- entity.Property(e => e.RewardData)
- .HasComment("奖励数据(JSON格式)")
- .HasColumnName("reward_data");
- entity.Property(e => e.RewardAt)
- .HasComment("奖励发放时间")
- .HasColumnName("reward_at");
- entity.Property(e => e.CreatedAt)
- .HasDefaultValueSql("(getdate())")
- .HasComment("创建时间")
- .HasColumnName("created_at");
- entity.Property(e => e.UpdatedAt)
- .HasDefaultValueSql("(getdate())")
- .HasComment("更新时间")
- .HasColumnName("updated_at");
-
- // 配置与 User 的关系
- entity.HasOne(e => e.User)
- .WithMany()
- .HasForeignKey(e => e.UserId)
- .OnDelete(DeleteBehavior.Restrict)
- .HasConstraintName("fk_payment_orders_users");
- });
-
- modelBuilder.Entity(entity =>
- {
- entity.HasKey(e => e.Id).HasName("pk_pictures");
-
- entity.ToTable("pictures", tb => tb.HasComment("图片管理表,存储上传的图片信息"));
-
- entity.HasIndex(e => e.Status, "ix_pictures_status");
-
- entity.HasIndex(e => e.Token, "ix_pictures_token");
-
- entity.HasIndex(e => e.Type, "ix_pictures_type");
-
- entity.Property(e => e.Id)
- .HasComment("主键ID")
- .HasColumnName("id");
- entity.Property(e => e.CreatedAt)
- .HasDefaultValueSql("(getdate())")
- .HasComment("创建时间")
- .HasColumnName("created_at");
- entity.Property(e => e.ImgUrl)
- .HasMaxLength(255)
- .HasComment("图片URL地址")
- .HasColumnName("img_url");
- entity.Property(e => e.Status)
- .HasDefaultValue((byte)1)
- .HasComment("状态:1-正常")
- .HasColumnName("status");
- entity.Property(e => e.Token)
- .HasMaxLength(255)
- .HasComment("图片令牌/标识")
- .HasColumnName("token");
- entity.Property(e => e.Type)
- .HasComment("图片类型")
- .HasColumnName("type");
- });
-
- modelBuilder.Entity(entity =>
- {
- entity.HasKey(e => e.Id).HasName("pk_deliveries");
-
- entity.ToTable("deliveries", tb => tb.HasComment("快递公司配置表,存储快递公司信息"));
-
- entity.HasIndex(e => e.Code, "ix_deliveries_code");
-
- entity.Property(e => e.Id)
- .HasComment("主键ID")
- .HasColumnName("id");
- entity.Property(e => e.Code)
- .HasMaxLength(30)
- .HasComment("快递公司编码")
- .HasColumnName("code");
- entity.Property(e => e.Name)
- .HasMaxLength(50)
- .HasComment("快递公司名称")
- .HasColumnName("name");
+ .HasComment("更新时间");
});
// ==================== 小程序业务表配置 ====================
diff --git a/server/MiAssessment/src/MiAssessment.Model/Entities/Admin.cs b/server/MiAssessment/src/MiAssessment.Model/Entities/Admin.cs
deleted file mode 100644
index b1a107b..0000000
--- a/server/MiAssessment/src/MiAssessment.Model/Entities/Admin.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace MiAssessment.Model.Entities;
-
-///
-/// 管理员表,存储后台管理员信息
-///
-public partial class Admin
-{
- ///
- /// 主键ID
- ///
- public int Id { get; set; }
-
- ///
- /// 用户名
- ///
- public string? Username { get; set; }
-
- ///
- /// 昵称
- ///
- public string Nickname { get; set; } = null!;
-
- ///
- /// 密码(加密)
- ///
- public string? Password { get; set; }
-
- ///
- /// 权限组ID
- ///
- public int? Qid { get; set; }
-
- ///
- /// 状态:0-正常
- ///
- public int? Status { get; set; }
-
- ///
- /// 获取时间
- ///
- public DateTime GetTime { get; set; }
-
- ///
- /// 随机字符串
- ///
- public string Random { get; set; } = null!;
-
- ///
- /// 登录令牌
- ///
- public string? Token { get; set; }
-
- ///
- /// 上级管理员ID
- ///
- public int AdminId { get; set; }
-
- ///
- /// 创建时间
- ///
- public DateTime CreatedAt { get; set; }
-
- ///
- /// 更新时间
- ///
- public DateTime UpdatedAt { get; set; }
-}
diff --git a/server/MiAssessment/src/MiAssessment.Model/Entities/AdminLoginLog.cs b/server/MiAssessment/src/MiAssessment.Model/Entities/AdminLoginLog.cs
deleted file mode 100644
index 8922aab..0000000
--- a/server/MiAssessment/src/MiAssessment.Model/Entities/AdminLoginLog.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace MiAssessment.Model.Entities;
-
-///
-/// 管理员登录日志表,记录管理员登录信息(仅结构,不迁移历史数据)
-///
-public partial class AdminLoginLog
-{
- ///
- /// 主键ID
- ///
- public int Id { get; set; }
-
- ///
- /// 管理员ID
- ///
- public int AdminId { get; set; }
-
- ///
- /// 登录IP地址
- ///
- public string Ip { get; set; } = null!;
-
- ///
- /// 登录时间
- ///
- public DateTime CreatedAt { get; set; }
-}
diff --git a/server/MiAssessment/src/MiAssessment.Model/Entities/AdminOperationLog.cs b/server/MiAssessment/src/MiAssessment.Model/Entities/AdminOperationLog.cs
deleted file mode 100644
index a11c571..0000000
--- a/server/MiAssessment/src/MiAssessment.Model/Entities/AdminOperationLog.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace MiAssessment.Model.Entities;
-
-///
-/// 管理员操作日志表,记录管理员操作信息(仅结构,不迁移历史数据)
-///
-public partial class AdminOperationLog
-{
- ///
- /// 主键ID
- ///
- public int Id { get; set; }
-
- ///
- /// 管理员ID
- ///
- public int AdminId { get; set; }
-
- ///
- /// 操作IP地址
- ///
- public string Ip { get; set; } = null!;
-
- ///
- /// 操作名称
- ///
- public string? Operation { get; set; }
-
- ///
- /// 操作内容详情
- ///
- public string? Content { get; set; }
-
- ///
- /// 操作时间
- ///
- public DateTime CreatedAt { get; set; }
-}
diff --git a/server/MiAssessment/src/MiAssessment.Model/Entities/Config.cs b/server/MiAssessment/src/MiAssessment.Model/Entities/Config.cs
index d987bbf..6504dc9 100644
--- a/server/MiAssessment/src/MiAssessment.Model/Entities/Config.cs
+++ b/server/MiAssessment/src/MiAssessment.Model/Entities/Config.cs
@@ -1,25 +1,64 @@
using System;
-using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
namespace MiAssessment.Model.Entities;
///
-/// 系统配置表,存储系统各项配置信息
+/// 业务配置表,存储业务相关配置信息
///
-public partial class Config
+[Table("configs")]
+public class Config
{
///
/// 主键ID
///
- public int Id { get; set; }
+ [Key]
+ public long Id { get; set; }
///
/// 配置键名
///
+ [Required]
+ [MaxLength(100)]
public string ConfigKey { get; set; } = null!;
///
/// 配置值(JSON格式)
///
- public string? ConfigValue { get; set; }
+ [Required]
+ public string ConfigValue { get; set; } = null!;
+
+ ///
+ /// 配置类型
+ ///
+ [Required]
+ [MaxLength(50)]
+ public string ConfigType { get; set; } = null!;
+
+ ///
+ /// 描述
+ ///
+ [MaxLength(500)]
+ public string? Description { get; set; }
+
+ ///
+ /// 排序
+ ///
+ public int Sort { get; set; }
+
+ ///
+ /// 创建时间
+ ///
+ public DateTime CreateTime { get; set; }
+
+ ///
+ /// 更新时间
+ ///
+ public DateTime UpdateTime { get; set; }
+
+ ///
+ /// 软删除标记
+ ///
+ public bool IsDeleted { get; set; }
}
diff --git a/server/MiAssessment/src/MiAssessment.Model/Entities/Delivery.cs b/server/MiAssessment/src/MiAssessment.Model/Entities/Delivery.cs
deleted file mode 100644
index 8282ee5..0000000
--- a/server/MiAssessment/src/MiAssessment.Model/Entities/Delivery.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace MiAssessment.Model.Entities;
-
-///
-/// 快递公司配置表,存储快递公司信息
-///
-public partial class Delivery
-{
- ///
- /// 主键ID
- ///
- public short Id { get; set; }
-
- ///
- /// 快递公司名称
- ///
- public string Name { get; set; } = null!;
-
- ///
- /// 快递公司编码
- ///
- public string Code { get; set; } = null!;
-}
diff --git a/server/MiAssessment/src/MiAssessment.Model/Entities/OrderNotify.cs b/server/MiAssessment/src/MiAssessment.Model/Entities/OrderNotify.cs
index 420e46f..d83fdd3 100644
--- a/server/MiAssessment/src/MiAssessment.Model/Entities/OrderNotify.cs
+++ b/server/MiAssessment/src/MiAssessment.Model/Entities/OrderNotify.cs
@@ -1,35 +1,44 @@
using System;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
namespace MiAssessment.Model.Entities;
///
/// 支付通知记录表,记录微信支付回调通知
///
-public partial class OrderNotify
+[Table("order_notifies")]
+public class OrderNotify
{
///
/// 主键ID
///
- public int Id { get; set; }
+ [Key]
+ public long Id { get; set; }
///
/// 商户订单号
///
+ [Required]
+ [MaxLength(64)]
public string OrderNo { get; set; } = null!;
///
/// 微信支付订单号
///
+ [MaxLength(64)]
public string? TransactionId { get; set; }
///
/// 回调通知URL
///
+ [MaxLength(500)]
public string? NotifyUrl { get; set; }
///
/// 随机字符串
///
+ [MaxLength(64)]
public string? NonceStr { get; set; }
///
@@ -45,7 +54,7 @@ public partial class OrderNotify
///
/// 处理状态:0=待处理,1=处理成功,2=处理失败
///
- public byte Status { get; set; }
+ public int Status { get; set; }
///
/// 重试次数
@@ -55,11 +64,13 @@ public partial class OrderNotify
///
/// 附加数据(订单类型)
///
+ [MaxLength(100)]
public string? Attach { get; set; }
///
/// 用户OpenId
///
+ [MaxLength(100)]
public string? OpenId { get; set; }
///
@@ -70,20 +81,16 @@ public partial class OrderNotify
///
/// 错误信息
///
+ [MaxLength(500)]
public string? ErrorMessage { get; set; }
- ///
- /// 扩展数据(JSON格式)
- ///
- public string? Extend { get; set; }
-
///
/// 创建时间
///
- public DateTime CreatedAt { get; set; }
+ public DateTime CreateTime { get; set; }
///
/// 更新时间
///
- public DateTime UpdatedAt { get; set; }
+ public DateTime UpdateTime { get; set; }
}
diff --git a/server/MiAssessment/src/MiAssessment.Model/Entities/PaymentOrder.cs b/server/MiAssessment/src/MiAssessment.Model/Entities/PaymentOrder.cs
deleted file mode 100644
index fd56e9c..0000000
--- a/server/MiAssessment/src/MiAssessment.Model/Entities/PaymentOrder.cs
+++ /dev/null
@@ -1,106 +0,0 @@
-using System;
-
-namespace MiAssessment.Model.Entities;
-
-///
-/// 通用支付订单表,支持多种订单类型和奖励发放机制
-///
-public partial class PaymentOrder
-{
- ///
- /// 主键ID
- ///
- public int Id { get; set; }
-
- ///
- /// 订单号(唯一)
- ///
- public string OrderNo { get; set; } = null!;
-
- ///
- /// 用户ID
- ///
- public int UserId { get; set; }
-
- ///
- /// 订单类型(如:diamond_recharge, vip_purchase 等)
- ///
- public string OrderType { get; set; } = null!;
-
- ///
- /// 订单标题
- ///
- public string Title { get; set; } = null!;
-
- ///
- /// 订单金额(单位:元)
- ///
- public decimal Amount { get; set; }
-
- ///
- /// 实付金额(单位:元)
- ///
- public decimal PayAmount { get; set; }
-
- ///
- /// 支付方式(如:wechat, alipay 等)
- ///
- public string? PayMethod { get; set; }
-
- ///
- /// 状态:0-待支付 1-已支付 2-已取消 3-已退款
- ///
- public byte Status { get; set; }
-
- ///
- /// 支付时间
- ///
- public DateTime? PaidAt { get; set; }
-
- ///
- /// 第三方交易号
- ///
- public string? TransactionId { get; set; }
-
- ///
- /// 业务关联ID
- ///
- public int? BizId { get; set; }
-
- ///
- /// 业务扩展数据(JSON格式)
- ///
- public string? BizData { get; set; }
-
- ///
- /// 奖励状态:0-未发放 1-已发放 2-发放失败
- ///
- public byte RewardStatus { get; set; }
-
- ///
- /// 奖励数据(JSON格式)
- ///
- public string? RewardData { get; set; }
-
- ///
- /// 奖励发放时间
- ///
- public DateTime? RewardAt { get; set; }
-
- ///
- /// 创建时间
- ///
- public DateTime CreatedAt { get; set; }
-
- ///
- /// 更新时间
- ///
- public DateTime UpdatedAt { get; set; }
-
- // ==================== 导航属性 ====================
-
- ///
- /// 关联的用户
- ///
- public virtual User? User { get; set; }
-}
diff --git a/server/MiAssessment/src/MiAssessment.Model/Entities/Picture.cs b/server/MiAssessment/src/MiAssessment.Model/Entities/Picture.cs
deleted file mode 100644
index 0ba363e..0000000
--- a/server/MiAssessment/src/MiAssessment.Model/Entities/Picture.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace MiAssessment.Model.Entities;
-
-///
-/// 图片管理表,存储上传的图片信息
-///
-public partial class Picture
-{
- ///
- /// 主键ID
- ///
- public int Id { get; set; }
-
- ///
- /// 图片URL地址
- ///
- public string ImgUrl { get; set; } = null!;
-
- ///
- /// 图片令牌/标识
- ///
- public string Token { get; set; } = null!;
-
- ///
- /// 创建时间
- ///
- public DateTime CreatedAt { get; set; }
-
- ///
- /// 状态:1-正常
- ///
- public byte Status { get; set; }
-
- ///
- /// 图片类型
- ///
- public byte? Type { get; set; }
-}
diff --git a/server/MiAssessment/src/MiAssessment.Model/Entities/User.cs b/server/MiAssessment/src/MiAssessment.Model/Entities/User.cs
index a0c58a6..02aaba7 100644
--- a/server/MiAssessment/src/MiAssessment.Model/Entities/User.cs
+++ b/server/MiAssessment/src/MiAssessment.Model/Entities/User.cs
@@ -1,73 +1,79 @@
using System;
-using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace MiAssessment.Model.Entities;
///
/// 用户主表,存储用户基本信息
-/// 精简版:只保留核心字段,业务字段移至 UserDetail 扩展表
///
+[Table("users")]
public partial class User
{
///
/// 主键ID
///
+ [Key]
public int Id { get; set; }
+ ///
+ /// 用户唯一标识
+ ///
+ [Required]
+ [MaxLength(6)]
+ public string Uid { get; set; } = null!;
+
///
/// 微信openid
///
+ [Required]
+ [MaxLength(64)]
public string OpenId { get; set; } = null!;
///
/// 微信unionid
///
+ [MaxLength(64)]
public string? UnionId { get; set; }
///
/// 公众号openid
///
+ [MaxLength(64)]
public string? GzhOpenId { get; set; }
- ///
- /// 用户唯一标识
- ///
- public string Uid { get; set; } = null!;
-
///
/// 手机号
///
- public string? Mobile { get; set; }
+ [MaxLength(20)]
+ public string? Phone { get; set; }
///
/// 昵称
///
- public string Nickname { get; set; } = null!;
+ [MaxLength(50)]
+ public string? Nickname { get; set; }
///
/// 头像URL
///
- public string HeadImg { get; set; } = null!;
-
- ///
- /// 密码
- ///
- public string? Password { get; set; }
-
- ///
- /// 推荐人ID
- ///
- public int Pid { get; set; }
+ [MaxLength(500)]
+ public string? Avatar { get; set; }
///
/// 用户等级:1普通用户 2合伙人 3渠道合伙人
///
public int UserLevel { get; set; } = 1;
+ ///
+ /// 推荐人用户ID
+ ///
+ public int? ParentUserId { get; set; }
+
///
/// 用户专属邀请码
///
+ [MaxLength(10)]
public string? InviteCode { get; set; }
///
@@ -91,23 +97,13 @@ public partial class User
///
/// 状态: 1正常 0禁用
///
- public byte Status { get; set; }
+ public int Status { get; set; }
///
/// 是否测试账号: 0否 1是
///
public int IsTest { get; set; }
- ///
- /// 创建时间
- ///
- public DateTime CreatedAt { get; set; }
-
- ///
- /// 更新时间
- ///
- public DateTime UpdatedAt { get; set; }
-
///
/// 最后登录时间
///
@@ -116,12 +112,22 @@ public partial class User
///
/// 最后登录IP
///
+ [MaxLength(50)]
public string? LastLoginIp { get; set; }
- // ==================== 导航属性 ====================
+ ///
+ /// 创建时间
+ ///
+ public DateTime CreateTime { get; set; }
///
- /// 用户详情(一对一关联)
+ /// 更新时间
///
- public virtual UserDetail? UserDetail { get; set; }
+ public DateTime UpdateTime { get; set; }
+
+ ///
+ /// 软删除标记
+ ///
+ public bool IsDeleted { get; set; }
+
}
diff --git a/server/MiAssessment/src/MiAssessment.Model/Entities/UserAddress.cs b/server/MiAssessment/src/MiAssessment.Model/Entities/UserAddress.cs
deleted file mode 100644
index cc0b9f8..0000000
--- a/server/MiAssessment/src/MiAssessment.Model/Entities/UserAddress.cs
+++ /dev/null
@@ -1,55 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace MiAssessment.Model.Entities;
-
-///
-/// 用户收货地址表,存储用户的收货地址信息
-///
-public partial class UserAddress
-{
- ///
- /// 主键ID
- ///
- public int Id { get; set; }
-
- ///
- /// 用户ID
- ///
- public int UserId { get; set; }
-
- ///
- /// 收货人姓名
- ///
- public string ReceiverName { get; set; } = null!;
-
- ///
- /// 收货人电话
- ///
- public string ReceiverPhone { get; set; } = null!;
-
- ///
- /// 详细地址
- ///
- public string DetailedAddress { get; set; } = null!;
-
- ///
- /// 是否默认地址: 0否 1是
- ///
- public byte? IsDefault { get; set; }
-
- ///
- /// 是否删除: 0否 1是
- ///
- public byte? IsDeleted { get; set; }
-
- ///
- /// 创建时间
- ///
- public DateTime CreatedAt { get; set; }
-
- ///
- /// 更新时间
- ///
- public DateTime UpdatedAt { get; set; }
-}
diff --git a/server/MiAssessment/src/MiAssessment.Model/Entities/UserDetail.cs b/server/MiAssessment/src/MiAssessment.Model/Entities/UserDetail.cs
deleted file mode 100644
index 02b07c5..0000000
--- a/server/MiAssessment/src/MiAssessment.Model/Entities/UserDetail.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-using System;
-
-namespace MiAssessment.Model.Entities;
-
-///
-/// 用户详情扩展表,用于存储业务扩展字段
-/// 与 User 表一对一关联,按需添加余额、积分、等级等业务字段
-///
-public partial class UserDetail
-{
- ///
- /// 主键ID
- ///
- public int Id { get; set; }
-
- ///
- /// 用户ID(唯一,与 User 表一对一关联)
- ///
- public int UserId { get; set; }
-
- ///
- /// 创建时间
- ///
- public DateTime CreatedAt { get; set; }
-
- ///
- /// 更新时间
- ///
- public DateTime UpdatedAt { get; set; }
-
- // ==================== 导航属性 ====================
-
- ///
- /// 关联的用户
- ///
- public virtual User User { get; set; } = null!;
-}
diff --git a/server/MiAssessment/src/MiAssessment.Model/Entities/UserLoginLog.cs b/server/MiAssessment/src/MiAssessment.Model/Entities/UserLoginLog.cs
index c2e9cbf..56e614e 100644
--- a/server/MiAssessment/src/MiAssessment.Model/Entities/UserLoginLog.cs
+++ b/server/MiAssessment/src/MiAssessment.Model/Entities/UserLoginLog.cs
@@ -1,65 +1,64 @@
using System;
-using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
namespace MiAssessment.Model.Entities;
///
-/// 用户登录日志表,记录用户每次登录的时间、设备和位置信息
+/// 用户登录日志表,记录用户每次登录信息
///
-public partial class UserLoginLog
+[Table("user_login_logs")]
+public class UserLoginLog
{
///
/// 主键ID
///
- public int Id { get; set; }
+ [Key]
+ public long Id { get; set; }
///
/// 用户ID
///
- public int UserId { get; set; }
+ public long UserId { get; set; }
///
- /// 登录日期
+ /// 登录类型(wechat/mobile/sms等)
///
- public DateOnly LoginDate { get; set; }
-
- ///
- /// 登录时间
- ///
- public DateTime? LoginTime { get; set; }
-
- ///
- /// 最后登录时间
- ///
- public DateTime? LastLoginTime { get; set; }
-
- ///
- /// 设备类型
- ///
- public string? Device { get; set; }
+ [Required]
+ [MaxLength(20)]
+ public string LoginType { get; set; } = null!;
///
/// 登录IP
///
- public string? Ip { get; set; }
+ [MaxLength(50)]
+ public string? LoginIp { get; set; }
///
- /// 登录位置
+ /// 用户代理
///
- public string? Location { get; set; }
+ [MaxLength(500)]
+ public string? UserAgent { get; set; }
///
- /// 年份
+ /// 平台(miniprogram/h5/app等)
///
- public int Year { get; set; }
+ [MaxLength(20)]
+ public string? Platform { get; set; }
///
- /// 月份
+ /// 状态:1成功 0失败
///
- public int Month { get; set; }
+ public int Status { get; set; }
///
- /// 周数
+ /// 失败原因
///
- public int Week { get; set; }
+ [MaxLength(200)]
+ public string? FailReason { get; set; }
+
+ ///
+ /// 创建时间
+ ///
+ public DateTime CreateTime { get; set; }
}
diff --git a/server/MiAssessment/src/MiAssessment.Model/Models/Address/AddressModels.cs b/server/MiAssessment/src/MiAssessment.Model/Models/Address/AddressModels.cs
deleted file mode 100644
index b1606a0..0000000
--- a/server/MiAssessment/src/MiAssessment.Model/Models/Address/AddressModels.cs
+++ /dev/null
@@ -1,115 +0,0 @@
-namespace MiAssessment.Model.Models.Address;
-
-///
-/// 地址响应DTO
-///
-public class AddressDto
-{
- ///
- /// 地址ID
- ///
- public int Id { get; set; }
-
- ///
- /// 用户ID
- ///
- public int UserId { get; set; }
-
- ///
- /// 收货人姓名
- ///
- public string ReceiverName { get; set; } = string.Empty;
-
- ///
- /// 收货人电话
- ///
- public string ReceiverPhone { get; set; } = string.Empty;
-
- ///
- /// 详细地址
- ///
- public string DetailedAddress { get; set; } = string.Empty;
-
- ///
- /// 是否默认地址: 0否 1是
- ///
- public int IsDefault { get; set; }
-
- ///
- /// 创建时间
- ///
- public string? CreateTime { get; set; }
-
- ///
- /// 更新时间
- ///
- public string? UpdateTime { get; set; }
-}
-
-///
-/// 添加地址请求
-///
-public class AddAddressRequest
-{
- ///
- /// 收货人姓名
- ///
- public string ReceiverName { get; set; } = string.Empty;
-
- ///
- /// 收货人电话
- ///
- public string ReceiverPhone { get; set; } = string.Empty;
-
- ///
- /// 详细地址
- ///
- public string DetailedAddress { get; set; } = string.Empty;
-
- ///
- /// 是否设为默认地址: 0否 1是
- ///
- public int IsDefault { get; set; }
-}
-
-///
-/// 更新地址请求
-///
-public class UpdateAddressRequest
-{
- ///
- /// 地址ID
- ///
- public int Id { get; set; }
-
- ///
- /// 收货人姓名
- ///
- public string ReceiverName { get; set; } = string.Empty;
-
- ///
- /// 收货人电话
- ///
- public string ReceiverPhone { get; set; } = string.Empty;
-
- ///
- /// 详细地址
- ///
- public string DetailedAddress { get; set; } = string.Empty;
-
- ///
- /// 是否设为默认地址: 0否 1是
- ///
- public int? IsDefault { get; set; }
-}
-
-///
-/// 地址ID请求
-///
-public class AddressIdRequest
-{
- ///
- /// 地址ID
- ///
- public int Id { get; set; }
-}
diff --git a/server/MiAssessment/src/MiAssessment.Model/Models/Payment/CreatePaymentOrderRequest.cs b/server/MiAssessment/src/MiAssessment.Model/Models/Payment/CreatePaymentOrderRequest.cs
deleted file mode 100644
index 0c907f1..0000000
--- a/server/MiAssessment/src/MiAssessment.Model/Models/Payment/CreatePaymentOrderRequest.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-namespace MiAssessment.Model.Models.Payment;
-
-///
-/// 创建支付订单请求
-///
-public class CreatePaymentOrderRequest
-{
- ///
- /// 用户ID
- ///
- public int UserId { get; set; }
-
- ///
- /// 订单类型(如:diamond_recharge, vip_purchase 等)
- ///
- public string OrderType { get; set; } = string.Empty;
-
- ///
- /// 订单标题
- ///
- public string Title { get; set; } = string.Empty;
-
- ///
- /// 订单金额(单位:元)
- ///
- public decimal Amount { get; set; }
-
- ///
- /// 实付金额(单位:元),默认等于订单金额
- ///
- public decimal? PayAmount { get; set; }
-
- ///
- /// 支付方式(如:wechat, alipay 等)
- ///
- public string? PayMethod { get; set; }
-
- ///
- /// 业务关联ID
- ///
- public int? BizId { get; set; }
-
- ///
- /// 业务扩展数据(JSON格式)
- ///
- public string? BizData { get; set; }
-}
diff --git a/server/MiAssessment/src/MiAssessment.Model/Models/Payment/PaymentOrderDto.cs b/server/MiAssessment/src/MiAssessment.Model/Models/Payment/PaymentOrderDto.cs
deleted file mode 100644
index a19b8fe..0000000
--- a/server/MiAssessment/src/MiAssessment.Model/Models/Payment/PaymentOrderDto.cs
+++ /dev/null
@@ -1,120 +0,0 @@
-namespace MiAssessment.Model.Models.Payment;
-
-///
-/// 支付订单DTO
-///
-public class PaymentOrderDto
-{
- ///
- /// 主键ID
- ///
- public int Id { get; set; }
-
- ///
- /// 订单号
- ///
- public string OrderNo { get; set; } = string.Empty;
-
- ///
- /// 用户ID
- ///
- public int UserId { get; set; }
-
- ///
- /// 订单类型
- ///
- public string OrderType { get; set; } = string.Empty;
-
- ///
- /// 订单标题
- ///
- public string Title { get; set; } = string.Empty;
-
- ///
- /// 订单金额(单位:元)
- ///
- public decimal Amount { get; set; }
-
- ///
- /// 实付金额(单位:元)
- ///
- public decimal PayAmount { get; set; }
-
- ///
- /// 支付方式
- ///
- public string? PayMethod { get; set; }
-
- ///
- /// 状态:0-待支付 1-已支付 2-已取消 3-已退款
- ///
- public byte Status { get; set; }
-
- ///
- /// 状态文本
- ///
- public string StatusText => Status switch
- {
- 0 => "待支付",
- 1 => "已支付",
- 2 => "已取消",
- 3 => "已退款",
- _ => "未知"
- };
-
- ///
- /// 支付时间
- ///
- public DateTime? PaidAt { get; set; }
-
- ///
- /// 第三方交易号
- ///
- public string? TransactionId { get; set; }
-
- ///
- /// 业务关联ID
- ///
- public int? BizId { get; set; }
-
- ///
- /// 业务扩展数据(JSON格式)
- ///
- public string? BizData { get; set; }
-
- ///
- /// 奖励状态:0-未发放 1-已发放 2-发放失败
- ///
- public byte RewardStatus { get; set; }
-
- ///
- /// 奖励状态文本
- ///
- public string RewardStatusText => RewardStatus switch
- {
- 0 => "未发放",
- 1 => "已发放",
- 2 => "发放失败",
- _ => "未知"
- };
-
- ///
- /// 奖励数据(JSON格式)
- ///
- public string? RewardData { get; set; }
-
- ///
- /// 奖励发放时间
- ///
- public DateTime? RewardAt { get; set; }
-
- ///
- /// 创建时间
- ///
- public DateTime CreatedAt { get; set; }
-
- ///
- /// 更新时间
- ///
- public DateTime UpdatedAt { get; set; }
-}
diff --git a/server/MiAssessment/src/MiAssessment.Model/Models/Payment/PaymentOrderQueryRequest.cs b/server/MiAssessment/src/MiAssessment.Model/Models/Payment/PaymentOrderQueryRequest.cs
deleted file mode 100644
index 7189d73..0000000
--- a/server/MiAssessment/src/MiAssessment.Model/Models/Payment/PaymentOrderQueryRequest.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-using Microsoft.AspNetCore.Mvc;
-
-namespace MiAssessment.Model.Models.Payment;
-
-///
-/// 支付订单查询请求
-///
-public class PaymentOrderQueryRequest
-{
- ///
- /// 页码,从1开始
- ///
- [FromQuery(Name = "page")]
- public int Page { get; set; } = 1;
-
- ///
- /// 每页数量
- ///
- [FromQuery(Name = "pageSize")]
- public int PageSize { get; set; } = 10;
-
- ///
- /// 订单类型(可选)
- ///
- [FromQuery(Name = "orderType")]
- public string? OrderType { get; set; }
-
- ///
- /// 订单状态(可选):0-待支付 1-已支付 2-已取消 3-已退款
- ///
- [FromQuery(Name = "status")]
- public byte? Status { get; set; }
-
- ///
- /// 开始时间(可选)
- ///
- [FromQuery(Name = "startTime")]
- public DateTime? StartTime { get; set; }
-
- ///
- /// 结束时间(可选)
- ///
- [FromQuery(Name = "endTime")]
- public DateTime? EndTime { get; set; }
-}
diff --git a/server/MiAssessment/tests/MiAssessment.Tests/Core/PaymentOrderServicePropertyTests.cs b/server/MiAssessment/tests/MiAssessment.Tests/Core/PaymentOrderServicePropertyTests.cs
deleted file mode 100644
index fb4f815..0000000
--- a/server/MiAssessment/tests/MiAssessment.Tests/Core/PaymentOrderServicePropertyTests.cs
+++ /dev/null
@@ -1,607 +0,0 @@
-using FsCheck;
-using FsCheck.Xunit;
-using MiAssessment.Core.Interfaces;
-using MiAssessment.Core.Services;
-using MiAssessment.Model.Data;
-using MiAssessment.Model.Entities;
-using MiAssessment.Model.Models.Payment;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.Extensions.Logging;
-using Moq;
-using Xunit;
-
-namespace MiAssessment.Tests.Core;
-
-///
-/// PaymentOrderService 属性测试
-/// Feature: framework-template
-///
-/// Property 1: Payment Order Creation Integrity
-/// *For any* payment order creation request with valid user ID, order type, and amount, the created order SHALL have:
-/// - A unique order number that does not exist in the database
-/// - The order_type field correctly set to the requested type
-/// - The amount field correctly set to the requested amount
-/// - The biz_data field correctly storing the provided JSON data
-/// **Validates: Requirements 5.1, 5.2, 5.3**
-///
-/// Property 2: Payment Order State Transition
-/// *For any* payment order that receives a successful payment callback:
-/// - The status SHALL be updated from 0 (pending) to 1 (paid)
-/// - The paid_at timestamp SHALL be set
-/// - The transaction_id SHALL be recorded
-/// - The reward processing SHALL be triggered
-/// - If reward succeeds, reward_status SHALL be 1 and reward_at SHALL be set
-/// - If reward fails, reward_status SHALL be 2
-/// **Validates: Requirements 5.4, 5.5, 5.6, 5.7**
-///
-public class PaymentOrderServicePropertyTests
-{
- private readonly Mock> _mockLogger = new();
-
- ///
- /// 订单状态:待支付
- ///
- private const byte StatusPending = 0;
-
- ///
- /// 订单状态:已支付
- ///
- private const byte StatusPaid = 1;
-
- ///
- /// 奖励状态:未发放
- ///
- private const byte RewardStatusPending = 0;
-
- ///
- /// 奖励状态:已发放
- ///
- private const byte RewardStatusSuccess = 1;
-
- ///
- /// 奖励状态:发放失败
- ///
- private const byte RewardStatusFailed = 2;
-
- #region Property 1: Payment Order Creation Integrity
-
- ///
- /// Feature: framework-template, Property 1: Payment Order Creation Integrity
- ///
- /// Property 1.1: Created order has unique order number
- /// A unique order number that does not exist in the database
- ///
- /// **Validates: Requirements 5.1**
- ///
- [Property(MaxTest = 100)]
- public bool CreateOrder_ShouldGenerateUniqueOrderNo(PositiveInt userId, PositiveInt seed)
- {
- // Arrange
- using var dbContext = CreateDbContext();
- var service = CreateService(dbContext);
-
- var request1 = CreateValidRequest(userId.Get, seed.Get);
- var request2 = CreateValidRequest(userId.Get, seed.Get + 1);
-
- // Act: Create two orders
- var order1 = service.CreateOrderAsync(request1).GetAwaiter().GetResult();
- var order2 = service.CreateOrderAsync(request2).GetAwaiter().GetResult();
-
- // Assert: Order numbers should be unique
- return order1.OrderNo != order2.OrderNo;
- }
-
- ///
- /// Feature: framework-template, Property 1: Payment Order Creation Integrity
- ///
- /// Property 1.2: Created order has correct order_type
- /// The order_type field correctly set to the requested type
- ///
- /// **Validates: Requirements 5.2**
- ///
- [Property(MaxTest = 100)]
- public bool CreateOrder_ShouldSetCorrectOrderType(PositiveInt userId, NonEmptyString orderType, PositiveInt seed)
- {
- // Arrange
- using var dbContext = CreateDbContext();
- var service = CreateService(dbContext);
-
- // Generate a valid order type (alphanumeric with underscores)
- var validOrderType = GenerateValidOrderType(orderType.Get, seed.Get);
- var request = CreateValidRequest(userId.Get, seed.Get);
- request.OrderType = validOrderType;
-
- // Act
- var order = service.CreateOrderAsync(request).GetAwaiter().GetResult();
-
- // Assert: Order type should match the request
- return order.OrderType == validOrderType;
- }
-
- ///
- /// Feature: framework-template, Property 1: Payment Order Creation Integrity
- ///
- /// Property 1.3: Created order has correct amount
- /// The amount field correctly set to the requested amount
- ///
- /// **Validates: Requirements 5.3**
- ///
- [Property(MaxTest = 100)]
- public bool CreateOrder_ShouldSetCorrectAmount(PositiveInt userId, PositiveInt amountCents, PositiveInt seed)
- {
- // Arrange
- using var dbContext = CreateDbContext();
- var service = CreateService(dbContext);
-
- // Generate a valid amount (convert cents to decimal to avoid floating point issues)
- var amount = Math.Round((decimal)(amountCents.Get % 100000 + 1) / 100, 2);
- var request = CreateValidRequest(userId.Get, seed.Get);
- request.Amount = amount;
-
- // Act
- var order = service.CreateOrderAsync(request).GetAwaiter().GetResult();
-
- // Assert: Amount should match the request
- return order.Amount == amount;
- }
-
- ///
- /// Feature: framework-template, Property 1: Payment Order Creation Integrity
- ///
- /// Property 1.4: Created order has correct biz_data
- /// The biz_data field correctly storing the provided JSON data
- ///
- /// **Validates: Requirements 5.3**
- ///
- [Property(MaxTest = 100)]
- public bool CreateOrder_ShouldSetCorrectBizData(PositiveInt userId, PositiveInt seed)
- {
- // Arrange
- using var dbContext = CreateDbContext();
- var service = CreateService(dbContext);
-
- // Generate valid JSON biz_data
- var bizData = $"{{\"product_id\":{seed.Get},\"quantity\":{(seed.Get % 10) + 1}}}";
- var request = CreateValidRequest(userId.Get, seed.Get);
- request.BizData = bizData;
-
- // Act
- var order = service.CreateOrderAsync(request).GetAwaiter().GetResult();
-
- // Assert: BizData should match the request
- return order.BizData == bizData;
- }
-
- ///
- /// Feature: framework-template, Property 1: Payment Order Creation Integrity
- ///
- /// Property 1.5: Created order has initial status of pending (0)
- /// The created order should have status = 0 (pending)
- ///
- /// **Validates: Requirements 5.1**
- ///
- [Property(MaxTest = 100)]
- public bool CreateOrder_ShouldHavePendingStatus(PositiveInt userId, PositiveInt seed)
- {
- // Arrange
- using var dbContext = CreateDbContext();
- var service = CreateService(dbContext);
-
- var request = CreateValidRequest(userId.Get, seed.Get);
-
- // Act
- var order = service.CreateOrderAsync(request).GetAwaiter().GetResult();
-
- // Assert: Status should be pending (0)
- return order.Status == StatusPending;
- }
-
- ///
- /// Feature: framework-template, Property 1: Payment Order Creation Integrity
- ///
- /// Property 1.6: Created order has initial reward_status of pending (0)
- /// The created order should have reward_status = 0 (not issued)
- ///
- /// **Validates: Requirements 5.1**
- ///
- [Property(MaxTest = 100)]
- public bool CreateOrder_ShouldHavePendingRewardStatus(PositiveInt userId, PositiveInt seed)
- {
- // Arrange
- using var dbContext = CreateDbContext();
- var service = CreateService(dbContext);
-
- var request = CreateValidRequest(userId.Get, seed.Get);
-
- // Act
- var order = service.CreateOrderAsync(request).GetAwaiter().GetResult();
-
- // Assert: RewardStatus should be pending (0)
- return order.RewardStatus == RewardStatusPending;
- }
-
- ///
- /// Feature: framework-template, Property 1: Payment Order Creation Integrity
- ///
- /// Property 1.7: Order number does not exist in database before creation
- /// A unique order number that does not exist in the database
- ///
- /// **Validates: Requirements 5.1**
- ///
- [Property(MaxTest = 100)]
- public bool CreateOrder_OrderNoShouldNotExistBeforeCreation(PositiveInt userId, PositiveInt seed)
- {
- // Arrange
- using var dbContext = CreateDbContext();
- var service = CreateService(dbContext);
-
- var request = CreateValidRequest(userId.Get, seed.Get);
-
- // Act
- var order = service.CreateOrderAsync(request).GetAwaiter().GetResult();
-
- // Verify: The order number should exist exactly once in the database
- var count = dbContext.PaymentOrders.Count(o => o.OrderNo == order.OrderNo);
-
- // Assert: Should exist exactly once
- return count == 1;
- }
-
- #endregion
-
- #region Property 2: Payment Order State Transition
-
- ///
- /// Feature: framework-template, Property 2: Payment Order State Transition
- ///
- /// Property 2.1: Payment success updates status from 0 to 1
- /// The status SHALL be updated from 0 (pending) to 1 (paid)
- ///
- /// **Validates: Requirements 5.4**
- ///
- [Property(MaxTest = 100)]
- public bool HandlePaymentSuccess_ShouldUpdateStatusToPaid(PositiveInt userId, PositiveInt seed)
- {
- // Arrange
- using var dbContext = CreateDbContext();
- var service = CreateService(dbContext);
-
- var request = CreateValidRequest(userId.Get, seed.Get);
- var order = service.CreateOrderAsync(request).GetAwaiter().GetResult();
-
- var transactionId = $"TX_{seed.Get}_{DateTime.Now.Ticks}";
-
- // Act
- var result = service.HandlePaymentSuccessAsync(order.OrderNo, transactionId, order.Amount).GetAwaiter().GetResult();
-
- // Refresh the order from database
- var updatedOrder = service.GetOrderByNoAsync(order.OrderNo).GetAwaiter().GetResult();
-
- // Assert: Status should be updated to paid (1)
- return result && updatedOrder != null && updatedOrder.Status == StatusPaid;
- }
-
- ///
- /// Feature: framework-template, Property 2: Payment Order State Transition
- ///
- /// Property 2.2: Payment success sets paid_at timestamp
- /// The paid_at timestamp SHALL be set
- ///
- /// **Validates: Requirements 5.4**
- ///
- [Property(MaxTest = 100)]
- public bool HandlePaymentSuccess_ShouldSetPaidAtTimestamp(PositiveInt userId, PositiveInt seed)
- {
- // Arrange
- using var dbContext = CreateDbContext();
- var service = CreateService(dbContext);
-
- var request = CreateValidRequest(userId.Get, seed.Get);
- var order = service.CreateOrderAsync(request).GetAwaiter().GetResult();
-
- var beforePayment = DateTime.Now.AddSeconds(-1);
- var transactionId = $"TX_{seed.Get}_{DateTime.Now.Ticks}";
-
- // Act
- service.HandlePaymentSuccessAsync(order.OrderNo, transactionId, order.Amount).GetAwaiter().GetResult();
-
- // Refresh the order from database
- var updatedOrder = service.GetOrderByNoAsync(order.OrderNo).GetAwaiter().GetResult();
- var afterPayment = DateTime.Now.AddSeconds(1);
-
- // Assert: PaidAt should be set and within reasonable time range
- return updatedOrder != null &&
- updatedOrder.PaidAt.HasValue &&
- updatedOrder.PaidAt.Value >= beforePayment &&
- updatedOrder.PaidAt.Value <= afterPayment;
- }
-
- ///
- /// Feature: framework-template, Property 2: Payment Order State Transition
- ///
- /// Property 2.3: Payment success records transaction_id
- /// The transaction_id SHALL be recorded
- ///
- /// **Validates: Requirements 5.4**
- ///
- [Property(MaxTest = 100)]
- public bool HandlePaymentSuccess_ShouldRecordTransactionId(PositiveInt userId, PositiveInt seed)
- {
- // Arrange
- using var dbContext = CreateDbContext();
- var service = CreateService(dbContext);
-
- var request = CreateValidRequest(userId.Get, seed.Get);
- var order = service.CreateOrderAsync(request).GetAwaiter().GetResult();
-
- var transactionId = $"TX_{seed.Get}_{DateTime.Now.Ticks}";
-
- // Act
- service.HandlePaymentSuccessAsync(order.OrderNo, transactionId, order.Amount).GetAwaiter().GetResult();
-
- // Refresh the order from database
- var updatedOrder = service.GetOrderByNoAsync(order.OrderNo).GetAwaiter().GetResult();
-
- // Assert: TransactionId should be recorded
- return updatedOrder != null && updatedOrder.TransactionId == transactionId;
- }
-
- ///
- /// Feature: framework-template, Property 2: Payment Order State Transition
- ///
- /// Property 2.4: Payment success with successful reward handler sets reward_status to 1
- /// If reward succeeds, reward_status SHALL be 1 and reward_at SHALL be set
- ///
- /// **Validates: Requirements 5.5, 5.6**
- ///
- [Property(MaxTest = 100)]
- public bool HandlePaymentSuccess_WithSuccessfulReward_ShouldSetRewardStatusToSuccess(PositiveInt userId, PositiveInt seed)
- {
- // Arrange
- using var dbContext = CreateDbContext();
-
- var orderType = $"test_reward_success_{seed.Get % 100}";
- var rewardData = $"{{\"reward_id\":{seed.Get}}}";
-
- // Create a mock reward handler that succeeds
- var mockHandler = new Mock();
- mockHandler.Setup(h => h.OrderType).Returns(orderType);
- mockHandler.Setup(h => h.ProcessRewardAsync(It.IsAny()))
- .ReturnsAsync(RewardResult.Ok(rewardData));
-
- var service = CreateService(dbContext, new[] { mockHandler.Object });
-
- var request = CreateValidRequest(userId.Get, seed.Get);
- request.OrderType = orderType;
- var order = service.CreateOrderAsync(request).GetAwaiter().GetResult();
-
- var transactionId = $"TX_{seed.Get}_{DateTime.Now.Ticks}";
-
- // Act
- service.HandlePaymentSuccessAsync(order.OrderNo, transactionId, order.Amount).GetAwaiter().GetResult();
-
- // Refresh the order from database
- var updatedOrder = service.GetOrderByNoAsync(order.OrderNo).GetAwaiter().GetResult();
-
- // Assert: RewardStatus should be success (1) and RewardAt should be set
- return updatedOrder != null &&
- updatedOrder.RewardStatus == RewardStatusSuccess &&
- updatedOrder.RewardAt.HasValue;
- }
-
- ///
- /// Feature: framework-template, Property 2: Payment Order State Transition
- ///
- /// Property 2.5: Payment success with failed reward handler sets reward_status to 2
- /// If reward fails, reward_status SHALL be 2
- ///
- /// **Validates: Requirements 5.7**
- ///
- [Property(MaxTest = 100)]
- public bool HandlePaymentSuccess_WithFailedReward_ShouldSetRewardStatusToFailed(PositiveInt userId, PositiveInt seed)
- {
- // Arrange
- using var dbContext = CreateDbContext();
-
- var orderType = $"test_reward_fail_{seed.Get % 100}";
- var errorMessage = $"Reward processing failed for seed {seed.Get}";
-
- // Create a mock reward handler that fails
- var mockHandler = new Mock();
- mockHandler.Setup(h => h.OrderType).Returns(orderType);
- mockHandler.Setup(h => h.ProcessRewardAsync(It.IsAny()))
- .ReturnsAsync(RewardResult.Fail(errorMessage));
-
- var service = CreateService(dbContext, new[] { mockHandler.Object });
-
- var request = CreateValidRequest(userId.Get, seed.Get);
- request.OrderType = orderType;
- var order = service.CreateOrderAsync(request).GetAwaiter().GetResult();
-
- var transactionId = $"TX_{seed.Get}_{DateTime.Now.Ticks}";
-
- // Act
- service.HandlePaymentSuccessAsync(order.OrderNo, transactionId, order.Amount).GetAwaiter().GetResult();
-
- // Refresh the order from database
- var updatedOrder = service.GetOrderByNoAsync(order.OrderNo).GetAwaiter().GetResult();
-
- // Assert: RewardStatus should be failed (2)
- return updatedOrder != null && updatedOrder.RewardStatus == RewardStatusFailed;
- }
-
- ///
- /// Feature: framework-template, Property 2: Payment Order State Transition
- ///
- /// Property 2.6: Payment success triggers reward processing
- /// The reward processing SHALL be triggered
- ///
- /// **Validates: Requirements 5.5**
- ///
- [Property(MaxTest = 100)]
- public bool HandlePaymentSuccess_ShouldTriggerRewardProcessing(PositiveInt userId, PositiveInt seed)
- {
- // Arrange
- using var dbContext = CreateDbContext();
-
- var orderType = $"test_trigger_{seed.Get % 100}";
- var rewardProcessed = false;
-
- // Create a mock reward handler that tracks if it was called
- var mockHandler = new Mock();
- mockHandler.Setup(h => h.OrderType).Returns(orderType);
- mockHandler.Setup(h => h.ProcessRewardAsync(It.IsAny()))
- .Callback(() => rewardProcessed = true)
- .ReturnsAsync(RewardResult.Ok());
-
- var service = CreateService(dbContext, new[] { mockHandler.Object });
-
- var request = CreateValidRequest(userId.Get, seed.Get);
- request.OrderType = orderType;
- var order = service.CreateOrderAsync(request).GetAwaiter().GetResult();
-
- var transactionId = $"TX_{seed.Get}_{DateTime.Now.Ticks}";
-
- // Act
- service.HandlePaymentSuccessAsync(order.OrderNo, transactionId, order.Amount).GetAwaiter().GetResult();
-
- // Assert: Reward handler should have been called
- return rewardProcessed;
- }
-
- ///
- /// Feature: framework-template, Property 2: Payment Order State Transition
- ///
- /// Property 2.7: Idempotent payment success handling
- /// Processing the same payment twice should not change the order state
- ///
- /// **Validates: Requirements 5.4**
- ///
- [Property(MaxTest = 100)]
- public bool HandlePaymentSuccess_ShouldBeIdempotent(PositiveInt userId, PositiveInt seed)
- {
- // Arrange
- using var dbContext = CreateDbContext();
- var service = CreateService(dbContext);
-
- var request = CreateValidRequest(userId.Get, seed.Get);
- var order = service.CreateOrderAsync(request).GetAwaiter().GetResult();
-
- var transactionId = $"TX_{seed.Get}_{DateTime.Now.Ticks}";
-
- // Act: Process payment twice
- var result1 = service.HandlePaymentSuccessAsync(order.OrderNo, transactionId, order.Amount).GetAwaiter().GetResult();
- var result2 = service.HandlePaymentSuccessAsync(order.OrderNo, transactionId, order.Amount).GetAwaiter().GetResult();
-
- // Refresh the order from database
- var updatedOrder = service.GetOrderByNoAsync(order.OrderNo).GetAwaiter().GetResult();
-
- // Assert: Both calls should succeed and order should be in paid state
- return result1 && result2 && updatedOrder != null && updatedOrder.Status == StatusPaid;
- }
-
- ///
- /// Feature: framework-template, Property 2: Payment Order State Transition
- ///
- /// Property 2.8: Successful reward stores reward_data
- /// If reward succeeds, reward_data SHALL contain the reward information
- ///
- /// **Validates: Requirements 5.6**
- ///
- [Property(MaxTest = 100)]
- public bool HandlePaymentSuccess_WithSuccessfulReward_ShouldStoreRewardData(PositiveInt userId, PositiveInt seed)
- {
- // Arrange
- using var dbContext = CreateDbContext();
-
- var orderType = $"test_reward_data_{seed.Get % 100}";
- var rewardData = $"{{\"diamonds\":{seed.Get % 1000 + 100},\"bonus\":{seed.Get % 50}}}";
-
- // Create a mock reward handler that returns reward data
- var mockHandler = new Mock();
- mockHandler.Setup(h => h.OrderType).Returns(orderType);
- mockHandler.Setup(h => h.ProcessRewardAsync(It.IsAny()))
- .ReturnsAsync(RewardResult.Ok(rewardData));
-
- var service = CreateService(dbContext, new[] { mockHandler.Object });
-
- var request = CreateValidRequest(userId.Get, seed.Get);
- request.OrderType = orderType;
- var order = service.CreateOrderAsync(request).GetAwaiter().GetResult();
-
- var transactionId = $"TX_{seed.Get}_{DateTime.Now.Ticks}";
-
- // Act
- service.HandlePaymentSuccessAsync(order.OrderNo, transactionId, order.Amount).GetAwaiter().GetResult();
-
- // Refresh the order from database
- var updatedOrder = service.GetOrderByNoAsync(order.OrderNo).GetAwaiter().GetResult();
-
- // Assert: RewardData should be stored
- return updatedOrder != null && updatedOrder.RewardData == rewardData;
- }
-
- #endregion
-
- #region Helper Methods
-
- ///
- /// 创建内存数据库上下文
- ///
- private MiAssessmentDbContext CreateDbContext()
- {
- var options = new DbContextOptionsBuilder()
- .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
- .Options;
-
- return new MiAssessmentDbContext(options);
- }
-
- ///
- /// 创建 PaymentOrderService 实例
- ///
- private PaymentOrderService CreateService(MiAssessmentDbContext dbContext, IEnumerable? handlers = null)
- {
- return new PaymentOrderService(
- dbContext,
- handlers ?? Array.Empty(),
- _mockLogger.Object);
- }
-
- ///
- /// 创建有效的支付订单请求
- ///
- private CreatePaymentOrderRequest CreateValidRequest(int userId, int seed)
- {
- return new CreatePaymentOrderRequest
- {
- UserId = Math.Max(1, userId), // Ensure positive user ID
- OrderType = $"test_order_{seed % 100}",
- Title = $"测试订单 {seed}",
- Amount = Math.Round((decimal)((seed % 10000) + 100) / 100, 2), // 1.00 to 101.00
- PayMethod = "wechat",
- BizData = $"{{\"seed\":{seed}}}"
- };
- }
-
- ///
- /// 生成有效的订单类型(只包含字母、数字和下划线)
- ///
- private string GenerateValidOrderType(string input, int seed)
- {
- // Filter to only alphanumeric and underscore characters
- var filtered = new string(input.Where(c => char.IsLetterOrDigit(c) || c == '_').ToArray());
-
- // Ensure it's not empty and has reasonable length
- if (string.IsNullOrEmpty(filtered))
- {
- filtered = "order";
- }
-
- // Limit length and add seed for uniqueness
- var maxLength = Math.Min(filtered.Length, 20);
- return $"{filtered.Substring(0, maxLength)}_{seed % 1000}";
- }
-
- #endregion
-}
diff --git a/server/MiAssessment/tests/MiAssessment.Tests/Core/PaymentRewardDispatcherPropertyTests.cs b/server/MiAssessment/tests/MiAssessment.Tests/Core/PaymentRewardDispatcherPropertyTests.cs
deleted file mode 100644
index 5444fd2..0000000
--- a/server/MiAssessment/tests/MiAssessment.Tests/Core/PaymentRewardDispatcherPropertyTests.cs
+++ /dev/null
@@ -1,540 +0,0 @@
-using FsCheck;
-using FsCheck.Xunit;
-using MiAssessment.Core.Interfaces;
-using MiAssessment.Core.Services;
-using MiAssessment.Model.Entities;
-using Microsoft.Extensions.Logging;
-using Moq;
-using Xunit;
-
-namespace MiAssessment.Tests.Core;
-
-///
-/// PaymentRewardDispatcher 属性测试
-/// Feature: framework-template
-///
-/// Property 5: Reward Handler Dispatch
-/// *For any* payment order with a specific order_type:
-/// - The system SHALL search for a registered IPaymentRewardHandler with matching OrderType
-/// - If a handler is found, its ProcessRewardAsync method SHALL be called with the order
-/// - The handler's RewardResult SHALL determine the order's reward_status and reward_data
-///
-/// **Validates: Requirements 6.2, 6.3**
-///
-public class PaymentRewardDispatcherPropertyTests
-{
- private readonly Mock> _mockLogger = new();
-
- #region Property 5: Reward Handler Dispatch
-
- ///
- /// Feature: framework-template, Property 5: Reward Handler Dispatch
- ///
- /// Property 5.1: Handler found for order type → handler's ProcessRewardAsync is called
- /// If a handler is found, its ProcessRewardAsync method SHALL be called with the order
- ///
- /// **Validates: Requirements 6.2, 6.3**
- ///
- [Property(MaxTest = 100)]
- public bool ProcessReward_WithMatchingHandler_ShouldCallProcessRewardAsync(PositiveInt seed)
- {
- // Arrange
- var orderType = GenerateValidOrderType(seed.Get);
- var handlerCalled = false;
- PaymentOrder? receivedOrder = null;
-
- var mockHandler = new Mock();
- mockHandler.Setup(h => h.OrderType).Returns(orderType);
- mockHandler.Setup(h => h.ProcessRewardAsync(It.IsAny()))
- .Callback(order =>
- {
- handlerCalled = true;
- receivedOrder = order;
- })
- .ReturnsAsync(RewardResult.Ok());
-
- var dispatcher = CreateDispatcher(new[] { mockHandler.Object });
- var paymentOrder = CreatePaymentOrder(seed.Get, orderType);
-
- // Act
- dispatcher.ProcessRewardAsync(paymentOrder).GetAwaiter().GetResult();
-
- // Assert: Handler should be called with the correct order
- return handlerCalled && receivedOrder != null && receivedOrder.OrderNo == paymentOrder.OrderNo;
- }
-
- ///
- /// Feature: framework-template, Property 5: Reward Handler Dispatch
- ///
- /// Property 5.2: Handler not found → returns success with no reward data
- /// If no handler is found for the order type, the system should return success (not failure)
- ///
- /// **Validates: Requirements 6.2**
- ///
- [Property(MaxTest = 100)]
- public bool ProcessReward_WithNoMatchingHandler_ShouldReturnSuccessWithNoRewardData(PositiveInt seed)
- {
- // Arrange
- var orderType = GenerateValidOrderType(seed.Get);
- var differentOrderType = $"different_{orderType}";
-
- // Create a handler for a different order type
- var mockHandler = new Mock();
- mockHandler.Setup(h => h.OrderType).Returns(differentOrderType);
- mockHandler.Setup(h => h.ProcessRewardAsync(It.IsAny()))
- .ReturnsAsync(RewardResult.Ok("should_not_be_called"));
-
- var dispatcher = CreateDispatcher(new[] { mockHandler.Object });
- var paymentOrder = CreatePaymentOrder(seed.Get, orderType);
-
- // Act
- var result = dispatcher.ProcessRewardAsync(paymentOrder).GetAwaiter().GetResult();
-
- // Assert: Should return success with no reward data
- return result.Success && result.RewardData == null;
- }
-
- ///
- /// Feature: framework-template, Property 5: Reward Handler Dispatch
- ///
- /// Property 5.3: Handler returns success → result contains reward data
- /// The handler's RewardResult SHALL determine the order's reward_data
- ///
- /// **Validates: Requirements 6.3**
- ///
- [Property(MaxTest = 100)]
- public bool ProcessReward_WithSuccessfulHandler_ShouldReturnRewardData(PositiveInt seed)
- {
- // Arrange
- var orderType = GenerateValidOrderType(seed.Get);
- var expectedRewardData = $"{{\"diamonds\":{seed.Get % 1000 + 100},\"bonus\":{seed.Get % 50}}}";
-
- var mockHandler = new Mock();
- mockHandler.Setup(h => h.OrderType).Returns(orderType);
- mockHandler.Setup(h => h.ProcessRewardAsync(It.IsAny()))
- .ReturnsAsync(RewardResult.Ok(expectedRewardData));
-
- var dispatcher = CreateDispatcher(new[] { mockHandler.Object });
- var paymentOrder = CreatePaymentOrder(seed.Get, orderType);
-
- // Act
- var result = dispatcher.ProcessRewardAsync(paymentOrder).GetAwaiter().GetResult();
-
- // Assert: Result should contain the reward data from handler
- return result.Success && result.RewardData == expectedRewardData;
- }
-
- ///
- /// Feature: framework-template, Property 5: Reward Handler Dispatch
- ///
- /// Property 5.4: Handler returns failure → result contains error message
- /// The handler's RewardResult SHALL determine the order's reward_status
- ///
- /// **Validates: Requirements 6.3**
- ///
- [Property(MaxTest = 100)]
- public bool ProcessReward_WithFailedHandler_ShouldReturnErrorMessage(PositiveInt seed)
- {
- // Arrange
- var orderType = GenerateValidOrderType(seed.Get);
- var expectedErrorMessage = $"Reward processing failed for seed {seed.Get}";
-
- var mockHandler = new Mock();
- mockHandler.Setup(h => h.OrderType).Returns(orderType);
- mockHandler.Setup(h => h.ProcessRewardAsync(It.IsAny()))
- .ReturnsAsync(RewardResult.Fail(expectedErrorMessage));
-
- var dispatcher = CreateDispatcher(new[] { mockHandler.Object });
- var paymentOrder = CreatePaymentOrder(seed.Get, orderType);
-
- // Act
- var result = dispatcher.ProcessRewardAsync(paymentOrder).GetAwaiter().GetResult();
-
- // Assert: Result should contain the error message from handler
- return !result.Success && result.Message == expectedErrorMessage;
- }
-
- ///
- /// Feature: framework-template, Property 5: Reward Handler Dispatch
- ///
- /// Property 5.5: Handler throws exception → result contains error message
- /// If the handler throws an exception, the dispatcher should catch it and return failure
- ///
- /// **Validates: Requirements 6.3**
- ///
- [Property(MaxTest = 100)]
- public bool ProcessReward_WithExceptionThrowingHandler_ShouldReturnErrorMessage(PositiveInt seed)
- {
- // Arrange
- var orderType = GenerateValidOrderType(seed.Get);
- var exceptionMessage = $"Unexpected error for seed {seed.Get}";
-
- var mockHandler = new Mock();
- mockHandler.Setup(h => h.OrderType).Returns(orderType);
- mockHandler.Setup(h => h.ProcessRewardAsync(It.IsAny()))
- .ThrowsAsync(new InvalidOperationException(exceptionMessage));
-
- var dispatcher = CreateDispatcher(new[] { mockHandler.Object });
- var paymentOrder = CreatePaymentOrder(seed.Get, orderType);
-
- // Act
- var result = dispatcher.ProcessRewardAsync(paymentOrder).GetAwaiter().GetResult();
-
- // Assert: Result should be failure and contain error message
- return !result.Success && result.Message != null && result.Message.Contains(exceptionMessage);
- }
-
- ///
- /// Feature: framework-template, Property 5: Reward Handler Dispatch
- ///
- /// Property 5.6: Multiple handlers registered → correct handler is selected
- /// The system SHALL search for a registered IPaymentRewardHandler with matching OrderType
- ///
- /// **Validates: Requirements 6.2**
- ///
- [Property(MaxTest = 100)]
- public bool ProcessReward_WithMultipleHandlers_ShouldSelectCorrectHandler(PositiveInt seed)
- {
- // Arrange
- var targetOrderType = GenerateValidOrderType(seed.Get);
- var otherOrderType1 = $"other1_{seed.Get}";
- var otherOrderType2 = $"other2_{seed.Get}";
-
- var targetRewardData = $"{{\"target_reward\":{seed.Get}}}";
- var targetHandlerCalled = false;
- var otherHandler1Called = false;
- var otherHandler2Called = false;
-
- // Create target handler
- var targetHandler = new Mock();
- targetHandler.Setup(h => h.OrderType).Returns(targetOrderType);
- targetHandler.Setup(h => h.ProcessRewardAsync(It.IsAny()))
- .Callback(() => targetHandlerCalled = true)
- .ReturnsAsync(RewardResult.Ok(targetRewardData));
-
- // Create other handlers
- var otherHandler1 = new Mock();
- otherHandler1.Setup(h => h.OrderType).Returns(otherOrderType1);
- otherHandler1.Setup(h => h.ProcessRewardAsync(It.IsAny()))
- .Callback(() => otherHandler1Called = true)
- .ReturnsAsync(RewardResult.Ok("other1_data"));
-
- var otherHandler2 = new Mock();
- otherHandler2.Setup(h => h.OrderType).Returns(otherOrderType2);
- otherHandler2.Setup(h => h.ProcessRewardAsync(It.IsAny()))
- .Callback(() => otherHandler2Called = true)
- .ReturnsAsync(RewardResult.Ok("other2_data"));
-
- var dispatcher = CreateDispatcher(new[]
- {
- otherHandler1.Object,
- targetHandler.Object,
- otherHandler2.Object
- });
-
- var paymentOrder = CreatePaymentOrder(seed.Get, targetOrderType);
-
- // Act
- var result = dispatcher.ProcessRewardAsync(paymentOrder).GetAwaiter().GetResult();
-
- // Assert: Only target handler should be called, result should match target handler's output
- return targetHandlerCalled &&
- !otherHandler1Called &&
- !otherHandler2Called &&
- result.Success &&
- result.RewardData == targetRewardData;
- }
-
- ///
- /// Feature: framework-template, Property 5: Reward Handler Dispatch
- ///
- /// Property 5.7: GetHandler returns correct handler for registered order type
- /// The system SHALL search for a registered IPaymentRewardHandler with matching OrderType
- ///
- /// **Validates: Requirements 6.2**
- ///
- [Property(MaxTest = 100)]
- public bool GetHandler_WithRegisteredOrderType_ShouldReturnCorrectHandler(PositiveInt seed)
- {
- // Arrange
- var orderType = GenerateValidOrderType(seed.Get);
-
- var mockHandler = new Mock();
- mockHandler.Setup(h => h.OrderType).Returns(orderType);
-
- var dispatcher = CreateDispatcher(new[] { mockHandler.Object });
-
- // Act
- var handler = dispatcher.GetHandler(orderType);
-
- // Assert: Should return the registered handler
- return handler != null && handler.OrderType == orderType;
- }
-
- ///
- /// Feature: framework-template, Property 5: Reward Handler Dispatch
- ///
- /// Property 5.8: GetHandler returns null for unregistered order type
- /// If no handler is found, GetHandler should return null
- ///
- /// **Validates: Requirements 6.2**
- ///
- [Property(MaxTest = 100)]
- public bool GetHandler_WithUnregisteredOrderType_ShouldReturnNull(PositiveInt seed)
- {
- // Arrange
- var registeredOrderType = GenerateValidOrderType(seed.Get);
- var unregisteredOrderType = $"unregistered_{seed.Get}";
-
- var mockHandler = new Mock();
- mockHandler.Setup(h => h.OrderType).Returns(registeredOrderType);
-
- var dispatcher = CreateDispatcher(new[] { mockHandler.Object });
-
- // Act
- var handler = dispatcher.GetHandler(unregisteredOrderType);
-
- // Assert: Should return null for unregistered order type
- return handler == null;
- }
-
- ///
- /// Feature: framework-template, Property 5: Reward Handler Dispatch
- ///
- /// Property 5.9: HasHandler returns true for registered order type
- /// The system should correctly identify if a handler exists for an order type
- ///
- /// **Validates: Requirements 6.2**
- ///
- [Property(MaxTest = 100)]
- public bool HasHandler_WithRegisteredOrderType_ShouldReturnTrue(PositiveInt seed)
- {
- // Arrange
- var orderType = GenerateValidOrderType(seed.Get);
-
- var mockHandler = new Mock();
- mockHandler.Setup(h => h.OrderType).Returns(orderType);
-
- var dispatcher = CreateDispatcher(new[] { mockHandler.Object });
-
- // Act
- var hasHandler = dispatcher.HasHandler(orderType);
-
- // Assert: Should return true for registered order type
- return hasHandler;
- }
-
- ///
- /// Feature: framework-template, Property 5: Reward Handler Dispatch
- ///
- /// Property 5.10: HasHandler returns false for unregistered order type
- /// The system should correctly identify if no handler exists for an order type
- ///
- /// **Validates: Requirements 6.2**
- ///
- [Property(MaxTest = 100)]
- public bool HasHandler_WithUnregisteredOrderType_ShouldReturnFalse(PositiveInt seed)
- {
- // Arrange
- var registeredOrderType = GenerateValidOrderType(seed.Get);
- var unregisteredOrderType = $"unregistered_{seed.Get}";
-
- var mockHandler = new Mock();
- mockHandler.Setup(h => h.OrderType).Returns(registeredOrderType);
-
- var dispatcher = CreateDispatcher(new[] { mockHandler.Object });
-
- // Act
- var hasHandler = dispatcher.HasHandler(unregisteredOrderType);
-
- // Assert: Should return false for unregistered order type
- return !hasHandler;
- }
-
- ///
- /// Feature: framework-template, Property 5: Reward Handler Dispatch
- ///
- /// Property 5.11: GetRegisteredOrderTypes returns all registered order types
- /// The system should track all registered handlers
- ///
- /// **Validates: Requirements 6.2**
- ///
- [Property(MaxTest = 100)]
- public bool GetRegisteredOrderTypes_ShouldReturnAllRegisteredTypes(PositiveInt seed)
- {
- // Arrange
- var orderType1 = $"type1_{seed.Get}";
- var orderType2 = $"type2_{seed.Get}";
- var orderType3 = $"type3_{seed.Get}";
-
- var handler1 = new Mock();
- handler1.Setup(h => h.OrderType).Returns(orderType1);
-
- var handler2 = new Mock();
- handler2.Setup(h => h.OrderType).Returns(orderType2);
-
- var handler3 = new Mock();
- handler3.Setup(h => h.OrderType).Returns(orderType3);
-
- var dispatcher = CreateDispatcher(new[]
- {
- handler1.Object,
- handler2.Object,
- handler3.Object
- });
-
- // Act
- var registeredTypes = dispatcher.GetRegisteredOrderTypes();
-
- // Assert: Should contain all registered order types
- return registeredTypes.Count == 3 &&
- registeredTypes.Contains(orderType1) &&
- registeredTypes.Contains(orderType2) &&
- registeredTypes.Contains(orderType3);
- }
-
- ///
- /// Feature: framework-template, Property 5: Reward Handler Dispatch
- ///
- /// Property 5.12: ProcessReward with null order returns failure
- /// The dispatcher should handle null orders gracefully
- ///
- /// **Validates: Requirements 6.3**
- ///
- [Fact]
- public void ProcessReward_WithNullOrder_ShouldReturnFailure()
- {
- // Arrange
- var dispatcher = CreateDispatcher(Array.Empty());
-
- // Act
- var result = dispatcher.ProcessRewardAsync(null!).GetAwaiter().GetResult();
-
- // Assert: Should return failure
- Assert.False(result.Success);
- Assert.NotNull(result.Message);
- }
-
- ///
- /// Feature: framework-template, Property 5: Reward Handler Dispatch
- ///
- /// Property 5.13: ProcessReward with empty order type returns failure
- /// The dispatcher should handle orders with empty order type gracefully
- ///
- /// **Validates: Requirements 6.3**
- ///
- [Property(MaxTest = 100)]
- public bool ProcessReward_WithEmptyOrderType_ShouldReturnFailure(PositiveInt seed)
- {
- // Arrange
- var dispatcher = CreateDispatcher(Array.Empty());
- var paymentOrder = CreatePaymentOrder(seed.Get, "");
-
- // Act
- var result = dispatcher.ProcessRewardAsync(paymentOrder).GetAwaiter().GetResult();
-
- // Assert: Should return failure
- return !result.Success && result.Message != null;
- }
-
- ///
- /// Feature: framework-template, Property 5: Reward Handler Dispatch
- ///
- /// Property 5.14: Order type matching is case-insensitive
- /// The system should match order types regardless of case
- ///
- /// **Validates: Requirements 6.2**
- ///
- [Property(MaxTest = 100)]
- public bool ProcessReward_OrderTypeMatching_ShouldBeCaseInsensitive(PositiveInt seed)
- {
- // Arrange
- var lowerCaseOrderType = $"order_type_{seed.Get}".ToLowerInvariant();
- var upperCaseOrderType = lowerCaseOrderType.ToUpperInvariant();
- var expectedRewardData = $"{{\"reward\":{seed.Get}}}";
-
- var mockHandler = new Mock();
- mockHandler.Setup(h => h.OrderType).Returns(lowerCaseOrderType);
- mockHandler.Setup(h => h.ProcessRewardAsync(It.IsAny()))
- .ReturnsAsync(RewardResult.Ok(expectedRewardData));
-
- var dispatcher = CreateDispatcher(new[] { mockHandler.Object });
- var paymentOrder = CreatePaymentOrder(seed.Get, upperCaseOrderType);
-
- // Act
- var result = dispatcher.ProcessRewardAsync(paymentOrder).GetAwaiter().GetResult();
-
- // Assert: Should find handler despite case difference
- return result.Success && result.RewardData == expectedRewardData;
- }
-
- ///
- /// Feature: framework-template, Property 5: Reward Handler Dispatch
- ///
- /// Property 5.15: Empty handlers collection returns success for any order
- /// When no handlers are registered, processing should succeed with no reward
- ///
- /// **Validates: Requirements 6.2**
- ///
- [Property(MaxTest = 100)]
- public bool ProcessReward_WithNoHandlers_ShouldReturnSuccess(PositiveInt seed)
- {
- // Arrange
- var dispatcher = CreateDispatcher(Array.Empty());
- var paymentOrder = CreatePaymentOrder(seed.Get, GenerateValidOrderType(seed.Get));
-
- // Act
- var result = dispatcher.ProcessRewardAsync(paymentOrder).GetAwaiter().GetResult();
-
- // Assert: Should return success with no reward data
- return result.Success && result.RewardData == null;
- }
-
- #endregion
-
- #region Helper Methods
-
- ///
- /// 创建 PaymentRewardDispatcher 实例
- ///
- private PaymentRewardDispatcher CreateDispatcher(IEnumerable handlers)
- {
- return new PaymentRewardDispatcher(handlers, _mockLogger.Object);
- }
-
- ///
- /// 创建测试用的 PaymentOrder
- ///
- private PaymentOrder CreatePaymentOrder(int seed, string orderType)
- {
- return new PaymentOrder
- {
- Id = seed,
- OrderNo = $"PO{DateTime.Now:yyyyMMddHHmmss}{seed:D6}",
- UserId = Math.Max(1, seed % 10000),
- OrderType = orderType,
- Title = $"测试订单 {seed}",
- Amount = Math.Round((decimal)((seed % 10000) + 100) / 100, 2),
- PayAmount = Math.Round((decimal)((seed % 10000) + 100) / 100, 2),
- PayMethod = "wechat",
- Status = 1, // 已支付
- PaidAt = DateTime.Now,
- TransactionId = $"TX_{seed}",
- BizData = $"{{\"seed\":{seed}}}",
- RewardStatus = 0,
- CreatedAt = DateTime.Now,
- UpdatedAt = DateTime.Now
- };
- }
-
- ///
- /// 生成有效的订单类型
- ///
- private string GenerateValidOrderType(int seed)
- {
- var types = new[] { "diamond_recharge", "vip_purchase", "gift_buy", "subscription", "premium" };
- return $"{types[seed % types.Length]}_{seed % 1000}";
- }
-
- #endregion
-}
diff --git a/server/MiAssessment/tests/MiAssessment.Tests/Services/AuthServiceLoginRecordPropertyTests.cs b/server/MiAssessment/tests/MiAssessment.Tests/Services/AuthServiceLoginRecordPropertyTests.cs
index 6a903ae..df61783 100644
--- a/server/MiAssessment/tests/MiAssessment.Tests/Services/AuthServiceLoginRecordPropertyTests.cs
+++ b/server/MiAssessment/tests/MiAssessment.Tests/Services/AuthServiceLoginRecordPropertyTests.cs
@@ -87,28 +87,18 @@ public class AuthServiceLoginRecordPropertyTests
Adcode = "110000"
});
- // Create a user
+ // 创建用户
var user = new User
{
OpenId = "openid_" + Guid.NewGuid().ToString().Substring(0, 8),
Uid = "uid123",
Nickname = "TestUser",
- HeadImg = "https://example.com/avatar.jpg",
+ Avatar = "https://example.com/avatar.jpg",
Status = 1,
- CreatedAt = DateTime.UtcNow,
- UpdatedAt = DateTime.UtcNow
+ CreateTime = DateTime.Now,
+ UpdateTime = DateTime.Now
};
await dbContext.Users.AddAsync(user);
-
- // Create UserAccount for the user
- var userAccount = new UserAccount
- {
- UserId = user.Id,
- AccountToken = "token123",
- TokenNum = "num123",
- LastLoginIp = string.Empty
- };
- await dbContext.UserAccounts.AddAsync(userAccount);
await dbContext.SaveChangesAsync();
var device = "iOS";
@@ -118,17 +108,15 @@ public class AuthServiceLoginRecordPropertyTests
await authService.RecordLoginAsync(user.Id, device, clientIp);
// Assert
- // 1. UserLoginLog should be created
+ // 1. UserLoginLog 应该被创建
var loginLog = await dbContext.UserLoginLogs.FirstOrDefaultAsync(l => l.UserId == user.Id);
- var logCreated = loginLog != null && loginLog.Device == device;
+ var logCreated = loginLog != null && loginLog.UserAgent == device;
- // 2. UserAccount should be updated
- var updatedAccount = await dbContext.UserAccounts.FirstOrDefaultAsync(ua => ua.UserId == user.Id);
- var accountUpdated = updatedAccount != null &&
- updatedAccount.LastLoginTime != null &&
- updatedAccount.IpProvince == "北京";
+ // 2. 用户最后登录时间应该被更新
+ var updatedUser = await dbContext.Users.FirstOrDefaultAsync(u => u.Id == user.Id);
+ var userUpdated = updatedUser != null && updatedUser.LastLoginTime != null;
- return logCreated && accountUpdated;
+ return logCreated && userUpdated;
}
///
@@ -153,16 +141,16 @@ public class AuthServiceLoginRecordPropertyTests
var expectedNickname = "TestUser_" + Random.Shared.Next(1000, 9999);
var expectedHeadimg = "https://example.com/avatar_" + Random.Shared.Next(1000, 9999) + ".jpg";
- // Create a user
+ // 创建用户
var user = new User
{
OpenId = "openid_" + Guid.NewGuid().ToString().Substring(0, 8),
Uid = expectedUid,
Nickname = expectedNickname,
- HeadImg = expectedHeadimg,
+ Avatar = expectedHeadimg,
Status = 1,
- CreatedAt = DateTime.UtcNow,
- UpdatedAt = DateTime.UtcNow
+ CreateTime = DateTime.Now,
+ UpdateTime = DateTime.Now
};
await dbContext.Users.AddAsync(user);
await dbContext.SaveChangesAsync();
@@ -197,10 +185,10 @@ public class AuthServiceLoginRecordPropertyTests
OpenId = "openid_" + Guid.NewGuid().ToString().Substring(0, 8),
Uid = "uid123",
Nickname = "TestUser",
- HeadImg = "https://example.com/avatar.jpg",
+ Avatar = "https://example.com/avatar.jpg",
Status = 1, // Active
- CreatedAt = DateTime.UtcNow,
- UpdatedAt = DateTime.UtcNow
+ CreateTime = DateTime.Now,
+ UpdateTime = DateTime.Now
};
await dbContext1.Users.AddAsync(user1);
await dbContext1.SaveChangesAsync();
@@ -221,10 +209,10 @@ public class AuthServiceLoginRecordPropertyTests
OpenId = "openid_" + Guid.NewGuid().ToString().Substring(0, 8),
Uid = "uid456",
Nickname = "TestUser2",
- HeadImg = "https://example.com/avatar.jpg",
+ Avatar = "https://example.com/avatar.jpg",
Status = 0, // Inactive
- CreatedAt = DateTime.UtcNow,
- UpdatedAt = DateTime.UtcNow
+ CreateTime = DateTime.Now,
+ UpdateTime = DateTime.Now
};
await dbContext2.Users.AddAsync(user2);
await dbContext2.SaveChangesAsync();