587 lines
22 KiB
C#
587 lines
22 KiB
C#
using Microsoft.AspNetCore.Mvc;
|
||
using YD_Event.Application.Client.Dtos;
|
||
using YD_Event.Core.Entities;
|
||
using YD_Event.Core.Enum;
|
||
using SqlSugar;
|
||
using Furion.DatabaseAccessor;
|
||
using Microsoft.AspNetCore.Authorization;
|
||
using System.Security.Claims;
|
||
using Furion.FriendlyException;
|
||
using ProjectEntity = YD_Event.Core.Entities.Project;
|
||
|
||
namespace YD_Event.Application.Client;
|
||
|
||
/// <summary>
|
||
/// 小程序-个人中心接口
|
||
/// </summary>
|
||
[ApiDescriptionSettings("微信小程序接口")]
|
||
[Authorize]
|
||
public class MyController : IDynamicApiController
|
||
{
|
||
private readonly ISqlSugarRepository<YD_Event.Core.Entities.AppUser> _appUserRepository;
|
||
private readonly ISqlSugarRepository<YD_Event.Core.Entities.Team> _teamRepository;
|
||
private readonly ISqlSugarRepository<TeamMember> _teamMemberRepository;
|
||
private readonly ISqlSugarRepository<EventCertificate> _certificateRepository;
|
||
private readonly ISqlSugarRepository<PointsRecord> _pointsRecordRepository;
|
||
private readonly ISqlSugarRepository<YD_Event.Core.Entities.Order> _orderRepository;
|
||
private readonly ISqlSugarRepository<EventRegistration> _registrationRepository;
|
||
private readonly ISqlSugarRepository<EventRegistrationItem> _registrationItemRepository;
|
||
private readonly ISqlSugarRepository<EventInfo> _eventRepository;
|
||
private readonly ISqlSugarRepository<MerchantCertification> _merchantCertificationRepository;
|
||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||
|
||
public MyController(
|
||
ISqlSugarRepository<YD_Event.Core.Entities.AppUser> appUserRepository,
|
||
ISqlSugarRepository<YD_Event.Core.Entities.Team> teamRepository,
|
||
ISqlSugarRepository<TeamMember> teamMemberRepository,
|
||
ISqlSugarRepository<EventCertificate> certificateRepository,
|
||
ISqlSugarRepository<PointsRecord> pointsRecordRepository,
|
||
ISqlSugarRepository<YD_Event.Core.Entities.Order> orderRepository,
|
||
ISqlSugarRepository<EventRegistration> registrationRepository,
|
||
ISqlSugarRepository<EventRegistrationItem> registrationItemRepository,
|
||
ISqlSugarRepository<EventInfo> eventRepository,
|
||
ISqlSugarRepository<MerchantCertification> merchantCertificationRepository,
|
||
IHttpContextAccessor httpContextAccessor)
|
||
{
|
||
_appUserRepository = appUserRepository;
|
||
_teamRepository = teamRepository;
|
||
_teamMemberRepository = teamMemberRepository;
|
||
_certificateRepository = certificateRepository;
|
||
_pointsRecordRepository = pointsRecordRepository;
|
||
_orderRepository = orderRepository;
|
||
_registrationRepository = registrationRepository;
|
||
_registrationItemRepository = registrationItemRepository;
|
||
_eventRepository = eventRepository;
|
||
_merchantCertificationRepository = merchantCertificationRepository;
|
||
_httpContextAccessor = httpContextAccessor;
|
||
}
|
||
|
||
private long GetCurrentUserId()
|
||
{
|
||
var userIdStr = _httpContextAccessor.HttpContext?.User?.FindFirst(AuthClaimsConst.AuthIdKey)?.Value;
|
||
if (string.IsNullOrEmpty(userIdStr) || !long.TryParse(userIdStr, out long userId))
|
||
{
|
||
throw Oops.Bah("未登录或登录已失效");
|
||
}
|
||
return userId;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取个人主页信息
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpGet("profile")]
|
||
public async Task<MyProfileDto> GetProfile()
|
||
{
|
||
var userId = GetCurrentUserId();
|
||
var user = await _appUserRepository.GetFirstAsync(u => u.Id == userId);
|
||
if (user == null) throw Oops.Bah("用户信息不存在");
|
||
|
||
// 统计证书数量
|
||
var certCount = await _certificateRepository.CountAsync(c => c.CreatedUserId == userId && c.CertificateStatus == 2);
|
||
|
||
// 积分 (需计算积分总和,PointsRecord 表有 Points 字段,Type 1-加 2-减)
|
||
// 简单计算:Sum(Type=1) - Sum(Type=2)
|
||
var pointsIn = await _pointsRecordRepository.AsQueryable().Where(p => p.UserId == userId && p.Type == PointsOperationType.Acquire).SumAsync(p => p.Points);
|
||
var pointsOut = await _pointsRecordRepository.AsQueryable().Where(p => p.UserId == userId && p.Type == PointsOperationType.Consume).SumAsync(p => p.Points);
|
||
var pointsBalance = (int)(pointsIn - pointsOut);
|
||
|
||
// 认证状态: 0-待提交, 1-已认证, 2-审核中, 3-失败
|
||
int authStatus = 0;
|
||
bool isAuthInfoSubmitted = !string.IsNullOrEmpty(user.Name) && !string.IsNullOrEmpty(user.IdCardNumber);
|
||
|
||
if (!isAuthInfoSubmitted)
|
||
{
|
||
authStatus = 0; // 未认证
|
||
}
|
||
else if (user.AuditStatus == AuditStatus.Pass)
|
||
{
|
||
authStatus = 1; // 已认证
|
||
}
|
||
else if (user.AuditStatus == AuditStatus.PendingAudit)
|
||
{
|
||
authStatus = 2; // 审核中
|
||
}
|
||
else
|
||
{
|
||
authStatus = 3; // 失败/其他
|
||
}
|
||
|
||
// 获取单位名称
|
||
string? merchantName = null;
|
||
if (user.MerchantCertificationId.HasValue)
|
||
{
|
||
var merchantCert = await _merchantCertificationRepository.GetFirstAsync(m => m.Id == user.MerchantCertificationId.Value);
|
||
merchantName = merchantCert?.MerchantName;
|
||
}
|
||
|
||
return new MyProfileDto
|
||
{
|
||
NickName = user.NickName ?? "微信用户",
|
||
Avatar = user.Avatar ?? "",
|
||
Mobile = MaskMobile(user.Mobile),
|
||
Points = pointsBalance,
|
||
CertificateCount = certCount,
|
||
AuthStatus = authStatus,
|
||
MerchantName = merchantName,
|
||
Gender = (int?)user.Gender,
|
||
BirthDate = user.BirthDate
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取实名认证信息
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpGet("auth")]
|
||
public async Task<MyAuthInfoDto> GetAuthInfo()
|
||
{
|
||
var userId = GetCurrentUserId();
|
||
var user = await _appUserRepository.GetFirstAsync(u => u.Id == userId);
|
||
if (user == null) throw Oops.Bah("用户信息不存在");
|
||
|
||
int authType = 1; // 默认身份证认证
|
||
if (!string.IsNullOrEmpty(user.PassportPhotoUrl))
|
||
{
|
||
authType = 2;
|
||
}
|
||
|
||
return new MyAuthInfoDto
|
||
{
|
||
AuthType = authType,
|
||
Name = user.Name,
|
||
Mobile = user.Mobile,
|
||
Gender = (int?)user.Gender,
|
||
BirthDate = user.BirthDate,
|
||
IdCardNumber = user.IdCardNumber,
|
||
IdCardImageUrl = user.IdCardImageUrl,
|
||
PassportPhotoUrl = user.PassportPhotoUrl,
|
||
AuditStatus = user.AuditStatus,
|
||
AuditRemark = user.AuditRemark
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 提交实名认证
|
||
/// </summary>
|
||
/// <param name="input"></param>
|
||
/// <returns></returns>
|
||
[HttpPost("auth")]
|
||
public async Task<bool> SubmitAuth([FromBody] SubmitAuthInput input)
|
||
{
|
||
var userId = GetCurrentUserId();
|
||
var user = await _appUserRepository.GetFirstAsync(u => u.Id == userId);
|
||
if (user == null) throw Oops.Bah("用户信息不存在");
|
||
|
||
if (user.AuditStatus == AuditStatus.Pass) throw Oops.Bah("已通过实名认证,无需重复提交");
|
||
if (user.AuditStatus == AuditStatus.PendingAudit) throw Oops.Bah("审核中,请勿重复提交");
|
||
|
||
// 验证必填字段
|
||
if (input.AuthType == 1)
|
||
{
|
||
if (string.IsNullOrEmpty(input.IdCardNumber)) throw Oops.Bah("身份证号不能为空");
|
||
if (string.IsNullOrEmpty(input.IdCardImageUrl)) throw Oops.Bah("身份证正面图片不能为空");
|
||
}
|
||
else if (input.AuthType == 2)
|
||
{
|
||
if (string.IsNullOrEmpty(input.PassportPhotoUrl)) throw Oops.Bah("护照图片不能为空");
|
||
if (!input.Gender.HasValue) throw Oops.Bah("性别不能为空");
|
||
if (!input.BirthDate.HasValue) throw Oops.Bah("出生日期不能为空");
|
||
}
|
||
else
|
||
{
|
||
throw Oops.Bah("不支持的认证类型");
|
||
}
|
||
|
||
// 验证手机号验证码(此处仅占位,实际业务中需要验证短信验证码)
|
||
if (string.IsNullOrEmpty(input.SmsCode)) throw Oops.Bah("手机号验证码不能为空");
|
||
|
||
user.Name = input.Name;
|
||
user.Mobile = input.Mobile;
|
||
|
||
if (input.AuthType == 1)
|
||
{
|
||
user.IdCardNumber = input.IdCardNumber;
|
||
user.IdCardImageUrl = input.IdCardImageUrl;
|
||
user.PassportPhotoUrl = null; // 清空护照图片
|
||
}
|
||
else
|
||
{
|
||
user.PassportPhotoUrl = input.PassportPhotoUrl;
|
||
user.IdCardImageUrl = null; // 清空身份证图片
|
||
user.Gender = (Gender)input.Gender.Value;
|
||
user.BirthDate = input.BirthDate.Value;
|
||
}
|
||
|
||
user.AuditStatus = AuditStatus.PendingAudit;
|
||
user.UpdatedTime = DateTime.Now;
|
||
|
||
return await _appUserRepository.UpdateAsync(user);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 我的团队列表
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpGet("teams")]
|
||
public async Task<PageResult<MyTeamDto>> GetTeams([FromQuery] MyPageInput input)
|
||
{
|
||
var userId = GetCurrentUserId();
|
||
|
||
var myTeamIds = await _teamMemberRepository.AsQueryable()
|
||
.Where(tm => tm.UserId == userId && !tm.DeleteMark)
|
||
.Select(tm => tm.TeamId)
|
||
.ToListAsync();
|
||
|
||
var query = _teamRepository.AsQueryable()
|
||
.Where(t => (t.CreatedUserId == userId || myTeamIds.Contains(t.Id)) && !t.DeleteMark);
|
||
|
||
var teams = await query.ToPagedListAsync(input);
|
||
|
||
var teamIds = teams.Rows.Select(t => t.Id).ToList();
|
||
var teamMembers = await _teamMemberRepository.AsQueryable()
|
||
.Where(tm => teamIds.Contains(tm.TeamId) && !tm.DeleteMark)
|
||
.ToListAsync();
|
||
var memberCounts = teamMembers
|
||
.GroupBy(tm => tm.TeamId)
|
||
.ToDictionary(g => g.Key, g => g.Count());
|
||
|
||
var result = new PageResult<MyTeamDto>
|
||
{
|
||
PageNo = teams.PageNo,
|
||
PageSize = teams.PageSize,
|
||
Total = teams.Total,
|
||
Pages = teams.Pages,
|
||
Rows = teams.Rows.Select(t => new MyTeamDto
|
||
{
|
||
Id = t.Id,
|
||
Name = t.Name,
|
||
IsLeader = t.CreatedUserId == userId,
|
||
MemberCount = memberCounts.TryGetValue(t.Id, out var count) ? count : 0
|
||
}).ToList()
|
||
};
|
||
|
||
return result;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 团队详情
|
||
/// </summary>
|
||
/// <param name="id">团队ID</param>
|
||
/// <returns></returns>
|
||
[HttpGet("teams/{id}")]
|
||
public async Task<MyTeamDetailDto> GetTeamDetail(long id)
|
||
{
|
||
var userId = GetCurrentUserId();
|
||
|
||
var team = await _teamRepository.GetFirstAsync(t => t.Id == id && !t.DeleteMark);
|
||
if (team == null) throw Oops.Bah("团队不存在");
|
||
|
||
var teamMembers = await _teamMemberRepository.AsQueryable()
|
||
.Where(tm => tm.TeamId == id && !tm.DeleteMark)
|
||
.ToListAsync();
|
||
|
||
if (!teamMembers.Any(tm => tm.UserId == userId) && team.CreatedUserId != userId)
|
||
{
|
||
throw Oops.Bah("无权访问该团队");
|
||
}
|
||
|
||
var userIds = teamMembers.Select(tm => tm.UserId).ToList();
|
||
var users = await _appUserRepository.AsQueryable()
|
||
.Where(u => userIds.Contains(u.Id))
|
||
.ToListAsync();
|
||
|
||
var userDict = users.ToDictionary(u => u.Id);
|
||
|
||
var members = teamMembers.Select(tm =>
|
||
{
|
||
userDict.TryGetValue(tm.UserId, out var user);
|
||
return new MyTeamMemberDto
|
||
{
|
||
Name = user?.Name ?? "未知",
|
||
Gender = (int)(user?.Gender ?? 0),
|
||
Age = user?.Age,
|
||
PersonType = (int)tm.PersonType,
|
||
Mobile = user?.Mobile != null ? MaskMobile(user.Mobile) : null
|
||
};
|
||
}).ToList();
|
||
|
||
var leader = members.FirstOrDefault(m => m.PersonType == 3);
|
||
var coach = members.FirstOrDefault(m => m.PersonType == 2);
|
||
|
||
return new MyTeamDetailDto
|
||
{
|
||
Id = team.Id,
|
||
Name = team.Name,
|
||
Leader = leader,
|
||
Coach = coach,
|
||
CreatedTime = team.CreatedTime,
|
||
MemberCount = members.Count,
|
||
Members = members
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 我的证书总览
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpGet("certificates/overview")]
|
||
public async Task<MyCertificateOverviewDto> GetCertificatesOverview()
|
||
{
|
||
var userId = GetCurrentUserId();
|
||
var count = await _certificateRepository.CountAsync(c => c.CreatedUserId == userId && c.CertificateStatus == 2 && !c.DeleteMark);
|
||
|
||
return new MyCertificateOverviewDto
|
||
{
|
||
TotalCount = count
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 我的证书列表
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpGet("certificates")]
|
||
public async Task<PageResult<MyCertificateDto>> GetCertificates([FromQuery] MyCertificatePageInput input)
|
||
{
|
||
var userId = GetCurrentUserId();
|
||
|
||
// 先查询原始数据,然后在内存中转换证书名称
|
||
var query = _certificateRepository.AsQueryable()
|
||
.LeftJoin<EventInfo>((c, e) => c.EventId == e.Id)
|
||
.LeftJoin<ProjectEntity>((c, e, p) => c.ProjectId == p.Id)
|
||
.Where((c, e, p) => c.CreatedUserId == userId && c.CertificateStatus == 2 && !c.DeleteMark)
|
||
.Select((c, e, p) => new
|
||
{
|
||
Id = c.Id,
|
||
EventName = e.EventName,
|
||
ProjectName = p.Name,
|
||
GroupName = c.GroupName,
|
||
CertificateType = c.CertificateType,
|
||
CertificateUrl = c.CertificateUrl,
|
||
IssuedTime = c.IssuedTime
|
||
})
|
||
.OrderByDescending(c => c.IssuedTime);
|
||
|
||
var pagedResult = await query.ToPagedListAsync(input);
|
||
|
||
// 在内存中转换证书名称
|
||
var result = new PageResult<MyCertificateDto>
|
||
{
|
||
PageNo = pagedResult.PageNo,
|
||
PageSize = pagedResult.PageSize,
|
||
Total = pagedResult.Total,
|
||
Pages = pagedResult.Pages,
|
||
Rows = pagedResult.Rows.Select(x => new MyCertificateDto
|
||
{
|
||
Id = x.Id,
|
||
EventName = x.EventName,
|
||
ProjectName = x.ProjectName,
|
||
GroupName = x.GroupName,
|
||
CertificateName = GetCertificateName(x.CertificateType),
|
||
CertificateUrl = x.CertificateUrl,
|
||
IssuedTime = x.IssuedTime
|
||
}).ToList()
|
||
};
|
||
|
||
return result;
|
||
}
|
||
|
||
private string GetCertificateName(int certificateType)
|
||
{
|
||
return certificateType switch
|
||
{
|
||
1 => "冠军证书",
|
||
2 => "亚军证书",
|
||
3 => "季军证书",
|
||
4 => "优胜证书",
|
||
5 => "参与证书",
|
||
_ => "荣誉证书"
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 我的积分总览
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpGet("points/overview")]
|
||
public async Task<MyPointsOverviewDto> GetPointsOverview()
|
||
{
|
||
var userId = GetCurrentUserId();
|
||
|
||
var pointsIn = await _pointsRecordRepository.AsQueryable().Where(p => p.UserId == userId && p.Type == PointsOperationType.Acquire).SumAsync(p => p.Points);
|
||
var pointsOut = await _pointsRecordRepository.AsQueryable().Where(p => p.UserId == userId && p.Type == PointsOperationType.Consume).SumAsync(p => p.Points);
|
||
var pointsBalance = (int)(pointsIn - pointsOut);
|
||
|
||
return new MyPointsOverviewDto
|
||
{
|
||
TotalPoints = pointsBalance
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 我的积分记录
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpGet("points")]
|
||
public async Task<PageResult<MyPointsRecordDto>> GetPoints([FromQuery] MyPointsPageInput input)
|
||
{
|
||
var userId = GetCurrentUserId();
|
||
var query = _pointsRecordRepository.AsQueryable()
|
||
.LeftJoin<EventInfo>((p, e) => p.EventId == e.Id)
|
||
.LeftJoin<ProjectEntity>((p, e, pr) => p.ProjectId == pr.Id)
|
||
.LeftJoin<ProjectGroup>((p, e, pr, pg) => p.ProjectGroupId == pg.Id)
|
||
.Where((p, e, pr, pg) => p.UserId == userId && !p.DeleteMark);
|
||
|
||
if (input.Type.HasValue)
|
||
{
|
||
var typeFilter = (PointsOperationType)input.Type.Value;
|
||
query = query.Where((p, e, pr, pg) => p.Type == typeFilter);
|
||
}
|
||
|
||
if (input.MerchantCertificationId.HasValue)
|
||
{
|
||
query = query.Where((p, e, pr, pg) => p.MerchantCertificationId == input.MerchantCertificationId.Value);
|
||
}
|
||
|
||
var resultQuery = query.Select((p, e, pr, pg) => new MyPointsRecordDto
|
||
{
|
||
Id = p.Id,
|
||
Title = p.Remark ?? (p.Type == PointsOperationType.Acquire ? "获取积分" : "消耗积分"),
|
||
EventName = e.EventName,
|
||
ProjectName = pr.Name,
|
||
GroupName = pg.GroupName,
|
||
Points = p.Points,
|
||
Type = (int)p.Type,
|
||
CreatedTime = p.CreatedTime,
|
||
Rank = 1 // 积分记录表暂无名次字段,后续若有需要可补充
|
||
})
|
||
.OrderByDescending(p => p.CreatedTime);
|
||
|
||
return await resultQuery.ToPagedListAsync(input);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 我的订单列表
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpGet("orders")]
|
||
public async Task<PageResult<MyOrderDto>> GetOrders([FromQuery] MyPageInput input)
|
||
{
|
||
var userId = GetCurrentUserId();
|
||
var query = _orderRepository.AsQueryable()
|
||
.LeftJoin<EventInfo>((o, e) => o.EventId == e.Id)
|
||
.Where((o, e) => o.CreatedUserId == userId && !o.DeleteMark)
|
||
.Select((o, e) => new MyOrderDto
|
||
{
|
||
Id = o.Id,
|
||
OrderNo = o.OrderNo,
|
||
EventName = e.EventName,
|
||
ActualAmount = o.ActualAmount,
|
||
RefundAmount = o.OrderType == 2 ? o.ActualAmount : null,
|
||
OrderStatus = o.OrderStatus,
|
||
PaymentTime = o.PaymentTime,
|
||
CreatedTime = o.CreatedTime
|
||
})
|
||
.OrderByDescending(o => o.CreatedTime);
|
||
|
||
return await query.ToPagedListAsync(input);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 订单详情
|
||
/// </summary>
|
||
/// <param name="id">订单ID</param>
|
||
/// <returns></returns>
|
||
[HttpGet("orders/{id}")]
|
||
public async Task<MyOrderDetailDto> GetOrderDetail(long id)
|
||
{
|
||
var userId = GetCurrentUserId();
|
||
|
||
var order = await _orderRepository.GetFirstAsync(o => o.Id == id && o.CreatedUserId == userId && !o.DeleteMark);
|
||
if (order == null) throw Oops.Bah("订单不存在");
|
||
|
||
var eventName = await _eventRepository.AsQueryable()
|
||
.Where(e => e.Id == order.EventId)
|
||
.Select(e => e.EventName)
|
||
.FirstAsync();
|
||
|
||
var items = await _registrationItemRepository.AsQueryable()
|
||
.Where(i => i.RegistrationId == order.RegistrationId && !i.DeleteMark)
|
||
.Select(i => new MyOrderItemDto
|
||
{
|
||
ProjectName = i.ProjectName,
|
||
GroupName = i.GroupName,
|
||
Fee = i.TotalPrice
|
||
})
|
||
.ToListAsync();
|
||
|
||
return new MyOrderDetailDto
|
||
{
|
||
Id = order.Id,
|
||
OrderNo = order.OrderNo,
|
||
EventName = eventName,
|
||
ActualAmount = order.ActualAmount,
|
||
RefundAmount = order.OrderType == 2 ? order.ActualAmount : null,
|
||
RefundTime = order.OrderType == 2 ? order.PaymentTime : null,
|
||
OrderStatus = order.OrderStatus,
|
||
PaymentTime = order.PaymentTime,
|
||
PaymentMethod = order.PaymentMethod,
|
||
Items = items
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 我的参赛记录(暂不对外提供)
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[ApiDescriptionSettings(false)]
|
||
[NonAction]
|
||
public async Task<PageResult<MyRegistrationDto>> GetRegistrations([FromQuery] MyPageInput input)
|
||
{
|
||
var userId = GetCurrentUserId();
|
||
var query = _registrationRepository.AsQueryable()
|
||
.LeftJoin<EventInfo>((r, e) => r.EventId == e.Id)
|
||
.Where(r => r.CreatedUserId == userId && !r.DeleteMark)
|
||
.Select((r, e) => new MyRegistrationDto
|
||
{
|
||
Id = r.Id,
|
||
EventName = e.EventName,
|
||
TeamName = r.TeamName,
|
||
Status = r.RegistrationStatus,
|
||
RegistrationTime = r.RegistrationTime,
|
||
ProjectNames = ""
|
||
})
|
||
.OrderByDescending(r => r.RegistrationTime);
|
||
|
||
var result = await query.ToPagedListAsync(input);
|
||
|
||
if (result.Rows.Any())
|
||
{
|
||
var registrationIds = result.Rows.Select(r => r.Id).ToList();
|
||
var items = await _registrationItemRepository.AsQueryable()
|
||
.Where(i => registrationIds.Contains(i.RegistrationId) && !i.DeleteMark)
|
||
.ToListAsync();
|
||
|
||
var itemsByRegistrationId = items.GroupBy(i => i.RegistrationId)
|
||
.ToDictionary(g => g.Key, g => string.Join("、", g.Select(i => i.ProjectName)));
|
||
|
||
foreach (var row in result.Rows)
|
||
{
|
||
if (itemsByRegistrationId.TryGetValue(row.Id, out var projectNames))
|
||
{
|
||
row.ProjectNames = projectNames;
|
||
}
|
||
}
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
private string MaskMobile(string mobile)
|
||
{
|
||
if (string.IsNullOrEmpty(mobile) || mobile.Length < 7) return mobile;
|
||
return mobile.Substring(0, 3) + "****" + mobile.Substring(7);
|
||
}
|
||
}
|