fix: 微信注册软删除占坑与字段过长导致保存失败

fix: 微信注册软删除占坑与字段过长导致保存失败
This commit is contained in:
biybuy 2026-07-11 10:20:44 +08:00 committed by GitHub
commit 4fd5fae482
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 153 additions and 14 deletions

View File

@ -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(

View File

@ -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];
}
}

View File

@ -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>

View File

@ -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)

View File

@ -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("邮箱已存在");
} }