Browse Source

feat: 重构网络栈配置管理功能

- 修复networkStackConfigService.ts接口不匹配问题
- 删除未使用的stackCoreIMSBindingService.ts
- 重构NetworkStackConfigForm为NetworkStackConfigDrawer
- 实现RAN配置下拉框,支持搜索功能
- 移除激活配置复选框,默认激活
- 修复loadRANConfigurations使用正确服务
- 实现核心网和IMS配置下拉框
- 优化绑定关系布局和滚动条显示
- 添加标签右对齐样式
- 修复下拉框定位和点击交互问题
- 实现下拉框互斥控制和自动关闭
- 添加完整的表单校验逻辑
- 实现内联错误提示替代弹窗
feature/x1-web-request
hyh 5 days ago
parent
commit
41828bf7cf
  1. 2
      src/X1.Application/Features/CoreNetworkConfigs/Queries/GetCoreNetworkConfigs/GetCoreNetworkConfigsQuery.cs
  2. 2
      src/X1.Application/Features/IMSConfiguration/Queries/GetIMS_Configurations/GetIMS_ConfigurationsQuery.cs
  3. 2
      src/X1.Application/Features/ProtocolVersions/Queries/GetProtocolVersions/GetProtocolVersionsQuery.cs
  4. 2
      src/X1.Application/Features/RANConfiguration/Queries/GetRAN_Configurations/GetRAN_ConfigurationsQuery.cs
  5. 4
      src/X1.WebAPI/Properties/launchSettings.json
  6. 4
      src/X1.WebAPI/X1.WebAPI.csproj
  7. 46
      src/X1.WebAPI/logs/app-20250726.log
  8. 604
      src/X1.WebAPI/logs/app-20250727.log
  9. 6375
      src/X1.WebAPI/logs/app-20250729.log
  10. 20
      src/X1.WebAPI/logs/error-20250727.log
  11. 165
      src/X1.WebAPI/logs/error-20250729.log
  12. 2
      src/X1.WebUI/src/config/core/env.config.ts
  13. 5
      src/X1.WebUI/src/constants/api.ts
  14. 771
      src/X1.WebUI/src/pages/network-stack-configs/NetworkStackConfigDrawer.tsx
  15. 90
      src/X1.WebUI/src/pages/network-stack-configs/NetworkStackConfigForm.tsx
  16. 6
      src/X1.WebUI/src/pages/network-stack-configs/NetworkStackConfigsTable.tsx
  17. 84
      src/X1.WebUI/src/pages/network-stack-configs/NetworkStackConfigsView.tsx
  18. 55
      src/X1.WebUI/src/services/networkStackConfigService.ts
  19. 112
      src/X1.WebUI/src/services/stackCoreIMSBindingService.ts
  20. 190
      src/modify.md

2
src/X1.Application/Features/CoreNetworkConfigs/Queries/GetCoreNetworkConfigs/GetCoreNetworkConfigsQuery.cs

@ -18,7 +18,7 @@ public class GetCoreNetworkConfigsQuery : IRequest<OperationResult<GetCoreNetwor
/// <summary>
/// 每页数量
/// </summary>
[Range(1, 100, ErrorMessage = "每页数量必须在1-100之间")]
[Range(1, 1000, ErrorMessage = "每页数量必须在1-1000之间")]
public int PageSize { get; set; } = 10;
/// <summary>

2
src/X1.Application/Features/IMSConfiguration/Queries/GetIMS_Configurations/GetIMS_ConfigurationsQuery.cs

@ -18,7 +18,7 @@ public class GetIMS_ConfigurationsQuery : IRequest<OperationResult<GetIMS_Config
/// <summary>
/// 每页数量
/// </summary>
[Range(1, 100, ErrorMessage = "每页数量必须在1-100之间")]
[Range(1, 1000, ErrorMessage = "每页数量必须在1-1000之间")]
public int PageSize { get; set; } = 10;
/// <summary>

2
src/X1.Application/Features/ProtocolVersions/Queries/GetProtocolVersions/GetProtocolVersionsQuery.cs

@ -18,7 +18,7 @@ public class GetProtocolVersionsQuery : IRequest<OperationResult<GetProtocolVers
/// <summary>
/// 每页数量
/// </summary>
[Range(1, 100, ErrorMessage = "每页数量必须在1-100之间")]
[Range(1, 1000, ErrorMessage = "每页数量必须在1-1000之间")]
public int PageSize { get; set; } = 10;
/// <summary>

2
src/X1.Application/Features/RANConfiguration/Queries/GetRAN_Configurations/GetRAN_ConfigurationsQuery.cs

@ -18,7 +18,7 @@ public class GetRAN_ConfigurationsQuery : IRequest<OperationResult<GetRAN_Config
/// <summary>
/// 每页数量
/// </summary>
[Range(1, 100, ErrorMessage = "每页数量必须在1-100之间")]
[Range(1, 1000, ErrorMessage = "每页数量必须在1-1000之间")]
public int PageSize { get; set; } = 10;
/// <summary>

4
src/X1.WebAPI/Properties/launchSettings.json

@ -24,8 +24,8 @@
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
//"applicationUrl": "https://localhost:7268;http://localhost:5000;https://192.168.2.142:7268;http://192.168.2.142:5000",
"applicationUrl": "https://localhost:7268;http://localhost:5000",
"applicationUrl": "https://localhost:7268;http://localhost:5000;https://192.168.2.142:7268;http://192.168.2.142:5000",
//"applicationUrl": "https://localhost:7268;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}

4
src/X1.WebAPI/X1.WebAPI.csproj

@ -40,4 +40,8 @@
</None>
</ItemGroup>
<ItemGroup>
<Folder Include="logs\" />
</ItemGroup>
</Project>

46
src/X1.WebAPI/logs/app-20250726.log

@ -1,46 +0,0 @@
2025-07-26 15:51:24.801 +08:00 [INF] DESKTOP-1Q3GI6C [1] 数据库配置验证通过
2025-07-26 15:51:24.856 +08:00 [INF] DESKTOP-1Q3GI6C [1] JWT配置验证通过
2025-07-26 15:51:24.858 +08:00 [INF] DESKTOP-1Q3GI6C [1] 邮件配置验证通过
2025-07-26 15:51:28.157 +08:00 [INF] DESKTOP-1Q3GI6C [1] 初始化 WebSocket 连接管理器
2025-07-26 15:51:28.209 +08:00 [INF] DESKTOP-1Q3GI6C [1] 创建消息队列完成,入站队列大小:10000,出站队列大小:10000
2025-07-26 15:51:28.450 +08:00 [INF] DESKTOP-1Q3GI6C [1] 生成新密钥成功,密钥长度: 88
2025-07-26 15:51:28.455 +08:00 [INF] DESKTOP-1Q3GI6C [1] 密钥Base64验证通过,字节长度: 64
2025-07-26 15:51:28.459 +08:00 [INF] DESKTOP-1Q3GI6C [1] 密钥熵值: 5.31705292530797
2025-07-26 15:51:28.467 +08:00 [INF] DESKTOP-1Q3GI6C [1] 初始化连接管理协调器,最大并发处理数:100
2025-07-26 15:51:28.474 +08:00 [INF] DESKTOP-1Q3GI6C [1] 初始化 WebSocket 消息服务
2025-07-26 15:51:28.479 +08:00 [INF] DESKTOP-1Q3GI6C [1] 注册消息处理器,消息类型:chat
2025-07-26 15:51:28.483 +08:00 [DBG] DESKTOP-1Q3GI6C [7] 处理器健康检查通过,处理器:ChatMessageHandler
2025-07-26 15:51:28.484 +08:00 [INF] DESKTOP-1Q3GI6C [1] 注册处理器,消息类型:chat,处理器:ChatMessageHandler,池大小:1
2025-07-26 15:51:28.491 +08:00 [DBG] DESKTOP-1Q3GI6C [1] 处理器注册完成,当前处理器数量:1
2025-07-26 15:51:28.493 +08:00 [INF] DESKTOP-1Q3GI6C [1] 注册消息处理器,消息类型:heartbeat
2025-07-26 15:51:28.494 +08:00 [INF] DESKTOP-1Q3GI6C [1] 注册处理器,消息类型:heartbeat,处理器:HeartbeatHandlerManager,池大小:1
2025-07-26 15:51:28.494 +08:00 [DBG] DESKTOP-1Q3GI6C [7] 处理器健康检查通过,处理器:HeartbeatHandlerManager
2025-07-26 15:51:28.497 +08:00 [DBG] DESKTOP-1Q3GI6C [1] 处理器注册完成,当前处理器数量:1
2025-07-26 15:51:28.501 +08:00 [INF] DESKTOP-1Q3GI6C [1] 注册消息处理器,消息类型:notification
2025-07-26 15:51:28.502 +08:00 [INF] DESKTOP-1Q3GI6C [1] 注册处理器,消息类型:notification,处理器:NotificationMessageHandler,池大小:1
2025-07-26 15:51:28.503 +08:00 [DBG] DESKTOP-1Q3GI6C [7] 处理器健康检查通过,处理器:NotificationMessageHandler
2025-07-26 15:51:28.508 +08:00 [DBG] DESKTOP-1Q3GI6C [1] 处理器注册完成,当前处理器数量:1
2025-07-26 15:51:28.515 +08:00 [INF] DESKTOP-1Q3GI6C [1] 注册消息处理器,消息类型:Protocol
2025-07-26 15:51:28.516 +08:00 [DBG] DESKTOP-1Q3GI6C [7] 处理器健康检查通过,处理器:ProtocolMessageHandler
2025-07-26 15:51:28.516 +08:00 [INF] DESKTOP-1Q3GI6C [1] 注册处理器,消息类型:Protocol,处理器:ProtocolMessageHandler,池大小:1
2025-07-26 15:51:28.518 +08:00 [DBG] DESKTOP-1Q3GI6C [1] 处理器注册完成,当前处理器数量:1
2025-07-26 15:51:28.522 +08:00 [INF] DESKTOP-1Q3GI6C [1] 初始化管道构建器,输入类型:WebSocketMessage,输出类型:WebSocketMessage
2025-07-26 15:51:28.523 +08:00 [INF] DESKTOP-1Q3GI6C [1] 添加处理步骤,步骤类型:MessageValidationStep
2025-07-26 15:51:28.525 +08:00 [INF] DESKTOP-1Q3GI6C [1] 初始化消息路由步骤,默认超时时间:"00:00:30",最大重试次数:3
2025-07-26 15:51:28.528 +08:00 [INF] DESKTOP-1Q3GI6C [1] 添加处理步骤,步骤类型:MessageRoutingStep
2025-07-26 15:51:28.532 +08:00 [INF] DESKTOP-1Q3GI6C [1] 开始构建处理管道,步骤数量:2
2025-07-26 15:51:28.533 +08:00 [DBG] DESKTOP-1Q3GI6C [1] 连接处理步骤:MessageValidationStep -> MessageRoutingStep
2025-07-26 15:51:28.535 +08:00 [DBG] DESKTOP-1Q3GI6C [1] 创建链式处理步骤,第一步:MessageValidationStep,第二步:MessageRoutingStep
2025-07-26 15:51:28.537 +08:00 [INF] DESKTOP-1Q3GI6C [1] 处理管道构建完成,总步骤数:2
2025-07-26 15:51:28.539 +08:00 [INF] DESKTOP-1Q3GI6C [1] 初始化入站消息处理器,最大并发处理数:10
2025-07-26 15:51:28.542 +08:00 [INF] DESKTOP-1Q3GI6C [1] WebSocket 消息服务初始化完成
2025-07-26 15:51:28.554 +08:00 [INF] DESKTOP-1Q3GI6C [1] 初始化连接健康检查服务,检查间隔:30秒,超时时间:120秒
2025-07-26 15:51:28.585 +08:00 [INF] DESKTOP-1Q3GI6C [1] 密钥Base64验证通过,字节长度: 64
2025-07-26 15:51:28.589 +08:00 [INF] DESKTOP-1Q3GI6C [1] 密钥熵值: 5.389670647189372
2025-07-26 15:51:28.592 +08:00 [INF] DESKTOP-1Q3GI6C [1] 密钥轮换服务初始化完成
2025-07-26 15:51:28.599 +08:00 [INF] DESKTOP-1Q3GI6C [1] WebSocket 消息服务开始运行
2025-07-26 15:51:28.602 +08:00 [INF] DESKTOP-1Q3GI6C [1] 入站消息处理服务开始运行
2025-07-26 15:51:28.611 +08:00 [DBG] DESKTOP-1Q3GI6C [1] 开始读取出站消息
2025-07-26 15:51:28.617 +08:00 [INF] DESKTOP-1Q3GI6C [1] 连接健康检查服务开始运行
2025-07-26 15:51:28.621 +08:00 [DBG] DESKTOP-1Q3GI6C [1] 获取所有连接,当前连接数:0
2025-07-26 15:51:28.624 +08:00 [INF] DESKTOP-1Q3GI6C [1] 连接健康检查完成,检查连接数:0,清理连接数:0

604
src/X1.WebAPI/logs/app-20250727.log

@ -1,604 +0,0 @@
2025-07-27 15:50:01.121 +08:00 [INF] DESKTOP-1Q3GI6C [1] 数据库配置验证通过
2025-07-27 15:50:01.147 +08:00 [INF] DESKTOP-1Q3GI6C [1] JWT配置验证通过
2025-07-27 15:50:01.149 +08:00 [INF] DESKTOP-1Q3GI6C [1] 邮件配置验证通过
2025-07-27 15:50:03.702 +08:00 [INF] DESKTOP-1Q3GI6C [1] 初始化 WebSocket 连接管理器
2025-07-27 15:50:03.736 +08:00 [INF] DESKTOP-1Q3GI6C [1] 创建消息队列完成,入站队列大小:10000,出站队列大小:10000
2025-07-27 15:50:03.928 +08:00 [INF] DESKTOP-1Q3GI6C [1] 生成新密钥成功,密钥长度: 88
2025-07-27 15:50:03.931 +08:00 [INF] DESKTOP-1Q3GI6C [1] 密钥Base64验证通过,字节长度: 64
2025-07-27 15:50:03.934 +08:00 [INF] DESKTOP-1Q3GI6C [1] 密钥熵值: 5.447845823084413
2025-07-27 15:50:03.941 +08:00 [INF] DESKTOP-1Q3GI6C [1] 初始化连接管理协调器,最大并发处理数:100
2025-07-27 15:50:03.943 +08:00 [INF] DESKTOP-1Q3GI6C [1] 初始化 WebSocket 消息服务
2025-07-27 15:50:03.949 +08:00 [INF] DESKTOP-1Q3GI6C [1] 注册消息处理器,消息类型:chat
2025-07-27 15:50:03.952 +08:00 [DBG] DESKTOP-1Q3GI6C [11] 处理器健康检查通过,处理器:ChatMessageHandler
2025-07-27 15:50:03.953 +08:00 [INF] DESKTOP-1Q3GI6C [1] 注册处理器,消息类型:chat,处理器:ChatMessageHandler,池大小:1
2025-07-27 15:50:03.956 +08:00 [DBG] DESKTOP-1Q3GI6C [1] 处理器注册完成,当前处理器数量:1
2025-07-27 15:50:03.957 +08:00 [INF] DESKTOP-1Q3GI6C [1] 注册消息处理器,消息类型:heartbeat
2025-07-27 15:50:03.959 +08:00 [DBG] DESKTOP-1Q3GI6C [11] 处理器健康检查通过,处理器:HeartbeatHandlerManager
2025-07-27 15:50:03.959 +08:00 [INF] DESKTOP-1Q3GI6C [1] 注册处理器,消息类型:heartbeat,处理器:HeartbeatHandlerManager,池大小:1
2025-07-27 15:50:03.961 +08:00 [DBG] DESKTOP-1Q3GI6C [1] 处理器注册完成,当前处理器数量:1
2025-07-27 15:50:03.962 +08:00 [INF] DESKTOP-1Q3GI6C [1] 注册消息处理器,消息类型:notification
2025-07-27 15:50:03.964 +08:00 [INF] DESKTOP-1Q3GI6C [1] 注册处理器,消息类型:notification,处理器:NotificationMessageHandler,池大小:1
2025-07-27 15:50:03.964 +08:00 [DBG] DESKTOP-1Q3GI6C [11] 处理器健康检查通过,处理器:NotificationMessageHandler
2025-07-27 15:50:03.966 +08:00 [DBG] DESKTOP-1Q3GI6C [1] 处理器注册完成,当前处理器数量:1
2025-07-27 15:50:03.968 +08:00 [INF] DESKTOP-1Q3GI6C [1] 注册消息处理器,消息类型:Protocol
2025-07-27 15:50:03.969 +08:00 [INF] DESKTOP-1Q3GI6C [1] 注册处理器,消息类型:Protocol,处理器:ProtocolMessageHandler,池大小:1
2025-07-27 15:50:03.969 +08:00 [DBG] DESKTOP-1Q3GI6C [11] 处理器健康检查通过,处理器:ProtocolMessageHandler
2025-07-27 15:50:03.971 +08:00 [DBG] DESKTOP-1Q3GI6C [1] 处理器注册完成,当前处理器数量:1
2025-07-27 15:50:03.975 +08:00 [INF] DESKTOP-1Q3GI6C [1] 初始化管道构建器,输入类型:WebSocketMessage,输出类型:WebSocketMessage
2025-07-27 15:50:03.977 +08:00 [INF] DESKTOP-1Q3GI6C [1] 添加处理步骤,步骤类型:MessageValidationStep
2025-07-27 15:50:03.980 +08:00 [INF] DESKTOP-1Q3GI6C [1] 初始化消息路由步骤,默认超时时间:"00:00:30",最大重试次数:3
2025-07-27 15:50:03.983 +08:00 [INF] DESKTOP-1Q3GI6C [1] 添加处理步骤,步骤类型:MessageRoutingStep
2025-07-27 15:50:03.985 +08:00 [INF] DESKTOP-1Q3GI6C [1] 开始构建处理管道,步骤数量:2
2025-07-27 15:50:03.986 +08:00 [DBG] DESKTOP-1Q3GI6C [1] 连接处理步骤:MessageValidationStep -> MessageRoutingStep
2025-07-27 15:50:03.988 +08:00 [DBG] DESKTOP-1Q3GI6C [1] 创建链式处理步骤,第一步:MessageValidationStep,第二步:MessageRoutingStep
2025-07-27 15:50:03.990 +08:00 [INF] DESKTOP-1Q3GI6C [1] 处理管道构建完成,总步骤数:2
2025-07-27 15:50:03.991 +08:00 [INF] DESKTOP-1Q3GI6C [1] 初始化入站消息处理器,最大并发处理数:10
2025-07-27 15:50:03.992 +08:00 [INF] DESKTOP-1Q3GI6C [1] WebSocket 消息服务初始化完成
2025-07-27 15:50:03.995 +08:00 [INF] DESKTOP-1Q3GI6C [1] 初始化连接健康检查服务,检查间隔:30秒,超时时间:120秒
2025-07-27 15:50:04.023 +08:00 [INF] DESKTOP-1Q3GI6C [1] 密钥Base64验证通过,字节长度: 64
2025-07-27 15:50:04.024 +08:00 [INF] DESKTOP-1Q3GI6C [1] 密钥熵值: 5.389670647189372
2025-07-27 15:50:04.026 +08:00 [INF] DESKTOP-1Q3GI6C [1] 密钥轮换服务初始化完成
2025-07-27 15:50:04.030 +08:00 [INF] DESKTOP-1Q3GI6C [1] WebSocket 消息服务开始运行
2025-07-27 15:50:04.033 +08:00 [INF] DESKTOP-1Q3GI6C [1] 入站消息处理服务开始运行
2025-07-27 15:50:04.039 +08:00 [DBG] DESKTOP-1Q3GI6C [1] 开始读取出站消息
2025-07-27 15:50:04.042 +08:00 [INF] DESKTOP-1Q3GI6C [1] 连接健康检查服务开始运行
2025-07-27 15:50:04.045 +08:00 [DBG] DESKTOP-1Q3GI6C [1] 获取所有连接,当前连接数:0
2025-07-27 15:50:04.046 +08:00 [INF] DESKTOP-1Q3GI6C [1] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 07:50:04
2025-07-27 15:50:34.058 +08:00 [DBG] DESKTOP-1Q3GI6C [10] 获取所有连接,当前连接数:0
2025-07-27 15:50:34.060 +08:00 [INF] DESKTOP-1Q3GI6C [10] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 07:50:34
2025-07-27 15:51:03.952 +08:00 [DBG] DESKTOP-1Q3GI6C [10] 处理器健康检查通过,处理器:ChatMessageHandler
2025-07-27 15:51:03.973 +08:00 [DBG] DESKTOP-1Q3GI6C [10] 处理器健康检查通过,处理器:HeartbeatHandlerManager
2025-07-27 15:51:03.974 +08:00 [DBG] DESKTOP-1Q3GI6C [16] 处理器健康检查通过,处理器:ProtocolMessageHandler
2025-07-27 15:51:03.973 +08:00 [DBG] DESKTOP-1Q3GI6C [17] 处理器健康检查通过,处理器:NotificationMessageHandler
2025-07-27 15:51:04.075 +08:00 [DBG] DESKTOP-1Q3GI6C [17] 获取所有连接,当前连接数:0
2025-07-27 15:51:04.076 +08:00 [INF] DESKTOP-1Q3GI6C [17] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 07:51:04
2025-07-27 15:51:29.932 +08:00 [INF] DESKTOP-1Q3GI6C [21] Failed to validate the token.
Microsoft.IdentityModel.Tokens.SecurityTokenExpiredException: IDX10223: Lifetime validation failed. The token is expired. ValidTo (UTC): '07/09/2025 14:03:11', Current time (UTC): '07/27/2025 07:51:29'.
at Microsoft.IdentityModel.Tokens.Validators.ValidateLifetime(Nullable`1 notBefore, Nullable`1 expires, SecurityToken securityToken, TokenValidationParameters validationParameters)
at Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.ValidateTokenPayloadAsync(JsonWebToken jsonWebToken, TokenValidationParameters validationParameters, BaseConfiguration configuration)
at Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.ValidateJWSAsync(JsonWebToken jsonWebToken, TokenValidationParameters validationParameters, BaseConfiguration configuration)
2025-07-27 15:51:29.932 +08:00 [INF] DESKTOP-1Q3GI6C [19] Failed to validate the token.
Microsoft.IdentityModel.Tokens.SecurityTokenExpiredException: IDX10223: Lifetime validation failed. The token is expired. ValidTo (UTC): '07/09/2025 14:03:11', Current time (UTC): '07/27/2025 07:51:29'.
at Microsoft.IdentityModel.Tokens.Validators.ValidateLifetime(Nullable`1 notBefore, Nullable`1 expires, SecurityToken securityToken, TokenValidationParameters validationParameters)
at Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.ValidateTokenPayloadAsync(JsonWebToken jsonWebToken, TokenValidationParameters validationParameters, BaseConfiguration configuration)
at Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.ValidateJWSAsync(JsonWebToken jsonWebToken, TokenValidationParameters validationParameters, BaseConfiguration configuration)
2025-07-27 15:51:29.955 +08:00 [INF] DESKTOP-1Q3GI6C [21] Bearer was not authenticated. Failure message: IDX10223: Lifetime validation failed. The token is expired. ValidTo (UTC): '07/09/2025 14:03:11', Current time (UTC): '07/27/2025 07:51:29'.
2025-07-27 15:51:29.956 +08:00 [INF] DESKTOP-1Q3GI6C [19] Bearer was not authenticated. Failure message: IDX10223: Lifetime validation failed. The token is expired. ValidTo (UTC): '07/09/2025 14:03:11', Current time (UTC): '07/27/2025 07:51:29'.
2025-07-27 15:51:30.808 +08:00 [WRN] DESKTOP-1Q3GI6C [21] The entity type 'IdentityUserLogin' was first mapped explicitly and then ignored. Consider not mapping the entity type in the first place.
2025-07-27 15:51:30.814 +08:00 [WRN] DESKTOP-1Q3GI6C [21] The entity type 'IdentityRoleClaim' was first mapped explicitly and then ignored. Consider not mapping the entity type in the first place.
2025-07-27 15:51:30.815 +08:00 [WRN] DESKTOP-1Q3GI6C [21] The entity type 'IdentityUserClaim' was first mapped explicitly and then ignored. Consider not mapping the entity type in the first place.
2025-07-27 15:51:30.816 +08:00 [WRN] DESKTOP-1Q3GI6C [21] The entity type 'IdentityUserToken' was first mapped explicitly and then ignored. Consider not mapping the entity type in the first place.
2025-07-27 15:51:30.817 +08:00 [WRN] DESKTOP-1Q3GI6C [21] The entity type 'IdentityUserRole' was first mapped explicitly and then ignored. Consider not mapping the entity type in the first place.
2025-07-27 15:51:30.880 +08:00 [WRN] DESKTOP-1Q3GI6C [21] Entity 'AppUser' has a global query filter defined and is the required end of a relationship with the entity 'UserRole'. This may lead to unexpected results when the required entity is filtered out. Either configure the navigation as optional, or define matching query filters for both entities in the navigation. See https://go.microsoft.com/fwlink/?linkid=2131316 for more information.
2025-07-27 15:51:30.892 +08:00 [WRN] DESKTOP-1Q3GI6C [21] Sensitive data logging is enabled. Log entries and exception messages may include sensitive application data; this mode should only be enabled during development.
2025-07-27 15:51:31.002 +08:00 [INF] DESKTOP-1Q3GI6C [19] 开始处理刷新令牌请求
2025-07-27 15:51:31.002 +08:00 [INF] DESKTOP-1Q3GI6C [21] 开始处理刷新令牌请求
2025-07-27 15:51:31.005 +08:00 [INF] DESKTOP-1Q3GI6C [21] 开始验证令牌: eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJuYW1laWQiOiJmNGJmOGNkZC0xYWI2LTQwMzItOTgzNy04OTAxYjI5N2Q5NTciLCJ1bmlxdWVfbmFtZSI6Imh5aCIsImVtYWlsIjoiMjk1MTcyNTUxQHFxLmNvbSIsIkxhc3RMb2dpblRpbWUiOiIyMDI1LTA3LTA5VDEzOjQ4OjEwLjg3NzU2NThaIiwicm9sZSI6IjMxNWExNWI0LTlmZjUtNGQ4OS1hMDJjLTJjYWFlZjdmYjY1MyIsInRva2VuX3R5cGUiOiJyZWZyZXNoX3Rva2VuIiwibmJmIjoxNzUyMDY4ODkxLCJleHAiOjE3NTI2NzM2OTEsImlhdCI6MTc1MjA2ODg5MSwiaXNzIjoiWDEiLCJhdWQiOiJYMS5XZWJBUEkifQ.0hYJmZOMlZVAW_g5WvbbtuiMrJtXg7MTlRycgkI-mr9aCY36a1-JMm2Gdfv814XyqD1cG6I4MKl8p9gl3HG87A
2025-07-27 15:51:31.005 +08:00 [INF] DESKTOP-1Q3GI6C [19] 开始验证令牌: eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJuYW1laWQiOiJmNGJmOGNkZC0xYWI2LTQwMzItOTgzNy04OTAxYjI5N2Q5NTciLCJ1bmlxdWVfbmFtZSI6Imh5aCIsImVtYWlsIjoiMjk1MTcyNTUxQHFxLmNvbSIsIkxhc3RMb2dpblRpbWUiOiIyMDI1LTA3LTA5VDEzOjQ4OjEwLjg3NzU2NThaIiwicm9sZSI6IjMxNWExNWI0LTlmZjUtNGQ4OS1hMDJjLTJjYWFlZjdmYjY1MyIsInRva2VuX3R5cGUiOiJyZWZyZXNoX3Rva2VuIiwibmJmIjoxNzUyMDY4ODkxLCJleHAiOjE3NTI2NzM2OTEsImlhdCI6MTc1MjA2ODg5MSwiaXNzIjoiWDEiLCJhdWQiOiJYMS5XZWJBUEkifQ.0hYJmZOMlZVAW_g5WvbbtuiMrJtXg7MTlRycgkI-mr9aCY36a1-JMm2Gdfv814XyqD1cG6I4MKl8p9gl3HG87A
2025-07-27 15:51:31.007 +08:00 [INF] DESKTOP-1Q3GI6C [21] 尝试从缓存获取密钥,缓存键: JwtKey_Current
2025-07-27 15:51:31.007 +08:00 [INF] DESKTOP-1Q3GI6C [19] 尝试从缓存获取密钥,缓存键: JwtKey_Current
2025-07-27 15:51:31.008 +08:00 [INF] DESKTOP-1Q3GI6C [21] 缓存中未找到密钥,从KeyRotationService获取
2025-07-27 15:51:31.008 +08:00 [INF] DESKTOP-1Q3GI6C [19] 缓存中未找到密钥,从KeyRotationService获取
2025-07-27 15:51:31.009 +08:00 [INF] DESKTOP-1Q3GI6C [21] 获取当前密钥
2025-07-27 15:51:31.012 +08:00 [INF] DESKTOP-1Q3GI6C [21] 密钥Base64验证通过,字节长度: 64
2025-07-27 15:51:31.010 +08:00 [INF] DESKTOP-1Q3GI6C [19] 获取当前密钥
2025-07-27 15:51:31.018 +08:00 [INF] DESKTOP-1Q3GI6C [21] 密钥熵值: 5.389670647189372
2025-07-27 15:51:31.021 +08:00 [INF] DESKTOP-1Q3GI6C [19] 密钥Base64验证通过,字节长度: 64
2025-07-27 15:51:31.023 +08:00 [INF] DESKTOP-1Q3GI6C [21] 当前密钥验证通过,密钥长度: 88
2025-07-27 15:51:31.025 +08:00 [INF] DESKTOP-1Q3GI6C [19] 密钥熵值: 5.389670647189372
2025-07-27 15:51:31.028 +08:00 [INF] DESKTOP-1Q3GI6C [21] 从KeyRotationService获取到密钥,密钥长度: 88
2025-07-27 15:51:31.029 +08:00 [INF] DESKTOP-1Q3GI6C [19] 当前密钥验证通过,密钥长度: 88
2025-07-27 15:51:31.031 +08:00 [INF] DESKTOP-1Q3GI6C [21] 密钥编码成功,字节长度: 88
2025-07-27 15:51:31.032 +08:00 [INF] DESKTOP-1Q3GI6C [19] 从KeyRotationService获取到密钥,密钥长度: 88
2025-07-27 15:51:31.033 +08:00 [INF] DESKTOP-1Q3GI6C [21] 密钥已缓存,过期时间: "2025-07-27T07:56:31.0333700Z"
2025-07-27 15:51:31.033 +08:00 [INF] DESKTOP-1Q3GI6C [19] 密钥编码成功,字节长度: 88
2025-07-27 15:51:31.034 +08:00 [INF] DESKTOP-1Q3GI6C [21] 验证令牌使用的密钥: a1mrtIiQN+AEmxE4WKFmKocGtrs3nrQaEbjzQgKp1XZWq8jP9HqzsjVgMKt3kAaCmTNaI9B9/YoaGMOY0sy8DQ==
2025-07-27 15:51:31.034 +08:00 [INF] DESKTOP-1Q3GI6C [19] 密钥已缓存,过期时间: "2025-07-27T07:56:31.0349335Z"
2025-07-27 15:51:31.036 +08:00 [INF] DESKTOP-1Q3GI6C [19] 验证令牌使用的密钥: a1mrtIiQN+AEmxE4WKFmKocGtrs3nrQaEbjzQgKp1XZWq8jP9HqzsjVgMKt3kAaCmTNaI9B9/YoaGMOY0sy8DQ==
2025-07-27 15:51:31.042 +08:00 [INF] DESKTOP-1Q3GI6C [21] 令牌算法: HS512
2025-07-27 15:51:31.042 +08:00 [INF] DESKTOP-1Q3GI6C [19] 令牌算法: HS512
2025-07-27 15:51:31.043 +08:00 [INF] DESKTOP-1Q3GI6C [21] 密钥解码成功,字节长度: 64
2025-07-27 15:51:31.043 +08:00 [INF] DESKTOP-1Q3GI6C [19] 密钥解码成功,字节长度: 64
2025-07-27 15:51:31.051 +08:00 [INF] DESKTOP-1Q3GI6C [21] 令牌验证参数: {"ValidateIssuer":true,"ValidIssuer":"X1","ValidateAudience":true,"ValidAudience":"X1.WebAPI","ValidateLifetime":true,"ClockSkew":"00:05:00","RequireExpirationTime":true,"RequireSignedTokens":true,"RequireAudience":true,"Algorithm":"HS512","KeyLength":64}
2025-07-27 15:51:31.051 +08:00 [INF] DESKTOP-1Q3GI6C [19] 令牌验证参数: {"ValidateIssuer":true,"ValidIssuer":"X1","ValidateAudience":true,"ValidAudience":"X1.WebAPI","ValidateLifetime":true,"ClockSkew":"00:05:00","RequireExpirationTime":true,"RequireSignedTokens":true,"RequireAudience":true,"Algorithm":"HS512","KeyLength":64}
2025-07-27 15:51:31.156 +08:00 [ERR] DESKTOP-1Q3GI6C [19] 令牌已过期: IDX10223: Lifetime validation failed. The token is expired. ValidTo (UTC): '07/16/2025 13:48:11', Current time (UTC): '07/27/2025 07:51:31'.
Microsoft.IdentityModel.Tokens.SecurityTokenExpiredException: IDX10223: Lifetime validation failed. The token is expired. ValidTo (UTC): '07/16/2025 13:48:11', Current time (UTC): '07/27/2025 07:51:31'.
at Microsoft.IdentityModel.Tokens.Validators.ValidateLifetime(Nullable`1 notBefore, Nullable`1 expires, SecurityToken securityToken, TokenValidationParameters validationParameters)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateLifetime(Nullable`1 notBefore, Nullable`1 expires, JwtSecurityToken jwtToken, TokenValidationParameters validationParameters)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateTokenPayload(JwtSecurityToken jwtToken, TokenValidationParameters validationParameters, BaseConfiguration configuration)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateJWS(String token, TokenValidationParameters validationParameters, BaseConfiguration currentConfiguration, SecurityToken& signatureValidatedToken, ExceptionDispatchInfo& exceptionThrown)
--- End of stack trace from previous location ---
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, JwtSecurityToken outerToken, TokenValidationParameters validationParameters, SecurityToken& signatureValidatedToken)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, TokenValidationParameters validationParameters, SecurityToken& validatedToken)
at CellularManagement.Infrastructure.Services.Authentication.JwtProvider.ValidateToken(String token) in D:\HistoryCode\CellularManagementAPI\CellularManagement\src\X1.Infrastructure\Services\Authentication\JwtProvider.cs:line 151
2025-07-27 15:51:31.156 +08:00 [ERR] DESKTOP-1Q3GI6C [21] 令牌已过期: IDX10223: Lifetime validation failed. The token is expired. ValidTo (UTC): '07/16/2025 13:48:11', Current time (UTC): '07/27/2025 07:51:31'.
Microsoft.IdentityModel.Tokens.SecurityTokenExpiredException: IDX10223: Lifetime validation failed. The token is expired. ValidTo (UTC): '07/16/2025 13:48:11', Current time (UTC): '07/27/2025 07:51:31'.
at Microsoft.IdentityModel.Tokens.Validators.ValidateLifetime(Nullable`1 notBefore, Nullable`1 expires, SecurityToken securityToken, TokenValidationParameters validationParameters)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateLifetime(Nullable`1 notBefore, Nullable`1 expires, JwtSecurityToken jwtToken, TokenValidationParameters validationParameters)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateTokenPayload(JwtSecurityToken jwtToken, TokenValidationParameters validationParameters, BaseConfiguration configuration)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateJWS(String token, TokenValidationParameters validationParameters, BaseConfiguration currentConfiguration, SecurityToken& signatureValidatedToken, ExceptionDispatchInfo& exceptionThrown)
--- End of stack trace from previous location ---
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, JwtSecurityToken outerToken, TokenValidationParameters validationParameters, SecurityToken& signatureValidatedToken)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, TokenValidationParameters validationParameters, SecurityToken& validatedToken)
at CellularManagement.Infrastructure.Services.Authentication.JwtProvider.ValidateToken(String token) in D:\HistoryCode\CellularManagementAPI\CellularManagement\src\X1.Infrastructure\Services\Authentication\JwtProvider.cs:line 151
2025-07-27 15:51:31.165 +08:00 [WRN] DESKTOP-1Q3GI6C [19] 刷新令牌验证失败
2025-07-27 15:51:31.165 +08:00 [WRN] DESKTOP-1Q3GI6C [21] 刷新令牌验证失败
2025-07-27 15:51:31.166 +08:00 [WRN] DESKTOP-1Q3GI6C [19] 令牌刷新失败: 无效的刷新令牌
2025-07-27 15:51:31.166 +08:00 [WRN] DESKTOP-1Q3GI6C [21] 令牌刷新失败: 无效的刷新令牌
2025-07-27 15:51:33.473 +08:00 [INF] DESKTOP-1Q3GI6C [17] Failed to validate the token.
Microsoft.IdentityModel.Tokens.SecurityTokenExpiredException: IDX10223: Lifetime validation failed. The token is expired. ValidTo (UTC): '07/09/2025 14:03:11', Current time (UTC): '07/27/2025 07:51:33'.
at Microsoft.IdentityModel.Tokens.Validators.ValidateLifetime(Nullable`1 notBefore, Nullable`1 expires, SecurityToken securityToken, TokenValidationParameters validationParameters)
at Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.ValidateTokenPayloadAsync(JsonWebToken jsonWebToken, TokenValidationParameters validationParameters, BaseConfiguration configuration)
at Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.ValidateJWSAsync(JsonWebToken jsonWebToken, TokenValidationParameters validationParameters, BaseConfiguration configuration)
2025-07-27 15:51:33.476 +08:00 [INF] DESKTOP-1Q3GI6C [17] Bearer was not authenticated. Failure message: IDX10223: Lifetime validation failed. The token is expired. ValidTo (UTC): '07/09/2025 14:03:11', Current time (UTC): '07/27/2025 07:51:33'.
2025-07-27 15:51:34.086 +08:00 [DBG] DESKTOP-1Q3GI6C [22] 获取所有连接,当前连接数:0
2025-07-27 15:51:34.087 +08:00 [INF] DESKTOP-1Q3GI6C [22] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 07:51:34
2025-07-27 15:51:34.100 +08:00 [INF] DESKTOP-1Q3GI6C [22] Executed DbCommand (62ms) [Parameters=[@__ipAddress_0='::1', @__windowStart_1='2025-07-27T07:21:33.6720416Z' (DbType = DateTime)], CommandType='"Text"', CommandTimeout='30']
SELECT count(*)::int
FROM "LoginLogs" AS l
WHERE l."IpAddress" = @__ipAddress_0 AND NOT (l."IsSuccess") AND l."LoginTime" >= @__windowStart_1
2025-07-27 15:51:34.223 +08:00 [INF] DESKTOP-1Q3GI6C [22] Executed DbCommand (21ms) [Parameters=[@__normalizedUserName_0='HYH'], CommandType='"Text"', CommandTimeout='30']
SELECT u."Id", u."AccessFailedCount", u."ConcurrencyStamp", u."CreatedTime", u."Email", u."EmailConfirmed", u."IsActive", u."IsDeleted", u."LastLoginTime", u."LockoutEnabled", u."LockoutEnd", u."ModifiedTime", u."NormalizedEmail", u."NormalizedUserName", u."PasswordHash", u."PhoneNumber", u."PhoneNumberConfirmed", u."RealName", u."SecurityStamp", u."TwoFactorEnabled", u."UserName"
FROM "Users" AS u
WHERE NOT (u."IsDeleted") AND u."NormalizedUserName" = @__normalizedUserName_0
LIMIT 1
2025-07-27 15:51:34.362 +08:00 [INF] DESKTOP-1Q3GI6C [17] Executed DbCommand (22ms) [Parameters=[@__normalizedUserName_0='HYH'], CommandType='"Text"', CommandTimeout='30']
SELECT u."Id", u."AccessFailedCount", u."ConcurrencyStamp", u."CreatedTime", u."Email", u."EmailConfirmed", u."IsActive", u."IsDeleted", u."LastLoginTime", u."LockoutEnabled", u."LockoutEnd", u."ModifiedTime", u."NormalizedEmail", u."NormalizedUserName", u."PasswordHash", u."PhoneNumber", u."PhoneNumberConfirmed", u."RealName", u."SecurityStamp", u."TwoFactorEnabled", u."UserName"
FROM "Users" AS u
WHERE NOT (u."IsDeleted") AND u."NormalizedUserName" = @__normalizedUserName_0
LIMIT 1
2025-07-27 15:51:34.473 +08:00 [INF] DESKTOP-1Q3GI6C [17] Executed DbCommand (18ms) [Parameters=[@p20='f4bf8cdd-1ab6-4032-9837-8901b297d957' (Nullable = false), @p0='0', @p1='91c53a77-9f60-4a53-a5b4-a8af7b11d79e', @p21='5d5626dd-5eea-4849-9288-c0be4790b767', @p2='2025-07-05T18:18:17.2254030Z' (DbType = DateTime), @p3='295172551@qq.com' (Nullable = false), @p4='False', @p5='True', @p6='False', @p7='2025-07-27T07:51:34.3353806Z' (Nullable = true) (DbType = DateTime), @p8='True', @p9=NULL (DbType = DateTime), @p10=NULL (DbType = DateTime), @p11='295172551@QQ.COM', @p12='HYH', @p13='AQAAAAIAAYagAAAAEFAQultUYv7OdZI4JnURtlHK68b60bgxQdQ938fMqqEXcu1f0QcWl4873JKGP0Nc/w==', @p14='18162486289' (Nullable = false), @p15='False', @p16='hongenen', @p17='IRRDDR2ICCZ5M6HA667X2DZMYBOHE7QK', @p18='False', @p19='hyh' (Nullable = false)], CommandType='"Text"', CommandTimeout='30']
UPDATE "Users" SET "AccessFailedCount" = @p0, "ConcurrencyStamp" = @p1, "CreatedTime" = @p2, "Email" = @p3, "EmailConfirmed" = @p4, "IsActive" = @p5, "IsDeleted" = @p6, "LastLoginTime" = @p7, "LockoutEnabled" = @p8, "LockoutEnd" = @p9, "ModifiedTime" = @p10, "NormalizedEmail" = @p11, "NormalizedUserName" = @p12, "PasswordHash" = @p13, "PhoneNumber" = @p14, "PhoneNumberConfirmed" = @p15, "RealName" = @p16, "SecurityStamp" = @p17, "TwoFactorEnabled" = @p18, "UserName" = @p19
WHERE "Id" = @p20 AND "ConcurrencyStamp" = @p21;
2025-07-27 15:51:34.548 +08:00 [INF] DESKTOP-1Q3GI6C [10] Executed DbCommand (17ms) [Parameters=[@__userId_0='f4bf8cdd-1ab6-4032-9837-8901b297d957'], CommandType='"Text"', CommandTimeout='30']
SELECT u."UserId", u."RoleId"
FROM "UserRoles" AS u
WHERE u."UserId" = @__userId_0
2025-07-27 15:51:34.584 +08:00 [INF] DESKTOP-1Q3GI6C [10] Executed DbCommand (17ms) [Parameters=[@__roleId_0='315a15b4-9ff5-4d89-a02c-2caaef7fb653'], CommandType='"Text"', CommandTimeout='30']
SELECT r."RoleId", r."PermissionId", r."CreatedAt"
FROM "RolePermissions" AS r
WHERE r."RoleId" = @__roleId_0
2025-07-27 15:51:34.590 +08:00 [INF] DESKTOP-1Q3GI6C [10] 尝试从缓存获取密钥,缓存键: JwtKey_Current
2025-07-27 15:51:34.591 +08:00 [INF] DESKTOP-1Q3GI6C [10] 从缓存获取到密钥,密钥长度: 88
2025-07-27 15:51:34.592 +08:00 [INF] DESKTOP-1Q3GI6C [10] 生成令牌使用的密钥: a1mrtIiQN+AEmxE4WKFmKocGtrs3nrQaEbjzQgKp1XZWq8jP9HqzsjVgMKt3kAaCmTNaI9B9/YoaGMOY0sy8DQ==
2025-07-27 15:51:34.593 +08:00 [INF] DESKTOP-1Q3GI6C [10] 密钥解码成功,字节长度: 64
2025-07-27 15:51:34.595 +08:00 [INF] DESKTOP-1Q3GI6C [10] 令牌签名算法: HS512
2025-07-27 15:51:34.607 +08:00 [INF] DESKTOP-1Q3GI6C [10] 生成的令牌信息: {"TokenType":"access_token","Expires":"2025-07-27T08:06:34.5971924Z","Issuer":"X1","Audience":"X1.WebAPI","IssuedAt":"2025-07-27T07:51:34.597343Z","NotBefore":"2025-07-27T07:51:34.5973801Z","Algorithm":"HS512","KeyLength":64}
2025-07-27 15:51:34.608 +08:00 [INF] DESKTOP-1Q3GI6C [10] 尝试从缓存获取密钥,缓存键: JwtKey_Current
2025-07-27 15:51:34.610 +08:00 [INF] DESKTOP-1Q3GI6C [10] 从缓存获取到密钥,密钥长度: 88
2025-07-27 15:51:34.611 +08:00 [INF] DESKTOP-1Q3GI6C [10] 生成令牌使用的密钥: a1mrtIiQN+AEmxE4WKFmKocGtrs3nrQaEbjzQgKp1XZWq8jP9HqzsjVgMKt3kAaCmTNaI9B9/YoaGMOY0sy8DQ==
2025-07-27 15:51:34.612 +08:00 [INF] DESKTOP-1Q3GI6C [10] 密钥解码成功,字节长度: 64
2025-07-27 15:51:34.613 +08:00 [INF] DESKTOP-1Q3GI6C [10] 令牌签名算法: HS512
2025-07-27 15:51:34.614 +08:00 [INF] DESKTOP-1Q3GI6C [10] 生成的令牌信息: {"TokenType":"refresh_token","Expires":"2025-08-03T07:51:34.6140086Z","Issuer":"X1","Audience":"X1.WebAPI","IssuedAt":"2025-07-27T07:51:34.614011Z","NotBefore":"2025-07-27T07:51:34.6140111Z","Algorithm":"HS512","KeyLength":64}
2025-07-27 15:51:34.685 +08:00 [INF] DESKTOP-1Q3GI6C [21] Executed DbCommand (21ms) [Parameters=[@p0='0ed101cc-1bc3-4f22-81fd-72e900a9f0c6' (Nullable = false), @p1='Chrome 138.0.0', @p2='2025-07-27T07:51:34.6158493Z' (DbType = DateTime), @p3=NULL, @p4='::1' (Nullable = false), @p5='False', @p6='True', @p7=NULL, @p8='Web' (Nullable = false), @p9='2025-07-27T07:51:34.6158489Z' (DbType = DateTime), @p10='Password' (Nullable = false), @p11='Windows 10', @p12=NULL, @p13=NULL (DbType = DateTime), @p14='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0' (Nullable = false), @p15='f4bf8cdd-1ab6-4032-9837-8901b297d957' (Nullable = false)], CommandType='"Text"', CommandTimeout='30']
INSERT INTO "LoginLogs" ("Id", "Browser", "CreatedAt", "FailureReason", "IpAddress", "IsDeleted", "IsSuccess", "Location", "LoginSource", "LoginTime", "LoginType", "OperatingSystem", "SessionId", "UpdatedAt", "UserAgent", "UserId")
VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11, @p12, @p13, @p14, @p15);
2025-07-27 15:51:34.689 +08:00 [INF] DESKTOP-1Q3GI6C [21] 用户 hyh 认证成功
2025-07-27 15:51:34.691 +08:00 [INF] DESKTOP-1Q3GI6C [21] 账号 hyh 登录成功
2025-07-27 15:51:34.693 +08:00 [WRN] DESKTOP-1Q3GI6C [21] Bearer eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJuYW1laWQiOiJmNGJmOGNkZC0xYWI2LTQwMzItOTgzNy04OTAxYjI5N2Q5NTciLCJ1bmlxdWVfbmFtZSI6Imh5aCIsImVtYWlsIjoiMjk1MTcyNTUxQHFxLmNvbSIsIkxhc3RMb2dpblRpbWUiOiIyMDI1LTA3LTI3VDA3OjUxOjM0LjMzNTM4MDZaIiwicm9sZSI6IjMxNWExNWI0LTlmZjUtNGQ4OS1hMDJjLTJjYWFlZjdmYjY1MyIsInRva2VuX3R5cGUiOiJhY2Nlc3NfdG9rZW4iLCJuYmYiOjE3NTM2MDI2OTQsImV4cCI6MTc1MzYwMzU5NCwiaWF0IjoxNzUzNjAyNjk0LCJpc3MiOiJYMSIsImF1ZCI6IlgxLldlYkFQSSJ9.vM2IyoORFgbs-tEeguQCHmuQVV9mx7epoeY3oO6PUu7NmrHFODVia5AUda_nJkF5QgzHF3fx4a8O9rq8fNqPfA
2025-07-27 15:51:39.407 +08:00 [DBG] DESKTOP-1Q3GI6C [17] Successfully validated the token.
2025-07-27 15:51:39.410 +08:00 [DBG] DESKTOP-1Q3GI6C [17] AuthenticationScheme: Bearer was successfully authenticated.
2025-07-27 15:51:39.415 +08:00 [DBG] DESKTOP-1Q3GI6C [17] Authorization was successful.
2025-07-27 15:51:39.453 +08:00 [INF] DESKTOP-1Q3GI6C [17] Executed DbCommand (18ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30']
SELECT count(*)::int
FROM "Users" AS u
WHERE NOT (u."IsDeleted")
2025-07-27 15:51:39.458 +08:00 [WRN] DESKTOP-1Q3GI6C [17] The query uses a row limiting operator ('Skip'/'Take') without an 'OrderBy' operator. This may lead to unpredictable results. If the 'Distinct' operator is used after 'OrderBy', then make sure to use the 'OrderBy' operator after 'Distinct' as the ordering would otherwise get erased.
2025-07-27 15:51:39.460 +08:00 [WRN] DESKTOP-1Q3GI6C [17] The query uses a row limiting operator ('Skip'/'Take') without an 'OrderBy' operator. This may lead to unpredictable results. If the 'Distinct' operator is used after 'OrderBy', then make sure to use the 'OrderBy' operator after 'Distinct' as the ordering would otherwise get erased.
2025-07-27 15:51:39.483 +08:00 [INF] DESKTOP-1Q3GI6C [17] Executed DbCommand (18ms) [Parameters=[@__p_1='10', @__p_0='0'], CommandType='"Text"', CommandTimeout='30']
SELECT u."Id", u."AccessFailedCount", u."ConcurrencyStamp", u."CreatedTime", u."Email", u."EmailConfirmed", u."IsActive", u."IsDeleted", u."LastLoginTime", u."LockoutEnabled", u."LockoutEnd", u."ModifiedTime", u."NormalizedEmail", u."NormalizedUserName", u."PasswordHash", u."PhoneNumber", u."PhoneNumberConfirmed", u."RealName", u."SecurityStamp", u."TwoFactorEnabled", u."UserName"
FROM "Users" AS u
WHERE NOT (u."IsDeleted")
LIMIT @__p_1 OFFSET @__p_0
2025-07-27 15:51:39.487 +08:00 [INF] DESKTOP-1Q3GI6C [17] 获取用户列表成功,共 1 条记录,当前第 1 页
2025-07-27 15:51:39.495 +08:00 [DBG] DESKTOP-1Q3GI6C [21] Successfully validated the token.
2025-07-27 15:51:39.497 +08:00 [DBG] DESKTOP-1Q3GI6C [21] AuthenticationScheme: Bearer was successfully authenticated.
2025-07-27 15:51:39.499 +08:00 [DBG] DESKTOP-1Q3GI6C [21] Authorization was successful.
2025-07-27 15:51:39.522 +08:00 [INF] DESKTOP-1Q3GI6C [21] Executed DbCommand (17ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30']
SELECT count(*)::int
FROM "Users" AS u
WHERE NOT (u."IsDeleted")
2025-07-27 15:51:39.541 +08:00 [INF] DESKTOP-1Q3GI6C [21] Executed DbCommand (15ms) [Parameters=[@__p_1='10', @__p_0='0'], CommandType='"Text"', CommandTimeout='30']
SELECT u."Id", u."AccessFailedCount", u."ConcurrencyStamp", u."CreatedTime", u."Email", u."EmailConfirmed", u."IsActive", u."IsDeleted", u."LastLoginTime", u."LockoutEnabled", u."LockoutEnd", u."ModifiedTime", u."NormalizedEmail", u."NormalizedUserName", u."PasswordHash", u."PhoneNumber", u."PhoneNumberConfirmed", u."RealName", u."SecurityStamp", u."TwoFactorEnabled", u."UserName"
FROM "Users" AS u
WHERE NOT (u."IsDeleted")
LIMIT @__p_1 OFFSET @__p_0
2025-07-27 15:51:39.543 +08:00 [INF] DESKTOP-1Q3GI6C [21] 获取用户列表成功,共 1 条记录,当前第 1 页
2025-07-27 15:51:44.810 +08:00 [DBG] DESKTOP-1Q3GI6C [20] Successfully validated the token.
2025-07-27 15:51:44.811 +08:00 [DBG] DESKTOP-1Q3GI6C [20] AuthenticationScheme: Bearer was successfully authenticated.
2025-07-27 15:51:44.840 +08:00 [INF] DESKTOP-1Q3GI6C [22] Executed DbCommand (17ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30']
SELECT count(*)::int
FROM "Roles" AS r
2025-07-27 15:51:44.843 +08:00 [WRN] DESKTOP-1Q3GI6C [22] The query uses a row limiting operator ('Skip'/'Take') without an 'OrderBy' operator. This may lead to unpredictable results. If the 'Distinct' operator is used after 'OrderBy', then make sure to use the 'OrderBy' operator after 'Distinct' as the ordering would otherwise get erased.
2025-07-27 15:51:44.845 +08:00 [WRN] DESKTOP-1Q3GI6C [22] The query uses a row limiting operator ('Skip'/'Take') without an 'OrderBy' operator. This may lead to unpredictable results. If the 'Distinct' operator is used after 'OrderBy', then make sure to use the 'OrderBy' operator after 'Distinct' as the ordering would otherwise get erased.
2025-07-27 15:51:44.864 +08:00 [INF] DESKTOP-1Q3GI6C [22] Executed DbCommand (16ms) [Parameters=[@__p_1='10', @__p_0='0'], CommandType='"Text"', CommandTimeout='30']
SELECT r."Id", r."ConcurrencyStamp", r."CreatedAt", r."Description", r."Name", r."NormalizedName", r."UpdatedAt"
FROM "Roles" AS r
LIMIT @__p_1 OFFSET @__p_0
2025-07-27 15:51:44.877 +08:00 [INF] DESKTOP-1Q3GI6C [22] 成功获取所有角色,共 1 个
2025-07-27 15:51:44.879 +08:00 [INF] DESKTOP-1Q3GI6C [22] 获取所有角色成功,共 1 个角色
2025-07-27 15:51:44.885 +08:00 [DBG] DESKTOP-1Q3GI6C [22] Successfully validated the token.
2025-07-27 15:51:44.886 +08:00 [DBG] DESKTOP-1Q3GI6C [22] AuthenticationScheme: Bearer was successfully authenticated.
2025-07-27 15:51:44.905 +08:00 [INF] DESKTOP-1Q3GI6C [22] Executed DbCommand (16ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30']
SELECT count(*)::int
FROM "Roles" AS r
2025-07-27 15:51:44.925 +08:00 [INF] DESKTOP-1Q3GI6C [20] Executed DbCommand (16ms) [Parameters=[@__p_1='10', @__p_0='0'], CommandType='"Text"', CommandTimeout='30']
SELECT r."Id", r."ConcurrencyStamp", r."CreatedAt", r."Description", r."Name", r."NormalizedName", r."UpdatedAt"
FROM "Roles" AS r
LIMIT @__p_1 OFFSET @__p_0
2025-07-27 15:51:44.930 +08:00 [INF] DESKTOP-1Q3GI6C [20] 成功获取所有角色,共 1 个
2025-07-27 15:51:44.932 +08:00 [INF] DESKTOP-1Q3GI6C [20] 获取所有角色成功,共 1 个角色
2025-07-27 15:51:49.133 +08:00 [DBG] DESKTOP-1Q3GI6C [21] Successfully validated the token.
2025-07-27 15:51:49.134 +08:00 [DBG] DESKTOP-1Q3GI6C [21] AuthenticationScheme: Bearer was successfully authenticated.
2025-07-27 15:51:49.138 +08:00 [DBG] DESKTOP-1Q3GI6C [21] Authorization was successful.
2025-07-27 15:51:49.144 +08:00 [INF] DESKTOP-1Q3GI6C [21] 开始获取设备列表,页码: 1, 每页数量: 10, 搜索关键词: null
2025-07-27 15:51:49.150 +08:00 [INF] DESKTOP-1Q3GI6C [21] 开始获取设备列表,页码: 1, 每页数量: 10, 搜索关键词: null
2025-07-27 15:51:49.178 +08:00 [INF] DESKTOP-1Q3GI6C [21] Executed DbCommand (18ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30']
SELECT count(*)::int
FROM "CellularDevices" AS c
2025-07-27 15:51:49.188 +08:00 [WRN] DESKTOP-1Q3GI6C [21] The query uses a row limiting operator ('Skip'/'Take') without an 'OrderBy' operator. This may lead to unpredictable results. If the 'Distinct' operator is used after 'OrderBy', then make sure to use the 'OrderBy' operator after 'Distinct' as the ordering would otherwise get erased.
2025-07-27 15:51:49.189 +08:00 [WRN] DESKTOP-1Q3GI6C [21] The query uses a row limiting operator ('Skip'/'Take') without an 'OrderBy' operator. This may lead to unpredictable results. If the 'Distinct' operator is used after 'OrderBy', then make sure to use the 'OrderBy' operator after 'Distinct' as the ordering would otherwise get erased.
2025-07-27 15:51:49.241 +08:00 [INF] DESKTOP-1Q3GI6C [21] Executed DbCommand (18ms) [Parameters=[@__p_1='10', @__p_0='0'], CommandType='"Text"', CommandTimeout='30']
SELECT t."Id", t."AgentPort", t."CreatedAt", t."CreatedBy", t."Description", t."IpAddress", t."IsDeleted", t."IsEnabled", t."IsRunning", t."Name", t."ProtocolVersionId", t."SerialNumber", t."UpdatedAt", t."UpdatedBy", p."Id", p."CreatedAt", p."CreatedBy", p."Description", p."IsDeleted", p."IsEnabled", p."MinimumSupportedVersion", p."Name", p."ReleaseDate", p."UpdatedAt", p."UpdatedBy", p."Version"
FROM (
SELECT c."Id", c."AgentPort", c."CreatedAt", c."CreatedBy", c."Description", c."IpAddress", c."IsDeleted", c."IsEnabled", c."IsRunning", c."Name", c."ProtocolVersionId", c."SerialNumber", c."UpdatedAt", c."UpdatedBy"
FROM "CellularDevices" AS c
LIMIT @__p_1 OFFSET @__p_0
) AS t
INNER JOIN "ProtocolVersions" AS p ON t."ProtocolVersionId" = p."Id"
2025-07-27 15:51:49.275 +08:00 [INF] DESKTOP-1Q3GI6C [21] 成功获取设备列表,共 3 条记录
2025-07-27 15:51:49.276 +08:00 [INF] DESKTOP-1Q3GI6C [21] 成功获取设备列表,共 3 条记录
2025-07-27 15:51:49.282 +08:00 [DBG] DESKTOP-1Q3GI6C [20] Successfully validated the token.
2025-07-27 15:51:49.283 +08:00 [DBG] DESKTOP-1Q3GI6C [20] AuthenticationScheme: Bearer was successfully authenticated.
2025-07-27 15:51:49.284 +08:00 [DBG] DESKTOP-1Q3GI6C [20] Authorization was successful.
2025-07-27 15:51:49.285 +08:00 [INF] DESKTOP-1Q3GI6C [20] 开始获取设备列表,页码: 1, 每页数量: 10, 搜索关键词: null
2025-07-27 15:51:49.288 +08:00 [INF] DESKTOP-1Q3GI6C [20] 开始获取设备列表,页码: 1, 每页数量: 10, 搜索关键词: null
2025-07-27 15:51:49.306 +08:00 [INF] DESKTOP-1Q3GI6C [10] Executed DbCommand (17ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30']
SELECT count(*)::int
FROM "CellularDevices" AS c
2025-07-27 15:51:49.327 +08:00 [INF] DESKTOP-1Q3GI6C [16] Executed DbCommand (17ms) [Parameters=[@__p_1='10', @__p_0='0'], CommandType='"Text"', CommandTimeout='30']
SELECT t."Id", t."AgentPort", t."CreatedAt", t."CreatedBy", t."Description", t."IpAddress", t."IsDeleted", t."IsEnabled", t."IsRunning", t."Name", t."ProtocolVersionId", t."SerialNumber", t."UpdatedAt", t."UpdatedBy", p."Id", p."CreatedAt", p."CreatedBy", p."Description", p."IsDeleted", p."IsEnabled", p."MinimumSupportedVersion", p."Name", p."ReleaseDate", p."UpdatedAt", p."UpdatedBy", p."Version"
FROM (
SELECT c."Id", c."AgentPort", c."CreatedAt", c."CreatedBy", c."Description", c."IpAddress", c."IsDeleted", c."IsEnabled", c."IsRunning", c."Name", c."ProtocolVersionId", c."SerialNumber", c."UpdatedAt", c."UpdatedBy"
FROM "CellularDevices" AS c
LIMIT @__p_1 OFFSET @__p_0
) AS t
INNER JOIN "ProtocolVersions" AS p ON t."ProtocolVersionId" = p."Id"
2025-07-27 15:51:49.330 +08:00 [INF] DESKTOP-1Q3GI6C [16] 成功获取设备列表,共 3 条记录
2025-07-27 15:51:49.332 +08:00 [INF] DESKTOP-1Q3GI6C [16] 成功获取设备列表,共 3 条记录
2025-07-27 15:52:03.948 +08:00 [DBG] DESKTOP-1Q3GI6C [22] 处理器健康检查通过,处理器:ChatMessageHandler
2025-07-27 15:52:03.963 +08:00 [DBG] DESKTOP-1Q3GI6C [19] 处理器健康检查通过,处理器:NotificationMessageHandler
2025-07-27 15:52:03.963 +08:00 [DBG] DESKTOP-1Q3GI6C [22] 处理器健康检查通过,处理器:HeartbeatHandlerManager
2025-07-27 15:52:03.963 +08:00 [DBG] DESKTOP-1Q3GI6C [21] 处理器健康检查通过,处理器:ProtocolMessageHandler
2025-07-27 15:52:04.090 +08:00 [DBG] DESKTOP-1Q3GI6C [21] 获取所有连接,当前连接数:0
2025-07-27 15:52:04.093 +08:00 [INF] DESKTOP-1Q3GI6C [21] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 07:52:04
2025-07-27 15:52:16.160 +08:00 [DBG] DESKTOP-1Q3GI6C [21] Successfully validated the token.
2025-07-27 15:52:16.161 +08:00 [DBG] DESKTOP-1Q3GI6C [21] AuthenticationScheme: Bearer was successfully authenticated.
2025-07-27 15:52:16.163 +08:00 [DBG] DESKTOP-1Q3GI6C [21] Authorization was successful.
2025-07-27 15:52:16.168 +08:00 [INF] DESKTOP-1Q3GI6C [21] 开始获取协议版本列表,页码: 1, 每页数量: 10, 搜索关键词: null, 是否启用: null
2025-07-27 15:52:16.173 +08:00 [INF] DESKTOP-1Q3GI6C [21] 开始获取协议版本列表,页码: 1, 每页数量: 10, 搜索关键词: null, 是否启用: null
2025-07-27 15:52:16.196 +08:00 [INF] DESKTOP-1Q3GI6C [21] Executed DbCommand (15ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30']
SELECT p."Id", p."CreatedAt", p."CreatedBy", p."Description", p."IsDeleted", p."IsEnabled", p."MinimumSupportedVersion", p."Name", p."ReleaseDate", p."UpdatedAt", p."UpdatedBy", p."Version"
FROM "ProtocolVersions" AS p
2025-07-27 15:52:16.200 +08:00 [INF] DESKTOP-1Q3GI6C [21] 成功获取协议版本列表,共 3 条记录
2025-07-27 15:52:16.201 +08:00 [INF] DESKTOP-1Q3GI6C [21] 成功获取协议版本列表,共 3 条记录
2025-07-27 15:52:16.208 +08:00 [DBG] DESKTOP-1Q3GI6C [16] Successfully validated the token.
2025-07-27 15:52:16.209 +08:00 [DBG] DESKTOP-1Q3GI6C [16] AuthenticationScheme: Bearer was successfully authenticated.
2025-07-27 15:52:16.211 +08:00 [DBG] DESKTOP-1Q3GI6C [16] Authorization was successful.
2025-07-27 15:52:16.212 +08:00 [INF] DESKTOP-1Q3GI6C [16] 开始获取协议版本列表,页码: 1, 每页数量: 10, 搜索关键词: null, 是否启用: null
2025-07-27 15:52:16.215 +08:00 [INF] DESKTOP-1Q3GI6C [16] 开始获取协议版本列表,页码: 1, 每页数量: 10, 搜索关键词: null, 是否启用: null
2025-07-27 15:52:16.232 +08:00 [INF] DESKTOP-1Q3GI6C [17] Executed DbCommand (16ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30']
SELECT p."Id", p."CreatedAt", p."CreatedBy", p."Description", p."IsDeleted", p."IsEnabled", p."MinimumSupportedVersion", p."Name", p."ReleaseDate", p."UpdatedAt", p."UpdatedBy", p."Version"
FROM "ProtocolVersions" AS p
2025-07-27 15:52:16.235 +08:00 [INF] DESKTOP-1Q3GI6C [17] 成功获取协议版本列表,共 3 条记录
2025-07-27 15:52:16.236 +08:00 [INF] DESKTOP-1Q3GI6C [17] 成功获取协议版本列表,共 3 条记录
2025-07-27 15:52:21.319 +08:00 [DBG] DESKTOP-1Q3GI6C [20] Successfully validated the token.
2025-07-27 15:52:21.321 +08:00 [DBG] DESKTOP-1Q3GI6C [20] AuthenticationScheme: Bearer was successfully authenticated.
2025-07-27 15:52:21.333 +08:00 [DBG] DESKTOP-1Q3GI6C [20] Successfully validated the token.
2025-07-27 15:52:21.335 +08:00 [DBG] DESKTOP-1Q3GI6C [20] AuthenticationScheme: Bearer was successfully authenticated.
2025-07-27 15:52:22.338 +08:00 [DBG] DESKTOP-1Q3GI6C [16] Successfully validated the token.
2025-07-27 15:52:22.345 +08:00 [DBG] DESKTOP-1Q3GI6C [16] AuthenticationScheme: Bearer was successfully authenticated.
2025-07-27 15:52:22.348 +08:00 [DBG] DESKTOP-1Q3GI6C [16] Successfully validated the token.
2025-07-27 15:52:22.353 +08:00 [DBG] DESKTOP-1Q3GI6C [16] AuthenticationScheme: Bearer was successfully authenticated.
2025-07-27 15:52:23.354 +08:00 [DBG] DESKTOP-1Q3GI6C [20] Successfully validated the token.
2025-07-27 15:52:23.357 +08:00 [DBG] DESKTOP-1Q3GI6C [20] AuthenticationScheme: Bearer was successfully authenticated.
2025-07-27 15:52:23.361 +08:00 [DBG] DESKTOP-1Q3GI6C [16] Successfully validated the token.
2025-07-27 15:52:23.370 +08:00 [DBG] DESKTOP-1Q3GI6C [16] AuthenticationScheme: Bearer was successfully authenticated.
2025-07-27 15:52:24.362 +08:00 [DBG] DESKTOP-1Q3GI6C [20] Successfully validated the token.
2025-07-27 15:52:24.364 +08:00 [DBG] DESKTOP-1Q3GI6C [20] AuthenticationScheme: Bearer was successfully authenticated.
2025-07-27 15:52:24.379 +08:00 [DBG] DESKTOP-1Q3GI6C [21] Successfully validated the token.
2025-07-27 15:52:24.380 +08:00 [DBG] DESKTOP-1Q3GI6C [21] AuthenticationScheme: Bearer was successfully authenticated.
2025-07-27 15:52:27.106 +08:00 [DBG] DESKTOP-1Q3GI6C [22] Successfully validated the token.
2025-07-27 15:52:27.108 +08:00 [DBG] DESKTOP-1Q3GI6C [22] AuthenticationScheme: Bearer was successfully authenticated.
2025-07-27 15:52:27.110 +08:00 [DBG] DESKTOP-1Q3GI6C [22] Authorization was successful.
2025-07-27 15:52:27.111 +08:00 [INF] DESKTOP-1Q3GI6C [22] 开始获取设备列表,页码: 1, 每页数量: 10, 搜索关键词: null
2025-07-27 15:52:27.116 +08:00 [INF] DESKTOP-1Q3GI6C [22] 开始获取设备列表,页码: 1, 每页数量: 10, 搜索关键词: null
2025-07-27 15:52:27.134 +08:00 [INF] DESKTOP-1Q3GI6C [22] Executed DbCommand (16ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30']
SELECT count(*)::int
FROM "CellularDevices" AS c
2025-07-27 15:52:27.156 +08:00 [INF] DESKTOP-1Q3GI6C [22] Executed DbCommand (18ms) [Parameters=[@__p_1='10', @__p_0='0'], CommandType='"Text"', CommandTimeout='30']
SELECT t."Id", t."AgentPort", t."CreatedAt", t."CreatedBy", t."Description", t."IpAddress", t."IsDeleted", t."IsEnabled", t."IsRunning", t."Name", t."ProtocolVersionId", t."SerialNumber", t."UpdatedAt", t."UpdatedBy", p."Id", p."CreatedAt", p."CreatedBy", p."Description", p."IsDeleted", p."IsEnabled", p."MinimumSupportedVersion", p."Name", p."ReleaseDate", p."UpdatedAt", p."UpdatedBy", p."Version"
FROM (
SELECT c."Id", c."AgentPort", c."CreatedAt", c."CreatedBy", c."Description", c."IpAddress", c."IsDeleted", c."IsEnabled", c."IsRunning", c."Name", c."ProtocolVersionId", c."SerialNumber", c."UpdatedAt", c."UpdatedBy"
FROM "CellularDevices" AS c
LIMIT @__p_1 OFFSET @__p_0
) AS t
INNER JOIN "ProtocolVersions" AS p ON t."ProtocolVersionId" = p."Id"
2025-07-27 15:52:27.159 +08:00 [INF] DESKTOP-1Q3GI6C [22] 成功获取设备列表,共 3 条记录
2025-07-27 15:52:27.161 +08:00 [INF] DESKTOP-1Q3GI6C [22] 成功获取设备列表,共 3 条记录
2025-07-27 15:52:27.164 +08:00 [DBG] DESKTOP-1Q3GI6C [20] Successfully validated the token.
2025-07-27 15:52:27.165 +08:00 [DBG] DESKTOP-1Q3GI6C [20] AuthenticationScheme: Bearer was successfully authenticated.
2025-07-27 15:52:27.166 +08:00 [DBG] DESKTOP-1Q3GI6C [20] Authorization was successful.
2025-07-27 15:52:27.166 +08:00 [INF] DESKTOP-1Q3GI6C [20] 开始获取设备列表,页码: 1, 每页数量: 10, 搜索关键词: null
2025-07-27 15:52:27.168 +08:00 [INF] DESKTOP-1Q3GI6C [20] 开始获取设备列表,页码: 1, 每页数量: 10, 搜索关键词: null
2025-07-27 15:52:27.186 +08:00 [INF] DESKTOP-1Q3GI6C [10] Executed DbCommand (16ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30']
SELECT count(*)::int
FROM "CellularDevices" AS c
2025-07-27 15:52:27.207 +08:00 [INF] DESKTOP-1Q3GI6C [10] Executed DbCommand (18ms) [Parameters=[@__p_1='10', @__p_0='0'], CommandType='"Text"', CommandTimeout='30']
SELECT t."Id", t."AgentPort", t."CreatedAt", t."CreatedBy", t."Description", t."IpAddress", t."IsDeleted", t."IsEnabled", t."IsRunning", t."Name", t."ProtocolVersionId", t."SerialNumber", t."UpdatedAt", t."UpdatedBy", p."Id", p."CreatedAt", p."CreatedBy", p."Description", p."IsDeleted", p."IsEnabled", p."MinimumSupportedVersion", p."Name", p."ReleaseDate", p."UpdatedAt", p."UpdatedBy", p."Version"
FROM (
SELECT c."Id", c."AgentPort", c."CreatedAt", c."CreatedBy", c."Description", c."IpAddress", c."IsDeleted", c."IsEnabled", c."IsRunning", c."Name", c."ProtocolVersionId", c."SerialNumber", c."UpdatedAt", c."UpdatedBy"
FROM "CellularDevices" AS c
LIMIT @__p_1 OFFSET @__p_0
) AS t
INNER JOIN "ProtocolVersions" AS p ON t."ProtocolVersionId" = p."Id"
2025-07-27 15:52:27.211 +08:00 [INF] DESKTOP-1Q3GI6C [10] 成功获取设备列表,共 3 条记录
2025-07-27 15:52:27.212 +08:00 [INF] DESKTOP-1Q3GI6C [10] 成功获取设备列表,共 3 条记录
2025-07-27 15:52:34.097 +08:00 [DBG] DESKTOP-1Q3GI6C [17] 获取所有连接,当前连接数:0
2025-07-27 15:52:34.101 +08:00 [INF] DESKTOP-1Q3GI6C [17] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 07:52:34
2025-07-27 15:52:53.265 +08:00 [DBG] DESKTOP-1Q3GI6C [20] Successfully validated the token.
2025-07-27 15:52:53.267 +08:00 [DBG] DESKTOP-1Q3GI6C [20] AuthenticationScheme: Bearer was successfully authenticated.
2025-07-27 15:52:53.269 +08:00 [DBG] DESKTOP-1Q3GI6C [20] Authorization was successful.
2025-07-27 15:52:53.271 +08:00 [INF] DESKTOP-1Q3GI6C [20] 开始获取协议版本列表,页码: 1, 每页数量: 10, 搜索关键词: null, 是否启用: null
2025-07-27 15:52:53.276 +08:00 [INF] DESKTOP-1Q3GI6C [20] 开始获取协议版本列表,页码: 1, 每页数量: 10, 搜索关键词: null, 是否启用: null
2025-07-27 15:52:53.297 +08:00 [INF] DESKTOP-1Q3GI6C [20] Executed DbCommand (19ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30']
SELECT p."Id", p."CreatedAt", p."CreatedBy", p."Description", p."IsDeleted", p."IsEnabled", p."MinimumSupportedVersion", p."Name", p."ReleaseDate", p."UpdatedAt", p."UpdatedBy", p."Version"
FROM "ProtocolVersions" AS p
2025-07-27 15:52:53.300 +08:00 [INF] DESKTOP-1Q3GI6C [20] 成功获取协议版本列表,共 3 条记录
2025-07-27 15:52:53.301 +08:00 [INF] DESKTOP-1Q3GI6C [20] 成功获取协议版本列表,共 3 条记录
2025-07-27 15:52:53.304 +08:00 [DBG] DESKTOP-1Q3GI6C [10] Successfully validated the token.
2025-07-27 15:52:53.305 +08:00 [DBG] DESKTOP-1Q3GI6C [10] AuthenticationScheme: Bearer was successfully authenticated.
2025-07-27 15:52:53.306 +08:00 [DBG] DESKTOP-1Q3GI6C [10] Authorization was successful.
2025-07-27 15:52:53.307 +08:00 [INF] DESKTOP-1Q3GI6C [10] 开始获取协议版本列表,页码: 1, 每页数量: 10, 搜索关键词: null, 是否启用: null
2025-07-27 15:52:53.310 +08:00 [INF] DESKTOP-1Q3GI6C [10] 开始获取协议版本列表,页码: 1, 每页数量: 10, 搜索关键词: null, 是否启用: null
2025-07-27 15:52:53.328 +08:00 [INF] DESKTOP-1Q3GI6C [16] Executed DbCommand (16ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30']
SELECT p."Id", p."CreatedAt", p."CreatedBy", p."Description", p."IsDeleted", p."IsEnabled", p."MinimumSupportedVersion", p."Name", p."ReleaseDate", p."UpdatedAt", p."UpdatedBy", p."Version"
FROM "ProtocolVersions" AS p
2025-07-27 15:52:53.331 +08:00 [INF] DESKTOP-1Q3GI6C [16] 成功获取协议版本列表,共 3 条记录
2025-07-27 15:52:53.333 +08:00 [INF] DESKTOP-1Q3GI6C [16] 成功获取协议版本列表,共 3 条记录
2025-07-27 15:53:03.947 +08:00 [DBG] DESKTOP-1Q3GI6C [21] 处理器健康检查通过,处理器:ChatMessageHandler
2025-07-27 15:53:03.963 +08:00 [DBG] DESKTOP-1Q3GI6C [21] 处理器健康检查通过,处理器:HeartbeatHandlerManager
2025-07-27 15:53:03.963 +08:00 [DBG] DESKTOP-1Q3GI6C [22] 处理器健康检查通过,处理器:ProtocolMessageHandler
2025-07-27 15:53:03.963 +08:00 [DBG] DESKTOP-1Q3GI6C [20] 处理器健康检查通过,处理器:NotificationMessageHandler
2025-07-27 15:53:04.106 +08:00 [DBG] DESKTOP-1Q3GI6C [20] 获取所有连接,当前连接数:0
2025-07-27 15:53:04.112 +08:00 [INF] DESKTOP-1Q3GI6C [20] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 07:53:04
2025-07-27 15:53:34.121 +08:00 [DBG] DESKTOP-1Q3GI6C [22] 获取所有连接,当前连接数:0
2025-07-27 15:53:34.124 +08:00 [INF] DESKTOP-1Q3GI6C [22] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 07:53:34
2025-07-27 15:54:03.946 +08:00 [DBG] DESKTOP-1Q3GI6C [21] 处理器健康检查通过,处理器:ChatMessageHandler
2025-07-27 15:54:03.967 +08:00 [DBG] DESKTOP-1Q3GI6C [21] 处理器健康检查通过,处理器:HeartbeatHandlerManager
2025-07-27 15:54:03.967 +08:00 [DBG] DESKTOP-1Q3GI6C [22] 处理器健康检查通过,处理器:NotificationMessageHandler
2025-07-27 15:54:03.967 +08:00 [DBG] DESKTOP-1Q3GI6C [20] 处理器健康检查通过,处理器:ProtocolMessageHandler
2025-07-27 15:54:04.126 +08:00 [DBG] DESKTOP-1Q3GI6C [20] 获取所有连接,当前连接数:0
2025-07-27 15:54:04.128 +08:00 [INF] DESKTOP-1Q3GI6C [20] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 07:54:04
2025-07-27 15:54:34.132 +08:00 [DBG] DESKTOP-1Q3GI6C [20] 获取所有连接,当前连接数:0
2025-07-27 15:54:34.137 +08:00 [INF] DESKTOP-1Q3GI6C [20] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 07:54:34
2025-07-27 15:55:03.947 +08:00 [DBG] DESKTOP-1Q3GI6C [21] 处理器健康检查通过,处理器:ChatMessageHandler
2025-07-27 15:55:03.964 +08:00 [DBG] DESKTOP-1Q3GI6C [20] 处理器健康检查通过,处理器:ProtocolMessageHandler
2025-07-27 15:55:03.963 +08:00 [DBG] DESKTOP-1Q3GI6C [3] 处理器健康检查通过,处理器:HeartbeatHandlerManager
2025-07-27 15:55:03.963 +08:00 [DBG] DESKTOP-1Q3GI6C [23] 处理器健康检查通过,处理器:NotificationMessageHandler
2025-07-27 15:55:04.141 +08:00 [DBG] DESKTOP-1Q3GI6C [20] 获取所有连接,当前连接数:0
2025-07-27 15:55:04.144 +08:00 [INF] DESKTOP-1Q3GI6C [20] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 07:55:04
2025-07-27 15:55:34.145 +08:00 [DBG] DESKTOP-1Q3GI6C [24] 获取所有连接,当前连接数:0
2025-07-27 15:55:34.162 +08:00 [INF] DESKTOP-1Q3GI6C [24] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 07:55:34
2025-07-27 15:56:03.955 +08:00 [DBG] DESKTOP-1Q3GI6C [23] 处理器健康检查通过,处理器:ChatMessageHandler
2025-07-27 15:56:03.955 +08:00 [DBG] DESKTOP-1Q3GI6C [3] 处理器健康检查通过,处理器:HeartbeatHandlerManager
2025-07-27 15:56:03.977 +08:00 [DBG] DESKTOP-1Q3GI6C [24] 处理器健康检查通过,处理器:NotificationMessageHandler
2025-07-27 15:56:03.978 +08:00 [DBG] DESKTOP-1Q3GI6C [25] 处理器健康检查通过,处理器:ProtocolMessageHandler
2025-07-27 15:56:04.192 +08:00 [DBG] DESKTOP-1Q3GI6C [24] 获取所有连接,当前连接数:0
2025-07-27 15:56:04.199 +08:00 [INF] DESKTOP-1Q3GI6C [24] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 07:56:04
2025-07-27 15:56:34.192 +08:00 [DBG] DESKTOP-1Q3GI6C [24] 获取所有连接,当前连接数:0
2025-07-27 15:56:34.194 +08:00 [INF] DESKTOP-1Q3GI6C [24] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 07:56:34
2025-07-27 15:57:03.947 +08:00 [DBG] DESKTOP-1Q3GI6C [25] 处理器健康检查通过,处理器:ChatMessageHandler
2025-07-27 15:57:03.964 +08:00 [DBG] DESKTOP-1Q3GI6C [25] 处理器健康检查通过,处理器:HeartbeatHandlerManager
2025-07-27 15:57:03.964 +08:00 [DBG] DESKTOP-1Q3GI6C [23] 处理器健康检查通过,处理器:ProtocolMessageHandler
2025-07-27 15:57:03.964 +08:00 [DBG] DESKTOP-1Q3GI6C [24] 处理器健康检查通过,处理器:NotificationMessageHandler
2025-07-27 15:57:04.206 +08:00 [DBG] DESKTOP-1Q3GI6C [23] 获取所有连接,当前连接数:0
2025-07-27 15:57:04.222 +08:00 [INF] DESKTOP-1Q3GI6C [23] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 07:57:04
2025-07-27 15:57:34.228 +08:00 [DBG] DESKTOP-1Q3GI6C [27] 获取所有连接,当前连接数:0
2025-07-27 15:57:34.233 +08:00 [INF] DESKTOP-1Q3GI6C [27] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 07:57:34
2025-07-27 15:58:03.959 +08:00 [DBG] DESKTOP-1Q3GI6C [25] 处理器健康检查通过,处理器:HeartbeatHandlerManager
2025-07-27 15:58:03.959 +08:00 [DBG] DESKTOP-1Q3GI6C [27] 处理器健康检查通过,处理器:ChatMessageHandler
2025-07-27 15:58:03.966 +08:00 [DBG] DESKTOP-1Q3GI6C [23] 处理器健康检查通过,处理器:NotificationMessageHandler
2025-07-27 15:58:03.966 +08:00 [DBG] DESKTOP-1Q3GI6C [25] 处理器健康检查通过,处理器:ProtocolMessageHandler
2025-07-27 15:58:04.249 +08:00 [DBG] DESKTOP-1Q3GI6C [25] 获取所有连接,当前连接数:0
2025-07-27 15:58:04.250 +08:00 [INF] DESKTOP-1Q3GI6C [25] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 07:58:04
2025-07-27 15:58:34.268 +08:00 [DBG] DESKTOP-1Q3GI6C [23] 获取所有连接,当前连接数:0
2025-07-27 15:58:34.269 +08:00 [INF] DESKTOP-1Q3GI6C [23] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 07:58:34
2025-07-27 15:59:03.945 +08:00 [DBG] DESKTOP-1Q3GI6C [27] 处理器健康检查通过,处理器:ChatMessageHandler
2025-07-27 15:59:03.964 +08:00 [DBG] DESKTOP-1Q3GI6C [27] 处理器健康检查通过,处理器:HeartbeatHandlerManager
2025-07-27 15:59:03.965 +08:00 [DBG] DESKTOP-1Q3GI6C [23] 处理器健康检查通过,处理器:ProtocolMessageHandler
2025-07-27 15:59:03.964 +08:00 [DBG] DESKTOP-1Q3GI6C [28] 处理器健康检查通过,处理器:NotificationMessageHandler
2025-07-27 15:59:04.281 +08:00 [DBG] DESKTOP-1Q3GI6C [28] 获取所有连接,当前连接数:0
2025-07-27 15:59:04.284 +08:00 [INF] DESKTOP-1Q3GI6C [28] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 07:59:04
2025-07-27 15:59:34.291 +08:00 [DBG] DESKTOP-1Q3GI6C [28] 获取所有连接,当前连接数:0
2025-07-27 15:59:34.323 +08:00 [INF] DESKTOP-1Q3GI6C [28] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 07:59:34
2025-07-27 16:00:03.947 +08:00 [DBG] DESKTOP-1Q3GI6C [27] 处理器健康检查通过,处理器:ChatMessageHandler
2025-07-27 16:00:03.963 +08:00 [DBG] DESKTOP-1Q3GI6C [23] 处理器健康检查通过,处理器:NotificationMessageHandler
2025-07-27 16:00:03.963 +08:00 [DBG] DESKTOP-1Q3GI6C [27] 处理器健康检查通过,处理器:HeartbeatHandlerManager
2025-07-27 16:00:03.963 +08:00 [DBG] DESKTOP-1Q3GI6C [28] 处理器健康检查通过,处理器:ProtocolMessageHandler
2025-07-27 16:00:04.363 +08:00 [DBG] DESKTOP-1Q3GI6C [28] 获取所有连接,当前连接数:0
2025-07-27 16:00:04.364 +08:00 [INF] DESKTOP-1Q3GI6C [28] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 08:00:04
2025-07-27 16:00:34.377 +08:00 [DBG] DESKTOP-1Q3GI6C [30] 获取所有连接,当前连接数:0
2025-07-27 16:00:34.378 +08:00 [INF] DESKTOP-1Q3GI6C [30] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 08:00:34
2025-07-27 16:01:03.945 +08:00 [DBG] DESKTOP-1Q3GI6C [27] 处理器健康检查通过,处理器:ChatMessageHandler
2025-07-27 16:01:03.960 +08:00 [DBG] DESKTOP-1Q3GI6C [27] 处理器健康检查通过,处理器:HeartbeatHandlerManager
2025-07-27 16:01:03.975 +08:00 [DBG] DESKTOP-1Q3GI6C [27] 处理器健康检查通过,处理器:NotificationMessageHandler
2025-07-27 16:01:03.975 +08:00 [DBG] DESKTOP-1Q3GI6C [28] 处理器健康检查通过,处理器:ProtocolMessageHandler
2025-07-27 16:01:04.396 +08:00 [DBG] DESKTOP-1Q3GI6C [27] 获取所有连接,当前连接数:0
2025-07-27 16:01:04.401 +08:00 [INF] DESKTOP-1Q3GI6C [27] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 08:01:04
2025-07-27 16:01:34.411 +08:00 [DBG] DESKTOP-1Q3GI6C [30] 获取所有连接,当前连接数:0
2025-07-27 16:01:34.419 +08:00 [INF] DESKTOP-1Q3GI6C [30] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 08:01:34
2025-07-27 16:02:03.946 +08:00 [DBG] DESKTOP-1Q3GI6C [30] 处理器健康检查通过,处理器:ChatMessageHandler
2025-07-27 16:02:03.962 +08:00 [DBG] DESKTOP-1Q3GI6C [31] 处理器健康检查通过,处理器:ProtocolMessageHandler
2025-07-27 16:02:03.962 +08:00 [DBG] DESKTOP-1Q3GI6C [32] 处理器健康检查通过,处理器:NotificationMessageHandler
2025-07-27 16:02:03.962 +08:00 [DBG] DESKTOP-1Q3GI6C [30] 处理器健康检查通过,处理器:HeartbeatHandlerManager
2025-07-27 16:02:04.438 +08:00 [DBG] DESKTOP-1Q3GI6C [30] 获取所有连接,当前连接数:0
2025-07-27 16:02:04.440 +08:00 [INF] DESKTOP-1Q3GI6C [30] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 08:02:04
2025-07-27 16:02:34.448 +08:00 [DBG] DESKTOP-1Q3GI6C [31] 获取所有连接,当前连接数:0
2025-07-27 16:02:34.450 +08:00 [INF] DESKTOP-1Q3GI6C [31] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 08:02:34
2025-07-27 16:03:03.955 +08:00 [DBG] DESKTOP-1Q3GI6C [32] 处理器健康检查通过,处理器:HeartbeatHandlerManager
2025-07-27 16:03:03.963 +08:00 [DBG] DESKTOP-1Q3GI6C [28] 处理器健康检查通过,处理器:NotificationMessageHandler
2025-07-27 16:03:03.955 +08:00 [DBG] DESKTOP-1Q3GI6C [31] 处理器健康检查通过,处理器:ChatMessageHandler
2025-07-27 16:03:03.963 +08:00 [DBG] DESKTOP-1Q3GI6C [33] 处理器健康检查通过,处理器:ProtocolMessageHandler
2025-07-27 16:03:04.455 +08:00 [DBG] DESKTOP-1Q3GI6C [28] 获取所有连接,当前连接数:0
2025-07-27 16:03:04.457 +08:00 [INF] DESKTOP-1Q3GI6C [28] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 08:03:04
2025-07-27 16:03:34.462 +08:00 [DBG] DESKTOP-1Q3GI6C [31] 获取所有连接,当前连接数:0
2025-07-27 16:03:34.463 +08:00 [INF] DESKTOP-1Q3GI6C [31] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 08:03:34
2025-07-27 16:03:58.900 +08:00 [DBG] DESKTOP-1Q3GI6C [36] Successfully validated the token.
2025-07-27 16:03:58.901 +08:00 [DBG] DESKTOP-1Q3GI6C [36] AuthenticationScheme: Bearer was successfully authenticated.
2025-07-27 16:03:58.902 +08:00 [DBG] DESKTOP-1Q3GI6C [36] Authorization was successful.
2025-07-27 16:03:58.903 +08:00 [INF] DESKTOP-1Q3GI6C [36] 开始获取协议版本列表,页码: 1, 每页数量: 10, 搜索关键词: null, 是否启用: null
2025-07-27 16:03:58.906 +08:00 [INF] DESKTOP-1Q3GI6C [36] 开始获取协议版本列表,页码: 1, 每页数量: 10, 搜索关键词: null, 是否启用: null
2025-07-27 16:03:58.979 +08:00 [INF] DESKTOP-1Q3GI6C [33] Executed DbCommand (11ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30']
SELECT p."Id", p."CreatedAt", p."CreatedBy", p."Description", p."IsDeleted", p."IsEnabled", p."MinimumSupportedVersion", p."Name", p."ReleaseDate", p."UpdatedAt", p."UpdatedBy", p."Version"
FROM "ProtocolVersions" AS p
2025-07-27 16:03:58.989 +08:00 [INF] DESKTOP-1Q3GI6C [33] 成功获取协议版本列表,共 0 条记录
2025-07-27 16:03:58.992 +08:00 [INF] DESKTOP-1Q3GI6C [33] 成功获取协议版本列表,共 0 条记录
2025-07-27 16:04:00.258 +08:00 [DBG] DESKTOP-1Q3GI6C [36] Successfully validated the token.
2025-07-27 16:04:00.260 +08:00 [DBG] DESKTOP-1Q3GI6C [36] AuthenticationScheme: Bearer was successfully authenticated.
2025-07-27 16:04:00.262 +08:00 [DBG] DESKTOP-1Q3GI6C [36] Authorization was successful.
2025-07-27 16:04:00.263 +08:00 [INF] DESKTOP-1Q3GI6C [36] 开始获取设备列表,页码: 1, 每页数量: 10, 搜索关键词: null
2025-07-27 16:04:00.264 +08:00 [INF] DESKTOP-1Q3GI6C [36] 开始获取设备列表,页码: 1, 每页数量: 10, 搜索关键词: null
2025-07-27 16:04:00.278 +08:00 [INF] DESKTOP-1Q3GI6C [36] Executed DbCommand (11ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30']
SELECT count(*)::int
FROM "CellularDevices" AS c
2025-07-27 16:04:00.293 +08:00 [INF] DESKTOP-1Q3GI6C [36] Executed DbCommand (12ms) [Parameters=[@__p_1='10', @__p_0='0'], CommandType='"Text"', CommandTimeout='30']
SELECT t."Id", t."AgentPort", t."CreatedAt", t."CreatedBy", t."Description", t."IpAddress", t."IsDeleted", t."IsEnabled", t."IsRunning", t."Name", t."ProtocolVersionId", t."SerialNumber", t."UpdatedAt", t."UpdatedBy", p."Id", p."CreatedAt", p."CreatedBy", p."Description", p."IsDeleted", p."IsEnabled", p."MinimumSupportedVersion", p."Name", p."ReleaseDate", p."UpdatedAt", p."UpdatedBy", p."Version"
FROM (
SELECT c."Id", c."AgentPort", c."CreatedAt", c."CreatedBy", c."Description", c."IpAddress", c."IsDeleted", c."IsEnabled", c."IsRunning", c."Name", c."ProtocolVersionId", c."SerialNumber", c."UpdatedAt", c."UpdatedBy"
FROM "CellularDevices" AS c
LIMIT @__p_1 OFFSET @__p_0
) AS t
INNER JOIN "ProtocolVersions" AS p ON t."ProtocolVersionId" = p."Id"
2025-07-27 16:04:00.295 +08:00 [INF] DESKTOP-1Q3GI6C [36] 成功获取设备列表,共 0 条记录
2025-07-27 16:04:00.296 +08:00 [INF] DESKTOP-1Q3GI6C [36] 成功获取设备列表,共 0 条记录
2025-07-27 16:04:00.299 +08:00 [DBG] DESKTOP-1Q3GI6C [31] Successfully validated the token.
2025-07-27 16:04:00.300 +08:00 [DBG] DESKTOP-1Q3GI6C [31] AuthenticationScheme: Bearer was successfully authenticated.
2025-07-27 16:04:00.302 +08:00 [DBG] DESKTOP-1Q3GI6C [31] Authorization was successful.
2025-07-27 16:04:00.303 +08:00 [INF] DESKTOP-1Q3GI6C [31] 开始获取设备列表,页码: 1, 每页数量: 10, 搜索关键词: null
2025-07-27 16:04:00.304 +08:00 [INF] DESKTOP-1Q3GI6C [31] 开始获取设备列表,页码: 1, 每页数量: 10, 搜索关键词: null
2025-07-27 16:04:00.317 +08:00 [INF] DESKTOP-1Q3GI6C [33] Executed DbCommand (10ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30']
SELECT count(*)::int
FROM "CellularDevices" AS c
2025-07-27 16:04:00.332 +08:00 [INF] DESKTOP-1Q3GI6C [33] Executed DbCommand (12ms) [Parameters=[@__p_1='10', @__p_0='0'], CommandType='"Text"', CommandTimeout='30']
SELECT t."Id", t."AgentPort", t."CreatedAt", t."CreatedBy", t."Description", t."IpAddress", t."IsDeleted", t."IsEnabled", t."IsRunning", t."Name", t."ProtocolVersionId", t."SerialNumber", t."UpdatedAt", t."UpdatedBy", p."Id", p."CreatedAt", p."CreatedBy", p."Description", p."IsDeleted", p."IsEnabled", p."MinimumSupportedVersion", p."Name", p."ReleaseDate", p."UpdatedAt", p."UpdatedBy", p."Version"
FROM (
SELECT c."Id", c."AgentPort", c."CreatedAt", c."CreatedBy", c."Description", c."IpAddress", c."IsDeleted", c."IsEnabled", c."IsRunning", c."Name", c."ProtocolVersionId", c."SerialNumber", c."UpdatedAt", c."UpdatedBy"
FROM "CellularDevices" AS c
LIMIT @__p_1 OFFSET @__p_0
) AS t
INNER JOIN "ProtocolVersions" AS p ON t."ProtocolVersionId" = p."Id"
2025-07-27 16:04:00.334 +08:00 [INF] DESKTOP-1Q3GI6C [33] 成功获取设备列表,共 0 条记录
2025-07-27 16:04:00.335 +08:00 [INF] DESKTOP-1Q3GI6C [33] 成功获取设备列表,共 0 条记录
2025-07-27 16:04:01.336 +08:00 [DBG] DESKTOP-1Q3GI6C [32] Successfully validated the token.
2025-07-27 16:04:01.337 +08:00 [DBG] DESKTOP-1Q3GI6C [32] AuthenticationScheme: Bearer was successfully authenticated.
2025-07-27 16:04:01.338 +08:00 [DBG] DESKTOP-1Q3GI6C [32] Authorization was successful.
2025-07-27 16:04:01.340 +08:00 [INF] DESKTOP-1Q3GI6C [32] 开始获取设备列表,页码: 1, 每页数量: 10, 搜索关键词: null
2025-07-27 16:04:01.342 +08:00 [INF] DESKTOP-1Q3GI6C [32] 开始获取设备列表,页码: 1, 每页数量: 10, 搜索关键词: null
2025-07-27 16:04:01.355 +08:00 [INF] DESKTOP-1Q3GI6C [33] Executed DbCommand (11ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30']
SELECT count(*)::int
FROM "CellularDevices" AS c
2025-07-27 16:04:01.369 +08:00 [INF] DESKTOP-1Q3GI6C [36] Executed DbCommand (11ms) [Parameters=[@__p_1='10', @__p_0='0'], CommandType='"Text"', CommandTimeout='30']
SELECT t."Id", t."AgentPort", t."CreatedAt", t."CreatedBy", t."Description", t."IpAddress", t."IsDeleted", t."IsEnabled", t."IsRunning", t."Name", t."ProtocolVersionId", t."SerialNumber", t."UpdatedAt", t."UpdatedBy", p."Id", p."CreatedAt", p."CreatedBy", p."Description", p."IsDeleted", p."IsEnabled", p."MinimumSupportedVersion", p."Name", p."ReleaseDate", p."UpdatedAt", p."UpdatedBy", p."Version"
FROM (
SELECT c."Id", c."AgentPort", c."CreatedAt", c."CreatedBy", c."Description", c."IpAddress", c."IsDeleted", c."IsEnabled", c."IsRunning", c."Name", c."ProtocolVersionId", c."SerialNumber", c."UpdatedAt", c."UpdatedBy"
FROM "CellularDevices" AS c
LIMIT @__p_1 OFFSET @__p_0
) AS t
INNER JOIN "ProtocolVersions" AS p ON t."ProtocolVersionId" = p."Id"
2025-07-27 16:04:01.372 +08:00 [INF] DESKTOP-1Q3GI6C [36] 成功获取设备列表,共 0 条记录
2025-07-27 16:04:01.374 +08:00 [INF] DESKTOP-1Q3GI6C [36] 成功获取设备列表,共 0 条记录
2025-07-27 16:04:02.597 +08:00 [DBG] DESKTOP-1Q3GI6C [32] Successfully validated the token.
2025-07-27 16:04:02.598 +08:00 [DBG] DESKTOP-1Q3GI6C [32] AuthenticationScheme: Bearer was successfully authenticated.
2025-07-27 16:04:02.602 +08:00 [DBG] DESKTOP-1Q3GI6C [31] Successfully validated the token.
2025-07-27 16:04:02.603 +08:00 [DBG] DESKTOP-1Q3GI6C [31] AuthenticationScheme: Bearer was successfully authenticated.
2025-07-27 16:04:03.610 +08:00 [DBG] DESKTOP-1Q3GI6C [31] Successfully validated the token.
2025-07-27 16:04:03.611 +08:00 [DBG] DESKTOP-1Q3GI6C [31] AuthenticationScheme: Bearer was successfully authenticated.
2025-07-27 16:04:03.614 +08:00 [DBG] DESKTOP-1Q3GI6C [33] Successfully validated the token.
2025-07-27 16:04:03.615 +08:00 [DBG] DESKTOP-1Q3GI6C [33] AuthenticationScheme: Bearer was successfully authenticated.
2025-07-27 16:04:03.947 +08:00 [DBG] DESKTOP-1Q3GI6C [33] 处理器健康检查通过,处理器:ChatMessageHandler
2025-07-27 16:04:03.962 +08:00 [DBG] DESKTOP-1Q3GI6C [33] 处理器健康检查通过,处理器:HeartbeatHandlerManager
2025-07-27 16:04:03.962 +08:00 [DBG] DESKTOP-1Q3GI6C [36] 处理器健康检查通过,处理器:NotificationMessageHandler
2025-07-27 16:04:03.962 +08:00 [DBG] DESKTOP-1Q3GI6C [32] 处理器健康检查通过,处理器:ProtocolMessageHandler
2025-07-27 16:04:04.468 +08:00 [DBG] DESKTOP-1Q3GI6C [36] 获取所有连接,当前连接数:0
2025-07-27 16:04:04.469 +08:00 [INF] DESKTOP-1Q3GI6C [36] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 08:04:04
2025-07-27 16:04:04.617 +08:00 [DBG] DESKTOP-1Q3GI6C [36] Successfully validated the token.
2025-07-27 16:04:04.618 +08:00 [DBG] DESKTOP-1Q3GI6C [36] AuthenticationScheme: Bearer was successfully authenticated.
2025-07-27 16:04:04.622 +08:00 [DBG] DESKTOP-1Q3GI6C [36] Successfully validated the token.
2025-07-27 16:04:04.622 +08:00 [DBG] DESKTOP-1Q3GI6C [36] AuthenticationScheme: Bearer was successfully authenticated.
2025-07-27 16:04:05.626 +08:00 [DBG] DESKTOP-1Q3GI6C [36] Successfully validated the token.
2025-07-27 16:04:05.627 +08:00 [DBG] DESKTOP-1Q3GI6C [36] AuthenticationScheme: Bearer was successfully authenticated.
2025-07-27 16:04:05.630 +08:00 [DBG] DESKTOP-1Q3GI6C [33] Successfully validated the token.
2025-07-27 16:04:05.632 +08:00 [DBG] DESKTOP-1Q3GI6C [33] AuthenticationScheme: Bearer was successfully authenticated.
2025-07-27 16:04:07.738 +08:00 [DBG] DESKTOP-1Q3GI6C [37] Successfully validated the token.
2025-07-27 16:04:07.740 +08:00 [DBG] DESKTOP-1Q3GI6C [37] AuthenticationScheme: Bearer was successfully authenticated.
2025-07-27 16:04:07.741 +08:00 [DBG] DESKTOP-1Q3GI6C [37] Authorization was successful.
2025-07-27 16:04:07.743 +08:00 [INF] DESKTOP-1Q3GI6C [37] 开始获取设备列表,页码: 1, 每页数量: 10, 搜索关键词: null
2025-07-27 16:04:07.745 +08:00 [INF] DESKTOP-1Q3GI6C [37] 开始获取设备列表,页码: 1, 每页数量: 10, 搜索关键词: null
2025-07-27 16:04:07.758 +08:00 [INF] DESKTOP-1Q3GI6C [37] Executed DbCommand (11ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30']
SELECT count(*)::int
FROM "CellularDevices" AS c
2025-07-27 16:04:07.771 +08:00 [INF] DESKTOP-1Q3GI6C [33] Executed DbCommand (11ms) [Parameters=[@__p_1='10', @__p_0='0'], CommandType='"Text"', CommandTimeout='30']
SELECT t."Id", t."AgentPort", t."CreatedAt", t."CreatedBy", t."Description", t."IpAddress", t."IsDeleted", t."IsEnabled", t."IsRunning", t."Name", t."ProtocolVersionId", t."SerialNumber", t."UpdatedAt", t."UpdatedBy", p."Id", p."CreatedAt", p."CreatedBy", p."Description", p."IsDeleted", p."IsEnabled", p."MinimumSupportedVersion", p."Name", p."ReleaseDate", p."UpdatedAt", p."UpdatedBy", p."Version"
FROM (
SELECT c."Id", c."AgentPort", c."CreatedAt", c."CreatedBy", c."Description", c."IpAddress", c."IsDeleted", c."IsEnabled", c."IsRunning", c."Name", c."ProtocolVersionId", c."SerialNumber", c."UpdatedAt", c."UpdatedBy"
FROM "CellularDevices" AS c
LIMIT @__p_1 OFFSET @__p_0
) AS t
INNER JOIN "ProtocolVersions" AS p ON t."ProtocolVersionId" = p."Id"
2025-07-27 16:04:07.774 +08:00 [INF] DESKTOP-1Q3GI6C [33] 成功获取设备列表,共 0 条记录
2025-07-27 16:04:07.775 +08:00 [INF] DESKTOP-1Q3GI6C [33] 成功获取设备列表,共 0 条记录
2025-07-27 16:04:07.778 +08:00 [DBG] DESKTOP-1Q3GI6C [36] Successfully validated the token.
2025-07-27 16:04:07.779 +08:00 [DBG] DESKTOP-1Q3GI6C [36] AuthenticationScheme: Bearer was successfully authenticated.
2025-07-27 16:04:07.780 +08:00 [DBG] DESKTOP-1Q3GI6C [36] Authorization was successful.
2025-07-27 16:04:07.781 +08:00 [INF] DESKTOP-1Q3GI6C [36] 开始获取设备列表,页码: 1, 每页数量: 10, 搜索关键词: null
2025-07-27 16:04:07.783 +08:00 [INF] DESKTOP-1Q3GI6C [36] 开始获取设备列表,页码: 1, 每页数量: 10, 搜索关键词: null
2025-07-27 16:04:07.796 +08:00 [INF] DESKTOP-1Q3GI6C [37] Executed DbCommand (11ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30']
SELECT count(*)::int
FROM "CellularDevices" AS c
2025-07-27 16:04:07.821 +08:00 [INF] DESKTOP-1Q3GI6C [37] Executed DbCommand (22ms) [Parameters=[@__p_1='10', @__p_0='0'], CommandType='"Text"', CommandTimeout='30']
SELECT t."Id", t."AgentPort", t."CreatedAt", t."CreatedBy", t."Description", t."IpAddress", t."IsDeleted", t."IsEnabled", t."IsRunning", t."Name", t."ProtocolVersionId", t."SerialNumber", t."UpdatedAt", t."UpdatedBy", p."Id", p."CreatedAt", p."CreatedBy", p."Description", p."IsDeleted", p."IsEnabled", p."MinimumSupportedVersion", p."Name", p."ReleaseDate", p."UpdatedAt", p."UpdatedBy", p."Version"
FROM (
SELECT c."Id", c."AgentPort", c."CreatedAt", c."CreatedBy", c."Description", c."IpAddress", c."IsDeleted", c."IsEnabled", c."IsRunning", c."Name", c."ProtocolVersionId", c."SerialNumber", c."UpdatedAt", c."UpdatedBy"
FROM "CellularDevices" AS c
LIMIT @__p_1 OFFSET @__p_0
) AS t
INNER JOIN "ProtocolVersions" AS p ON t."ProtocolVersionId" = p."Id"
2025-07-27 16:04:07.824 +08:00 [INF] DESKTOP-1Q3GI6C [37] 成功获取设备列表,共 0 条记录
2025-07-27 16:04:07.825 +08:00 [INF] DESKTOP-1Q3GI6C [37] 成功获取设备列表,共 0 条记录
2025-07-27 16:04:34.481 +08:00 [DBG] DESKTOP-1Q3GI6C [31] 获取所有连接,当前连接数:0
2025-07-27 16:04:34.483 +08:00 [INF] DESKTOP-1Q3GI6C [31] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 08:04:34
2025-07-27 16:05:03.955 +08:00 [DBG] DESKTOP-1Q3GI6C [37] 处理器健康检查通过,处理器:ChatMessageHandler
2025-07-27 16:05:03.955 +08:00 [DBG] DESKTOP-1Q3GI6C [36] 处理器健康检查通过,处理器:HeartbeatHandlerManager
2025-07-27 16:05:03.970 +08:00 [DBG] DESKTOP-1Q3GI6C [36] 处理器健康检查通过,处理器:NotificationMessageHandler
2025-07-27 16:05:03.970 +08:00 [DBG] DESKTOP-1Q3GI6C [37] 处理器健康检查通过,处理器:ProtocolMessageHandler
2025-07-27 16:05:04.486 +08:00 [DBG] DESKTOP-1Q3GI6C [35] 获取所有连接,当前连接数:0
2025-07-27 16:05:04.487 +08:00 [INF] DESKTOP-1Q3GI6C [35] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 08:05:04
2025-07-27 16:05:34.502 +08:00 [DBG] DESKTOP-1Q3GI6C [37] 获取所有连接,当前连接数:0
2025-07-27 16:05:34.505 +08:00 [INF] DESKTOP-1Q3GI6C [37] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 08:05:34
2025-07-27 16:06:03.945 +08:00 [DBG] DESKTOP-1Q3GI6C [37] 处理器健康检查通过,处理器:ChatMessageHandler
2025-07-27 16:06:03.955 +08:00 [DBG] DESKTOP-1Q3GI6C [37] 处理器健康检查通过,处理器:HeartbeatHandlerManager
2025-07-27 16:06:03.963 +08:00 [DBG] DESKTOP-1Q3GI6C [35] 处理器健康检查通过,处理器:ProtocolMessageHandler
2025-07-27 16:06:03.963 +08:00 [DBG] DESKTOP-1Q3GI6C [37] 处理器健康检查通过,处理器:NotificationMessageHandler
2025-07-27 16:06:04.504 +08:00 [DBG] DESKTOP-1Q3GI6C [35] 获取所有连接,当前连接数:0
2025-07-27 16:06:04.506 +08:00 [INF] DESKTOP-1Q3GI6C [35] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 08:06:04
2025-07-27 16:06:34.515 +08:00 [DBG] DESKTOP-1Q3GI6C [31] 获取所有连接,当前连接数:0
2025-07-27 16:06:34.517 +08:00 [INF] DESKTOP-1Q3GI6C [31] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 08:06:34
2025-07-27 16:07:03.958 +08:00 [DBG] DESKTOP-1Q3GI6C [31] 处理器健康检查通过,处理器:HeartbeatHandlerManager
2025-07-27 16:07:03.958 +08:00 [DBG] DESKTOP-1Q3GI6C [40] 处理器健康检查通过,处理器:ChatMessageHandler
2025-07-27 16:07:03.974 +08:00 [DBG] DESKTOP-1Q3GI6C [40] 处理器健康检查通过,处理器:NotificationMessageHandler
2025-07-27 16:07:03.974 +08:00 [DBG] DESKTOP-1Q3GI6C [38] 处理器健康检查通过,处理器:ProtocolMessageHandler
2025-07-27 16:07:04.522 +08:00 [DBG] DESKTOP-1Q3GI6C [40] 获取所有连接,当前连接数:0
2025-07-27 16:07:04.524 +08:00 [INF] DESKTOP-1Q3GI6C [40] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 08:07:04
2025-07-27 16:07:34.533 +08:00 [DBG] DESKTOP-1Q3GI6C [31] 获取所有连接,当前连接数:0
2025-07-27 16:07:34.536 +08:00 [INF] DESKTOP-1Q3GI6C [31] 连接健康检查完成,检查连接数:0,清理连接数:0,检查时间:2025-07-27 08:07:34

6375
src/X1.WebAPI/logs/app-20250729.log

File diff suppressed because it is too large

20
src/X1.WebAPI/logs/error-20250727.log

@ -1,20 +0,0 @@
2025-07-27 15:51:31.156 +08:00 [ERR] DESKTOP-1Q3GI6C [19] 令牌已过期: IDX10223: Lifetime validation failed. The token is expired. ValidTo (UTC): '07/16/2025 13:48:11', Current time (UTC): '07/27/2025 07:51:31'.
Microsoft.IdentityModel.Tokens.SecurityTokenExpiredException: IDX10223: Lifetime validation failed. The token is expired. ValidTo (UTC): '07/16/2025 13:48:11', Current time (UTC): '07/27/2025 07:51:31'.
at Microsoft.IdentityModel.Tokens.Validators.ValidateLifetime(Nullable`1 notBefore, Nullable`1 expires, SecurityToken securityToken, TokenValidationParameters validationParameters)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateLifetime(Nullable`1 notBefore, Nullable`1 expires, JwtSecurityToken jwtToken, TokenValidationParameters validationParameters)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateTokenPayload(JwtSecurityToken jwtToken, TokenValidationParameters validationParameters, BaseConfiguration configuration)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateJWS(String token, TokenValidationParameters validationParameters, BaseConfiguration currentConfiguration, SecurityToken& signatureValidatedToken, ExceptionDispatchInfo& exceptionThrown)
--- End of stack trace from previous location ---
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, JwtSecurityToken outerToken, TokenValidationParameters validationParameters, SecurityToken& signatureValidatedToken)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, TokenValidationParameters validationParameters, SecurityToken& validatedToken)
at CellularManagement.Infrastructure.Services.Authentication.JwtProvider.ValidateToken(String token) in D:\HistoryCode\CellularManagementAPI\CellularManagement\src\X1.Infrastructure\Services\Authentication\JwtProvider.cs:line 151
2025-07-27 15:51:31.156 +08:00 [ERR] DESKTOP-1Q3GI6C [21] 令牌已过期: IDX10223: Lifetime validation failed. The token is expired. ValidTo (UTC): '07/16/2025 13:48:11', Current time (UTC): '07/27/2025 07:51:31'.
Microsoft.IdentityModel.Tokens.SecurityTokenExpiredException: IDX10223: Lifetime validation failed. The token is expired. ValidTo (UTC): '07/16/2025 13:48:11', Current time (UTC): '07/27/2025 07:51:31'.
at Microsoft.IdentityModel.Tokens.Validators.ValidateLifetime(Nullable`1 notBefore, Nullable`1 expires, SecurityToken securityToken, TokenValidationParameters validationParameters)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateLifetime(Nullable`1 notBefore, Nullable`1 expires, JwtSecurityToken jwtToken, TokenValidationParameters validationParameters)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateTokenPayload(JwtSecurityToken jwtToken, TokenValidationParameters validationParameters, BaseConfiguration configuration)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateJWS(String token, TokenValidationParameters validationParameters, BaseConfiguration currentConfiguration, SecurityToken& signatureValidatedToken, ExceptionDispatchInfo& exceptionThrown)
--- End of stack trace from previous location ---
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, JwtSecurityToken outerToken, TokenValidationParameters validationParameters, SecurityToken& signatureValidatedToken)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, TokenValidationParameters validationParameters, SecurityToken& validatedToken)
at CellularManagement.Infrastructure.Services.Authentication.JwtProvider.ValidateToken(String token) in D:\HistoryCode\CellularManagementAPI\CellularManagement\src\X1.Infrastructure\Services\Authentication\JwtProvider.cs:line 151

165
src/X1.WebAPI/logs/error-20250729.log

@ -73,3 +73,168 @@ Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorException: Failed to generate
at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GetSwaggerAsync(String documentName, String host, String basePath)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
2025-07-29 10:35:30.394 +08:00 [ERR] DESKTOP-T6EU05A [73] Failed executing DbCommand (19ms) [Parameters=[@p0='dc0852fc-2fce-44f6-b116-a0e9aa8a26a1' (Nullable = false), @p1='2025-07-29T02:35:30.2904751Z' (DbType = DateTime), @p2='e7bc3f29-a217-48e7-9724-e76e04d7ed41' (Nullable = false), @p3='', @p4='True', @p5='False', @p6='12333' (Nullable = false), @p7='', @p8='2025-07-29T02:35:30.2904753Z' (DbType = DateTime), @p9='e7bc3f29-a217-48e7-9724-e76e04d7ed41', @p10='fa96dce4-afb0-4300-b02c-66ac43d88982' (Nullable = false), @p11='35b201b3-2703-42b4-bd4e-0a8aa9a0566d' (Nullable = false), @p12='d5190d20-4bdc-4d64-96cd-af62c6648796' (Nullable = false), @p13='1', @p14='dc0852fc-2fce-44f6-b116-a0e9aa8a26a1' (Nullable = false)], CommandType='"Text"', CommandTimeout='30']
INSERT INTO "NetworkStackConfigs" ("Id", "CreatedAt", "CreatedBy", "Description", "IsActive", "IsDeleted", "NetworkStackName", "RanId", "UpdatedAt", "UpdatedBy")
VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9);
INSERT INTO "Stack_CoreIMS_Bindings" ("Id", "CnId", "ImsId", "Index", "NetworkStackConfigId")
VALUES (@p10, @p11, @p12, @p13, @p14);
2025-07-29 10:35:30.456 +08:00 [ERR] DESKTOP-T6EU05A [73] An exception occurred in the database while saving changes for context type 'CellularManagement.Infrastructure.Context.AppDbContext'.
Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
---> Npgsql.PostgresException (0x80004005): 23503: insert or update on table "NetworkStackConfigs" violates foreign key constraint "FK_NetworkStackConfigs_RAN_Configurations_RanId"
DETAIL: Detail redacted as it may contain sensitive data. Specify 'Include Error Detail' in the connection string to include this information.
at Npgsql.Internal.NpgsqlConnector.ReadMessageLong(Boolean async, DataRowLoadingMode dataRowLoadingMode, Boolean readingNotifications, Boolean isReadingPrependedMessage)
at System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder`1.StateMachineBox`1.System.Threading.Tasks.Sources.IValueTaskSource<TResult>.GetResult(Int16 token)
at Npgsql.NpgsqlDataReader.NextResult(Boolean async, Boolean isConsuming, CancellationToken cancellationToken)
at Npgsql.NpgsqlDataReader.NextResult(Boolean async, Boolean isConsuming, CancellationToken cancellationToken)
at Npgsql.NpgsqlCommand.ExecuteReader(Boolean async, CommandBehavior behavior, CancellationToken cancellationToken)
at Npgsql.NpgsqlCommand.ExecuteReader(Boolean async, CommandBehavior behavior, CancellationToken cancellationToken)
at Npgsql.NpgsqlCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
Exception data:
Severity: ERROR
SqlState: 23503
MessageText: insert or update on table "NetworkStackConfigs" violates foreign key constraint "FK_NetworkStackConfigs_RAN_Configurations_RanId"
Detail: Detail redacted as it may contain sensitive data. Specify 'Include Error Detail' in the connection string to include this information.
SchemaName: public
TableName: NetworkStackConfigs
ConstraintName: FK_NetworkStackConfigs_RAN_Configurations_RanId
File: ri_triggers.c
Line: 2528
Routine: ri_ReportViolation
--- End of inner exception stack trace ---
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.<>c__DisplayClass30_0`2.<<ExecuteAsync>b__0>d.MoveNext()
--- End of stack trace from previous location ---
at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteImplementationAsync[TState,TResult](Func`4 operation, Func`4 verifySucceeded, TState state, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteImplementationAsync[TState,TResult](Func`4 operation, Func`4 verifySucceeded, TState state, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
---> Npgsql.PostgresException (0x80004005): 23503: insert or update on table "NetworkStackConfigs" violates foreign key constraint "FK_NetworkStackConfigs_RAN_Configurations_RanId"
DETAIL: Detail redacted as it may contain sensitive data. Specify 'Include Error Detail' in the connection string to include this information.
at Npgsql.Internal.NpgsqlConnector.ReadMessageLong(Boolean async, DataRowLoadingMode dataRowLoadingMode, Boolean readingNotifications, Boolean isReadingPrependedMessage)
at System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder`1.StateMachineBox`1.System.Threading.Tasks.Sources.IValueTaskSource<TResult>.GetResult(Int16 token)
at Npgsql.NpgsqlDataReader.NextResult(Boolean async, Boolean isConsuming, CancellationToken cancellationToken)
at Npgsql.NpgsqlDataReader.NextResult(Boolean async, Boolean isConsuming, CancellationToken cancellationToken)
at Npgsql.NpgsqlCommand.ExecuteReader(Boolean async, CommandBehavior behavior, CancellationToken cancellationToken)
at Npgsql.NpgsqlCommand.ExecuteReader(Boolean async, CommandBehavior behavior, CancellationToken cancellationToken)
at Npgsql.NpgsqlCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
Exception data:
Severity: ERROR
SqlState: 23503
MessageText: insert or update on table "NetworkStackConfigs" violates foreign key constraint "FK_NetworkStackConfigs_RAN_Configurations_RanId"
Detail: Detail redacted as it may contain sensitive data. Specify 'Include Error Detail' in the connection string to include this information.
SchemaName: public
TableName: NetworkStackConfigs
ConstraintName: FK_NetworkStackConfigs_RAN_Configurations_RanId
File: ri_triggers.c
Line: 2528
Routine: ri_ReportViolation
--- End of inner exception stack trace ---
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.<>c__DisplayClass30_0`2.<<ExecuteAsync>b__0>d.MoveNext()
--- End of stack trace from previous location ---
at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteImplementationAsync[TState,TResult](Func`4 operation, Func`4 verifySucceeded, TState state, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteImplementationAsync[TState,TResult](Func`4 operation, Func`4 verifySucceeded, TState state, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
2025-07-29 10:35:30.615 +08:00 [ERR] DESKTOP-T6EU05A [73] 保存更改时发生错误
Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
---> Npgsql.PostgresException (0x80004005): 23503: insert or update on table "NetworkStackConfigs" violates foreign key constraint "FK_NetworkStackConfigs_RAN_Configurations_RanId"
DETAIL: Detail redacted as it may contain sensitive data. Specify 'Include Error Detail' in the connection string to include this information.
at Npgsql.Internal.NpgsqlConnector.ReadMessageLong(Boolean async, DataRowLoadingMode dataRowLoadingMode, Boolean readingNotifications, Boolean isReadingPrependedMessage)
at System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder`1.StateMachineBox`1.System.Threading.Tasks.Sources.IValueTaskSource<TResult>.GetResult(Int16 token)
at Npgsql.NpgsqlDataReader.NextResult(Boolean async, Boolean isConsuming, CancellationToken cancellationToken)
at Npgsql.NpgsqlDataReader.NextResult(Boolean async, Boolean isConsuming, CancellationToken cancellationToken)
at Npgsql.NpgsqlCommand.ExecuteReader(Boolean async, CommandBehavior behavior, CancellationToken cancellationToken)
at Npgsql.NpgsqlCommand.ExecuteReader(Boolean async, CommandBehavior behavior, CancellationToken cancellationToken)
at Npgsql.NpgsqlCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
Exception data:
Severity: ERROR
SqlState: 23503
MessageText: insert or update on table "NetworkStackConfigs" violates foreign key constraint "FK_NetworkStackConfigs_RAN_Configurations_RanId"
Detail: Detail redacted as it may contain sensitive data. Specify 'Include Error Detail' in the connection string to include this information.
SchemaName: public
TableName: NetworkStackConfigs
ConstraintName: FK_NetworkStackConfigs_RAN_Configurations_RanId
File: ri_triggers.c
Line: 2528
Routine: ri_ReportViolation
--- End of inner exception stack trace ---
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.<>c__DisplayClass30_0`2.<<ExecuteAsync>b__0>d.MoveNext()
--- End of stack trace from previous location ---
at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteImplementationAsync[TState,TResult](Func`4 operation, Func`4 verifySucceeded, TState state, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteImplementationAsync[TState,TResult](Func`4 operation, Func`4 verifySucceeded, TState state, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at CellularManagement.Infrastructure.Context.UnitOfWork.SaveChangesAsync(CancellationToken cancellationToken) in D:\dev\clean-architecture-starter-main\CellularManagement\src\X1.Infrastructure\Context\UnitOfWork.cs:line 112
2025-07-29 10:35:30.748 +08:00 [ERR] DESKTOP-T6EU05A [73] 创建网络栈配置时发生错误,网络栈名称: 12333
Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
---> Npgsql.PostgresException (0x80004005): 23503: insert or update on table "NetworkStackConfigs" violates foreign key constraint "FK_NetworkStackConfigs_RAN_Configurations_RanId"
DETAIL: Detail redacted as it may contain sensitive data. Specify 'Include Error Detail' in the connection string to include this information.
at Npgsql.Internal.NpgsqlConnector.ReadMessageLong(Boolean async, DataRowLoadingMode dataRowLoadingMode, Boolean readingNotifications, Boolean isReadingPrependedMessage)
at System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder`1.StateMachineBox`1.System.Threading.Tasks.Sources.IValueTaskSource<TResult>.GetResult(Int16 token)
at Npgsql.NpgsqlDataReader.NextResult(Boolean async, Boolean isConsuming, CancellationToken cancellationToken)
at Npgsql.NpgsqlDataReader.NextResult(Boolean async, Boolean isConsuming, CancellationToken cancellationToken)
at Npgsql.NpgsqlCommand.ExecuteReader(Boolean async, CommandBehavior behavior, CancellationToken cancellationToken)
at Npgsql.NpgsqlCommand.ExecuteReader(Boolean async, CommandBehavior behavior, CancellationToken cancellationToken)
at Npgsql.NpgsqlCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
Exception data:
Severity: ERROR
SqlState: 23503
MessageText: insert or update on table "NetworkStackConfigs" violates foreign key constraint "FK_NetworkStackConfigs_RAN_Configurations_RanId"
Detail: Detail redacted as it may contain sensitive data. Specify 'Include Error Detail' in the connection string to include this information.
SchemaName: public
TableName: NetworkStackConfigs
ConstraintName: FK_NetworkStackConfigs_RAN_Configurations_RanId
File: ri_triggers.c
Line: 2528
Routine: ri_ReportViolation
--- End of inner exception stack trace ---
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.<>c__DisplayClass30_0`2.<<ExecuteAsync>b__0>d.MoveNext()
--- End of stack trace from previous location ---
at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteImplementationAsync[TState,TResult](Func`4 operation, Func`4 verifySucceeded, TState state, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteImplementationAsync[TState,TResult](Func`4 operation, Func`4 verifySucceeded, TState state, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at CellularManagement.Infrastructure.Context.UnitOfWork.SaveChangesAsync(CancellationToken cancellationToken) in D:\dev\clean-architecture-starter-main\CellularManagement\src\X1.Infrastructure\Context\UnitOfWork.cs:line 112
at CellularManagement.Application.Features.NetworkStackConfigs.Commands.CreateNetworkStackConfig.CreateNetworkStackConfigCommandHandler.Handle(CreateNetworkStackConfigCommand request, CancellationToken cancellationToken) in D:\dev\clean-architecture-starter-main\CellularManagement\src\X1.Application\Features\NetworkStackConfigs\Commands\CreateNetworkStackConfig\CreateNetworkStackConfigCommandHandler.cs:line 120

2
src/X1.WebUI/src/config/core/env.config.ts

@ -4,7 +4,7 @@ import type { ApiConfig, AuthConfig, AppConfig, MockConfig, Environment } from '
// 默认配置
const DEFAULT_CONFIG = {
// API配置
VITE_API_BASE_URL: 'https://localhost:7268/api',
VITE_API_BASE_URL: 'https://192.168.2.142:7268/api',
VITE_API_TIMEOUT: '30000',
VITE_API_VERSION: 'v1',
VITE_API_MAX_RETRIES: '3',

5
src/X1.WebUI/src/constants/api.ts

@ -15,10 +15,7 @@ export const API_PATHS = {
// 核心网络配置相关
CORE_NETWORK_CONFIGS: '/corenetworkconfigs',
// 栈核心网IMS绑定相关
STACK_CORE_IMS_BINDINGS: '/stackcoreimsbindings',
// 网络栈配置相关
// 网络栈配置相关
NETWORK_STACK_CONFIGS: '/networkstackconfigs',
// 用户相关

771
src/X1.WebUI/src/pages/network-stack-configs/NetworkStackConfigDrawer.tsx

@ -0,0 +1,771 @@
import React, { useEffect, useState, useRef } from 'react';
import {
CreateNetworkStackConfigRequest,
UpdateNetworkStackConfigRequest,
NetworkStackConfig,
CreateStackCoreIMSBindingItem
} from '@/services/networkStackConfigService';
import { RANConfiguration, ranConfigurationService } from '@/services/ranConfigurationService';
import { CoreNetworkConfig, coreNetworkConfigService } from '@/services/coreNetworkConfigService';
import { IMSConfiguration, imsConfigurationService } from '@/services/imsConfigurationService';
import { Drawer, DrawerHeader, DrawerContent, DrawerFooter } from '@/components/ui/drawer';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Textarea } from '@/components/ui/textarea';
import { Badge } from '@/components/ui/badge';
import { Plus, Trash2, X } from 'lucide-react';
interface NetworkStackConfigDrawerProps {
open: boolean;
onOpenChange: (open: boolean) => void;
onSubmit: (data: CreateNetworkStackConfigRequest | UpdateNetworkStackConfigRequest) => Promise<void>;
initialData?: NetworkStackConfig;
isEdit?: boolean;
isSubmitting?: boolean;
}
export default function NetworkStackConfigDrawer({
open,
onOpenChange,
onSubmit,
initialData,
isEdit = false,
isSubmitting = false
}: NetworkStackConfigDrawerProps) {
const [formData, setFormData] = useState<CreateNetworkStackConfigRequest | UpdateNetworkStackConfigRequest>({
networkStackName: '',
ranId: '',
description: '',
isActive: true,
stackCoreIMSBindings: []
});
// RAN配置列表状态
const [ranConfigurations, setRanConfigurations] = useState<RANConfiguration[]>([]);
const [filteredRanConfigurations, setFilteredRanConfigurations] = useState<RANConfiguration[]>([]);
const [isLoadingRAN, setIsLoadingRAN] = useState(false);
const [searchTerm, setSearchTerm] = useState('');
const [isOpen, setIsOpen] = useState(false);
const dropdownRef = useRef<HTMLDivElement>(null);
// 核心网配置列表状态
const [coreNetworkConfigs, setCoreNetworkConfigs] = useState<CoreNetworkConfig[]>([]);
const [filteredCoreNetworkConfigs, setFilteredCoreNetworkConfigs] = useState<CoreNetworkConfig[]>([]);
const [isLoadingCoreNetwork, setIsLoadingCoreNetwork] = useState(false);
const [coreNetworkSearchTerm, setCoreNetworkSearchTerm] = useState('');
const [openCoreNetworkIndex, setOpenCoreNetworkIndex] = useState<number | null>(null);
const coreNetworkDropdownRef = useRef<HTMLDivElement>(null);
// IMS配置列表状态
const [imsConfigurations, setImsConfigurations] = useState<IMSConfiguration[]>([]);
const [filteredImsConfigurations, setFilteredImsConfigurations] = useState<IMSConfiguration[]>([]);
const [isLoadingIMS, setIsLoadingIMS] = useState(false);
const [imsSearchTerm, setImsSearchTerm] = useState('');
const [openIMSIndex, setOpenIMSIndex] = useState<number | null>(null);
const imsDropdownRef = useRef<HTMLDivElement>(null);
// 校验错误信息状态
const [validationError, setValidationError] = useState<string>('');
// 当抽屉打开时,初始化表单数据
useEffect(() => {
if (open) {
if (initialData && isEdit) {
setFormData({
networkStackConfigId: initialData.networkStackConfigId,
networkStackName: initialData.networkStackName || '',
ranId: initialData.ranId || '',
description: initialData.description || '',
isActive: initialData.isActive ?? true,
stackCoreIMSBindings: initialData.stackCoreIMSBindings?.map(binding => ({
index: binding.index,
coreNetworkConfigId: binding.coreNetworkConfigId,
imsConfigId: binding.imsConfigId
})) || []
});
} else {
// 重置表单
setFormData({
networkStackName: '',
ranId: '',
description: '',
isActive: true,
stackCoreIMSBindings: []
});
}
}
}, [open, initialData, isEdit]);
// 加载RAN配置列表
useEffect(() => {
const loadRANConfigurations = async () => {
setIsLoadingRAN(true);
try {
const result = await ranConfigurationService.getRANConfigurations({
pageSize: 1000,
isDisabled: false
});
if (result.isSuccess && result.data) {
const configs = result.data.items || [];
setRanConfigurations(configs);
setFilteredRanConfigurations(configs);
}
} catch (error) {
console.error('加载RAN配置失败:', error);
} finally {
setIsLoadingRAN(false);
}
};
// 加载核心网配置列表
const loadCoreNetworkConfigs = async () => {
setIsLoadingCoreNetwork(true);
try {
const result = await coreNetworkConfigService.getCoreNetworkConfigs({
pageSize: 1000,
isDisabled: false
});
if (result.isSuccess && result.data) {
const configs = result.data.items || [];
setCoreNetworkConfigs(configs);
setFilteredCoreNetworkConfigs(configs);
}
} catch (error) {
console.error('加载核心网配置失败:', error);
} finally {
setIsLoadingCoreNetwork(false);
}
};
// 加载IMS配置列表
const loadIMSConfigurations = async () => {
setIsLoadingIMS(true);
try {
const result = await imsConfigurationService.getIMSConfigurations({
pageSize: 1000,
isDisabled: false
});
if (result.isSuccess && result.data) {
const configs = result.data.items || [];
setImsConfigurations(configs);
setFilteredImsConfigurations(configs);
}
} catch (error) {
console.error('加载IMS配置失败:', error);
} finally {
setIsLoadingIMS(false);
}
};
if (open) {
loadRANConfigurations();
loadCoreNetworkConfigs();
loadIMSConfigurations();
}
}, [open]);
// 点击外部关闭下拉框
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
const target = event.target as Node;
// 检查是否点击了任何下拉框区域
const isRANDropdown = dropdownRef.current?.contains(target);
const isCoreNetworkDropdown = coreNetworkDropdownRef.current?.contains(target);
const isIMSDropdown = imsDropdownRef.current?.contains(target);
// 检查是否点击了下拉框内容
const isDropdownContent = (target as HTMLElement).closest('.dropdown-content');
// 如果点击了RAN下拉框外部,关闭RAN下拉框
if (!isRANDropdown && !isDropdownContent) {
setIsOpen(false);
setSearchTerm('');
setFilteredRanConfigurations(ranConfigurations);
}
// 如果点击了核心网下拉框外部,关闭核心网下拉框
if (!isCoreNetworkDropdown && !isDropdownContent) {
setOpenCoreNetworkIndex(null);
setCoreNetworkSearchTerm('');
setFilteredCoreNetworkConfigs(coreNetworkConfigs);
}
// 如果点击了IMS下拉框外部,关闭IMS下拉框
if (!isIMSDropdown && !isDropdownContent) {
setOpenIMSIndex(null);
setImsSearchTerm('');
setFilteredImsConfigurations(imsConfigurations);
}
};
document.addEventListener('mousedown', handleClickOutside);
return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
}, [ranConfigurations, coreNetworkConfigs, imsConfigurations]);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (isSubmitting) return;
// 清除之前的错误信息
setValidationError('');
// 基本验证
if (!formData.networkStackName?.trim()) {
setValidationError('请输入网络栈名称');
return;
}
// RAN配置和绑定关系至少选择一个
const hasRAN = !!formData.ranId;
const hasValidBindings = formData.stackCoreIMSBindings && formData.stackCoreIMSBindings.length > 0 &&
formData.stackCoreIMSBindings.some(binding => {
const hasCoreNetwork = !!binding.coreNetworkConfigId;
const hasIMS = !!binding.imsConfigId;
return hasCoreNetwork && hasIMS; // 至少有一个完整的绑定项
});
if (!hasRAN && !hasValidBindings) {
setValidationError('请至少选择RAN配置或添加完整的绑定关系');
return;
}
// 绑定关系验证
if (formData.stackCoreIMSBindings && formData.stackCoreIMSBindings.length > 0) {
// 检查部分填写的绑定项(只选了一个)
const partialBindings = formData.stackCoreIMSBindings.filter(binding => {
const hasCoreNetwork = !!binding.coreNetworkConfigId;
const hasIMS = !!binding.imsConfigId;
return (hasCoreNetwork && !hasIMS) || (!hasCoreNetwork && hasIMS);
});
// 检查完全空白的绑定项(都不选)
const emptyBindings = formData.stackCoreIMSBindings.filter(binding => {
const hasCoreNetwork = !!binding.coreNetworkConfigId;
const hasIMS = !!binding.imsConfigId;
return !hasCoreNetwork && !hasIMS;
});
let errorMessage = '';
if (partialBindings.length > 0) {
const partialIndexes = partialBindings.map(binding => binding.index).join('、');
errorMessage += `绑定关系 #${partialIndexes} 未完成,请选择完整的核心网配置和IMS配置。`;
}
if (emptyBindings.length > 0) {
const emptyIndexes = emptyBindings.map(binding => binding.index).join('、');
if (errorMessage) errorMessage += '\n';
errorMessage += `绑定关系 #${emptyIndexes} 为空,请移除该绑定项。`;
}
if (errorMessage) {
setValidationError(errorMessage);
return;
}
}
await onSubmit(formData);
};
const handleInputChange = (field: string, value: string | boolean) => {
setFormData(prev => ({
...prev,
[field]: value
}));
};
// 搜索RAN配置
const handleSearchChange = (value: string) => {
setSearchTerm(value);
if (value.trim() === '') {
setFilteredRanConfigurations(ranConfigurations);
} else {
const searchValue = value.toLowerCase();
const filtered = ranConfigurations.filter(config =>
config.name.toLowerCase().includes(searchValue) ||
(config.description && config.description.toLowerCase().includes(searchValue))
);
setFilteredRanConfigurations(filtered);
}
};
// 选择RAN配置
const handleRANSelect = (value: string) => {
handleInputChange('ranId', value === 'none' ? '' : value);
setIsOpen(false);
setSearchTerm('');
setFilteredRanConfigurations(ranConfigurations);
};
// 搜索核心网配置
const handleCoreNetworkSearchChange = (value: string) => {
setCoreNetworkSearchTerm(value);
if (value.trim() === '') {
setFilteredCoreNetworkConfigs(coreNetworkConfigs);
} else {
const searchValue = value.toLowerCase();
const filtered = coreNetworkConfigs.filter(config =>
config.name.toLowerCase().includes(searchValue) ||
(config.description && config.description.toLowerCase().includes(searchValue))
);
setFilteredCoreNetworkConfigs(filtered);
}
};
// 选择核心网配置
const handleCoreNetworkSelect = (value: string) => {
return value === 'none' ? '' : value;
};
// 搜索IMS配置
const handleIMSSearchChange = (value: string) => {
setImsSearchTerm(value);
if (value.trim() === '') {
setFilteredImsConfigurations(imsConfigurations);
} else {
const searchValue = value.toLowerCase();
const filtered = imsConfigurations.filter(config =>
config.name.toLowerCase().includes(searchValue) ||
(config.description && config.description.toLowerCase().includes(searchValue))
);
setFilteredImsConfigurations(filtered);
}
};
// 选择IMS配置
const handleIMSSelect = (value: string) => {
return value === 'none' ? '' : value;
};
const addBinding = () => {
const newBinding: CreateStackCoreIMSBindingItem = {
index: (formData.stackCoreIMSBindings?.length || 0) + 1,
coreNetworkConfigId: '',
imsConfigId: ''
};
setFormData(prev => ({
...prev,
stackCoreIMSBindings: [...(prev.stackCoreIMSBindings || []), newBinding]
}));
};
const removeBinding = (index: number) => {
setFormData(prev => {
const updatedBindings = prev.stackCoreIMSBindings?.filter((_, i) => i !== index) || [];
// 重新排序索引,从1开始
const reorderedBindings = updatedBindings.map((binding, i) => ({
...binding,
index: i + 1
}));
return {
...prev,
stackCoreIMSBindings: reorderedBindings
};
});
};
const updateBinding = (index: number, field: keyof CreateStackCoreIMSBindingItem, value: string | number) => {
setFormData(prev => ({
...prev,
stackCoreIMSBindings: prev.stackCoreIMSBindings?.map((binding, i) =>
i === index ? { ...binding, [field]: value } : binding
) || []
}));
};
return (
<Drawer open={open} onOpenChange={onOpenChange}>
<div className="flex flex-col h-full">
<DrawerHeader className="flex-shrink-0">
<div className="flex items-center justify-between w-full">
<h2 className="text-lg font-semibold">
{isEdit ? '编辑网络栈配置' : '创建网络栈配置'}
</h2>
<Button
variant="ghost"
size="sm"
onClick={() => onOpenChange(false)}
className="h-8 w-8 p-0"
>
<X className="h-4 w-4" />
</Button>
</div>
</DrawerHeader>
<form onSubmit={handleSubmit} className="flex flex-col flex-1 min-h-0">
<DrawerContent className="flex flex-col flex-1 min-h-0">
<div className="space-y-6 flex-1 flex flex-col min-h-0">
{/* 基本信息 */}
<div className="border rounded-lg p-4 flex-shrink-0">
<h3 className="text-md font-semibold mb-4"></h3>
<div className="space-y-4">
<div className="space-y-2">
<Label htmlFor="networkStackName" className="text-sm font-medium">
<span className="text-red-500">*</span>
</Label>
<Input
id="networkStackName"
value={formData.networkStackName || ''}
onChange={e => handleInputChange('networkStackName', e.target.value)}
placeholder="请输入网络栈名称"
required
disabled={isSubmitting || isEdit}
className={isEdit ? "bg-gray-100" : ""}
/>
{isEdit && (
<p className="text-xs text-gray-500">
</p>
)}
</div>
<div className="space-y-2">
<Label htmlFor="ranId" className="text-sm font-medium">
RAN配置
</Label>
<div className="relative" ref={dropdownRef}>
<div
data-dropdown-trigger="ran"
className="flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 cursor-pointer"
onClick={() => {
if (!isSubmitting && !isLoadingRAN) {
// 关闭所有其他下拉框
setOpenCoreNetworkIndex(null);
setCoreNetworkSearchTerm('');
setFilteredCoreNetworkConfigs(coreNetworkConfigs);
setOpenIMSIndex(null);
setImsSearchTerm('');
setFilteredImsConfigurations(imsConfigurations);
// 切换当前下拉框
setIsOpen(!isOpen);
}
}}
>
<span className={formData.ranId ?
(() => {
const config = ranConfigurations.find(c => c.raN_ConfigurationId === formData.ranId);
return config ? `${config.name}${config.description ? ` | ${config.description}` : ''}` : '未知配置';
})() :
(isLoadingRAN ? "加载中..." : "请选择RAN配置(可选)")
}>
{formData.ranId ?
(() => {
const config = ranConfigurations.find(c => c.raN_ConfigurationId === formData.ranId);
return config ? `${config.name}${config.description ? ` | ${config.description}` : ''}` : '未知配置';
})() :
(isLoadingRAN ? "加载中..." : "请选择RAN配置(可选)")
}
</span>
<svg className="h-4 w-4 opacity-50" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</div>
{isOpen && (
<div className="dropdown-content absolute z-50 w-full mt-1 bg-popover border rounded-md shadow-md max-h-60 overflow-hidden">
<div className="p-2 border-b">
<Input
placeholder="搜索RAN配置..."
value={searchTerm}
onChange={(e) => handleSearchChange(e.target.value)}
className="h-8"
/>
</div>
<div className="max-h-48 overflow-y-auto">
<div
className="px-2 py-1.5 text-sm cursor-pointer hover:bg-accent hover:text-accent-foreground"
onClick={() => handleRANSelect('none')}
>
</div>
{filteredRanConfigurations.map((ranConfig) => (
<div
key={ranConfig.raN_ConfigurationId}
className="px-2 py-1.5 text-sm cursor-pointer hover:bg-accent hover:text-accent-foreground"
onClick={() => handleRANSelect(ranConfig.raN_ConfigurationId)}
>
{ranConfig.name}{ranConfig.description ? ` | ${ranConfig.description}` : ''}
</div>
))}
{filteredRanConfigurations.length === 0 && searchTerm && (
<div className="px-2 py-1.5 text-sm text-muted-foreground">
RAN配置
</div>
)}
</div>
</div>
)}
</div>
</div>
<div className="space-y-2">
<Label htmlFor="description" className="text-sm font-medium">
</Label>
<Textarea
id="description"
value={formData.description || ''}
onChange={e => handleInputChange('description', e.target.value)}
placeholder="请输入配置描述"
rows={3}
disabled={isSubmitting}
/>
</div>
</div>
</div>
{/* 栈与核心网/IMS绑定关系 */}
<div className="border rounded-lg p-4 flex flex-col flex-1 min-h-0">
<div className="flex items-center justify-between mb-4 flex-shrink-0">
<h3 className="text-md font-semibold">CoreNetwork/IMS绑定关系</h3>
<Button
type="button"
variant="outline"
size="sm"
onClick={addBinding}
disabled={isSubmitting}
className="flex items-center gap-1"
>
<Plus className="h-4 w-4" />
</Button>
</div>
<div className="flex-1 overflow-y-auto" style={{ maxHeight: 'calc(100vh - 400px)' }}>
{formData.stackCoreIMSBindings && formData.stackCoreIMSBindings.length > 0 ? (
<div className="space-y-2">
{formData.stackCoreIMSBindings.map((binding, index) => (
<div key={index} className="flex items-center gap-3 p-3 border rounded-lg hover:bg-gray-50">
<div className="flex items-center gap-2 min-w-0 flex-1">
<Badge variant="secondary" className="shrink-0">#{binding.index}</Badge>
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2">
<span className="text-sm font-medium text-gray-500 w-16 text-right">CN:</span>
<div className="flex-1 min-w-0 relative">
<div
data-dropdown-trigger="core-network"
className="flex h-8 w-full items-center justify-between rounded border border-input bg-background px-2 py-1 text-sm cursor-pointer hover:bg-accent"
onClick={() => {
if (!isSubmitting && !isLoadingCoreNetwork) {
// 关闭所有其他下拉框
setIsOpen(false);
setSearchTerm('');
setFilteredRanConfigurations(ranConfigurations);
setOpenIMSIndex(null);
setImsSearchTerm('');
setFilteredImsConfigurations(imsConfigurations);
// 切换当前下拉框
setOpenCoreNetworkIndex(openCoreNetworkIndex === index ? null : index);
}
}}
>
<span className="truncate">
{binding.coreNetworkConfigId ?
(() => {
const config = coreNetworkConfigs.find(c => c.coreNetworkConfigId === binding.coreNetworkConfigId);
return config ? `${config.name}${config.description ? ` | ${config.description}` : ''}` : '未知配置';
})() :
(isLoadingCoreNetwork ? "加载中..." : "请选择核心网配置")
}
</span>
<svg className="h-3 w-3 opacity-50 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</div>
{openCoreNetworkIndex === index && (
<div className="dropdown-content absolute z-50 w-64 mt-1 bg-popover border rounded-md shadow-md max-h-60 overflow-hidden" style={{ position: 'absolute', top: '100%', left: 0 }}>
<div className="p-2 border-b">
<Input
placeholder="搜索核心网配置..."
value={coreNetworkSearchTerm}
onChange={(e) => handleCoreNetworkSearchChange(e.target.value)}
className="h-8"
/>
</div>
<div className="max-h-48 overflow-y-auto">
<div
className="px-2 py-1.5 text-sm cursor-pointer hover:bg-accent hover:text-accent-foreground"
onClick={() => {
updateBinding(index, 'coreNetworkConfigId', '');
setOpenCoreNetworkIndex(null);
setCoreNetworkSearchTerm('');
setFilteredCoreNetworkConfigs(coreNetworkConfigs);
}}
>
</div>
{filteredCoreNetworkConfigs.map((config) => (
<div
key={config.coreNetworkConfigId}
className="px-2 py-1.5 text-sm cursor-pointer hover:bg-accent hover:text-accent-foreground"
onClick={() => {
updateBinding(index, 'coreNetworkConfigId', config.coreNetworkConfigId);
setOpenCoreNetworkIndex(null);
setCoreNetworkSearchTerm('');
setFilteredCoreNetworkConfigs(coreNetworkConfigs);
}}
>
{config.name}{config.description ? ` | ${config.description}` : ''}
</div>
))}
{filteredCoreNetworkConfigs.length === 0 && coreNetworkSearchTerm && (
<div className="px-2 py-1.5 text-sm text-muted-foreground">
</div>
)}
</div>
</div>
)}
</div>
</div>
<div className="flex items-center gap-2 mt-1">
<span className="text-sm font-medium text-gray-500 w-16 text-right">IMS:</span>
<div className="flex-1 min-w-0 relative">
<div
data-dropdown-trigger="ims"
className="flex h-8 w-full items-center justify-between rounded border border-input bg-background px-2 py-1 text-sm cursor-pointer hover:bg-accent"
onClick={() => {
if (!isSubmitting && !isLoadingIMS) {
// 关闭所有其他下拉框
setIsOpen(false);
setSearchTerm('');
setFilteredRanConfigurations(ranConfigurations);
setOpenCoreNetworkIndex(null);
setCoreNetworkSearchTerm('');
setFilteredCoreNetworkConfigs(coreNetworkConfigs);
// 切换当前下拉框
setOpenIMSIndex(openIMSIndex === index ? null : index);
}
}}
>
<span className="truncate">
{binding.imsConfigId ?
(() => {
const config = imsConfigurations.find(c => c.imS_ConfigurationId === binding.imsConfigId);
return config ? `${config.name}${config.description ? ` | ${config.description}` : ''}` : '未知配置';
})() :
(isLoadingIMS ? "加载中..." : "请选择IMS配置")
}
</span>
<svg className="h-3 w-3 opacity-50 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</div>
{openIMSIndex === index && (
<div className="dropdown-content absolute z-50 w-64 mt-1 bg-popover border rounded-md shadow-md max-h-60 overflow-hidden" style={{ position: 'absolute', top: '100%', left: 0 }}>
<div className="p-2 border-b">
<Input
placeholder="搜索IMS配置..."
value={imsSearchTerm}
onChange={(e) => handleIMSSearchChange(e.target.value)}
className="h-8"
/>
</div>
<div className="max-h-48 overflow-y-auto">
<div
className="px-2 py-1.5 text-sm cursor-pointer hover:bg-accent hover:text-accent-foreground"
onClick={() => {
updateBinding(index, 'imsConfigId', '');
setOpenIMSIndex(null);
setImsSearchTerm('');
setFilteredImsConfigurations(imsConfigurations);
}}
>
</div>
{filteredImsConfigurations.map((config) => (
<div
key={config.imS_ConfigurationId}
className="px-2 py-1.5 text-sm cursor-pointer hover:bg-accent hover:text-accent-foreground"
onClick={() => {
updateBinding(index, 'imsConfigId', config.imS_ConfigurationId);
setOpenIMSIndex(null);
setImsSearchTerm('');
setFilteredImsConfigurations(imsConfigurations);
}}
>
{config.name}{config.description ? ` | ${config.description}` : ''}
</div>
))}
{filteredImsConfigurations.length === 0 && imsSearchTerm && (
<div className="px-2 py-1.5 text-sm text-muted-foreground">
IMS配置
</div>
)}
</div>
</div>
)}
</div>
</div>
</div>
</div>
<Button
type="button"
variant="ghost"
size="sm"
onClick={() => removeBinding(index)}
disabled={isSubmitting}
className="text-red-500 hover:text-red-700 shrink-0"
>
<Trash2 className="h-4 w-4" />
</Button>
</div>
))}
</div>
) : (
<div className="text-center py-8 text-gray-500">
<p></p>
<p className="text-sm">"添加绑定"/IMS的绑定关系</p>
</div>
)}
</div>
</div>
</div>
</DrawerContent>
<DrawerFooter>
<div className="flex items-center justify-between w-full">
<div className="flex-1">
{validationError && (
<div className="text-red-500 text-sm flex items-center gap-2">
<svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z" />
</svg>
<span className="whitespace-pre-line">{validationError}</span>
</div>
)}
</div>
<div className="flex gap-2">
<Button
type="button"
variant="outline"
onClick={() => onOpenChange(false)}
disabled={isSubmitting}
>
</Button>
<Button
type="submit"
disabled={isSubmitting}
className="bg-primary text-primary-foreground hover:bg-primary/90"
>
{isSubmitting ? '保存中...' : (isEdit ? '更新' : '创建')}
</Button>
</div>
</div>
</DrawerFooter>
</form>
</div>
</Drawer>
);
}

90
src/X1.WebUI/src/pages/network-stack-configs/NetworkStackConfigForm.tsx

@ -1,90 +0,0 @@
import React from 'react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Textarea } from '@/components/ui/textarea';
import { Checkbox } from '@/components/ui/checkbox';
import { CreateNetworkStackConfigRequest, UpdateNetworkStackConfigRequest, NetworkStackConfig } from '@/services/networkStackConfigService';
interface NetworkStackConfigFormProps {
onSubmit: (data: CreateNetworkStackConfigRequest | UpdateNetworkStackConfigRequest) => void;
initialData?: Partial<NetworkStackConfig>;
isEdit?: boolean;
isSubmitting?: boolean;
}
export default function NetworkStackConfigForm({ onSubmit, initialData, isEdit = false, isSubmitting = false }: NetworkStackConfigFormProps) {
const [formData, setFormData] = React.useState<CreateNetworkStackConfigRequest>({
stackId: initialData?.stackId || '',
ranId: initialData?.ranId || '',
description: initialData?.description || '',
isActive: initialData?.isActive ?? true
});
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (isSubmitting) return; // 防止重复提交
onSubmit(formData);
};
return (
<form onSubmit={handleSubmit} className="space-y-4">
<div className="space-y-2">
<Label htmlFor="stackId">ID</Label>
<Input
id="stackId"
value={formData.stackId}
onChange={e => setFormData({ ...formData, stackId: e.target.value })}
placeholder="请输入栈ID"
required
disabled={isSubmitting || isEdit} // 编辑时不允许修改栈ID
className={isEdit ? "bg-gray-100" : ""}
/>
{isEdit && (
<p className="text-xs text-gray-500">
ID
</p>
)}
</div>
<div className="space-y-2">
<Label htmlFor="ranId">RAN ID</Label>
<Input
id="ranId"
value={formData.ranId}
onChange={e => setFormData({ ...formData, ranId: e.target.value })}
placeholder="请输入RAN ID(可选)"
disabled={isSubmitting}
/>
</div>
<div className="space-y-2">
<Label htmlFor="description"></Label>
<Textarea
id="description"
value={formData.description}
onChange={e => setFormData({ ...formData, description: e.target.value })}
placeholder="请输入配置描述"
rows={3}
disabled={isSubmitting}
/>
</div>
<div className="flex items-center space-x-2">
<Checkbox
id="isActive"
checked={formData.isActive}
onCheckedChange={(checked) =>
setFormData({ ...formData, isActive: checked as boolean })
}
disabled={isSubmitting}
/>
<Label htmlFor="isActive"></Label>
</div>
<Button type="submit" className="w-full" disabled={isSubmitting}>
{isSubmitting ? '提交中...' : (isEdit ? '更新网络栈配置' : '创建网络栈配置')}
</Button>
</form>
);
}

6
src/X1.WebUI/src/pages/network-stack-configs/NetworkStackConfigsTable.tsx

@ -67,10 +67,10 @@ export default function NetworkStackConfigsTable({
const renderCell = (config: NetworkStackConfig, columnKey: string) => {
switch (columnKey) {
case 'stackId':
case 'networkStackName':
return (
<div className="max-w-xs truncate font-mono text-sm" title={config.stackId}>
{config.stackId}
<div className="max-w-xs truncate font-mono text-sm" title={config.networkStackName}>
{config.networkStackName}
</div>
);
case 'ranId':

84
src/X1.WebUI/src/pages/network-stack-configs/NetworkStackConfigsView.tsx

@ -1,17 +1,17 @@
import React, { useEffect, useState } from 'react';
import { networkStackConfigService, NetworkStackConfig, GetNetworkStackConfigsRequest, CreateNetworkStackConfigRequest, UpdateNetworkStackConfigRequest } from '@/services/networkStackConfigService';
import NetworkStackConfigsTable from './NetworkStackConfigsTable';
import NetworkStackConfigForm from './NetworkStackConfigForm';
import NetworkStackConfigDrawer from './NetworkStackConfigDrawer';
import { Input } from '@/components/ui/input';
import PaginationBar from '@/components/ui/PaginationBar';
import TableToolbar, { DensityType } from '@/components/ui/TableToolbar';
import { Dialog, DialogContent, DialogTrigger } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { ChevronDownIcon, ChevronUpIcon } from '@radix-ui/react-icons';
import { useToast } from '@/components/ui/use-toast';
const defaultColumns = [
{ key: 'stackId', title: '栈ID', visible: true },
{ key: 'networkStackName', title: '网络栈名称', visible: true },
{ key: 'ranId', title: 'RAN ID', visible: true },
{ key: 'description', title: '描述', visible: true },
{ key: 'isActive', title: '状态', visible: true },
@ -26,7 +26,7 @@ type SearchField =
// 第一行字段(收起时只显示这3个)
const firstRowFields: SearchField[] = [
{ key: 'searchTerm', label: '搜索关键词', type: 'input', placeholder: '请输入栈ID或描述' },
{ key: 'networkStackName', label: '网络栈名称', type: 'input', placeholder: '请输入网络栈名称' },
{ key: 'isActive', label: '状态', type: 'select', options: [
{ value: '', label: '请选择' },
{ value: 'true', label: '激活' },
@ -55,12 +55,11 @@ export default function NetworkStackConfigsView() {
const [showAdvanced, setShowAdvanced] = useState(false);
// 搜索参数
const [searchTerm, setSearchTerm] = useState('');
const [networkStackName, setNetworkStackName] = useState('');
const [isActive, setIsActive] = useState<boolean | undefined>(undefined);
// 表单对话框状态
const [open, setOpen] = useState(false);
const [editOpen, setEditOpen] = useState(false);
// 抽屉状态
const [drawerOpen, setDrawerOpen] = useState(false);
const [selectedConfig, setSelectedConfig] = useState<NetworkStackConfig | null>(null);
// 提交状态
@ -74,14 +73,14 @@ export default function NetworkStackConfigsView() {
const queryParams: GetNetworkStackConfigsRequest = {
pageNumber,
pageSize,
searchTerm,
networkStackName,
isActive,
...params
};
const result = await networkStackConfigService.getNetworkStackConfigs(queryParams);
if (result.isSuccess && result.data) {
setNetworkStackConfigs(result.data.items || []);
setNetworkStackConfigs(result.data.networkStackConfigs || []);
setTotal(result.data.totalCount || 0);
}
setLoading(false);
@ -94,17 +93,17 @@ export default function NetworkStackConfigsView() {
const handleEdit = (config: NetworkStackConfig) => {
setSelectedConfig(config);
setEditOpen(true);
setDrawerOpen(true);
};
const handleDelete = async (config: NetworkStackConfig) => {
if (confirm(`确定要删除网络栈配置 "${config.stackId}" 吗?`)) {
if (confirm(`确定要删除网络栈配置 "${config.networkStackName}" 吗?`)) {
try {
const result = await networkStackConfigService.deleteNetworkStackConfig(config.networkStackConfigId);
if (result.isSuccess) {
toast({
title: "删除成功",
description: `网络栈配置 "${config.stackId}" 删除成功`,
description: `网络栈配置 "${config.networkStackName}" 删除成功`,
});
fetchNetworkStackConfigs();
} else {
@ -139,9 +138,9 @@ export default function NetworkStackConfigsView() {
if (result.isSuccess) {
toast({
title: "创建成功",
description: `网络栈配置 "${data.stackId}" 创建成功`,
description: `网络栈配置 "${data.networkStackName}" 创建成功`,
});
setOpen(false);
setDrawerOpen(false);
fetchNetworkStackConfigs();
} else {
const errorMessage = result.errorMessages?.join(', ') || "创建网络栈配置时发生错误";
@ -173,9 +172,9 @@ export default function NetworkStackConfigsView() {
if (result.isSuccess) {
toast({
title: "更新成功",
description: `网络栈配置 "${selectedConfig.stackId}" 更新成功`,
description: `网络栈配置 "${selectedConfig.networkStackName}" 更新成功`,
});
setEditOpen(false);
setDrawerOpen(false);
setSelectedConfig(null);
fetchNetworkStackConfigs();
} else {
@ -207,11 +206,11 @@ export default function NetworkStackConfigsView() {
// 重置按钮
const handleReset = () => {
setSearchTerm('');
setNetworkStackName('');
setIsActive(undefined);
setPageNumber(1);
fetchNetworkStackConfigs({
searchTerm: '',
networkStackName: '',
isActive: undefined,
pageNumber: 1
});
@ -249,9 +248,9 @@ export default function NetworkStackConfigsView() {
<Input
className="input flex-1"
placeholder={field.placeholder}
value={field.key === 'searchTerm' ? searchTerm : ''}
value={field.key === 'networkStackName' ? networkStackName : ''}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
if (field.key === 'searchTerm') setSearchTerm(e.target.value);
if (field.key === 'networkStackName') setNetworkStackName(e.target.value);
}}
/>
)}
@ -298,14 +297,15 @@ export default function NetworkStackConfigsView() {
<div className="rounded-md border bg-background p-4">
{/* 顶部操作栏:添加网络栈配置+工具栏 */}
<div className="flex items-center justify-between mb-2">
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<Button className="bg-primary text-primary-foreground hover:bg-primary/90">+ </Button>
</DialogTrigger>
<DialogContent className="bg-background">
<NetworkStackConfigForm onSubmit={handleCreate} isSubmitting={isSubmitting} />
</DialogContent>
</Dialog>
<Button
className="bg-primary text-primary-foreground hover:bg-primary/90"
onClick={() => {
setSelectedConfig(null);
setDrawerOpen(true);
}}
>
+
</Button>
<TableToolbar
onRefresh={() => fetchNetworkStackConfigs()}
onDensityChange={setDensity}
@ -340,17 +340,21 @@ export default function NetworkStackConfigsView() {
</div>
</div>
{/* 编辑网络栈配置对话框 */}
<Dialog open={editOpen} onOpenChange={setEditOpen}>
<DialogContent className="bg-background">
<NetworkStackConfigForm
onSubmit={(data: CreateNetworkStackConfigRequest | UpdateNetworkStackConfigRequest) => handleUpdate(data as UpdateNetworkStackConfigRequest)}
initialData={selectedConfig || undefined}
isEdit={true}
isSubmitting={isSubmitting}
/>
</DialogContent>
</Dialog>
{/* 网络栈配置抽屉 */}
<NetworkStackConfigDrawer
open={drawerOpen}
onOpenChange={setDrawerOpen}
onSubmit={async (data: CreateNetworkStackConfigRequest | UpdateNetworkStackConfigRequest) => {
if (selectedConfig) {
await handleUpdate(data as UpdateNetworkStackConfigRequest);
} else {
await handleCreate(data as CreateNetworkStackConfigRequest);
}
}}
initialData={selectedConfig || undefined}
isEdit={!!selectedConfig}
isSubmitting={isSubmitting}
/>
</main>
);
}

55
src/X1.WebUI/src/services/networkStackConfigService.ts

@ -5,7 +5,7 @@ import { API_PATHS } from '@/constants/api';
// 网络栈配置接口定义
export interface NetworkStackConfig {
networkStackConfigId: string;
stackId: string;
networkStackName: string;
ranId?: string;
description?: string;
isActive: boolean;
@ -13,13 +13,24 @@ export interface NetworkStackConfig {
updatedAt?: string;
createdBy: string;
updatedBy?: string;
stackCoreIMSBindings?: StackCoreIMSBinding[];
}
// 栈与核心网/IMS绑定关系接口
export interface StackCoreIMSBinding {
stackCoreIMSBindingId: string;
networkStackConfigId: string;
index: number;
coreNetworkConfigId: string;
imsConfigId: string;
createdAt: string;
}
// 获取网络栈配置列表请求接口
export interface GetNetworkStackConfigsRequest {
pageNumber?: number;
pageSize?: number;
searchTerm?: string;
networkStackName?: string; // 修改:使用 networkStackName 而不是 searchTerm
isActive?: boolean;
ranId?: string;
}
@ -32,43 +43,69 @@ export interface GetNetworkStackConfigsResponse {
totalPages: number;
hasPreviousPage: boolean;
hasNextPage: boolean;
items: NetworkStackConfig[];
networkStackConfigs: NetworkStackConfig[]; // 修改:使用 networkStackConfigs 而不是 items
}
// 创建网络栈配置请求接口
export interface CreateNetworkStackConfigRequest {
stackId: string;
networkStackName: string; // 修改:使用 networkStackName 而不是 stackId
ranId?: string;
description?: string;
isActive?: boolean;
stackCoreIMSBindings?: CreateStackCoreIMSBindingItem[];
}
// 栈与核心网/IMS绑定关系创建项
export interface CreateStackCoreIMSBindingItem {
index: number;
coreNetworkConfigId: string;
imsConfigId: string;
}
// 创建网络栈配置响应接口
export interface CreateNetworkStackConfigResponse {
networkStackConfigId: string;
stackId: string;
networkStackName: string;
ranId?: string;
description?: string;
isActive: boolean;
createdAt: string;
stackCoreIMSBindings: StackCoreIMSBinding[];
}
// 更新网络栈配置请求接口
export interface UpdateNetworkStackConfigRequest {
networkStackConfigId: string;
networkStackName?: string; // 修改:使用 networkStackName 而不是 stackId
ranId?: string;
description?: string;
isActive?: boolean;
stackCoreIMSBindings?: UpdateStackCoreIMSBindingItem[];
}
// 栈与核心网/IMS绑定关系更新项
export interface UpdateStackCoreIMSBindingItem {
index: number;
coreNetworkConfigId: string;
imsConfigId: string;
}
// 更新网络栈配置响应接口
export interface UpdateNetworkStackConfigResponse {
networkStackConfigId: string;
stackId: string;
networkStackName: string;
ranId?: string;
description?: string;
isActive: boolean;
updatedAt: string;
stackCoreIMSBindings: StackCoreIMSBinding[];
}
// 删除网络栈配置响应接口
export interface DeleteNetworkStackConfigResponse {
networkStackConfigId: string;
networkStackName: string;
deletedAt: string;
}
class NetworkStackConfigService {
@ -80,7 +117,7 @@ class NetworkStackConfigService {
if (params.pageNumber) queryParams.append('pageNumber', params.pageNumber.toString());
if (params.pageSize) queryParams.append('pageSize', params.pageSize.toString());
if (params.searchTerm) queryParams.append('searchTerm', params.searchTerm);
if (params.networkStackName) queryParams.append('networkStackName', params.networkStackName); // 修改:使用 networkStackName
if (params.isActive !== undefined) queryParams.append('isActive', params.isActive.toString());
if (params.ranId) queryParams.append('ranId', params.ranId);
@ -104,8 +141,8 @@ class NetworkStackConfigService {
}
// 删除网络栈配置
async deleteNetworkStackConfig(id: string): Promise<OperationResult<boolean>> {
return httpClient.delete<boolean>(`${this.baseUrl}/${id}`);
async deleteNetworkStackConfig(id: string): Promise<OperationResult<DeleteNetworkStackConfigResponse>> { // 修改:返回类型改为 DeleteNetworkStackConfigResponse
return httpClient.delete<DeleteNetworkStackConfigResponse>(`${this.baseUrl}/${id}`);
}
}

112
src/X1.WebUI/src/services/stackCoreIMSBindingService.ts

@ -1,112 +0,0 @@
import { httpClient } from '@/lib/http-client';
import { OperationResult } from '@/types/auth';
import { API_PATHS } from '@/constants/api';
// 栈核心网IMS绑定接口定义
export interface StackCoreIMSBinding {
stackCoreIMSBindingId: string;
stackId: string;
index: number;
cnId: string;
imsId: string;
createdAt: string;
updatedAt?: string;
createdBy: string;
updatedBy: string;
}
// 获取栈核心网IMS绑定列表请求接口
export interface GetStackCoreIMSBindingsRequest {
pageNumber?: number;
pageSize?: number;
stackId?: string;
cnId?: string;
imsId?: string;
}
// 获取栈核心网IMS绑定列表响应接口
export interface GetStackCoreIMSBindingsResponse {
totalCount: number;
pageNumber: number;
pageSize: number;
totalPages: number;
hasPreviousPage: boolean;
hasNextPage: boolean;
items: StackCoreIMSBinding[];
}
// 创建栈核心网IMS绑定请求接口
export interface CreateStackCoreIMSBindingRequest {
stackId: string;
index: number;
cnId: string;
imsId: string;
}
// 创建栈核心网IMS绑定响应接口
export interface CreateStackCoreIMSBindingResponse {
stackCoreIMSBindingId: string;
stackId: string;
index: number;
cnId: string;
imsId: string;
createdAt: string;
}
// 更新栈核心网IMS绑定请求接口
export interface UpdateStackCoreIMSBindingRequest {
stackCoreIMSBindingId: string;
index: number;
cnId: string;
imsId: string;
}
// 更新栈核心网IMS绑定响应接口
export interface UpdateStackCoreIMSBindingResponse {
stackCoreIMSBindingId: string;
stackId: string;
index: number;
cnId: string;
imsId: string;
updatedAt: string;
}
class StackCoreIMSBindingService {
private readonly baseUrl = API_PATHS.STACK_CORE_IMS_BINDINGS;
// 获取栈核心网IMS绑定列表
async getStackCoreIMSBindings(params: GetStackCoreIMSBindingsRequest = {}): Promise<OperationResult<GetStackCoreIMSBindingsResponse>> {
const queryParams = new URLSearchParams();
if (params.pageNumber) queryParams.append('pageNumber', params.pageNumber.toString());
if (params.pageSize) queryParams.append('pageSize', params.pageSize.toString());
if (params.stackId) queryParams.append('stackId', params.stackId);
if (params.cnId) queryParams.append('cnId', params.cnId);
if (params.imsId) queryParams.append('imsId', params.imsId);
const url = `${this.baseUrl}?${queryParams.toString()}`;
return httpClient.get<GetStackCoreIMSBindingsResponse>(url);
}
// 根据ID获取栈核心网IMS绑定详情
async getStackCoreIMSBindingById(id: string): Promise<OperationResult<StackCoreIMSBinding>> {
return httpClient.get<StackCoreIMSBinding>(`${this.baseUrl}/${id}`);
}
// 创建栈核心网IMS绑定
async createStackCoreIMSBinding(data: CreateStackCoreIMSBindingRequest): Promise<OperationResult<CreateStackCoreIMSBindingResponse>> {
return httpClient.post<CreateStackCoreIMSBindingResponse>(this.baseUrl, data);
}
// 更新栈核心网IMS绑定
async updateStackCoreIMSBinding(id: string, data: UpdateStackCoreIMSBindingRequest): Promise<OperationResult<UpdateStackCoreIMSBindingResponse>> {
return httpClient.put<UpdateStackCoreIMSBindingResponse>(`${this.baseUrl}/${id}`, data);
}
// 删除栈核心网IMS绑定
async deleteStackCoreIMSBinding(id: string): Promise<OperationResult<boolean>> {
return httpClient.delete<boolean>(`${this.baseUrl}/${id}`);
}
}
export const stackCoreIMSBindingService = new StackCoreIMSBindingService();

190
src/modify.md

@ -1966,49 +1966,147 @@ const createResult = await coreNetworkConfigService.createCoreNetworkConfig({
- 修复字段名称大小写问题,从 `CoreNetworkConfigId` 改为 `coreNetworkConfigId`
- 保持与后端数据结构的同步
## 2025-07-28
### 修复 instrumentService.ts 中的 protocolVersion 字段问题
#### 问题描述
- 前端 `instrumentService.ts` 中的设备接口定义包含了后端不存在的 `protocolVersion` 字段
- 创建设备和更新设备的请求接口中包含了后端命令中不存在的 `protocolVersionId` 字段
- 这导致前后端接口不匹配,可能引起运行时错误
#### 修复内容
1. **修复设备响应接口**
- 从 `Device` 接口中移除 `protocolVersion: string;` 字段
- 从 `CreateDeviceResponse` 接口中移除 `protocolVersion: string;` 字段
- 从 `UpdateDeviceResponse` 接口中移除 `protocolVersion: string;` 字段
2. **修复设备请求接口**
- 从 `CreateDeviceRequest` 接口中移除 `protocolVersionId: string;` 字段
- 从 `UpdateDeviceRequest` 接口中移除 `protocolVersionId: string;` 字段
3. **修复 DeviceForm 组件**
- 移除对 `protocolVersionId` 字段的状态管理
- 移除协议版本加载逻辑
- 移除协议版本选择表单字段
- 添加 `isEnabled``isRunning` 复选框字段
4. **修复 DevicesTable 组件**
- 移除对 `protocolVersion` 字段的渲染逻辑
- 更新表格字段映射关系注释
- 优化组件结构和样式
5. **修复 DevicesView 组件**
- 移除默认列配置中的 `protocolVersion` 字段
- 更新表格字段映射关系注释
- 移除编辑功能中对不存在字段的引用
#### 技术细节
- 后端设备实体 `CellularDevice` 通过 `ProtocolVersions` 集合与协议版本关联,而不是直接存储协议版本字符串
- 后端的设备响应模型(`GetDeviceByIdResponse`、`CreateDeviceResponse`、`UpdateDeviceResponse`)中没有 `protocolVersion` 字段
- 后端的设备命令(`CreateDeviceCommand`、`UpdateDeviceCommand`)中没有 `protocolVersionId` 字段
#### 影响范围
- 前端设备管理功能现在与后端API完全匹配
- 设备表单不再包含协议版本选择,简化了用户界面
- 设备与协议版本的关联关系需要在后续功能中单独处理
- 设备表格不再显示协议版本列,但保留了其他所有功能
## 2025-07-28 重构网络栈配置表单
### 重构内容
- **类型安全改进**:修复了表单类型不匹配问题,支持创建和编辑模式的不同类型
- **绑定关系管理**:添加了栈与核心网/IMS绑定关系的完整管理功能
- **表单验证**:添加了基本的表单验证,确保必填字段不为空
- **用户体验优化**:使用卡片布局,改进表单结构和交互体验
- **功能完整性**:支持添加、删除、编辑绑定关系
### 技术改进
- **类型系统**:使用联合类型 `CreateNetworkStackConfigRequest | UpdateNetworkStackConfigRequest`
- **状态管理**:使用 `useEffect` 处理初始数据变化
- **表单验证**:添加网络栈名称的必填验证
- **绑定管理**:实现完整的绑定关系CRUD操作
- **响应式设计**:使用网格布局适配不同屏幕尺寸
### 新增功能
- **绑定关系管理**
- 添加绑定关系
- 删除绑定关系
- 编辑绑定关系(索引、核心网配置ID、IMS配置ID)
- **表单验证**:网络栈名称必填验证
- **用户体验**
- 卡片式布局
- 绑定关系可视化
- 空状态提示
### 界面改进
- **基本信息卡片**:包含网络栈名称、RAN配置下拉框、描述、激活状态
- **绑定关系卡片**:包含绑定关系列表和添加按钮
- **绑定项**:每个绑定关系显示为独立的卡片项
- **操作按钮**:添加和删除绑定关系的按钮
### 2025-07-28 改进RAN配置选择
- **下拉框选择**:将RAN ID输入框改为下拉框,从ranConfigurationService获取数据
- **数据加载**:自动加载所有可用的RAN配置(未禁用的)
- **用户体验**:提供更直观的RAN配置选择方式
- **数据一致性**:确保选择的RAN配置ID与现有配置一致
- **错误修复**:修复Radix UI Select组件空值错误,使用"none"作为"无"选项的值
- **界面简化**:移除"激活此配置"复选框,默认激活状态
- **服务调用修复**:使用ranConfigurationService.getRANConfigurations()方法替代直接fetch调用
- **搜索功能增强**:为RAN配置下拉框添加搜索功能,支持按名称过滤配置
- **抽屉式界面**:创建NetworkStackConfigDrawer组件,采用抽屉形式替代对话框表单
- **清理冗余文件**:删除不再使用的NetworkStackConfigForm.tsx文件
- **RAN配置显示优化**:下拉框显示格式改为"名称 | 描述"的组合形式,提升用户识别度
- **搜索功能增强**:RAN配置搜索同时匹配名称和描述字段,提供更灵活的搜索体验
- **绑定关系索引优化**:索引自动从1开始递增,删除后自动重新排序,提升用户体验
- **绑定关系配置选择**:核心网配置ID和IMS配置ID改为下拉框,分别从coreNetworkConfigService和imsConfigurationService获取数据,支持搜索功能
- **布局优化**:栈与核心网/IMS绑定关系区域铺满剩余空白,内容支持纵向滚动
- **布局修复**:调整抽屉内容结构,确保绑定关系区域正确占据剩余空间并显示滚动条
- **列表化设计**:将栈与核心网/IMS绑定关系改为列表形式,更紧凑和直观
- **下拉框状态修复**:修复多个绑定项共享下拉框状态的问题,每个绑定项现在有独立的下拉框控制
- **下拉框互斥控制**:确保同时只有一个下拉框打开,点击任何下拉框都会关闭其他所有下拉框
- **自动关闭机制**:当鼠标离开下拉框区域时自动关闭所有下拉框,提升用户体验
- **悬停显示下拉框**:改为鼠标悬停显示下拉框,鼠标离开时自动关闭,提供更直观的交互体验
- **回退到点击交互**:由于悬停交互不够稳定,改回点击交互方式,优化点击外部关闭逻辑
- **滚动条优化**:修复绑定关系区域的滚动条显示问题,确保内容超出时正确显示滚动条
- **强制滚动高度**:为绑定关系区域设置明确的最大高度,确保滚动条正确显示
- **标签右对齐**:将核心网和IMS标签设置为右对齐,提升界面美观度
- **下拉框定位修复**:修复下拉框无法点击的问题,通过正确的定位和层级设置确保下拉框可以正常交互
- **点击外部关闭逻辑优化**:修复点击下拉框内容时意外关闭的问题,确保只有在真正点击外部时才关闭下拉框
- **绑定关系校验**:添加创建时的绑定关系完整性校验,确保每个绑定项都完整填写或完全为空,避免部分填写的情况
- **双重校验逻辑**:区分部分填写和完全空白两种情况,分别提示用户完成填写或移除绑定项
- **内联警告显示**:将校验错误信息显示在取消按钮左边,替代弹窗提示,提供更好的用户体验
- **RAN和绑定关系校验**:确保RAN配置和绑定关系至少选择一个,不能都不填写
## 2025-07-28 删除未使用的栈核心网IMS绑定服务
### 删除内容
- **删除文件**:`X1.WebUI/src/services/stackCoreIMSBindingService.ts` - 栈核心网IMS绑定管理服务
- **清理API路径**:从 `X1.WebUI/src/constants/api.ts` 中移除 `STACK_CORE_IMS_BINDINGS` 配置
### 删除原因
- 该服务没有被任何页面组件引用或使用
- 栈与核心网/IMS绑定关系管理已集成到网络栈配置服务中
- 避免代码冗余和维护负担
### 技术说明
- 栈与核心网/IMS绑定关系的接口定义已保留在 `networkStackConfigService.ts`
- 绑定关系的CRUD操作通过网络栈配置服务进行管理
- 保持了功能的完整性,只是简化了服务架构
## 2025-07-28 修复网络栈配置服务接口不匹配问题
### 问题描述
前端 `networkStackConfigService.ts` 中的接口定义与后端API不匹配,导致以下问题:
- 字段名称不匹配:前端使用 `stackId`,后端使用 `NetworkStackName`
- 搜索参数不匹配:前端使用 `searchTerm`,后端使用 `NetworkStackName`
- 响应结构不匹配:前端期望 `items` 字段,后端返回 `NetworkStackConfigs`
- 删除响应不匹配:前端期望返回 `boolean`,后端返回 `DeleteNetworkStackConfigResponse`
### 修复内容
#### 1. 修复前端接口定义
- **字段名称统一**
- `stackId``networkStackName`
- `searchTerm``networkStackName`
- `items``networkStackConfigs`
- **新增接口定义**
- 添加 `StackCoreIMSBinding` 接口
- 添加 `CreateStackCoreIMSBindingItem` 接口
- 添加 `UpdateStackCoreIMSBindingItem` 接口
- 添加 `DeleteNetworkStackConfigResponse` 接口
- **更新请求/响应接口**
- 所有接口中的 `stackId` 字段改为 `networkStackName`
- 添加 `stackCoreIMSBindings` 字段支持
- 删除操作返回类型改为 `DeleteNetworkStackConfigResponse`
#### 2. 修复页面组件
- **NetworkStackConfigsView.tsx**
- 更新搜索字段:`searchTerm` → `networkStackName`
- 更新表格列配置:`stackId` → `networkStackName`
- 修复所有字段引用和状态管理
- 更新表单提交处理逻辑
- **NetworkStackConfigForm.tsx**
- 更新表单字段:`stackId` → `networkStackName`
- 更新标签和占位符文本
- 修复表单状态管理
- **NetworkStackConfigsTable.tsx**
- 更新表格渲染逻辑:`stackId` → `networkStackName`
- 修复字段映射关系
#### 3. 技术细节
- **接口一致性**:确保前端接口定义与后端API完全匹配
- **类型安全**:提供完整的TypeScript类型定义
- **功能完整性**:支持栈与核心网/IMS绑定关系管理
- **错误处理**:保持统一的错误处理机制
### 影响范围
- **前端服务**:网络栈配置服务现在与后端API完全匹配
- **用户界面**:搜索、表格、表单功能正常工作
- **数据完整性**:所有CRUD操作都能正确处理数据
- **开发体验**:提供完整的类型安全和代码提示
### 测试建议
1. 测试网络栈配置的创建、编辑、删除功能
2. 验证搜索和过滤功能
3. 检查表格显示和分页功能
4. 确认表单验证和提交功能
5. 测试栈与核心网/IMS绑定关系管理
Loading…
Cancel
Save