feat: 完成ai message、session搭建
This commit is contained in:
@@ -0,0 +1,15 @@
|
|||||||
|
using Volo.Abp.Application.Dtos;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AiHub.Application.Contracts.Dtos;
|
||||||
|
|
||||||
|
public class MessageDto : FullAuditedEntityDto<Guid>
|
||||||
|
{
|
||||||
|
public Guid UserId { get; set; }
|
||||||
|
public Guid SessionId { get; set; }
|
||||||
|
public string Content { get; set; }
|
||||||
|
public string Role { get; set; }
|
||||||
|
public decimal DeductCost { get; set; }
|
||||||
|
public decimal TotalTokens { get; set; }
|
||||||
|
public string ModelId { get; set; }
|
||||||
|
public string Remark { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using Yi.Framework.Ddd.Application.Contracts;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AiHub.Application.Contracts.Dtos;
|
||||||
|
|
||||||
|
public class MessageGetListInput:PagedAllResultRequestDto
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public Guid SessionId { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
namespace Yi.Framework.AiHub.Application.Contracts.Dtos;
|
||||||
|
|
||||||
|
public class MessageInputDto
|
||||||
|
{
|
||||||
|
public string Content { get; set; }
|
||||||
|
public string Role { get; set; }
|
||||||
|
public decimal DeductCost { get; set; }
|
||||||
|
public decimal TotalTokens { get; set; }
|
||||||
|
public string ModelId { get; set; }
|
||||||
|
public string Remark { get; set; }
|
||||||
|
}
|
||||||
@@ -4,6 +4,8 @@ public class SendMessageInput
|
|||||||
{
|
{
|
||||||
public List<Message> Messages { get; set; }
|
public List<Message> Messages { get; set; }
|
||||||
public string Model { get; set; }
|
public string Model { get; set; }
|
||||||
|
|
||||||
|
public Guid? SessionId{ get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Message
|
public class Message
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
using Volo.Abp.Application.Dtos;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AiHub.Application.Contracts.Dtos;
|
||||||
|
|
||||||
|
public class SessionDto : FullAuditedEntityDto<Guid>
|
||||||
|
{
|
||||||
|
public string SessionTitle { get; set; }
|
||||||
|
public string SessionContent { get; set; }
|
||||||
|
public string Remark { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace Yi.Framework.AiHub.Application.Contracts.Dtos;
|
||||||
|
|
||||||
|
public class SessionGetListInput
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
namespace Yi.Framework.AiHub.Application.Contracts.Dtos;
|
||||||
|
|
||||||
|
public class SessionInputDto
|
||||||
|
{
|
||||||
|
public Guid UserId { get; set; }
|
||||||
|
public string SessionTitle { get; set; }
|
||||||
|
public string SessionContent { get; set; }
|
||||||
|
public string Remark { get; set; }
|
||||||
|
}
|
||||||
@@ -6,21 +6,28 @@ using Newtonsoft.Json;
|
|||||||
using Newtonsoft.Json.Serialization;
|
using Newtonsoft.Json.Serialization;
|
||||||
using OpenAI.Chat;
|
using OpenAI.Chat;
|
||||||
using Volo.Abp.Application.Services;
|
using Volo.Abp.Application.Services;
|
||||||
|
using Volo.Abp.Users;
|
||||||
using Yi.Framework.AiHub.Application.Contracts.Dtos;
|
using Yi.Framework.AiHub.Application.Contracts.Dtos;
|
||||||
using Yi.Framework.AiHub.Application.Contracts.Options;
|
using Yi.Framework.AiHub.Application.Contracts.Options;
|
||||||
using Yi.Framework.AiHub.Domain.Managers;
|
using Yi.Framework.AiHub.Domain.Managers;
|
||||||
|
|
||||||
namespace Yi.Framework.AiHub.Application.Services;
|
namespace Yi.Framework.AiHub.Application.Services;
|
||||||
|
|
||||||
public class AiService : ApplicationService
|
/// <summary>
|
||||||
|
/// ai服务
|
||||||
|
/// </summary>
|
||||||
|
public class AiChatService : ApplicationService
|
||||||
{
|
{
|
||||||
private readonly AiGateWayOptions _options;
|
private readonly AiGateWayOptions _options;
|
||||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||||
|
private readonly AiMessageManager _aiMessageManager;
|
||||||
|
|
||||||
public AiService(IOptions<AiGateWayOptions> options, IHttpContextAccessor httpContextAccessor)
|
public AiChatService(IOptions<AiGateWayOptions> options, IHttpContextAccessor httpContextAccessor,
|
||||||
|
AiMessageManager aiMessageManager)
|
||||||
{
|
{
|
||||||
_options = options.Value;
|
_options = options.Value;
|
||||||
this._httpContextAccessor = httpContextAccessor;
|
this._httpContextAccessor = httpContextAccessor;
|
||||||
|
_aiMessageManager = aiMessageManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -75,7 +82,7 @@ public class AiService : ApplicationService
|
|||||||
}
|
}
|
||||||
|
|
||||||
var gateWay = LazyServiceProvider.GetRequiredService<AiGateWayManager>();
|
var gateWay = LazyServiceProvider.GetRequiredService<AiGateWayManager>();
|
||||||
var completeChatResponse = gateWay.CompleteChatAsync(input.Model, history,cancellationToken);
|
var completeChatResponse = gateWay.CompleteChatAsync(input.Model, history, cancellationToken);
|
||||||
await using var writer = new StreamWriter(response.Body, Encoding.UTF8, leaveOpen: true);
|
await using var writer = new StreamWriter(response.Body, Encoding.UTF8, leaveOpen: true);
|
||||||
await foreach (var data in completeChatResponse)
|
await foreach (var data in completeChatResponse)
|
||||||
{
|
{
|
||||||
@@ -88,10 +95,24 @@ public class AiService : ApplicationService
|
|||||||
await writer.WriteLineAsync($"data: {message}\n");
|
await writer.WriteLineAsync($"data: {message}\n");
|
||||||
await writer.FlushAsync(cancellationToken); // 确保立即推送数据
|
await writer.FlushAsync(cancellationToken); // 确保立即推送数据
|
||||||
}
|
}
|
||||||
|
|
||||||
//断开连接
|
//断开连接
|
||||||
await writer.WriteLineAsync($"data: done\n");
|
await writer.WriteLineAsync($"data: done\n");
|
||||||
await writer.FlushAsync(cancellationToken); // 确保立即推送数据
|
await writer.FlushAsync(cancellationToken); // 确保立即推送数据
|
||||||
|
|
||||||
|
if (CurrentUser.IsAuthenticated && input.SessionId.HasValue)
|
||||||
|
{
|
||||||
|
// 等待接入token
|
||||||
|
// await _aiMessageManager.CreateMessageAsync(CurrentUser.GetId(), input.SessionId.Value, new MessageInputDto
|
||||||
|
// {
|
||||||
|
// Content = null,
|
||||||
|
// Role = null,
|
||||||
|
// DeductCost = 0,
|
||||||
|
// TotalTokens = 0,
|
||||||
|
// ModelId = null,
|
||||||
|
// Remark = null
|
||||||
|
// });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
using Mapster;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using SqlSugar;
|
||||||
|
using Volo.Abp.Application.Dtos;
|
||||||
|
using Volo.Abp.Application.Services;
|
||||||
|
using Volo.Abp.Users;
|
||||||
|
using Yi.Framework.AiHub.Application.Contracts.Dtos;
|
||||||
|
using Yi.Framework.AiHub.Domain.Entities;
|
||||||
|
using Yi.Framework.SqlSugarCore.Abstractions;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AiHub.Application.Services;
|
||||||
|
|
||||||
|
public class MessageService : ApplicationService
|
||||||
|
{
|
||||||
|
private readonly ISqlSugarRepository<MessageAggregateRoot> _repository;
|
||||||
|
|
||||||
|
public MessageService(ISqlSugarRepository<MessageAggregateRoot> repository)
|
||||||
|
{
|
||||||
|
_repository = repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查询消息
|
||||||
|
/// 需要会话id
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[Authorize]
|
||||||
|
public async Task<PagedResultDto<MessageDto>> GetListAsync(MessageGetListInput input)
|
||||||
|
{
|
||||||
|
RefAsync<int> total = 0;
|
||||||
|
var userId = CurrentUser.GetId();
|
||||||
|
var entities = await _repository._DbQueryable
|
||||||
|
.Where(x => x.SessionId == input.SessionId)
|
||||||
|
.Where(x=>x.UserId == userId)
|
||||||
|
.OrderByDescending(x => x.Id)
|
||||||
|
.ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
|
||||||
|
return new PagedResultDto<MessageDto>(total, entities.Adapt<List<MessageDto>>());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
using Mapster;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Volo.Abp.Application.Dtos;
|
||||||
|
using Volo.Abp.Application.Services;
|
||||||
|
using Volo.Abp.Domain.Repositories;
|
||||||
|
using Volo.Abp.Users;
|
||||||
|
using Yi.Framework.AiHub.Application.Contracts.Dtos;
|
||||||
|
using Yi.Framework.AiHub.Domain.Entities;
|
||||||
|
using Yi.Framework.SqlSugarCore.Abstractions;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AiHub.Application.Services;
|
||||||
|
|
||||||
|
public class SessionService : CrudAppService<SessionAggregateRoot, SessionDto, Guid, SessionGetListInput>
|
||||||
|
{
|
||||||
|
private readonly ISqlSugarRepository<SessionAggregateRoot, Guid> _repository;
|
||||||
|
public readonly ISqlSugarRepository<MessageAggregateRoot, Guid> _messageRepository;
|
||||||
|
public SessionService(ISqlSugarRepository<SessionAggregateRoot, Guid> repository, ISqlSugarRepository<MessageAggregateRoot, Guid> messageRepository) : base(repository)
|
||||||
|
{
|
||||||
|
_repository = repository;
|
||||||
|
_messageRepository = messageRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建会话
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[Authorize]
|
||||||
|
public override async Task<SessionDto> CreateAsync(SessionDto input)
|
||||||
|
{
|
||||||
|
var entity = await MapToEntityAsync(input);
|
||||||
|
entity.UserId = CurrentUser.GetId();
|
||||||
|
await _repository.InsertAsync(entity);
|
||||||
|
return entity.Adapt<SessionDto>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 详情会话
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[Authorize]
|
||||||
|
public override Task<SessionDto> GetAsync(Guid id)
|
||||||
|
{
|
||||||
|
return base.GetAsync(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 编辑会话
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id"></param>
|
||||||
|
/// <param name="input"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[Authorize]
|
||||||
|
public override Task<SessionDto> UpdateAsync(Guid id, SessionDto input)
|
||||||
|
{
|
||||||
|
return base.UpdateAsync(id, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 删除会话
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[Authorize]
|
||||||
|
public override async Task DeleteAsync(Guid id)
|
||||||
|
{
|
||||||
|
await base.DeleteAsync(id);
|
||||||
|
//对应的消息一起删除
|
||||||
|
await _messageRepository.DeleteAsync(x => x.SessionId == id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查询会话
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[Authorize]
|
||||||
|
public override Task<PagedResultDto<SessionDto>> GetListAsync(SessionGetListInput input)
|
||||||
|
{
|
||||||
|
return base.GetListAsync(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
using SqlSugar;
|
||||||
|
using Volo.Abp.Domain.Entities.Auditing;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AiHub.Domain.Entities;
|
||||||
|
|
||||||
|
[SugarTable("Ai_Message")]
|
||||||
|
[SugarIndex($"index_{{table}}_{nameof(UserId)}", $"{nameof(UserId)}", OrderByType.Asc)]
|
||||||
|
public class MessageAggregateRoot : FullAuditedAggregateRoot<Guid>
|
||||||
|
{
|
||||||
|
public MessageAggregateRoot()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageAggregateRoot(Guid userId, Guid sessionId, string content, string role, string modelId)
|
||||||
|
{
|
||||||
|
UserId = userId;
|
||||||
|
SessionId = sessionId;
|
||||||
|
Content = content;
|
||||||
|
Role = role;
|
||||||
|
ModelId = modelId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Guid UserId { get; set; }
|
||||||
|
public Guid SessionId { get; set; }
|
||||||
|
public string Content { get; set; }
|
||||||
|
public string Role { get; set; }
|
||||||
|
public decimal DeductCost { get; set; }
|
||||||
|
public decimal TotalTokens { get; set; }
|
||||||
|
public string ModelId { get; set; }
|
||||||
|
public string Remark { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using SqlSugar;
|
||||||
|
using Volo.Abp.Domain.Entities.Auditing;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AiHub.Domain.Entities;
|
||||||
|
|
||||||
|
[SugarTable("Ai_Session")]
|
||||||
|
[SugarIndex($"index_{{table}}_{nameof(UserId)}",$"{nameof(UserId)}", OrderByType.Asc)]
|
||||||
|
public class SessionAggregateRoot : FullAuditedAggregateRoot<Guid>
|
||||||
|
{
|
||||||
|
public Guid UserId { get; set; }
|
||||||
|
public string SessionTitle { get; set; }
|
||||||
|
public string SessionContent { get; set; }
|
||||||
|
public string Remark { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
using Volo.Abp.Domain.Services;
|
||||||
|
using Volo.Abp.Users;
|
||||||
|
using Yi.Framework.AiHub.Application.Contracts.Dtos;
|
||||||
|
using Yi.Framework.AiHub.Domain.Entities;
|
||||||
|
using Yi.Framework.SqlSugarCore.Abstractions;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AiHub.Domain.Managers;
|
||||||
|
|
||||||
|
public class AiMessageManager : DomainService
|
||||||
|
{
|
||||||
|
private readonly ISqlSugarRepository<MessageAggregateRoot> _repository;
|
||||||
|
|
||||||
|
public AiMessageManager(ISqlSugarRepository<MessageAggregateRoot> repository)
|
||||||
|
{
|
||||||
|
_repository = repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建消息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sessionId"></param>
|
||||||
|
/// <param name="userId"></param>
|
||||||
|
/// <param name="input"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task CreateMessageAsync(Guid userId, Guid sessionId, MessageInputDto input)
|
||||||
|
{
|
||||||
|
var message = new MessageAggregateRoot(userId, sessionId, input.Content, input.Role, input.ModelId);
|
||||||
|
await _repository.InsertAsync(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,7 +10,7 @@ namespace Yi.Framework.Rbac.Application.Contracts.IServices
|
|||||||
Task<UserRoleMenuDto> GetAsync();
|
Task<UserRoleMenuDto> GetAsync();
|
||||||
Task<CaptchaImageDto> GetCaptchaImageAsync();
|
Task<CaptchaImageDto> GetCaptchaImageAsync();
|
||||||
Task<LoginOutputDto> PostLoginAsync(LoginInputVo input);
|
Task<LoginOutputDto> PostLoginAsync(LoginInputVo input);
|
||||||
Task PostRegisterAsync(RegisterDto input);
|
Task<LoginOutputDto> PostRegisterAsync(RegisterDto input);
|
||||||
Task<bool> RestPasswordAsync(Guid userId, RestPasswordDto input);
|
Task<bool> RestPasswordAsync(Guid userId, RestPasswordDto input);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -25,7 +25,7 @@ namespace Yi.Framework.Rbac.Application.Contracts.IServices
|
|||||||
/// <param name="userName"></param>
|
/// <param name="userName"></param>
|
||||||
/// <param name="phone"></param>
|
/// <param name="phone"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<UserRoleMenuDto?> GetAsync(string? userName,long? phone);
|
Task<UserRoleMenuDto?> GetAsync(string? userName, long? phone);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 校验电话验证码,需要与电话号码绑定
|
/// 校验电话验证码,需要与电话号码绑定
|
||||||
@@ -40,4 +40,4 @@ namespace Yi.Framework.Rbac.Application.Contracts.IServices
|
|||||||
/// <param name="input"></param>
|
/// <param name="input"></param>
|
||||||
Task PostTempRegisterAsync(RegisterDto input);
|
Task PostTempRegisterAsync(RegisterDto input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,11 +5,7 @@ using Microsoft.AspNetCore.Authorization;
|
|||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.Extensions.Caching.Distributed;
|
using Microsoft.Extensions.Caching.Distributed;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using SqlSugar;
|
|
||||||
using Volo.Abp;
|
|
||||||
using Volo.Abp.Application.Services;
|
using Volo.Abp.Application.Services;
|
||||||
using Volo.Abp.Authorization;
|
using Volo.Abp.Authorization;
|
||||||
using Volo.Abp.Caching;
|
using Volo.Abp.Caching;
|
||||||
@@ -81,8 +77,8 @@ namespace Yi.Framework.Rbac.Application.Services
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 校验图片登录验证码,无需和账号绑定
|
/// 校验图片登录验证码,无需和账号绑定
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RemoteService(isEnabled:false)]
|
[RemoteService(isEnabled: false)]
|
||||||
public void ValidationImageCaptcha(string? uuid,string? code )
|
private void ValidationImageCaptcha(string? uuid, string? code)
|
||||||
{
|
{
|
||||||
if (_rbacOptions.EnableCaptcha)
|
if (_rbacOptions.EnableCaptcha)
|
||||||
{
|
{
|
||||||
@@ -109,7 +105,7 @@ namespace Yi.Framework.Rbac.Application.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
//校验验证码
|
//校验验证码
|
||||||
ValidationImageCaptcha(input.Uuid,input.Code);
|
ValidationImageCaptcha(input.Uuid, input.Code);
|
||||||
|
|
||||||
UserAggregateRoot user = new();
|
UserAggregateRoot user = new();
|
||||||
//校验
|
//校验
|
||||||
@@ -174,7 +170,7 @@ namespace Yi.Framework.Rbac.Application.Services
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 验证电话号码
|
/// 验证电话号码
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="str_handset"></param>
|
/// <param name="phone"></param>
|
||||||
private async Task ValidationPhone(string phone)
|
private async Task ValidationPhone(string phone)
|
||||||
{
|
{
|
||||||
var res = Regex.IsMatch(phone, @"^\d{11}$");
|
var res = Regex.IsMatch(phone, @"^\d{11}$");
|
||||||
@@ -207,7 +203,7 @@ namespace Yi.Framework.Rbac.Application.Services
|
|||||||
{
|
{
|
||||||
return await PostCaptchaPhoneAsync(ValidationPhoneTypeEnum.RetrievePassword, input);
|
return await PostCaptchaPhoneAsync(ValidationPhoneTypeEnum.RetrievePassword, input);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 手机验证码-绑定
|
/// 手机验证码-绑定
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -219,20 +215,20 @@ namespace Yi.Framework.Rbac.Application.Services
|
|||||||
{
|
{
|
||||||
return await PostCaptchaPhoneAsync(ValidationPhoneTypeEnum.Bind, input);
|
return await PostCaptchaPhoneAsync(ValidationPhoneTypeEnum.Bind, input);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 手机验证码-需通过图形验证码
|
/// 手机验证码-需通过图形验证码
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[RemoteService(isEnabled:false)]
|
[RemoteService(isEnabled: false)]
|
||||||
private async Task<object> PostCaptchaPhoneAsync(ValidationPhoneTypeEnum validationPhoneType,
|
private async Task<object> PostCaptchaPhoneAsync(ValidationPhoneTypeEnum validationPhoneType,
|
||||||
PhoneCaptchaImageDto input)
|
PhoneCaptchaImageDto input)
|
||||||
{
|
{
|
||||||
//验证uuid 和 验证码
|
//验证uuid 和 验证码
|
||||||
ValidationImageCaptcha(input.Uuid,input.Code);
|
ValidationImageCaptcha(input.Uuid, input.Code);
|
||||||
|
|
||||||
await ValidationPhone(input.Phone);
|
await ValidationPhone(input.Phone);
|
||||||
|
|
||||||
if (validationPhoneType == ValidationPhoneTypeEnum.Register &&
|
if (validationPhoneType == ValidationPhoneTypeEnum.Register &&
|
||||||
await _userRepository.IsAnyAsync(x => x.Phone.ToString() == input.Phone))
|
await _userRepository.IsAnyAsync(x => x.Phone.ToString() == input.Phone))
|
||||||
{
|
{
|
||||||
@@ -310,7 +306,7 @@ namespace Yi.Framework.Rbac.Application.Services
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
[UnitOfWork]
|
[UnitOfWork]
|
||||||
public async Task PostRegisterAsync(RegisterDto input)
|
public async Task<LoginOutputDto> PostRegisterAsync(RegisterDto input)
|
||||||
{
|
{
|
||||||
if (_rbacOptions.EnableRegister == false)
|
if (_rbacOptions.EnableRegister == false)
|
||||||
{
|
{
|
||||||
@@ -321,20 +317,22 @@ namespace Yi.Framework.Rbac.Application.Services
|
|||||||
{
|
{
|
||||||
throw new UserFriendlyException("手机号不能为空");
|
throw new UserFriendlyException("手机号不能为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
//临时账号
|
//临时账号
|
||||||
if (input.UserName.StartsWith("ls_"))
|
if (input.UserName.StartsWith("ls_"))
|
||||||
{
|
{
|
||||||
throw new UserFriendlyException("注册账号不能以ls_字符开头");
|
throw new UserFriendlyException("注册账号不能以ls_字符开头");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_rbacOptions.EnableCaptcha)
|
if (_rbacOptions.EnableCaptcha)
|
||||||
{
|
{
|
||||||
//校验验证码,根据电话号码获取 value,比对验证码已经uuid
|
//校验验证码,根据电话号码获取 value,比对验证码已经uuid
|
||||||
await ValidationPhoneCaptchaAsync(ValidationPhoneTypeEnum.Register, input.Phone.Value, input.Code);
|
await ValidationPhoneCaptchaAsync(ValidationPhoneTypeEnum.Register, input.Phone.Value, input.Code);
|
||||||
}
|
}
|
||||||
|
|
||||||
//注册领域逻辑
|
//注册之后,免再次登录,直接给前端token
|
||||||
await _accountManager.RegisterAsync(input.UserName, input.Password, input.Phone, input.Nick);
|
var userId = await _accountManager.RegisterAsync(input.UserName, input.Password, input.Phone, input.Nick);
|
||||||
|
return await this.PostLoginAsync(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -342,7 +340,7 @@ namespace Yi.Framework.Rbac.Application.Services
|
|||||||
/// 不需要验证,为了给第三方使用,例如微信小程序,后续可通过绑定操作,进行账号合并
|
/// 不需要验证,为了给第三方使用,例如微信小程序,后续可通过绑定操作,进行账号合并
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="input"></param>
|
/// <param name="input"></param>
|
||||||
[RemoteService(isEnabled:false)]
|
[RemoteService(isEnabled: false)]
|
||||||
public async Task PostTempRegisterAsync(RegisterDto input)
|
public async Task PostTempRegisterAsync(RegisterDto input)
|
||||||
{
|
{
|
||||||
//注册领域逻辑
|
//注册领域逻辑
|
||||||
@@ -423,13 +421,17 @@ namespace Yi.Framework.Rbac.Application.Services
|
|||||||
{
|
{
|
||||||
//将后端菜单转换成前端路由,组件级别需要过滤
|
//将后端菜单转换成前端路由,组件级别需要过滤
|
||||||
output =
|
output =
|
||||||
ObjectMapper.Map<List<MenuDto>, List<MenuAggregateRoot>>(menus.Where(x=>x.MenuSource==MenuSourceEnum.Ruoyi).ToList()).Vue3RuoYiRouterBuild();
|
ObjectMapper
|
||||||
|
.Map<List<MenuDto>, List<MenuAggregateRoot>>(menus
|
||||||
|
.Where(x => x.MenuSource == MenuSourceEnum.Ruoyi).ToList()).Vue3RuoYiRouterBuild();
|
||||||
}
|
}
|
||||||
else if (routerType == "pure")
|
else if (routerType == "pure")
|
||||||
{
|
{
|
||||||
//将后端菜单转换成前端路由,组件级别需要过滤
|
//将后端菜单转换成前端路由,组件级别需要过滤
|
||||||
output =
|
output =
|
||||||
ObjectMapper.Map<List<MenuDto>, List<MenuAggregateRoot>>(menus.Where(x=>x.MenuSource==MenuSourceEnum.Pure).ToList()).Vue3PureRouterBuild();
|
ObjectMapper
|
||||||
|
.Map<List<MenuDto>, List<MenuAggregateRoot>>(menus
|
||||||
|
.Where(x => x.MenuSource == MenuSourceEnum.Pure).ToList()).Vue3PureRouterBuild();
|
||||||
}
|
}
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
|
|||||||
@@ -272,11 +272,12 @@ namespace Yi.Framework.Rbac.Domain.Managers
|
|||||||
/// <param name="password"></param>
|
/// <param name="password"></param>
|
||||||
/// <param name="phone"></param>
|
/// <param name="phone"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task RegisterAsync(string userName, string password, long? phone,string? nick)
|
public async Task<Guid> RegisterAsync(string userName, string password, long? phone,string? nick)
|
||||||
{
|
{
|
||||||
var user = new UserAggregateRoot(userName, password, phone,nick);
|
var user = new UserAggregateRoot(userName, password, phone,nick);
|
||||||
await _userManager.CreateAsync(user);
|
var userId=await _userManager.CreateAsync(user);
|
||||||
await _userManager.SetDefautRoleAsync(user.Id);
|
await _userManager.SetDefautRoleAsync(user.Id);
|
||||||
|
return userId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ namespace Yi.Framework.Rbac.Domain.Managers
|
|||||||
string CreateRefreshToken(Guid userId);
|
string CreateRefreshToken(Guid userId);
|
||||||
Task<string> GetTokenByUserIdAsync(Guid userId,Action<UserRoleMenuDto>? getUserInfo=null);
|
Task<string> GetTokenByUserIdAsync(Guid userId,Action<UserRoleMenuDto>? getUserInfo=null);
|
||||||
Task LoginValidationAsync(string userName, string password, Action<UserAggregateRoot>? userAction = null);
|
Task LoginValidationAsync(string userName, string password, Action<UserAggregateRoot>? userAction = null);
|
||||||
Task RegisterAsync(string userName, string password, long? phone,string? nick);
|
Task<Guid> RegisterAsync(string userName, string password, long? phone,string? nick);
|
||||||
Task<bool> RestPasswordAsync(Guid userId, string password);
|
Task<bool> RestPasswordAsync(Guid userId, string password);
|
||||||
Task UpdatePasswordAsync(Guid userId, string newPassword, string oldPassword);
|
Task UpdatePasswordAsync(Guid userId, string newPassword, string oldPassword);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,9 +29,16 @@ namespace Yi.Framework.Rbac.Domain.Managers
|
|||||||
private readonly IGuidGenerator _guidGenerator;
|
private readonly IGuidGenerator _guidGenerator;
|
||||||
private IUserRepository _userRepository;
|
private IUserRepository _userRepository;
|
||||||
private ILocalEventBus _localEventBus;
|
private ILocalEventBus _localEventBus;
|
||||||
public UserManager(ISqlSugarRepository<UserAggregateRoot> repository, ISqlSugarRepository<UserRoleEntity> repositoryUserRole, ISqlSugarRepository<UserPostEntity> repositoryUserPost, IGuidGenerator guidGenerator, IDistributedCache<UserInfoCacheItem, UserInfoCacheKey> userCache, IUserRepository userRepository, ILocalEventBus localEventBus, ISqlSugarRepository<RoleAggregateRoot> roleRepository) =>
|
|
||||||
(_repository, _repositoryUserRole, _repositoryUserPost, _guidGenerator, _userCache, _userRepository, _localEventBus, _roleRepository) =
|
public UserManager(ISqlSugarRepository<UserAggregateRoot> repository,
|
||||||
(repository, repositoryUserRole, repositoryUserPost, guidGenerator, userCache, userRepository, localEventBus, roleRepository);
|
ISqlSugarRepository<UserRoleEntity> repositoryUserRole,
|
||||||
|
ISqlSugarRepository<UserPostEntity> repositoryUserPost, IGuidGenerator guidGenerator,
|
||||||
|
IDistributedCache<UserInfoCacheItem, UserInfoCacheKey> userCache, IUserRepository userRepository,
|
||||||
|
ILocalEventBus localEventBus, ISqlSugarRepository<RoleAggregateRoot> roleRepository) =>
|
||||||
|
(_repository, _repositoryUserRole, _repositoryUserPost, _guidGenerator, _userCache, _userRepository,
|
||||||
|
_localEventBus, _roleRepository) =
|
||||||
|
(repository, repositoryUserRole, repositoryUserPost, guidGenerator, userCache, userRepository,
|
||||||
|
localEventBus, roleRepository);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 给用户设置角色
|
/// 给用户设置角色
|
||||||
@@ -56,6 +63,7 @@ namespace Yi.Framework.Rbac.Domain.Managers
|
|||||||
{
|
{
|
||||||
userRoleEntities.Add(new UserRoleEntity() { UserId = userId, RoleId = roleId });
|
userRoleEntities.Add(new UserRoleEntity() { UserId = userId, RoleId = roleId });
|
||||||
}
|
}
|
||||||
|
|
||||||
//一次性批量添加
|
//一次性批量添加
|
||||||
await _repositoryUserRole.InsertRangeAsync(userRoleEntities);
|
await _repositoryUserRole.InsertRangeAsync(userRoleEntities);
|
||||||
}
|
}
|
||||||
@@ -88,7 +96,6 @@ namespace Yi.Framework.Rbac.Domain.Managers
|
|||||||
//一次性批量添加
|
//一次性批量添加
|
||||||
await _repositoryUserPost.InsertRangeAsync(userPostEntities);
|
await _repositoryUserPost.InsertRangeAsync(userPostEntities);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,7 +103,7 @@ namespace Yi.Framework.Rbac.Domain.Managers
|
|||||||
/// 创建用户
|
/// 创建用户
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task CreateAsync(UserAggregateRoot userEntity)
|
public async Task<Guid> CreateAsync(UserAggregateRoot userEntity)
|
||||||
{
|
{
|
||||||
//校验用户名
|
//校验用户名
|
||||||
ValidateUserName(userEntity);
|
ValidateUserName(userEntity);
|
||||||
@@ -111,7 +118,6 @@ namespace Yi.Framework.Rbac.Domain.Managers
|
|||||||
if (await _repository.IsAnyAsync(x => x.Phone == userEntity.Phone))
|
if (await _repository.IsAnyAsync(x => x.Phone == userEntity.Phone))
|
||||||
{
|
{
|
||||||
throw new UserFriendlyException(UserConst.Phone_Repeat);
|
throw new UserFriendlyException(UserConst.Phone_Repeat);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,10 +129,8 @@ namespace Yi.Framework.Rbac.Domain.Managers
|
|||||||
|
|
||||||
var entity = await _repository.InsertReturnEntityAsync(userEntity);
|
var entity = await _repository.InsertReturnEntityAsync(userEntity);
|
||||||
|
|
||||||
userEntity = entity;
|
|
||||||
await _localEventBus.PublishAsync(new UserCreateEventArgs(entity.Id));
|
await _localEventBus.PublishAsync(new UserCreateEventArgs(entity.Id));
|
||||||
|
return entity.Id;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -174,37 +178,43 @@ namespace Yi.Framework.Rbac.Domain.Managers
|
|||||||
{
|
{
|
||||||
throw new AbpAuthorizationException();
|
throw new AbpAuthorizationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
//data.Menus.Clear();
|
//data.Menus.Clear();
|
||||||
// output = data;
|
// output = data;
|
||||||
return data;
|
return data;
|
||||||
// var output = await GetInfoByCacheAsync(userId);
|
// var output = await GetInfoByCacheAsync(userId);
|
||||||
// return output;
|
// return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<UserRoleMenuDto> GetInfoByCacheAsync(Guid userId)
|
private async Task<UserRoleMenuDto> GetInfoByCacheAsync(Guid userId)
|
||||||
{
|
{
|
||||||
//此处优先从缓存中获取
|
//此处优先从缓存中获取
|
||||||
UserRoleMenuDto output = null;
|
UserRoleMenuDto output = null;
|
||||||
var tokenExpiresMinuteTime = LazyServiceProvider.GetRequiredService<IOptions<JwtOptions>>().Value.ExpiresMinuteTime;
|
var tokenExpiresMinuteTime =
|
||||||
|
LazyServiceProvider.GetRequiredService<IOptions<JwtOptions>>().Value.ExpiresMinuteTime;
|
||||||
var cacheData = await _userCache.GetOrAddAsync(new UserInfoCacheKey(userId),
|
var cacheData = await _userCache.GetOrAddAsync(new UserInfoCacheKey(userId),
|
||||||
async () =>
|
async () =>
|
||||||
{
|
{
|
||||||
var user = await _userRepository.GetUserAllInfoAsync(userId);
|
var user = await _userRepository.GetUserAllInfoAsync(userId);
|
||||||
var data = EntityMapToDto(user);
|
var data = EntityMapToDto(user);
|
||||||
//系统用户数据被重置,老前端访问重新授权
|
//系统用户数据被重置,老前端访问重新授权
|
||||||
if (data is null)
|
if (data is null)
|
||||||
{
|
{
|
||||||
throw new AbpAuthorizationException();
|
throw new AbpAuthorizationException();
|
||||||
}
|
}
|
||||||
//data.Menus.Clear();
|
|
||||||
output = data;
|
//data.Menus.Clear();
|
||||||
return new UserInfoCacheItem(data);
|
output = data;
|
||||||
},
|
return new UserInfoCacheItem(data);
|
||||||
() => new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(tokenExpiresMinuteTime) });
|
},
|
||||||
|
() => new DistributedCacheEntryOptions
|
||||||
|
{ AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(tokenExpiresMinuteTime) });
|
||||||
|
|
||||||
if (cacheData is not null)
|
if (cacheData is not null)
|
||||||
{
|
{
|
||||||
output = cacheData.Info;
|
output = cacheData.Info;
|
||||||
}
|
}
|
||||||
|
|
||||||
return output!;
|
return output!;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,14 +231,13 @@ namespace Yi.Framework.Rbac.Domain.Managers
|
|||||||
{
|
{
|
||||||
output.Add(await GetInfoByCacheAsync(userId));
|
output.Add(await GetInfoByCacheAsync(userId));
|
||||||
}
|
}
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private UserRoleMenuDto EntityMapToDto(UserAggregateRoot user)
|
private UserRoleMenuDto EntityMapToDto(UserAggregateRoot user)
|
||||||
{
|
{
|
||||||
|
|
||||||
var userRoleMenu = new UserRoleMenuDto();
|
var userRoleMenu = new UserRoleMenuDto();
|
||||||
//首先获取到该用户全部信息,导航到角色、菜单,(菜单需要去重,完全交给Set来处理即可)
|
//首先获取到该用户全部信息,导航到角色、菜单,(菜单需要去重,完全交给Set来处理即可)
|
||||||
if (user is null)
|
if (user is null)
|
||||||
@@ -236,6 +245,7 @@ namespace Yi.Framework.Rbac.Domain.Managers
|
|||||||
//为了解决token前端缓存,后端数据库重新dbseed
|
//为了解决token前端缓存,后端数据库重新dbseed
|
||||||
throw new UserFriendlyException($"数据错误,查询用户不存在,请重新登录");
|
throw new UserFriendlyException($"数据错误,查询用户不存在,请重新登录");
|
||||||
}
|
}
|
||||||
|
|
||||||
user.EncryPassword.Password = string.Empty;
|
user.EncryPassword.Password = string.Empty;
|
||||||
user.EncryPassword.Salt = string.Empty;
|
user.EncryPassword.Salt = string.Empty;
|
||||||
|
|
||||||
@@ -264,6 +274,7 @@ namespace Yi.Framework.Rbac.Domain.Managers
|
|||||||
{
|
{
|
||||||
userRoleMenu.PermissionCodes.Add(menu.PermissionCode);
|
userRoleMenu.PermissionCodes.Add(menu.PermissionCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
userRoleMenu.Menus.Add(menu.Adapt<MenuDto>());
|
userRoleMenu.Menus.Add(menu.Adapt<MenuDto>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -279,5 +290,4 @@ namespace Yi.Framework.Rbac.Domain.Managers
|
|||||||
return userRoleMenu;
|
return userRoleMenu;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user