Procházet zdrojové kódy

Merge branch 'feature/snapshot' of http://110.188.24.182:10023/Fengwo/hotline into feature/snapshot

xf před 4 měsíci
rodič
revize
a0c61add8e
46 změnil soubory, kde provedl 1598 přidání a 66 odebrání
  1. 1 0
      .gitignore
  2. 1 0
      src/Hotline.Api/Controllers/HomeController.cs
  3. 3 1
      src/Hotline.Api/Controllers/IdentityController.cs
  4. 256 2
      src/Hotline.Api/Controllers/Snapshot/IndustryController.cs
  5. 11 2
      src/Hotline.Api/Controllers/Snapshot/SnapshotController.cs
  6. 1 1
      src/Hotline.Api/StartupExtensions.cs
  7. 3 3
      src/Hotline.Api/config/appsettings.Development.json
  8. 100 0
      src/Hotline.Application.Tests/Application/IndustryApplicationTest.cs
  9. 1 0
      src/Hotline.Application.Tests/Application/SnapshotApplicationMockTest.cs
  10. 3 0
      src/Hotline.Application.Tests/Mock/ThirdTestService.cs
  11. 2 2
      src/Hotline.Application.Tests/Startup.cs
  12. 1 1
      src/Hotline.Application.Tests/TestBase.cs
  13. 6 2
      src/Hotline.Application/Identity/IdentityAppService.cs
  14. 1 1
      src/Hotline.Application/Mappers/SnapshotMapperConfigs.cs
  15. 1 1
      src/Hotline.Application/Snapshot/DefaultSnapshotApplication.cs
  16. 149 0
      src/Hotline.Application/Snapshot/IIndustryApplication.cs
  17. 8 1
      src/Hotline.Application/Snapshot/ISnapshotApplication.cs
  18. 323 3
      src/Hotline.Application/Snapshot/IndustryApplication.cs
  19. 44 7
      src/Hotline.Application/Snapshot/SnapshotApplicationBase.cs
  20. 1 1
      src/Hotline.Application/Snapshot/ZiGongSnapshotApplication.cs
  21. 2 1
      src/Hotline.Repository.SqlSugar/Orders/OrderVisitDetailRepository.cs
  22. 19 0
      src/Hotline.Repository.SqlSugar/Snapshot/IndustryCaseRepository.cs
  23. 18 0
      src/Hotline.Repository.SqlSugar/Snapshot/SnapshotSMSTemplateRepository.cs
  24. 5 0
      src/Hotline.Share/Dtos/Identity/LoginDto.cs
  25. 260 6
      src/Hotline.Share/Dtos/Snapshot/IndustryDto.cs
  26. 6 2
      src/Hotline.Share/Dtos/Snapshot/OrderDto.cs
  27. 26 0
      src/Hotline.Share/Dtos/Snapshot/OrderPublishDto.cs
  28. 55 2
      src/Hotline.Share/Dtos/Snapshot/PractitionerDto.cs
  29. 4 4
      src/Hotline.Share/Dtos/Snapshot/RedPackDto.cs
  30. 9 3
      src/Hotline.Share/Dtos/Snapshot/SnapshotUserInfoDto.cs
  31. 20 2
      src/Hotline.Share/Dtos/Snapshot/VolunteerDto.cs
  32. 82 1
      src/Hotline.Share/Dtos/Snapshot/VolunteerReportDto.cs
  33. 23 0
      src/Hotline.Share/Enums/Snapshot/ESnapshotSMSStatus.cs
  34. 2 2
      src/Hotline.Share/Tools/DoubleExtensions.cs
  35. 5 0
      src/Hotline/Caching/Interfaces/ISysDicDataCacheManager.cs
  36. 2 0
      src/Hotline/Caching/Interfaces/ISystemSettingCacheManager.cs
  37. 5 0
      src/Hotline/Caching/Services/SysDicDataCacheManager.cs
  38. 7 0
      src/Hotline/Caching/Services/SystemSettingCacheManager.cs
  39. 30 0
      src/Hotline/SeedData/SystemDicDataSeedData.cs
  40. 5 0
      src/Hotline/Settings/SysDicTypeConsts.cs
  41. 12 6
      src/Hotline/Snapshot/Industry.cs
  42. 12 6
      src/Hotline/Snapshot/IndustryCase.cs
  43. 11 0
      src/Hotline/Snapshot/Interfaces/IIndustryCaseRepository.cs
  44. 11 0
      src/Hotline/Snapshot/Interfaces/ISnapshotSMSTemplateRepository.cs
  45. 48 0
      src/Hotline/Snapshot/SnapshotSMSTemplate.cs
  46. 3 3
      src/Hotline/Snapshot/ThirdAccount.cs

+ 1 - 0
.gitignore

@@ -344,3 +344,4 @@ ASALocalRun/
 
 # BeatPulse healthcheck temp database
 healthchecksdb
+/merge.ps1

+ 1 - 0
src/Hotline.Api/Controllers/HomeController.cs

@@ -193,6 +193,7 @@ public class HomeController : BaseController
             NationalPlatformWordLimit = int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.NationalPlatformWordLimit).SettingValue[0]),
             HandleOpinionWordLimit= int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.HandleOpinionWordLimit).SettingValue[0]),
             CallInOpenType = int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.CallInOpenType).SettingValue[0]),
+            Snapshot = _systemSettingCacheManager.Snapshot
         };
         return rsp;
     }

+ 3 - 1
src/Hotline.Api/Controllers/IdentityController.cs

@@ -107,6 +107,7 @@ jxrWXHbT1FB6DqkdOnBbQqS1Azqz5HxLlSyEK3F60e3SgB5iZsDZ
     /// <param name="openId"></param>
     /// <returns></returns>
     [HttpGet("third/refresh")]
+    [AllowAnonymous]
     public async Task<TokenOutDto> RefreshTokenAsync(string openId)
         => await _identityAppService.RefreshTokenAsync(openId);
 
@@ -179,7 +180,8 @@ jxrWXHbT1FB6DqkdOnBbQqS1Azqz5HxLlSyEK3F60e3SgB5iZsDZ
             MenuLogoImageMini = menuLogoImageMini,
             IsLoginMessageCode = IsLoginMessageCode,
             AppScope = _appOptions.Value.AppScope,
-            CallCenterType = _appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType
+            CallCenterType = _appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType,
+            Snapshot = _systemSettingCacheManager.Snapshot
         };
     }
 

+ 256 - 2
src/Hotline.Api/Controllers/Snapshot/IndustryController.cs

@@ -1,10 +1,17 @@
-using Hotline.Application.Snapshot;
+using Amazon.Runtime.Internal.Transform;
+using Hotline.Application.Snapshot;
+using Hotline.Caching.Interfaces;
+using Hotline.Configurations;
 using Hotline.Repository.SqlSugar.Extensions;
+using Hotline.Settings;
 using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.Snapshot;
 using Hotline.Share.Tools;
+using Hotline.Snapshot;
 using Hotline.Snapshot.Interfaces;
 using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Options;
+using SqlSugar;
 
 namespace Hotline.Api.Controllers.Snapshot;
 
@@ -14,14 +21,34 @@ namespace Hotline.Api.Controllers.Snapshot;
 public class IndustryController : BaseController
 {
     private readonly IIndustryRepository _industryRepository;
+    private readonly ISystemDicDataCacheManager _systemDicDataCacheManager;
     private readonly IIndustryApplication _industryApplication;
+    private readonly ISystemAreaDomainService _systemAreaDomainService;
+    private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
 
-    public IndustryController(IIndustryRepository industryRepository, IIndustryApplication industryApplication)
+    public IndustryController(IIndustryRepository industryRepository, IIndustryApplication industryApplication, ISystemDicDataCacheManager systemDicDataCacheManager, ISystemAreaDomainService systemAreaDomainService, IOptionsSnapshot<AppConfiguration> appOptions)
     {
         _industryRepository = industryRepository;
         _industryApplication = industryApplication;
+        _systemDicDataCacheManager = systemDicDataCacheManager;
+        _systemAreaDomainService = systemAreaDomainService;
+        _appOptions = appOptions;
     }
 
+    /// <summary>
+    /// 添加行业页面基础数据
+    /// </summary>
+    /// <returns></returns>
+    [HttpGet("basedata")]
+    public Dictionary<string, object> GetBaseData()
+    {
+        return new Dictionary<string, object>
+        {
+            { "department", _systemDicDataCacheManager.SnapshotDepartment },
+            { "acceptType", _systemDicDataCacheManager.AcceptType},
+            { "bulletinType", _systemDicDataCacheManager.SnapshotBulletinType}
+        };
+    }
     /// <summary>
     /// 新增行业
     /// </summary>
@@ -30,6 +57,15 @@ public class IndustryController : BaseController
     public async Task<string> AddIndustry([FromBody] AddIndustryDto dto)
         => await _industryApplication.AddIndustryAsync(dto, HttpContext.RequestAborted);
 
+    /// <summary>
+    /// 行业详情
+    /// </summary>
+    /// <param name="id"></param>
+    /// <returns></returns>
+    [HttpGet("{id}")]
+    public async Task<IndustryDetailOutDto> GetIndustryDetailAsync(string id)
+        => await _industryApplication.GetIndustryDetailAsync(id);
+
     /// <summary>
     /// 获取行业集合
     /// </summary>
@@ -37,4 +73,222 @@ public class IndustryController : BaseController
     [HttpGet("industry")]
     public async Task<PagedDto<IndustryItemsOutDto>> GetIndustryAsync([FromQuery] IndustryListInDto dto)
         => (await _industryApplication.GetIndustres(dto).ToPagedListAsync(dto, HttpContext.RequestAborted)).ToPaged();
+
+    /// <summary>
+    /// 修改行业
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpPut]
+    public async Task UpdateIndustry([FromBody] UpdateIndustryInDto dto)
+        => await _industryApplication.UpdateIndustryAsync(dto, HttpContext.RequestAborted);
+
+    #region 行业线索
+    /// <summary>
+    /// 行业线索集合
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpGet("case")]
+    public async Task<PagedDto<IndustryCaseItemOutDto>> GetIndustryCaseItemAsync([FromQuery] IndustryCaseItemInDto dto)
+        => (await _industryApplication.GetIndustryCaseItems(dto).ToPagedListAsync(dto, HttpContext.RequestAborted)).ToPaged();
+
+    /// <summary>
+    /// 添加行业线索
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpPost("case")]
+    public async Task AddIndustryCaseAsync([FromBody] AddIndustryCaseDto dto)
+        => await _industryApplication.AddIndustryCaseAsync(dto);
+
+    /// <summary>
+    /// 更新行业线索
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpPut("case")]
+    public async Task UpdateIndustryCaseAsync([FromBody]UpdateIndustryCaseDto dto)
+        => await _industryApplication.UpdateIndustryCaseAsync(dto);
+
+    /// <summary>
+    /// 获取行业线索详情
+    /// </summary>
+    /// <param name="id"></param>
+    /// <returns></returns>
+    [HttpGet("case/{id}")]
+    public async Task<IndustryCase> GetIndustryCaseDetailAsync(string id)
+        => await _industryApplication.GetIndustryCaseAsync(id);
+
+    /// <summary>
+    /// 页面基础数据
+    /// </summary>
+    /// <returns></returns>
+    [HttpGet("case/database")]
+    public async Task<Dictionary<string, object>> GetIndustryCaseDataBaseAsync()
+    {
+        var items = await _industryRepository.Queryable()
+            .Select(m => new { m.Id, m.Name })
+            .ToListAsync();
+        return new Dictionary<string, object>
+        {
+            { "industry", items }
+        };
+    }
+    #endregion
+
+    #region 行业短信模板
+    /// <summary>
+    /// 行业短信模板集合
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpGet("sms_template")]
+    public async Task<PagedDto<SnapshotSMSTemplateItemsOutDto>> GetSmsTemplateItemsAsync([FromQuery]SnapshotSMSTemplateItemsInDto dto)
+        => (await _industryApplication.GetSMSTemplates(dto).ToPagedListAsync(dto, HttpContext.RequestAborted)).ToPaged();
+
+    /// <summary>
+    /// 添加行业短信模板
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpPost("sms_template")]
+    public async Task AddSmsTemplateAsync([FromBody] AddSnapshotSMSTemplateInDto dto)
+        => await _industryApplication.AddSMSTemplateAsync(dto);
+
+    /// <summary>
+    /// 修改行业短信模板
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpPut("sms_template")]
+    public async Task UpdateSmsTemplateAsync([FromBody] UpdateSnapshotSMSTemplateInDto dto)
+        => await _industryApplication.UpdateSMSTemplateAsync(dto);
+
+    /// <summary>
+    /// 短信详情
+    /// </summary>
+    /// <param name="id"></param>
+    /// <returns></returns>
+    [HttpGet("sms_template/{id}")]
+    public async Task<SnapshotSMSTemplateItemsOutDto> GetSMSTemplateDetailAsync(string id)
+        => await _industryApplication.GetSMSTemplateDetailAsync(id);
+    #endregion
+
+    #region 区域从业人员
+    /// <summary>
+    /// 区域从业人员集合
+    /// </summary>
+    /// <returns></returns>
+    [HttpGet("practitioner")]
+    public async Task<PagedDto<PractitionerItemsOutDto>> GetPractitionerItemsAsync([FromQuery] PractitionerItemsInDto dto)
+        => (await _industryApplication.GetPractitionerItemsAsync(dto).ToPagedListAsync(dto, HttpContext.RequestAborted)).ToPaged();
+
+    /// <summary>
+    /// 添加区域从业人员
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpPost("practitioner")]
+    public async Task<string> AddPractitionerAsync([FromBody]AddPractitionerInDto dto)
+        => await _industryApplication.AddPractitionerAsync(dto);
+
+    /// <summary>
+    /// 删除区域从业人员
+    /// </summary>
+    /// <param name="ids"></param>
+    /// <returns></returns>
+    [HttpDelete("practitioner")]
+    public async Task DeletePractitionerAsync([FromBody]IList<string> ids)
+        => await _industryApplication.DeletePractitionerAsync(ids);
+
+    /// <summary>
+    /// 修改区域从业人员
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpPut("practitioner")]
+    public async Task UpdatePractitionerAsync(UpdatePractitionerInDto dto)
+        => await _industryApplication.UpdatePractitionerAsync(dto);
+
+    /// <summary>
+    /// 从业人员详情
+    /// </summary>
+    /// <param name="id"></param>
+    /// <returns></returns>
+    [HttpGet("practitioner/{id}")]
+    public async Task<PractitionerItemsOutDto> GetPractitionerAsync(string id)
+        => await _industryApplication.GetPractitionerAsync(id);
+
+    /// <summary>
+    /// 添加从业人员基础数据
+    /// </summary>
+    /// <returns></returns>
+    [HttpGet("practitioner/basedata")]
+    public async Task<Dictionary<string, object>> GetPractitionerDataBaseAsync()
+    {
+        var parentId = "";
+        if (_appOptions.Value.IsZiGong) parentId = _appOptions.Value.ZiGong.AreaCode;
+        return new Dictionary<string, object>
+        {
+            { "area", await _systemAreaDomainService.GetAreaTree(parentId: parentId)}
+        };
+    }
+    #endregion
+
+    #region 志愿者
+    /// <summary>
+    /// 志愿者集合
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpGet("volunteer")]
+    public async Task<PagedDto<VolunteerItemsOutDto>> GetVolunteerItemsAsync([FromQuery] VolunteerItemsInDto dto)
+        => (await _industryApplication.GetVolunteerItemsAsync(dto).ToPagedListAsync(dto, HttpContext.RequestAborted)).ToPaged();
+
+    /// <summary>
+    /// 添加志愿者
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpPost("volunteer")]
+    public async Task<string> AddVolunteerAsync([FromBody] AddVolunteerInDto dto)
+        => await _industryApplication.AddVolunteerAsync(dto);
+
+    /// <summary>
+    /// 批量删除志愿者
+    /// </summary>
+    /// <param name="ids"></param>
+    /// <returns></returns>
+    [HttpDelete("volunteer")]
+    public async Task DeleteVolunteerAsync([FromBody]IList<string> ids)
+        => await _industryApplication.DeleteVolunteerAsync(ids);
+
+    /// <summary>
+    /// 志愿者详情
+    /// </summary>
+    /// <param name="id"></param>
+    /// <returns></returns>
+    [HttpGet("volunteer/{id}")]
+    public async Task<Volunteer> GetVolunteerAsync(string id)
+        => await _industryApplication.GetVolunteerAsync(id);
+
+    /// <summary>
+    /// 修改志愿者
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpPut("volunteer")]
+    public async Task UpdateVolunteerAsync([FromBody]UpdateVolunteerInDto dto)
+        => await _industryApplication.UpdateVolunteerAsync(dto);
+
+    /// <summary>
+    /// 志愿者上报集合
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpGet("volunteer/report")]
+    public async Task<PagedDto<VolunteerReportItemsOutDto>> GetVolunteerReportItemsAsync([FromQuery]VolunteerReportItemsInDto dto)
+        => (await _industryApplication.GetVolunteerReportItemsAsync(dto).ToPagedListAsync(dto)).ToPaged();
+    #endregion
 }

+ 11 - 2
src/Hotline.Api/Controllers/Snapshot/SnapshotController.cs

@@ -185,9 +185,18 @@ public class SnapshotController : BaseController
     /// <param name="id"></param>
     /// <returns></returns>
     [HttpGet("order/{id}")]
-    public async Task<OrderPublishDetailOutDto> QueryOrderListAsync([FromQuery] string id)
+    public async Task<OrderPublishDetailOutDto> QueryOrderListAsync(string id)
         => await _snapshotApplication.GetSnapshotOrderDetailAsync(id, HttpContext.RequestAborted);
 
+    /// <summary>
+    /// 获取回访详情
+    /// </summary>
+    /// <param name="id"></param>
+    /// <returns></returns>
+    [HttpGet("order/visit/{id}")]
+    public async Task<IList<OrderVisitItemsOutDto>> GetOrderVisitDetailAsync(string id)
+        => await _snapshotApplication.GetOrderVisitDetailAsync(id);
+
     /// <summary>
     /// 统计红包金额, 每月的总金额
     /// </summary>
@@ -239,7 +248,7 @@ public class SnapshotController : BaseController
     /// <param name="dtos"></param>
     /// <returns></returns>
     [HttpPost("practitioner")]
-    public async Task AddPractitionerAsync([FromBody]IList<AddPractitionerInDto> dtos)
+    public async Task AddPractitionerAsync([FromBody]IList<AddBatchPractitionerInDto> dtos)
         => await _snapshotApplication.AddPractitionerAsync(dtos);
 
     /// <summary>

+ 1 - 1
src/Hotline.Api/StartupExtensions.cs

@@ -155,7 +155,7 @@ internal static class StartupExtensions
                 services.AddProxiedScoped<ISnapshotApplication, DefaultSnapshotApplication>();
                 break;
             case AppDefaults.AppScope.ZiGong:
-                services.AddProxiedScoped<ISnapshotApplication, DefaultSnapshotApplication>();
+                services.AddProxiedScoped<ISnapshotApplication, ZiGongSnapshotApplication>();
                 break;
             case AppDefaults.AppScope.LuZhou:
                 services.AddProxiedScoped<ISnapshotApplication, DefaultSnapshotApplication>();

+ 3 - 3
src/Hotline.Api/config/appsettings.Development.json

@@ -1,7 +1,7 @@
 {
   "AllowedHosts": "*",
   "AppConfiguration": {
-    "AppScope": "YiBin",
+    "AppScope": "ZiGong",
     "YiBin": {
       "AreaCode": "511500",
       "CallCenterType": "TianRun", //XunShi、WeiErXin、TianRun、XingTang
@@ -62,13 +62,13 @@
     }
   },
   "ConnectionStrings": {
-    "Hotline": "PORT=5432;DATABASE=hotline;HOST=110.188.24.182;PASSWORD=fengwo11!!;USER ID=dev;"
+    "Hotline": "PORT=5432;DATABASE=hotline_dev;HOST=110.188.24.182;PASSWORD=fengwo11!!;USER ID=dev;"
   },
   "Cache": {
     "Host": "110.188.24.182",
     "Port": 50179,
     "Password": "fengwo123!$!$",
-    "Database": 3 //test:3, dev:5
+    "Database": 5 //test:3, dev:5
   },
   "Swagger": true,
   "AccLog":  false,

+ 100 - 0
src/Hotline.Application.Tests/Application/IndustryApplicationTest.cs

@@ -0,0 +1,100 @@
+using Hotline.Api.Controllers;
+using AutoFixture;
+using Hotline.Application.Snapshot;
+using Hotline.Identity.Accounts;
+using Hotline.Identity.Roles;
+using Hotline.Share.Dtos.Snapshot;
+using Hotline.Share.Tools;
+using Hotline.Snapshot.Interfaces;
+using Hotline.Users;
+using Mapster;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.DependencyInjection;
+using Shouldly;
+using XF.Domain.Repository;
+
+namespace Hotline.Application.Tests.Application;
+public class IndustryApplicationTest : TestBase
+{
+    private readonly IIndustryApplication _industryApplication;
+    private readonly IIndustryRepository _industryRepository;
+
+    public IndustryApplicationTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IHttpContextAccessor httpContextAccessor, IThirdIdentiyService thirdIdentiyService, IThirdAccountRepository thirdAccountRepository, IIndustryApplication industryApplication, IIndustryRepository industryRepository) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdIdentiyService, thirdAccountRepository)
+    {
+        _industryApplication = industryApplication;
+        _industryRepository = industryRepository;
+    }
+
+    [Fact]
+    public async Task UpdateIndustry_Test()
+    {
+        var industryItems = _industryApplication.GetIndustres(new IndustryListInDto(null, null)).ToList();
+        industryItems.NotNullOrEmpty().ShouldBeTrue("行业集合为空");
+        var industry = industryItems.First().Adapt<UpdateIndustryInDto>();
+        var item = await _industryRepository.GetAsync(industry.Id);
+        industry.ForeachClassProperties(async (industry, property, name, value) =>
+        {
+            if (name.ToUpper() == "ID") return true;
+            if (value is String)
+                industry.GetType().GetProperty(name).SetValue(industry, value + DateTime.Now.ToString("ss"));
+            return true;
+        });
+        await _industryApplication.UpdateIndustryAsync(industry, CancellationToken.None);
+        var updateIndustry = await _industryApplication.GetIndustryDetailAsync(item.Id);
+        updateIndustry.ForeachClassProperties(async (industry, property, name, value) =>
+        {
+            industry.GetType().GetProperty(name).GetValue(industry).ShouldBe(value);
+            return true;
+        });
+        await _industryApplication.UpdateIndustryAsync(item.Adapt<UpdateIndustryInDto>(), CancellationToken.None);
+    }
+
+    [Fact]
+    public async Task IndustryCase_Test()
+    {
+        var industry = await _industryApplication.GetIndustres(new IndustryListInDto(null, null)).ToListAsync();
+        var industryCase = new AddIndustryCaseDto
+        {
+            IndustryId = industry.First().Id,
+            Name = "单元测试" + DateTime.Now.ToString("ss"),
+            CitizenReadPackAmount = 10,
+            GuiderReadPackAmount = 10,
+            IsEnable = true,
+            DisplayOrder = 1
+        };
+        var caseId = await _industryApplication.AddIndustryCaseAsync(industryCase);
+        var items = await _industryApplication.GetIndustryCaseItems(new IndustryCaseItemInDto(null, null)).ToListAsync();
+        items.Count.ShouldNotBe(0);
+        items.Any(m => m.Id.IsNullOrEmpty()).ShouldBeFalse();
+        items.Any(m => m.Name.IsNullOrEmpty()).ShouldBeFalse();
+
+        var caseEntity = await _industryApplication.GetIndustryCaseAsync(caseId);
+        var updateDto = caseEntity.Adapt<UpdateIndustryCaseDto>();
+        updateDto.DisplayOrder = 2;
+        await _industryApplication.UpdateIndustryCaseAsync(updateDto);
+        var caseEntityUpdate = await _industryApplication.GetIndustryCaseAsync(caseId);
+        caseEntityUpdate.DisplayOrder.ShouldBe(updateDto.DisplayOrder);
+        caseEntityUpdate.Name.ShouldBe(updateDto.Name);
+    }
+
+    /// <summary>
+    /// 新增行业短信模板
+    /// 行业短信模板集合
+    /// </summary>
+    /// <returns></returns>
+    [Fact]
+    public async Task SMSTemplate_Test()
+    {
+        var industryItems = await _industryApplication.GetIndustres(new IndustryListInDto(null, null)).ToListAsync();
+        var industry = industryItems.First();
+        var inDto = _fixture.Create<AddSnapshotSMSTemplateInDto>();
+        inDto.IndustryId = industry.Id;
+        var smsId = await _industryApplication.AddSMSTemplateAsync(inDto);
+        var items = await _industryApplication.GetSMSTemplates(new SnapshotSMSTemplateItemsInDto(null)).ToListAsync();
+        items.Count.ShouldNotBe(0);
+        var sms = items.Where(m => m.Id == smsId).First();
+        sms.Content.ShouldBe(inDto.Content);
+        sms.IndustryName.ShouldNotBeNullOrEmpty();
+        sms.IsEnable.ShouldBe(inDto.IsEnable);
+    }
+}

+ 1 - 0
src/Hotline.Application.Tests/Application/SnapshotApplicationMockTest.cs

@@ -106,6 +106,7 @@ namespace Hotline.Application.Tests.Snapshot
                 _fileDomainServiceMock.Object,
                 null,
                 null,
+                null,
                 null
             );
         }

+ 3 - 0
src/Hotline.Application.Tests/Mock/ThirdTestService.cs

@@ -1,4 +1,5 @@
 using Hotline.Share.Dtos.Snapshot;
+using Hotline.Share.Tools;
 using Hotline.Users;
 using XF.Domain.Dependency;
 
@@ -15,6 +16,8 @@ public class ThirdTestService : IThirdIdentiyService, IScopeDependency
 
     public async Task<ThirdTokenOutDto> GetTokenAsync(ThirdTokenDto dto)
     {
+        //var resultString = "{\"SessionKey\":\"letVB1m+8ZYsMjo8PxhwUw==\",\"OpenId\":\"oHBwj4_8hQG1Q00HyTO3d47RLuAA\"}";
+        //return resultString.FromJson<ThirdTokenOutDto>();
         return new ThirdTokenOutDto
         {
             SessionKey = "sessionKeyfjdklsafjdskla",

+ 2 - 2
src/Hotline.Application.Tests/Startup.cs

@@ -154,8 +154,8 @@ public class Startup
                 .ToList()
                 .ForEach(d => ServiceRegister.Register(services, d));
 
-            services.AddScoped<IThirdIdentiyService, WeChatService>();
-            //services.AddScoped<IThirdIdentiyService, ThirdTestService>();
+            //services.AddScoped<IThirdIdentiyService, WeChatService>();
+            services.AddScoped<IThirdIdentiyService, ThirdTestService>();
 
             //services.AddScoped<IThirdAccountRepository, ThirdAccountRepository>();
             services.AddApplication();

+ 1 - 1
src/Hotline.Application.Tests/TestBase.cs

@@ -130,7 +130,7 @@ public class TestBase
             new(AppClaimTypes.DepartmentAreaName, user.Organization?.AreaName ?? string.Empty),
             new(AppClaimTypes.DepartmentLevel, user.Organization?.Level.ToString() ?? string.Empty),
             new(AppClaimTypes.AreaId, user.OrgId?.GetHigherOrgId() ?? string.Empty),
-            new(AppClaimTypes.OpenId, thirdAccount.OpenId ?? string.Empty),
+            new(AppClaimTypes.OpenId, thirdAccount?.OpenId ?? string.Empty),
         ];
         ClaimsIdentity identity = new ClaimsIdentity(userClaims);
         var principal = new ClaimsPrincipal(identity);

+ 6 - 2
src/Hotline.Application/Identity/IdentityAppService.cs

@@ -52,6 +52,8 @@ public class IdentityAppService : IIdentityAppService, IScopeDependency
     private readonly IThirdAccountRepository _thirdAccountRepository;
     private readonly IGuiderInfoRepository _guiderInfoRepository;
     private readonly IVolunteerRepository _volunteerRepository;
+    private readonly ISystemLogRepository _systemLog;
+
 
     public IdentityAppService(
         IAccountRepository accountRepository,
@@ -69,7 +71,8 @@ public class IdentityAppService : IIdentityAppService, IScopeDependency
         ISessionContext sessionContext,
         IRepository<Citizen> citizenRepository,
         IGuiderInfoRepository guiderInfoRepository,
-        IVolunteerRepository volunteerRepository)
+        IVolunteerRepository volunteerRepository,
+        ISystemLogRepository systemLog)
     {
         _accountRepository = accountRepository;
         _accountDomainService = accountDomainService;
@@ -87,6 +90,7 @@ public class IdentityAppService : IIdentityAppService, IScopeDependency
         _citizenRepository = citizenRepository;
         _guiderInfoRepository = guiderInfoRepository;
         _volunteerRepository = volunteerRepository;
+        _systemLog = systemLog;
     }
 
     public async Task<string> OldToNewLoginAsync(HotlineLoginOldToNewDto dto, CancellationToken cancellationToken)
@@ -339,7 +343,7 @@ public class IdentityAppService : IIdentityAppService, IScopeDependency
             else
             {
                 var citizen = await _citizenRepository.Queryable().Where(m => m.PhoneNumber == phone.PhoneNumber).FirstAsync();
-                thirdAccount.UserId = citizen.Id;
+                thirdAccount.UserId = citizen?.Id;
             }
             thirdAccount.Id = await _thirdAccountRepository.AddAsync(thirdAccount);
         }

+ 1 - 1
src/Hotline.Application/Mappers/SnapshotMapperConfigs.cs

@@ -46,7 +46,7 @@ public class SnapshotMapperConfigs : IRegister
         config.ForType<Order, OrderPublishDetailOutDto>()
             .Map(m => m.Opinion, n => n.ActualOpinion);
 
-        config.ForType<AddPractitionerInDto, Practitioner>()
+        config.ForType<AddBatchPractitionerInDto, Practitioner>()
             .Ignore(m => m.Gender);
 
         config.ForType<GuiderSystemInDto, OrderSnapshot>()

+ 1 - 1
src/Hotline.Application/Snapshot/DefaultSnapshotApplication.cs

@@ -25,7 +25,7 @@ namespace Hotline.Application.Snapshot;
 public class DefaultSnapshotApplication : SnapshotApplicationBase
     , ISnapshotApplication, IScopeDependency
 {
-    public DefaultSnapshotApplication(IThirdIdentiyService thirdLoginService, IRepository<Industry> industryRepository, ISnapshotBulletinRepository bulletinRepository, ISessionContext sessionContext, IRepository<RedPackRecord> redPackRecordRepository, IRepository<Order> orderRepository, IThirdAccountRepository thirdAccountRepository, IOrderSnapshotRepository orderSnapshotRepository, ISystemSettingCacheManager systemSettingCacheManager, ISystemAreaDomainService systemAreaDomainService, IFileRepository fileRepository, ISystemDicDataCacheManager systemDicDataCacheManager, ISnapshotOrderPublishRepository snapshotOrderPublishRepository, IRepository<WorkflowTrace> workflowTraceRepository, IPractitionerRepository practitionerRepository, IRepository<SystemArea> systemAreaRepository, IVolunteerRepository volunteerRepository, IVolunteerReportRepository volunteerReportRepository, ISystemLogRepository systemLog, IGuiderSystemService guiderSystemService, ICapPublisher capPublisher, Publisher publisher, IGuiderInfoRepository guiderInfoRepository, IFileDomainService fileDomainService, ICommunityInfoRepository communityInfoRepository, IRedPackAuditRepository redPackAuditRepository, IOrderVisitRepository orderVisitRepository) : base(thirdLoginService, industryRepository, bulletinRepository, sessionContext, redPackRecordRepository, orderRepository, thirdAccountRepository, orderSnapshotRepository, systemSettingCacheManager, systemAreaDomainService, fileRepository, systemDicDataCacheManager, snapshotOrderPublishRepository, workflowTraceRepository, practitionerRepository, systemAreaRepository, volunteerRepository, volunteerReportRepository, systemLog, guiderSystemService, capPublisher, publisher, guiderInfoRepository, fileDomainService, communityInfoRepository, redPackAuditRepository, orderVisitRepository)
+    public DefaultSnapshotApplication(IThirdIdentiyService thirdLoginService, IRepository<Industry> industryRepository, ISnapshotBulletinRepository bulletinRepository, ISessionContext sessionContext, IRepository<RedPackRecord> redPackRecordRepository, IRepository<Order> orderRepository, IThirdAccountRepository thirdAccountRepository, IOrderSnapshotRepository orderSnapshotRepository, ISystemSettingCacheManager systemSettingCacheManager, ISystemAreaDomainService systemAreaDomainService, IFileRepository fileRepository, ISystemDicDataCacheManager systemDicDataCacheManager, ISnapshotOrderPublishRepository snapshotOrderPublishRepository, IRepository<WorkflowTrace> workflowTraceRepository, IPractitionerRepository practitionerRepository, IRepository<SystemArea> systemAreaRepository, IVolunteerRepository volunteerRepository, IVolunteerReportRepository volunteerReportRepository, ISystemLogRepository systemLog, IGuiderSystemService guiderSystemService, ICapPublisher capPublisher, Publisher publisher, IGuiderInfoRepository guiderInfoRepository, IFileDomainService fileDomainService, ICommunityInfoRepository communityInfoRepository, IRedPackAuditRepository redPackAuditRepository, IOrderVisitRepository orderVisitRepository, IOrderVisitDetailRepository orderVisitDetailRepository) : base(thirdLoginService, industryRepository, bulletinRepository, sessionContext, redPackRecordRepository, orderRepository, thirdAccountRepository, orderSnapshotRepository, systemSettingCacheManager, systemAreaDomainService, fileRepository, systemDicDataCacheManager, snapshotOrderPublishRepository, workflowTraceRepository, practitionerRepository, systemAreaRepository, volunteerRepository, volunteerReportRepository, systemLog, guiderSystemService, capPublisher, publisher, guiderInfoRepository, fileDomainService, communityInfoRepository, redPackAuditRepository, orderVisitRepository, orderVisitDetailRepository)
     {
     }
 }

+ 149 - 0
src/Hotline.Application/Snapshot/IIndustryApplication.cs

@@ -1,4 +1,5 @@
 using Hotline.Share.Dtos.Snapshot;
+using Hotline.Snapshot;
 using SqlSugar;
 using System;
 using System.Collections.Generic;
@@ -21,4 +22,152 @@ public interface IIndustryApplication
     /// <param name="dto"></param>
     /// <returns></returns>
     ISugarQueryable<IndustryItemsOutDto> GetIndustres(IndustryListInDto dto);
+
+    /// <summary>
+    /// 获取行业详情
+    /// </summary>
+    /// <param name="id"></param>
+    /// <returns></returns>
+    Task<IndustryDetailOutDto> GetIndustryDetailAsync(string id);
+
+    /// <summary>
+    /// 修改行业
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <param name="requestAborted"></param>
+    /// <returns></returns>
+    Task UpdateIndustryAsync(UpdateIndustryInDto dto, CancellationToken requestAborted);
+
+    /// <summary>
+    /// 行业线索集合
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    ISugarQueryable<IndustryCaseItemOutDto> GetIndustryCaseItems(IndustryCaseItemInDto dto);
+
+    /// <summary>
+    /// 添加行业线索
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    Task<string> AddIndustryCaseAsync(AddIndustryCaseDto dto);
+
+    /// <summary>
+    /// 修改行业线索
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    Task UpdateIndustryCaseAsync(UpdateIndustryCaseDto dto);
+
+    /// <summary>
+    /// 获取行业线索详情
+    /// </summary>
+    /// <param name="caseId"></param>
+    /// <returns></returns>
+    Task<IndustryCase> GetIndustryCaseAsync(string caseId);
+
+    /// <summary>
+    /// 添加行业模板
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    Task<string> AddSMSTemplateAsync(AddSnapshotSMSTemplateInDto dto);
+
+    /// <summary>
+    /// 行业模板集合
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    ISugarQueryable<SnapshotSMSTemplateItemsOutDto> GetSMSTemplates(SnapshotSMSTemplateItemsInDto dto);
+
+    /// <summary>
+    /// 修改行业模板
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    Task UpdateSMSTemplateAsync(UpdateSnapshotSMSTemplateInDto dto);
+
+    /// <summary>
+    /// 短信详情
+    /// </summary>
+    /// <param name="id"></param>
+    /// <returns></returns>
+    Task<SnapshotSMSTemplateItemsOutDto> GetSMSTemplateDetailAsync(string id);
+
+    /// <summary>
+    /// 区域从业人员集合
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    ISugarQueryable<PractitionerItemsOutDto> GetPractitionerItemsAsync(PractitionerItemsInDto dto);
+
+    /// <summary>
+    /// 删除区域从业人员
+    /// </summary>
+    /// <param name="id"></param>
+    /// <returns></returns>
+    Task DeletePractitionerAsync(IList<string> id);
+
+    /// <summary>
+    /// 修改区域从业人员
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    Task UpdatePractitionerAsync(UpdatePractitionerInDto dto);
+
+    /// <summary>
+    /// 添加区域从业人员
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    Task<string> AddPractitionerAsync(AddPractitionerInDto dto);
+
+    /// <summary>
+    /// 区域从业人员详情
+    /// </summary>
+    /// <param name="id"></param>
+    /// <returns></returns>
+    Task<PractitionerItemsOutDto> GetPractitionerAsync(string id);
+
+    /// <summary>
+    /// 志愿者集合
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    ISugarQueryable<VolunteerItemsOutDto> GetVolunteerItemsAsync(VolunteerItemsInDto dto);
+
+    /// <summary>
+    /// 添加志愿者
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    Task<string> AddVolunteerAsync(AddVolunteerInDto dto);
+
+    /// <summary>
+    /// 批量删除志愿者
+    /// </summary>
+    /// <param name="ids"></param>
+    /// <returns></returns>
+    Task DeleteVolunteerAsync(IList<string> ids);
+
+    /// <summary>
+    /// 志愿者详情
+    /// </summary>
+    /// <param name="id"></param>
+    /// <returns></returns>
+    Task<Volunteer> GetVolunteerAsync(string id);
+
+    /// <summary>
+    /// 修改志愿者
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    Task UpdateVolunteerAsync(UpdateVolunteerInDto dto);
+
+    /// <summary>
+    /// 志愿者上报集合
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    ISugarQueryable<VolunteerReportItemsOutDto> GetVolunteerReportItemsAsync(VolunteerReportItemsInDto dto);
 }

+ 8 - 1
src/Hotline.Application/Snapshot/ISnapshotApplication.cs

@@ -139,7 +139,7 @@ public interface ISnapshotApplication
     /// </summary>
     /// <param name="dtos"></param>
     /// <returns></returns>
-    Task AddPractitionerAsync(IList<AddPractitionerInDto> dtos);
+    Task AddPractitionerAsync(IList<AddBatchPractitionerInDto> dtos);
 
     /// <summary>
     /// 添加志愿者
@@ -214,4 +214,11 @@ public interface ISnapshotApplication
     /// <param name="cancellationToken"></param>
     /// <returns></returns>
     Task<string> AddRedPardAsync(string id, CancellationToken cancellationToken);
+
+    /// <summary>
+    /// 获取回访详情
+    /// </summary>
+    /// <param name="id"></param>
+    /// <returns></returns>
+    Task<IList<OrderVisitItemsOutDto>> GetOrderVisitDetailAsync(string id);
 }

+ 323 - 3
src/Hotline.Application/Snapshot/IndustryApplication.cs

@@ -1,31 +1,47 @@
-using Hotline.File;
+using DocumentFormat.OpenXml.Office2010.Excel;
+using Hotline.Caching.Interfaces;
+using Hotline.File;
 using Hotline.Repository.SqlSugar.Extensions;
 using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.Snapshot;
 using Hotline.Share.Tools;
 using Hotline.Snapshot;
 using Hotline.Snapshot.Interfaces;
+using Hotline.Tools;
 using Mapster;
 using SqlSugar;
 using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
+using System.Threading;
 using System.Threading.Tasks;
 using XF.Domain.Dependency;
+using XF.Domain.Exceptions;
 
 namespace Hotline.Application.Snapshot;
 public class IndustryApplication : IIndustryApplication, IScopeDependency
 {
     private readonly IIndustryRepository _industryRepository;
     private readonly IFileRepository _fileRepository;
+    private readonly ISystemSettingCacheManager _sysSetting;
+    private readonly IIndustryCaseRepository _industryCaseRepository;
+    private readonly ISnapshotSMSTemplateRepository _snapshotSMSTemplateRepository;
+    private readonly IPractitionerRepository _practitionerRepository;
+    private readonly IVolunteerRepository _volunteerRepository;
+    private readonly IVolunteerReportRepository _volunteerReportRepository;
 
-    public IndustryApplication(IIndustryRepository industryRepository, IFileRepository fileRepository)
+    public IndustryApplication(IIndustryRepository industryRepository, IFileRepository fileRepository, ISystemSettingCacheManager sysSetting, IIndustryCaseRepository industryCaseRepository, ISnapshotSMSTemplateRepository snapshotSMSTemplateRepository, IPractitionerRepository practitionerRepository, IVolunteerRepository volunteerRepository, IVolunteerReportRepository volunteerReportRepository)
     {
         _industryRepository = industryRepository;
         _fileRepository = fileRepository;
+        _sysSetting = sysSetting;
+        _industryCaseRepository = industryCaseRepository;
+        _snapshotSMSTemplateRepository = snapshotSMSTemplateRepository;
+        _practitionerRepository = practitionerRepository;
+        _volunteerRepository = volunteerRepository;
+        _volunteerReportRepository = volunteerReportRepository;
     }
-
     /// <summary>
     /// 新增行业
     /// </summary>
@@ -50,9 +66,313 @@ public class IndustryApplication : IIndustryApplication, IScopeDependency
         var query = _industryRepository.Queryable()
             .WhereIF(dto.Name.NotNullOrEmpty(), m => m.Name.Contains(dto.Name))
             .WhereIF(dto.ApproveOrgName.NotNullOrEmpty(), m => m.ApproveOrgName.Contains(dto.ApproveOrgName))
+            .OrderByDescending(m => m.CreationTime)
             .Select<IndustryItemsOutDto>();
         
 
         return query;
     }
+
+    public async Task<IndustryDetailOutDto> GetIndustryDetailAsync(string id)
+    {
+        var fileServiceUrl = _sysSetting.FileServerUrl;
+        var fileDownloadApi = fileServiceUrl + _sysSetting.FileDownloadApi;
+        var industry = await _industryRepository.GetAsync(id);
+        var files = await _fileRepository.GetByKeyAsync(id, CancellationToken.None);
+        var outDto = industry.Adapt<IndustryDetailOutDto>();
+        outDto.Files = files.Adapt<IList<IndustryFileDto>>();
+        if (outDto.BackgroundImgUrl.NotNullOrEmpty())
+            outDto.BackgroundImgUrl = fileDownloadApi + outDto.BackgroundImgUrl;
+        if (outDto.BannerImgUrl.NotNullOrEmpty())
+            outDto.BannerImgUrl = fileDownloadApi + outDto.BannerImgUrl;
+        if (outDto.CareCellImgUrl.NotNullOrEmpty())
+            outDto.CareCellImgUrl = fileDownloadApi + outDto.CareCellImgUrl;
+        if (outDto.CellImgUrl.NotNullOrEmpty())
+            outDto.CellImgUrl = fileDownloadApi + outDto.CellImgUrl;
+        return outDto;
+    }
+
+    /// <summary>
+    /// 修改行业
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <param name="requestAborted"></param>
+    /// <returns></returns>
+    /// <exception cref="NotImplementedException"></exception>
+    public async Task UpdateIndustryAsync(UpdateIndustryInDto dto, CancellationToken requestAborted)
+    {
+        dto.ValidateObject();
+        var entity = await _industryRepository.GetAsync(dto.Id) ?? throw UserFriendlyException.SameMessage($"行业不存在 {dto.Id}");
+        if (dto.Files.NotNullOrEmpty())
+        {
+            var fileEntities = dto.Files.Adapt<List<File.File>>();
+            fileEntities.ForEach(m => m.Key = entity.Id);
+            await _fileRepository.Removeable().Where(m => m.Key == entity.Id).ExecuteCommandAsync(requestAborted);
+            await _fileRepository.AddRangeAsync(fileEntities, requestAborted);
+        }
+        dto.Adapt(entity);
+        await _industryRepository.UpdateAsync(entity, requestAborted);
+    }
+
+    #region 行业线索
+    public ISugarQueryable<IndustryCaseItemOutDto> GetIndustryCaseItems(IndustryCaseItemInDto dto)
+    { 
+        var query = _industryCaseRepository.Queryable()
+            .LeftJoin<Industry>((c, i) => c.IndustryId == i.Id)
+            .WhereIF(dto.IndustryName.NotNullOrEmpty(), (c, i) => i.Name.Contains(dto.IndustryName))
+            .WhereIF(dto.CaseName.NotNullOrEmpty(), (c, i) => c.Name.Contains(dto.CaseName))
+            .OrderByDescending((c, i) => c.CreationTime)
+            .Select<IndustryCaseItemOutDto>((c, i) => 
+            new IndustryCaseItemOutDto {
+                Id = c.Id,
+                Name = c.Name,
+            IndustryId = i.Id, 
+            IndustryName = i.Name}, true);
+        return query;
+    }
+
+    /// <summary>
+    /// 添加行业线索
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    public async Task<string> AddIndustryCaseAsync(AddIndustryCaseDto dto)
+    {
+        dto.ValidateObject();
+        var entity = dto.Adapt<IndustryCase>();
+        entity.CitizenReadPackAmount = entity.CitizenReadPackAmount * 100;
+        entity.GuiderReadPackAmount = entity.GuiderReadPackAmount * 100;
+        return await _industryCaseRepository.AddAsync(entity);
+    }
+
+    /// <summary>
+    /// 修改行业线索
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    public async Task UpdateIndustryCaseAsync(UpdateIndustryCaseDto dto)
+    {
+        dto.ValidateObject();
+        var entity = await _industryCaseRepository.GetAsync(dto.Id) 
+            ?? throw UserFriendlyException.SameMessage($"行业线索不存在 {dto.Id}");
+        dto.Adapt(entity);
+        await _industryCaseRepository.UpdateAsync(entity);
+    }
+
+    public async Task<IndustryCase> GetIndustryCaseAsync(string caseId)
+    {
+        return await _industryCaseRepository.GetAsync(caseId);
+    }
+    #endregion
+
+    #region 行业短信模板
+
+    /// <summary>
+    /// 行业模板集合
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    public ISugarQueryable<SnapshotSMSTemplateItemsOutDto> GetSMSTemplates(SnapshotSMSTemplateItemsInDto dto)
+    {
+        var query = _snapshotSMSTemplateRepository.Queryable()
+            .LeftJoin<Industry>((s, i) => s.IndustryId == i.Id)
+            .WhereIF(dto.IndustryName.NotNullOrEmpty(), (s, i) => i.Name.Contains(dto.IndustryName))
+            .OrderByDescending((s, i) => s.DisplayOrder)
+            .Select<SnapshotSMSTemplateItemsOutDto>();
+        return query;
+    }
+
+    /// <summary>
+    /// 添加行业模板
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    public async Task<string> AddSMSTemplateAsync(AddSnapshotSMSTemplateInDto dto)
+    {
+        dto.ValidateObject();
+        var entity = dto.Adapt<SnapshotSMSTemplate>();
+        return await _snapshotSMSTemplateRepository.AddAsync(entity);
+    }
+
+    /// <summary>
+    /// 修改行业模板
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    public async Task UpdateSMSTemplateAsync(UpdateSnapshotSMSTemplateInDto dto)
+    {
+        dto.ValidateObject();
+        var entity = await _snapshotSMSTemplateRepository.GetAsync(dto.Id)
+            ?? throw UserFriendlyException.SameMessage($"行业短信模板不存在 {dto.Id}");
+        dto.Adapt(entity);
+        await _snapshotSMSTemplateRepository.UpdateAsync(entity);
+    }
+
+    /// <summary>
+    /// 短信详情
+    /// </summary>
+    /// <param name="id"></param>
+    /// <returns></returns>
+    public async Task<SnapshotSMSTemplateItemsOutDto> GetSMSTemplateDetailAsync(string id)
+    {
+        return await _snapshotSMSTemplateRepository.Queryable()
+            .LeftJoin<Industry>((s, i) => s.IndustryId == i.Id)
+            .Where((s, i) => s.Id == id)
+            .Select<SnapshotSMSTemplateItemsOutDto>()
+            .FirstAsync();
+    }
+
+    #endregion
+
+    #region 区域从业人员
+    /// <summary>
+    /// 区域从业人员集合
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    /// <exception cref="NotImplementedException"></exception>
+    public ISugarQueryable<PractitionerItemsOutDto> GetPractitionerItemsAsync(PractitionerItemsInDto dto)
+    {
+        var query = _practitionerRepository.Queryable()
+            .WhereIF(dto.Name.NotNullOrEmpty(), m => m.Name.Contains(dto.Name!))
+            .WhereIF(dto.SystemAreaName.NotNullOrEmpty(), m => m.SystemAreaName.Contains(dto.SystemAreaName!))
+            .WhereIF(dto.PhoneNumber.NotNullOrEmpty(), m => m.PhoneNumber.Contains(dto.PhoneNumber!))
+            .OrderByDescending(m => m.CreationTime)
+            .Select<PractitionerItemsOutDto>();
+
+        return query;
+    }
+
+    /// <summary>
+    /// 添加区域从业人员
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    public async Task<string> AddPractitionerAsync(AddPractitionerInDto dto)
+    {
+        dto.ValidateObject();
+        var entity = dto.Adapt<Practitioner>();
+        return await _practitionerRepository.AddAsync(entity);
+    }
+
+    /// <summary>
+    /// 区域从业人员详情
+    /// </summary>
+    /// <param name="id"></param>
+    /// <returns></returns>
+    public async Task<PractitionerItemsOutDto> GetPractitionerAsync(string id)
+    {
+        return (await _practitionerRepository.GetAsync(id)).Adapt<PractitionerItemsOutDto>();
+    }
+
+    /// <summary>
+    /// 删除区域从业人员
+    /// </summary>
+    /// <param name="id"></param>
+    /// <returns></returns>
+    public async Task DeletePractitionerAsync(IList<string> id)
+    {
+        await _practitionerRepository.Updateable()
+            .SetColumns(m => m.IsDeleted, true)
+            .Where(m => id.Contains(m.Id))
+            .ExecuteCommandAsync();
+    }
+
+    /// <summary>
+    /// 修改区域从业人员
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    public async Task UpdatePractitionerAsync(UpdatePractitionerInDto dto)
+    {
+        dto.ValidateObject();
+
+        var entity = await _practitionerRepository.GetAsync(dto.Id) ?? throw UserFriendlyException.SameMessage($"从业人员不存在 {dto.Id}");
+        dto.Adapt(entity);
+        await _practitionerRepository.UpdateAsync(entity);
+    }
+
+    #endregion
+
+    #region 志愿者
+
+    /// <summary>
+    /// 志愿者集合
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    /// <exception cref="NotImplementedException"></exception>
+    public ISugarQueryable<VolunteerItemsOutDto> GetVolunteerItemsAsync(VolunteerItemsInDto dto)
+    {
+        var query = _volunteerRepository.Queryable()
+            .WhereIF(dto.Name.NotNullOrEmpty(), m => m.Name.Contains(dto.Name))
+            .WhereIF(dto.PhoneNumber.NotNullOrEmpty(), m => m.PhoneNumber.Contains(dto.PhoneNumber))
+            .OrderByDescending(m => m.CreationTime)
+            .Select<VolunteerItemsOutDto>();
+        return query;
+    }
+
+    /// <summary>
+    /// 添加志愿者
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    public async Task<string> AddVolunteerAsync(AddVolunteerInDto dto)
+    {
+        var entity = dto.Adapt<Volunteer>();
+        entity.Id = await _volunteerRepository.AddAsync(entity);
+        return entity.Id;
+    }
+
+    /// <summary>
+    /// 批量删除志愿者
+    /// </summary>
+    /// <param name="ids"></param>
+    /// <returns></returns>
+    public async Task DeleteVolunteerAsync(IList<string> ids)
+    {
+        await _volunteerRepository.Updateable()
+            .SetColumns(m => m.IsDeleted, true)
+            .Where(m => ids.Contains(m.Id))
+            .ExecuteCommandAsync();
+    }
+
+    /// <summary>
+    /// 志愿者详情
+    /// </summary>
+    /// <param name="id"></param>
+    /// <returns></returns>
+    public async Task<Volunteer> GetVolunteerAsync(string id)
+    {
+        return await _volunteerRepository.GetAsync(id);
+    }
+
+    /// <summary>
+    /// 修改志愿者
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    public async Task UpdateVolunteerAsync(UpdateVolunteerInDto dto)
+    {
+        dto.ValidateObject();
+        var entity = await _volunteerRepository.GetAsync(dto.Id) ?? throw UserFriendlyException.SameMessage($"志愿者不存在 {dto.Id}");
+        dto.Adapt(entity);
+        await _volunteerRepository.UpdateAsync(entity);
+    }
+
+    /// <summary>
+    /// 志愿者上报集合
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    public ISugarQueryable<VolunteerReportItemsOutDto> GetVolunteerReportItemsAsync(VolunteerReportItemsInDto dto)
+    {
+        var query = _volunteerReportRepository.Queryable()
+            .WhereIF(dto.Name.NotNullOrEmpty(), m => m.Name.Contains(dto.Name))
+            .WhereIF(dto.PhoneNumber.NotNullOrEmpty(), m => m.PhoneNumber.Contains(dto.PhoneNumber))
+            .OrderByDescending(m => m.CreationTime)
+            .Select<VolunteerReportItemsOutDto>();
+        return query;
+    }
+    #endregion
 }

+ 44 - 7
src/Hotline.Application/Snapshot/SnapshotApplicationBase.cs

@@ -35,6 +35,7 @@ using Hotline.Snapshot.Notifications;
 using Hotline.EventBus;
 using Hotline.Quality.Notifications;
 using Hotline.Settings.SystemLogDomain;
+using XF.Utility.EnumExtensions;
 
 namespace Hotline.Application.Snapshot;
 
@@ -74,8 +75,9 @@ public abstract class SnapshotApplicationBase
     private readonly ICommunityInfoRepository _communityInfoRepository;
     private readonly IRedPackAuditRepository _redPackAuditRepository;
     private readonly IOrderVisitRepository _orderVisitRepository;
+    private readonly IOrderVisitDetailRepository _orderVisitDetailRepository;
 
-    public SnapshotApplicationBase(IThirdIdentiyService thirdLoginService, IRepository<Industry> industryRepository, ISnapshotBulletinRepository bulletinRepository, ISessionContext sessionContext, IRepository<RedPackRecord> redPackRecordRepository, IRepository<Order> orderRepository, IThirdAccountRepository thirdAccountRepository, IOrderSnapshotRepository orderSnapshotRepository, ISystemSettingCacheManager systemSettingCacheManager, ISystemAreaDomainService systemAreaDomainService, IFileRepository fileRepository, ISystemDicDataCacheManager systemDicDataCacheManager, ISnapshotOrderPublishRepository snapshotOrderPublishRepository, IRepository<WorkflowTrace> workflowTraceRepository, IPractitionerRepository practitionerRepository, IRepository<SystemArea> systemAreaRepository, IVolunteerRepository volunteerRepository, IVolunteerReportRepository volunteerReportRepository, ISystemLogRepository systemLog, IGuiderSystemService guiderSystemService, ICapPublisher capPublisher, Publisher publisher, IGuiderInfoRepository guiderInfoRepository, IFileDomainService fileDomainService, ICommunityInfoRepository communityInfoRepository, IRedPackAuditRepository redPackAuditRepository, IOrderVisitRepository orderVisitRepository)
+    public SnapshotApplicationBase(IThirdIdentiyService thirdLoginService, IRepository<Industry> industryRepository, ISnapshotBulletinRepository bulletinRepository, ISessionContext sessionContext, IRepository<RedPackRecord> redPackRecordRepository, IRepository<Order> orderRepository, IThirdAccountRepository thirdAccountRepository, IOrderSnapshotRepository orderSnapshotRepository, ISystemSettingCacheManager systemSettingCacheManager, ISystemAreaDomainService systemAreaDomainService, IFileRepository fileRepository, ISystemDicDataCacheManager systemDicDataCacheManager, ISnapshotOrderPublishRepository snapshotOrderPublishRepository, IRepository<WorkflowTrace> workflowTraceRepository, IPractitionerRepository practitionerRepository, IRepository<SystemArea> systemAreaRepository, IVolunteerRepository volunteerRepository, IVolunteerReportRepository volunteerReportRepository, ISystemLogRepository systemLog, IGuiderSystemService guiderSystemService, ICapPublisher capPublisher, Publisher publisher, IGuiderInfoRepository guiderInfoRepository, IFileDomainService fileDomainService, ICommunityInfoRepository communityInfoRepository, IRedPackAuditRepository redPackAuditRepository, IOrderVisitRepository orderVisitRepository, IOrderVisitDetailRepository orderVisitDetailRepository)
     {
         _thirdLoginService = thirdLoginService;
         _industryRepository = industryRepository;
@@ -104,6 +106,7 @@ public abstract class SnapshotApplicationBase
         _communityInfoRepository = communityInfoRepository;
         _redPackAuditRepository = redPackAuditRepository;
         _orderVisitRepository = orderVisitRepository;
+        _orderVisitDetailRepository = orderVisitDetailRepository;
     }
 
     #region 小程序
@@ -234,10 +237,10 @@ public abstract class SnapshotApplicationBase
     /// <returns></returns>
     public async Task<OrderPublishDetailOutDto> GetOrderPublishDetailAsync(string id, CancellationToken requestAborted)
     {
-        var publish = await _snapshotOrderPublishRepository.GetAsync(id) ??
+        var order = await _orderRepository.GetAsync(id) ??
             throw UserFriendlyException.SameMessage("工单不存在");
 
-        var outDto = publish.Adapt<OrderPublishDetailOutDto>();
+        var outDto = order.Adapt<OrderPublishDetailOutDto>();
         var fileServiceUrl = _sysSetting.FileServerUrl;
         if (outDto.FileJson != null)
         {
@@ -247,7 +250,7 @@ public abstract class SnapshotApplicationBase
             }
         }
         var traces = await _workflowTraceRepository.Queryable()
-            .Where(m => m.ExternalId == publish.OrderId && m.Status == EWorkflowStepStatus.Handled)
+            .Where(m => m.ExternalId == order.Id && m.Status == EWorkflowStepStatus.Handled)
             .OrderBy(m => m.AcceptTime)
             .ToListAsync(requestAborted);
         var centre = traces.Where(m => m.StepType == EStepType.End || m.StepType == EStepType.Start || m.BusinessType == EBusinessType.Send || m.BusinessType == EBusinessType.Seat || m.BusinessType == EBusinessType.File)
@@ -317,7 +320,7 @@ public abstract class SnapshotApplicationBase
             .WhereIF(dto.Status == EOrderQueryStatus.Appraise, (snapshot, order) => order.Status == EOrderStatus.Visited)
             .WhereIF(dto.Status == EOrderQueryStatus.NoReply, (snapshot, order) => order.Status < EOrderStatus.Filed)
             .WhereIF(dto.Status == EOrderQueryStatus.Reply, (snapshot, order) => order.Status >= EOrderStatus.Filed)
-            .WhereIF(dto.KeyWords.NotNullOrEmpty(), (snapshot, order) => order.Title.Contains(dto.KeyWords))
+            .WhereIF(dto.KeyWords.NotNullOrEmpty(), (snapshot, order) => order.Title.Contains(dto.KeyWords) || order.No.Contains(dto.KeyWords))
             .Select((snapshot, order) => new OrderOutDto
             {
                 Id = snapshot.Id,
@@ -387,6 +390,40 @@ public abstract class SnapshotApplicationBase
         return outDto;
     }
 
+    /// <summary>
+    /// 获取回访详情
+    /// </summary>
+    /// <param name="id"></param>
+    /// <returns></returns>
+    public async Task<IList<OrderVisitItemsOutDto>> GetOrderVisitDetailAsync(string id)
+    { 
+        var orderVisitId = await _orderVisitRepository.Queryable()
+            .Where(m => m.OrderId == id)
+            .Select(m => m.Id)
+            .FirstAsync();
+        if (orderVisitId.IsNullOrEmpty()) return [];
+        var orderVisitDetail = await _orderVisitDetailRepository.Queryable()
+            .Where(m => m.VisitId == orderVisitId)
+            .ToListAsync();
+        if (orderVisitDetail.IsNullOrEmpty()) return [];
+        var seat = orderVisitDetail.Where(m => m.VisitTarget == EVisitTarget.Seat).First();
+        var item = new OrderVisitItemsOutDto();
+        if (seat != null && seat.SeatEvaluate.HasValue)
+        {
+            item.SeatEvaluate = seat.SeatEvaluate.Value.GetDescription();
+        }
+        var org = orderVisitDetail.Where(m => m.VisitTarget == EVisitTarget.Org).First();
+        if (org != null)
+        { 
+            if (org.OrgProcessingResults != null) item.OrgProcessingResults = org.OrgProcessingResults.Value;
+            if (org.OrgHandledAttitude != null) item.OrgHandledAttitude = org.OrgHandledAttitude.Value;
+        }
+        return
+        [
+            item
+        ];
+    }
+
     /// <summary>
     /// 获取当月详细红包列表
     /// </summary>
@@ -633,7 +670,7 @@ public abstract class SnapshotApplicationBase
     /// </summary>
     /// <param name="dtos"></param>
     /// <returns></returns>
-    public async Task AddPractitionerAsync(IList<AddPractitionerInDto> dtos)
+    public async Task AddPractitionerAsync(IList<AddBatchPractitionerInDto> dtos)
     {
         foreach (var item in dtos)
         {
@@ -653,7 +690,7 @@ public abstract class SnapshotApplicationBase
                         break;
                 }
                 var area = await _systemAreaRepository.Queryable()
-                    .Where(m => m.AreaName == item.SystemAreaName)
+                    .Where(m => m.AreaName == item.AreaName)
                     .FirstAsync();
                 entity.SystemAreaId = area.Id;
                 entity.SystemAreaName = area.AreaName;

+ 1 - 1
src/Hotline.Application/Snapshot/ZiGongSnapshotApplication.cs

@@ -24,7 +24,7 @@ namespace Hotline.Application.Snapshot;
 [Injection(AppScopes = EAppScope.ZiGong)]
 public class ZiGongSnapshotApplication : SnapshotApplicationBase, ISnapshotApplication, IScopeDependency
 {
-    public ZiGongSnapshotApplication(IThirdIdentiyService thirdLoginService, IRepository<Industry> industryRepository, ISnapshotBulletinRepository bulletinRepository, ISessionContext sessionContext, IRepository<RedPackRecord> redPackRecordRepository, IRepository<Order> orderRepository, IThirdAccountRepository thirdAccountRepository, IOrderSnapshotRepository orderSnapshotRepository, ISystemSettingCacheManager systemSettingCacheManager, ISystemAreaDomainService systemAreaDomainService, IFileRepository fileRepository, ISystemDicDataCacheManager systemDicDataCacheManager, ISnapshotOrderPublishRepository snapshotOrderPublishRepository, IRepository<WorkflowTrace> workflowTraceRepository, IPractitionerRepository practitionerRepository, IRepository<SystemArea> systemAreaRepository, IVolunteerRepository volunteerRepository, IVolunteerReportRepository volunteerReportRepository, ISystemLogRepository systemLog, IGuiderSystemService guiderSystemService, ICapPublisher capPublisher, Publisher publisher, IGuiderInfoRepository guiderInfoRepository, IFileDomainService fileDomainService, ICommunityInfoRepository communityInfoRepository, IRedPackAuditRepository redPackAuditRepository, IOrderVisitRepository orderVisitRepository) : base(thirdLoginService, industryRepository, bulletinRepository, sessionContext, redPackRecordRepository, orderRepository, thirdAccountRepository, orderSnapshotRepository, systemSettingCacheManager, systemAreaDomainService, fileRepository, systemDicDataCacheManager, snapshotOrderPublishRepository, workflowTraceRepository, practitionerRepository, systemAreaRepository, volunteerRepository, volunteerReportRepository, systemLog, guiderSystemService, capPublisher, publisher, guiderInfoRepository, fileDomainService, communityInfoRepository, redPackAuditRepository, orderVisitRepository)
+    public ZiGongSnapshotApplication(IThirdIdentiyService thirdLoginService, IRepository<Industry> industryRepository, ISnapshotBulletinRepository bulletinRepository, ISessionContext sessionContext, IRepository<RedPackRecord> redPackRecordRepository, IRepository<Order> orderRepository, IThirdAccountRepository thirdAccountRepository, IOrderSnapshotRepository orderSnapshotRepository, ISystemSettingCacheManager systemSettingCacheManager, ISystemAreaDomainService systemAreaDomainService, IFileRepository fileRepository, ISystemDicDataCacheManager systemDicDataCacheManager, ISnapshotOrderPublishRepository snapshotOrderPublishRepository, IRepository<WorkflowTrace> workflowTraceRepository, IPractitionerRepository practitionerRepository, IRepository<SystemArea> systemAreaRepository, IVolunteerRepository volunteerRepository, IVolunteerReportRepository volunteerReportRepository, ISystemLogRepository systemLog, IGuiderSystemService guiderSystemService, ICapPublisher capPublisher, Publisher publisher, IGuiderInfoRepository guiderInfoRepository, IFileDomainService fileDomainService, ICommunityInfoRepository communityInfoRepository, IRedPackAuditRepository redPackAuditRepository, IOrderVisitRepository orderVisitRepository, IOrderVisitDetailRepository orderVisitDetailRepository) : base(thirdLoginService, industryRepository, bulletinRepository, sessionContext, redPackRecordRepository, orderRepository, thirdAccountRepository, orderSnapshotRepository, systemSettingCacheManager, systemAreaDomainService, fileRepository, systemDicDataCacheManager, snapshotOrderPublishRepository, workflowTraceRepository, practitionerRepository, systemAreaRepository, volunteerRepository, volunteerReportRepository, systemLog, guiderSystemService, capPublisher, publisher, guiderInfoRepository, fileDomainService, communityInfoRepository, redPackAuditRepository, orderVisitRepository, orderVisitDetailRepository)
     {
     }
 }

+ 2 - 1
src/Hotline.Repository.SqlSugar/Orders/OrderVisitDetailRepository.cs

@@ -6,9 +6,10 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
+using XF.Domain.Dependency;
 
 namespace Hotline.Repository.SqlSugar.Orders;
-public class OrderVisitDetailRepository : BaseRepository<OrderVisitDetail>, IOrderVisitDetailRepository
+public class OrderVisitDetailRepository : BaseRepository<OrderVisitDetail>, IOrderVisitDetailRepository, IScopeDependency
 {
     public OrderVisitDetailRepository(ISugarUnitOfWork<HotlineDbContext> uow, IDataPermissionFilterBuilder dataPermissionFilterBuilder) : base(uow, dataPermissionFilterBuilder)
     {

+ 19 - 0
src/Hotline.Repository.SqlSugar/Snapshot/IndustryCaseRepository.cs

@@ -0,0 +1,19 @@
+using Hotline.Repository.SqlSugar.DataPermissions;
+using Hotline.Snapshot;
+using Hotline.Snapshot.Interfaces;
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Dependency;
+
+namespace Hotline.Repository.SqlSugar.Snapshot;
+public class IndustryCaseRepository : BaseRepository<IndustryCase>, IIndustryCaseRepository, IScopeDependency
+{
+    public IndustryCaseRepository(ISugarUnitOfWork<HotlineDbContext> uow, IDataPermissionFilterBuilder dataPermissionFilterBuilder) : base(uow, dataPermissionFilterBuilder)
+    {
+    }
+}
+

+ 18 - 0
src/Hotline.Repository.SqlSugar/Snapshot/SnapshotSMSTemplateRepository.cs

@@ -0,0 +1,18 @@
+using Hotline.Repository.SqlSugar.DataPermissions;
+using Hotline.Snapshot;
+using Hotline.Snapshot.Interfaces;
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Dependency;
+
+namespace Hotline.Repository.SqlSugar.Snapshot;
+public class SnapshotSMSTemplateRepository : BaseRepository<SnapshotSMSTemplate>, ISnapshotSMSTemplateRepository, IScopeDependency
+{
+    public SnapshotSMSTemplateRepository(ISugarUnitOfWork<HotlineDbContext> uow, IDataPermissionFilterBuilder dataPermissionFilterBuilder) : base(uow, dataPermissionFilterBuilder)
+    {
+    }
+}

+ 5 - 0
src/Hotline.Share/Dtos/Identity/LoginDto.cs

@@ -116,6 +116,11 @@ namespace Hotline.Share.Dtos.Identity
         /// 下载地址前缀
         /// </summary>
         public string RecordDownLoadPrefix { get; set; }
+
+        /// <summary>
+        /// 随手拍功能开关
+        /// </summary>
+        public bool Snapshot { get; set; }
     }
 
 

+ 260 - 6
src/Hotline.Share/Dtos/Snapshot/IndustryDto.cs

@@ -1,19 +1,67 @@
-using Hotline.Share.Dtos.Settings;
+using Hotline.Share.Dtos.File;
+using Hotline.Share.Dtos.Settings;
+using Hotline.Share.Enums.Order;
+using Hotline.Share.Enums.Snapshot;
 using Hotline.Share.Requests;
+using Hotline.Share.Tools;
 using System;
 using System.Collections.Generic;
 using System.ComponentModel.DataAnnotations;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
+using XF.Utility.EnumExtensions;
 
 namespace Hotline.Share.Dtos.Snapshot;
 internal class IndustryDto
 {
 }
 
+public class IndustryDetailOutDto : IndustryItemsOutDto
+{
+    /// <summary>
+    /// 背景图片 url
+    /// </summary>
+    public string? BackgroundImgUrl { get; set; }
+
+    /// <summary>
+    /// Banner 图片 url
+    /// </summary>
+    public string? BannerImgUrl { get; set; }
+
+    /// <summary>
+    /// 宫格图
+    /// </summary>
+    public string? CellImgUrl { get; set; }
+
+    /// <summary>
+    /// 关怀宫格图
+    /// </summary>
+    public string? CareCellImgUrl { get; set; }
+
+    /// <summary>
+    /// 附件集合(小程序上面可以下载的 doc 文件)
+    /// </summary>
+    public IList<IndustryFileDto> Files { get; set; }
+}
+
 public class IndustryItemsOutDto : IndustryOutDto
 {
+    /// <summary>
+    /// 受理类型
+    /// </summary>
+    public string AcceptType { get; set; }
+
+    /// <summary>
+    /// 受理类型代码
+    /// </summary>
+    public string? AcceptTypeCode { get; set; }
+
+    /// <summary>
+    /// 标题追加信息
+    /// </summary>
+    public string? TitleSuffix { get; set; }
+
     /// <summary>
     /// 审批部门Id
     /// </summary>
@@ -25,14 +73,14 @@ public class IndustryItemsOutDto : IndustryOutDto
     public string? ApproveOrgName { get; set; }
 
     /// <summary>
-    /// 市民发放红包金额(单位:)
+    /// 市民发放红包金额(单位:)
     /// </summary>
-    public int CitizenReadPackAmount { get; set; }
+    public double CitizenReadPackAmount { get; set; }
 
     /// <summary>
-    /// 网络员发放红包金额(单位:)
+    /// 网络员发放红包金额(单位:)
     /// </summary>
-    public int GuiderReadPackAmount { get; set; }
+    public double GuiderReadPackAmount { get; set; }
 
     /// <summary>
     /// 是否启用
@@ -43,8 +91,8 @@ public class IndustryItemsOutDto : IndustryOutDto
     /// 排序
     /// </summary>
     public int DisplayOrder { get; set; }
-
 }
+
 public class IndustryOutDto
 {
     /// <summary>
@@ -90,6 +138,14 @@ public class IndustryOutDto
 /// <param name="departmentName">审批部门</param>
 public record IndustryListInDto(string? Name, string? ApproveOrgName) : PagedRequest;
 
+/// <summary>
+/// 行业线索集合入参
+/// </summary>
+/// <param name="CaseName">线索名称</param>
+/// <param name="IndustryName">行业名称</param>
+public record IndustryCaseItemInDto(string? CaseName, string? IndustryName) : PagedRequest;
+
+
 public class IndustryBaseOutDto
 {
     /// <summary>
@@ -133,6 +189,15 @@ public class IndustryBaseOutDto
     public IReadOnlyList<SystemDicDataOutDto> BusinessUnitType { get; set; }
 }
 
+public class UpdateIndustryInDto : AddIndustryDto
+{
+    /// <summary>
+    /// Id
+    /// </summary>
+    [Required]
+    public string Id { get; set; }
+}
+
 public class AddIndustryDto
 {
     /// <summary>
@@ -183,6 +248,11 @@ public class AddIndustryDto
     /// </summary>
     public bool IsEnable { get; set; }
 
+    /// <summary>
+    /// App是否启用
+    /// </summary>
+    public bool IsAppEnable { get; set; }
+
     /// <summary>
     /// 帮助引导用语
     /// </summary>
@@ -267,3 +337,187 @@ public class AddIndustryDto
     /// </summary>
     public IList<IndustryFileDto> Files { get; set; }
 }
+
+public class IndustryCaseItemOutDto : AddIndustryCaseDto
+{
+    /// <summary>
+    /// Id
+    /// </summary>
+    public string Id { get; set; }
+
+    /// <summary>
+    /// 行业名称
+    /// </summary>
+    public string IndustryName { get; set; }
+
+    /// <summary>
+    /// 市民发放红包金额(单位:元)
+    /// </summary>
+    public string CitizenReadPackAmountTxt => CitizenReadPackAmount.ToYuanFinance();
+
+    /// <summary>
+    /// 网络员发放红包金额(单位:元)
+    /// </summary>
+    public string GuiderReadPackAmountTxt => GuiderReadPackAmount.ToYuanFinance();
+}
+
+public class UpdateIndustryCaseDto : AddIndustryCaseDto
+{
+    /// <summary>
+    /// Id
+    /// </summary>
+    [Required]
+    public string Id { get; set; }
+}
+
+public class AddIndustryCaseDto
+{
+    /// <summary>
+    /// 行业Id
+    /// </summary>
+    [Required]
+    public string IndustryId { get; set; }
+
+    /// <summary>
+    /// 线索名称
+    /// </summary>
+    [Required]
+    public string Name { get; set; }
+
+    /// <summary>
+    /// 市民发放红包金额(单位:元)
+    /// </summary>
+    public double CitizenReadPackAmount { get; set; }
+
+    /// <summary>
+    /// 网络员发放红包金额(单位:元)
+    /// </summary>
+    public double GuiderReadPackAmount { get; set; }
+
+    /// <summary>
+    /// 是否启用
+    /// </summary>
+    public bool IsEnable { get; set; }
+
+    /// <summary>
+    /// 排序
+    /// </summary>
+    public int DisplayOrder { get; set; }
+}
+
+/// <summary>
+/// 行业短信模板集合入参
+/// </summary>
+/// <param name="IndustryName">行业名称</param>
+public record SnapshotSMSTemplateItemsInDto(string? IndustryName) : PagedRequest;
+
+public class SnapshotSMSTemplateItemsOutDto : AddSnapshotSMSTemplateInDto
+{
+    /// <summary>
+    /// Id
+    /// </summary>
+    public string Id { get; set; }
+
+    /// <summary>
+    /// 审核状态
+    /// </summary>
+    public string StatusTxt => Status.GetDescription();
+
+    /// <summary>
+    /// 行业名称
+    /// </summary>
+    public string IndustryName { get; set; }
+}
+
+public class UpdateSnapshotSMSTemplateInDto : AddSnapshotSMSTemplateInDto
+{
+    /// <summary>
+    /// Id
+    /// </summary>
+    public string Id { get; set; }
+}
+public class AddSnapshotSMSTemplateInDto
+{
+    /// <summary>
+    /// 行业Id
+    /// </summary>
+    [Required]
+    public string IndustryId { get; set; }
+
+    /// <summary>
+    /// 模板内容
+    /// </summary>
+    [Required]
+    public string Content { get; set; }
+
+    /// <summary>
+    /// 审核状态
+    /// </summary>
+    public ESnapshotSMSStatus Status { get; set; }
+
+    /// <summary>
+    /// 是否启用
+    /// </summary>
+    public bool IsEnable { get; set; }
+
+    /// <summary>
+    /// 是否公用
+    /// </summary>
+    public bool IsPublic { get; set; }
+
+    /// <summary>
+    /// 排序
+    /// </summary>
+    public int DisplayOrder { get; set; }
+}
+
+/// <summary>
+/// 区域从业人员集合入参
+/// </summary>
+/// <param name="Name">姓名</param>
+/// <param name="PhoneNumber">联系方式</param>
+/// <param name="SystemAreaName">区县</param>
+public record PractitionerItemsInDto(string? Name, string? PhoneNumber, string? SystemAreaName) : PagedRequest;
+
+public class PractitionerItemsOutDto
+{
+    /// <summary>
+    /// Id
+    /// </summary>
+    public string Id { get; set; }
+
+    /// <summary>
+    /// 名字
+    /// </summary>
+    public string Name { get; set; }
+
+    /// <summary>
+    /// 区域Id
+    /// </summary>
+    public string SystemAreaId { get; set; }
+
+    /// <summary>
+    /// 区域名称
+    /// </summary>
+    public string SystemAreaName { get; set; }
+
+    /// <summary>
+    /// 详细街道
+    /// </summary>
+    public string Street { get; set; }
+
+    /// <summary>
+    /// 电话
+    /// </summary>
+    public string PhoneNumber { get; set; }
+
+    /// <summary>
+    /// 性别
+    /// </summary>
+    public EGender Gender { get; set; }
+
+    /// <summary>
+    /// 性别
+    /// </summary>
+    public string GenderTxt => Gender.GetDescription();
+}

+ 6 - 2
src/Hotline.Share/Dtos/Snapshot/OrderDto.cs

@@ -15,7 +15,11 @@ public class OrderInDto : QueryFixedDto
     public string? KeyWords { get; set; }
 
     /// <summary>
-    /// 工单状态
+    /// 工单状态;
+    /// 0: 全部;
+    /// 1: 未回复;
+    /// 2: 已回复;
+    /// 3: 已评价;
     /// </summary>
     public EOrderQueryStatus Status { get; set; }
 }
@@ -166,7 +170,7 @@ public class AddSnapshotOrderInDto : Position
                     $"作业时间:{this.StartWorkTime.Value.ToString("yyyy-MM-dd hh:mm")}~{this.EndWorkTime.Value.ToString("yyyy-MM-dd hh:mm")}\r\n" +
                     $"作业地点: {this.Town}({this.County})({this.Street})"; // 舒平(自流井区)(油库)"
         }
-        return $"{Description} (地址:{Street}({Town}{County}))";
+        return $"{Description}";
     }
 
     public string GetTitle(EIndustryType industryType, string acceptType)

+ 26 - 0
src/Hotline.Share/Dtos/Snapshot/OrderPublishDto.cs

@@ -175,3 +175,29 @@ public class OrderPublishOutDto
     public string County { get; set; }
 }
 
+
+/// <summary>
+/// 满意度
+/// </summary>
+public class OrderVisitItemsOutDto
+{
+    /// <summary>
+    /// 中心满意度
+    /// </summary>
+    public string SeatEvaluate { get; set; }
+
+    /// <summary>
+    /// 部门满意度
+    /// </summary>
+    public string OrgProcessingResults { get; set; }
+
+    /// <summary>
+    /// 办事态度
+    /// </summary>
+    public string OrgHandledAttitude { get; set; }
+
+    /// <summary>
+    /// 备注
+    /// </summary>
+    public string Remark { get; set; }
+}

+ 55 - 2
src/Hotline.Share/Dtos/Snapshot/PractitionerDto.cs

@@ -7,7 +7,7 @@ using System.Text;
 using System.Threading.Tasks;
 
 namespace Hotline.Share.Dtos.Snapshot;
-public class AddPractitionerInDto
+public class AddBatchPractitionerInDto
 {
     /// <summary>
     /// 名字
@@ -19,6 +19,11 @@ public class AddPractitionerInDto
     /// </summary>
     public string Gender { get; set; }
 
+    /// <summary>
+    /// 区域名称
+    /// </summary>
+    public string AreaName { get; set; }
+
     /// <summary>
     /// 区域名称
     /// </summary>
@@ -35,7 +40,7 @@ public class AddPractitionerInDto
     public string Street { get; set; }
 }
 
-public class PractitionerDetailOutDto : AddPractitionerInDto
+public class PractitionerDetailOutDto : AddBatchPractitionerInDto
 {
     /// <summary>
     /// Id
@@ -92,3 +97,51 @@ public class PractitionerItemOutDto
     /// </summary>
     public string Name { get; set; }
 }
+
+public class UpdatePractitionerInDto : AddPractitionerInDto
+{
+    /// <summary>
+    /// Id
+    /// </summary>
+    [Required]
+    public string Id { get; set; }
+}
+
+public class AddPractitionerInDto
+{
+    /// <summary>
+    /// 名字
+    /// </summary>
+    [Required]
+    public string Name { get; set; }
+
+    /// <summary>
+    /// 区域Id
+    /// </summary>
+    [Required]
+    public string SystemAreaId { get; set; }
+
+    /// <summary>
+    /// 区域名称
+    /// </summary>
+    [Required]
+    public string SystemAreaName { get; set; }
+
+    /// <summary>
+    /// 详细街道
+    /// </summary>
+    [Required]
+    public string Street { get; set; }
+
+    /// <summary>
+    /// 电话
+    /// </summary>
+    [Required]
+    public string PhoneNumber { get; set; }
+
+    /// <summary>
+    /// 性别
+    /// </summary>
+    [Required]
+    public EGender Gender { get; set; }
+}

+ 4 - 4
src/Hotline.Share/Dtos/Snapshot/RedPackDto.cs

@@ -16,9 +16,9 @@ public class RedPackOutDto
     public string AmountTxt => Amount.ToYuanFinance();
 
     /// <summary>
-    /// 金额(单位:)
+    /// 金额(单位:)
     /// </summary>
-    public int Amount { get; set; }
+    public double Amount { get; set; }
 }
 
 public class RedPacksInDto : QueryFixedDto
@@ -53,9 +53,9 @@ public class RedPackDateOutDto
     public string CreationTimeText => CreationTime.ToString("yyyy-MM");
 
     /// <summary>
-    /// 金额(单位:)
+    /// 金额(单位:)
     /// </summary>
-    public int Amount { get; set; }
+    public double Amount { get; set; }
 
     /// <summary>
     /// 金额(单位:元)

+ 9 - 3
src/Hotline.Share/Dtos/Snapshot/SnapshotUserInfoDto.cs

@@ -13,14 +13,20 @@ public class SnapshotUserInfoOutDto
     /// </summary>
     public string PhoneNumberMask => PhoneNumber.MaskPhoneNumber();
 
-    public int DayAmount { get; set; }
+    /// <summary>
+    /// 当日奖励(单位:元)
+    /// </summary>
+    public double DayAmount { get; set; }
 
     /// <summary>
-    /// 当日奖励(单元: 元)
+    /// 当日奖励(单位:元)
     /// </summary>
     public string DayAmountTxt => DayAmount.ToYuanFinance();
 
-    public int TotalAmount { get; set; }
+    /// <summary>
+    /// 总奖励(单位:元)
+    /// </summary>
+    public double TotalAmount { get; set; }
 
     /// <summary>
     /// 总奖励(单位:元)

+ 20 - 2
src/Hotline.Share/Dtos/Snapshot/VolunteerDto.cs

@@ -1,4 +1,5 @@
-using System;
+using Hotline.Share.Requests;
+using System;
 using System.Collections.Generic;
 using System.ComponentModel.DataAnnotations;
 using System.Linq;
@@ -6,6 +7,16 @@ using System.Text;
 using System.Threading.Tasks;
 
 namespace Hotline.Share.Dtos.Snapshot;
+
+public class UpdateVolunteerInDto : AddVolunteerInDto
+{
+    /// <summary>
+    /// 志愿者Id
+    /// </summary>
+    [Required]
+    public string Id { get; set; }
+}
+
 public class AddVolunteerInDto
 {
     /// <summary>
@@ -21,7 +32,7 @@ public class AddVolunteerInDto
     public string PhoneNumber { get; set; }
 }
 
-public class VolunteerListOutDto
+public class VolunteerItemsOutDto
 {
     public string Id { get; set; }
 
@@ -35,3 +46,10 @@ public class VolunteerListOutDto
     /// </summary>
     public string PhoneNumber { get; set; }
 }
+
+/// <summary>
+/// 志愿者集合入参
+/// </summary>
+/// <param name="Name">姓名</param>
+/// <param name="PhoneNumber">电话</param>
+public record VolunteerItemsInDto(string? Name, string? PhoneNumber): PagedRequest;

+ 82 - 1
src/Hotline.Share/Dtos/Snapshot/VolunteerReportDto.cs

@@ -1,4 +1,5 @@
-using System;
+using Hotline.Share.Requests;
+using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
@@ -75,3 +76,83 @@ public class AddVolunteerReportOutDto
     /// </summary>
     public string Id { get; set; }
 }
+
+/// <summary>
+/// 入参
+/// </summary>
+/// <param name="Name">名字</param>
+/// <param name="PhoneNumber">电话</param>
+public record VolunteerReportItemsInDto(string? Name , string? PhoneNumber) : PagedRequest;
+
+public class VolunteerReportItemsOutDto
+{
+    /// <summary>
+    /// Id
+    /// </summary>
+    public string Id { get; set; }
+
+    /// <summary>
+    /// 作业类型
+    /// </summary>
+    public string JobType { get; set; }
+
+    /// <summary>
+    /// 上报人联系方式
+    /// </summary>
+    public string PhoneNumber { get; set; }
+
+    /// <summary>
+    /// 上报人姓名
+    /// </summary>
+    public string Name { get; set; }
+
+    /// <summary>
+    /// 是否已经申报
+    /// </summary>
+    public bool IsDeclare { get; set; }
+
+    /// <summary>
+    /// 生产经营单位内部是否按规定办理审批手续
+    /// </summary>
+    public bool IsApprovalProcess { get; set; }
+
+    /// <summary>
+    /// 电气焊作业人员是否取得职业资格证书
+    /// </summary>
+    public bool IsProfessionalCertificate { get; set; }
+
+    /// <summary>
+    /// 是否落实作业现场监护人员
+    /// </summary>
+    public bool IsSiteMonitoring { get; set; }
+
+    /// <summary>
+    /// 是否在人员密集场所营业期间动火作业
+    /// </summary>
+    public bool IsFireWork { get; set; }
+
+    /// <summary>
+    /// 是否清除作业现场及周围易燃物品或落实有效安全防范措施
+    /// </summary>
+    public bool IsClearSafety { get; set; }
+
+    /// <summary>
+    /// 作业现场是否配备能满足现场灭火应急需求消防器材
+    /// </summary>
+    public bool HasFireEquipment { get; set; }
+
+    /// <summary>
+    /// 作业现场使用的工器具是否进行安全检查
+    /// </summary>
+    public bool IsToolSafety { get; set; }
+
+    /// <summary>
+    /// 施工地点
+    /// </summary>
+    public string FullAddress { get; set; }
+
+    /// <summary>
+    /// 上报时间
+    /// </summary>
+    public DateTime CreationTime { get; set; }
+}

+ 23 - 0
src/Hotline.Share/Enums/Snapshot/ESnapshotSMSStatus.cs

@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Share.Enums.Snapshot;
+public enum ESnapshotSMSStatus
+{
+    /// <summary>
+    /// 同意
+    /// </summary>
+    [Description("同意")]
+    Agree,
+
+    /// <summary>
+    /// 不同意
+    /// </summary>
+    [Description("不同意")]
+    Refuse,
+
+}

+ 2 - 2
src/Hotline.Share/Tools/DoubleExtensions.cs

@@ -48,8 +48,8 @@ public static class DoubleExtensions
         return value.Value.SecondsToString();
     }
 
-    public static string ToYuanFinance(this int value)
+    public static string ToYuanFinance(this double value)
     {
-        return (value / 100.0).ToString("F2");
+        return value.ToString("F2");
     }
 }

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

@@ -50,5 +50,10 @@ namespace Hotline.Caching.Interfaces
         public IReadOnlyList<SystemDicDataOutDto> WorkArea { get; }
         public IReadOnlyList<SystemDicData> VisitMananer { get; }
         public IReadOnlyList<SystemDicData> SourceChannel { get; }
+
+        /// <summary>
+        /// 自贡随手拍行业审批部门
+        /// </summary>
+        public IReadOnlyCollection<SystemDicDataOutDto> SnapshotDepartment { get; }
     }
 }

+ 2 - 0
src/Hotline/Caching/Interfaces/ISystemSettingCacheManager.cs

@@ -98,5 +98,7 @@ namespace Hotline.Caching.Interfaces
         /// 天阙推送受理信息接口Url
         /// </summary>
         string TianQuanPostAcceptInfoApi { get; }
+
+        bool Snapshot { get; }
     }
 }

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

@@ -112,6 +112,11 @@ namespace Hotline.Caching.Services
         public IReadOnlyList<SystemDicData> VisitMananer => GetSysDicDataCache(SysDicTypeConsts.VisitManner);
         public IReadOnlyList<SystemDicData> SourceChannel => GetSysDicDataCache(SysDicTypeConsts.SourceChannel);
 
+        /// <summary>
+        /// 自贡随手拍行业审批部门
+        /// </summary>
+        public IReadOnlyCollection<SystemDicDataOutDto> SnapshotDepartment => GetOrAdd(SysDicTypeConsts.SnapshotDepartment);
+
 
         public void RemoveSysDicDataCache(string code)
         {

+ 7 - 0
src/Hotline/Caching/Services/SystemSettingCacheManager.cs

@@ -193,5 +193,12 @@ namespace Hotline.Caching.Services
         /// </summary>
         public string TianQuanPostAcceptInfoApi =>
             GetOrDefault("08dcd143-5f4b-477f-80e2-c2326d1d82e8", SettingConstants.TianQuanPostAcceptInfoApi, "天阙推送受理信息API接口地址", "http://10.0.188.11:6090/api/v1/test/accept/saveAcceptInfoApi", "测试: http://10.0.188.11:6090/api/v1/test/accept/saveAcceptInfoApi  正式: http://10.0.188.11:6090/api/v1/prod/accept/saveAcceptInfoApi");
+
+        /// <summary>
+        /// 随手拍功能开关
+        /// </summary>
+        public bool Snapshot =>
+            GetOrDefault("08dd0eca-66b8-4c98-8dec-0c76c29d77e3", SettingConstants.Snapshot, "随手拍功能开关", false, "随手拍功能开关");
+
     }
 }

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

@@ -17,6 +17,31 @@ public class SystemDicDataSeedData : ISeedData<SystemDicData>
 
     public IEnumerable<SystemDicData> GetData(string dicTypeCode)
     {
+        if (dicTypeCode == SysDicTypeConsts.SnapshotDepartment)
+        {
+            return [
+                    new() { Id = "08dd1fd9-ec8b-455b-8a45-e7b449b760c6", DicDataValue = "1", DicDataName = "政务服务热线系统", Sort = 1 },
+                    new() { Id = "08dd1fd9-d8e4-4715-8605-de7c11d25ebf", DicDataValue = "2" , DicDataName = "热线中心" , Sort = 2},
+                    new() { Id = "08dd1fd9-d79d-4dc8-80fe-90d211edd1a9", DicDataValue = "2661", DicDataName = "自贡建工建设工程有限公司" , Sort = 3},
+                    new() { Id = "08dd1fd5-298b-49c4-813b-5a1ff2edcd29", DicDataValue = "2039", DicDataName = "自流井区人民政府" , Sort = 4},
+                    new() { Id = "08dd1fd5-0a4d-4e22-87bf-337653f883c1", DicDataValue = "2040", DicDataName = "贡井区人民政府" , Sort = 5},
+                    new() { Id = "08dd1fd5-0841-4119-89d6-cb923dfe3998", DicDataValue = "2041", DicDataName = "大安区人民政府" , Sort = 6},
+                    new() { Id = "08dd1fd5-0660-44a5-8104-4f6e4d0714e5", DicDataValue = "2042", DicDataName = "沿滩区人民政府" , Sort = 7},
+                    new() { Id = "08dd1f9f-e706-4cf9-8ee6-3c3cd7602c21", DicDataValue = "2043", DicDataName = "富顺县人民政府" , Sort = 8},
+                    new() { Id = "08dd1f67-0797-47f5-8da2-5742a98a53c4", DicDataValue = "2044", DicDataName = "荣县人民政府" , Sort = 9},
+                    new() { Id = "08dd1f66-441e-4eff-81fc-8b0afd78ca8f", DicDataValue = "2045", DicDataName = "高新区管委会" , Sort = 10},
+                    new() { Id = "08dd1f63-5682-456f-8596-8d99868334f6", DicDataValue = "2074", DicDataName = "荣县行政审批和营商环境局" , Sort = 11},
+                    new() { Id = "08dd1f62-ae99-474b-8a18-6351f9456bd9", DicDataValue = "2075", DicDataName = "荣县经开区管委会" , Sort = 12},
+                    new() { Id = "08dd1f61-3ec6-49c9-85d8-be35ddd9859b", DicDataValue = "2076", DicDataName = "荣县发展和改革局" , Sort = 13},
+                    new() { Id = "08dd1f5f-b885-4dae-86dc-4464660908ac", DicDataValue = "2077", DicDataName = "荣县科技和经信局" , Sort = 14},
+                    new() { Id = "08dd1f5f-b856-4e8c-8b33-0565dea6b56d", DicDataValue = "2078", DicDataName = "荣县教育和体育局" , Sort = 15},
+                    new() { Id = "08dd1f5f-af91-48c2-8b03-69f2c07ccefd", DicDataValue = "2079", DicDataName = "荣县公安局" , Sort = 16},
+                    new() { Id = "08dd1f5f-af5a-4fc7-85f5-034ba952d7fd", DicDataValue = "2834", DicDataName = "中国联通自贡分公司" , Sort = 17},
+                    new() { Id = "08dd1f5f-af18-42e6-8b8e-51923a92cf67", DicDataValue = "2081", DicDataName = "荣县民政局" , Sort = 18},
+                    new() { Id = "08dd1f5f-595d-4913-83be-ee71bebf3c30", DicDataValue = "2082", DicDataName = "荣县财政局" , Sort = 19},
+                    new() { Id = "08dd1f5e-d913-48cf-86f7-4bd3842669f4", DicDataValue = "2083", DicDataName = "荣县人力资源社会保障局" , Sort = 20}
+                ];
+        }
         if (dicTypeCode == SysDicTypeConsts.Workplace)
         {
             return
@@ -147,6 +172,11 @@ public class SystemDicDataSeedData : ISeedData<SystemDicData>
         {
             dicType = ["08dc0681-a6e1-473d-8b1d-1b0b67e0ec13", "随手拍公告类型"];
         }
+        if (dicTypeCode == SysDicTypeConsts.SnapshotDepartment)
+        {
+            dicType = ["08dd1f5d-ebd8-4dc1-861c-d3190ad4c528", "随手拍审核部门"];
+        }
+
         return new SystemDicType
         {
             Id = dicType[0],

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

@@ -291,4 +291,9 @@ public class SysDicTypeConsts
     /// 作业区域
     /// </summary>
     public const string WorkArea = "WorkArea";
+
+    /// <summary>
+    /// 自贡随手拍行业审批部门
+    /// </summary>
+    public const string SnapshotDepartment = "SnapshotDepartment";
 }

+ 12 - 6
src/Hotline/Snapshot/Industry.cs

@@ -50,16 +50,16 @@ public class Industry : CreationSoftDeleteEntity
     public string? AcceptTypeCode { get; set; }
 
     /// <summary>
-    /// 市民发放红包金额(单位:)
+    /// 市民发放红包金额(单位:)
     /// </summary>
-    [SugarColumn(ColumnDescription = "市民发放红包金额(单位:)")]
-    public int CitizenReadPackAmount { get; set; }
+    [SugarColumn(ColumnDescription = "市民发放红包金额(单位:)")]
+    public double CitizenReadPackAmount { get; set; }
 
     /// <summary>
-    /// 网络员发放红包金额(单位:)
+    /// 网络员发放红包金额(单位:)
     /// </summary>
-    [SugarColumn(ColumnDescription = "网络员发放红包金额(单位:)")]
-    public int GuiderReadPackAmount { get; set; }
+    [SugarColumn(ColumnDescription = "网络员发放红包金额(单位:)")]
+    public double GuiderReadPackAmount { get; set; }
 
     /// <summary>
     /// 是否启用
@@ -67,6 +67,12 @@ public class Industry : CreationSoftDeleteEntity
     [SugarColumn(ColumnDescription = "是否启用")]
     public bool IsEnable { get; set; }
 
+    /// <summary>
+    /// App是否启用
+    /// </summary>
+    [SugarColumn(ColumnDescription = "App是否启用")]
+    public bool IsAppEnable { get; set; }
+
     /// <summary>
     /// 帮助引导用语
     /// </summary>

+ 12 - 6
src/Hotline/Snapshot/IndustryCase.cs

@@ -15,6 +15,12 @@ namespace Hotline.Snapshot;
 [Description("行业线索")]
 public class IndustryCase : CreationSoftDeleteEntity
 {
+    /// <summary>
+    /// 行业Id
+    /// </summary>
+    [SugarColumn(ColumnDescription = "行业Id")]
+    public string IndustryId { get; set; }
+
     /// <summary>
     /// 线索名称
     /// </summary>
@@ -22,16 +28,16 @@ public class IndustryCase : CreationSoftDeleteEntity
     public string Name { get; set; }
 
     /// <summary>
-    /// 市民发放红包金额(单位:)
+    /// 市民发放红包金额(单位:)
     /// </summary>
-    [SugarColumn(ColumnDescription = "市民发放红包金额(单位:)")]
-    public int CitizenReadPackAmount { get; set; }
+    [SugarColumn(ColumnDescription = "市民发放红包金额(单位:)")]
+    public double CitizenReadPackAmount { get; set; }
 
     /// <summary>
-    /// 网络员发放红包金额(单位:)
+    /// 网络员发放红包金额(单位:)
     /// </summary>
-    [SugarColumn(ColumnDescription = "网络员发放红包金额(单位:)")]
-    public int GuiderReadPackAmount { get; set; }
+    [SugarColumn(ColumnDescription = "网络员发放红包金额(单位:)")]
+    public double GuiderReadPackAmount { get; set; }
 
     /// <summary>
     /// 是否启用

+ 11 - 0
src/Hotline/Snapshot/Interfaces/IIndustryCaseRepository.cs

@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Repository;
+
+namespace Hotline.Snapshot.Interfaces;
+public interface IIndustryCaseRepository : IRepository<IndustryCase>
+{
+}

+ 11 - 0
src/Hotline/Snapshot/Interfaces/ISnapshotSMSTemplateRepository.cs

@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Repository;
+
+namespace Hotline.Snapshot.Interfaces;
+public interface ISnapshotSMSTemplateRepository : IRepository<SnapshotSMSTemplate>
+{
+}

+ 48 - 0
src/Hotline/Snapshot/SnapshotSMSTemplate.cs

@@ -0,0 +1,48 @@
+using Hotline.Share.Enums.Snapshot;
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Repository;
+
+namespace Hotline.Snapshot;
+public class SnapshotSMSTemplate : FullStateEntity
+{
+    /// <summary>
+    /// 行业Id
+    /// </summary>
+    [SugarColumn(ColumnDescription = "行业Id")]
+    public string IndustryId { get; set; }
+
+    /// <summary>
+    /// 模板内容
+    /// </summary>
+    [SugarColumn(ColumnDescription = "模板内容")]
+    public string Content { get; set; }
+
+    /// <summary>
+    /// 审核状态
+    /// </summary>
+    [SugarColumn(ColumnDescription = "审核状态")]
+    public ESnapshotSMSStatus Status { get; set; }
+
+    /// <summary>
+    /// 是否启用
+    /// </summary>
+    [SugarColumn(ColumnDescription = "是否启用")]
+    public bool IsEnable { get; set; }
+
+    /// <summary>
+    /// 是否公用
+    /// </summary>
+    [SugarColumn(ColumnDescription = "是否公用")]
+    public bool IsPublic { get; set; }
+
+    /// <summary>
+    /// 排序
+    /// </summary>
+    [SugarColumn(ColumnDescription = "排序")]
+    public int DisplayOrder { get; set; }
+}

+ 3 - 3
src/Hotline/Snapshot/ThirdAccount.cs

@@ -54,10 +54,10 @@ public class ThirdAccount : CreationSoftDeleteEntity
     public EThirdType AccountType { get; set; }
 
     /// <summary>
-    /// 历史已经领取金额总和()
+    /// 历史已经领取金额总和(单位:元)
     /// </summary>
-    [SugarColumn(ColumnDescription = "历史已经领取金额总和()")]
-    public int TotalAmount { get; set; }
+    [SugarColumn(ColumnDescription = "历史已经领取金额总和(单位:元)")]
+    public double TotalAmount { get; set; }
 
     /// <summary>
     /// 用户头像Url