fix: 微信注册软删除占坑与字段过长导致保存失败
fix: 微信注册软删除占坑与字段过长导致保存失败
This commit is contained in:
commit
4fd5fae482
@ -69,7 +69,65 @@ public static class OmsRbacRegistrationGuard
|
||||
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(
|
||||
|
||||
@ -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> ExistsPhoneAnyAsync(string phone, CancellationToken cancellationToken = default);
|
||||
|
||||
Task<bool> ExistsEmailAnyAsync(string email, CancellationToken cancellationToken = default);
|
||||
|
||||
Task<bool> ExistsWechatOpenidAnyAsync(string wechatOpenid, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// 查询指定前缀(WyyMM)下已用顺序号的最大值。
|
||||
/// </summary>
|
||||
|
||||
@ -32,6 +32,33 @@ public class CustomerRepository : OmsSqlSugarRepository<Customer>, ICustomerRepo
|
||||
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(
|
||||
string prefix,
|
||||
CancellationToken cancellationToken = default)
|
||||
|
||||
@ -7,6 +7,7 @@ using Fake.Rbac.Infrastructure;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Oms.Application.Shared;
|
||||
using Oms.Domain.CustomersAggregate.Entities;
|
||||
using Oms.Domain.CustomersAggregate.Enums;
|
||||
@ -26,7 +27,8 @@ public class WeChatCustomerService(
|
||||
ICustomerRepository customerRepository,
|
||||
UserService userService,
|
||||
RoleService roleService,
|
||||
FakeRbacDbContext rbacDbContext) : ApplicationService
|
||||
FakeRbacDbContext rbacDbContext,
|
||||
ILogger<WeChatCustomerService> logger) : ApplicationService
|
||||
{
|
||||
private const string CustomerRoleCode = "Customer";
|
||||
|
||||
@ -80,17 +82,32 @@ public class WeChatCustomerService(
|
||||
{
|
||||
ValidateWechatProfile(input.Wechat);
|
||||
|
||||
var customerName = NormalizeRequired(input.CustomerName, "客户名称");
|
||||
var phone = NormalizeRequired(input.Phone, "手机号");
|
||||
var email = NormalizeRequired(input.Email, "邮箱");
|
||||
var customerName = WeChatRegistrationFieldNormalizer.TruncateRequired(
|
||||
NormalizeRequired(input.CustomerName, "客户名称"),
|
||||
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 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)
|
||||
{
|
||||
throw new BusinessException("密码长度不能少于6位");
|
||||
}
|
||||
|
||||
if (await customerRepository.GetByWechatOpenidAsync(input.Wechat.Openid, cancellationToken) != null)
|
||||
if (await customerRepository.ExistsWechatOpenidAnyAsync(wechatOpenid, cancellationToken))
|
||||
{
|
||||
throw new BusinessException("当前微信已绑定账号");
|
||||
}
|
||||
@ -109,11 +126,10 @@ public class WeChatCustomerService(
|
||||
Account = phone,
|
||||
Password = password,
|
||||
Email = email,
|
||||
Avatar = NormalizeOptional(input.Wechat.Avatar),
|
||||
RoleIds = []
|
||||
Avatar = wechatAvatar,
|
||||
RoleIds = [customerRoleId]
|
||||
});
|
||||
|
||||
await userService.AssignRolesAsync(user.Id, [customerRoleId]);
|
||||
var userId = await GetRbacUserMapIdOrThrowAsync(user.Id, cancellationToken);
|
||||
var entity = new Customer
|
||||
{
|
||||
@ -123,9 +139,9 @@ public class WeChatCustomerService(
|
||||
Phone = phone,
|
||||
Email = email,
|
||||
Password = OmsPasswordHelper.ToMd5(password),
|
||||
WechatOpenid = input.Wechat.Openid,
|
||||
WechatNickname = NormalizeOptional(input.Wechat.Nickname),
|
||||
WechatAvatar = NormalizeOptional(input.Wechat.Avatar),
|
||||
WechatOpenid = wechatOpenid,
|
||||
WechatNickname = wechatNickname,
|
||||
WechatAvatar = wechatAvatar,
|
||||
Status = CustomerStatus.Normal
|
||||
};
|
||||
await customerRepository.InsertAsync(entity);
|
||||
@ -137,6 +153,7 @@ public class WeChatCustomerService(
|
||||
await TryRollbackRbacUserAsync(user.Id);
|
||||
}
|
||||
|
||||
logger.LogWarning(ex, "微信客户注册失败: phone={Phone}, email={Email}, openid={Openid}", phone, email, wechatOpenid);
|
||||
throw ex is BusinessException ? ex : OmsRbacRegistrationGuard.ToSaveBusinessException(ex);
|
||||
}
|
||||
}
|
||||
@ -207,12 +224,12 @@ public class WeChatCustomerService(
|
||||
throw new BusinessException("客户编号已存在");
|
||||
}
|
||||
|
||||
if (await customerRepository.GetByPhoneAsync(phone, cancellationToken) != null)
|
||||
if (await customerRepository.ExistsPhoneAnyAsync(phone, cancellationToken))
|
||||
{
|
||||
throw new BusinessException("手机号已存在");
|
||||
}
|
||||
|
||||
if (await customerRepository.GetByEmailAsync(email, cancellationToken) != null)
|
||||
if (await customerRepository.ExistsEmailAnyAsync(email, cancellationToken))
|
||||
{
|
||||
throw new BusinessException("邮箱已存在");
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user