feat: add wechat mini program mall, check-in supplement and pet skin system

This commit implements a complete WeChat mini program mall and related features:
1. Add pet skin entity and backpack item type support
2. Add make-up check-in and missed date query functions
3. Implement mall product browsing, exchange and record query
4. Add backpack management and item usage (make-up card)
5. Add pet skin equipping function
6. Fix UserBag ItemId type from int to long
7. Adjust Dockerfile exposed port to 8080
8. Fix session cookie unprotect warning
This commit is contained in:
glz
2026-06-04 18:03:34 +08:00
parent 903ccd3073
commit ae2c6ddfc7
14 changed files with 1128 additions and 8 deletions

View File

@ -192,11 +192,6 @@ public class CheckInService(
if (lastDate == today || lastDate == today.AddDays(-1))
{
consecutiveDays = lastRecord.ConsecutiveDays;
if (lastDate == today)
{
// 今天已签到,连续天数就是今天的值
}
// 如果是昨天,则连续天数保持(今天还没签到)
}
}
@ -233,6 +228,160 @@ public class CheckInService(
};
}
/// <summary>
/// 补签(消耗补签卡,补签历史漏签日期)
/// </summary>
public async Task<CheckInOutput> MakeUpCheckInAsync(long userId, DateTime targetDate)
{
logger.LogInformation("用户补签UserId: {UserId}, TargetDate: {Date}", userId, targetDate);
targetDate = targetDate.Date;
if (targetDate >= DateTime.Now.Date)
throw new BusinessException("只能补签过去的日期", 400);
// 检查目标日期是否已有签到记录
var alreadyCheckedIn = await checkInRecordRepository.Context.Queryable<CheckInRecord>()
.Where(r => r.UserId == userId && !r.IsDeleted
&& r.CheckInDate >= targetDate && r.CheckInDate < targetDate.AddDays(1))
.AnyAsync();
if (alreadyCheckedIn)
throw new BusinessException($"{targetDate:yyyy-MM-dd} 已签到,无需补签", 400);
// 查询用户信息
var user = await checkInRecordRepository.Context.Queryable<Users>()
.Where(u => u.Id == userId && !u.IsDeleted)
.FirstAsync();
if (user == null)
throw new BusinessException("用户不存在", 404);
// 查询宠物
var pet = await checkInRecordRepository.Context.Queryable<Pet>()
.Where(p => p.UserId == userId && !p.IsDeleted)
.FirstAsync();
// 补签奖励按基础值计算(不享受连续签到加成)
var (pointsReward, growthReward) = await CalculateRewardsAsync(1);
var result = new CheckInOutput();
await checkInRecordRepository.UseTranAsync(async () =>
{
// 创建补签记录
var checkInRecord = new CheckInRecord
{
UserId = userId,
CheckInDate = targetDate,
PointsAwarded = pointsReward,
GrowthPointsAwarded = growthReward,
ConsecutiveDays = 0, // 补签不纳入连续天数
Type = "MakeUp",
Status = "Success",
IsDeleted = false,
CreatedBy = userId.ToString(),
CreatedAt = DateTime.Now,
UpdatedBy = userId.ToString(),
UpdatedAt = DateTime.Now
};
var recordId = await checkInRecordRepository.Insertable(checkInRecord).ExecuteReturnIdentityAsync();
checkInRecord.Id = recordId;
// 更新用户积分和成长值
var newPointsBalance = user.Points + pointsReward;
var newGrowthBalance = user.GrowthPoints + growthReward;
await checkInRecordRepository.Context.Updateable<Users>()
.SetColumns(u => u.Points == newPointsBalance)
.SetColumns(u => u.GrowthPoints == newGrowthBalance)
.Where(u => u.Id == userId && !u.IsDeleted)
.ExecuteCommandAsync();
// 创建积分变动记录
var pointsRecord = new PointsRecord
{
UserId = userId,
ChangeAmount = pointsReward,
BalanceAfter = newPointsBalance,
ChangeType = "MakeUpSign",
RelatedId = recordId,
Description = $"补签奖励({targetDate:yyyy-MM-dd}",
Type = "Income",
Status = "Success",
IsDeleted = false,
CreatedBy = userId.ToString(),
CreatedAt = DateTime.Now,
UpdatedBy = userId.ToString(),
UpdatedAt = DateTime.Now
};
await checkInRecordRepository.Context.Insertable(pointsRecord).ExecuteCommandAsync();
result.RecordId = (long)recordId;
result.CheckInDate = targetDate;
result.ConsecutiveDays = 0;
result.PointsAwarded = pointsReward;
result.GrowthPointsAwarded = growthReward;
result.PointsBalance = newPointsBalance;
result.GrowthPointsBalance = newGrowthBalance;
result.HasPet = pet != null;
});
// 如果有活跃宠物,喂养成长值
if (pet != null && pet.Status == "Active" && growthReward > 0)
{
try
{
var feedResult = await petService.FeedPetAsync(userId, new Models.Dto.Pet.FeedPetInput
{
PetId = pet.Id,
GrowthPoints = growthReward
});
result.HasEvolved = feedResult.HasEvolved;
result.EvolvedStageName = feedResult.EvolvedStageName;
}
catch (Exception ex)
{
logger.LogWarning(ex, "补签后喂养宠物失败PetId: {PetId}", pet.Id);
// 补偿机制:如需可在此创建补偿任务
}
}
logger.LogInformation("补签成功UserId: {UserId}, Date: {Date}, 积分+{Points}, 成长值+{Growth}",
userId, targetDate, pointsReward, growthReward);
return result;
}
/// <summary>
/// 获取用户漏签日期列表
/// </summary>
public async Task<List<DateTime>> GetMissedDatesAsync(long userId, int days = 30)
{
var startDate = DateTime.Now.Date.AddDays(-days);
// 查询该时间段内所有签到记录
var checkedDates = await checkInRecordRepository.Context.Queryable<CheckInRecord>()
.Where(r => r.UserId == userId && !r.IsDeleted && r.CheckInDate >= startDate)
.Select(r => r.CheckInDate.Date)
.ToListAsync();
var checkedDateSet = new HashSet<DateTime>(checkedDates);
var missedDates = new List<DateTime>();
// 遍历每一天,找出漏签的日期(排除今天,今天不算漏签)
for (var date = startDate; date < DateTime.Now.Date; date = date.AddDays(1))
{
if (!checkedDateSet.Contains(date))
{
missedDates.Add(date);
}
}
return missedDates;
}
/// <summary>
/// 计算连续签到天数
/// </summary>