Bläddra i källkod

Merge branch 'release' of http://git.12345lm.cn/Fengwo/hotline into release

Dun.Jason 6 månader sedan
förälder
incheckning
99e401e927

+ 129 - 116
src/Hotline.Api/Controllers/OrderController.cs

@@ -59,7 +59,10 @@ using MiniExcelLibs;
 using MongoDB.Driver;
 using SqlSugar;
 using StackExchange.Redis;
+using System;
+using System.ComponentModel.DataAnnotations;
 using System.Text;
+using Wex.Sdk.Tel;
 using XF.Domain.Authentications;
 using XF.Domain.Cache;
 using XF.Domain.Entities;
@@ -6029,8 +6032,12 @@ public class OrderController : BaseController
         return _exportApplication.ExportData(list, "demo.xlsx");
     }
 
-    /// <summary>ExternalId
+    /// <summary>
     /// 导入工单
+    /// TODO 回访信息需要写回访表? 
+    /// TODO 工单是否需要写发布表?
+    /// TODO 是否自动签收工单?
+    /// TODO SourceChannel 是否和 Source 相同?
     /// </summary>
     /// <param name="file"></param>
     /// <returns></returns>
@@ -6045,159 +6052,165 @@ public class OrderController : BaseController
             int errorCount = 0;
             int addCount = 0;
             int modifyCount = 0;
-            if (list != null && list.Count > 0)
+            var allowSources = new Dictionary<string, string>
             {
-                count = list.Count;
-                foreach (var item in list)
+                { "麻辣社区", "MLSQ" }, {"人民网", "RMW" }, {"省长信箱", "SZXX" }, {"问政四川", "WZSC"}
+            };
+            var errorMessage = new StringBuilder();
+            if (list == null || list.Count == 0)
+            {
+                return new { Count = count, ErrorCount = errorCount, AddCount = addCount, ModifyCount = modifyCount, ErrorMessage = "数据为空" };
+            }
+
+            count = list.Count;
+            var i = 0;
+            foreach (var item in list)
+            {
+                i++;
+                try
                 {
-                    try
+                    var validationResult = item.ValidateObject();
+                    if (validationResult.NotNullOrEmpty())
                     {
-                        if (item.Source != "麻辣社区" || item.Source != "人民网" || item.Source != "省长信箱" || item.Source != "问政四川")
-                        //if (item.Source < ESource.MLSQ || item.Source > ESource.WZSC)
-                        {
-                            errorCount++;
-                            continue;
-                        }
+                        errorMessage.Append($"第{i + 1}行: {validationResult}\r\n");
+                        errorCount++;
+                        continue;
+                    }
 
-                        int SourceCode = 0;
+                    var allowSource = allowSources.FirstOrDefault(m => m.Key == item.Source).Value;
+                    if (allowSource.IsNullOrEmpty())
+                    {
+                        errorCount++;
+                        continue;
+                    }
 
-                        switch (item.Source)
-                        {
-                            case "麻辣社区":
-                                SourceCode = 500;
-                                break;
-                            case "人民网":
-                                SourceCode = 501;
-                                break;
-                            case "省长信箱":
-                                SourceCode = 502;
-                                break;
-                            case "问政四川":
-                                SourceCode = 529;
-                                break;
-                            default:
-                                break;
-                        }
+                    var SourceCode = (ESource)Enum.Parse(typeof(ESource), allowSource);
 
-                        var order = await _orderRepository.GetAsync(x => x.ExternalId == item.ExternalId && x.Source == (ESource)SourceCode,
-                            HttpContext.RequestAborted);
+                    var order = await _orderRepository.GetAsync(x => x.ExternalId == item.ExternalId && x.Source == SourceCode,
+                        HttpContext.RequestAborted) ?? new Orders.Order();
+                    item.Source = SourceCode.ToString();
+                    order = _mapper.Map(item, order);
 
-                        order = _mapper.Map<Orders.Order>(item);
+                    order.SourceChannel = SourceCode.GetDescription();
+                    order.SourceChannelCode = ((int)SourceCode).ToString();
 
-                        #region 处理数据开始
+                    #region 处理数据开始
 
-                        order.Source = (ESource)SourceCode; //来源
+                    // order.Source = SourceCode; //来源
 
-                        //处理热点
-                        //处理一级热点
-                        string hotspotId = "";
-                        string hotspotName = "";
-                        string hotspotFullName = "";
-                        var hotspotOne = await _hotspotTypeRepository.Queryable()
-                            .FirstAsync(x => x.HotSpotName == item.HotspotNameOne, HttpContext.RequestAborted);
-                        if (hotspotOne != null)
+                    //处理热点
+                    //处理一级热点
+                    string hotspotId = "";
+                    string hotspotName = "";
+                    string hotspotFullName = "";
+                    var hotspotOne = await _hotspotTypeRepository.Queryable()
+                        .FirstAsync(x => x.HotSpotName == item.HotspotNameOne, HttpContext.RequestAborted);
+                    if (hotspotOne != null)
+                    {
+                        hotspotId = hotspotOne.Id;
+                        hotspotName = hotspotOne.HotSpotName;
+                        hotspotFullName = hotspotOne.HotSpotFullName;
+                        var hotspotTwo = await _hotspotTypeRepository.Queryable()
+                            .FirstAsync(x => x.HotSpotName == item.HotspotNameTwo && x.ParentId == hotspotId, HttpContext.RequestAborted);
+                        if (hotspotTwo != null)
                         {
-                            hotspotId = hotspotOne.Id;
-                            hotspotName = hotspotOne.HotSpotName;
-                            hotspotFullName = hotspotOne.HotSpotFullName;
-                            var hotspotTwo = await _hotspotTypeRepository.Queryable()
-                                .FirstAsync(x => x.HotSpotName == item.HotspotNameTwo && x.ParentId == hotspotId, HttpContext.RequestAborted);
-                            if (hotspotTwo != null)
+                            hotspotId = hotspotTwo.Id;
+                            hotspotName = hotspotTwo.HotSpotName;
+                            hotspotFullName = hotspotTwo.HotSpotFullName;
+                            var hotspotThree = await _hotspotTypeRepository.Queryable()
+                                .FirstAsync(x => x.HotSpotName == item.HotspotNameThree && x.ParentId == hotspotId, HttpContext.RequestAborted);
+                            if (hotspotThree != null)
                             {
-                                hotspotId = hotspotTwo.Id;
-                                hotspotName = hotspotTwo.HotSpotName;
-                                hotspotFullName = hotspotTwo.HotSpotFullName;
-                                var hotspotThree = await _hotspotTypeRepository.Queryable()
-                                    .FirstAsync(x => x.HotSpotName == item.HotspotNameThree && x.ParentId == hotspotId, HttpContext.RequestAborted);
-                                if (hotspotThree != null)
+                                hotspotId = hotspotThree.Id;
+                                hotspotName = hotspotThree.HotSpotName;
+                                hotspotFullName = hotspotThree.HotSpotFullName;
+                                var hotspotFour = await _hotspotTypeRepository.Queryable()
+                                    .FirstAsync(x => x.HotSpotName == item.HotspotNameFour && x.ParentId == hotspotId,
+                                        HttpContext.RequestAborted);
+                                if (hotspotFour != null)
                                 {
-                                    hotspotId = hotspotThree.Id;
-                                    hotspotName = hotspotThree.HotSpotName;
-                                    hotspotFullName = hotspotThree.HotSpotFullName;
-                                    var hotspotFour = await _hotspotTypeRepository.Queryable()
-                                        .FirstAsync(x => x.HotSpotName == item.HotspotNameFour && x.ParentId == hotspotId,
+                                    hotspotId = hotspotFour.Id;
+                                    hotspotName = hotspotFour.HotSpotName;
+                                    hotspotFullName = hotspotFour.HotSpotFullName;
+                                    var hotspotFive = await _hotspotTypeRepository.Queryable()
+                                        .FirstAsync(x => x.HotSpotName == item.HotspotNameFive && x.ParentId == hotspotId,
                                             HttpContext.RequestAborted);
-                                    if (hotspotFour != null)
+                                    if (hotspotFive != null)
                                     {
-                                        hotspotId = hotspotFour.Id;
-                                        hotspotName = hotspotFour.HotSpotName;
-                                        hotspotFullName = hotspotFour.HotSpotFullName;
-                                        var hotspotFive = await _hotspotTypeRepository.Queryable()
-                                            .FirstAsync(x => x.HotSpotName == item.HotspotNameFive && x.ParentId == hotspotId,
-                                                HttpContext.RequestAborted);
-                                        if (hotspotFive != null)
-                                        {
-                                            hotspotId = hotspotFive.Id;
-                                            hotspotName = hotspotFive.HotSpotName;
-                                            hotspotFullName = hotspotFive.HotSpotFullName;
-                                        }
+                                        hotspotId = hotspotFive.Id;
+                                        hotspotName = hotspotFive.HotSpotName;
+                                        hotspotFullName = hotspotFive.HotSpotFullName;
                                     }
                                 }
                             }
                         }
+                    }
 
-                        order.HotspotId = hotspotId;
-                        order.HotspotName = hotspotName;
-                        order.HotspotSpliceName = hotspotFullName;
+                    order.HotspotId = hotspotId;
+                    order.HotspotName = hotspotName;
+                    order.HotspotSpliceName = hotspotFullName;
 
-                        //处理部门
-                        var orgOne = await _organizeRepository.Queryable()
-                            .FirstAsync(x => x.Name == item.OrgLevelOneName, HttpContext.RequestAborted);
-                        if (orgOne != null)
+                    //处理部门
+                    var orgOne = await _organizeRepository.Queryable()
+                        .FirstAsync(x => x.Name == item.OrgLevelOneName, HttpContext.RequestAborted);
+                    if (orgOne != null)
+                    {
+                        order.OrgLevelOneCode = orgOne.Id;
+                        order.OrgLevelOneName = orgOne.Name;
+                        var orgTwo = await _organizeRepository.Queryable()
+                            .FirstAsync(x => x.Name == item.OrgLevelTwoName && x.ParentId == order.OrgLevelOneCode, HttpContext.RequestAborted);
+                        if (orgTwo != null)
                         {
-                            order.OrgLevelOneCode = orgOne.Id;
-                            order.OrgLevelOneName = orgOne.Name;
-                            var orgTwo = await _organizeRepository.Queryable()
-                                .FirstAsync(x => x.Name == item.OrgLevelTwoName && x.ParentId == order.OrgLevelOneCode, HttpContext.RequestAborted);
-                            if (orgTwo != null)
-                            {
-                                order.OrgLevelTwoCode = orgTwo.Id;
-                                order.OrgLevelTwoName = orgTwo.Name;
-                            }
+                            order.OrgLevelTwoCode = orgTwo.Id;
+                            order.OrgLevelTwoName = orgTwo.Name;
                         }
+                    }
 
-                        //承办部门
-                        var ActualHandleOrg = await _organizeRepository.Queryable()
-                            .FirstAsync(x => x.Name == item.ActualHandleOrgName, HttpContext.RequestAborted);
-                        if (ActualHandleOrg != null)
-                        {
-                            order.ActualHandleOrgCode = ActualHandleOrg.Id;
-                        }
+                    //承办部门
+                    var ActualHandleOrg = await _organizeRepository.Queryable()
+                        .FirstAsync(x => x.Name == item.ActualHandleOrgName, HttpContext.RequestAborted);
+                    if (ActualHandleOrg != null)
+                    {
+                        order.ActualHandleOrgCode = ActualHandleOrg.Id;
+                    }
+
+                    //处理地址
+                    order.FullAddress = $"{order.Address}{order.Street}";
 
-                        //处理地址
-                        order.Address = $"{order.Province}{order.City}{order.County}{order.Town}";
-                        order.FullAddress = $"{order.Address}{order.Street}";
+                    order.FirstVisitResultCode = _sysDicDataCacheManager
+                        .GetSysDicDataCache(SysDicTypeConsts.VisitSatisfaction)
+                        .FirstOrDefault(m => m.DicDataName == item.VisitResult)?.DicDataValue 
+                        ?? order.FirstVisitResultCode;
 
-                        #endregion
+                    #endregion
 
-                        if (order is null)
+                    if (order.Id.IsNullOrEmpty())
+                    {
+                        //order.Source = item;
+                        var id = await _orderDomainService.AddAsync(order,false,  HttpContext.RequestAborted);
+                        if (!string.IsNullOrEmpty(id))
                         {
-                            //order.Source = item;
-                            var id = await _orderRepository.AddAsync(order, HttpContext.RequestAborted);
-                            if (!string.IsNullOrEmpty(id))
-                            {
-                                addCount++;
-                            }
-                            else
-                            {
-                                errorCount++;
-                            }
+                            addCount++;
                         }
                         else
                         {
-                            _mapper.Map(item, order);
-                            await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted);
-                            modifyCount++;
+                            errorCount++;
                         }
                     }
-                    catch (Exception ex)
+                    else
                     {
-                        errorCount++;
+                        // _mapper.Map(item, order);
+                        await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted);
+                        modifyCount++;
                     }
                 }
+                catch (Exception ex)
+                {
+                    errorCount++;
+                }
             }
 
-            return new { Count = count, ErrorCount = errorCount, AddCount = addCount, ModifyCount = modifyCount };
+            return new { Count = count, ErrorCount = errorCount, AddCount = addCount, ModifyCount = modifyCount, ErrorMessage = errorMessage.ToString() };
         }
     }
 

+ 1 - 1
src/Hotline.Application/FlowEngine/WorkflowApplication.cs

@@ -1622,7 +1622,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
             case EHandlerType.AssignedUser:
                 return FlowAssignInfo.Create(EFlowAssignType.User, handlers, isStartCountersign);
             case EHandlerType.AssignedOrgOrRole:
-	            return FlowAssignInfo.Create(EFlowAssignType.OrgOrRole, handlers, isStartCountersign);
+	            return FlowAssignInfo.Create(EFlowAssignType.OrgAndRole, handlers, isStartCountersign);
 
             default:
                 throw new ArgumentOutOfRangeException();

+ 5 - 0
src/Hotline.Application/Mappers/MapperConfigs.cs

@@ -1,4 +1,5 @@
 using Hotline.CallCenter.BlackLists;
+using Hotline.Import;
 using Hotline.JudicialManagement;
 using Hotline.Orders;
 using Hotline.Push.FWMessage;
@@ -23,6 +24,10 @@ namespace Hotline.Application.Mappers
     {
         public void Register(TypeAdapterConfig config)
         {
+            config.ForType<ExcelContent, Order>()
+                .Map(d => d.FirstVisitResult, x => x.VisitResult)
+                .IgnoreNullValues(true);
+
             config.ForType<SystemDicData, Kv>()
                 .Map(s => s.Key, d => d.DicDataValue)
                 .Map(s => s.Value, d => d.DicDataName);

+ 25 - 0
src/Hotline.Share/Tools/ObjectExtensions.cs

@@ -1,6 +1,7 @@
 using Newtonsoft.Json;
 using System;
 using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
 using System.Linq;
 using System.Reflection;
 using System.Text;
@@ -28,6 +29,30 @@ public static class ObjectExtensions
         }
     }
 
+    /// <summary>
+    /// 扩展方法用于手动验证对象,并返回验证结果。
+    /// </summary>
+    /// <param name="obj">需要验证的对象</param>
+    /// <returns>如果验证成功返回 string.Empty,否则返回错误信息</returns>
+    public static string ValidateObject(this object obj)
+    {
+        var validationResults = new List<ValidationResult>();
+        var validationContext = new ValidationContext(obj);
+
+        // 验证对象
+        bool isValid = Validator.TryValidateObject(obj, validationContext, validationResults, true);
+
+        if (isValid)
+        {
+            return string.Empty;
+        }
+        else
+        {
+            // 如果验证失败,返回所有错误信息的拼接
+            return string.Join("; ", validationResults.Select(result => result.ErrorMessage));
+        }
+    }
+
     public static string ToJson(this object obj)
     {
         return JsonConvert.SerializeObject(obj);

+ 1 - 0
src/Hotline/FlowEngine/Workflows/StepBasicEntity.cs

@@ -466,6 +466,7 @@ public abstract class StepBasicEntity : CreationEntity
             EFlowAssignType.Org => new Kv(HandlerOrgId, HandlerOrgName),
             EFlowAssignType.User => new Kv(HandlerId, HandlerName),
             EFlowAssignType.Role => new Kv(RoleId, RoleName),
+            EFlowAssignType.OrgAndRole => new Kv(RoleId, $"{HandlerOrgName} - {RoleName}"),
             _ => throw new ArgumentOutOfRangeException()
         };
     }

+ 47 - 10
src/Hotline/Import/ExcelContent.cs

@@ -1,85 +1,122 @@
 using Hotline.Share.Enums.Order;
 using MiniExcelLibs.Attributes;
 using SqlSugar;
+using System.ComponentModel.DataAnnotations;
 
 
 namespace Hotline.Import
 {
     public class ExcelContent
     {
+        [Required(ErrorMessage = "来源 不能为空")]
         [ExcelColumnName("来源")]
         public string Source { get; set; }
 
+        [Required(ErrorMessage = "编号 不能为空")]
         [ExcelColumnName("编号")]
         public string ExternalId { get; set; }
 
+        [Required(ErrorMessage = "受理时间 不能为空")]
         [ExcelColumnName("受理时间")]
         public DateTime StartTime { get; set; }
 
+        [Required(ErrorMessage = "标题 不能为空")]
         [ExcelColumnName("标题")]
         public string Title { get; set; }
 
+        [Required(ErrorMessage = "期满时间 不能为空")]
         [ExcelColumnName("期满时间")]
         public DateTime ExpiredTime { get; set; }
+
         /// <summary>
         /// 一级部门名称
         /// </summary>
         [ExcelColumnName("一级部门")]
         public string? OrgLevelOneName { get; set; }
+
         /// <summary>
         /// 二级部门名称
         /// </summary>
         [ExcelColumnName("二级部门")]
         public string? OrgLevelTwoName { get; set; }
 
+        [Required(ErrorMessage = "承办部门 不能为空")]
         [ExcelColumnName("承办部门")]
         public string ActualHandleOrgName { get; set; }
+
+        [Required(ErrorMessage = "办结时间 不能为空")]
         [ExcelColumnName("办结时间")]
         public DateTime ActualHandleTime { get; set; }
+
+        [Required(ErrorMessage = "受理类型 不能为空")]
         [ExcelColumnName("受理类型")]
         public string AcceptType { get; set; }
+
+        [Required(ErrorMessage = "一级热点 不能为空")]
         [ExcelColumnName("一级热点")]
         public string HotspotNameOne { get; set; }
 
         [ExcelColumnName("二级热点")]
         public string HotspotNameTwo { get; set; }
+
         [ExcelColumnName("三级热点")]
         public string HotspotNameThree { get; set; }
 
         [ExcelColumnName("四级热点")]
-        public string HotspotNameFour { get; set;}
+        public string HotspotNameFour { get; set; }
 
         [ExcelColumnName("五级热点")]
         public string HotspotNameFive { get; set; }
 
-        [ExcelColumnName("市")]
-        public string City { get; set; }
-
-        [ExcelColumnName("区")]
-        public string County { get; set; }
-
-        [ExcelColumnName("乡镇")]
-        public string? Town { get; set; }
+        /// <summary>
+        /// 区域名称
+        /// </summary>
+        [Required(ErrorMessage = "区域 不能为空")]
+        [ExcelColumnName("区域")]
+        public string Address { get; set; }
 
         [ExcelColumnName("事发地址")]
         public string Street { get; set; }
 
+        [Required(ErrorMessage = "来电人姓名 不能为空")]
         [ExcelColumnName("来电人姓名")]
         public string FromName { get; set; }
 
+        [Required(ErrorMessage = "联系电话 不能为空")]
         [ExcelColumnName("联系电话")]
         public string Contact { get; set; }
-        
+
+        /// <summary>
+        /// 是否超期(是或否)
+        /// "是" or "否"
+        /// </summary>
+        [ExcelColumnName("是否超期")]
+        public string IsExpired { get; set; }
+
+        /// <summary>
+        /// 默认 0
+        /// </summary>
+        [Required(ErrorMessage = "重办次数 不能为空")]
         [ExcelColumnName("重办次数")]
         public int ReTransactNum { get; set; }
+
+        [Required(ErrorMessage = "信件满意度 不能为空")]
         [ExcelColumnName("信件满意度")]
         public string VisitResult { get; set; }
 
+        [Required(ErrorMessage = "受理内容 不能为空")]
         [ExcelColumnName("受理内容")]
         public string Content { get; set; }
 
+        [Required(ErrorMessage = "承办意见 不能为空")]
         [ExcelColumnName("承办意见")]
         public string ActualOpinion { get; set; }
 
+        /// <summary>
+        /// 链接
+        /// TODO 没有存
+        /// </summary>
+        [ExcelColumnName("链接")]
+        public string Link { get; set; }
     }
 }

+ 1 - 1
src/Hotline/Orders/OrderDomainService.cs

@@ -495,7 +495,7 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
         return cacheOrderNo;
     }
 
-    private string GenerateNewOrderNo()
+    public string GenerateNewOrderNo()
     {
         var today = DateTime.Today;
         var cacheKey = $"{today:yyyyMMdd}";

+ 2 - 2
src/XF.Domain/Entities/IWorkflow.cs

@@ -78,9 +78,9 @@ public enum EFlowAssignType
     Role = 2,
 
 	/// <summary>
-	/// 指派到部门与角色
+	/// 指派到指定部门的指定角色
 	/// </summary>
-	OrgOrRole = 3,
+	OrgAndRole = 3,
 }
 
 /// <summary>