diff --git a/src/Oms.Application/Dtos/System/NoticeCreateInput.cs b/src/Oms.Application/Dtos/System/NoticeCreateInput.cs
index f7b4503..c9742ac 100644
--- a/src/Oms.Application/Dtos/System/NoticeCreateInput.cs
+++ b/src/Oms.Application/Dtos/System/NoticeCreateInput.cs
@@ -15,11 +15,10 @@ public class NoticeCreateInput
public string NoticeType { get; set; } = string.Empty;
///
- /// 标题。
+ /// 标题(公告必填;站内信可空)。
///
- [Required]
[StringLength(128)]
- public string Title { get; set; } = string.Empty;
+ public string? Title { get; set; }
///
/// 正文内容。
diff --git a/src/Oms.Application/Services/Customers/CustomerService.cs b/src/Oms.Application/Services/Customers/CustomerService.cs
index a4c8cb3..5af5acc 100644
--- a/src/Oms.Application/Services/Customers/CustomerService.cs
+++ b/src/Oms.Application/Services/Customers/CustomerService.cs
@@ -227,7 +227,54 @@ public class CustomerService : ApplicationService
public async Task DeleteAsync(IdInput input)
{
var entity = await GetCustomerOrThrowAsync(input.Id);
+
+ if (!entity.ParentCustomerId.HasValue
+ && await CustomerRepository.AnyAsync(x => x.ParentCustomerId == entity.Id))
+ {
+ throw new BusinessException("存在子客户,请先删除子客户");
+ }
+
await CustomerRepository.DeleteAsync(entity);
+ await DeleteLinkedRbacUserAsync(entity);
+ }
+
+ private async Task DeleteLinkedRbacUserAsync(Customer entity)
+ {
+ var userGuid = await GetRbacUserGuidByMapIdAsync(entity.UserId);
+ if (userGuid.HasValue && userGuid.Value != Guid.Empty)
+ {
+ await UserService.DeleteAsync(userGuid.Value);
+ }
+
+ if (entity.ParentCustomerId.HasValue)
+ {
+ await TryDeleteSubCustomerRoleAsync(entity.UserId);
+ }
+ }
+
+ private async Task GetRbacUserGuidByMapIdAsync(int mapId)
+ {
+ return await RbacDbContext.Database.SqlQuery(
+ $"select `Id` as `Value` from `user` where `userid` = {mapId} and `IsDeleted` = 0")
+ .FirstOrDefaultAsync();
+ }
+
+ private async Task TryDeleteSubCustomerRoleAsync(int userId)
+ {
+ try
+ {
+ var roles = await RoleService.GetAllRolesAsync();
+ var role = roles.FirstOrDefault(x =>
+ string.Equals(x.Code, $"CustomerSub_{userId}", StringComparison.OrdinalIgnoreCase));
+ if (role != null)
+ {
+ await RoleService.DeleteAsync(role.Id);
+ }
+ }
+ catch
+ {
+ // 子客户角色清理失败不阻断客户删除
+ }
}
///
diff --git a/src/Oms.Application/Services/System/NoticeService.cs b/src/Oms.Application/Services/System/NoticeService.cs
index 9393413..5b50b99 100644
--- a/src/Oms.Application/Services/System/NoticeService.cs
+++ b/src/Oms.Application/Services/System/NoticeService.cs
@@ -49,7 +49,17 @@ public class NoticeService : ApplicationService
[HttpGet("/system/notice/list")]
public async Task> GetListAsync([FromQuery] NoticeListInput input)
{
- var predicate = BuildListPredicate(input);
+ var receiverUserId = CurrentUser.GetId();
+ if (receiverUserId <= 0)
+ {
+ return new OmsPageResult { Items = [], Total = 0 };
+ }
+
+ var expectedReceiverType = OmsSessionHelper.IsCustomerLogin(CurrentUser)
+ ? ReceiverTypeCustomer
+ : ReceiverTypeUser;
+
+ var predicate = BuildListPredicate(input, receiverUserId, expectedReceiverType);
var pageIndex = OmsDocHelper.NormalizePage(input.Page);
var pageSize = OmsDocHelper.NormalizePageSize(input.PageSize);
var notices = await NoticeRepository.GetPagedListAsync(
@@ -106,12 +116,13 @@ public class NoticeService : ApplicationService
[HttpPost("/system/notice/create")]
public async Task CreateAsync(NoticeCreateInput input)
{
- ValidateNoticeText(input.Title, input.Content);
+ var noticeType = NormalizeNoticeType(input.NoticeType);
+ ValidateNoticeText(noticeType, input.Title, input.Content);
var receiverIds = await NormalizeAndValidateReceiverIdsAsync(input.ReceiverType, input.ReceiverIds);
await NoticeRepository.InsertAsync(new Notice
{
- NoticeType = NormalizeNoticeType(input.NoticeType),
- Title = input.Title.Trim(),
+ NoticeType = noticeType,
+ Title = NormalizeTitle(input.Title),
Content = input.Content.Trim(),
IsPopup = NormalizePopupValue(input.IsPopup),
ReceiverType = NormalizeReceiverType(input.ReceiverType),
@@ -126,10 +137,11 @@ public class NoticeService : ApplicationService
public async Task UpdateAsync(NoticeUpdateInput input)
{
var entity = await GetNoticeOrThrowAsync(input.Id);
- ValidateNoticeText(input.Title, input.Content);
+ var noticeType = NormalizeNoticeType(input.NoticeType);
+ ValidateNoticeText(noticeType, input.Title, input.Content);
var receiverIds = await NormalizeAndValidateReceiverIdsAsync(input.ReceiverType, input.ReceiverIds);
- entity.NoticeType = NormalizeNoticeType(input.NoticeType);
- entity.Title = input.Title.Trim();
+ entity.NoticeType = noticeType;
+ entity.Title = NormalizeTitle(input.Title);
entity.Content = input.Content.Trim();
entity.IsPopup = NormalizePopupValue(input.IsPopup);
entity.ReceiverType = NormalizeReceiverType(input.ReceiverType);
@@ -162,7 +174,7 @@ public class NoticeService : ApplicationService
{
var notice = await GetNoticeOrThrowAsync(input.Id);
var receiverIds = OmsDocHelper.DeserializeJson>(notice.ReceiverIds) ?? [];
- var currentReceiverType = ReceiverTypeUser;
+ var currentReceiverType = NormalizeReceiverType(notice.ReceiverType);
var currentReceiverId = CurrentUser.GetId();
if (currentReceiverId <= 0)
{
@@ -314,17 +326,26 @@ public class NoticeService : ApplicationService
return result;
}
- private static Expression> BuildListPredicate(NoticeListInput input)
+ private static Expression> BuildListPredicate(
+ NoticeListInput input,
+ int receiverUserId,
+ string expectedReceiverType)
{
var noticeType = input.NoticeType?.Trim();
var receiverType = input.ReceiverType?.Trim();
var keyword = input.Keyword?.Trim();
+ var receiverIdToken = receiverUserId.ToString();
return x =>
(string.IsNullOrWhiteSpace(noticeType) || x.NoticeType == noticeType) &&
(string.IsNullOrWhiteSpace(receiverType) || x.ReceiverType == receiverType) &&
(string.IsNullOrWhiteSpace(keyword) ||
x.Title.Contains(keyword) ||
- x.Content.Contains(keyword));
+ x.Content.Contains(keyword)) &&
+ x.ReceiverType == expectedReceiverType &&
+ (x.ReceiverIds == $"[{receiverIdToken}]" ||
+ x.ReceiverIds.StartsWith($"[{receiverIdToken},") ||
+ x.ReceiverIds.Contains($",{receiverIdToken},") ||
+ x.ReceiverIds.EndsWith($",{receiverIdToken}]"));
}
private async Task GetNoticeOrThrowAsync(int id)
@@ -397,9 +418,9 @@ public class NoticeService : ApplicationService
.ToListAsync();
}
- private static void ValidateNoticeText(string title, string content)
+ private static void ValidateNoticeText(string noticeType, string? title, string content)
{
- if (string.IsNullOrWhiteSpace(title))
+ if (noticeType == NoticeTypeNotice && string.IsNullOrWhiteSpace(title))
{
throw new BusinessException("通知标题不能为空");
}
@@ -410,6 +431,9 @@ public class NoticeService : ApplicationService
}
}
+ private static string NormalizeTitle(string? title) =>
+ string.IsNullOrWhiteSpace(title) ? string.Empty : title.Trim();
+
private static NoticeOutput MapNoticeOutput(Notice entity, int readCount, List receiverSelectionIds)
{
var receiverIds = OmsDocHelper.DeserializeJson>(entity.ReceiverIds) ?? [];