qinchaoyue 2 tháng trước cách đây
mục cha
commit
c7fb2b6298

+ 0 - 7
Hotline.sln

@@ -53,8 +53,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XingTang.Sdk", "src\XingTan
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hotline.XingTang", "src\Hotline.XingTang\Hotline.XingTang.csproj", "{9F99C272-5BC2-452C-9D97-BC756AF04669}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hotline.Logger", "src\Hotline.Logger\Hotline.Logger.csproj", "{37784861-ABC0-41F4-87B4-2E08A89A2C42}"
-EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hotline.WeChat", "src\Hotline.WeChat\Hotline.WeChat.csproj", "{75215667-65AF-4B7B-85E7-3140239B30CC}"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TianQue.Sdk", "src\TianQue.Sdk\TianQue.Sdk.csproj", "{6CF27647-D0E0-4D17-80FB-3EE57864A2B4}"
@@ -147,10 +145,6 @@ Global
 		{9F99C272-5BC2-452C-9D97-BC756AF04669}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{9F99C272-5BC2-452C-9D97-BC756AF04669}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{9F99C272-5BC2-452C-9D97-BC756AF04669}.Release|Any CPU.Build.0 = Release|Any CPU
-		{37784861-ABC0-41F4-87B4-2E08A89A2C42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{37784861-ABC0-41F4-87B4-2E08A89A2C42}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{37784861-ABC0-41F4-87B4-2E08A89A2C42}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{37784861-ABC0-41F4-87B4-2E08A89A2C42}.Release|Any CPU.Build.0 = Release|Any CPU
 		{75215667-65AF-4B7B-85E7-3140239B30CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{75215667-65AF-4B7B-85E7-3140239B30CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{75215667-65AF-4B7B-85E7-3140239B30CC}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -199,7 +193,6 @@ Global
 		{C3F289D5-C50B-46DB-852C-9543EF9B0355} = {D041C554-B78E-4AAF-B597-E309DC8EEF4F}
 		{CF2A8B80-FF4E-4291-B383-D735BB629F32} = {D041C554-B78E-4AAF-B597-E309DC8EEF4F}
 		{9F99C272-5BC2-452C-9D97-BC756AF04669} = {D041C554-B78E-4AAF-B597-E309DC8EEF4F}
-		{37784861-ABC0-41F4-87B4-2E08A89A2C42} = {D041C554-B78E-4AAF-B597-E309DC8EEF4F}
 		{75215667-65AF-4B7B-85E7-3140239B30CC} = {D041C554-B78E-4AAF-B597-E309DC8EEF4F}
 		{6CF27647-D0E0-4D17-80FB-3EE57864A2B4} = {D041C554-B78E-4AAF-B597-E309DC8EEF4F}
 		{8E4F64EF-314A-45BA-8BB2-46FF5B06F7D5} = {D041C554-B78E-4AAF-B597-E309DC8EEF4F}

+ 24 - 3
src/Hotline.Api/Controllers/IPPbxController.cs

@@ -43,6 +43,7 @@ using Hotline.Tools;
 using Hotline.Api.Filter;
 using XF.Domain.Cache;
 using Hotline.Application.CallCenter;
+using Mapster;
 
 namespace Hotline.Api.Controllers
 {
@@ -75,6 +76,7 @@ namespace Hotline.Api.Controllers
         private readonly ITrCallRecordRepository _callRecordRepository;
         private readonly IIPPbxApplication _iPPbxApplication;
         private readonly ICallTelClient _callTelClient;
+        private readonly IRepository<TelOperation> _telOperationRepository;
 
         public IPPbxController(IMapper mapper, IUserDomainService userDomainService,
             ISessionContext sessionContext, IRepository<TrCallRecord> trCallRecordRepository,
@@ -86,7 +88,7 @@ namespace Hotline.Api.Controllers
             ITelApplication telApplication, IRepository<Quality.Quality> qualiteyRepository,
             IAiQualityService aiQualityService, IRepository<QualityTemplate> qualityTemplate,
             ISystemSettingCacheManager systemSettingCacheManager, IRepository<TelActionRecord> telActionRecordRepository,
-            ISystemMobilAreaApplication systemMobilAreaApplication, IRepository<Work> workRepository, Publisher publisher, ITrCallRecordRepository callRecordRepository, ITypedCache<Work> cacheWork, IIPPbxApplication iPPbxApplication, ICallTelClient callTelClient)
+            ISystemMobilAreaApplication systemMobilAreaApplication, IRepository<Work> workRepository, Publisher publisher, ITrCallRecordRepository callRecordRepository, ITypedCache<Work> cacheWork, IIPPbxApplication iPPbxApplication, ICallTelClient callTelClient, IRepository<TelOperation> telOperationRepository)
         {
             _mapper = mapper;
             _userDomainService = userDomainService;
@@ -115,6 +117,7 @@ namespace Hotline.Api.Controllers
             _cacheWork = cacheWork;
             _iPPbxApplication = iPPbxApplication;
             _callTelClient = callTelClient;
+            _telOperationRepository = telOperationRepository;
         }
 
         #region 添添呼
@@ -457,7 +460,6 @@ namespace Hotline.Api.Controllers
 
         #endregion
 
-
         #region 通话记录(对外)
         /// <summary>
         /// 接收通话记录
@@ -669,9 +671,28 @@ namespace Hotline.Api.Controllers
         /// <param name="dto"></param>
         /// <returns></returns>
         [AllowAnonymous]
+        [StaffNoSessionContextFilter()]
         [HttpPost("notify/status")]
+        [LogFilterAlpha("话机状态通知")]
         public async Task NotifyStatus(NotifyInDto dto)
-        { }
+        {
+            if (dto.Status == 0) // 签出
+            {
+                await _iPPbxApplication.ResetTelStatus(null, dto.TelNo, CancellationToken.None);
+            }
+            dto.Status = dto.Status switch
+            {
+                0 => 16, //签出
+                100 => 0, //签入
+                301 => 1, // 接听
+                202 => 2,// 置忙
+                200 => 3, // 置闲
+                303 => 17, //呼出
+                400 => 30, // 挂机
+                _ => -1
+            };
+            await _callApplication.EndActionAsync(dto.Adapt<EndActionInDto>());
+        }
 
         #endregion
 

+ 62 - 0
src/Hotline.Api/Filter/StaffNoSessionContextFilter.cs

@@ -0,0 +1,62 @@
+using Hotline.Identity.Accounts;
+using Hotline.Settings;
+using Hotline.Share.Dtos.CallCenter;
+using Hotline.Share.Tools;
+using Hotline.Users;
+using IdentityModel;
+using Microsoft.AspNetCore.Mvc.Filters;
+using System.Security.Claims;
+using XF.Domain.Authentications;
+using XF.Domain.Repository;
+using static Hotline.AppDefaults;
+
+namespace Hotline.Api.Filter;
+
+public class StaffNoSessionContextFilter : ActionFilterAttribute
+{
+    private IAccountRepository _accountRepository;
+    private IRepository<User> _userRepository;
+
+    public StaffNoSessionContextFilter()
+    {
+    }
+
+    public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
+    {
+        await ReloadUser(context);
+        await next();
+    }
+
+    private async Task ReloadUser(ActionExecutingContext context)
+    {
+        try
+        {
+            _accountRepository = context.HttpContext.RequestServices.GetRequiredService<IAccountRepository>();
+            _userRepository = context.HttpContext.RequestServices.GetRequiredService<IRepository<User>>();
+            var notifyInDto = context.ActionArguments.Values.FirstOrDefault() as NotifyInDto;
+            if (notifyInDto == null) return;
+            var user = _userRepository.Queryable().Where(m => m.StaffNo == notifyInDto.StaffNo).First();
+            if (user == null) return;
+            var account = await _accountRepository.GetExtAsync(m => m.Id == user.Id, m => m.Includes(x => x.Roles));
+
+            List<Claim> userClaims = [
+                new(JwtClaimTypes.Subject, account.Id),
+                new(JwtClaimTypes.PhoneNumber, account.PhoneNo ?? string.Empty),
+                new(ClaimTypes.NameIdentifier, user.Id),
+                new(AppClaimTypes.UserDisplayName, account.Name),
+                new(AppClaimTypes.DepartmentId, user.OrgId ?? string.Empty),
+                new(AppClaimTypes.DepartmentIsCenter, user.Organization?.IsCenter.ToString() ?? string.Empty),
+                new(AppClaimTypes.DepartmentName, user.Organization?.Name ?? string.Empty),
+                new(AppClaimTypes.DepartmentAreaCode, user.Organization?.AreaCode ?? string.Empty),
+                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),
+            ];
+            userClaims.AddRange(account.Roles.Select(d => new Claim(JwtClaimTypes.Role, d.Name)));
+            context.HttpContext.User = new ClaimsPrincipal(new ClaimsIdentity(userClaims));
+        }
+        catch
+        {
+        }
+    }
+}

+ 0 - 1
src/Hotline.Api/Hotline.Api.csproj

@@ -27,7 +27,6 @@
 
   <ItemGroup>
     <ProjectReference Include="..\Hotline.Application\Hotline.Application.csproj" />
-    <ProjectReference Include="..\Hotline.Logger\Hotline.Logger.csproj" />
     <ProjectReference Include="..\Hotline.WeChat\Hotline.WeChat.csproj" />
     <ProjectReference Include="..\Hotline.XingTang\Hotline.XingTang.csproj" />
     <ProjectReference Include="..\TianQue.Sdk\TianQue.Sdk.csproj" />

+ 1 - 0
src/Hotline.Api/Program.cs

@@ -1,5 +1,6 @@
 using Hotline.Api;
 using Serilog;
+using XF.Domain.Authentications;
 
 Log.Logger = new LoggerConfiguration()
     .WriteTo.Console()

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

@@ -29,7 +29,6 @@ using Hotline.Configurations;
 using Hotline.DI;
 using Hotline.Settings.TimeLimitDomain.ExpireTimeSupplier;
 using XF.Domain.Authentications;
-using HotPot.Mvc.Filters;
 using Hotline.WeChat;
 using Hotline.Snapshot.Interfaces;
 using TianQue.Sdk;

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

@@ -68,13 +68,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,

+ 19 - 0
src/Hotline.Application/CallCenter/DefaultCallApplication.cs

@@ -120,6 +120,25 @@ public abstract class DefaultCallApplication : ICallApplication
             .ToListAsync(cancellationToken);
     }
 
+    /// <summary>
+    /// 记录分机结束动作时间
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    public async Task EndActionAsync(EndActionInDto dto)
+    {
+        var telOperation = await _telOperationRepository.Queryable()
+            .Where(m => m.StaffNo == dto.StaffNo && m.TelNo == dto.TelNo && !m.EndTime.HasValue)
+            .WhereIF(dto.Status != -1, m => m.OperateState != dto.Status)
+            .WhereIF(dto.Status == -1, m => m.OperateStateText == "未知")
+            .OrderByDescending(m => m.CreationTime)
+            .FirstAsync();
+        if (telOperation == null) return;
+        telOperation.EndAction();
+        await _telOperationRepository.UpdateAsync(telOperation);
+    }
+
+
     /// <summary>
     /// 新增黑名单
     /// </summary>

+ 7 - 0
src/Hotline.Application/CallCenter/ICallApplication.cs

@@ -13,6 +13,13 @@ namespace Hotline.Application.CallCenter
 {
     public interface ICallApplication
     {
+        /// <summary>
+        /// 记录分机结束动作时间
+        /// </summary>
+        /// <param name="inDto"></param>
+        /// <returns></returns>
+        Task EndActionAsync(EndActionInDto inDto);
+
         /// <summary>
         /// 查询分机
         /// </summary>

+ 0 - 63
src/Hotline.Logger/Filters/ErrorHandlingFilter.cs

@@ -1,63 +0,0 @@
-
-using System;
-using Hotline.Logger.Models;
-using Hotline.Share.Tools;
-using Microsoft.AspNetCore.Mvc.Filters;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
-using Serilog;
-
-namespace HotPot.Mvc.Filters
-{
-    /// <summary>
-    /// 异常拦截处理
-    /// </summary>
-    public class ErrorHandlingFilter : IExceptionFilter
-    {
-        /// <summary>
-        /// 日志记录器
-        /// </summary>
-        private readonly Serilog.ILogger _logger;
-
-        private readonly IConfiguration _configuration;
-
-        public ErrorHandlingFilter(ILogger logger, IConfiguration configuration)
-        {
-            _configuration = configuration;
-            _logger = new LoggerConfiguration()
-                .WriteTo.Logger(configure => configure
-                .MinimumLevel.Debug()
-                .WriteTo.RollingFile(
-                    Path.Combine("logs", "err-log-{Date}.txt"),
-                    retainedFileCountLimit: 7,
-                    outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}"
-                ))
-                .CreateLogger();
-
-        }
-
-        /// <summary>
-        /// 异常拦截处理
-        /// </summary>
-        /// <param name="context">异常</param>
-        public void OnException(ExceptionContext context)
-        {
-            if (_configuration.GetSection("AccLog").Get<bool>() == false) return;
-            var exceptionModel = new ExceptionModel();
-            try
-            {
-
-                context.HttpContext.Items.TryAdd("ErrorId", exceptionModel.Id);
-                exceptionModel.Context = context.Exception.ToJson();
-                exceptionModel.Method = context.HttpContext.Request.Path;
-                exceptionModel.Message = context.Exception.Message;
-                _logger.Error(exceptionModel.ToJson());
-            }
-            catch
-            {
-                // ignore
-            }
-        }
-    }
-}
-

+ 0 - 22
src/Hotline.Logger/Hotline.Logger.csproj

@@ -1,22 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-
-  <PropertyGroup>
-    <TargetFramework>net8.0</TargetFramework>
-    <ImplicitUsings>enable</ImplicitUsings>
-    <Nullable>enable</Nullable>
-  </PropertyGroup>
-
-  <ItemGroup>
-    <PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
-    <PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.2.0" />
-    <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.2" />
-    <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.2" />
-    <PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
-    <PackageReference Include="Serilog.Sinks.RollingFile" Version="3.3.0" />
-  </ItemGroup>
-
-  <ItemGroup>
-    <ProjectReference Include="..\Hotline.Share\Hotline.Share.csproj" />
-  </ItemGroup>
-
-</Project>

+ 0 - 59
src/Hotline.Logger/Models/AccModel.cs

@@ -1,59 +0,0 @@
-namespace Hotline.Logger.Models
-{
-    /// <summary>
-    /// 日志类
-    /// </summary>
-    public class AccModel : BaseLogModel
-    {
-        /// <summary>
-        /// 时间间隔
-        /// </summary>
-        /// <returns></returns>
-        public long Interval { get; set; }
-
-        /// <summary>
-        /// 方向 (Response, Request)
-        /// </summary>
-        public string Direction { get; set; } = string.Empty;
-
-        /// <summary>
-        /// 服务地址
-        /// 请求/响应服务的地址
-        /// </summary>
-        public string ServiceUrl { get; set; }
-
-        /// <summary>
-        /// 被调用方法
-        /// 被调用的方法,直接API地址
-        /// </summary>
-        public string Method { get; set; }
-
-        /// <summary>
-        /// 请求入参
-        /// 请求(Request)的请求参数,响应时为空
-        /// </summary>
-        public string InParam { get; set; }
-
-        /// <summary>
-        /// 异常ID
-        /// 调用服务有异常时,异常信息的日志ID,没异常日志时为空
-        /// </summary>
-        public string? ErrorId { get; set; }
-
-        /// <summary>
-        /// 返回值
-        /// 响应结果
-        /// </summary>
-        public string OutResult { get; set; } = string.Empty;
-
-        /// <summary>
-        /// 用户
-        /// </summary>
-        public string User { get; set; }
-
-        /// <summary>
-        /// 用户字段Key
-        /// </summary>
-        public string UserKey = "user_display_name";
-    }
-}

+ 0 - 48
src/Hotline.Logger/Models/BaseLogModel.cs

@@ -1,48 +0,0 @@
-using System.Net;
-
-namespace Hotline.Logger.Models
-{
-    public class BaseLogModel
-    {
-        public BaseLogModel()
-        {
-            Id = Guid.NewGuid().ToString();
-        }
-
-        /// <summary>
-        /// 日志id
-        /// </summary>
-        public string Id { get; set; }
-
-        /// <summary>
-        /// 时间点
-        /// 发起请求时间点
-        /// </summary>
-        public string RequestTime => DateTime.Now.ToString("yyyy年MM月dd日 hh:mm:ss");
-
-        /// <summary>
-        /// 时间戳
-        /// </summary>
-        public long Timestamp =>
-            (long)(DateTime.Now - TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1))).TotalMilliseconds;
-
-        /// <summary>
-        /// 主机名
-        /// 服务所在的机器名
-        /// </summary>
-        public string Host
-        {
-            get
-            {
-                try
-                {
-                    return Dns.GetHostName();
-                }
-                catch (Exception)
-                {
-                    return "获取主机名失败";
-                }
-            }
-        }
-    }
-}

+ 0 - 72
src/Hotline.Logger/Models/ExceptionModel.cs

@@ -1,72 +0,0 @@
-using System.Diagnostics;
-
-namespace Hotline.Logger.Models
-{
-    /// <summary>
-    /// 异常日志
-    /// </summary>
-    public class ExceptionModel : BaseLogModel
-    {
-        /// <summary>
-        /// 进程ID
-        /// 应用程序的进程ID,可为空
-        /// </summary>
-        public string ProcessId
-        {
-            get
-            {
-                try
-                {
-                    return Process.GetCurrentProcess().Id.ToString();
-                }
-                catch
-                {
-                    return "获取进程Id失败";
-                }
-            }
-        }
-
-        /// <summary>
-        /// 线程ID
-        /// 可为空
-        /// </summary>
-        public string ThreadId
-        {
-            get
-            {
-                try
-                {
-                    return Thread.CurrentThread.ManagedThreadId.ToString();
-                }
-                catch
-                {
-                    return "获取线程Id失败";
-                }
-            }
-        }
-
-        /// <summary>
-        /// 错误码
-        /// 程序自定义的错误码,某种错误指定的错误码,没有定义时为为空
-        /// </summary>
-        public string ErrorCode { get; set; } = string.Empty;
-
-        /// <summary>
-        /// 异常信息
-        /// Exception message信息
-        /// </summary>
-        public string Message { get; set; } = string.Empty;
-
-        /// <summary>
-        /// 异常上下文
-        /// 包括了异常堆栈信息,用于分析具体问题
-        /// </summary>
-        public string Context { get; set; } = string.Empty;
-
-        /// <summary>
-        /// 被调用方法
-        /// 被调用的方法,直接API地址
-        /// </summary>
-        public string Method { get; set; }
-    }
-}

+ 0 - 188
src/Hotline.Logger/RequestResponseLoggingMiddleware.cs

@@ -1,188 +0,0 @@
-using Hotline.Logger.Models;
-using Microsoft.Extensions.Configuration;
-using Hotline.Share.Tools;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Http;
-using Microsoft.Extensions.Logging;
-using Serilog;
-using System.Text;
-
-namespace Hotline.Logger
-{
-
-    /// <summary>
-    /// Acc 日志记录
-    /// </summary>
-    public class RequestResponseLoggingMiddleware
-    {
-        /// <summary>
-        /// 组件
-        /// </summary>
-        private readonly RequestDelegate _next;
-
-        /// <summary>
-        /// 日志记录器
-        /// </summary>
-        private readonly Serilog.ILogger _logger;
-
-        public RequestResponseLoggingMiddleware(RequestDelegate next)
-        {
-            _next = next;
-            _logger = new LoggerConfiguration()
-                .WriteTo.Logger(configure => configure 
-                .MinimumLevel.Debug()
-                .WriteTo.RollingFile(
-                    Path.Combine("logs", "acc-log-{Date}.txt"),
-                    retainedFileCountLimit: 7,
-                    outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}"
-                ))
-                .CreateLogger();
-        }
-
-        /// <summary>
-        /// 日志记录器
-        /// </summary>
-        /// <param name="context"> The context.  </param>
-        /// <returns> The <see cref="Task"/>.  </returns>
-        public async Task Invoke(HttpContext context)
-        {
-            var injectedRequestStream = new MemoryStream();
-            try
-            {
-                var requestTime = DateTime.Now;
-                var accModel = new AccModel();
-                context.Items.TryAdd("AccId", accModel.Id);
-                await GetMethod(context, injectedRequestStream, accModel);
-                var originalBodyStream = context.Response.Body;
-                using (var responseBody = new MemoryStream())
-                {
-                    context.Response.Body = responseBody;
-                    await _next(context);
-
-                    accModel = await FormatResponse(context.Response, requestTime, accModel);
-                    if (context.Items.TryGetValue("ErrorId", out var errorId))
-                        accModel.ErrorId = errorId.ToString();
-                    _logger.Information(accModel.ToJson());
-                    await responseBody.CopyToAsync(originalBodyStream);
-                }
-
-            }
-            catch (Exception e)
-            {
-                throw new Exception("Hotline.Logger.RequestResponseLoggingMiddleware.GetMethod", e);
-            }
-            finally
-            {
-                injectedRequestStream.Dispose();
-            }
-        }
-
-        /// <summary>
-        /// 获取 响应日志数据
-        /// </summary>
-        /// <param name="response"> The response.  </param>
-        /// <param name="requestTime"> The request time.  </param>
-        /// <returns> The <see cref="Task"/>.  </returns>
-        private async Task<AccModel> FormatResponse(HttpResponse response, DateTime requestTime, AccModel accModel)
-        {
-            response.Body.Seek(0, SeekOrigin.Begin);
-            var text = await new StreamReader(response.Body).ReadToEndAsync();
-            response.Body.Seek(0, SeekOrigin.Begin);
-            if (response.ContentType.Contains("application/json"))
-            { 
-                accModel.OutResult = text;
-            }
-            accModel.Interval = (long)(DateTime.Now - requestTime).TotalMilliseconds;
-            return accModel;
-        }
-
-        /// <summary>
-        /// 获取请求入参和方法
-        /// </summary>
-        /// <param name="context">
-        /// The context.
-        /// </param>
-        /// <param name="injectedRequestStream">
-        /// The injected Request Stream.
-        /// </param>
-        private async Task GetMethod(HttpContext context, MemoryStream injectedRequestStream, AccModel accModel)
-        {
-            try
-            {
-                if (context.Request.Method.ToUpper() == "GET")
-                {
-                    try
-                    {
-                        accModel.InParam = context.Request.QueryString.ToString();
-                        accModel.Method = context.Request.Path;
-                        accModel.ServiceUrl = context.Request.Host.ToString();
-                    }
-                    catch (Exception e)
-                    {
-                        accModel.InParam = "GetMethod.Get 代码块异常;";
-                        accModel.Method = "GetMethod.Get 代码块异常;";
-                        accModel.ServiceUrl = e.ToString();
-                    }
-                }
-
-                if (context.Request.Method.ToUpper() == "POST" || context.Request.Method.ToUpper() == "PUT" || context.Request.Method.ToUpper() == "DELETE")
-                {
-                    if (context.Request.ContentType?.IndexOf("multipart/form-data", StringComparison.Ordinal) == -1)
-                    {
-                        using var bodyReader = new StreamReader(context.Request.Body);
-                        var bodyAsText = await bodyReader.ReadToEndAsync();
-
-                        var bytesToWrite = Encoding.UTF8.GetBytes(bodyAsText);
-                        injectedRequestStream.Write(bytesToWrite, 0, bytesToWrite.Length);
-                        injectedRequestStream.Seek(0, SeekOrigin.Begin);
-                        context.Request.Body = injectedRequestStream;
-
-                        accModel.InParam = bodyAsText;
-                    }
-                    accModel.Method = context.Request.Path;
-                    accModel.ServiceUrl = context.Request.Host.ToString();
-                }
-
-                try
-                {
-                    accModel.User = context.User.Identities
-                        .FirstOrDefault()?.Claims
-                        .Where(m => m.Type == accModel.UserKey)
-                        .Select(m => m.Value)
-                        .FirstOrDefault() ?? string.Empty;
-                }
-                catch { }
-            }
-            catch (Exception e)
-            {
-                _logger.Error($"Hotline.Logger.RequestResponseLoggingMiddleware.GetMethod: {e}");
-            }
-
-        }
-    }
-
-    /// <summary>
-    /// 注册 acc 日志记录器
-    /// </summary>
-    public static class RequestResponseLoggingMiddlewareExtensions
-    {
-        /// <summary>
-        /// 注册日志记录服务
-        /// </summary>
-        /// <param name="builder">
-        /// The builder.
-        /// </param>
-        /// <returns>
-        /// The <see cref="IApplicationBuilder"/>.
-        /// </returns>
-        public static IApplicationBuilder UseRequestResponseLogging(this IApplicationBuilder builder, IConfiguration configuration)
-        {
-            var isAccLog = configuration.GetSection("AccLog").Get<bool>();
-            if (isAccLog)
-            {
-                return builder.UseMiddleware<RequestResponseLoggingMiddleware>();
-            }
-            return builder;
-        }
-    }
-}

+ 7 - 0
src/Hotline.Share/Dtos/CallCenter/TelDto.cs

@@ -95,6 +95,13 @@ namespace Hotline.Share.Dtos.CallCenter
     {
     }
 
+    public class EndActionInDto
+    {
+        public string StaffNo { get; set; }
+        public string TelNo { get; set; }
+        public int Status { get; set; }
+    }
+
     public class NotifyStatusInDto
     {
         /// <summary>

+ 0 - 1
src/Hotline.XingTang/ServiceCollectionExtensions.cs

@@ -1,6 +1,5 @@
 using Fw.Utility.UnifyResponse;
 using Hotline.CallCenter.Tels;
-using Hotline.XingTang.Dto;
 using Microsoft.AspNetCore.Builder;
 using Microsoft.AspNetCore.Http;
 using Microsoft.Extensions.DependencyInjection;

+ 20 - 0
src/Hotline/CallCenter/Tels/TelOperation.cs

@@ -37,8 +37,28 @@ namespace Hotline.CallCenter.Tels
         public string? OperateStateText { get; set; }
 
         public DateTime? OperateTime { get; set; }
+
+        /// <summary>
+        /// 动作结束时间
+        /// </summary>
+        [SugarColumn(ColumnDescription = "动作结束时间")]
+        public DateTime? EndTime { get; set; }
+
+        /// <summary>
+        /// 时长(秒)
+        /// </summary>
+        [SugarColumn(ColumnDescription = "动作时长(秒)")]
+        public double? Duration { get; set; }
+
         public int? Channel { get; set; }
         public string? CompanyId { get; set; }
         public string? Remark { get; set; }
+
+        public void EndAction()
+        {
+            EndTime = DateTime.Now;
+            Duration = (EndTime.Value - OperateTime.Value).TotalSeconds;
+        }
+
     }
 }

+ 16 - 31
src/XF.Domain/Authentications/DefaultSessionContext.cs

@@ -9,6 +9,7 @@ namespace XF.Domain.Authentications
 {
     public class DefaultSessionContext : ISessionContext, IScopeDependency
     {
+        private readonly HttpContext _context;
         public DefaultSessionContext(IHttpContextAccessor httpContextAccessor)
         {
             var httpContext = httpContextAccessor.HttpContext;
@@ -16,29 +17,13 @@ namespace XF.Domain.Authentications
                 //throw new ArgumentNullException(nameof(httpContext));
                 return;
 
-            var user = httpContext.User;
-            //UserId = user.FindFirstValue(JwtClaimTypes.Id);
-            UserId = user.FindFirstValue(ClaimTypes.NameIdentifier);
-            UserName = user.FindFirstValue(AppClaimTypes.UserDisplayName);
-            Phone = user.FindFirstValue(JwtClaimTypes.PhoneNumber);
-            //Roles = user.Claims.Where(d => d.Type == JwtClaimTypes.Role).Select(d => d.Value).ToArray();
-            Roles = user.Claims.Where(d => d.Type == ClaimTypes.Role).Select(d => d.Value).ToArray();
-            OrgId = user.FindFirstValue(AppClaimTypes.DepartmentId);
-            OrgName = user.FindFirstValue(AppClaimTypes.DepartmentName);
-            OrgLevel = user.FindIntValue(AppClaimTypes.DepartmentLevel);
-            OrgAreaCode = user.FindFirstValue(AppClaimTypes.DepartmentAreaCode);
-            OrgAreaName = user.FindFirstValue(AppClaimTypes.DepartmentAreaName);
-            OrgIsCenter = user.FindBoolValue(AppClaimTypes.DepartmentIsCenter);
-            AreaId = user.FindFirstValue(AppClaimTypes.AreaId);
-            ClientId = user.FindFirstValue(JwtClaimTypes.ClientId);
-            StaffNo = user.FindFirstValue(AppClaimTypes.StaffNo);
-            OpenId = user.FindFirstValue(AppClaimTypes.OpenId);
+            _context = httpContext;
         }
 
         /// <summary>
         /// Id of current tenant or null for host
         /// </summary>
-        public string? UserId { get; init; }
+        public string? UserId { get => _context.User.FindFirstValue(ClaimTypes.NameIdentifier); init { } }
 
         /// <summary>
         /// Id of current user or throw Exception for guest
@@ -46,43 +31,43 @@ namespace XF.Domain.Authentications
         /// <exception cref="AuthenticationException"></exception>
         public string RequiredUserId => UserId ?? throw new ArgumentNullException();
 
-        public string? UserName { get; init; }
+        public string? UserName { get => _context.User.FindFirstValue(AppClaimTypes.UserDisplayName); init { } }
 
-        public string? Phone { get; init; }
+        public string? Phone { get => _context.User.FindFirstValue(JwtClaimTypes.PhoneNumber); init { } }
 
         /// <summary>
         /// Roles
         /// </summary>
-        public string[] Roles { get; init; }
+        public string[] Roles { get => _context.User.Claims.Where(d => d.Type == JwtClaimTypes.Role).Select(d => d.Value).ToArray(); init { } }
 
-        public string? OrgId { get; init; }
-        public string? OrgName { get; init; }
+        public string? OrgId { get => _context.User.FindFirstValue(AppClaimTypes.DepartmentId); init { } }
+        public string? OrgName { get => _context.User.FindFirstValue(AppClaimTypes.DepartmentName); init { } }
 
-        public int OrgLevel { get; init; }
-        public string? OrgAreaCode { get; init; }
-        public bool OrgIsCenter { get; init; }
+        public int OrgLevel { get => _context.User.FindIntValue(AppClaimTypes.DepartmentLevel); init { } }
+        public string? OrgAreaCode { get => _context.User.FindFirstValue(AppClaimTypes.DepartmentAreaCode); init { } }
+        public bool OrgIsCenter { get => _context.User.FindBoolValue(AppClaimTypes.DepartmentIsCenter); init { } }
 
         /// <summary>
         /// 部门行政区划名称
         /// </summary>
-        public string? OrgAreaName { get; init; }
+        public string? OrgAreaName { get => _context.User.FindFirstValue(AppClaimTypes.DepartmentAreaName); init { } }
 
-        public string? AreaId { get; init; }
+        public string? AreaId { get => _context.User.FindFirstValue(AppClaimTypes.AreaId); init { } }
 
         public string RequiredOrgId => OrgId ?? throw new ArgumentNullException();
         
-        public string? ClientId { get; init; }
+        public string? ClientId { get => _context.User.FindFirstValue(JwtClaimTypes.ClientId); init { } }
 
         /// <summary>
         /// 工号
         /// </summary>
-        public string? StaffNo { get; init; }
+        public string? StaffNo { get => _context.User.FindFirstValue(AppClaimTypes.StaffNo); init { } }
 
         /// <summary>
         /// 第三方平台用户唯一标识
         /// 例如: 微信的OpenId
         /// </summary>
-        public string? OpenId { get; init; }
+        public string? OpenId { get => _context.User.FindFirstValue(AppClaimTypes.OpenId); init { } }
     }
 
     public static class ClaimsPrincipalExtensions

+ 2 - 2
test/Hotline.Tests/Controller/DefaultSessionContext.cs → test/Hotline.Tests/Controller/TestSessionContext.cs

@@ -6,10 +6,10 @@ using XF.Domain.Authentications;
 using XF.Domain.Dependency;
 
 namespace Hotline.Tests.Controller;
-public class DefaultSessionContext : ISessionContext, IScopeDependency
+public class TestSessionContext : ISessionContext, IScopeDependency
 {
     private readonly IHttpContextAccessor _contextAccessor;
-    public DefaultSessionContext(IHttpContextAccessor httpContextAccessor)
+    public TestSessionContext(IHttpContextAccessor httpContextAccessor)
     {
         _contextAccessor = httpContextAccessor;
         //Roles = user.Claims.Where(d => d.Type == JwtClaimTypes.Role).Select(d => d.Value).ToArray();

+ 2 - 1
test/Hotline.Tests/Startup.cs

@@ -32,6 +32,7 @@ using Mapster;
 using MediatR;
 using Microsoft.AspNetCore.Builder;
 using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Identity;
 using Microsoft.Extensions.Configuration;
 using Microsoft.Extensions.DependencyInjection;
@@ -168,7 +169,7 @@ public class Startup
             services.AddScoped<RedPackController>();
             services.AddScoped<PushMessageController>();
             services.AddHttpContextAccessor();
-            services.AddScoped<ISessionContext, Controller.DefaultSessionContext>();
+            services.AddScoped<ISessionContext, Controller.TestSessionContext>();
             services.AddScoped<ISessionContextProvider, SessionContextProvider>();
             services.AddScoped<ICallApplication, XingTangCallApplication>();
             services.AddScoped<XingTangCallApplication>();