fix: 微信注册软删除占坑与字段过长导致保存失败
fix: 微信注册软删除占坑与字段过长导致保存失败
This commit is contained in:
commit
4fd5fae482
@ -69,7 +69,65 @@ public static class OmsRbacRegistrationGuard
|
|||||||
return new BusinessException("账号信息已存在,请直接绑定或更换手机号/邮箱");
|
return new BusinessException("账号信息已存在,请直接绑定或更换手机号/邮箱");
|
||||||
}
|
}
|
||||||
|
|
||||||
return new BusinessException("注册失败,请稍后重试或联系客服");
|
if (message.Contains("Data too long", StringComparison.OrdinalIgnoreCase)
|
||||||
|
|| message.Contains("1406", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
if (message.Contains("Avatar", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return new BusinessException("微信头像地址过长,请稍后重试或联系客服");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.Contains("Nickname", StringComparison.OrdinalIgnoreCase)
|
||||||
|
|| message.Contains("CustomerName", StringComparison.OrdinalIgnoreCase)
|
||||||
|
|| message.Contains("Name", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return new BusinessException("客户名称或微信昵称过长,请修改后重试");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new BusinessException("注册信息字段过长,请缩短客户名称后重试");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.Contains("foreign key constraint fails", StringComparison.OrdinalIgnoreCase)
|
||||||
|
|| message.Contains("1452", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return new BusinessException("客户角色未正确初始化,请联系管理员");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.Contains("Cannot insert duplicate key", StringComparison.OrdinalIgnoreCase)
|
||||||
|
|| message.Contains("2627", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return new BusinessException("账号信息已存在,请直接绑定或更换手机号/邮箱");
|
||||||
|
}
|
||||||
|
|
||||||
|
var reason = ExtractActionableReason(ex);
|
||||||
|
return new BusinessException($"注册失败:{reason}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ExtractActionableReason(Exception ex)
|
||||||
|
{
|
||||||
|
var parts = new List<string>();
|
||||||
|
for (var current = ex; current != null; current = current.InnerException)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(current.Message))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current.Message.Contains("saving the entity changes", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
parts.Add(current.Message.Trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
var reason = parts.LastOrDefault();
|
||||||
|
if (string.IsNullOrWhiteSpace(reason))
|
||||||
|
{
|
||||||
|
return "请稍后重试或联系客服";
|
||||||
|
}
|
||||||
|
|
||||||
|
return reason.Length <= 160 ? reason : reason[..160];
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<bool> ExistsActiveUserByAccountAsync(
|
private static async Task<bool> ExistsActiveUserByAccountAsync(
|
||||||
|
|||||||
@ -0,0 +1,31 @@
|
|||||||
|
namespace Oms.Application.Shared;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 微信注册字段裁剪,避免超出库表长度触发保存失败。
|
||||||
|
/// </summary>
|
||||||
|
public static class WeChatRegistrationFieldNormalizer
|
||||||
|
{
|
||||||
|
public const int CustomerNameMaxLength = 128;
|
||||||
|
public const int PhoneMaxLength = 16;
|
||||||
|
public const int EmailMaxLength = 64;
|
||||||
|
public const int AvatarMaxLength = 255;
|
||||||
|
public const int NicknameMaxLength = 64;
|
||||||
|
public const int OpenidMaxLength = 64;
|
||||||
|
|
||||||
|
public static string TruncateRequired(string value, int maxLength)
|
||||||
|
{
|
||||||
|
var normalized = value.Trim();
|
||||||
|
return normalized.Length <= maxLength ? normalized : normalized[..maxLength];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string? TruncateOptional(string? value, int maxLength)
|
||||||
|
{
|
||||||
|
var normalized = value?.Trim();
|
||||||
|
if (string.IsNullOrWhiteSpace(normalized))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return normalized.Length <= maxLength ? normalized : normalized[..maxLength];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -15,6 +15,12 @@ public interface ICustomerRepository : IRepository<Customer>
|
|||||||
|
|
||||||
Task<bool> ExistsPhoneAsync(string phone, CancellationToken cancellationToken = default);
|
Task<bool> ExistsPhoneAsync(string phone, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
|
Task<bool> ExistsPhoneAnyAsync(string phone, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
|
Task<bool> ExistsEmailAnyAsync(string email, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
|
Task<bool> ExistsWechatOpenidAnyAsync(string wechatOpenid, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查询指定前缀(WyyMM)下已用顺序号的最大值。
|
/// 查询指定前缀(WyyMM)下已用顺序号的最大值。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -32,6 +32,33 @@ public class CustomerRepository : OmsSqlSugarRepository<Customer>, ICustomerRepo
|
|||||||
return AnyAsync(x => x.Phone == phone, cancellationToken);
|
return AnyAsync(x => x.Phone == phone, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<bool> ExistsPhoneAnyAsync(string phone, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var db = await GetDbContextAsync(cancellationToken);
|
||||||
|
var hit = await db.Ado.SqlQuerySingleAsync<int?>(
|
||||||
|
"SELECT 1 FROM t_customer WHERE Phone = @phone LIMIT 1",
|
||||||
|
new { phone });
|
||||||
|
return hit.HasValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> ExistsEmailAnyAsync(string email, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var db = await GetDbContextAsync(cancellationToken);
|
||||||
|
var hit = await db.Ado.SqlQuerySingleAsync<int?>(
|
||||||
|
"SELECT 1 FROM t_customer WHERE Email = @email LIMIT 1",
|
||||||
|
new { email });
|
||||||
|
return hit.HasValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> ExistsWechatOpenidAnyAsync(string wechatOpenid, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var db = await GetDbContextAsync(cancellationToken);
|
||||||
|
var hit = await db.Ado.SqlQuerySingleAsync<int?>(
|
||||||
|
"SELECT 1 FROM t_customer WHERE WechatOpenid = @wechatOpenid LIMIT 1",
|
||||||
|
new { wechatOpenid });
|
||||||
|
return hit.HasValue;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<int> GetMaxCustomerCodeSequenceForPrefixAsync(
|
public async Task<int> GetMaxCustomerCodeSequenceForPrefixAsync(
|
||||||
string prefix,
|
string prefix,
|
||||||
CancellationToken cancellationToken = default)
|
CancellationToken cancellationToken = default)
|
||||||
|
|||||||
@ -7,6 +7,7 @@ using Fake.Rbac.Infrastructure;
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using Oms.Application.Shared;
|
using Oms.Application.Shared;
|
||||||
using Oms.Domain.CustomersAggregate.Entities;
|
using Oms.Domain.CustomersAggregate.Entities;
|
||||||
using Oms.Domain.CustomersAggregate.Enums;
|
using Oms.Domain.CustomersAggregate.Enums;
|
||||||
@ -26,7 +27,8 @@ public class WeChatCustomerService(
|
|||||||
ICustomerRepository customerRepository,
|
ICustomerRepository customerRepository,
|
||||||
UserService userService,
|
UserService userService,
|
||||||
RoleService roleService,
|
RoleService roleService,
|
||||||
FakeRbacDbContext rbacDbContext) : ApplicationService
|
FakeRbacDbContext rbacDbContext,
|
||||||
|
ILogger<WeChatCustomerService> logger) : ApplicationService
|
||||||
{
|
{
|
||||||
private const string CustomerRoleCode = "Customer";
|
private const string CustomerRoleCode = "Customer";
|
||||||
|
|
||||||
@ -80,17 +82,32 @@ public class WeChatCustomerService(
|
|||||||
{
|
{
|
||||||
ValidateWechatProfile(input.Wechat);
|
ValidateWechatProfile(input.Wechat);
|
||||||
|
|
||||||
var customerName = NormalizeRequired(input.CustomerName, "客户名称");
|
var customerName = WeChatRegistrationFieldNormalizer.TruncateRequired(
|
||||||
var phone = NormalizeRequired(input.Phone, "手机号");
|
NormalizeRequired(input.CustomerName, "客户名称"),
|
||||||
var email = NormalizeRequired(input.Email, "邮箱");
|
WeChatRegistrationFieldNormalizer.CustomerNameMaxLength);
|
||||||
|
var phone = WeChatRegistrationFieldNormalizer.TruncateRequired(
|
||||||
|
NormalizeRequired(input.Phone, "手机号"),
|
||||||
|
WeChatRegistrationFieldNormalizer.PhoneMaxLength);
|
||||||
|
var email = WeChatRegistrationFieldNormalizer.TruncateRequired(
|
||||||
|
NormalizeRequired(input.Email, "邮箱"),
|
||||||
|
WeChatRegistrationFieldNormalizer.EmailMaxLength);
|
||||||
var password = NormalizeRequired(input.Password, "密码");
|
var password = NormalizeRequired(input.Password, "密码");
|
||||||
|
var wechatOpenid = WeChatRegistrationFieldNormalizer.TruncateRequired(
|
||||||
|
input.Wechat.Openid.Trim(),
|
||||||
|
WeChatRegistrationFieldNormalizer.OpenidMaxLength);
|
||||||
|
var wechatNickname = WeChatRegistrationFieldNormalizer.TruncateOptional(
|
||||||
|
input.Wechat.Nickname,
|
||||||
|
WeChatRegistrationFieldNormalizer.NicknameMaxLength);
|
||||||
|
var wechatAvatar = WeChatRegistrationFieldNormalizer.TruncateOptional(
|
||||||
|
input.Wechat.Avatar,
|
||||||
|
WeChatRegistrationFieldNormalizer.AvatarMaxLength);
|
||||||
|
|
||||||
if (password.Length < 6)
|
if (password.Length < 6)
|
||||||
{
|
{
|
||||||
throw new BusinessException("密码长度不能少于6位");
|
throw new BusinessException("密码长度不能少于6位");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (await customerRepository.GetByWechatOpenidAsync(input.Wechat.Openid, cancellationToken) != null)
|
if (await customerRepository.ExistsWechatOpenidAnyAsync(wechatOpenid, cancellationToken))
|
||||||
{
|
{
|
||||||
throw new BusinessException("当前微信已绑定账号");
|
throw new BusinessException("当前微信已绑定账号");
|
||||||
}
|
}
|
||||||
@ -109,11 +126,10 @@ public class WeChatCustomerService(
|
|||||||
Account = phone,
|
Account = phone,
|
||||||
Password = password,
|
Password = password,
|
||||||
Email = email,
|
Email = email,
|
||||||
Avatar = NormalizeOptional(input.Wechat.Avatar),
|
Avatar = wechatAvatar,
|
||||||
RoleIds = []
|
RoleIds = [customerRoleId]
|
||||||
});
|
});
|
||||||
|
|
||||||
await userService.AssignRolesAsync(user.Id, [customerRoleId]);
|
|
||||||
var userId = await GetRbacUserMapIdOrThrowAsync(user.Id, cancellationToken);
|
var userId = await GetRbacUserMapIdOrThrowAsync(user.Id, cancellationToken);
|
||||||
var entity = new Customer
|
var entity = new Customer
|
||||||
{
|
{
|
||||||
@ -123,9 +139,9 @@ public class WeChatCustomerService(
|
|||||||
Phone = phone,
|
Phone = phone,
|
||||||
Email = email,
|
Email = email,
|
||||||
Password = OmsPasswordHelper.ToMd5(password),
|
Password = OmsPasswordHelper.ToMd5(password),
|
||||||
WechatOpenid = input.Wechat.Openid,
|
WechatOpenid = wechatOpenid,
|
||||||
WechatNickname = NormalizeOptional(input.Wechat.Nickname),
|
WechatNickname = wechatNickname,
|
||||||
WechatAvatar = NormalizeOptional(input.Wechat.Avatar),
|
WechatAvatar = wechatAvatar,
|
||||||
Status = CustomerStatus.Normal
|
Status = CustomerStatus.Normal
|
||||||
};
|
};
|
||||||
await customerRepository.InsertAsync(entity);
|
await customerRepository.InsertAsync(entity);
|
||||||
@ -137,6 +153,7 @@ public class WeChatCustomerService(
|
|||||||
await TryRollbackRbacUserAsync(user.Id);
|
await TryRollbackRbacUserAsync(user.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.LogWarning(ex, "微信客户注册失败: phone={Phone}, email={Email}, openid={Openid}", phone, email, wechatOpenid);
|
||||||
throw ex is BusinessException ? ex : OmsRbacRegistrationGuard.ToSaveBusinessException(ex);
|
throw ex is BusinessException ? ex : OmsRbacRegistrationGuard.ToSaveBusinessException(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -207,12 +224,12 @@ public class WeChatCustomerService(
|
|||||||
throw new BusinessException("客户编号已存在");
|
throw new BusinessException("客户编号已存在");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (await customerRepository.GetByPhoneAsync(phone, cancellationToken) != null)
|
if (await customerRepository.ExistsPhoneAnyAsync(phone, cancellationToken))
|
||||||
{
|
{
|
||||||
throw new BusinessException("手机号已存在");
|
throw new BusinessException("手机号已存在");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (await customerRepository.GetByEmailAsync(email, cancellationToken) != null)
|
if (await customerRepository.ExistsEmailAnyAsync(email, cancellationToken))
|
||||||
{
|
{
|
||||||
throw new BusinessException("邮箱已存在");
|
throw new BusinessException("邮箱已存在");
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user