qinchaoyue 4 өдөр өмнө
parent
commit
5de1ee2b5c

+ 37 - 0
src/Hotline.Api/Controllers/Snapshot/SnapshotUserController.cs

@@ -0,0 +1,37 @@
+using Hotline.Application.Snapshot.Contracts;
+using Hotline.Repository.SqlSugar.Extensions;
+using Hotline.Share.Dtos;
+using Hotline.Share.Dtos.Snapshot;
+using Hotline.Share.Tools;
+using Microsoft.AspNetCore.Mvc;
+using System.ComponentModel;
+
+namespace Hotline.Api.Controllers.Snapshot;
+
+[Description("随手拍用户管理")]
+public class SnapshotUserController : BaseController
+{
+    private readonly ISnapshotUserApplication _snapshotUserApplication;
+
+    public SnapshotUserController(ISnapshotUserApplication snapshotUserApplication)
+    {
+        _snapshotUserApplication = snapshotUserApplication;
+    }
+
+    /// <summary>
+    /// 安全志愿者列表
+    /// </summary>
+    /// <returns></returns>
+    [HttpGet("citizen_relation")]
+    public async Task<PagedDto<CitizenRelationSafetyTypeOutDto>> GetCitizenRelationSafetyType([FromQuery] CitizenRelationSafetyTypeInDto dto)
+        => (await _snapshotUserApplication.GetCitizenRelationSafetyType(dto).ToPagedListAsync(dto)).ToPaged();
+
+    /// <summary>
+    /// 添加安全志愿者
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpPost("citizen_relation")]
+    public async Task AddCitizenRelationSafetyTypeInDto([FromBody]AddCitizenRelationSafetyTypeInDto dto)
+        => await _snapshotUserApplication.AddCitizenRelationSafetyType(dto, HttpContext.RequestAborted);
+}

+ 11 - 0
src/Hotline.Application/Snapshot/Contracts/ISnapshotUserApplication.cs

@@ -0,0 +1,11 @@
+using Hotline.Share.Dtos.Snapshot;
+using SqlSugar;
+
+namespace Hotline.Application.Snapshot.Contracts;
+
+public interface ISnapshotUserApplication
+{
+    ISugarQueryable<CitizenRelationSafetyTypeOutDto> GetCitizenRelationSafetyType(CitizenRelationSafetyTypeInDto dto);
+
+    Task<string> AddCitizenRelationSafetyType(AddCitizenRelationSafetyTypeInDto dto, CancellationToken token);
+}

+ 83 - 0
src/Hotline.Application/Snapshot/SnapshotUserApplication.cs

@@ -0,0 +1,83 @@
+using DocumentFormat.OpenXml.Vml.Office;
+using Hotline.Application.Snapshot.Contracts;
+using Hotline.Caching.Interfaces;
+using Hotline.Orders;
+using Hotline.Settings;
+using Hotline.Share.Dtos.Snapshot;
+using Hotline.Share.Tools;
+using Hotline.Snapshot;
+using Hotline.Snapshot.IRepository;
+using Hotline.ThirdAccountDomainServices;
+using Hotline.Tools;
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Dependency;
+using XF.Domain.Exceptions;
+using XF.Domain.Repository;
+
+namespace Hotline.Application.Snapshot;
+
+public class SnapshotUserApplication : ISnapshotUserApplication, IScopeDependency
+{
+    private readonly IRepository<CitizenRelationSafetyType> _citizenRelationSafetyTypeRepository;
+    private readonly ICitizenRepository _citizenRepository;
+    private readonly ISystemDicDataCacheManager _dicData;
+
+    public SnapshotUserApplication(IRepository<CitizenRelationSafetyType> citizenRelationSafetyTypeRepository, ICitizenRepository citizenRepository, ISystemDicDataCacheManager dicData)
+    {
+        _citizenRelationSafetyTypeRepository = citizenRelationSafetyTypeRepository;
+        _citizenRepository = citizenRepository;
+        _dicData = dicData;
+    }
+
+    public async Task<string> AddCitizenRelationSafetyType(AddCitizenRelationSafetyTypeInDto dto, CancellationToken token)
+    {
+        dto.ValidateObject();
+        var safetyType = _dicData.SafetyType.FirstOrDefault(m => m.DicDataValue == dto.DicDataValue);
+        if (safetyType == null) UserFriendlyException.SameMessage("志愿者类型错误");
+        await _citizenRepository.Queryable()
+            .LeftJoin<ThirdAccount>((citizen, account) => account.ExternalId == citizen.Id)
+            .Where(citizen => citizen.PhoneNumber == dto.PhoneNumber)
+            .Select((citizen, account) => citizen.Id)
+            .FirstAsync(token)
+            .Then(async citizenId =>
+            {
+                var relationEntity = await _citizenRelationSafetyTypeRepository.Queryable()
+                    .Where(m => m.CitizenId == citizenId && m.SafetyTypeValue == dto.DicDataValue)
+                    .FirstAsync(token);
+                if (relationEntity != null) return string.Empty;
+                relationEntity = new CitizenRelationSafetyType
+                {
+                    CitizenId = citizenId,
+                    Name = dto.Name,
+                    SafetyTypeValue = dto.DicDataValue
+                };
+                return await _citizenRelationSafetyTypeRepository.AddAsync(relationEntity, token);
+            }, nullCache => 
+            { 
+                throw UserFriendlyException.SameMessage("微信用户不存在");
+            });
+
+        return string.Empty;
+    }
+
+    public ISugarQueryable<CitizenRelationSafetyTypeOutDto> GetCitizenRelationSafetyType(CitizenRelationSafetyTypeInDto dto)
+    {
+        var query = _citizenRelationSafetyTypeRepository.Queryable()
+            .LeftJoin<SystemDicData>((relation, dicData) => relation.SafetyTypeValue == dicData.DicDataValue && dicData.DicTypeCode == SysDicTypeConsts.SafetyType)
+            .LeftJoin<Citizen>((relation, dicData, citizen) => citizen.Id == relation.CitizenId)
+            .WhereIF(dto.SafetyTypeValue.NotNullOrEmpty(), (relation, dicData) => relation.SafetyTypeValue == dto.SafetyTypeValue)
+            .Select((relation, dicData, citizen) => new CitizenRelationSafetyTypeOutDto
+            {
+                CitizenRelationSafetyTypeId = relation.Id,
+                Name = relation.Name,
+                PhoneNumber = citizen.PhoneNumber,
+                SafetyTypeTxt = dicData.DicDataName,
+            });
+        return query;
+    }
+}

+ 59 - 1
src/Hotline.Share/Dtos/Snapshot/SnapshotUserInfoDto.cs

@@ -1,4 +1,6 @@
-using Hotline.Share.Tools;
+using Hotline.Share.Requests;
+using Hotline.Share.Tools;
+using System.ComponentModel.DataAnnotations;
 
 namespace Hotline.Share.Dtos.Snapshot;
 public class SnapshotUserInfoOutDto
@@ -49,3 +51,59 @@ public class SnapshotUserInfoOutDto
     public int AppraiseCount { get; set; }
 }
 
+public record CitizenRelationSafetyTypeInDto : PagedRequest
+{
+    /// <summary>
+    /// 志愿者类型
+    /// </summary>
+    public string? SafetyTypeValue { get; set; }
+}
+
+public class CitizenRelationSafetyTypeOutDto
+{
+    /// <summary>
+    /// Id
+    /// </summary>
+    public string CitizenRelationSafetyTypeId { get; set; }
+
+    /// <summary>
+    /// 用户名
+    /// </summary>
+    public string? Name { get; set; }
+
+    /// <summary>
+    /// 志愿者类型名称
+    /// </summary>
+    public string SafetyTypeTxt { get; set; }
+
+    /// <summary>
+    /// 电话号码
+    /// </summary>
+    public string PhoneNumber { get; set; }
+}
+
+public class AddCitizenRelationSafetyTypeInDto
+{
+    /// <summary>
+    /// 志愿者类型
+    /// </summary>
+    [Required(ErrorMessage = "请选择志愿者类型")]
+    public string DicDataValue { get; set; }
+
+    /// <summary>
+    /// 名字
+    /// </summary>
+    public string? Name { get; set; }
+
+    /// <summary>
+    /// 联系方式
+    /// </summary>
+    [Required(ErrorMessage = "请输入联系方式")]
+    public string PhoneNumber { get; set; }
+
+    /// <summary>
+    /// 备注
+    /// </summary>
+    public string? Remark { get; set; }
+}
+

+ 14 - 0
src/Hotline.Share/Tools/TaskExtensions.cs

@@ -19,6 +19,20 @@ public static class TaskExtensions
         }
     }
 
+    public static async Task<string> Then<T>(this Task<T> task, Func<T, Task<string>> action, Func<T, Task<string>> nullCatch)
+    {
+        var result = await task;
+
+        if (result != null)
+        {
+            return await action(result);
+        }
+        else
+        {
+            return await nullCatch(result);
+        }
+    }
+
     /// <summary>
     /// 为 Task 类型的扩展方法,如果实体不为 null,则执行指定的操作。
     /// </summary>

+ 5 - 0
src/Hotline/Caching/Interfaces/ISysDicDataCacheManager.cs

@@ -106,5 +106,10 @@ namespace Hotline.Caching.Interfaces
         /// 随手拍重办原因
         /// </summary>
         IReadOnlyList<SystemDicData> InstaShotSpecialReason { get; }
+
+        /// <summary>
+        /// 随手拍安全员类型
+        /// </summary>
+        IReadOnlyList<SystemDicData> SafetyType { get; }
     }
 }

+ 5 - 0
src/Hotline/Caching/Services/SysDicDataCacheManager.cs

@@ -162,6 +162,11 @@ namespace Hotline.Caching.Services
 
         public IReadOnlyList<SystemDicData> InstaShotSpecialReason => GetOrAddDic(SysDicTypeConsts.InstaShotSpecialReason);
 
+        /// <summary>
+        /// 随手拍安全员类型
+        /// </summary>
+        public IReadOnlyList<SystemDicData> SafetyType => GetOrAddDic(SysDicTypeConsts.SafetyType);
+
         public void RemoveSysDicDataCache(string code)
         {
             _cacheSysDicData.Remove(code);

+ 12 - 0
src/Hotline/SeedData/SystemDicDataSeedData.cs

@@ -203,6 +203,14 @@ public class SystemDicDataSeedData : ISeedData<SystemDicData>
                 new () { Id = "08dcd790-e54b-4da2-8a1a-bba70490b08c", DicDataValue = "随手拍整改时间过长", DicDataName = "随手拍整改时间过长", Sort = 8}
                 ];
         }
+        if (dicTypeCode == SysDicTypeConsts.SafetyType)
+        {
+            return [
+                new() { Id = "08dd7db8-5dc1-4f52-8d87-bc0772399a47", DicDataName = "安全志愿者", DicDataValue = "1", Sort = 1},
+                new() { Id = "08dd78a1-4823-4940-8ebd-8951d7a07e75", DicDataName = "宣传员", DicDataValue = "2", Sort = 2},
+                new() { Id = "08dd7bc9-44f5-4075-80dd-e4e5c3ee6af7", DicDataName = "安全卫士", DicDataValue = "3", Sort = 3},
+                ];
+        }
 
         throw new NotImplementedException();
     }
@@ -210,6 +218,10 @@ public class SystemDicDataSeedData : ISeedData<SystemDicData>
     public SystemDicType GetType(string dicTypeCode)
     {
         var dicType = new string[2];
+        if (dicTypeCode == SysDicTypeConsts.SafetyType)
+        {
+            dicType = ["08dd7c8d-974f-4c1b-84e9-d9aafcb53c1f", "安全志愿者类型"];
+        }
         if (dicTypeCode == SysDicTypeConsts.InstaShotSpecialReason)
         {
             dicType = ["81c202b7-5c50-45e5-bbde-fb1904957f85", "随手拍特提原因"];

+ 5 - 1
src/Hotline/Settings/SysDicTypeConsts.cs

@@ -340,5 +340,9 @@ public class SysDicTypeConsts
     /// 政治身份
     /// </summary>
     public static string PoliticalIdentity = "PoliticalIdentity";
-    
+
+    /// <summary>
+    /// 随手拍安全员类型
+    /// </summary>
+    public const string SafetyType = "SafetyType";
 }

+ 33 - 0
src/Hotline/Snapshot/CitizenRelationSafetyType.cs

@@ -0,0 +1,33 @@
+using SqlSugar;
+using System.ComponentModel;
+using XF.Domain.Entities;
+
+namespace Hotline.Snapshot;
+
+[Description("市民关联随手拍安全角色分类")]
+public class CitizenRelationSafetyType : ITable, IEntity<string>
+{
+    /// <summary>
+    /// Id
+    /// </summary>
+    [SugarColumn(ColumnDescription = "Id")]
+    public string Id { get; set; }
+
+    /// <summary>
+    /// 市民Id
+    /// </summary>
+    [SugarColumn(ColumnDescription = "市民Id")]
+    public string CitizenId { get; set; }
+
+    /// <summary>
+    /// 字典类型value
+    /// </summary>
+    [SugarColumn(ColumnDescription = "字典类型value")]
+    public string SafetyTypeValue { get; set; }
+
+    /// <summary>
+    /// 用户名
+    /// </summary>
+    [SugarColumn(ColumnDescription = "用户名")]
+    public string? Name { get; set; }
+}

+ 1 - 1
src/Hotline/Snapshot/Services/SnapshotPointsDomainService.cs

@@ -42,7 +42,7 @@ public class SnapshotPointsDomainService : ISnapshotPointsDomainService, IScopeD
             OrderId = orderId,
             Points = order.ReportPoints.Value,
             Source = source,
-            Direction = Share.Enums.CallCenter.EPointsDirection.In
+            Direction = Share.Enums.CallCenter.EPointsDirection.In,
         };
         if (source == EPointsSource.Report)
             points.Points = order.ReportPoints.Value;

+ 62 - 0
test/Hotline.Tests/Application/SnapshotUserApplicationTest.cs

@@ -0,0 +1,62 @@
+using Hotline.Api.Controllers;
+using Hotline.Application.Snapshot.Contracts;
+using Hotline.Caching.Interfaces;
+using Hotline.Identity.Accounts;
+using Hotline.Identity.Roles;
+using Hotline.Orders;
+using Hotline.Settings;
+using Hotline.Share.Dtos.Snapshot;
+using Hotline.Snapshot;
+using Hotline.ThirdAccountDomainServices;
+using Hotline.ThirdAccountDomainServices.Interfaces;
+using Hotline.Users;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.DependencyInjection;
+using Shouldly;
+using XF.Domain.Cache;
+using XF.Domain.Repository;
+
+namespace Hotline.Tests.Application;
+
+public class SnapshotUserApplicationTest : TestBase
+{
+    private readonly ISnapshotUserApplication _snapshotUserApplication;
+    private readonly ISystemDicDataCacheManager _dicData;
+    private readonly ICitizenRepository _citizenRepository;
+    public SnapshotUserApplicationTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IHttpContextAccessor httpContextAccessor, IThirdIdentiyService thirdIdentiyService, IThirdAccountRepository thirdAccountRepository, ITypedCache<SystemSetting> cacheSettingData, ThirdAccounSupplierFactory thirdAccountDomainFactory, IServiceProvider serviceProvider, ISnapshotUserApplication snapshotUserApplication, ISystemDicDataCacheManager dicData, ICitizenRepository citizenRepository) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdIdentiyService, thirdAccountRepository, cacheSettingData, thirdAccountDomainFactory, serviceProvider)
+    {
+        _snapshotUserApplication = snapshotUserApplication;
+        _dicData = dicData;
+        _citizenRepository = citizenRepository;
+    }
+
+    [Fact]
+    public async Task SnapshotUserApplication_Test()
+    {
+        var dic = _dicData.SafetyType.First();
+        var dicDataValue = dic.DicDataValue;
+        var citizen = await _citizenRepository.Queryable()
+            .LeftJoin<CitizenRelationSafetyType>((citizen, relation) => relation.CitizenId == citizen.Id)
+            .Where((citizen, relation) => relation.Id == null)
+            .FirstAsync();
+        var addDto = new AddCitizenRelationSafetyTypeInDto
+        {
+            DicDataValue = dicDataValue,
+            PhoneNumber = citizen.PhoneNumber,
+            Name = citizen.Name
+        };
+
+        var relationId = await _snapshotUserApplication.AddCitizenRelationSafetyType(addDto, CancellationToken.None);
+        relationId.ShouldNotBeNull();
+
+        var inDto = new CitizenRelationSafetyTypeInDto
+        {
+        };
+        var items = await _snapshotUserApplication.GetCitizenRelationSafetyType(inDto).ToListAsync();
+        var item = items.FirstOrDefault(m => m.CitizenRelationSafetyTypeId == relationId);
+        item.ShouldNotBeNull();
+        item.Name.ShouldBe(addDto.Name);
+        item.PhoneNumber.ShouldBe(addDto.PhoneNumber);
+        item.SafetyTypeTxt.ShouldBe(dic.DicDataName);
+    }
+}