Fix compilation errors and repository duplicate definitions

- Fixed duplicate repository definitions by removing separate files and keeping only main definitions
- Fixed IRepository SaveAsync method return type to match BaseRepository (Task<int>)
- Removed duplicate using statements and resolved type conflicts
- Fixed DeviceStatus enum issue in DbContext (changed to string property)
- Added missing LogEntry and TagMapping models
- Fixed TaskStatus naming conflicts in ScheduledTaskRepository
- Resolved duplicate ConversionRule class definition
- Fixed CNCDbContext references to use correct model namespaces
- Updated CNCBusinessDbContext to include missing TaskExecutionResults DbSet
- Build now succeeds with only warnings (no errors)
main
821644@qq.com 3 weeks ago
parent f53ba60b8b
commit aa3c532725

@ -0,0 +1,264 @@
# CNC机床数据采集分析系统 - 开发规范
## 🚀 项目概述
CNC机床多品牌统一化分布式数据采集分析系统实现设备状态监控、零件产量自动统计、加工过程分析、人员与设备绑定管理及BI大屏实时展示。
## 📋 技术栈
- **Backend**: .NET 6.0 WebApi (IIS部署)
- **Frontend**: Vue.js 管理后台 + BI大屏
- **Database**: MariaDB 10.6+ (本地部署,双库分离)
- **Real-Time**: SignalR WebSocket
- **Testing**: xUnit + Moq
- **Caching**: Memory Cache + Redis
## 🏗️ 项目结构
```
src/
├── Haoliang.Api/ # API接口层 (.NET 6.0)
│ ├── Controllers/ # API控制器
│ ├── Hubs/ # SignalR Hub
│ ├── Middleware/ # 中间件
│ └── Filters/ # 过滤器
├── Haoliang.Core/ # 业务逻辑层 (.NET 6.0)
│ └── Services/ # 业务服务
├── Haoliang.Data/ # 数据访问层 (.NET 6.0)
│ └── Repositories/ # 数据仓储
├── Haoliang.Models/ # 数据模型层 (.NET 6.0)
└── Haoliang.Tests/ # 单元测试 (.NET 6.0)
```
## 🔧 开发环境要求
### 必需组件
- .NET 6.0 SDK
- Visual Studio 2022 或 VS Code
- MySQL/MariaDB 10.6+
- Git
- Redis (可选,用于分布式缓存)
### IDE推荐配置
- C# Dev Kit 扩展
- IntelliCode C# 扩展
- GitLens 扩展
- Docker 扩展
## 📝 代码规范
### C# 代码规范
- 使用 PascalCase 命名空间和类名
- 使用 camelCase 参数和局部变量
- 使用 PascalCase 公共方法和属性
- 使用 _ 前缀表示私有字段
### API 设计规范
- RESTful API 设计
- 统一响应格式:`{ success, data, message, timestamp }`
- API 版本化:`/api/v1/`
- 状态码200(成功), 400(客户端错误), 500(服务器错误)
### 注释规范
- 使用 XML 文档注释
- 公共接口必须注释
- 复杂业务逻辑需要注释
- 使用英文注释
## 🔄 Git 工作流
### 强制要求每次修改必须提交到Git仓库
**仓库信息**:
- **仓库地址**: https://git.cjy.net.cn/jcl/haoliang.git
- **用户名**: 821644@qq.com
- **密码**: 123465a
### 提交规范
#### 1. 每次修改完成后必须执行以下步骤:
```bash
# 1. 查看当前状态
git status
# 2. 添加所有修改的文件
git add .
# 3. 查看即将提交的变更
git status
# 4. 创建提交(根据修改内容选择合适的类型)
git commit -m "类型: 简短描述
详细说明(可选)"
# 5. 推送到远程仓库
git push origin main
```
#### 2. 提交信息规范
**提交类型**:
- `feat`: 新功能
- `fix`: 修复bug
- `docs`: 文档更新
- `style`: 代码格式调整
- `refactor`: 代码重构
- `test`: 测试相关
- `chore`: 构建或辅助工具变动
**示例**:
```bash
git commit -m "feat: 添加生产统计功能
- 实现OEE计算
- 添加生产趋势分析
- 集成实时数据更新"
git commit -m "fix: 修复设备状态同步问题
- 解决WebSocket连接异常
- 优化状态机逻辑"
```
#### 3. 分支管理策略
**主分支**:
- `main`: 生产环境代码
**开发流程**:
```bash
# 创建功能分支
git checkout -b feature/user-management
# 开发完成后合并到main
git checkout main
git merge feature/user-management
# 删除分支
git branch -d feature/user-management
```
## 🧪 测试要求
### 单元测试
- 所有核心服务必须有单元测试
- 测试覆盖率不低于80%
- 使用 Moq 进行模拟测试
- 测试文件命名: `[ClassName]Tests.cs`
### 集成测试
- API端点必须有集成测试
- 使用 TestHost 进行测试
- 测试数据库连接和事务
### 测试命令
```bash
# 运行所有测试
dotnet test
# 运行特定测试
dotnet test --filter "ProductionServiceTests"
# 生成测试报告
dotnet test --collect:"XPlat Code Coverage"
```
## 🚀 部署要求
### 开发环境
- 使用 Docker Compose 快速启动
- 配置文件:`docker-compose.yml`
- 数据库迁移:`dotnet ef database update`
### 生产环境
- Windows Server 2019+
- IIS 10.0+
- .NET 6.0 运行时
- MariaDB 10.6+
### 性能要求
- 支持100+设备同时采集
- API响应时间 < 500ms
- WebSocket延迟 < 100ms
- 7×24小时稳定运行
## 🔒 安全要求
### 认证授权
- JWT Token 认证
- 角色基础访问控制(RBAC)
- 密码加密存储
### 数据安全
- 数据库连接字符串加密
- 敏感信息配置化
- 审计日志记录
### 网络安全
- HTTPS强制加密
- CORS跨域配置
- API限流保护
## 📊 监控和日志
### 日志级别
- **Error**: 系统错误和异常
- **Warning**: 警告和潜在问题
- **Information**: 重要业务操作
- **Debug**: 调试信息
### 性能监控
- 使用 Application Insights
- 关键指标监控
- 告警规则配置
## 🔄 代码审查流程
1. **开发完成** → 提交到Git
2. **自动构建** → CI/CD流水线
3. **自动化测试** → 单元测试+集成测试
4. **代码审查** → 团队成员Review
5. **部署上线** → 生产环境发布
## 📚 相关文档
- [API接口文档](https://git.cjy.net.cn/jcl/haoliang.git/blob/main/docs/api.md)
- [数据库设计文档](https://git.cjy.net.cn/jcl/haoliang.git/blob/main/docs/database.md)
- [部署运维文档](https://git.cjy.net.cn/jcl/haoliang.git/blob/main/docs/deployment.md)
- [用户操作手册](https://git.cjy.net.cn/jcl/haoliang.git/blob/main/docs/user-manual.md)
## 🆘 常见问题
### Git操作问题
```bash
# 解决Git认证问题
git config --global user.name "821644@qq.com"
git config --global user.password "123465a"
# 清理Git缓存
git rm -r --cached .
git add .
```
### 构建问题
```bash
# 清理解决方案
dotnet clean
dotnet restore
# 重新生成项目文件
dotnet build --force
```
### 数据库问题
```bash
# 更新数据库迁移
dotnet ef database update
# 创建新的迁移
dotnet ef migrations add MigrationName
```
---
**注意**: 本文档将随着项目发展持续更新,请定期查看最新版本。

@ -21,12 +21,12 @@
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.1.0" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="1.1.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="6.0.0" />
<PackageReference Include="StackExchange.Redis" Version="2.6.122" />
<PackageReference Include="Moq" Version="4.20.69" />
<PackageReference Include="xunit" Version="2.6.1" />
<PackageReference Include="Xunit.DependencyInjection" Version="7.6.2" />
<PackageReference Include="Xunit.DependencyInjection" Version="7.7.0" />
</ItemGroup>
<ItemGroup>

@ -1,5 +1,6 @@
using System;
using System.IO;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;

@ -1,6 +1,8 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Serilog;
using Serilog.Events;
using System;
using System.Collections.Generic;
using System.IO;
@ -19,6 +21,11 @@ namespace Haoliang.Api
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseSerilog((context, services, configuration) => configuration
.ReadFrom.Configuration(context.Configuration)
.Enrich.FromLogContext()
.WriteTo.Console()
.WriteTo.File("logs/app.log", rollingInterval: RollingInterval.Day))
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();

@ -6,12 +6,16 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Pomelo.EntityFrameworkCore.MySql;
using Haoliang.Core.Services;
using Haoliang.Api.Middleware;
using Haoliang.Data.Entities;
using Haoliang.Data.Repositories;
namespace Haoliang.Api
{
@ -81,8 +85,50 @@ namespace Haoliang.Api
{
// 配置数据库连接
var connectionString = Configuration.GetConnectionString("DefaultConnection");
services.AddDbContext<Haoliang.Data.Entities.CNCDbContext>(options =>
options.UseSqlServer(connectionString));
var businessConnectionString = Configuration.GetConnectionString("BusinessDbConnection");
// 业务数据库配置
if (!string.IsNullOrEmpty(businessConnectionString))
{
services.AddDbContext<CNCBusinessDbContext>(options =>
options.UseMySql(businessConnectionString,
ServerVersion.AutoDetect(businessConnectionString),
mysqlOptions => mysqlOptions.EnableRetryOnFailure(
maxRetryCount: 3,
maxRetryDelay: TimeSpan.FromSeconds(30),
errorNumbersToAdd: null)));
}
// 日志数据库配置
var logConnectionString = Configuration.GetConnectionString("LogDbConnection");
if (!string.IsNullOrEmpty(logConnectionString))
{
services.AddDbContext<CNCLLogDbContext>(options =>
options.UseMySql(logConnectionString,
ServerVersion.AutoDetect(logConnectionString),
mysqlOptions => mysqlOptions.EnableRetryOnFailure(
maxRetryCount: 3,
maxRetryDelay: TimeSpan.FromSeconds(30),
errorNumbersToAdd: null)));
}
// 注册主要数据库上下文(用于业务操作)
services.AddDbContext<CNCBusinessDbContext>(options =>
options.UseMySql(connectionString,
ServerVersion.AutoDetect(connectionString),
mysqlOptions => mysqlOptions.EnableRetryOnFailure(
maxRetryCount: 3,
maxRetryDelay: TimeSpan.FromSeconds(30),
errorNumbersToAdd: null)));
// 配置数据库连接池
services.AddDbContextPool<CNCBusinessDbContext>(options =>
options.UseMySql(connectionString,
ServerVersion.AutoDetect(connectionString),
mysqlOptions => mysqlOptions.EnableRetryOnFailure(
maxRetryCount: 3,
maxRetryDelay: TimeSpan.FromSeconds(30),
errorNumbersToAdd: null)));
// 配置内存缓存
services.AddMemoryCache();
@ -97,34 +143,60 @@ namespace Haoliang.Api
// 注册服务
services.AddScoped<IDeviceCollectionService, DeviceCollectionService>();
services.AddScoped<IProductionService, ProductionService>();
services.AddScoped<IProductionCalculator, ProductionCalculator>();
services.AddScoped<IProductionScheduler, ProductionScheduler>();
services.AddScoped<IAlarmService, AlarmManager>();
services.AddScoped<IAlarmRuleService, AlarmRuleService>();
services.AddScoped<IAlarmNotificationService, AlarmNotificationService>();
services.AddScoped<ITemplateService, TemplateManager>();
services.AddScoped<ISystemConfigService, SystemConfigManager>();
services.AddScoped<ILoggingService, LoggingManager>();
services.AddScoped<ISchedulerService, BackgroundTaskManager>();
services.AddScoped<ICachingService, CacheManager>();
services.AddScoped<ITagMappingService, TagMappingService>();
services.AddScoped<ITemplateValidationService, TemplateValidationService>();
services.AddScoped<ITemplateMigrationService, TemplateMigrationService>();
services.AddScoped<ILoggerService, ConsoleLoggerService>();
services.AddScoped<ICacheService, MemoryCacheService>();
services.AddScoped<IRealTimeService, RealTimeService>();
services.AddScoped<IDeviceStateMachine, DeviceStateMachine>();
services.AddScoped<IProductionStatisticsService, ProductionStatisticsService>();
services.AddScoped<IRulesService, RulesService>();
// 注册配置服务
services.AddScoped<ISystemService, SystemService>();
services.AddScoped<ISystemConfigService, SystemConfigService>();
// 注册中间件服务
services.AddScoped<IDeviceStateMachine, DeviceStateMachine>();
// 注册后台任务服务
services.AddHostedService<BackgroundTaskService>();
// 注册仓储
services.AddScoped<IDeviceRepository, DeviceRepository>();
services.AddScoped<ITemplateRepository, TemplateRepository>();
services.AddScoped<IProductionRepository, ProductionRepository>();
services.AddScoped<IProgramProductionSummaryRepository, ProgramProductionSummaryRepository>();
services.AddScoped<IProductionSummaryRepository, ProductionSummaryRepository>();
services.AddScoped<IAlarmRepository, AlarmRepository>();
services.AddScoped<IAlarmRuleRepository, AlarmRuleRepository>();
services.AddScoped<IAlarmNotificationRepository, AlarmNotificationRepository>();
services.AddScoped<ISystemRepository, SystemRepository>();
services.AddScoped<ICollectionRepository, CollectionRepository>();
services.AddScoped<ILogRepository, LogRepository>();
services.AddScoped<ISystemConfigRepository, SystemConfigRepository>();
services.AddScoped<ICollectionTaskRepository, CollectionTaskRepository>();
services.AddScoped<ICollectionResultRepository, CollectionResultRepository>();
services.AddScoped<ICollectionLogRepository, CollectionLogRepository>();
services.AddScoped<ILogRepository, LogRepository>();
services.AddScoped<IUserRepository, UserRepository>();
services.AddScoped<IProgramProductionSummaryRepository, ProgramProductionSummaryRepository>();
services.AddScoped<IProductionSummaryRepository, ProductionSummaryRepository>();
services.AddScoped<IAlarmNotificationRepository, AlarmNotificationRepository>();
services.AddScoped<ITagMappingRepository, TagMappingRepository>();
// 注册设备状态相关仓储
services.AddScoped<IDeviceStatusRepository, DeviceStatusRepository>();
// 注册Ping服务
services.AddScoped<IPingService, PingService>();
// 注册数据解析和存储服务
services.AddScoped<IDataParserService, DataParserService>();
services.AddScoped<IDataStorageService, DataStorageService>();
services.AddScoped<IRetryService, RetryService>();
// 注册SignalR Hub
services.AddSingleton<RealTimeHub>();

@ -56,6 +56,14 @@
"target": "Package",
"version": "[6.0.0, )"
},
"Microsoft.AspNetCore.SignalR": {
"target": "Package",
"version": "[1.1.0, )"
},
"Microsoft.AspNetCore.SignalR.Protocols.MessagePack": {
"target": "Package",
"version": "[1.1.0, )"
},
"Microsoft.EntityFrameworkCore.Design": {
"include": "Runtime, Build, Native, ContentFiles, Analyzers, BuildTransitive",
"suppressParent": "All",
@ -68,13 +76,37 @@
"target": "Package",
"version": "[7.0.2, )"
},
"Microsoft.Extensions.Caching.Memory": {
"target": "Package",
"version": "[7.0.0, )"
},
"Microsoft.Extensions.Caching.StackExchangeRedis": {
"target": "Package",
"version": "[6.0.0, )"
},
"Moq": {
"target": "Package",
"version": "[4.20.69, )"
},
"Pomelo.EntityFrameworkCore.MySql": {
"target": "Package",
"version": "[7.0.0, )"
},
"StackExchange.Redis": {
"target": "Package",
"version": "[2.6.122, )"
},
"Swashbuckle.AspNetCore": {
"target": "Package",
"version": "[6.5.0, )"
},
"Xunit.DependencyInjection": {
"target": "Package",
"version": "[7.7.0, )"
},
"xunit": {
"target": "Package",
"version": "[2.6.1, )"
}
},
"imports": [
@ -121,6 +153,9 @@
"net6.0": {
"targetAlias": "net6.0",
"projectReferences": {
"/root/opencode/haoliang/Haoliang.Data/Haoliang.Data.csproj": {
"projectPath": "/root/opencode/haoliang/Haoliang.Data/Haoliang.Data.csproj"
},
"/root/opencode/haoliang/Haoliang.Models/Haoliang.Models.csproj": {
"projectPath": "/root/opencode/haoliang/Haoliang.Models/Haoliang.Models.csproj"
}
@ -136,6 +171,36 @@
"frameworks": {
"net6.0": {
"targetAlias": "net6.0",
"dependencies": {
"BCrypt.Net-Next": {
"target": "Package",
"version": "[4.0.3, )"
},
"Microsoft.AspNetCore.Http.Abstractions": {
"target": "Package",
"version": "[2.2.0, )"
},
"Microsoft.AspNetCore.SignalR": {
"target": "Package",
"version": "[1.1.0, )"
},
"Microsoft.Extensions.Caching.Memory": {
"target": "Package",
"version": "[6.0.0, )"
},
"Microsoft.Extensions.Logging.Abstractions": {
"target": "Package",
"version": "[6.0.0, )"
},
"Microsoft.IdentityModel.Tokens": {
"target": "Package",
"version": "[6.26.0, )"
},
"System.IdentityModel.Tokens.Jwt": {
"target": "Package",
"version": "[6.26.0, )"
}
},
"imports": [
"net461",
"net462",
@ -177,9 +242,6 @@
"net6.0": {
"targetAlias": "net6.0",
"projectReferences": {
"/root/opencode/haoliang/Haoliang.Core/Haoliang.Core.csproj": {
"projectPath": "/root/opencode/haoliang/Haoliang.Core/Haoliang.Core.csproj"
},
"/root/opencode/haoliang/Haoliang.Models/Haoliang.Models.csproj": {
"projectPath": "/root/opencode/haoliang/Haoliang.Models/Haoliang.Models.csproj"
}
@ -198,19 +260,19 @@
"dependencies": {
"Microsoft.EntityFrameworkCore": {
"target": "Package",
"version": "[7.0.2, )"
"version": "[6.0.0, )"
},
"Microsoft.EntityFrameworkCore.Design": {
"target": "Package",
"version": "[7.0.2, )"
"version": "[6.0.0, )"
},
"Microsoft.EntityFrameworkCore.Tools": {
"target": "Package",
"version": "[7.0.2, )"
"version": "[6.0.0, )"
},
"Pomelo.EntityFrameworkCore.MySql": {
"target": "Package",
"version": "[7.0.0, )"
"version": "[6.0.0, )"
}
},
"imports": [

@ -13,12 +13,15 @@
<SourceRoot Include="/root/.nuget/packages/" />
</ItemGroup>
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<Import Project="$(NuGetPackageRoot)xunit.core/2.6.1/build/xunit.core.props" Condition="Exists('$(NuGetPackageRoot)xunit.core/2.6.1/build/xunit.core.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.extensions.apidescription.server/6.0.5/build/Microsoft.Extensions.ApiDescription.Server.props" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.apidescription.server/6.0.5/build/Microsoft.Extensions.ApiDescription.Server.props')" />
<Import Project="$(NuGetPackageRoot)swashbuckle.aspnetcore/6.5.0/build/Swashbuckle.AspNetCore.props" Condition="Exists('$(NuGetPackageRoot)swashbuckle.aspnetcore/6.5.0/build/Swashbuckle.AspNetCore.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.entityframeworkcore/7.0.2/buildTransitive/net6.0/Microsoft.EntityFrameworkCore.props" Condition="Exists('$(NuGetPackageRoot)microsoft.entityframeworkcore/7.0.2/buildTransitive/net6.0/Microsoft.EntityFrameworkCore.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.entityframeworkcore.design/7.0.2/build/net6.0/Microsoft.EntityFrameworkCore.Design.props" Condition="Exists('$(NuGetPackageRoot)microsoft.entityframeworkcore.design/7.0.2/build/net6.0/Microsoft.EntityFrameworkCore.Design.props')" />
</ImportGroup>
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<PkgXunit_DependencyInjection Condition=" '$(PkgXunit_DependencyInjection)' == '' ">/root/.nuget/packages/xunit.dependencyinjection/7.7.0</PkgXunit_DependencyInjection>
<Pkgxunit_analyzers Condition=" '$(Pkgxunit_analyzers)' == '' ">/root/.nuget/packages/xunit.analyzers/1.4.0</Pkgxunit_analyzers>
<PkgMicrosoft_Extensions_ApiDescription_Server Condition=" '$(PkgMicrosoft_Extensions_ApiDescription_Server)' == '' ">/root/.nuget/packages/microsoft.extensions.apidescription.server/6.0.5</PkgMicrosoft_Extensions_ApiDescription_Server>
<PkgMicrosoft_EntityFrameworkCore_Tools Condition=" '$(PkgMicrosoft_EntityFrameworkCore_Tools)' == '' ">/root/.nuget/packages/microsoft.entityframeworkcore.tools/7.0.2</PkgMicrosoft_EntityFrameworkCore_Tools>
</PropertyGroup>

@ -1,9 +1,11 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<Import Project="$(NuGetPackageRoot)system.text.json/7.0.0/buildTransitive/net6.0/System.Text.Json.targets" Condition="Exists('$(NuGetPackageRoot)system.text.json/7.0.0/buildTransitive/net6.0/System.Text.Json.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.extensions.apidescription.server/6.0.5/build/Microsoft.Extensions.ApiDescription.Server.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.apidescription.server/6.0.5/build/Microsoft.Extensions.ApiDescription.Server.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.extensions.options/8.0.2/buildTransitive/net6.0/Microsoft.Extensions.Options.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.options/8.0.2/buildTransitive/net6.0/Microsoft.Extensions.Options.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.extensions.logging.abstractions/8.0.2/buildTransitive/net6.0/Microsoft.Extensions.Logging.Abstractions.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.logging.abstractions/8.0.2/buildTransitive/net6.0/Microsoft.Extensions.Logging.Abstractions.targets')" />
<Import Project="$(NuGetPackageRoot)xunit.dependencyinjection/7.7.0/buildTransitive/netstandard2.0/Xunit.DependencyInjection.targets" Condition="Exists('$(NuGetPackageRoot)xunit.dependencyinjection/7.7.0/buildTransitive/netstandard2.0/Xunit.DependencyInjection.targets')" />
<Import Project="$(NuGetPackageRoot)xunit.core/2.6.1/build/xunit.core.targets" Condition="Exists('$(NuGetPackageRoot)xunit.core/2.6.1/build/xunit.core.targets')" />
<Import Project="$(NuGetPackageRoot)system.text.json/7.0.0/buildTransitive/net6.0/System.Text.Json.targets" Condition="Exists('$(NuGetPackageRoot)system.text.json/7.0.0/buildTransitive/net6.0/System.Text.Json.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.extensions.apidescription.server/6.0.5/build/Microsoft.Extensions.ApiDescription.Server.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.apidescription.server/6.0.5/build/Microsoft.Extensions.ApiDescription.Server.targets')" />
</ImportGroup>
</Project>

File diff suppressed because it is too large Load Diff

@ -1,16 +1,37 @@
{
"version": 2,
"dgSpecHash": "rf8aFVRiFQwg0xDg31tFCBl3lY9bGLl2JY9FWoCZLzcRy7s21dFiCjsegb24H1j4sj1KmlSdHAfbur13AerStw==",
"dgSpecHash": "iyYFED9MoYEL4mRTwzsS9YWC8COENma8aqxGbVOV+D866T8f96/0OL3jSTYUPkdcLCH7Yv7t5UUipEHM3Nkdxg==",
"success": true,
"projectFilePath": "/root/opencode/haoliang/Haoliang.Api/Haoliang.Api.csproj",
"expectedPackageFiles": [
"/root/.nuget/packages/bcrypt.net-next/4.0.3/bcrypt.net-next.4.0.3.nupkg.sha512",
"/root/.nuget/packages/castle.core/5.1.1/castle.core.5.1.1.nupkg.sha512",
"/root/.nuget/packages/humanizer.core/2.14.1/humanizer.core.2.14.1.nupkg.sha512",
"/root/.nuget/packages/messagepack/1.7.3.4/messagepack.1.7.3.4.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.authentication.abstractions/2.2.0/microsoft.aspnetcore.authentication.abstractions.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.authorization/2.2.0/microsoft.aspnetcore.authorization.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.authorization.policy/2.2.0/microsoft.aspnetcore.authorization.policy.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.connections.abstractions/2.2.0/microsoft.aspnetcore.connections.abstractions.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.cors/2.3.0/microsoft.aspnetcore.cors.2.3.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.hosting.abstractions/2.2.0/microsoft.aspnetcore.hosting.abstractions.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.hosting.server.abstractions/2.2.0/microsoft.aspnetcore.hosting.server.abstractions.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.http/2.2.0/microsoft.aspnetcore.http.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.http.abstractions/2.3.0/microsoft.aspnetcore.http.abstractions.2.3.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.http.connections/1.1.0/microsoft.aspnetcore.http.connections.1.1.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.http.connections.common/1.1.0/microsoft.aspnetcore.http.connections.common.1.1.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.http.extensions/2.3.0/microsoft.aspnetcore.http.extensions.2.3.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.http.features/2.3.0/microsoft.aspnetcore.http.features.2.3.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.jsonpatch/6.0.0/microsoft.aspnetcore.jsonpatch.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.mvc.newtonsoftjson/6.0.0/microsoft.aspnetcore.mvc.newtonsoftjson.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.routing/2.2.0/microsoft.aspnetcore.routing.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.routing.abstractions/2.2.0/microsoft.aspnetcore.routing.abstractions.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.signalr/1.1.0/microsoft.aspnetcore.signalr.1.1.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.signalr.common/1.1.0/microsoft.aspnetcore.signalr.common.1.1.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.signalr.core/1.1.0/microsoft.aspnetcore.signalr.core.1.1.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.signalr.protocols.json/1.1.0/microsoft.aspnetcore.signalr.protocols.json.1.1.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.signalr.protocols.messagepack/1.1.0/microsoft.aspnetcore.signalr.protocols.messagepack.1.1.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.websockets/2.2.0/microsoft.aspnetcore.websockets.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.webutilities/2.2.0/microsoft.aspnetcore.webutilities.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.csharp/4.7.0/microsoft.csharp.4.7.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.entityframeworkcore/7.0.2/microsoft.entityframeworkcore.7.0.2.nupkg.sha512",
"/root/.nuget/packages/microsoft.entityframeworkcore.abstractions/7.0.2/microsoft.entityframeworkcore.abstractions.7.0.2.nupkg.sha512",
@ -21,32 +42,133 @@
"/root/.nuget/packages/microsoft.extensions.apidescription.server/6.0.5/microsoft.extensions.apidescription.server.6.0.5.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.caching.abstractions/7.0.0/microsoft.extensions.caching.abstractions.7.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.caching.memory/7.0.0/microsoft.extensions.caching.memory.7.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.caching.stackexchangeredis/6.0.0/microsoft.extensions.caching.stackexchangeredis.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.configuration/2.1.0/microsoft.extensions.configuration.2.1.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.configuration.abstractions/8.0.0/microsoft.extensions.configuration.abstractions.8.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.dependencyinjection/7.0.0/microsoft.extensions.dependencyinjection.7.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.dependencyinjection.abstractions/8.0.2/microsoft.extensions.dependencyinjection.abstractions.8.0.2.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.dependencymodel/7.0.0/microsoft.extensions.dependencymodel.7.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.fileproviders.abstractions/8.0.0/microsoft.extensions.fileproviders.abstractions.8.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.fileproviders.physical/2.1.0/microsoft.extensions.fileproviders.physical.2.1.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.filesystemglobbing/2.1.0/microsoft.extensions.filesystemglobbing.2.1.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.hosting/2.1.0/microsoft.extensions.hosting.2.1.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.hosting.abstractions/2.2.0/microsoft.extensions.hosting.abstractions.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.logging/7.0.0/microsoft.extensions.logging.7.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.logging.abstractions/8.0.2/microsoft.extensions.logging.abstractions.8.0.2.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.objectpool/2.2.0/microsoft.extensions.objectpool.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.options/8.0.2/microsoft.extensions.options.8.0.2.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.primitives/8.0.0/microsoft.extensions.primitives.8.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.identitymodel.abstractions/6.26.0/microsoft.identitymodel.abstractions.6.26.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.identitymodel.jsonwebtokens/6.26.0/microsoft.identitymodel.jsonwebtokens.6.26.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.identitymodel.logging/6.26.0/microsoft.identitymodel.logging.6.26.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.identitymodel.tokens/6.26.0/microsoft.identitymodel.tokens.6.26.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.net.http.headers/2.3.0/microsoft.net.http.headers.2.3.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.netcore.platforms/2.0.0/microsoft.netcore.platforms.2.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.netcore.targets/1.1.0/microsoft.netcore.targets.1.1.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.openapi/1.2.3/microsoft.openapi.1.2.3.nupkg.sha512",
"/root/.nuget/packages/microsoft.win32.primitives/4.3.0/microsoft.win32.primitives.4.3.0.nupkg.sha512",
"/root/.nuget/packages/mono.texttemplating/2.2.1/mono.texttemplating.2.2.1.nupkg.sha512",
"/root/.nuget/packages/moq/4.20.69/moq.4.20.69.nupkg.sha512",
"/root/.nuget/packages/mysqlconnector/2.2.5/mysqlconnector.2.2.5.nupkg.sha512",
"/root/.nuget/packages/netstandard.library/1.6.1/netstandard.library.1.6.1.nupkg.sha512",
"/root/.nuget/packages/newtonsoft.json/13.0.1/newtonsoft.json.13.0.1.nupkg.sha512",
"/root/.nuget/packages/newtonsoft.json.bson/1.0.2/newtonsoft.json.bson.1.0.2.nupkg.sha512",
"/root/.nuget/packages/pipelines.sockets.unofficial/2.2.8/pipelines.sockets.unofficial.2.2.8.nupkg.sha512",
"/root/.nuget/packages/pomelo.entityframeworkcore.mysql/7.0.0/pomelo.entityframeworkcore.mysql.7.0.0.nupkg.sha512",
"/root/.nuget/packages/runtime.debian.8-x64.runtime.native.system.security.cryptography.openssl/4.3.0/runtime.debian.8-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"/root/.nuget/packages/runtime.fedora.23-x64.runtime.native.system.security.cryptography.openssl/4.3.0/runtime.fedora.23-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"/root/.nuget/packages/runtime.fedora.24-x64.runtime.native.system.security.cryptography.openssl/4.3.0/runtime.fedora.24-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"/root/.nuget/packages/runtime.native.system/4.3.0/runtime.native.system.4.3.0.nupkg.sha512",
"/root/.nuget/packages/runtime.native.system.io.compression/4.3.0/runtime.native.system.io.compression.4.3.0.nupkg.sha512",
"/root/.nuget/packages/runtime.native.system.net.http/4.3.0/runtime.native.system.net.http.4.3.0.nupkg.sha512",
"/root/.nuget/packages/runtime.native.system.security.cryptography.apple/4.3.0/runtime.native.system.security.cryptography.apple.4.3.0.nupkg.sha512",
"/root/.nuget/packages/runtime.native.system.security.cryptography.openssl/4.3.0/runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"/root/.nuget/packages/runtime.opensuse.13.2-x64.runtime.native.system.security.cryptography.openssl/4.3.0/runtime.opensuse.13.2-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"/root/.nuget/packages/runtime.opensuse.42.1-x64.runtime.native.system.security.cryptography.openssl/4.3.0/runtime.opensuse.42.1-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"/root/.nuget/packages/runtime.osx.10.10-x64.runtime.native.system.security.cryptography.apple/4.3.0/runtime.osx.10.10-x64.runtime.native.system.security.cryptography.apple.4.3.0.nupkg.sha512",
"/root/.nuget/packages/runtime.osx.10.10-x64.runtime.native.system.security.cryptography.openssl/4.3.0/runtime.osx.10.10-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"/root/.nuget/packages/runtime.rhel.7-x64.runtime.native.system.security.cryptography.openssl/4.3.0/runtime.rhel.7-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"/root/.nuget/packages/runtime.ubuntu.14.04-x64.runtime.native.system.security.cryptography.openssl/4.3.0/runtime.ubuntu.14.04-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"/root/.nuget/packages/runtime.ubuntu.16.04-x64.runtime.native.system.security.cryptography.openssl/4.3.0/runtime.ubuntu.16.04-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"/root/.nuget/packages/runtime.ubuntu.16.10-x64.runtime.native.system.security.cryptography.openssl/4.3.0/runtime.ubuntu.16.10-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"/root/.nuget/packages/stackexchange.redis/2.6.122/stackexchange.redis.2.6.122.nupkg.sha512",
"/root/.nuget/packages/swashbuckle.aspnetcore/6.5.0/swashbuckle.aspnetcore.6.5.0.nupkg.sha512",
"/root/.nuget/packages/swashbuckle.aspnetcore.swagger/6.5.0/swashbuckle.aspnetcore.swagger.6.5.0.nupkg.sha512",
"/root/.nuget/packages/swashbuckle.aspnetcore.swaggergen/6.5.0/swashbuckle.aspnetcore.swaggergen.6.5.0.nupkg.sha512",
"/root/.nuget/packages/swashbuckle.aspnetcore.swaggerui/6.5.0/swashbuckle.aspnetcore.swaggerui.6.5.0.nupkg.sha512",
"/root/.nuget/packages/system.appcontext/4.3.0/system.appcontext.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.buffers/4.6.0/system.buffers.4.6.0.nupkg.sha512",
"/root/.nuget/packages/system.codedom/4.4.0/system.codedom.4.4.0.nupkg.sha512",
"/root/.nuget/packages/system.collections/4.3.0/system.collections.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.collections.concurrent/4.3.0/system.collections.concurrent.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.console/4.3.0/system.console.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.diagnostics.debug/4.3.0/system.diagnostics.debug.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.diagnostics.diagnosticsource/8.0.1/system.diagnostics.diagnosticsource.8.0.1.nupkg.sha512",
"/root/.nuget/packages/system.diagnostics.eventlog/6.0.0/system.diagnostics.eventlog.6.0.0.nupkg.sha512",
"/root/.nuget/packages/system.diagnostics.tools/4.3.0/system.diagnostics.tools.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.diagnostics.tracing/4.3.0/system.diagnostics.tracing.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.globalization/4.3.0/system.globalization.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.globalization.calendars/4.3.0/system.globalization.calendars.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.globalization.extensions/4.3.0/system.globalization.extensions.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.identitymodel.tokens.jwt/6.26.0/system.identitymodel.tokens.jwt.6.26.0.nupkg.sha512",
"/root/.nuget/packages/system.io/4.3.0/system.io.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.io.compression/4.3.0/system.io.compression.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.io.compression.zipfile/4.3.0/system.io.compression.zipfile.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.io.filesystem/4.3.0/system.io.filesystem.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.io.filesystem.primitives/4.3.0/system.io.filesystem.primitives.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.io.pipelines/5.0.1/system.io.pipelines.5.0.1.nupkg.sha512",
"/root/.nuget/packages/system.linq/4.3.0/system.linq.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.linq.expressions/4.3.0/system.linq.expressions.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.net.http/4.3.0/system.net.http.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.net.primitives/4.3.0/system.net.primitives.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.net.sockets/4.3.0/system.net.sockets.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.net.websockets.websocketprotocol/4.5.1/system.net.websockets.websocketprotocol.4.5.1.nupkg.sha512",
"/root/.nuget/packages/system.objectmodel/4.3.0/system.objectmodel.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.reflection/4.3.0/system.reflection.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.reflection.emit/4.3.0/system.reflection.emit.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.reflection.emit.ilgeneration/4.3.0/system.reflection.emit.ilgeneration.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.reflection.emit.lightweight/4.3.0/system.reflection.emit.lightweight.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.reflection.extensions/4.3.0/system.reflection.extensions.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.reflection.primitives/4.3.0/system.reflection.primitives.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.reflection.typeextensions/4.3.0/system.reflection.typeextensions.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.resources.resourcemanager/4.3.0/system.resources.resourcemanager.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.runtime/4.3.0/system.runtime.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.runtime.compilerservices.unsafe/6.0.0/system.runtime.compilerservices.unsafe.6.0.0.nupkg.sha512",
"/root/.nuget/packages/system.runtime.extensions/4.3.0/system.runtime.extensions.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.runtime.handles/4.3.0/system.runtime.handles.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.runtime.interopservices/4.3.0/system.runtime.interopservices.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.runtime.interopservices.runtimeinformation/4.3.0/system.runtime.interopservices.runtimeinformation.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.runtime.numerics/4.3.0/system.runtime.numerics.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.runtime.serialization.primitives/4.3.0/system.runtime.serialization.primitives.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.security.cryptography.algorithms/4.3.0/system.security.cryptography.algorithms.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.security.cryptography.cng/4.5.0/system.security.cryptography.cng.4.5.0.nupkg.sha512",
"/root/.nuget/packages/system.security.cryptography.csp/4.3.0/system.security.cryptography.csp.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.security.cryptography.encoding/4.3.0/system.security.cryptography.encoding.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.security.cryptography.openssl/4.3.0/system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.security.cryptography.primitives/4.3.0/system.security.cryptography.primitives.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.security.cryptography.x509certificates/4.3.0/system.security.cryptography.x509certificates.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.security.principal.windows/4.5.0/system.security.principal.windows.4.5.0.nupkg.sha512",
"/root/.nuget/packages/system.text.encoding/4.3.0/system.text.encoding.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.text.encoding.extensions/4.3.0/system.text.encoding.extensions.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.text.encodings.web/8.0.0/system.text.encodings.web.8.0.0.nupkg.sha512",
"/root/.nuget/packages/system.text.json/7.0.0/system.text.json.7.0.0.nupkg.sha512"
"/root/.nuget/packages/system.text.json/7.0.0/system.text.json.7.0.0.nupkg.sha512",
"/root/.nuget/packages/system.text.regularexpressions/4.3.0/system.text.regularexpressions.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.threading/4.3.0/system.threading.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.threading.channels/4.5.0/system.threading.channels.4.5.0.nupkg.sha512",
"/root/.nuget/packages/system.threading.tasks/4.3.0/system.threading.tasks.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.threading.tasks.extensions/4.3.0/system.threading.tasks.extensions.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.threading.timer/4.3.0/system.threading.timer.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.valuetuple/4.3.0/system.valuetuple.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.xml.readerwriter/4.3.0/system.xml.readerwriter.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.xml.xdocument/4.3.0/system.xml.xdocument.4.3.0.nupkg.sha512",
"/root/.nuget/packages/xunit/2.6.1/xunit.2.6.1.nupkg.sha512",
"/root/.nuget/packages/xunit.abstractions/2.0.3/xunit.abstractions.2.0.3.nupkg.sha512",
"/root/.nuget/packages/xunit.analyzers/1.4.0/xunit.analyzers.1.4.0.nupkg.sha512",
"/root/.nuget/packages/xunit.assert/2.6.1/xunit.assert.2.6.1.nupkg.sha512",
"/root/.nuget/packages/xunit.core/2.6.1/xunit.core.2.6.1.nupkg.sha512",
"/root/.nuget/packages/xunit.dependencyinjection/7.7.0/xunit.dependencyinjection.7.7.0.nupkg.sha512",
"/root/.nuget/packages/xunit.extensibility.core/2.6.1/xunit.extensibility.core.2.6.1.nupkg.sha512",
"/root/.nuget/packages/xunit.extensibility.execution/2.6.1/xunit.extensibility.execution.2.6.1.nupkg.sha512"
],
"logs": []
}

@ -1,7 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Haoliang.Models.System;
using Haoliang.Models.Device;
using Haoliang.Models.DataCollection;
using Haoliang.Data.Repositories;
using Haoliang.Core.Services;
namespace Haoliang.Core.Services
{
@ -180,4 +185,464 @@ namespace Haoliang.Core.Services
return await _alarmRepository.GetByDeviceAndDateRangeAsync(deviceId, startDate, endDate);
}
}
public class AlarmRuleService : IAlarmRuleService
{
private readonly IAlarmRuleRepository _ruleRepository;
private readonly IAlarmRepository _alarmRepository;
private readonly IDeviceRepository _deviceRepository;
private readonly ILoggerService _logger;
public AlarmRuleService(
IAlarmRuleRepository ruleRepository,
IAlarmRepository alarmRepository,
IDeviceRepository deviceRepository,
ILoggerService logger)
{
_ruleRepository = ruleRepository;
_alarmRepository = alarmRepository;
_deviceRepository = deviceRepository;
_logger = logger;
}
public async Task<AlarmRule> CreateAlarmRuleAsync(AlarmRule rule)
{
rule.IsActive = true;
rule.CreateTime = DateTime.Now;
rule.UpdateTime = DateTime.Now;
return await _ruleRepository.AddAsync(rule);
}
public async Task<AlarmRule> UpdateAlarmRuleAsync(int ruleId, AlarmRule rule)
{
var existingRule = await _ruleRepository.GetByIdAsync(ruleId);
if (existingRule == null)
{
throw new KeyNotFoundException($"Alarm rule with ID {ruleId} not found");
}
rule.RuleId = ruleId;
rule.UpdateTime = DateTime.Now;
return await _ruleRepository.UpdateAsync(rule);
}
public async Task<bool> DeleteAlarmRuleAsync(int ruleId)
{
return await _ruleRepository.DeleteAsync(ruleId);
}
public async Task<AlarmRule> GetAlarmRuleByIdAsync(int ruleId)
{
return await _ruleRepository.GetByIdAsync(ruleId);
}
public async Task<IEnumerable<AlarmRule>> GetAllAlarmRulesAsync()
{
return await _ruleRepository.GetAllAsync();
}
public async Task<IEnumerable<AlarmRule>> GetActiveAlarmRulesAsync()
{
return await _ruleRepository.GetByStatusAsync(true);
}
public async Task<IEnumerable<AlarmRule>> GetRulesByDeviceAsync(int deviceId)
{
return await _ruleRepository.GetByDeviceIdAsync(deviceId);
}
public async Task<bool> EvaluateAlarmRuleAsync(AlarmRule rule, DeviceCurrentStatus status)
{
if (!rule.IsActive || status == null)
return false;
try
{
switch (rule.RuleType)
{
case AlarmRuleType.DeviceOffline:
return EvaluateDeviceOfflineRule(rule, status);
case AlarmRuleType.TemperatureHigh:
return EvaluateTemperatureRule(rule, status);
case AlarmRuleType.PressureHigh:
return EvaluatePressureRule(rule, status);
case AlarmRuleType.ProductionStop:
return EvaluateProductionStopRule(rule, status);
case AlarmRuleType.NetworkError:
return EvaluateNetworkErrorRule(rule, status);
default:
return false;
}
}
catch (Exception ex)
{
await _logger.LogErrorAsync($"Failed to evaluate alarm rule {rule.RuleId}: {ex.Message}");
return false;
}
}
public async Task<Alarm> GenerateAlarmFromRuleAsync(AlarmRule rule, DeviceCurrentStatus status)
{
var alarm = new Alarm
{
DeviceId = status.DeviceId,
DeviceCode = "", // Will be populated from device
AlarmType = rule.AlarmType,
Severity = rule.Severity,
Title = rule.AlarmTitle,
Description = rule.AlarmDescription,
AlarmStatus = AlarmStatus.Active,
RuleId = rule.RuleId,
CreateTime = DateTime.Now,
UpdateTime = DateTime.Now
};
// Get device code
var device = await _deviceRepository.GetByIdAsync(status.DeviceId);
if (device != null)
{
alarm.DeviceCode = device.DeviceCode;
}
return alarm;
}
public async Task TestAlarmRuleAsync(int ruleId)
{
var rule = await _ruleRepository.GetByIdAsync(ruleId);
if (rule == null)
throw new KeyNotFoundException($"Alarm rule with ID {ruleId} not found");
// Get a sample device status for testing
var devices = await _deviceRepository.GetAllAsync();
if (!devices.Any())
throw new Exception("No devices available for testing");
var sampleDevice = devices.First();
var deviceStatus = new DeviceCurrentStatus
{
DeviceId = sampleDevice.Id,
Status = "Running",
IsRunning = true,
NCProgram = "O1234",
CumulativeCount = 1000,
RecordTime = DateTime.Now
};
// Evaluate the rule
var shouldTrigger = await EvaluateAlarmRuleAsync(rule, deviceStatus);
if (shouldTrigger)
{
var alarm = await GenerateAlarmFromRuleAsync(rule, deviceStatus);
alarm.Title = $"Test Alarm: {rule.AlarmTitle}";
alarm.Description = $"This is a test alarm for rule '{rule.RuleName}'.";
await _alarmRepository.AddAsync(alarm);
await _alarmRepository.SaveAsync();
await _logger.LogInformationAsync($"Test alarm created for rule {rule.RuleId}");
}
else
{
await _logger.LogInformationAsync($"Rule {rule.RuleId} did not trigger alarm during test");
}
}
private bool EvaluateDeviceOfflineRule(AlarmRule rule, DeviceCurrentStatus status)
{
// Check if device status indicates offline
return status.Status?.ToLower() == "offline" ||
!status.IsRunning ||
string.IsNullOrEmpty(status.NCProgram);
}
private bool EvaluateTemperatureRule(AlarmRule rule, DeviceCurrentStatus status)
{
// Find temperature tag
var temperatureTag = status.Tags?.FirstOrDefault(t => t.Id?.Contains("temp") == true || t.Id?.Contains("温度") == true);
if (temperatureTag == null || temperatureTag.Value == null)
return false;
if (decimal.TryParse(temperatureTag.Value.ToString(), out decimal temperature))
{
return temperature > rule.ThresholdValue;
}
return false;
}
private bool EvaluatePressureRule(AlarmRule rule, DeviceCurrentStatus status)
{
// Find pressure tag
var pressureTag = status.Tags?.FirstOrDefault(t => t.Id?.Contains("pressure") == true || t.Id?.Contains("压力") == true);
if (pressureTag == null || pressureTag.Value == null)
return false;
if (decimal.TryParse(pressureTag.Value.ToString(), out decimal pressure))
{
return pressure > rule.ThresholdValue;
}
return false;
}
private bool EvaluateProductionStopRule(AlarmRule rule, DeviceCurrentStatus status)
{
// Check if device has been stopped for specified duration
var stopDuration = TimeSpan.FromMinutes(rule.ThresholdValue);
return !status.IsRunning &&
status.RecordTime < DateTime.Now.Subtract(stopDuration);
}
private bool EvaluateNetworkErrorRule(AlarmRule rule, DeviceCurrentStatus status)
{
// Check for network-related errors in status
return status.Tags?.Any(t => t.Id?.Contains("error") == true && t.Value?.ToString() == "1") == true;
}
}
public class AlarmNotificationService : IAlarmNotificationService
{
private readonly IAlarmNotificationRepository _notificationRepository;
private readonly IEmailService _emailService;
private readonly ISmsService _smsService;
private readonly IWechatService _wechatService;
private readonly ILoggerService _logger;
private readonly IDeviceRepository _deviceRepository;
public AlarmNotificationService(
IAlarmNotificationRepository notificationRepository,
IEmailService emailService,
ISmsService smsService,
IWechatService wechatService,
ILoggerService logger,
IDeviceRepository deviceRepository)
{
_notificationRepository = notificationRepository;
_emailService = emailService;
_smsService = smsService;
_wechatService = wechatService;
_logger = logger;
_deviceRepository = deviceRepository;
}
public async Task SendAlarmNotificationAsync(Alarm alarm)
{
try
{
var device = await _deviceRepository.GetByIdAsync(alarm.DeviceId);
var notificationChannels = await GetNotificationChannelsForDevice(alarm.DeviceId);
foreach (var channel in notificationChannels)
{
if (channel.IsEnabled)
{
await SendNotificationViaChannel(alarm, channel, device);
}
}
// Log the notification
await LogNotificationSent(alarm, notificationChannels.Count());
}
catch (Exception ex)
{
await _logger.LogErrorAsync($"Failed to send alarm notification for alarm {alarm.AlarmId}: {ex.Message}");
}
}
public async Task SendBulkAlarmNotificationsAsync(IEnumerable<Alarm> alarms)
{
foreach (var alarm in alarms)
{
await SendAlarmNotificationAsync(alarm);
}
}
public async Task<bool> SendSmsNotificationAsync(string phoneNumber, string message)
{
try
{
return await _smsService.SendSmsAsync(phoneNumber, message);
}
catch (Exception ex)
{
await _logger.LogErrorAsync($"Failed to send SMS to {phoneNumber}: {ex.Message}");
return false;
}
}
public async Task<bool> SendEmailNotificationAsync(string email, string subject, string message)
{
try
{
return await _emailService.SendEmailAsync(email, subject, message);
}
catch (Exception ex)
{
await _logger.LogErrorAsync($"Failed to send email to {email}: {ex.Message}");
return false;
}
}
public async Task<bool> SendWechatNotificationAsync(string openId, string message)
{
try
{
return await _wechatService.SendMessageAsync(openId, message);
}
catch (Exception ex)
{
await _logger.LogErrorAsync($"Failed to send WeChat message to {openId}: {ex.Message}");
return false;
}
}
public async Task<IEnumerable<AlarmNotification>> GetNotificationHistoryAsync(DateTime startDate, DateTime endDate)
{
return await _notificationRepository.GetByDateRangeAsync(startDate, endDate);
}
public async Task<bool> ConfigureNotificationChannelAsync(NotificationChannel channel)
{
// Validate channel configuration
if (!ValidateChannelConfiguration(channel))
return false;
// Save channel configuration
return await _notificationRepository.SaveChannelAsync(channel);
}
public async Task<IEnumerable<NotificationChannel>> GetAvailableChannelsAsync()
{
return await _notificationRepository.GetAllChannelsAsync();
}
private async Task<List<NotificationChannel>> GetNotificationChannelsForDevice(int deviceId)
{
// This would typically query the database for device-specific notification settings
// For now, return a default set of channels
return new List<NotificationChannel>
{
new NotificationChannel { ChannelType = NotificationChannelType.Email, IsEnabled = true },
new NotificationChannel { ChannelType = NotificationChannelType.Sms, IsEnabled = false },
new NotificationChannel { ChannelType = NotificationChannelType.WeChat, IsEnabled = false }
};
}
private async Task SendNotificationViaChannel(Alarm alarm, NotificationChannel channel, Device device)
{
var message = FormatAlarmMessage(alarm, device);
var subject = $"Alarm: {alarm.AlarmType} - {device?.DeviceCode}";
switch (channel.ChannelType)
{
case NotificationChannelType.Email:
if (!string.IsNullOrEmpty(channel.Recipient))
{
await SendEmailNotificationAsync(channel.Recipient, subject, message);
}
break;
case NotificationChannelType.Sms:
if (!string.IsNullOrEmpty(channel.Recipient))
{
await SendSmsNotificationAsync(channel.Recipient, message);
}
break;
case NotificationChannelType.WeChat:
if (!string.IsNullOrEmpty(channel.Recipient))
{
await SendWechatNotificationAsync(channel.Recipient, message);
}
break;
}
}
private string FormatAlarmMessage(Alarm alarm, Device device)
{
return $"🚨 Alarm Alert\n\n" +
$"Device: {device?.DeviceCode} ({device?.DeviceName})\n" +
$"Type: {alarm.AlarmType}\n" +
$"Severity: {alarm.Severity}\n" +
$"Title: {alarm.Title}\n" +
$"Description: {alarm.Description}\n" +
$"Time: {alarm.CreateTime:yyyy-MM-dd HH:mm:ss}\n" +
$"Device ID: {alarm.DeviceId}";
}
private bool ValidateChannelConfiguration(NotificationChannel channel)
{
switch (channel.ChannelType)
{
case NotificationChannelType.Email:
return !string.IsNullOrEmpty(channel.Recipient) && channel.Recipient.Contains("@");
case NotificationChannelType.Sms:
return !string.IsNullOrEmpty(channel.Recipient) && channel.Recipient.All(char.IsDigit);
case NotificationChannelType.WeChat:
return !string.IsNullOrEmpty(channel.Recipient);
default:
return false;
}
}
private async Task LogNotificationSent(Alarm alarm, int channelCount)
{
var notification = new AlarmNotification
{
AlarmId = alarm.AlarmId,
NotificationTime = DateTime.Now,
ChannelsUsed = channelCount,
Success = true
};
await _notificationRepository.AddNotificationAsync(notification);
}
}
// Additional supporting classes and interfaces
public interface IEmailService
{
Task<bool> SendEmailAsync(string email, string subject, string message);
}
public interface ISmsService
{
Task<bool> SendSmsAsync(string phoneNumber, string message);
}
public interface IWechatService
{
Task<bool> SendMessageAsync(string openId, string message);
}
public interface IAlarmRuleRepository
{
Task<AlarmRule> AddAsync(AlarmRule rule);
Task<AlarmRule> UpdateAsync(AlarmRule rule);
Task<bool> DeleteAsync(int ruleId);
Task<AlarmRule> GetByIdAsync(int ruleId);
Task<IEnumerable<AlarmRule>> GetAllAsync();
Task<IEnumerable<AlarmRule>> GetByStatusAsync(bool isActive);
Task<IEnumerable<AlarmRule>> GetByDeviceIdAsync(int deviceId);
}
public interface IAlarmNotificationRepository
{
Task<AlarmNotification> AddNotificationAsync(AlarmNotification notification);
Task<IEnumerable<AlarmNotification>> GetByDateRangeAsync(DateTime startDate, DateTime endDate);
Task<bool> SaveChannelAsync(NotificationChannel channel);
Task<IEnumerable<NotificationChannel>> GetAllChannelsAsync();
}
}

@ -0,0 +1,384 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Haoliang.Core.Services;
using Haoliang.Data.Repositories;
namespace Haoliang.Core.Services
{
public interface IBackgroundTaskService
{
Task StartAsync(CancellationToken cancellationToken);
Task StopAsync(CancellationToken cancellationToken);
}
public class BackgroundTaskService : BackgroundService, IBackgroundTaskService
{
private readonly ILogger<BackgroundTaskService> _logger;
private readonly IDeviceCollectionService _collectionService;
private readonly IProductionService _productionService;
private readonly IAlarmService _alarmService;
private readonly IRealTimeService _realTimeService;
private readonly ISchedulerService _schedulerService;
private readonly Timer _collectionTimer;
private Timer _productionTimer;
private Timer _alarmTimer;
private Timer _realTimeTimer;
private bool _isRunning;
public BackgroundTaskService(
ILogger<BackgroundTaskService> logger,
IDeviceCollectionService collectionService,
IProductionService productionService,
IAlarmService alarmService,
IRealTimeService realTimeService,
ISchedulerService schedulerService)
{
_logger = logger;
_collectionService = collectionService;
_productionService = productionService;
_alarmService = alarmService;
_realTimeService = realTimeService;
_schedulerService = schedulerService;
_isRunning = false;
_collectionTimer = new Timer(ExecuteCollectionTasks, null, TimeSpan.Zero, TimeSpan.FromMinutes(1));
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("Background Task Service is starting.");
_isRunning = true;
try
{
await StartTimers(stoppingToken);
while (!stoppingToken.IsCancellationRequested)
{
await Task.Delay(TimeSpan.FromSeconds(30), stoppingToken);
// Log service health
await LogServiceHealthAsync();
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Background Task Service encountered an error.");
}
finally
{
await StopTimersAsync();
_logger.LogInformation("Background Task Service is stopping.");
}
}
public async Task StartAsync(CancellationToken cancellationToken)
{
if (_isRunning)
return;
_logger.LogInformation("Starting background task service...");
try
{
// Start device collection
await _collectionService.CollectAllDevicesAsync();
_logger.LogInformation("Device collection started.");
// Start production calculation
await _productionService.CalculateAllProductionAsync();
_logger.LogInformation("Production calculation started.");
// Start alarm monitoring
var activeAlarms = await _alarmService.GetActiveAlarmsAsync();
if (activeAlarms.Any())
{
_logger.LogInformation($"Found {activeAlarms.Count()} active alarms.");
}
_isRunning = true;
_logger.LogInformation("Background task service started successfully.");
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to start background task service.");
throw;
}
}
public async Task StopAsync(CancellationToken cancellationToken)
{
if (!_isRunning)
return;
_logger.LogInformation("Stopping background task service...");
try
{
await StopTimersAsync();
_isRunning = false;
_logger.LogInformation("Background task service stopped successfully.");
}
catch (Exception ex)
{
_logger.LogError(ex, "Error while stopping background task service.");
throw;
}
}
private async void ExecuteCollectionTasks(object state)
{
if (!_isRunning)
return;
try
{
await _collectionService.CollectAllDevicesAsync();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error executing collection tasks.");
}
}
private async Task StartTimers(CancellationToken cancellationToken)
{
// Start production calculation timer (every 5 minutes)
_productionTimer = new Timer(async _ =>
{
if (!_isRunning) return;
try
{
await _productionService.CalculateAllProductionAsync();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in production calculation timer.");
}
}, null, TimeSpan.Zero, TimeSpan.FromMinutes(5));
// Start alarm monitoring timer (every 1 minute)
_alarmTimer = new Timer(async _ =>
{
if (!_isRunning) return;
try
{
var activeAlarms = await _alarmService.GetActiveAlarmsAsync();
_logger.LogInformation($"Monitoring {activeAlarms.Count()} active alarms.");
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in alarm monitoring timer.");
}
}, null, TimeSpan.Zero, TimeSpan.FromMinutes(1));
// Start real-time data push timer (every 30 seconds)
_realTimeTimer = new Timer(async _ =>
{
if (!_isRunning) return;
try
{
await _realTimeService.BroadcastDeviceStatusAsync();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in real-time data push timer.");
}
}, null, TimeSpan.Zero, TimeSpan.FromSeconds(30));
_logger.LogInformation("Background timers started.");
}
private async Task StopTimersAsync()
{
_collectionTimer?.Dispose();
_productionTimer?.Dispose();
_alarmTimer?.Dispose();
_realTimeTimer?.Dispose();
_logger.LogInformation("Background timers stopped.");
}
private async Task LogServiceHealthAsync()
{
try
{
var collectionHealth = await _collectionService.GetCollectionHealthAsync();
var deviceCount = await _collectionService.GetCollectionStatisticsAsync(DateTime.Today);
_logger.LogInformation($"Service Health - Devices: {collectionHealth.TotalDevices}, " +
$"Online: {collectionHealth.OnlineDevices}, " +
$"Success Rate: {collectionHealth.SuccessRate:F1}%, " +
$"Active Tasks: {collectionHealth.ActiveCollectionTasks}");
}
catch (Exception ex)
{
_logger.LogError(ex, "Error logging service health.");
}
}
}
public interface ISchedulerService
{
Task ScheduleDeviceCollectionAsync(int deviceId);
Task ScheduleProductionCalculationAsync(int deviceId);
Task ScheduleAlarmCheckAsync();
Task CancelScheduledTaskAsync(string taskId);
Task<IEnumerable<ScheduledTask>> GetScheduledTasksAsync();
}
public class BackgroundTaskManager : ISchedulerService
{
private readonly ILogger<BackgroundTaskManager> _logger;
private readonly IDeviceCollectionService _collectionService;
private readonly IProductionService _productionService;
private readonly IAlarmService _alarmService;
private readonly Dictionary<string, Timer> _scheduledTasks = new Dictionary<string, Timer>();
private readonly object _lock = new object();
public BackgroundTaskManager(
ILogger<BackgroundTaskManager> logger,
IDeviceCollectionService collectionService,
IProductionService productionService,
IAlarmService alarmService)
{
_logger = logger;
_collectionService = collectionService;
_productionService = productionService;
_alarmService = alarmService;
}
public async Task ScheduleDeviceCollectionAsync(int deviceId)
{
var taskId = $"collection_{deviceId}_{DateTime.Now:yyyyMMddHHmmss}";
lock (_lock)
{
if (_scheduledTasks.ContainsKey(taskId))
{
_scheduledTasks[taskId].Dispose();
}
var timer = new Timer(async _ =>
{
try
{
await _collectionService.CollectDeviceAsync(deviceId);
}
catch (Exception ex)
{
_logger.LogError(ex, $"Failed to execute scheduled collection for device {deviceId}");
}
}, null, TimeSpan.Zero, TimeSpan.FromMinutes(5));
_scheduledTasks[taskId] = timer;
}
_logger.LogInformation($"Scheduled device collection for device {deviceId} with task ID {taskId}");
}
public async Task ScheduleProductionCalculationAsync(int deviceId)
{
var taskId = $"production_{deviceId}_{DateTime.Now:yyyyMMddHHmmss}";
lock (_lock)
{
if (_scheduledTasks.ContainsKey(taskId))
{
_scheduledTasks[taskId].Dispose();
}
var timer = new Timer(async _ =>
{
try
{
await _productionService.CalculateProductionAsync(deviceId);
}
catch (Exception ex)
{
_logger.LogError(ex, $"Failed to execute scheduled production calculation for device {deviceId}");
}
}, null, TimeSpan.Zero, TimeSpan.FromMinutes(10));
_scheduledTasks[taskId] = timer;
}
_logger.LogInformation($"Scheduled production calculation for device {deviceId} with task ID {taskId}");
}
public async Task ScheduleAlarmCheckAsync()
{
var taskId = $"alarm_check_{DateTime.Now:yyyyMMddHHmmss}";
lock (_lock)
{
if (_scheduledTasks.ContainsKey(taskId))
{
_scheduledTasks[taskId].Dispose();
}
var timer = new Timer(async _ =>
{
try
{
var activeAlarms = await _alarmService.GetActiveAlarmsAsync();
_logger.LogInformation($"Alarm check completed: {activeAlarms.Count()} active alarms");
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to execute alarm check");
}
}, null, TimeSpan.Zero, TimeSpan.FromMinutes(2));
_scheduledTasks[taskId] = timer;
}
_logger.LogInformation($"Scheduled alarm check with task ID {taskId}");
}
public Task CancelScheduledTaskAsync(string taskId)
{
lock (_lock)
{
if (_scheduledTasks.TryGetValue(taskId, out var timer))
{
timer.Dispose();
_scheduledTasks.Remove(taskId);
_logger.LogInformation($"Cancelled scheduled task {taskId}");
return Task.CompletedTask;
}
}
_logger.LogWarning($"Attempted to cancel non-existent task {taskId}");
return Task.CompletedTask;
}
public Task<IEnumerable<ScheduledTask>> GetScheduledTasksAsync()
{
var tasks = _scheduledTasks.Keys.Select(key => new ScheduledTask
{
TaskId = key,
ScheduledTime = DateTime.Now,
Status = "Active"
}).ToList();
return Task.FromResult<IEnumerable<ScheduledTask>>(tasks);
}
}
public class ScheduledTask
{
public string TaskId { get; set; }
public DateTime ScheduledTime { get; set; }
public string Status { get; set; }
}
}

@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
namespace Haoliang.Core.Services
{
public class ConsoleLoggerService : ILoggerService
{
private readonly ILogger<ConsoleLoggerService> _logger;
public ConsoleLoggerService(ILogger<ConsoleLoggerService> logger)
{
_logger = logger;
}
public async Task LogInformationAsync(string message)
{
_logger.LogInformation(message);
await Task.CompletedTask;
}
public async Task LogWarningAsync(string message)
{
_logger.LogWarning(message);
await Task.CompletedTask;
}
public async Task LogErrorAsync(string message)
{
_logger.LogError(message);
await Task.CompletedTask;
}
public async Task LogDebugAsync(string message)
{
_logger.LogDebug(message);
await Task.CompletedTask;
}
}
}

@ -1,676 +1,356 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;
using Haoliang.Models.Device;
using Haoliang.Models.DataCollection;
using Haoliang.Models.Production;
using Haoliang.Models.System;
using Haoliang.Data.Repositories;
using Haoliang.Core.Services;
using Haoliang.Models.Models.Device;
using Haoliang.Models.Models.Production;
using Haoliang.Models.Models.System;
using Haoliang.Models.Common;
namespace Haoliang.Core.Services
{
public interface IRealTimeService
{
/// <summary>
/// Connect a client to WebSocket hub
/// </summary>
Task ConnectClientAsync(string connectionId, string userId, string clientType);
/// <summary>
/// Disconnect a client
/// </summary>
Task DisconnectClientAsync(string connectionId);
/// <summary>
/// Join a device monitoring group
/// </summary>
Task BroadcastDeviceStatusAsync();
Task BroadcastProductionDataAsync();
Task BroadcastAlarmDataAsync();
Task SendDeviceUpdateAsync(int deviceId, DeviceCurrentStatus status);
Task SendProductionUpdateAsync(int deviceId, ProductionRecord production);
Task SendAlarmUpdateAsync(Alarm alarm);
Task BroadcastSystemHealthAsync();
Task JoinDeviceGroupAsync(string connectionId, int deviceId);
/// <summary>
/// Leave a device monitoring group
/// </summary>
Task LeaveDeviceGroupAsync(string connectionId, int deviceId);
/// <summary>
/// Join a dashboard group
/// </summary>
Task JoinDashboardGroupAsync(string connectionId, string dashboardId);
/// <summary>
/// Leave a dashboard group
/// </summary>
Task LeaveDashboardGroupAsync(string connectionId, string dashboardId);
/// <summary>
/// Broadcast device status update
/// </summary>
Task BroadcastDeviceStatusAsync(DeviceStatusUpdate statusUpdate);
/// <summary>
/// Broadcast production update
/// </summary>
Task BroadcastProductionUpdateAsync(ProductionUpdate productionUpdate);
/// <summary>
/// Broadcast alert update
/// </summary>
Task BroadcastAlertAsync(AlertUpdate alertUpdate);
/// <summary>
/// Send system notification
/// </summary>
Task SendSystemNotificationAsync(SystemNotification notification);
/// <summary>
/// Send real-time dashboard data
/// </summary>
Task SendDashboardUpdateAsync(DashboardUpdate dashboardUpdate);
/// <summary>
/// Send command to specific client
/// </summary>
Task SendCommandToClientAsync(string connectionId, RealTimeCommand command);
/// <summary>
/// Broadcast command to all clients
/// </summary>
Task BroadcastCommandAsync(RealTimeCommand command);
/// <summary>
/// Get connected clients count
/// </summary>
Task<int> GetConnectedClientsCountAsync();
/// <summary>
/// Get connected clients by type
/// </summary>
Task<List<ClientInfo>> GetConnectedClientsByTypeAsync(string clientType);
/// <summary>
/// Get device monitoring status
/// </summary>
Task<DeviceMonitoringStatus> GetDeviceMonitoringStatusAsync(int deviceId);
/// <summary>
/// Start data streaming for device
/// </summary>
Task StartDeviceStreamingAsync(int deviceId, int intervalMs = 1000);
/// <summary>
/// Stop data streaming for device
/// </summary>
Task StopDeviceStreamingAsync(int deviceId);
/// <summary>
/// Get active streaming devices
/// </summary>
Task<List<int>> GetActiveStreamingDevicesAsync();
Task JoinAllDevicesGroupAsync(string connectionId);
Task LeaveAllDevicesGroupAsync(string connectionId);
}
public class RealTimeService : IRealTimeService
{
private readonly IHubContext<RealTimeHub> _hubContext;
private readonly IDeviceCollectionService _deviceCollectionService;
private readonly IProductionService _productionService;
private readonly IAlarmService _alarmService;
private readonly ICacheService _cacheService;
private readonly ConcurrentDictionary<string, ClientInfo> _connectedClients = new ConcurrentDictionary<string, ClientInfo>();
private readonly ConcurrentDictionary<int, DeviceStreamingInfo> _deviceStreaming = new ConcurrentDictionary<int, DeviceStreamingInfo>();
private readonly Timer _deviceStatusTimer;
private readonly Timer _productionTimer;
private readonly IDeviceRepository _deviceRepository;
private readonly IProductionRepository _productionRepository;
private readonly IAlarmRepository _alarmRepository;
private readonly ICollectionRepository _collectionRepository;
private readonly ILoggerService _logger;
private readonly Dictionary<string, HashSet<int>> _userDeviceGroups = new Dictionary<string, HashSet<int>>();
private readonly object _lock = new object();
public RealTimeService(
IHubContext<RealTimeHub> hubContext,
IDeviceCollectionService deviceCollectionService,
IProductionService productionService,
IAlarmService alarmService,
ICacheService cacheService)
IDeviceRepository deviceRepository,
IProductionRepository productionRepository,
IAlarmRepository alarmRepository,
ICollectionRepository collectionRepository,
ILoggerService logger)
{
_hubContext = hubContext;
_deviceCollectionService = deviceCollectionService;
_productionService = productionService;
_alarmService = alarmService;
_cacheService = cacheService;
// Start timers for periodic updates
_deviceStatusTimer = new Timer(UpdateDeviceStatuses, null, TimeSpan.Zero, TimeSpan.FromSeconds(30));
_productionTimer = new Timer(UpdateProductionData, null, TimeSpan.Zero, TimeSpan.FromSeconds(60));
_deviceRepository = deviceRepository;
_productionRepository = productionRepository;
_alarmRepository = alarmRepository;
_collectionRepository = collectionRepository;
_logger = logger;
}
public async Task ConnectClientAsync(string connectionId, string userId, string clientType)
public async Task BroadcastDeviceStatusAsync()
{
var clientInfo = new ClientInfo
{
ConnectionId = connectionId,
UserId = userId,
ClientType = clientType,
ConnectedAt = DateTime.UtcNow,
LastActivity = DateTime.UtcNow,
Groups = new HashSet<string>(),
DeviceGroups = new HashSet<int>()
};
_connectedClients.AddOrUpdate(connectionId, clientInfo, (key, existing) => clientInfo);
await _hubContext.Clients.Client(connectionId).SendAsync("ClientConnected", new
try
{
ClientId = connectionId,
UserId = userId,
ClientType = clientType,
Timestamp = DateTime.UtcNow
});
}
var devices = await _deviceRepository.GetAllAsync();
var deviceStatuses = new List<DeviceCurrentStatus>();
public async Task DisconnectClientAsync(string connectionId)
{
if (_connectedClients.TryRemove(connectionId, out var clientInfo))
{
// Remove from all groups
foreach (var group in clientInfo.Groups)
foreach (var device in devices)
{
await _hubContext.Groups.RemoveFromGroupAsync(connectionId, group);
var status = await GetDeviceCurrentStatusAsync(device.Id);
deviceStatuses.Add(status);
}
foreach (var deviceId in clientInfo.DeviceGroups)
{
await _hubContext.Groups.RemoveFromGroupAsync(connectionId, $"device_{deviceId}");
await _hubContext.Clients.All.SendAsync("ReceiveDeviceStatusUpdate", deviceStatuses);
_logger.LogDebug($"Broadcasted device status update for {deviceStatuses.Count} devices");
}
// Notify other clients
await _hubContext.Clients.AllExcept(connectionId).SendAsync("ClientDisconnected", new
catch (Exception ex)
{
ClientId = connectionId,
UserId = clientInfo.UserId,
Timestamp = DateTime.UtcNow
});
_logger.LogError(ex, "Failed to broadcast device status update");
}
}
public async Task JoinDeviceGroupAsync(string connectionId, int deviceId)
public async Task BroadcastProductionDataAsync()
{
if (_connectedClients.TryGetValue(connectionId, out var clientInfo))
try
{
clientInfo.DeviceGroups.Add(deviceId);
clientInfo.LastActivity = DateTime.UtcNow;
var devices = await _deviceRepository.GetAllAsync();
var productionData = new Dictionary<int, List<ProductionRecord>>();
await _hubContext.Groups.AddToGroupAsync(connectionId, $"device_{deviceId}");
// Send current device status
var deviceStatus = await _deviceCollectionService.GetDeviceCurrentStatusAsync(deviceId);
await _hubContext.Clients.Client(connectionId).SendAsync("DeviceStatusUpdated", new
foreach (var device in devices)
{
DeviceId = deviceId,
Status = deviceStatus.Status,
Timestamp = DateTime.UtcNow
});
}
var todayProductions = await _productionRepository.GetByDeviceAndDateAsync(device.Id, DateTime.Today);
productionData[device.Id] = todayProductions.ToList();
}
public async Task LeaveDeviceGroupAsync(string connectionId, int deviceId)
{
if (_connectedClients.TryGetValue(connectionId, out var clientInfo))
await _hubContext.Clients.All.SendAsync("ReceiveProductionUpdate", productionData);
_logger.LogDebug($"Broadcasted production data update for {devices.Count} devices");
}
catch (Exception ex)
{
clientInfo.DeviceGroups.Remove(deviceId);
await _hubContext.Groups.RemoveFromGroupAsync(connectionId, $"device_{deviceId}");
_logger.LogError(ex, "Failed to broadcast production data update");
}
}
public async Task JoinDashboardGroupAsync(string connectionId, string dashboardId)
public async Task BroadcastAlarmDataAsync()
{
if (_connectedClients.TryGetValue(connectionId, out var clientInfo))
try
{
clientInfo.Groups.Add($"dashboard_{dashboardId}");
clientInfo.LastActivity = DateTime.UtcNow;
await _hubContext.Groups.AddToGroupAsync(connectionId, $"dashboard_{dashboardId}");
var activeAlarms = await _alarmRepository.GetActiveAlarmsAsync();
var alarmData = activeAlarms.Select(a => new
{
a.AlarmId,
a.DeviceCode,
a.AlarmType,
a.Severity,
a.Title,
a.Description,
a.AlarmStatus,
a.CreateTime
}).ToList();
// Send current dashboard data
var dashboardUpdate = await GetDashboardUpdateAsync();
await _hubContext.Clients.Client(connectionId).SendAsync("DashboardUpdated", dashboardUpdate);
await _hubContext.Clients.All.SendAsync("ReceiveAlarmUpdate", alarmData);
_logger.LogDebug($"Broadcasted alarm data update for {alarmData.Count} alarms");
}
}
public async Task LeaveDashboardGroupAsync(string connectionId, string dashboardId)
{
if (_connectedClients.TryGetValue(connectionId, out var clientInfo))
catch (Exception ex)
{
clientInfo.Groups.Remove($"dashboard_{dashboardId}");
await _hubContext.Groups.RemoveFromGroupAsync(connectionId, $"dashboard_{dashboardId}");
_logger.LogError(ex, "Failed to broadcast alarm data update");
}
}
public async Task BroadcastDeviceStatusAsync(DeviceStatusUpdate statusUpdate)
public async Task SendDeviceUpdateAsync(int deviceId, DeviceCurrentStatus status)
{
await _hubContext.Clients.Group($"device_{statusUpdate.DeviceId}").SendAsync("DeviceStatusUpdated", statusUpdate);
// Also broadcast to dashboard groups
await _hubContext.Clients.Group("dashboard").SendAsync("DeviceStatusUpdated", statusUpdate);
}
public async Task BroadcastProductionUpdateAsync(ProductionUpdate productionUpdate)
try
{
await _hubContext.Clients.Group($"device_{productionUpdate.DeviceId}").SendAsync("ProductionUpdated", productionUpdate);
// Also broadcast to dashboard groups
await _hubContext.Clients.Group("dashboard").SendAsync("ProductionUpdated", productionUpdate);
await _hubContext.Clients.Group($"device_{deviceId}").SendAsync("ReceiveDeviceUpdate", status);
_logger.LogDebug($"Sent device update for device {deviceId}");
}
public async Task BroadcastAlertAsync(AlertUpdate alertUpdate)
{
await _hubContext.Clients.Group("dashboard").SendAsync("AlertUpdated", alertUpdate);
await _hubContext.Clients.Group("alerts").SendAsync("AlertUpdated", alertUpdate);
// Send to specific device groups if alert is device-specific
if (alertUpdate.DeviceId.HasValue)
catch (Exception ex)
{
await _hubContext.Clients.Group($"device_{alertUpdate.DeviceId.Value}").SendAsync("AlertUpdated", alertUpdate);
_logger.LogError(ex, $"Failed to send device update for device {deviceId}");
}
}
public async Task SendSystemNotificationAsync(SystemNotification notification)
public async Task SendProductionUpdateAsync(int deviceId, ProductionRecord production)
{
await _hubContext.Clients.Group("notifications").SendAsync("SystemNotification", notification);
}
public async Task SendDashboardUpdateAsync(DashboardUpdate dashboardUpdate)
try
{
await _hubContext.Clients.Group("dashboard").SendAsync("DashboardUpdated", dashboardUpdate);
await _hubContext.Clients.Group($"device_{deviceId}").SendAsync("ReceiveProductionUpdate", production);
await _hubContext.Clients.All.SendAsync("ReceiveGlobalProductionUpdate", production);
_logger.LogDebug($"Sent production update for device {deviceId}");
}
public async Task SendCommandToClientAsync(string connectionId, RealTimeCommand command)
catch (Exception ex)
{
await _hubContext.Clients.Client(connectionId).SendAsync("Command", command);
_logger.LogError(ex, $"Failed to send production update for device {deviceId}");
}
public async Task BroadcastCommandAsync(RealTimeCommand command)
{
await _hubContext.Clients.All.SendAsync("Command", command);
}
public async Task<int> GetConnectedClientsCountAsync()
public async Task SendAlarmUpdateAsync(Alarm alarm)
{
// Clean up inactive clients
var cutoffTime = DateTime.UtcNow.AddMinutes(-5);
var inactiveClients = _connectedClients.Values.Where(c => c.LastActivity < cutoffTime).ToList();
foreach (var client in inactiveClients)
try
{
await DisconnectClientAsync(client.ConnectionId);
}
return _connectedClients.Count;
await _hubContext.Clients.Group($"device_{alarm.DeviceId}").SendAsync("ReceiveAlarmUpdate", alarm);
await _hubContext.Clients.All.SendAsync("ReceiveGlobalAlarmUpdate", alarm);
_logger.LogDebug($"Sent alarm update for alarm {alarm.AlarmId}");
}
public async Task<List<ClientInfo>> GetConnectedClientsByTypeAsync(string clientType)
catch (Exception ex)
{
return _connectedClients.Values
.Where(c => c.ClientType.Equals(clientType, StringComparison.OrdinalIgnoreCase))
.ToList();
_logger.LogError(ex, $"Failed to send alarm update for alarm {alarm.AlarmId}");
}
public async Task<DeviceMonitoringStatus> GetDeviceMonitoringStatusAsync(int deviceId)
{
var streamingInfo = _deviceStreaming.GetValueOrDefault(deviceId);
var monitoringClients = _connectedClients.Values
.Count(c => c.DeviceGroups.Contains(deviceId));
return new DeviceMonitoringStatus
{
DeviceId = deviceId,
IsStreaming = streamingInfo != null,
StreamingIntervalMs = streamingInfo?.IntervalMs ?? 0,
MonitoringClients = monitoringClients,
StreamingStartedAt = streamingInfo?.StartedAt,
LastStreamingUpdate = streamingInfo?.LastUpdate
};
}
public async Task StartDeviceStreamingAsync(int deviceId, int intervalMs = 1000)
public async Task BroadcastSystemHealthAsync()
{
if (!_deviceStreaming.ContainsKey(deviceId))
try
{
var streamingInfo = new DeviceStreamingInfo
var onlineDevices = await _deviceRepository.CountOnlineDevicesAsync();
var activeAlarms = await _alarmRepository.CountActiveAlarmsAsync();
var totalProductions = await _productionRepository.CountTodayProductionsAsync();
var healthData = new
{
DeviceId = deviceId,
IntervalMs = intervalMs,
StartedAt = DateTime.UtcNow,
LastUpdate = DateTime.UtcNow,
IsRunning = true
Timestamp = DateTime.Now,
OnlineDevices = onlineDevices,
ActiveAlarms = activeAlarms,
TotalProductions = totalProductions,
SystemStatus = activeAlarms > 10 ? "Warning" : "Healthy"
};
_deviceStreaming.AddOrUpdate(deviceId, streamingInfo, (key, existing) => streamingInfo);
// Start streaming task
Task.Run(() => StreamDeviceData(deviceId, intervalMs));
await _hubContext.Clients.All.SendAsync("ReceiveSystemHealth", healthData);
_logger.LogDebug($"Broadcasted system health update");
}
}
public async Task StopDeviceStreamingAsync(int deviceId)
{
if (_deviceStreaming.TryRemove(deviceId, out var streamingInfo))
catch (Exception ex)
{
streamingInfo.IsRunning = false;
_logger.LogError(ex, "Failed to broadcast system health update");
}
}
public async Task<List<int>> GetActiveStreamingDevicesAsync()
{
return _deviceStreaming.Values
.Where(s => s.IsRunning)
.Select(s => s.DeviceId)
.ToList();
}
#region Private Methods
private void UpdateDeviceStatuses(object state)
{
Task.Run(async () =>
public async Task JoinDeviceGroupAsync(string connectionId, int deviceId)
{
try
{
var activeDevices = await _deviceCollectionService.GetAllActiveDevicesAsync();
foreach (var device in activeDevices)
lock (_lock)
{
var status = await _deviceCollectionService.GetDeviceCurrentStatusAsync(device.Id);
var statusUpdate = new DeviceStatusUpdate
if (!_userDeviceGroups.ContainsKey(connectionId))
{
DeviceId = device.Id,
DeviceName = device.Name,
Status = status.Status,
CurrentProgram = status.CurrentProgram,
Runtime = status.Runtime,
Timestamp = DateTime.UtcNow
};
await BroadcastDeviceStatusAsync(statusUpdate);
_userDeviceGroups[connectionId] = new HashSet<int>();
}
_userDeviceGroups[connectionId].Add(deviceId);
}
await _hubContext.Groups.AddToGroupAsync(connectionId, $"device_{deviceId}");
_logger.LogDebug($"Connection {connectionId} joined device group {deviceId}");
}
catch (Exception ex)
{
// Log error
Console.WriteLine($"Error updating device statuses: {ex.Message}");
_logger.LogError(ex, $"Failed to add connection {connectionId} to device group {deviceId}");
}
});
}
private void UpdateProductionData(object state)
{
Task.Run(async () =>
public async Task LeaveDeviceGroupAsync(string connectionId, int deviceId)
{
try
{
var date = DateTime.Today;
var devices = await _deviceCollectionService.GetAllActiveDevicesAsync();
foreach (var device in devices)
lock (_lock)
{
var production = await _productionService.GetDeviceProductionForDateAsync(device.Id, date);
var productionUpdate = new ProductionUpdate
if (_userDeviceGroups.ContainsKey(connectionId))
{
DeviceId = device.Id,
DeviceName = device.Name,
Quantity = production,
Timestamp = DateTime.UtcNow
};
await BroadcastProductionUpdateAsync(productionUpdate);
_userDeviceGroups[connectionId].Remove(deviceId);
if (_userDeviceGroups[connectionId].Count == 0)
{
_userDeviceGroups.Remove(connectionId);
}
}
}
await _hubContext.Groups.RemoveFromGroupAsync(connectionId, $"device_{deviceId}");
_logger.LogDebug($"Connection {connectionId} left device group {deviceId}");
}
catch (Exception ex)
{
// Log error
Console.WriteLine($"Error updating production data: {ex.Message}");
_logger.LogError(ex, $"Failed to remove connection {connectionId} from device group {deviceId}");
}
});
}
private async Task StreamDeviceData(int deviceId, int intervalMs)
public async Task JoinAllDevicesGroupAsync(string connectionId)
{
var streamingInfo = _deviceStreaming.GetValueOrDefault(deviceId);
if (streamingInfo == null || !streamingInfo.IsRunning)
return;
try
{
while (streamingInfo.IsRunning)
{
try
{
// Get current device status
var status = await _deviceCollectionService.GetDeviceCurrentStatusAsync(deviceId);
// Get current production data
var production = await _productionService.GetDeviceProductionForDateAsync(deviceId, DateTime.Today);
// Create streaming message
var streamingMessage = new DeviceStreamingMessage
{
DeviceId = deviceId,
DeviceName = status.DeviceName,
Status = status.Status,
CurrentProgram = status.CurrentProgram,
Runtime = status.Runtime,
Quantity = production,
Timestamp = DateTime.UtcNow,
IntervalMs = intervalMs
};
// Send to device group
await _hubContext.Clients.Group($"device_{deviceId}").SendAsync("DeviceStreamingData", streamingMessage);
// Update last streaming time
streamingInfo.LastUpdate = DateTime.UtcNow;
await _hubContext.Groups.AddToGroupAsync(connectionId, "all_devices");
_logger.LogDebug($"Connection {connectionId} joined all devices group");
}
catch (Exception ex)
{
// Log error but continue streaming
Console.WriteLine($"Error streaming device {deviceId} data: {ex.Message}");
_logger.LogError(ex, $"Failed to add connection {connectionId} to all devices group");
}
await Task.Delay(intervalMs);
}
public async Task LeaveAllDevicesGroupAsync(string connectionId)
{
try
{
await _hubContext.Groups.RemoveFromGroupAsync(connectionId, "all_devices");
_logger.LogDebug($"Connection {connectionId} left all devices group");
}
catch (Exception ex)
{
Console.WriteLine($"Device streaming task for device {deviceId} failed: {ex.Message}");
_logger.LogError(ex, $"Failed to remove connection {connectionId} from all devices group");
}
}
private async Task<DashboardUpdate> GetDashboardUpdateAsync()
private async Task<DeviceCurrentStatus> GetDeviceCurrentStatusAsync(int deviceId)
{
// Get dashboard summary from cache or service
var dashboardSummary = await _cacheService.GetOrSetDashboardSummaryAsync(DateTime.Today,
() => _productionService.GetDashboardSummaryAsync(new DashboardFilter { Date = DateTime.Today }));
var device = await _deviceRepository.GetByIdAsync(deviceId);
if (device == null)
return new DeviceCurrentStatus();
var latestCollection = await _collectionRepository.GetLatestDeviceStatusAsync(deviceId);
return new DashboardUpdate
return new DeviceCurrentStatus
{
Timestamp = DateTime.UtcNow,
TotalDevices = dashboardSummary.TotalDevices,
ActiveDevices = dashboardSummary.ActiveDevices,
OfflineDevices = dashboardSummary.OfflineDevices,
TotalProductionToday = dashboardSummary.TotalProductionToday,
TotalProductionThisWeek = dashboardSummary.TotalProductionThisWeek,
TotalProductionThisMonth = dashboardSummary.TotalProductionThisMonth,
OverallEfficiency = dashboardSummary.OverallEfficiency,
QualityRate = dashboardSummary.QualityRate,
DeviceSummaries = dashboardSummary.DeviceSummaries
DeviceId = deviceId,
DeviceCode = device.DeviceCode,
DeviceName = device.DeviceName,
Status = latestCollection?.Status ?? "Unknown",
IsRunning = latestCollection?.IsRunning ?? false,
NCProgram = latestCollection?.NCProgram ?? "",
CumulativeCount = latestCollection?.CumulativeCount ?? 0,
OperatingMode = latestCollection?.OperatingMode ?? "",
RecordTime = latestCollection?.RecordTime ?? DateTime.Now
};
}
#endregion
}
#region Supporting Models
// SignalR Hub for real-time communication
public class RealTimeHub : Hub
{
private readonly IRealTimeService _realTimeService;
private readonly ILoggerService _logger;
public RealTimeHub(IRealTimeService realTimeService)
public RealTimeHub(IRealTimeService realTimeService, ILoggerService logger)
{
_realTimeService = realTimeService;
_logger = logger;
}
public override async Task OnConnectedAsync()
{
_logger.LogInformation($"Connection {Context.ConnectionId} connected to RealTimeHub");
// Automatically join all devices group for new connections
await _realTimeService.JoinAllDevicesGroupAsync(Context.ConnectionId);
await base.OnConnectedAsync();
}
public override async Task OnDisconnectedAsync(Exception exception)
{
_logger.LogInformation($"Connection {Context.ConnectionId} disconnected from RealTimeHub");
// Clean up device group memberships
// Note: This is a simplified cleanup - in production you'd track which groups each user was in
await _realTimeService.LeaveAllDevicesGroupAsync(Context.ConnectionId);
await base.OnDisconnectedAsync(exception);
}
// Client methods that can be called from frontend
public async Task JoinDeviceGroup(int deviceId)
{
await _realTimeService.JoinDeviceGroupAsync(Context.ConnectionId, deviceId);
await Clients.Caller.SendAsync("JoinedDeviceGroup", new { DeviceId = deviceId });
await Clients.Caller.SendAsync("JoinedDeviceGroup", deviceId);
}
public async Task LeaveDeviceGroup(int deviceId)
{
await _realTimeService.LeaveDeviceGroupAsync(Context.ConnectionId, deviceId);
await Clients.Caller.SendAsync("LeftDeviceGroup", new { DeviceId = deviceId });
}
public async Task JoinDashboardGroup(string dashboardId)
{
await _realTimeService.JoinDashboardGroupAsync(Context.ConnectionId, dashboardId);
await Clients.Caller.SendAsync("JoinedDashboardGroup", new { DashboardId = dashboardId });
}
public async Task LeaveDashboardGroup(string dashboardId)
{
await _realTimeService.LeaveDashboardGroupAsync(Context.ConnectionId, dashboardId);
await Clients.Caller.SendAsync("LeftDashboardGroup", new { DashboardId = dashboardId });
}
public async Task RequestDeviceStreaming(int deviceId, int intervalMs = 1000)
{
await _realTimeService.StartDeviceStreamingAsync(deviceId, intervalMs);
await Clients.Caller.SendAsync("DeviceStreamingStarted", new { DeviceId = deviceId, IntervalMs = intervalMs });
}
public async Task StopDeviceStreaming(int deviceId)
{
await _realTimeService.StopDeviceStreamingAsync(deviceId);
await Clients.Caller.SendAsync("DeviceStreamingStopped", new { DeviceId = deviceId });
await Clients.Caller.SendAsync("LeftDeviceGroup", deviceId);
}
public async Task Ping()
public async Task RequestSystemHealth()
{
await Clients.Caller.SendAsync("Pong", new { Timestamp = DateTime.UtcNow });
}
await _realTimeService.BroadcastSystemHealthAsync();
}
public class ClientInfo
public async Task RequestDeviceStatus()
{
public string ConnectionId { get; set; }
public string UserId { get; set; }
public string ClientType { get; set; }
public DateTime ConnectedAt { get; set; }
public DateTime LastActivity { get; set; }
public HashSet<string> Groups { get; set; }
public HashSet<int> DeviceGroups { get; set; }
await _realTimeService.BroadcastDeviceStatusAsync();
}
public class DeviceStreamingInfo
public async Task RequestProductionData()
{
public int DeviceId { get; set; }
public int IntervalMs { get; set; }
public DateTime StartedAt { get; set; }
public DateTime LastUpdate { get; set; }
public bool IsRunning { get; set; }
await _realTimeService.BroadcastProductionDataAsync();
}
public class DeviceStatusUpdate
public async Task RequestAlarmData()
{
public int DeviceId { get; set; }
public string DeviceName { get; set; }
public DeviceStatus Status { get; set; }
public string CurrentProgram { get; set; }
public TimeSpan Runtime { get; set; }
public DateTime Timestamp { get; set; }
await _realTimeService.BroadcastAlarmDataAsync();
}
public class ProductionUpdate
{
public int DeviceId { get; set; }
public string DeviceName { get; set; }
public decimal Quantity { get; set; }
public DateTime Timestamp { get; set; }
}
public class AlertUpdate
{
public int? DeviceId { get; set; }
public string DeviceName { get; set; }
public string AlertType { get; set; }
public string Message { get; set; }
public DateTime Timestamp { get; set; }
public bool IsResolved { get; set; }
}
public class SystemNotification
{
public string NotificationType { get; set; }
public string Title { get; set; }
public string Message { get; set; }
public DateTime Timestamp { get; set; }
public Dictionary<string, object> Data { get; set; }
}
public class DashboardUpdate
{
public DateTime Timestamp { get; set; }
public int TotalDevices { get; set; }
public int ActiveDevices { get; set; }
public int OfflineDevices { get; set; }
public decimal TotalProductionToday { get; set; }
public decimal TotalProductionThisWeek { get; set; }
public decimal TotalProductionThisMonth { get; set; }
public decimal OverallEfficiency { get; set; }
public decimal QualityRate { get; set; }
public List<DeviceSummary> DeviceSummaries { get; set; }
}
public class RealTimeCommand
{
public string Command { get; set; }
public object Parameters { get; set; }
public DateTime Timestamp { get; set; }
public string CommandType { get; set; }
}
public class DeviceStreamingMessage
{
public int DeviceId { get; set; }
public string DeviceName { get; set; }
public DeviceStatus Status { get; set; }
public string CurrentProgram { get; set; }
public TimeSpan Runtime { get; set; }
public decimal Quantity { get; set; }
public DateTime Timestamp { get; set; }
public int IntervalMs { get; set; }
}
public class DeviceMonitoringStatus
{
public int DeviceId { get; set; }
public bool IsStreaming { get; set; }
public int StreamingIntervalMs { get; set; }
public int MonitoringClients { get; set; }
public DateTime? StreamingStartedAt { get; set; }
public DateTime? LastStreamingUpdate { get; set; }
}
#endregion
}

@ -0,0 +1,257 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Haoliang.Models.System;
using Haoliang.Data.Repositories;
namespace Haoliang.Core.Services
{
public interface ISystemConfigService
{
Task<SystemConfig> GetConfigAsync(string configKey);
Task<SystemConfig> SetConfigAsync(string configKey, string configValue);
Task<IEnumerable<SystemConfig>> GetAllConfigsAsync();
Task<bool> DeleteConfigAsync(string configKey);
Task<SystemConfig> GetOrCreateConfigAsync(string configKey, string defaultValue);
Task<bool> ValidateConfigAsync(SystemConfig config);
}
public class SystemConfigService : ISystemConfigService
{
private readonly ISystemConfigRepository _configRepository;
private readonly ILoggerService _logger;
public SystemConfigService(
ISystemConfigRepository configRepository,
ILoggerService logger)
{
_configRepository = configRepository;
_logger = logger;
}
public async Task<SystemConfig> GetConfigAsync(string configKey)
{
return await _configRepository.GetByKeyAsync(configKey);
}
public async Task<SystemConfig> SetConfigAsync(string configKey, string configValue)
{
var existingConfig = await _configRepository.GetByKeyAsync(configKey);
if (existingConfig != null)
{
// Update existing config
existingConfig.ConfigValue = configValue;
existingConfig.UpdateTime = DateTime.Now;
var updatedConfig = await _configRepository.UpdateAsync(existingConfig);
await _logger.LogInformationAsync($"Updated config '{configKey}' with new value");
return updatedConfig;
}
else
{
// Create new config
var newConfig = new SystemConfig
{
ConfigKey = configKey,
ConfigValue = configValue,
Description = $"Configuration for {configKey}",
CreatedAt = DateTime.Now,
UpdateTime = DateTime.Now
};
var createdConfig = await _configRepository.AddAsync(newConfig);
await _logger.LogInformationAsync($"Created new config '{configKey}'");
return createdConfig;
}
}
public async Task<IEnumerable<SystemConfig>> GetAllConfigsAsync()
{
return await _configRepository.GetAllAsync();
}
public async Task<bool> DeleteConfigAsync(string configKey)
{
var config = await _configRepository.GetByKeyAsync(configKey);
if (config != null)
{
var result = await _configRepository.DeleteAsync(config.ConfigId);
if (result)
{
await _logger.LogInformationAsync($"Deleted config '{configKey}'");
}
return result;
}
return false;
}
public async Task<SystemConfig> GetOrCreateConfigAsync(string configKey, string defaultValue)
{
var config = await GetConfigAsync(configKey);
if (config == null)
{
return await SetConfigAsync(configKey, defaultValue);
}
return config;
}
public async Task<bool> ValidateConfigAsync(SystemConfig config)
{
if (config == null)
{
await _logger.LogWarningAsync("System config validation failed: config is null");
return false;
}
if (string.IsNullOrEmpty(config.ConfigKey))
{
await _logger.LogWarningAsync("System config validation failed: config key is empty");
return false;
}
if (string.IsNullOrEmpty(config.ConfigValue))
{
await _logger.LogWarningAsync($"System config validation failed: config value is empty for key '{config.ConfigKey}'");
return false;
}
// Validate specific config keys
if (config.ConfigKey == "DailyProductionTarget" && !int.TryParse(config.ConfigValue, out _))
{
await _logger.LogWarningAsync($"System config validation failed: invalid DailyProductionTarget value '{config.ConfigValue}'");
return false;
}
if (config.ConfigKey == "CollectionInterval" && !int.TryParse(config.ConfigValue, out _))
{
await _logger.LogWarningAsync($"System config validation failed: invalid CollectionInterval value '{config.ConfigValue}'");
return false;
}
return true;
}
}
public class SystemConfigManager : ISystemConfigService
{
private readonly ISystemConfigRepository _configRepository;
private readonly ILoggerService _logger;
public SystemConfigManager(
ISystemConfigRepository configRepository,
ILoggerService logger)
{
_configRepository = configRepository;
_logger = logger;
}
public async Task<SystemConfig> GetConfigAsync(string configKey)
{
return await _configRepository.GetByKeyAsync(configKey);
}
public async Task<SystemConfig> SetConfigAsync(string configKey, string configValue)
{
return await new SystemConfigService(_configRepository, _logger).SetConfigAsync(configKey, configValue);
}
public async Task<IEnumerable<SystemConfig>> GetAllConfigsAsync()
{
return await _configRepository.GetAllAsync();
}
public async Task<bool> DeleteConfigAsync(string configKey)
{
return await _configRepository.DeleteByKeyAsync(configKey);
}
public async Task<SystemConfig> GetOrCreateConfigAsync(string configKey, string defaultValue)
{
return await new SystemConfigService(_configRepository, _logger).GetOrCreateConfigAsync(configKey, defaultValue);
}
public async Task<bool> ValidateConfigAsync(SystemConfig config)
{
return await new SystemConfigService(_configRepository, _logger).ValidateConfigAsync(config);
}
}
public class LoggingManager : ILoggingService
{
private readonly ILogRepository _logRepository;
private readonly ILoggerService _logger;
public LoggingManager(
ILogRepository logRepository,
ILoggerService logger)
{
_logRepository = logRepository;
_logger = logger;
}
public async Task LogInformationAsync(string message)
{
await _logRepository.LogAsync(message, "Information");
await _logger.LogInformationAsync(message);
}
public async Task LogWarningAsync(string message)
{
await _logRepository.LogAsync(message, "Warning");
await _logger.LogWarningAsync(message);
}
public async Task LogErrorAsync(string message)
{
await _logRepository.LogAsync(message, "Error");
await _logger.LogErrorAsync(message);
}
public async Task LogDebugAsync(string message)
{
await _logRepository.LogAsync(message, "Debug");
await _logger.LogDebugAsync(message);
}
public async Task LogExceptionAsync(Exception ex, string message)
{
var fullMessage = $"{message}: {ex.Message}\n{ex.StackTrace}";
await _logRepository.LogAsync(fullMessage, "Error");
await _logger.LogErrorAsync(fullMessage);
}
public async Task LogAsync(LogLevel level, string message)
{
await _logRepository.LogAsync(message, level.ToString());
await LogByLevel(level, message);
}
private async Task LogByLevel(LogLevel level, string message)
{
switch (level)
{
case LogLevel.Trace:
await _logger.LogDebugAsync(message);
break;
case LogLevel.Debug:
await _logger.LogDebugAsync(message);
break;
case LogLevel.Information:
await _logger.LogInformationAsync(message);
break;
case LogLevel.Warning:
await _logger.LogWarningAsync(message);
break;
case LogLevel.Error:
case LogLevel.Critical:
await _logger.LogErrorAsync(message);
break;
default:
await _logger.LogInformationAsync(message);
break;
}
}
}
}

File diff suppressed because it is too large Load Diff

@ -26,6 +26,9 @@
"net6.0": {
"targetAlias": "net6.0",
"projectReferences": {
"/root/opencode/haoliang/Haoliang.Data/Haoliang.Data.csproj": {
"projectPath": "/root/opencode/haoliang/Haoliang.Data/Haoliang.Data.csproj"
},
"/root/opencode/haoliang/Haoliang.Models/Haoliang.Models.csproj": {
"projectPath": "/root/opencode/haoliang/Haoliang.Models/Haoliang.Models.csproj"
}
@ -90,6 +93,80 @@
}
}
},
"/root/opencode/haoliang/Haoliang.Data/Haoliang.Data.csproj": {
"version": "1.0.0",
"restore": {
"projectUniqueName": "/root/opencode/haoliang/Haoliang.Data/Haoliang.Data.csproj",
"projectName": "Haoliang.Data",
"projectPath": "/root/opencode/haoliang/Haoliang.Data/Haoliang.Data.csproj",
"packagesPath": "/root/.nuget/packages/",
"outputPath": "/root/opencode/haoliang/Haoliang.Data/obj/",
"projectStyle": "PackageReference",
"configFilePaths": [
"/root/.nuget/NuGet/NuGet.Config"
],
"originalTargetFrameworks": [
"net6.0"
],
"sources": {
"https://api.nuget.org/v3/index.json": {}
},
"frameworks": {
"net6.0": {
"targetAlias": "net6.0",
"projectReferences": {
"/root/opencode/haoliang/Haoliang.Models/Haoliang.Models.csproj": {
"projectPath": "/root/opencode/haoliang/Haoliang.Models/Haoliang.Models.csproj"
}
}
}
},
"warningProperties": {
"warnAsError": [
"NU1605"
]
}
},
"frameworks": {
"net6.0": {
"targetAlias": "net6.0",
"dependencies": {
"Microsoft.EntityFrameworkCore": {
"target": "Package",
"version": "[6.0.0, )"
},
"Microsoft.EntityFrameworkCore.Design": {
"target": "Package",
"version": "[6.0.0, )"
},
"Microsoft.EntityFrameworkCore.Tools": {
"target": "Package",
"version": "[6.0.0, )"
},
"Pomelo.EntityFrameworkCore.MySql": {
"target": "Package",
"version": "[6.0.0, )"
}
},
"imports": [
"net461",
"net462",
"net47",
"net471",
"net472",
"net48"
],
"assetTargetFallback": true,
"warn": true,
"frameworkReferences": {
"Microsoft.NETCore.App": {
"privateAssets": "all"
}
},
"runtimeIdentifierGraphPath": "/usr/lib/dotnet/sdk/6.0.136/RuntimeIdentifierGraph.json"
}
}
},
"/root/opencode/haoliang/Haoliang.Models/Haoliang.Models.csproj": {
"version": "1.0.0",
"restore": {

@ -12,4 +12,7 @@
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<SourceRoot Include="/root/.nuget/packages/" />
</ItemGroup>
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<PkgMicrosoft_EntityFrameworkCore_Tools Condition=" '$(PkgMicrosoft_EntityFrameworkCore_Tools)' == '' ">/root/.nuget/packages/microsoft.entityframeworkcore.tools/6.0.0</PkgMicrosoft_EntityFrameworkCore_Tools>
</PropertyGroup>
</Project>

@ -11,6 +11,15 @@
"lib/net6.0/BCrypt.Net-Next.dll": {}
}
},
"Humanizer.Core/2.8.26": {
"type": "package",
"compile": {
"lib/netstandard2.0/Humanizer.dll": {}
},
"runtime": {
"lib/netstandard2.0/Humanizer.dll": {}
}
},
"Microsoft.AspNetCore.Authentication.Abstractions/2.2.0": {
"type": "package",
"dependencies": {
@ -304,6 +313,83 @@
"lib/netcoreapp2.0/_._": {}
}
},
"Microsoft.EntityFrameworkCore/6.0.0": {
"type": "package",
"dependencies": {
"Microsoft.EntityFrameworkCore.Abstractions": "6.0.0",
"Microsoft.EntityFrameworkCore.Analyzers": "6.0.0",
"Microsoft.Extensions.Caching.Memory": "6.0.0",
"Microsoft.Extensions.DependencyInjection": "6.0.0",
"Microsoft.Extensions.Logging": "6.0.0",
"System.Collections.Immutable": "6.0.0",
"System.Diagnostics.DiagnosticSource": "6.0.0"
},
"compile": {
"lib/net6.0/Microsoft.EntityFrameworkCore.dll": {}
},
"runtime": {
"lib/net6.0/Microsoft.EntityFrameworkCore.dll": {}
}
},
"Microsoft.EntityFrameworkCore.Abstractions/6.0.0": {
"type": "package",
"compile": {
"lib/net6.0/Microsoft.EntityFrameworkCore.Abstractions.dll": {}
},
"runtime": {
"lib/net6.0/Microsoft.EntityFrameworkCore.Abstractions.dll": {}
}
},
"Microsoft.EntityFrameworkCore.Analyzers/6.0.0": {
"type": "package",
"compile": {
"lib/netstandard2.0/_._": {}
},
"runtime": {
"lib/netstandard2.0/_._": {}
}
},
"Microsoft.EntityFrameworkCore.Design/6.0.0": {
"type": "package",
"dependencies": {
"Humanizer.Core": "2.8.26",
"Microsoft.EntityFrameworkCore.Relational": "6.0.0"
},
"compile": {
"lib/net6.0/Microsoft.EntityFrameworkCore.Design.dll": {}
},
"runtime": {
"lib/net6.0/Microsoft.EntityFrameworkCore.Design.dll": {}
},
"build": {
"build/net6.0/_._": {}
}
},
"Microsoft.EntityFrameworkCore.Relational/6.0.0": {
"type": "package",
"dependencies": {
"Microsoft.EntityFrameworkCore": "6.0.0",
"Microsoft.Extensions.Configuration.Abstractions": "6.0.0"
},
"compile": {
"lib/net6.0/Microsoft.EntityFrameworkCore.Relational.dll": {}
},
"runtime": {
"lib/net6.0/Microsoft.EntityFrameworkCore.Relational.dll": {}
}
},
"Microsoft.EntityFrameworkCore.Tools/6.0.0": {
"type": "package",
"dependencies": {
"Microsoft.EntityFrameworkCore.Design": "6.0.0"
},
"compile": {
"lib/net6.0/_._": {}
},
"runtime": {
"lib/net6.0/_._": {}
}
},
"Microsoft.Extensions.Caching.Abstractions/6.0.0": {
"type": "package",
"dependencies": {
@ -332,10 +418,10 @@
"lib/netstandard2.0/Microsoft.Extensions.Caching.Memory.dll": {}
}
},
"Microsoft.Extensions.Configuration.Abstractions/2.2.0": {
"Microsoft.Extensions.Configuration.Abstractions/6.0.0": {
"type": "package",
"dependencies": {
"Microsoft.Extensions.Primitives": "2.2.0"
"Microsoft.Extensions.Primitives": "6.0.0"
},
"compile": {
"lib/netstandard2.0/Microsoft.Extensions.Configuration.Abstractions.dll": {}
@ -344,6 +430,22 @@
"lib/netstandard2.0/Microsoft.Extensions.Configuration.Abstractions.dll": {}
}
},
"Microsoft.Extensions.DependencyInjection/6.0.0": {
"type": "package",
"dependencies": {
"Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
},
"compile": {
"lib/net6.0/Microsoft.Extensions.DependencyInjection.dll": {}
},
"runtime": {
"lib/net6.0/Microsoft.Extensions.DependencyInjection.dll": {}
},
"build": {
"buildTransitive/netcoreapp3.1/_._": {}
}
},
"Microsoft.Extensions.DependencyInjection.Abstractions/6.0.0": {
"type": "package",
"compile": {
@ -383,6 +485,22 @@
"lib/netstandard2.0/Microsoft.Extensions.Hosting.Abstractions.dll": {}
}
},
"Microsoft.Extensions.Logging/6.0.0": {
"type": "package",
"dependencies": {
"Microsoft.Extensions.DependencyInjection": "6.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
"Microsoft.Extensions.Logging.Abstractions": "6.0.0",
"Microsoft.Extensions.Options": "6.0.0",
"System.Diagnostics.DiagnosticSource": "6.0.0"
},
"compile": {
"lib/netstandard2.1/Microsoft.Extensions.Logging.dll": {}
},
"runtime": {
"lib/netstandard2.1/Microsoft.Extensions.Logging.dll": {}
}
},
"Microsoft.Extensions.Logging.Abstractions/6.0.0": {
"type": "package",
"compile": {
@ -514,6 +632,15 @@
"lib/netstandard1.0/_._": {}
}
},
"MySqlConnector/2.0.0": {
"type": "package",
"compile": {
"lib/net6.0/MySqlConnector.dll": {}
},
"runtime": {
"lib/net6.0/MySqlConnector.dll": {}
}
},
"Newtonsoft.Json/11.0.2": {
"type": "package",
"compile": {
@ -523,6 +650,20 @@
"lib/netstandard2.0/Newtonsoft.Json.dll": {}
}
},
"Pomelo.EntityFrameworkCore.MySql/6.0.0": {
"type": "package",
"dependencies": {
"Microsoft.EntityFrameworkCore.Relational": "[6.0.0, 7.0.0)",
"Microsoft.Extensions.DependencyInjection": "6.0.0",
"MySqlConnector": "2.0.0"
},
"compile": {
"lib/net6.0/Pomelo.EntityFrameworkCore.MySql.dll": {}
},
"runtime": {
"lib/net6.0/Pomelo.EntityFrameworkCore.MySql.dll": {}
}
},
"System.Buffers/4.5.0": {
"type": "package",
"compile": {
@ -532,6 +673,36 @@
"lib/netcoreapp2.0/_._": {}
}
},
"System.Collections.Immutable/6.0.0": {
"type": "package",
"dependencies": {
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
},
"compile": {
"lib/net6.0/System.Collections.Immutable.dll": {}
},
"runtime": {
"lib/net6.0/System.Collections.Immutable.dll": {}
},
"build": {
"buildTransitive/netcoreapp3.1/_._": {}
}
},
"System.Diagnostics.DiagnosticSource/6.0.0": {
"type": "package",
"dependencies": {
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
},
"compile": {
"lib/net6.0/System.Diagnostics.DiagnosticSource.dll": {}
},
"runtime": {
"lib/net6.0/System.Diagnostics.DiagnosticSource.dll": {}
},
"build": {
"buildTransitive/netcoreapp3.1/_._": {}
}
},
"System.IdentityModel.Tokens.Jwt/6.26.0": {
"type": "package",
"dependencies": {
@ -738,6 +909,23 @@
"ref/netstandard1.3/System.Threading.Tasks.dll": {}
}
},
"Haoliang.Data/1.0.0": {
"type": "project",
"framework": ".NETCoreApp,Version=v6.0",
"dependencies": {
"Haoliang.Models": "1.0.0",
"Microsoft.EntityFrameworkCore": "6.0.0",
"Microsoft.EntityFrameworkCore.Design": "6.0.0",
"Microsoft.EntityFrameworkCore.Tools": "6.0.0",
"Pomelo.EntityFrameworkCore.MySql": "6.0.0"
},
"compile": {
"bin/placeholder/Haoliang.Data.dll": {}
},
"runtime": {
"bin/placeholder/Haoliang.Data.dll": {}
}
},
"Haoliang.Models/1.0.0": {
"type": "project",
"framework": ".NETCoreApp,Version=v6.0",
@ -782,6 +970,22 @@
"readme.md"
]
},
"Humanizer.Core/2.8.26": {
"sha512": "OiKusGL20vby4uDEswj2IgkdchC1yQ6rwbIkZDVBPIR6al2b7n3pC91elBul9q33KaBgRKhbZH3+2Ur4fnWx2A==",
"type": "package",
"path": "humanizer.core/2.8.26",
"files": [
".nupkg.metadata",
".signature.p7s",
"humanizer.core.2.8.26.nupkg.sha512",
"humanizer.core.nuspec",
"lib/netstandard1.0/Humanizer.dll",
"lib/netstandard1.0/Humanizer.xml",
"lib/netstandard2.0/Humanizer.dll",
"lib/netstandard2.0/Humanizer.xml",
"logo.png"
]
},
"Microsoft.AspNetCore.Authentication.Abstractions/2.2.0": {
"sha512": "VloMLDJMf3n/9ic5lCBOa42IBYJgyB1JhzLsL68Zqg+2bEPWfGBj/xCJy/LrKTArN0coOcZp3wyVTZlx0y9pHQ==",
"type": "package",
@ -1116,6 +1320,101 @@
"version.txt"
]
},
"Microsoft.EntityFrameworkCore/6.0.0": {
"sha512": "BdHAtHzfQt3rltgSoYamSlHg2qawPtEDT677/bcSJlO8lQ/lj6XWlusM0TOt59O8Sbqm3hAC1a+4cEBxmv56pw==",
"type": "package",
"path": "microsoft.entityframeworkcore/6.0.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"Icon.png",
"lib/net6.0/Microsoft.EntityFrameworkCore.dll",
"lib/net6.0/Microsoft.EntityFrameworkCore.xml",
"microsoft.entityframeworkcore.6.0.0.nupkg.sha512",
"microsoft.entityframeworkcore.nuspec"
]
},
"Microsoft.EntityFrameworkCore.Abstractions/6.0.0": {
"sha512": "MrMLWEw4JsZdkVci0MkkGj+fSjZrXnm3m6UNuIEwytiAAIZPvJs3iPpnzfK4qM7np82W374voYm96q7QCdL0ow==",
"type": "package",
"path": "microsoft.entityframeworkcore.abstractions/6.0.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"Icon.png",
"lib/net6.0/Microsoft.EntityFrameworkCore.Abstractions.dll",
"lib/net6.0/Microsoft.EntityFrameworkCore.Abstractions.xml",
"microsoft.entityframeworkcore.abstractions.6.0.0.nupkg.sha512",
"microsoft.entityframeworkcore.abstractions.nuspec"
]
},
"Microsoft.EntityFrameworkCore.Analyzers/6.0.0": {
"sha512": "BqWBL05PUDKwPwLeQCJdc2R4cIUycXV9UmuSjYfux2fcgyet8I2eYnOWlA7NgsDwRVcxW26vxvNQ0wuc8UAcLA==",
"type": "package",
"path": "microsoft.entityframeworkcore.analyzers/6.0.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"Icon.png",
"analyzers/dotnet/cs/Microsoft.EntityFrameworkCore.Analyzers.dll",
"lib/netstandard2.0/_._",
"microsoft.entityframeworkcore.analyzers.6.0.0.nupkg.sha512",
"microsoft.entityframeworkcore.analyzers.nuspec"
]
},
"Microsoft.EntityFrameworkCore.Design/6.0.0": {
"sha512": "RFdomymyuPNffl+VPk7osdxCJQ0xlGuxr28ifdfFFNUaMK0OYiJOjr6w9z3kscOM2p2gdPWNI1IFUXllEyphow==",
"type": "package",
"path": "microsoft.entityframeworkcore.design/6.0.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"Icon.png",
"build/net6.0/Microsoft.EntityFrameworkCore.Design.props",
"lib/net6.0/Microsoft.EntityFrameworkCore.Design.dll",
"lib/net6.0/Microsoft.EntityFrameworkCore.Design.xml",
"microsoft.entityframeworkcore.design.6.0.0.nupkg.sha512",
"microsoft.entityframeworkcore.design.nuspec"
]
},
"Microsoft.EntityFrameworkCore.Relational/6.0.0": {
"sha512": "rTRzrSbkUXoCGijlT9O7oq7JfuaU1/+VFyfSBjADQuOsfa0FCrWeB8ybue5CDvO/D6uW0kvPvlKfY2kwxXOOdg==",
"type": "package",
"path": "microsoft.entityframeworkcore.relational/6.0.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"Icon.png",
"lib/net6.0/Microsoft.EntityFrameworkCore.Relational.dll",
"lib/net6.0/Microsoft.EntityFrameworkCore.Relational.xml",
"microsoft.entityframeworkcore.relational.6.0.0.nupkg.sha512",
"microsoft.entityframeworkcore.relational.nuspec"
]
},
"Microsoft.EntityFrameworkCore.Tools/6.0.0": {
"sha512": "m9e6nFnkyRdKcrTFO8rl3ZihCIKrYdECw+fHZVbKz6TBMwKhih/N0sjPnNt0k7sZPvI8izKPkh1d+z4OR2qgXQ==",
"type": "package",
"path": "microsoft.entityframeworkcore.tools/6.0.0",
"hasTools": true,
"files": [
".nupkg.metadata",
".signature.p7s",
"Icon.png",
"lib/net6.0/_._",
"microsoft.entityframeworkcore.tools.6.0.0.nupkg.sha512",
"microsoft.entityframeworkcore.tools.nuspec",
"tools/EntityFrameworkCore.PS2.psd1",
"tools/EntityFrameworkCore.PS2.psm1",
"tools/EntityFrameworkCore.psd1",
"tools/EntityFrameworkCore.psm1",
"tools/about_EntityFrameworkCore.help.txt",
"tools/init.ps1",
"tools/net461/any/ef.exe",
"tools/net461/win-x86/ef.exe",
"tools/netcoreapp2.0/any/ef.dll",
"tools/netcoreapp2.0/any/ef.runtimeconfig.json"
]
},
"Microsoft.Extensions.Caching.Abstractions/6.0.0": {
"sha512": "bcz5sSFJbganH0+YrfvIjJDIcKNW7TL07C4d1eTmXy/wOt52iz4LVogJb6pazs7W0+74j0YpXFErvp++Aq5Bsw==",
"type": "package",
@ -1154,17 +1453,48 @@
"useSharedDesignerContext.txt"
]
},
"Microsoft.Extensions.Configuration.Abstractions/2.2.0": {
"sha512": "65MrmXCziWaQFrI0UHkQbesrX5wTwf9XPjY5yFm/VkgJKFJ5gqvXRoXjIZcf2wLi5ZlwGz/oMYfyURVCWbM5iw==",
"Microsoft.Extensions.Configuration.Abstractions/6.0.0": {
"sha512": "qWzV9o+ZRWq+pGm+1dF+R7qTgTYoXvbyowRoBxQJGfqTpqDun2eteerjRQhq5PQ/14S+lqto3Ft4gYaRyl4rdQ==",
"type": "package",
"path": "microsoft.extensions.configuration.abstractions/2.2.0",
"path": "microsoft.extensions.configuration.abstractions/6.0.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"Icon.png",
"LICENSE.TXT",
"THIRD-PARTY-NOTICES.TXT",
"lib/net461/Microsoft.Extensions.Configuration.Abstractions.dll",
"lib/net461/Microsoft.Extensions.Configuration.Abstractions.xml",
"lib/netstandard2.0/Microsoft.Extensions.Configuration.Abstractions.dll",
"lib/netstandard2.0/Microsoft.Extensions.Configuration.Abstractions.xml",
"microsoft.extensions.configuration.abstractions.2.2.0.nupkg.sha512",
"microsoft.extensions.configuration.abstractions.nuspec"
"microsoft.extensions.configuration.abstractions.6.0.0.nupkg.sha512",
"microsoft.extensions.configuration.abstractions.nuspec",
"useSharedDesignerContext.txt"
]
},
"Microsoft.Extensions.DependencyInjection/6.0.0": {
"sha512": "k6PWQMuoBDGGHOQTtyois2u4AwyVcIwL2LaSLlTZQm2CYcJ1pxbt6jfAnpWmzENA/wfrYRI/X9DTLoUkE4AsLw==",
"type": "package",
"path": "microsoft.extensions.dependencyinjection/6.0.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"Icon.png",
"LICENSE.TXT",
"THIRD-PARTY-NOTICES.TXT",
"buildTransitive/netcoreapp2.0/Microsoft.Extensions.DependencyInjection.targets",
"buildTransitive/netcoreapp3.1/_._",
"lib/net461/Microsoft.Extensions.DependencyInjection.dll",
"lib/net461/Microsoft.Extensions.DependencyInjection.xml",
"lib/net6.0/Microsoft.Extensions.DependencyInjection.dll",
"lib/net6.0/Microsoft.Extensions.DependencyInjection.xml",
"lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.dll",
"lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.xml",
"lib/netstandard2.1/Microsoft.Extensions.DependencyInjection.dll",
"lib/netstandard2.1/Microsoft.Extensions.DependencyInjection.xml",
"microsoft.extensions.dependencyinjection.6.0.0.nupkg.sha512",
"microsoft.extensions.dependencyinjection.nuspec",
"useSharedDesignerContext.txt"
]
},
"Microsoft.Extensions.DependencyInjection.Abstractions/6.0.0": {
@ -1218,6 +1548,27 @@
"microsoft.extensions.hosting.abstractions.nuspec"
]
},
"Microsoft.Extensions.Logging/6.0.0": {
"sha512": "eIbyj40QDg1NDz0HBW0S5f3wrLVnKWnDJ/JtZ+yJDFnDj90VoPuoPmFkeaXrtu+0cKm5GRAwoDf+dBWXK0TUdg==",
"type": "package",
"path": "microsoft.extensions.logging/6.0.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"Icon.png",
"LICENSE.TXT",
"THIRD-PARTY-NOTICES.TXT",
"lib/net461/Microsoft.Extensions.Logging.dll",
"lib/net461/Microsoft.Extensions.Logging.xml",
"lib/netstandard2.0/Microsoft.Extensions.Logging.dll",
"lib/netstandard2.0/Microsoft.Extensions.Logging.xml",
"lib/netstandard2.1/Microsoft.Extensions.Logging.dll",
"lib/netstandard2.1/Microsoft.Extensions.Logging.xml",
"microsoft.extensions.logging.6.0.0.nupkg.sha512",
"microsoft.extensions.logging.nuspec",
"useSharedDesignerContext.txt"
]
},
"Microsoft.Extensions.Logging.Abstractions/6.0.0": {
"sha512": "/HggWBbTwy8TgebGSX5DBZ24ndhzi93sHUBDvP1IxbZD7FDokYzdAr6+vbWGjw2XAfR2EJ1sfKUotpjHnFWPxA==",
"type": "package",
@ -1458,6 +1809,35 @@
"runtime.json"
]
},
"MySqlConnector/2.0.0": {
"sha512": "EY0KXqQas+QvdZQU0NPkqBSfJitWAl8IUCg0v/Qn0P7f/KApJTFJFm8czYWoDPyewUjPHrAnE/cSYzzSFGc8Ng==",
"type": "package",
"path": "mysqlconnector/2.0.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"README.md",
"lib/net45/MySqlConnector.dll",
"lib/net45/MySqlConnector.xml",
"lib/net461/MySqlConnector.dll",
"lib/net461/MySqlConnector.xml",
"lib/net471/MySqlConnector.dll",
"lib/net471/MySqlConnector.xml",
"lib/net5.0/MySqlConnector.dll",
"lib/net5.0/MySqlConnector.xml",
"lib/net6.0/MySqlConnector.dll",
"lib/net6.0/MySqlConnector.xml",
"lib/netcoreapp3.1/MySqlConnector.dll",
"lib/netcoreapp3.1/MySqlConnector.xml",
"lib/netstandard2.0/MySqlConnector.dll",
"lib/netstandard2.0/MySqlConnector.xml",
"lib/netstandard2.1/MySqlConnector.dll",
"lib/netstandard2.1/MySqlConnector.xml",
"logo.png",
"mysqlconnector.2.0.0.nupkg.sha512",
"mysqlconnector.nuspec"
]
},
"Newtonsoft.Json/11.0.2": {
"sha512": "IvJe1pj7JHEsP8B8J8DwlMEx8UInrs/x+9oVY+oCD13jpLu4JbJU2WCIsMRn5C4yW9+DgkaO8uiVE5VHKjpmdQ==",
"type": "package",
@ -1488,6 +1868,20 @@
"newtonsoft.json.nuspec"
]
},
"Pomelo.EntityFrameworkCore.MySql/6.0.0": {
"sha512": "iWloXFjpN6BllZA9oPqZTW9mNtFV5Q6DFv0WwFyh1IuOJ71btS3ifTwpLmaFXSlXzuEU9o7Rul0dU0WiwkOq0Q==",
"type": "package",
"path": "pomelo.entityframeworkcore.mysql/6.0.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"icon.png",
"lib/net6.0/Pomelo.EntityFrameworkCore.MySql.dll",
"lib/net6.0/Pomelo.EntityFrameworkCore.MySql.xml",
"pomelo.entityframeworkcore.mysql.6.0.0.nupkg.sha512",
"pomelo.entityframeworkcore.mysql.nuspec"
]
},
"System.Buffers/4.5.0": {
"sha512": "pL2ChpaRRWI/p4LXyy4RgeWlYF2sgfj/pnVMvBqwNFr5cXg7CXNnWZWxrOONLg8VGdFB8oB+EG2Qw4MLgTOe+A==",
"type": "package",
@ -1517,6 +1911,54 @@
"version.txt"
]
},
"System.Collections.Immutable/6.0.0": {
"sha512": "l4zZJ1WU2hqpQQHXz1rvC3etVZN+2DLmQMO79FhOTZHMn8tDRr+WU287sbomD0BETlmKDn0ygUgVy9k5xkkJdA==",
"type": "package",
"path": "system.collections.immutable/6.0.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"Icon.png",
"LICENSE.TXT",
"THIRD-PARTY-NOTICES.TXT",
"buildTransitive/netcoreapp2.0/System.Collections.Immutable.targets",
"buildTransitive/netcoreapp3.1/_._",
"lib/net461/System.Collections.Immutable.dll",
"lib/net461/System.Collections.Immutable.xml",
"lib/net6.0/System.Collections.Immutable.dll",
"lib/net6.0/System.Collections.Immutable.xml",
"lib/netstandard2.0/System.Collections.Immutable.dll",
"lib/netstandard2.0/System.Collections.Immutable.xml",
"system.collections.immutable.6.0.0.nupkg.sha512",
"system.collections.immutable.nuspec",
"useSharedDesignerContext.txt"
]
},
"System.Diagnostics.DiagnosticSource/6.0.0": {
"sha512": "frQDfv0rl209cKm1lnwTgFPzNigy2EKk1BS3uAvHvlBVKe5cymGyHO+Sj+NLv5VF/AhHsqPIUUwya5oV4CHMUw==",
"type": "package",
"path": "system.diagnostics.diagnosticsource/6.0.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"Icon.png",
"LICENSE.TXT",
"THIRD-PARTY-NOTICES.TXT",
"buildTransitive/netcoreapp2.0/System.Diagnostics.DiagnosticSource.targets",
"buildTransitive/netcoreapp3.1/_._",
"lib/net461/System.Diagnostics.DiagnosticSource.dll",
"lib/net461/System.Diagnostics.DiagnosticSource.xml",
"lib/net5.0/System.Diagnostics.DiagnosticSource.dll",
"lib/net5.0/System.Diagnostics.DiagnosticSource.xml",
"lib/net6.0/System.Diagnostics.DiagnosticSource.dll",
"lib/net6.0/System.Diagnostics.DiagnosticSource.xml",
"lib/netstandard2.0/System.Diagnostics.DiagnosticSource.dll",
"lib/netstandard2.0/System.Diagnostics.DiagnosticSource.xml",
"system.diagnostics.diagnosticsource.6.0.0.nupkg.sha512",
"system.diagnostics.diagnosticsource.nuspec",
"useSharedDesignerContext.txt"
]
},
"System.IdentityModel.Tokens.Jwt/6.26.0": {
"sha512": "GT6imbntzCpoGHTRFUa98TPCF9PTnzV1v5KiTj9sT5ZmeYZErNA5ks5VDvYBaOC59y3dQ78IsMzEJm+XrxDk6w==",
"type": "package",
@ -2304,6 +2746,11 @@
"system.threading.tasks.nuspec"
]
},
"Haoliang.Data/1.0.0": {
"type": "project",
"path": "../Haoliang.Data/Haoliang.Data.csproj",
"msbuildProject": "../Haoliang.Data/Haoliang.Data.csproj"
},
"Haoliang.Models/1.0.0": {
"type": "project",
"path": "../Haoliang.Models/Haoliang.Models.csproj",
@ -2313,6 +2760,7 @@
"projectFileDependencyGroups": {
"net6.0": [
"BCrypt.Net-Next >= 4.0.3",
"Haoliang.Data >= 1.0.0",
"Haoliang.Models >= 1.0.0",
"Microsoft.AspNetCore.Http.Abstractions >= 2.2.0",
"Microsoft.AspNetCore.SignalR >= 1.1.0",
@ -2347,6 +2795,9 @@
"net6.0": {
"targetAlias": "net6.0",
"projectReferences": {
"/root/opencode/haoliang/Haoliang.Data/Haoliang.Data.csproj": {
"projectPath": "/root/opencode/haoliang/Haoliang.Data/Haoliang.Data.csproj"
},
"/root/opencode/haoliang/Haoliang.Models/Haoliang.Models.csproj": {
"projectPath": "/root/opencode/haoliang/Haoliang.Models/Haoliang.Models.csproj"
}

@ -1,10 +1,11 @@
{
"version": 2,
"dgSpecHash": "JXZHRpHRIVB4k9X9GkQYjgJFTdFXJDSb+42sJl8bI1k2k9teZWdbTGwx0JJgh5J3M4+9rp1wh+omg4LmNZnqzQ==",
"dgSpecHash": "UrcVVpvInVazwc35FwsmV5vhcLVoOwid1NCCuZjn3O133q3kza7gearS2X9ki8CFJLx8yoTeQY+38HJQOCyyAA==",
"success": true,
"projectFilePath": "/root/opencode/haoliang/Haoliang.Core/Haoliang.Core.csproj",
"expectedPackageFiles": [
"/root/.nuget/packages/bcrypt.net-next/4.0.3/bcrypt.net-next.4.0.3.nupkg.sha512",
"/root/.nuget/packages/humanizer.core/2.8.26/humanizer.core.2.8.26.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.authentication.abstractions/2.2.0/microsoft.aspnetcore.authentication.abstractions.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.authorization/2.2.0/microsoft.aspnetcore.authorization.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.authorization.policy/2.2.0/microsoft.aspnetcore.authorization.policy.2.2.0.nupkg.sha512",
@ -26,12 +27,20 @@
"/root/.nuget/packages/microsoft.aspnetcore.websockets/2.2.0/microsoft.aspnetcore.websockets.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.webutilities/2.2.0/microsoft.aspnetcore.webutilities.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.csharp/4.5.0/microsoft.csharp.4.5.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.entityframeworkcore/6.0.0/microsoft.entityframeworkcore.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.entityframeworkcore.abstractions/6.0.0/microsoft.entityframeworkcore.abstractions.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.entityframeworkcore.analyzers/6.0.0/microsoft.entityframeworkcore.analyzers.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.entityframeworkcore.design/6.0.0/microsoft.entityframeworkcore.design.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.entityframeworkcore.relational/6.0.0/microsoft.entityframeworkcore.relational.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.entityframeworkcore.tools/6.0.0/microsoft.entityframeworkcore.tools.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.caching.abstractions/6.0.0/microsoft.extensions.caching.abstractions.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.caching.memory/6.0.0/microsoft.extensions.caching.memory.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.configuration.abstractions/2.2.0/microsoft.extensions.configuration.abstractions.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.configuration.abstractions/6.0.0/microsoft.extensions.configuration.abstractions.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.dependencyinjection/6.0.0/microsoft.extensions.dependencyinjection.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.dependencyinjection.abstractions/6.0.0/microsoft.extensions.dependencyinjection.abstractions.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.fileproviders.abstractions/2.2.0/microsoft.extensions.fileproviders.abstractions.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.hosting.abstractions/2.2.0/microsoft.extensions.hosting.abstractions.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.logging/6.0.0/microsoft.extensions.logging.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.logging.abstractions/6.0.0/microsoft.extensions.logging.abstractions.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.objectpool/2.2.0/microsoft.extensions.objectpool.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.options/6.0.0/microsoft.extensions.options.6.0.0.nupkg.sha512",
@ -43,8 +52,12 @@
"/root/.nuget/packages/microsoft.net.http.headers/2.2.0/microsoft.net.http.headers.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.netcore.platforms/2.0.0/microsoft.netcore.platforms.2.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.netcore.targets/1.1.0/microsoft.netcore.targets.1.1.0.nupkg.sha512",
"/root/.nuget/packages/mysqlconnector/2.0.0/mysqlconnector.2.0.0.nupkg.sha512",
"/root/.nuget/packages/newtonsoft.json/11.0.2/newtonsoft.json.11.0.2.nupkg.sha512",
"/root/.nuget/packages/pomelo.entityframeworkcore.mysql/6.0.0/pomelo.entityframeworkcore.mysql.6.0.0.nupkg.sha512",
"/root/.nuget/packages/system.buffers/4.5.0/system.buffers.4.5.0.nupkg.sha512",
"/root/.nuget/packages/system.collections.immutable/6.0.0/system.collections.immutable.6.0.0.nupkg.sha512",
"/root/.nuget/packages/system.diagnostics.diagnosticsource/6.0.0/system.diagnostics.diagnosticsource.6.0.0.nupkg.sha512",
"/root/.nuget/packages/system.identitymodel.tokens.jwt/6.26.0/system.identitymodel.tokens.jwt.6.26.0.nupkg.sha512",
"/root/.nuget/packages/system.io/4.3.0/system.io.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.io.pipelines/4.5.2/system.io.pipelines.4.5.2.nupkg.sha512",

@ -1,6 +1,7 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Haoliang.Data.Entities;
using Haoliang.Models.System;
namespace Haoliang.Data
{
@ -10,10 +11,12 @@ namespace Haoliang.Data
// Device Management
public DbSet<Models.Device.CNCDevice> Devices { get; set; }
public DbSet<Models.Device.DeviceStatus> DeviceStatus { get; set; }
public DbSet<Models.Device.DeviceCurrentStatus> DeviceCurrentStatus { get; set; }
public DbSet<Models.DataCollection.TagData> TagData { get; set; }
// DeviceStatus as string property (since it's an enum)
public string DeviceStatus { get; set; } = null!;
// Template Management
public DbSet<Models.Template.CNCBrandTemplate> CNCTemplates { get; set; }
public DbSet<Models.Template.TagMapping> TagMappings { get; set; }

@ -4,8 +4,6 @@ using Haoliang.Models.Template;
using Haoliang.Models.Production;
using Haoliang.Models.User;
using Haoliang.Models.System;
using Haoliang.Models.System;
using Haoliang.Models.User;
using Haoliang.Models.DataCollection;
namespace Haoliang.Data.Entities
@ -14,22 +12,19 @@ namespace Haoliang.Data.Entities
{
public CNCBusinessDbContext(DbContextOptions<CNCBusinessDbContext> options) : base(options) { }
public DbSet<CNCDevice> Devices { get; set; }
public DbSet<DeviceStatus> DeviceStatus { get; set; }
public DbSet<DeviceCurrentStatus> DeviceCurrentStatus { get; set; }
public DbSet<TagData> TagData { get; set; }
public DbSet<CNCDevice> Devices { get; set; }
public DbSet<DeviceCurrentStatus> DeviceCurrentStatus { get; set; } = null!;
public DbSet<TagData> TagData { get; set; } = null!;
public DbSet<CNCBrandTemplate> CNCTemplates { get; set; }
public DbSet<TemplateFieldMapping> TemplateFieldMappings { get; set; }
public DbSet<ProductionRecord> ProductionRecords { get; set; }
public DbSet<ProgramProductionSummary> ProgramProductionSummary { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<Role> Roles { get; set; }
public DbSet<Employee> Employees { get; set; }
public DbSet<DeviceAssignment> DeviceAssignments { get; set; }
public DbSet<StatisticRule> StatisticRules { get; set; }
public DbSet<Alarm> Alarms { get; set; }
public DbSet<AlarmRule> AlarmRules { get; set; }
public DbSet<StatisticRule> StatisticRules { get; set; }
public DbSet<ScheduledTask> ScheduledTasks { get; set; }
public DbSet<SystemConfig> SystemConfig { get; set; }
public DbSet<LogEntry> LogEntries { get; set; }
public DbSet<AlarmStatistics> AlarmStatistics { get; set; }
public DbSet<AlarmNotification> AlarmNotifications { get; set; }
public DbSet<Permission> Permissions { get; set; }
@ -42,6 +37,8 @@ namespace Haoliang.Data.Entities
public DbSet<CollectionResult> CollectionResults { get; set; }
public DbSet<CollectionLog> CollectionLogs { get; set; }
public DbSet<CollectionConfig> CollectionConfigs { get; set; }
public DbSet<TaskExecutionResult> TaskExecutionResults { get; set; }
public DbSet<TaskExecutionSummary> TaskExecutionSummaries { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{

@ -5,10 +5,10 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="7.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.2" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="6.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.0" />
</ItemGroup>

@ -1,132 +0,0 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Haoliang.Models.System;
using Haoliang.Data.Repositories;
namespace Haoliang.Data.Repositories
{
public interface IAlarmRepository : IRepository<Alarm>
{
Task<IEnumerable<Alarm>> GetByDeviceIdAsync(int deviceId);
Task<IEnumerable<Alarm>> GetByAlarmTypeAsync(AlarmType type);
Task<IEnumerable<Alarm>> GetByStatusAsync(AlarmStatus status);
Task<IEnumerable<Alarm>> GetByDateRangeAsync(DateTime startDate, DateTime endDate);
Task<AlarmStatistics> GetAlarmStatisticsAsync(DateTime date);
Task<IEnumerable<Alarm>> GetBySeverityAsync(AlarmSeverity severity);
Task<IEnumerable<Alarm>> GetByDeviceAndDateRangeAsync(int deviceId, DateTime startDate, DateTime endDate);
Task<int> CountActiveAlarmsAsync();
Task<IEnumerable<Alarm>> GetActiveAlarmsAsync();
Task<IEnumerable<Alarm>> GetAlarmsByPriorityAsync(AlarmPriority priority);
}
public class AlarmRepository : Repository<Alarm>, IAlarmRepository
{
private readonly CNCDbContext _context;
public AlarmRepository(CNCDbContext context) : base(context)
{
_context = context;
}
public async Task<IEnumerable<Alarm>> GetByDeviceIdAsync(int deviceId)
{
return await _context.Alarms
.Where(a => a.DeviceId == deviceId)
.OrderByDescending(a => a.CreatedAt)
.ToListAsync();
}
public async Task<IEnumerable<Alarm>> GetByAlarmTypeAsync(AlarmType type)
{
return await _context.Alarms
.Where(a => a.AlarmType == type)
.OrderByDescending(a => a.CreatedAt)
.ToListAsync();
}
public async Task<IEnumerable<Alarm>> GetByStatusAsync(AlarmStatus status)
{
return await _context.Alarms
.Where(a => a.Status == status)
.OrderByDescending(a => a.CreatedAt)
.ToListAsync();
}
public async Task<IEnumerable<Alarm>> GetByDateRangeAsync(DateTime startDate, DateTime endDate)
{
return await _context.Alarms
.Where(a => a.CreatedAt >= startDate && a.CreatedAt <= endDate)
.OrderByDescending(a => a.CreatedAt)
.ToListAsync();
}
public async Task<AlarmStatistics> GetAlarmStatisticsAsync(DateTime date)
{
var startOfDay = date.Date;
var endOfDay = startOfDay.AddDays(1);
var alarms = await _context.Alarms
.Where(a => a.CreatedAt >= startOfDay && a.CreatedAt <= endOfDay)
.ToListAsync();
var stats = new AlarmStatistics
{
Date = date,
TotalAlarms = alarms.Count,
ActiveAlarms = alarms.Count(a => a.Status == AlarmStatus.Active),
ResolvedAlarms = alarms.Count(a => a.Status == AlarmStatus.Resolved),
CriticalAlarms = alarms.Count(a => a.Severity == AlarmSeverity.Critical),
HighAlarms = alarms.Count(a => a.Severity == AlarmSeverity.High),
MediumAlarms = alarms.Count(a => a.Severity == AlarmSeverity.Medium),
LowAlarms = alarms.Count(a => a.Severity == AlarmSeverity.Low),
DeviceAlarms = alarms.GroupBy(a => a.DeviceId)
.ToDictionary(g => g.Key, g => g.Count())
};
return stats;
}
public async Task<IEnumerable<Alarm>> GetBySeverityAsync(AlarmSeverity severity)
{
return await _context.Alarms
.Where(a => a.Severity == severity)
.OrderByDescending(a => a.CreatedAt)
.ToListAsync();
}
public async Task<IEnumerable<Alarm>> GetByDeviceAndDateRangeAsync(int deviceId, DateTime startDate, DateTime endDate)
{
return await _context.Alarms
.Where(a => a.DeviceId == deviceId &&
a.CreatedAt >= startDate &&
a.CreatedAt <= endDate)
.OrderByDescending(a => a.CreatedAt)
.ToListAsync();
}
public async Task<int> CountActiveAlarmsAsync()
{
return await _context.Alarms
.CountAsync(a => a.Status == AlarmStatus.Active);
}
public async Task<IEnumerable<Alarm>> GetActiveAlarmsAsync()
{
return await _context.Alarms
.Where(a => a.Status == AlarmStatus.Active)
.OrderByDescending(a => a.CreatedAt)
.ToListAsync();
}
public async Task<IEnumerable<Alarm>> GetAlarmsByPriorityAsync(AlarmPriority priority)
{
return await _context.Alarms
.Where(a => a.Priority == priority)
.OrderByDescending(a => a.CreatedAt)
.ToListAsync();
}
}
}

@ -1,126 +0,0 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Haoliang.Models.DataCollection;
using Haoliang.Data.Repositories;
namespace Haoliang.Data.Repositories
{
public interface ICollectionLogRepository : IRepository<CollectionLog>
{
Task<IEnumerable<CollectionLog>> GetByDeviceAsync(int deviceId);
Task<IEnumerable<CollectionLog>> GetByLogLevelAsync(LogLevel logLevel);
Task<int> GetErrorCountAsync(int deviceId);
Task ArchiveLogsAsync(int daysToKeep = 30);
Task ClearLogsAsync();
Task<IEnumerable<CollectionLog>> GetRecentLogsAsync(int count = 100);
Task<CollectionLogStatistics> GetLogStatisticsAsync(DateTime date);
Task<IEnumerable<CollectionLog>> GetLogsByCategoryAsync(string category);
Task<bool> LogExistsAsync(int logId);
}
public class CollectionLogRepository : Repository<CollectionLog>, ICollectionLogRepository
{
private readonly CNCDbContext _context;
public CollectionLogRepository(CNCDbContext context) : base(context)
{
_context = context;
}
public async Task<IEnumerable<CollectionLog>> GetByDeviceAsync(int deviceId)
{
return await _context.CollectionLogs
.Where(l => l.DeviceId == deviceId)
.OrderByDescending(l => l.LogTime)
.ToListAsync();
}
public async Task<IEnumerable<CollectionLog>> GetByLogLevelAsync(LogLevel logLevel)
{
return await _context.CollectionLogs
.Where(l => l.LogLevel == logLevel)
.OrderByDescending(l => l.LogTime)
.ToListAsync();
}
public async Task<int> GetErrorCountAsync(int deviceId)
{
return await _context.CollectionLogs
.CountAsync(l => l.DeviceId == deviceId &&
(l.LogLevel == LogLevel.Error || l.LogLevel == LogLevel.Critical));
}
public async Task ArchiveLogsAsync(int daysToKeep = 30)
{
var cutoffDate = DateTime.Now.AddDays(-daysToKeep);
var logsToArchive = await _context.CollectionLogs
.Where(l => l.LogTime < cutoffDate)
.ToListAsync();
if (logsToArchive.Any())
{
// In a real implementation, you would move these to an archive table
_context.CollectionLogs.RemoveRange(logsToArchive);
await SaveAsync();
}
}
public async Task ClearLogsAsync()
{
_context.CollectionLogs.RemoveRange(_context.CollectionLogs);
await SaveAsync();
}
public async Task<IEnumerable<CollectionLog>> GetRecentLogsAsync(int count = 100)
{
return await _context.CollectionLogs
.OrderByDescending(l => l.LogTime)
.Take(count)
.ToListAsync();
}
public async Task<CollectionLogStatistics> GetLogStatisticsAsync(DateTime date)
{
var startOfDay = date.Date;
var endOfDay = startOfDay.AddDays(1);
var logs = await _context.CollectionLogs
.Where(l => l.LogTime >= startOfDay && l.LogTime <= endOfDay)
.ToListAsync();
var stats = new CollectionLogStatistics
{
Date = date,
TotalLogs = logs.Count,
ErrorLogs = logs.Count(l => l.LogLevel == LogLevel.Error || l.LogLevel == LogLevel.Critical),
WarningLogs = logs.Count(l => l.LogLevel == LogLevel.Warning),
InfoLogs = logs.Count(l => l.LogLevel == LogLevel.Information),
DebugLogs = logs.Count(l => l.LogLevel == LogLevel.Debug),
DeviceLogs = logs.GroupBy(l => l.DeviceId)
.ToDictionary(g => g.Key, g => g.Count()),
LogCategories = logs.GroupBy(l => l.LogCategory)
.ToDictionary(g => g.Key, g => g.Count())
};
return stats;
}
public async Task<IEnumerable<CollectionLog>> GetLogsByCategoryAsync(string category)
{
return await _context.CollectionLogs
.Where(l => l.LogCategory == category)
.OrderByDescending(l => l.LogTime)
.ToListAsync();
}
public async Task<bool> LogExistsAsync(int logId)
{
return await _context.CollectionLogs
.AnyAsync(l => l.LogId == logId);
}
}
}

@ -344,64 +344,4 @@ namespace Haoliang.Data.Repositories
return false;
}
}
public interface ICollectionConfigRepository : IRepository<CollectionConfig>
{
Task<CollectionConfig> GetByKeyAsync(string configKey);
Task<string> GetConfigValueAsync(string configKey);
Task<bool> UpdateConfigValueAsync(string configKey, string configValue);
Task<IEnumerable<CollectionConfig>> GetEnabledConfigsAsync();
Task<bool> ConfigKeyExistsAsync(string configKey);
}
public class CollectionConfigRepository : Repository<CollectionConfig>, ICollectionConfigRepository
{
private readonly CNCDbContext _context;
public CollectionConfigRepository(CNCDbContext context) : base(context)
{
_context = context;
}
public async Task<CollectionConfig> GetByKeyAsync(string configKey)
{
return await _context.CollectionConfigs
.FirstOrDefaultAsync(cc => cc.ConfigKey == configKey);
}
public async Task<string> GetConfigValueAsync(string configKey)
{
var config = await GetByKeyAsync(configKey);
return config?.ConfigValue;
}
public async Task<bool> UpdateConfigValueAsync(string configKey, string configValue)
{
var config = await GetByKeyAsync(configKey);
if (config != null)
{
config.ConfigValue = configValue;
config.UpdatedAt = DateTime.Now;
Update(config);
await SaveAsync();
return true;
}
return false;
}
public async Task<IEnumerable<CollectionConfig>> GetEnabledConfigsAsync()
{
return await _context.CollectionConfigs
.Where(cc => cc.IsEnabled)
.OrderBy(cc => cc.ConfigKey)
.ToListAsync();
}
public async Task<bool> ConfigKeyExistsAsync(string configKey)
{
return await _context.CollectionConfigs
.AnyAsync(cc => cc.ConfigKey == configKey);
}
}
}

@ -1,216 +0,0 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Haoliang.Models.DataCollection;
using Haoliang.Data.Repositories;
namespace Haoliang.Data.Repositories
{
public interface ICollectionResultRepository : IRepository<CollectionResult>
{
Task<IEnumerable<CollectionResult>> GetByDeviceAsync(int deviceId);
Task<IEnumerable<CollectionResult>> GetByDateRangeAsync(int deviceId, DateTime startDate, DateTime endDate);
Task<CollectionStatistics> GetStatisticsAsync(DateTime date);
Task<CollectionHealth> GetHealthAsync();
Task ArchiveResultsAsync(int daysToKeep = 30);
Task<IEnumerable<CollectionResult>> GetSuccessfulResultsAsync(int deviceId, DateTime date);
Task<IEnumerable<CollectionResult>> GetFailedResultsAsync(int deviceId, DateTime date);
Task<AverageResponseTime> GetAverageResponseTimeAsync(int deviceId, DateTime date);
Task<int> GetSuccessRateAsync(int deviceId, DateTime date);
}
public class CollectionResultRepository : Repository<CollectionResult>, ICollectionResultRepository
{
private readonly CNCDbContext _context;
public CollectionResultRepository(CNCDbContext context) : base(context)
{
_context = context;
}
public async Task<IEnumerable<CollectionResult>> GetByDeviceAsync(int deviceId)
{
return await _context.CollectionResults
.Where(r => r.DeviceId == deviceId)
.OrderByDescending(r => r.CollectionTime)
.ToListAsync();
}
public async Task<IEnumerable<CollectionResult>> GetByDateRangeAsync(int deviceId, DateTime startDate, DateTime endDate)
{
return await _context.CollectionResults
.Where(r => r.DeviceId == deviceId &&
r.CollectionTime >= startDate &&
r.CollectionTime <= endDate)
.OrderByDescending(r => r.CollectionTime)
.ToListAsync();
}
public async Task<CollectionStatistics> GetStatisticsAsync(DateTime date)
{
var startOfDay = date.Date;
var endOfDay = startOfDay.AddDays(1);
var results = await _context.CollectionResults
.Where(r => r.CollectionTime >= startOfDay &&
r.CollectionTime <= endOfDay)
.ToListAsync();
var stats = new CollectionStatistics
{
Date = date,
TotalAttempts = results.Count(),
SuccessCount = results.Count(r => r.IsSuccess),
FailedCount = results.Count(r => !r.IsSuccess),
SuccessRate = results.Any() ? (decimal)results.Count(r => r.IsSuccess) / results.Count() * 100 : 0,
DeviceCount = results.Select(r => r.DeviceId).Distinct().Count(),
OnlineDeviceCount = await _context.Devices.CountAsync(d => d.IsOnline),
TotalDataSize = results.Sum(r => r.DataSize ?? 0)
};
if (stats.SuccessCount > 0)
{
var successfulResults = results.Where(r => r.IsSuccess).ToList();
stats.AverageResponseTime = TimeSpan.FromTicks(
(long)successfulResults.Average(r => r.ResponseTime ?? 0));
}
return stats;
}
public async Task<CollectionHealth> GetHealthAsync()
{
var stats = await GetStatisticsAsync(DateTime.Now);
var onlineDeviceCount = await _context.Devices.CountAsync(d => d.IsOnline);
var availableDeviceCount = await _context.Devices.CountAsync(d => d.IsAvailable);
var activeTasks = await _context.CollectionTasks
.CountAsync(t => t.Status == "Running");
var failedTasks = await _context.CollectionTasks
.CountAsync(t => t.Status == "Failed");
var lastSuccessful = await _context.CollectionResults
.Where(r => r.IsSuccess)
.OrderByDescending(r => r.CollectionTime)
.FirstOrDefault();
var lastFailed = await _context.CollectionResults
.Where(r => !r.IsSuccess)
.OrderByDescending(r => r.CollectionTime)
.FirstOrDefault();
return new CollectionHealth
{
CheckTime = DateTime.Now,
TotalDevices = onlineDeviceCount,
OnlineDevices = availableDeviceCount,
ActiveCollectionTasks = activeTasks,
FailedTasks = failedTasks,
SuccessRate = stats.SuccessRate,
AverageResponseTime = stats.AverageResponseTime,
TotalCollectedData = stats.TotalDataSize,
LastSuccessfulCollection = lastSuccessful?.CollectionTime ?? DateTime.MinValue,
LastFailedCollection = lastFailed?.CollectionTime ?? DateTime.MinValue
};
}
public async Task ArchiveResultsAsync(int daysToKeep = 30)
{
var cutoffDate = DateTime.Now.AddDays(-daysToKeep);
var resultsToArchive = await _context.CollectionResults
.Where(r => r.CollectionTime < cutoffDate)
.ToListAsync();
if (resultsToArchive.Any())
{
// In a real implementation, you would move these to an archive table
_context.CollectionResults.RemoveRange(resultsToArchive);
await SaveAsync();
}
}
public async Task<IEnumerable<CollectionResult>> GetSuccessfulResultsAsync(int deviceId, DateTime date)
{
var startOfDay = date.Date;
var endOfDay = startOfDay.AddDays(1);
return await _context.CollectionResults
.Where(r => r.DeviceId == deviceId &&
r.CollectionTime >= startOfDay &&
r.CollectionTime <= endOfDay &&
r.IsSuccess)
.OrderByDescending(r => r.CollectionTime)
.ToListAsync();
}
public async Task<IEnumerable<CollectionResult>> GetFailedResultsAsync(int deviceId, DateTime date)
{
var startOfDay = date.Date;
var endOfDay = startOfDay.AddDays(1);
return await _context.CollectionResults
.Where(r => r.DeviceId == deviceId &&
r.CollectionTime >= startOfDay &&
r.CollectionTime <= endOfDay &&
!r.IsSuccess)
.OrderByDescending(r => r.CollectionTime)
.ToListAsync();
}
public async Task<AverageResponseTime> GetAverageResponseTimeAsync(int deviceId, DateTime date)
{
var startOfDay = date.Date;
var endOfDay = startOfDay.AddDays(1);
var successfulResults = await _context.CollectionResults
.Where(r => r.DeviceId == deviceId &&
r.CollectionTime >= startOfDay &&
r.CollectionTime <= endOfDay &&
r.IsSuccess)
.ToListAsync();
if (successfulResults.Any())
{
var averageTicks = (long)successfulResults.Average(r => r.ResponseTime ?? 0);
return new AverageResponseTime
{
DeviceId = deviceId,
Date = date,
AverageTime = TimeSpan.FromTicks(averageTicks),
SampleCount = successfulResults.Count
};
}
return new AverageResponseTime
{
DeviceId = deviceId,
Date = date,
AverageTime = TimeSpan.Zero,
SampleCount = 0
};
}
public async Task<int> GetSuccessRateAsync(int deviceId, DateTime date)
{
var startOfDay = date.Date;
var endOfDay = startOfDay.AddDays(1);
var results = await _context.CollectionResults
.Where(r => r.DeviceId == deviceId &&
r.CollectionTime >= startOfDay &&
r.CollectionTime <= endOfDay)
.ToListAsync();
if (results.Any())
{
var successCount = results.Count(r => r.IsSuccess);
return (int)(decimal)successCount / results.Count() * 100;
}
return 0;
}
}
}

@ -1,132 +0,0 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Haoliang.Models.DataCollection;
using Haoliang.Data.Repositories;
namespace Haoliang.Data.Repositories
{
public interface ICollectionTaskRepository : IRepository<CollectionTask>
{
Task<IEnumerable<CollectionTask>> GetPendingTasksAsync();
Task<IEnumerable<CollectionTask>> GetFailedTasksAsync();
Task<CollectionTask> GetByDeviceAsync(int deviceId);
Task<bool> MarkTaskCompletedAsync(int taskId, bool isSuccess, string result);
Task<IEnumerable<CollectionTask>> GetTasksByDateAsync(DateTime date);
Task<IEnumerable<CollectionTask>> GetRunningTasksAsync();
Task<CollectionTaskStatistics> GetTaskStatisticsAsync(DateTime date);
Task<bool> HasPendingTasksAsync(int deviceId);
Task<IEnumerable<CollectionTask>> GetTasksByStatusAsync(string status);
}
public class CollectionTaskRepository : Repository<CollectionTask>, ICollectionTaskRepository
{
private readonly CNCDbContext _context;
public CollectionTaskRepository(CNCDbContext context) : base(context)
{
_context = context;
}
public async Task<IEnumerable<CollectionTask>> GetPendingTasksAsync()
{
return await _context.CollectionTasks
.Where(t => t.Status == "Pending")
.OrderBy(t => t.ScheduledTime)
.ToListAsync();
}
public async Task<IEnumerable<CollectionTask>> GetFailedTasksAsync()
{
return await _context.CollectionTasks
.Where(t => t.Status == "Failed")
.OrderByDescending(t => t.CreatedAt)
.ToListAsync();
}
public async Task<CollectionTask> GetByDeviceAsync(int deviceId)
{
return await _context.CollectionTasks
.Where(t => t.DeviceId == deviceId)
.OrderByDescending(t => t.CreatedAt)
.FirstOrDefaultAsync();
}
public async Task<bool> MarkTaskCompletedAsync(int taskId, bool isSuccess, string result)
{
var task = await GetByIdAsync(taskId);
if (task == null)
{
return false;
}
task.Status = isSuccess ? "Completed" : "Failed";
task.Result = result;
task.CompletedAt = DateTime.Now;
await SaveAsync();
return true;
}
public async Task<IEnumerable<CollectionTask>> GetTasksByDateAsync(DateTime date)
{
var startOfDay = date.Date;
var endOfDay = startOfDay.AddDays(1);
return await _context.CollectionTasks
.Where(t => t.CreatedAt >= startOfDay &&
t.CreatedAt < endOfDay)
.OrderBy(t => t.ScheduledTime)
.ToListAsync();
}
public async Task<IEnumerable<CollectionTask>> GetRunningTasksAsync()
{
return await _context.CollectionTasks
.Where(t => t.Status == "Running")
.OrderBy(t => t.ScheduledTime)
.ToListAsync();
}
public async Task<CollectionTaskStatistics> GetTaskStatisticsAsync(DateTime date)
{
var startOfDay = date.Date;
var endOfDay = startOfDay.AddDays(1);
var tasks = await _context.CollectionTasks
.Where(t => t.CreatedAt >= startOfDay &&
t.CreatedAt < endOfDay)
.ToListAsync();
var stats = new CollectionTaskStatistics
{
Date = date,
TotalTasks = tasks.Count,
PendingTasks = tasks.Count(t => t.Status == "Pending"),
RunningTasks = tasks.Count(t => t.Status == "Running"),
CompletedTasks = tasks.Count(t => t.Status == "Completed"),
FailedTasks = tasks.Count(t => t.Status == "Failed"),
DeviceTasks = tasks.GroupBy(t => t.DeviceId)
.ToDictionary(g => g.Key, g => g.Count())
};
return stats;
}
public async Task<bool> HasPendingTasksAsync(int deviceId)
{
return await _context.CollectionTasks
.AnyAsync(t => t.DeviceId == deviceId && t.Status == "Pending");
}
public async Task<IEnumerable<CollectionTask>> GetTasksByStatusAsync(string status)
{
return await _context.CollectionTasks
.Where(t => t.Status == status)
.OrderBy(t => t.ScheduledTime)
.ToListAsync();
}
}
}

@ -95,70 +95,4 @@ namespace Haoliang.Data.Repositories
.CountAsync(d => d.IsAvailable);
}
}
public interface IDeviceStatusRepository : IRepository<DeviceStatus>
{
Task<IEnumerable<DeviceStatus>> GetLatestStatusAsync(int deviceId, int count = 10);
Task<DeviceStatus> GetLatestStatusByDeviceIdAsync(int deviceId);
Task<IEnumerable<DeviceStatus>> GetStatusByDateRangeAsync(int deviceId, DateTime startDate, DateTime endDate);
Task<int> CountStatusRecordsAsync(int deviceId);
Task DeleteOldStatusRecordsAsync(int deviceId, int keepDays = 30);
}
public class DeviceStatusRepository : Repository<DeviceStatus>, IDeviceStatusRepository
{
private readonly CNCDbContext _context;
public DeviceStatusRepository(CNCDbContext context) : base(context)
{
_context = context;
}
public async Task<IEnumerable<DeviceStatus>> GetLatestStatusAsync(int deviceId, int count = 10)
{
return await _context.DeviceStatus
.Where(ds => ds.DeviceId == deviceId)
.OrderByDescending(ds => ds.RecordTime)
.Take(count)
.ToListAsync();
}
public async Task<DeviceStatus> GetLatestStatusByDeviceIdAsync(int deviceId)
{
return await _context.DeviceStatus
.Where(ds => ds.DeviceId == deviceId)
.OrderByDescending(ds => ds.RecordTime)
.FirstOrDefaultAsync();
}
public async Task<IEnumerable<DeviceStatus>> GetStatusByDateRangeAsync(int deviceId, DateTime startDate, DateTime endDate)
{
return await _context.DeviceStatus
.Where(ds => ds.DeviceId == deviceId &&
ds.RecordTime >= startDate &&
ds.RecordTime <= endDate)
.OrderBy(ds => ds.RecordTime)
.ToListAsync();
}
public async Task<int> CountStatusRecordsAsync(int deviceId)
{
return await _context.DeviceStatus
.CountAsync(ds => ds.DeviceId == deviceId);
}
public async Task DeleteOldStatusRecordsAsync(int deviceId, int keepDays = 30)
{
var cutoffDate = DateTime.Now.AddDays(-keepDays);
var oldRecords = await _context.DeviceStatus
.Where(ds => ds.DeviceId == deviceId && ds.RecordTime < cutoffDate)
.ToListAsync();
if (oldRecords.Any())
{
RemoveRange(oldRecords);
await SaveAsync();
}
}
}
}

@ -18,7 +18,7 @@ namespace Haoliang.Data.Repositories
void RemoveRange(IEnumerable<T> entities);
Task<int> CountAsync(System.Linq.Expressions.Expression<Func<T, bool>> predicate = null);
Task<bool> ExistsAsync(System.Linq.Expressions.Expression<Func<T, bool>> predicate);
Task SaveAsync();
Task<int> SaveAsync();
}
public interface IReadRepository<T> where T : class

@ -1,176 +0,0 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Haoliang.Models.Production;
using Haoliang.Data.Repositories;
namespace Haoliang.Data.Repositories
{
public interface IProgramProductionSummaryRepository : IRepository<ProgramProductionSummary>
{
Task<ProgramProductionSummary> GetByDeviceAndDateAsync(int deviceId, DateTime date);
Task<IEnumerable<ProgramProductionSummary>> GetByDateAsync(DateTime date);
Task<IEnumerable<ProgramProductionSummary>> GetByDeviceAsync(int deviceId);
Task<IEnumerable<ProgramProductionSummary>> GetByProgramAsync(string programName);
Task<ProgramProductionSummary> GetByDeviceAndProgramAsync(int deviceId, string programName);
Task<IEnumerable<ProgramProductionSummary>> GetByDateRangeAsync(DateTime startDate, DateTime endDate);
Task<ProductionSummary> GetTotalProductionAsync(DateTime date);
Task<bool> UpdateProductionSummaryAsync(int deviceId, string programName, int quantity);
Task ArchiveProductionSummariesAsync(int daysToKeep = 90);
}
public class ProgramProductionSummaryRepository : Repository<ProgramProductionSummary>, IProgramProductionSummaryRepository
{
private readonly CNCDbContext _context;
public ProgramProductionSummaryRepository(CNCDbContext context) : base(context)
{
_context = context;
}
public async Task<ProgramProductionSummary> GetByDeviceAndDateAsync(int deviceId, DateTime date)
{
var startOfDay = date.Date;
var endOfDay = startOfDay.AddDays(1);
return await _context.ProgramProductionSummaries
.FirstOrDefaultAsync(p => p.DeviceId == deviceId &&
p.ProductionDate >= startOfDay &&
p.ProductionDate < endOfDay);
}
public async Task<IEnumerable<ProgramProductionSummary>> GetByDateAsync(DateTime date)
{
var startOfDay = date.Date;
var endOfDay = startOfDay.AddDays(1);
return await _context.ProgramProductionSummaries
.Where(p => p.ProductionDate >= startOfDay &&
p.ProductionDate < endOfDay)
.OrderBy(p => p.DeviceName)
.ThenBy(p => p.ProgramName)
.ToListAsync();
}
public async Task<IEnumerable<ProgramProductionSummary>> GetByDeviceAsync(int deviceId)
{
return await _context.ProgramProductionSummaries
.Where(p => p.DeviceId == deviceId)
.OrderByDescending(p => p.ProductionDate)
.ThenBy(p => p.ProgramName)
.ToListAsync();
}
public async Task<IEnumerable<ProgramProductionSummary>> GetByProgramAsync(string programName)
{
return await _context.ProgramProductionSummaries
.Where(p => p.ProgramName == programName)
.OrderByDescending(p => p.ProductionDate)
.ThenBy(p => p.DeviceName)
.ToListAsync();
}
public async Task<ProgramProductionSummary> GetByDeviceAndProgramAsync(int deviceId, string programName)
{
var today = DateTime.Today;
return await _context.ProgramProductionSummaries
.FirstOrDefaultAsync(p => p.DeviceId == deviceId &&
p.ProgramName == programName &&
p.ProductionDate == today);
}
public async Task<IEnumerable<ProgramProductionSummary>> GetByDateRangeAsync(DateTime startDate, DateTime endDate)
{
return await _context.ProgramProductionSummaries
.Where(p => p.ProductionDate >= startDate &&
p.ProductionDate <= endDate)
.OrderBy(p => p.ProductionDate)
.ThenBy(p => p.DeviceName)
.ThenBy(p => p.ProgramName)
.ToListAsync();
}
public async Task<ProductionSummary> GetTotalProductionAsync(DateTime date)
{
var summaries = await GetByDateAsync(date);
var totalSummary = new ProductionSummary
{
ProductionDate = date,
TotalDevices = summaries.Select(s => s.DeviceId).Distinct().Count(),
TotalPrograms = summaries.Count(),
TotalQuantity = summaries.Sum(s => s.Quantity),
AverageQuantity = summaries.Any() ? summaries.Average(s => s.Quantity) : 0,
DeviceSummaries = summaries.GroupBy(s => s.DeviceId)
.Select(g => new DeviceProductionSummary
{
DeviceId = g.Key,
DeviceName = g.FirstOrDefault()?.DeviceName ?? "",
TotalQuantity = g.Sum(s => s.Quantity),
ProgramCount = g.Count(),
Programs = g.Select(s => new ProgramSummary
{
ProgramName = s.ProgramName,
Quantity = s.Quantity,
Percentage = g.Sum(s => s.Quantity) > 0 ?
(decimal)s.Quantity / g.Sum(s => s.Quantity) * 100 : 0
}).ToList()
}).ToList()
};
return totalSummary;
}
public async Task<bool> UpdateProductionSummaryAsync(int deviceId, string programName, int quantity)
{
var today = DateTime.Today;
var summary = await GetByDeviceAndProgramAsync(deviceId, programName);
if (summary != null)
{
// Update existing summary
summary.Quantity += quantity;
summary.UpdatedAt = DateTime.Now;
_context.ProgramProductionSummaries.Update(summary);
}
else
{
// Create new summary
var device = await _context.Devices.FindAsync(deviceId);
summary = new ProgramProductionSummary
{
DeviceId = deviceId,
DeviceName = device?.DeviceName ?? "",
ProgramName = programName,
Quantity = quantity,
ProductionDate = today,
CreatedAt = DateTime.Now,
UpdatedAt = DateTime.Now
};
_context.ProgramProductionSummaries.Add(summary);
}
await SaveAsync();
return true;
}
public async Task ArchiveProductionSummariesAsync(int daysToKeep = 90)
{
var cutoffDate = DateTime.Today.AddDays(-daysToKeep);
var summariesToArchive = await _context.ProgramProductionSummaries
.Where(p => p.ProductionDate < cutoffDate)
.ToListAsync();
if (summariesToArchive.Any())
{
// In a real implementation, you would move these to an archive table
_context.ProgramProductionSummaries.RemoveRange(summariesToArchive);
await SaveAsync();
}
}
}
}

@ -11,7 +11,7 @@ namespace Haoliang.Data.Repositories
public interface IScheduledTaskRepository : IRepository<ScheduledTask>
{
Task<IEnumerable<ScheduledTask>> GetActiveTasksAsync();
Task<IEnumerable<ScheduledTask>> GetTasksByStatusAsync(TaskStatus status);
Task<IEnumerable<ScheduledTask>> GetTasksByStatusAsync(Haoliang.Models.System.TaskStatus status);
Task<TaskExecutionResult> GetLastExecutionResultAsync(string taskId);
Task<IEnumerable<ScheduledTask>> GetTasksByCronExpressionAsync(string cronExpression);
Task<IEnumerable<ScheduledTask>> GetOverdueTasksAsync();
@ -38,7 +38,7 @@ namespace Haoliang.Data.Repositories
.ToListAsync();
}
public async Task<IEnumerable<ScheduledTask>> GetTasksByStatusAsync(TaskStatus status)
public async Task<IEnumerable<ScheduledTask>> GetTasksByStatusAsync(Haoliang.Models.System.TaskStatus status)
{
return await _context.ScheduledTasks
.Where(t => t.TaskStatus == status)

@ -1,140 +0,0 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Haoliang.Models.System;
using Haoliang.Data.Repositories;
namespace Haoliang.Data.Repositories
{
public interface ISystemConfigRepository : IRepository<SystemConfig>
{
Task<SystemConfig> GetByKeyAsync(string configKey);
Task<bool> DeleteByKeyAsync(string configKey);
Task<bool> KeyExistsAsync(string configKey);
Task<IEnumerable<SystemConfig>> GetByCategoryAsync(string category);
SystemConfig UpsertAsync(SystemConfig config);
Task<string> GetValueAsync(string configKey);
Task<bool> SetValueAsync(string configKey, string value);
Task<IEnumerable<SystemConfig>> GetActiveConfigsAsync();
Task<SystemConfig> GetDefaultConfigAsync();
Task<bool> UpdateConfigValueAsync(string configKey, string value);
}
public class SystemConfigRepository : Repository<SystemConfig>, ISystemConfigRepository
{
private readonly CNCDbContext _context;
public SystemConfigRepository(CNCDbContext context) : base(context)
{
_context = context;
}
public async Task<SystemConfig> GetByKeyAsync(string configKey)
{
return await _context.SystemConfigs
.FirstOrDefaultAsync(c => c.ConfigKey == configKey);
}
public async Task<bool> DeleteByKeyAsync(string configKey)
{
var config = await GetByKeyAsync(configKey);
if (config != null)
{
_context.SystemConfigs.Remove(config);
await SaveAsync();
return true;
}
return false;
}
public async Task<bool> KeyExistsAsync(string configKey)
{
return await _context.SystemConfigs
.AnyAsync(c => c.ConfigKey == configKey);
}
public async Task<IEnumerable<SystemConfig>> GetByCategoryAsync(string category)
{
return await _context.SystemConfigs
.Where(c => c.Category == category)
.OrderBy(c => c.ConfigKey)
.ToListAsync();
}
public SystemConfig UpsertAsync(SystemConfig config)
{
var existing = _context.SystemConfigs
.FirstOrDefault(c => c.ConfigKey == config.ConfigKey);
if (existing != null)
{
// Update existing
existing.ConfigValue = config.ConfigValue;
existing.Description = config.Description;
existing.UpdatedAt = DateTime.Now;
existing.IsActive = config.IsActive;
existing.Category = config.Category;
_context.SystemConfigs.Update(existing);
}
else
{
// Insert new
config.CreatedAt = DateTime.Now;
config.UpdatedAt = DateTime.Now;
_context.SystemConfigs.Add(config);
}
SaveAsync();
return config;
}
public async Task<string> GetValueAsync(string configKey)
{
var config = await GetByKeyAsync(configKey);
return config?.ConfigValue;
}
public async Task<bool> SetValueAsync(string configKey, string value)
{
var config = await GetByKeyAsync(configKey);
if (config != null)
{
config.ConfigValue = value;
config.UpdatedAt = DateTime.Now;
await SaveAsync();
return true;
}
return false;
}
public async Task<IEnumerable<SystemConfig>> GetActiveConfigsAsync()
{
return await _context.SystemConfigs
.Where(c => c.IsActive)
.OrderBy(c => c.Category)
.ThenBy(c => c.ConfigKey)
.ToListAsync();
}
public async Task<SystemConfig> GetDefaultConfigAsync()
{
return await _context.SystemConfigs
.FirstOrDefaultAsync(c => c.IsDefault);
}
public async Task<bool> UpdateConfigValueAsync(string configKey, string value)
{
var config = await GetByKeyAsync(configKey);
if (config != null)
{
config.ConfigValue = value;
config.UpdatedAt = DateTime.Now;
await SaveAsync();
return true;
}
return false;
}
}
}

@ -132,211 +132,4 @@ namespace Haoliang.Data.Repositories
return false;
}
}
public interface IAlarmRuleRepository : IRepository<AlarmRule>
{
Task<AlarmRule> GetByNameAsync(string ruleName);
Task<IEnumerable<AlarmRule>> GetEnabledRulesAsync();
Task<IEnumerable<AlarmRule>> GetRulesByDeviceIdAsync(int deviceId);
Task<bool> RuleNameExistsAsync(string ruleName);
Task<bool> EnableRuleAsync(int ruleId);
Task<bool> DisableRuleAsync(int ruleId);
}
public class AlarmRuleRepository : Repository<AlarmRule>, IAlarmRuleRepository
{
private readonly CNCDbContext _context;
public AlarmRuleRepository(CNCDbContext context) : base(context)
{
_context = context;
}
public async Task<AlarmRule> GetByNameAsync(string ruleName)
{
return await _context.AlarmRules
.FirstOrDefaultAsync(ar => ar.RuleName == ruleName);
}
public async Task<IEnumerable<AlarmRule>> GetEnabledRulesAsync()
{
return await _context.AlarmRules
.Where(ar => ar.IsEnabled)
.OrderBy(ar => ar.RuleName)
.ToListAsync();
}
public async Task<IEnumerable<AlarmRule>> GetRulesByDeviceIdAsync(int deviceId)
{
return await _context.AlarmRules
.Where(ar => ar.DeviceId == null || ar.DeviceId == deviceId)
.OrderBy(ar => ar.RuleName)
.ToListAsync();
}
public async Task<bool> RuleNameExistsAsync(string ruleName)
{
return await _context.AlarmRules
.AnyAsync(ar => ar.RuleName == ruleName);
}
public async Task<bool> EnableRuleAsync(int ruleId)
{
var rule = await GetByIdAsync(ruleId);
if (rule != null)
{
rule.IsEnabled = true;
rule.UpdatedAt = DateTime.Now;
Update(rule);
await SaveAsync();
return true;
}
return false;
}
public async Task<bool> DisableRuleAsync(int ruleId)
{
var rule = await GetByIdAsync(ruleId);
if (rule != null)
{
rule.IsEnabled = false;
rule.UpdatedAt = DateTime.Now;
Update(rule);
await SaveAsync();
return true;
}
return false;
}
}
public interface ISystemConfigRepository : IRepository<SystemConfig>
{
Task<SystemConfig> GetByKeyAsync(string configKey);
Task<string> GetConfigValueAsync(string configKey);
Task<bool> UpdateConfigValueAsync(string configKey, string configValue);
Task<IEnumerable<SystemConfig>> GetByCategoryAsync(string category);
Task<bool> ConfigKeyExistsAsync(string configKey);
}
public class SystemConfigRepository : Repository<SystemConfig>, ISystemConfigRepository
{
private readonly CNCDbContext _context;
public SystemConfigRepository(CNCDbContext context) : base(context)
{
_context = context;
}
public async Task<SystemConfig> GetByKeyAsync(string configKey)
{
return await _context.SystemConfig
.FirstOrDefaultAsync(sc => sc.ConfigKey == configKey);
}
public async Task<string> GetConfigValueAsync(string configKey)
{
var config = await GetByKeyAsync(configKey);
return config?.ConfigValue;
}
public async Task<bool> UpdateConfigValueAsync(string configKey, string configValue)
{
var config = await GetByKeyAsync(configKey);
if (config != null)
{
config.ConfigValue = configValue;
config.UpdatedAt = DateTime.Now;
Update(config);
await SaveAsync();
return true;
}
return false;
}
public async Task<IEnumerable<SystemConfig>> GetByCategoryAsync(string category)
{
return await _context.SystemConfig
.Where(sc => sc.Description?.Contains(category) == true)
.OrderBy(sc => sc.ConfigKey)
.ToListAsync();
}
public async Task<bool> ConfigKeyExistsAsync(string configKey)
{
return await _context.SystemConfig
.AnyAsync(sc => sc.ConfigKey == configKey);
}
}
public interface IStatisticRuleRepository : IRepository<StatisticRule>
{
Task<StatisticRule> GetByNameAsync(string ruleName);
Task<IEnumerable<StatisticRule>> GetEnabledRulesAsync();
Task<bool> RuleNameExistsAsync(string ruleName);
Task<bool> EnableRuleAsync(int ruleId);
Task<bool> DisableRuleAsync(int ruleId);
}
public class StatisticRuleRepository : Repository<StatisticRule>, IStatisticRuleRepository
{
private readonly CNCDbContext _context;
public StatisticRuleRepository(CNCDbContext context) : base(context)
{
_context = context;
}
public async Task<StatisticRule> GetByNameAsync(string ruleName)
{
return await _context.StatisticRules
.FirstOrDefaultAsync(sr => sr.RuleName == ruleName);
}
public async Task<IEnumerable<StatisticRule>> GetEnabledRulesAsync()
{
return await _context.StatisticRules
.Where(sr => sr.IsEnabled)
.OrderBy(sr => sr.RuleName)
.ToListAsync();
}
public async Task<bool> RuleNameExistsAsync(string ruleName)
{
return await _context.StatisticRules
.AnyAsync(sr => sr.RuleName == ruleName);
}
public async Task<bool> EnableRuleAsync(int ruleId)
{
var rule = await GetByIdAsync(ruleId);
if (rule != null)
{
rule.IsEnabled = true;
rule.UpdatedAt = DateTime.Now;
Update(rule);
await SaveAsync();
return true;
}
return false;
}
public async Task<bool> DisableRuleAsync(int ruleId)
{
var rule = await GetByIdAsync(ruleId);
if (rule != null)
{
rule.IsEnabled = false;
rule.UpdatedAt = DateTime.Now;
Update(rule);
await SaveAsync();
return true;
}
return false;
}
}
}

@ -1 +1 @@
3e3908621d77d028c205325d4d43007864ecc556
4ed16a54e5ac1a1c4893fbacd380ecf37ee763c1

@ -4,92 +4,6 @@
"/root/opencode/haoliang/Haoliang.Data/Haoliang.Data.csproj": {}
},
"projects": {
"/root/opencode/haoliang/Haoliang.Core/Haoliang.Core.csproj": {
"version": "1.0.0",
"restore": {
"projectUniqueName": "/root/opencode/haoliang/Haoliang.Core/Haoliang.Core.csproj",
"projectName": "Haoliang.Core",
"projectPath": "/root/opencode/haoliang/Haoliang.Core/Haoliang.Core.csproj",
"packagesPath": "/root/.nuget/packages/",
"outputPath": "/root/opencode/haoliang/Haoliang.Core/obj/",
"projectStyle": "PackageReference",
"configFilePaths": [
"/root/.nuget/NuGet/NuGet.Config"
],
"originalTargetFrameworks": [
"net6.0"
],
"sources": {
"https://api.nuget.org/v3/index.json": {}
},
"frameworks": {
"net6.0": {
"targetAlias": "net6.0",
"projectReferences": {
"/root/opencode/haoliang/Haoliang.Models/Haoliang.Models.csproj": {
"projectPath": "/root/opencode/haoliang/Haoliang.Models/Haoliang.Models.csproj"
}
}
}
},
"warningProperties": {
"warnAsError": [
"NU1605"
]
}
},
"frameworks": {
"net6.0": {
"targetAlias": "net6.0",
"dependencies": {
"BCrypt.Net-Next": {
"target": "Package",
"version": "[4.0.3, )"
},
"Microsoft.AspNetCore.Http.Abstractions": {
"target": "Package",
"version": "[2.2.0, )"
},
"Microsoft.AspNetCore.SignalR": {
"target": "Package",
"version": "[1.1.0, )"
},
"Microsoft.Extensions.Caching.Memory": {
"target": "Package",
"version": "[6.0.0, )"
},
"Microsoft.Extensions.Logging.Abstractions": {
"target": "Package",
"version": "[6.0.0, )"
},
"Microsoft.IdentityModel.Tokens": {
"target": "Package",
"version": "[6.26.0, )"
},
"System.IdentityModel.Tokens.Jwt": {
"target": "Package",
"version": "[6.26.0, )"
}
},
"imports": [
"net461",
"net462",
"net47",
"net471",
"net472",
"net48"
],
"assetTargetFallback": true,
"warn": true,
"frameworkReferences": {
"Microsoft.NETCore.App": {
"privateAssets": "all"
}
},
"runtimeIdentifierGraphPath": "/usr/lib/dotnet/sdk/6.0.136/RuntimeIdentifierGraph.json"
}
}
},
"/root/opencode/haoliang/Haoliang.Data/Haoliang.Data.csproj": {
"version": "1.0.0",
"restore": {
@ -112,9 +26,6 @@
"net6.0": {
"targetAlias": "net6.0",
"projectReferences": {
"/root/opencode/haoliang/Haoliang.Core/Haoliang.Core.csproj": {
"projectPath": "/root/opencode/haoliang/Haoliang.Core/Haoliang.Core.csproj"
},
"/root/opencode/haoliang/Haoliang.Models/Haoliang.Models.csproj": {
"projectPath": "/root/opencode/haoliang/Haoliang.Models/Haoliang.Models.csproj"
}
@ -133,19 +44,19 @@
"dependencies": {
"Microsoft.EntityFrameworkCore": {
"target": "Package",
"version": "[7.0.2, )"
"version": "[6.0.0, )"
},
"Microsoft.EntityFrameworkCore.Design": {
"target": "Package",
"version": "[7.0.2, )"
"version": "[6.0.0, )"
},
"Microsoft.EntityFrameworkCore.Tools": {
"target": "Package",
"version": "[7.0.2, )"
"version": "[6.0.0, )"
},
"Pomelo.EntityFrameworkCore.MySql": {
"target": "Package",
"version": "[7.0.0, )"
"version": "[6.0.0, )"
}
},
"imports": [

@ -13,10 +13,9 @@
<SourceRoot Include="/root/.nuget/packages/" />
</ItemGroup>
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<Import Project="$(NuGetPackageRoot)microsoft.entityframeworkcore/7.0.2/buildTransitive/net6.0/Microsoft.EntityFrameworkCore.props" Condition="Exists('$(NuGetPackageRoot)microsoft.entityframeworkcore/7.0.2/buildTransitive/net6.0/Microsoft.EntityFrameworkCore.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.entityframeworkcore.design/7.0.2/build/net6.0/Microsoft.EntityFrameworkCore.Design.props" Condition="Exists('$(NuGetPackageRoot)microsoft.entityframeworkcore.design/7.0.2/build/net6.0/Microsoft.EntityFrameworkCore.Design.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.entityframeworkcore.design/6.0.0/build/net6.0/Microsoft.EntityFrameworkCore.Design.props" Condition="Exists('$(NuGetPackageRoot)microsoft.entityframeworkcore.design/6.0.0/build/net6.0/Microsoft.EntityFrameworkCore.Design.props')" />
</ImportGroup>
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<PkgMicrosoft_EntityFrameworkCore_Tools Condition=" '$(PkgMicrosoft_EntityFrameworkCore_Tools)' == '' ">/root/.nuget/packages/microsoft.entityframeworkcore.tools/7.0.2</PkgMicrosoft_EntityFrameworkCore_Tools>
<PkgMicrosoft_EntityFrameworkCore_Tools Condition=" '$(PkgMicrosoft_EntityFrameworkCore_Tools)' == '' ">/root/.nuget/packages/microsoft.entityframeworkcore.tools/6.0.0</PkgMicrosoft_EntityFrameworkCore_Tools>
</PropertyGroup>
</Project>

@ -1,7 +1,2 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<Import Project="$(NuGetPackageRoot)system.text.json/7.0.0/buildTransitive/net6.0/System.Text.Json.targets" Condition="Exists('$(NuGetPackageRoot)system.text.json/7.0.0/buildTransitive/net6.0/System.Text.Json.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.extensions.logging.abstractions/7.0.0/buildTransitive/net6.0/Microsoft.Extensions.Logging.Abstractions.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.logging.abstractions/7.0.0/buildTransitive/net6.0/Microsoft.Extensions.Logging.Abstractions.targets')" />
</ImportGroup>
</Project>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" />

File diff suppressed because it is too large Load Diff

@ -1,81 +1,30 @@
{
"version": 2,
"dgSpecHash": "n+xdRAhcNg3J/OdmEBMOpDsgnuQbCY8EtwKbUclpRKp0/OYy4jdcYs5E4vglBVc6KURjabQne39GuK3NzrCrLA==",
"dgSpecHash": "wQAfwmPHorUKjFxQTMXchTVaWeo2gGjdDVGsDBGyC9aQdwk+Xi/Xsvkvg1DidkHWGTb7MeD9JzhsNZATgutK6A==",
"success": true,
"projectFilePath": "/root/opencode/haoliang/Haoliang.Data/Haoliang.Data.csproj",
"expectedPackageFiles": [
"/root/.nuget/packages/bcrypt.net-next/4.0.3/bcrypt.net-next.4.0.3.nupkg.sha512",
"/root/.nuget/packages/humanizer.core/2.14.1/humanizer.core.2.14.1.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.authentication.abstractions/2.2.0/microsoft.aspnetcore.authentication.abstractions.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.authorization/2.2.0/microsoft.aspnetcore.authorization.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.authorization.policy/2.2.0/microsoft.aspnetcore.authorization.policy.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.connections.abstractions/2.2.0/microsoft.aspnetcore.connections.abstractions.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.hosting.abstractions/2.2.0/microsoft.aspnetcore.hosting.abstractions.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.hosting.server.abstractions/2.2.0/microsoft.aspnetcore.hosting.server.abstractions.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.http/2.2.0/microsoft.aspnetcore.http.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.http.abstractions/2.2.0/microsoft.aspnetcore.http.abstractions.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.http.connections/1.1.0/microsoft.aspnetcore.http.connections.1.1.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.http.connections.common/1.1.0/microsoft.aspnetcore.http.connections.common.1.1.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.http.extensions/2.2.0/microsoft.aspnetcore.http.extensions.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.http.features/2.2.0/microsoft.aspnetcore.http.features.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.routing/2.2.0/microsoft.aspnetcore.routing.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.routing.abstractions/2.2.0/microsoft.aspnetcore.routing.abstractions.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.signalr/1.1.0/microsoft.aspnetcore.signalr.1.1.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.signalr.common/1.1.0/microsoft.aspnetcore.signalr.common.1.1.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.signalr.core/1.1.0/microsoft.aspnetcore.signalr.core.1.1.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.signalr.protocols.json/1.1.0/microsoft.aspnetcore.signalr.protocols.json.1.1.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.websockets/2.2.0/microsoft.aspnetcore.websockets.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.webutilities/2.2.0/microsoft.aspnetcore.webutilities.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.csharp/4.5.0/microsoft.csharp.4.5.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.entityframeworkcore/7.0.2/microsoft.entityframeworkcore.7.0.2.nupkg.sha512",
"/root/.nuget/packages/microsoft.entityframeworkcore.abstractions/7.0.2/microsoft.entityframeworkcore.abstractions.7.0.2.nupkg.sha512",
"/root/.nuget/packages/microsoft.entityframeworkcore.analyzers/7.0.2/microsoft.entityframeworkcore.analyzers.7.0.2.nupkg.sha512",
"/root/.nuget/packages/microsoft.entityframeworkcore.design/7.0.2/microsoft.entityframeworkcore.design.7.0.2.nupkg.sha512",
"/root/.nuget/packages/microsoft.entityframeworkcore.relational/7.0.2/microsoft.entityframeworkcore.relational.7.0.2.nupkg.sha512",
"/root/.nuget/packages/microsoft.entityframeworkcore.tools/7.0.2/microsoft.entityframeworkcore.tools.7.0.2.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.caching.abstractions/7.0.0/microsoft.extensions.caching.abstractions.7.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.caching.memory/7.0.0/microsoft.extensions.caching.memory.7.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.configuration.abstractions/7.0.0/microsoft.extensions.configuration.abstractions.7.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.dependencyinjection/7.0.0/microsoft.extensions.dependencyinjection.7.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.dependencyinjection.abstractions/7.0.0/microsoft.extensions.dependencyinjection.abstractions.7.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.dependencymodel/7.0.0/microsoft.extensions.dependencymodel.7.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.fileproviders.abstractions/2.2.0/microsoft.extensions.fileproviders.abstractions.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.hosting.abstractions/2.2.0/microsoft.extensions.hosting.abstractions.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.logging/7.0.0/microsoft.extensions.logging.7.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.logging.abstractions/7.0.0/microsoft.extensions.logging.abstractions.7.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.objectpool/2.2.0/microsoft.extensions.objectpool.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.options/7.0.0/microsoft.extensions.options.7.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.primitives/7.0.0/microsoft.extensions.primitives.7.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.identitymodel.abstractions/6.26.0/microsoft.identitymodel.abstractions.6.26.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.identitymodel.jsonwebtokens/6.26.0/microsoft.identitymodel.jsonwebtokens.6.26.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.identitymodel.logging/6.26.0/microsoft.identitymodel.logging.6.26.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.identitymodel.tokens/6.26.0/microsoft.identitymodel.tokens.6.26.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.net.http.headers/2.2.0/microsoft.net.http.headers.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.netcore.platforms/2.0.0/microsoft.netcore.platforms.2.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.netcore.targets/1.1.0/microsoft.netcore.targets.1.1.0.nupkg.sha512",
"/root/.nuget/packages/mono.texttemplating/2.2.1/mono.texttemplating.2.2.1.nupkg.sha512",
"/root/.nuget/packages/mysqlconnector/2.2.5/mysqlconnector.2.2.5.nupkg.sha512",
"/root/.nuget/packages/newtonsoft.json/11.0.2/newtonsoft.json.11.0.2.nupkg.sha512",
"/root/.nuget/packages/pomelo.entityframeworkcore.mysql/7.0.0/pomelo.entityframeworkcore.mysql.7.0.0.nupkg.sha512",
"/root/.nuget/packages/system.buffers/4.5.0/system.buffers.4.5.0.nupkg.sha512",
"/root/.nuget/packages/system.codedom/4.4.0/system.codedom.4.4.0.nupkg.sha512",
"/root/.nuget/packages/system.identitymodel.tokens.jwt/6.26.0/system.identitymodel.tokens.jwt.6.26.0.nupkg.sha512",
"/root/.nuget/packages/system.io/4.3.0/system.io.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.io.pipelines/4.5.2/system.io.pipelines.4.5.2.nupkg.sha512",
"/root/.nuget/packages/system.net.websockets.websocketprotocol/4.5.1/system.net.websockets.websocketprotocol.4.5.1.nupkg.sha512",
"/root/.nuget/packages/system.reflection/4.3.0/system.reflection.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.reflection.emit/4.3.0/system.reflection.emit.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.reflection.emit.ilgeneration/4.3.0/system.reflection.emit.ilgeneration.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.reflection.primitives/4.3.0/system.reflection.primitives.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.runtime/4.3.0/system.runtime.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.runtime.compilerservices.unsafe/6.0.0/system.runtime.compilerservices.unsafe.6.0.0.nupkg.sha512",
"/root/.nuget/packages/system.security.cryptography.cng/4.5.0/system.security.cryptography.cng.4.5.0.nupkg.sha512",
"/root/.nuget/packages/system.security.principal.windows/4.5.0/system.security.principal.windows.4.5.0.nupkg.sha512",
"/root/.nuget/packages/system.text.encoding/4.3.0/system.text.encoding.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.text.encodings.web/7.0.0/system.text.encodings.web.7.0.0.nupkg.sha512",
"/root/.nuget/packages/system.text.json/7.0.0/system.text.json.7.0.0.nupkg.sha512",
"/root/.nuget/packages/system.threading.channels/4.5.0/system.threading.channels.4.5.0.nupkg.sha512",
"/root/.nuget/packages/system.threading.tasks/4.3.0/system.threading.tasks.4.3.0.nupkg.sha512"
"/root/.nuget/packages/humanizer.core/2.8.26/humanizer.core.2.8.26.nupkg.sha512",
"/root/.nuget/packages/microsoft.entityframeworkcore/6.0.0/microsoft.entityframeworkcore.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.entityframeworkcore.abstractions/6.0.0/microsoft.entityframeworkcore.abstractions.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.entityframeworkcore.analyzers/6.0.0/microsoft.entityframeworkcore.analyzers.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.entityframeworkcore.design/6.0.0/microsoft.entityframeworkcore.design.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.entityframeworkcore.relational/6.0.0/microsoft.entityframeworkcore.relational.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.entityframeworkcore.tools/6.0.0/microsoft.entityframeworkcore.tools.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.caching.abstractions/6.0.0/microsoft.extensions.caching.abstractions.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.caching.memory/6.0.0/microsoft.extensions.caching.memory.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.configuration.abstractions/6.0.0/microsoft.extensions.configuration.abstractions.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.dependencyinjection/6.0.0/microsoft.extensions.dependencyinjection.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.dependencyinjection.abstractions/6.0.0/microsoft.extensions.dependencyinjection.abstractions.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.logging/6.0.0/microsoft.extensions.logging.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.logging.abstractions/6.0.0/microsoft.extensions.logging.abstractions.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.options/6.0.0/microsoft.extensions.options.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.primitives/6.0.0/microsoft.extensions.primitives.6.0.0.nupkg.sha512",
"/root/.nuget/packages/mysqlconnector/2.0.0/mysqlconnector.2.0.0.nupkg.sha512",
"/root/.nuget/packages/pomelo.entityframeworkcore.mysql/6.0.0/pomelo.entityframeworkcore.mysql.6.0.0.nupkg.sha512",
"/root/.nuget/packages/system.collections.immutable/6.0.0/system.collections.immutable.6.0.0.nupkg.sha512",
"/root/.nuget/packages/system.diagnostics.diagnosticsource/6.0.0/system.diagnostics.diagnosticsource.6.0.0.nupkg.sha512",
"/root/.nuget/packages/system.runtime.compilerservices.unsafe/6.0.0/system.runtime.compilerservices.unsafe.6.0.0.nupkg.sha512"
],
"logs": []
}

@ -1,9 +1,10 @@
using System;
using System.Collections.Generic;
using Haoliang.Models.Device;
namespace Haoliang.Models.DataCollection
{
public class CollectionTask
public class CollectionTaskDetailed
{
public int Id { get; set; }
public int DeviceId { get; set; }
@ -18,6 +19,93 @@ namespace Haoliang.Models.DataCollection
public DateTime CreatedAt { get; set; }
}
public class CollectionResultDetailed
{
public int Id { get; set; }
public int DeviceId { get; set; }
public bool IsSuccess { get; set; }
public string RawJson { get; set; }
public string ParsedData { get; set; }
public DateTime CollectionTime { get; set; }
public long? ResponseTime { get; set; }
public int? DataSize { get; set; }
public string ErrorMessage { get; set; }
public DateTime CreatedAt { get; set; }
}
public class CollectionLogDetailed
{
public int Id { get; set; }
public int DeviceId { get; set; }
public LogLevel LogLevel { get; set; }
public string LogCategory { get; set; }
public string LogMessage { get; set; }
public string LogData { get; set; }
public DateTime LogTime { get; set; }
public DateTime CreatedAt { get; set; }
}
public class PingResultDetailed
{
public bool IsSuccess { get; set; }
public int PingTimeMs { get; set; }
public string ErrorMessage { get; set; }
public DateTime Timestamp { get; set; }
}
public class DeviceCurrentStatusDetailed
{
public int DeviceId { get; set; }
public string DeviceCode { get; set; }
public DeviceStatus Status { get; set; }
public string NCProgram { get; set; }
public int CumulativeCount { get; set; }
public DateTime RecordTime { get; set; }
public bool IsActive => Status == DeviceStatus.Online;
}
public class CollectionHealthDetailed
{
public int TotalDevices { get; set; }
public int OnlineDevices { get; set; }
public int ActiveCollections { get; set; }
public double AverageResponseTime { get; set; }
public double SuccessRate { get; set; }
public Dictionary<string, int> StatusCounts { get; set; }
}
public class CollectionStatisticsDetailed
{
public DateTime Date { get; set; }
public int TotalCollections { get; set; }
public int SuccessfulCollections { get; set; }
public int FailedCollections { get; set; }
public double AverageResponseTime { get; set; }
public Dictionary<string, int> ErrorCounts { get; set; }
}
public class CollectionConfigDetailed
{
public int Id { get; set; }
public string ConfigKey { get; set; }
public string ConfigValue { get; set; }
public string Description { get; set; }
public bool IsEnabled { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
}
public class CollectionFilterDetailed
{
public List<int> DeviceIds { get; set; }
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
public bool? IsSuccess { get; set; }
public string Status { get; set; }
public int? RetryCount { get; set; }
public string SearchKeyword { get; set; }
}
public class CollectionResult
{
public int Id { get; set; }
@ -52,98 +140,97 @@ namespace Haoliang.Models.DataCollection
public DateTime Timestamp { get; set; }
}
public class DeviceStatus
public class DeviceCurrentStatus
{
public int Id { get; set; }
public int DeviceId { get; set; }
public string Status { get; set; }
public bool IsRunning { get; set; }
public string DeviceCode { get; set; }
public DeviceStatus Status { get; set; }
public string NCProgram { get; set; }
public int CumulativeCount { get; set; }
public string OperatingMode { get; set; }
public DateTime RecordTime { get; set; }
public bool IsActive => Status == DeviceStatus.Online;
}
public class TagData
// Duplicate definition removed - see CollectionHealthDetailed below
public class DetailedCollectionHealth
{
public string Id { get; set; }
public string Desc { get; set; }
public string Quality { get; set; }
public object Value { get; set; }
public DateTime Time { get; set; }
public DateTime CheckTime { get; set; }
public int TotalDevices { get; set; }
public int OnlineDevices { get; set; }
public int ActiveCollectionTasks { get; set; }
public int FailedTasks { get; set; }
public double SuccessRate { get; set; }
public double AverageResponseTime { get; set; }
public long TotalCollectedData { get; set; }
public DateTime LastSuccessfulCollection { get; set; }
public DateTime LastFailedCollection { get; set; }
}
public class CollectionStatistics
// Duplicate definition removed - see CollectionStatisticsDetailed below
public class DetailedCollectionStatistics
{
public DateTime Date { get; set; }
public int TotalAttempts { get; set; }
public int SuccessCount { get; set; }
public int FailedCount { get; set; }
public decimal SuccessRate { get; set; }
public TimeSpan AverageResponseTime { get; set; }
public int DeviceCount { get; set; }
public int OnlineDeviceCount { get; set; }
public long TotalDataSize { get; set; }
public TimeSpan? AverageResponseTime { get; set; }
}
public interface ICachingService
public class DeviceStatistics
{
Task<T> GetAsync<T>(string key);
Task SetAsync<T>(string key, T value, TimeSpan? expiration = null);
Task<bool> RemoveAsync(string key);
Task<bool> ExistsAsync(string key);
Task ClearAsync();
Task<T> GetOrCreateAsync<T>(string key, Func<Task<T>> factory, TimeSpan? expiration = null);
Task<IEnumerable<string>> GetAllKeysAsync();
Task<bool> RefreshAsync<T>(string key);
public int DeviceId { get; set; }
public string DeviceCode { get; set; }
public int TotalRunTime { get; set; }
public int TotalProductionCount { get; set; }
public double EfficiencyRate { get; set; }
public DateTime LastActiveTime { get; set; }
public Dictionary<string, int> ProgramCounts { get; set; }
}
public interface ISchedulerService
public class TagData
{
Task StartSchedulerAsync();
Task StopSchedulerAsync();
Task ScheduleTaskAsync(ScheduledTask task);
Task<bool> RemoveTaskAsync(string taskId);
Task<IEnumerable<ScheduledTask>> GetAllScheduledTasksAsync();
Task<ScheduledTask> GetTaskByIdAsync(string taskId);
Task ExecuteTaskAsync(string taskId);
Task<TaskExecutionResult> GetTaskExecutionResultAsync(string taskId);
Task<bool> IsTaskRunningAsync(string taskId);
public string Id { get; set; }
public string Description { get; set; }
public int Quality { get; set; }
public object Value { get; set; }
public DateTime Time { get; set; }
}
public interface IWebSocketAuthMiddleware
public enum DataCollectionLogLevel
{
Task AuthenticateAsync(string connectionId, string token);
Task<string> GetUserIdAsync(string connectionId);
Task<string> GetConnectionIdAsync(string userId);
Task<bool> IsAuthenticatedAsync(string connectionId);
Task<bool> HasPermissionAsync(string connectionId, string permission);
Debug = 0,
Information = 1,
Warning = 2,
Error = 3,
Critical = 4
}
public class BackgroundTaskManager : ISchedulerService
{
// Implementation would go here - this is just a placeholder
public async Task StartSchedulerAsync() { await Task.CompletedTask; }
public async Task StopSchedulerAsync() { await Task.CompletedTask; }
public async Task ScheduleTaskAsync(ScheduledTask task) { await Task.CompletedTask; }
public async Task<bool> RemoveTaskAsync(string taskId) { return true; }
public async Task<IEnumerable<ScheduledTask>> GetAllScheduledTasksAsync() { return new List<ScheduledTask>(); }
public async Task<ScheduledTask> GetTaskByIdAsync(string taskId) { return null; }
public async Task ExecuteTaskAsync(string taskId) { await Task.CompletedTask; }
public async Task<TaskExecutionResult> GetTaskExecutionResultAsync(string taskId) { return null; }
public async Task<bool> IsTaskRunningAsync(string taskId) { return false; }
}
// Duplicate definition removed - see DetailedCollectionStatistics above
// Duplicate definition removed - see CollectionFilterDetailed below
public class CacheManager : ICachingService
public class CollectionConfig
{
// Implementation would go here - this is just a placeholder
public async Task<T> GetAsync<T>(string key) { return default; }
public async Task SetAsync<T>(string key, T value, TimeSpan? expiration = null) { await Task.CompletedTask; }
public async Task<bool> RemoveAsync(string key) { return true; }
public async Task<bool> ExistsAsync(string key) { return false; }
public async Task ClearAsync() { await Task.CompletedTask; }
public async Task<T> GetOrCreateAsync<T>(string key, Func<Task<T>> factory, TimeSpan? expiration = null) { return default; }
public async Task<IEnumerable<string>> GetAllKeysAsync() { return new List<string>(); }
public async Task<bool> RefreshAsync<T>(string key) { return true; }
public int Id { get; set; }
public string ConfigKey { get; set; }
public string ConfigValue { get; set; }
public string Description { get; set; }
public bool IsEnabled { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
}
// Duplicate definition removed - see CollectionFilterDetailed in CollectionModels.cs
// Duplicate definition removed - see CollectionFilterDetailed above
// Duplicate definition removed - see CollectionHealthDetailed above
// Duplicate definition removed - see CollectionFilterDetailed in CollectionModels.cs
}

@ -19,7 +19,7 @@ namespace Haoliang.Models.DataCollection
public DateTime CreatedAt { get; set; }
}
public class CollectionResult
public class CollectionResultBasic
{
public int ResultId { get; set; }
public int TaskId { get; set; }
@ -33,7 +33,7 @@ namespace Haoliang.Models.DataCollection
public Dictionary<string, object> Metadata { get; set; }
}
public class CollectionLog
public class CollectionLogBasic
{
public int LogId { get; set; }
public int DeviceId { get; set; }
@ -44,7 +44,7 @@ namespace Haoliang.Models.DataCollection
public string Category { get; set; }
}
public class PingResult
public class PingResultBasic
{
public bool IsSuccess { get; set; }
public int PingTimeMs { get; set; }
@ -52,7 +52,7 @@ namespace Haoliang.Models.DataCollection
public DateTime Timestamp { get; set; }
}
public class DeviceCurrentStatus
public class DeviceCurrentStatusBasic
{
public int DeviceId { get; set; }
public string DeviceCode { get; set; }
@ -63,7 +63,7 @@ namespace Haoliang.Models.DataCollection
public bool IsActive => Status == DeviceStatus.Online;
}
public class CollectionHealth
public class CollectionHealthBasic
{
public int TotalDevices { get; set; }
public int OnlineDevices { get; set; }
@ -73,7 +73,7 @@ namespace Haoliang.Models.DataCollection
public Dictionary<string, int> StatusCounts { get; set; }
}
public class CollectionStatistics
public class CollectionStatisticsBasic
{
public DateTime Date { get; set; }
public int TotalCollections { get; set; }
@ -83,7 +83,11 @@ namespace Haoliang.Models.DataCollection
public Dictionary<string, int> ErrorCounts { get; set; }
}
public class DeviceStatistics
// Duplicate definition removed - see DetailedCollectionStatistics in AdditionalCollectionModels.cs
// Duplicate definition removed - see DetailedCollectionStatistics above
public class DeviceStatisticsBasic
{
public int DeviceId { get; set; }
public string DeviceCode { get; set; }
@ -94,7 +98,7 @@ namespace Haoliang.Models.DataCollection
public Dictionary<string, int> ProgramCounts { get; set; }
}
public class TagData
public class TagDataBasic
{
public string Id { get; set; }
public string Description { get; set; }
@ -102,35 +106,6 @@ namespace Haoliang.Models.DataCollection
public object Value { get; set; }
public DateTime Time { get; set; }
}
}
public class CollectionResult
{
public int Id { get; set; }
public int DeviceId { get; set; }
public int TaskId { get; set; }
public DateTime CollectionTime { get; set; }
public string RawJson { get; set; }
public bool IsSuccess { get; set; }
public string ErrorMessage { get; set; }
public int RetryCount { get; set; }
public DateTime CreatedAt { get; set; }
public DeviceCurrentStatus ParsedData { get; set; }
}
public class CollectionLog
{
public int Id { get; set; }
public int DeviceId { get; set; }
public LogLevel LogLevel { get; set; }
public string LogCategory { get; set; }
public string LogMessage { get; set; }
public string LogData { get; set; }
public string SourceMethod { get; set; }
public string SourceFile { get; set; }
public DateTime LogTime { get; set; }
public DateTime CreatedAt { get; set; }
}
public enum LogLevel
{
@ -141,7 +116,7 @@ namespace Haoliang.Models.DataCollection
Critical = 4
}
public class CollectionStatistics
public class DetailedCollectionStatisticsBasic
{
public DateTime Date { get; set; }
public int TotalAttempts { get; set; }
@ -154,7 +129,7 @@ namespace Haoliang.Models.DataCollection
public long TotalDataSize { get; set; }
}
public class CollectionConfig
public class CollectionConfigBasic
{
public int Id { get; set; }
public string ConfigKey { get; set; }
@ -165,28 +140,7 @@ namespace Haoliang.Models.DataCollection
public DateTime UpdatedAt { get; set; }
}
public class CollectionHealth
{
public DateTime CheckTime { get; set; }
public int TotalDevices { get; set; }
public int OnlineDevices { get; set; }
public int ActiveCollectionTasks { get; set; }
public int FailedTasks { get; set; }
public double SuccessRate { get; set; }
public double AverageResponseTime { get; set; }
public long TotalCollectedData { get; set; }
public DateTime LastSuccessfulCollection { get; set; }
public DateTime LastFailedCollection { get; set; }
}
// Duplicate definition removed - see DetailedCollectionHealth in AdditionalCollectionModels.cs
public class CollectionFilter
{
public List<int> DeviceIds { get; set; }
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
public bool? IsSuccess { get; set; }
public string Status { get; set; }
public int? RetryCount { get; set; }
public string SearchKeyword { get; set; }
}
// Duplicate definition removed - see CollectionFilter in AdditionalCollectionModels.cs
}

@ -19,16 +19,14 @@ namespace Haoliang.Models.Device
public DateTime UpdatedAt { get; set; }
}
public class DeviceStatus
public enum DeviceStatus
{
public int Id { get; set; }
public int DeviceId { get; set; }
public string Status { get; set; }
public bool IsRunning { get; set; }
public string NCProgram { get; set; }
public int CumulativeCount { get; set; }
public string OperatingMode { get; set; }
public DateTime RecordTime { get; set; }
Online = 1,
Offline = 2,
Running = 3,
Stopped = 4,
Error = 5,
Maintenance = 6
}
public class DeviceCurrentStatus

@ -3,7 +3,7 @@ using System.Collections.Generic;
namespace Haoliang.Models.Production
{
public class ProgramProductionSummary
public class ProgramProductionSummaryDetailed
{
public int SummaryId { get; set; }
public int DeviceId { get; set; }
@ -15,6 +15,34 @@ namespace Haoliang.Models.Production
public DateTime UpdatedAt { get; set; }
}
public class ProductionStatisticsDetailed
{
public DateTime Date { get; set; }
public int TotalDevices { get; set; }
public int ActiveDevices { get; set; }
public int TotalProduction { get; set; }
public decimal AverageProduction { get; set; }
public int TotalPrograms { get; set; }
public decimal QualityRate { get; set; }
public Dictionary<string, int> ProductionByDevice { get; set; }
public Dictionary<string, int> ProductionByProgram { get; set; }
}
public class ProductionRecordDetailed
{
public int RecordId { get; set; }
public int DeviceId { get; set; }
public string DeviceName { get; set; }
public string ProgramName { get; set; }
public int Quantity { get; set; }
public DateTime ProductionDate { get; set; }
public TimeSpan ProductionTime { get; set; }
public bool IsCompleted { get; set; }
public string Operator { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
}
public class ProductionSummary
{
public int SummaryId { get; set; }

@ -4,7 +4,7 @@ using Haoliang.Models.Device;
namespace Haoliang.Models.Production
{
public class ProductionRecord
public class ProductionRecordBasic
{
public int Id { get; set; }
public int DeviceId { get; set; }
@ -18,6 +18,8 @@ namespace Haoliang.Models.Production
public DateTime CreatedAt { get; set; }
}
// Duplicate definition removed - see ProductionStatisticsBasic above
public class ProgramProductionSummary
{
public int Id { get; set; }
@ -30,7 +32,7 @@ namespace Haoliang.Models.Production
public decimal QualityRate { get; set; }
}
public class ProductionStatistics
public class ProductionStatisticsBasic
{
public DateTime Date { get; set; }
public int DeviceId { get; set; }

@ -53,7 +53,7 @@ namespace Haoliang.Models.System
Delivered = 4
}
public class Alarm
public class AlarmDetailed
{
public int AlarmId { get; set; }
public int DeviceId { get; set; }
@ -71,7 +71,7 @@ namespace Haoliang.Models.System
public bool IsActive => AlarmStatus == AlarmStatus.Active;
}
public class AlarmRule
public class AlarmRuleDetailed
{
public int RuleId { get; set; }
public string RuleName { get; set; }
@ -84,7 +84,7 @@ namespace Haoliang.Models.System
public DateTime? UpdatedAt { get; set; }
}
public class AlarmNotification
public class AlarmNotificationDetailed
{
public int NotificationId { get; set; }
public int AlarmId { get; set; }
@ -97,7 +97,7 @@ namespace Haoliang.Models.System
public DateTime? RetryTime { get; set; }
}
public class AlarmStatistics
public class AlarmStatisticsDetailed
{
public int TotalAlarms { get; set; }
public int ActiveAlarms { get; set; }
@ -107,7 +107,7 @@ namespace Haoliang.Models.System
public Dictionary<AlarmSeverity, int> AlarmsBySeverity { get; set; }
}
public class LogEntry
public class LogEntryDetailed
{
public int LogId { get; set; }
public LogLevel LogLevel { get; set; }

@ -0,0 +1,17 @@
using System;
namespace Haoliang.Models.System
{
public class LogEntry
{
public int Id { get; set; }
public DateTime Timestamp { get; set; }
public string Level { get; set; }
public string Category { get; set; }
public string Message { get; set; }
public string Exception { get; set; }
public string Source { get; set; }
public string DeviceId { get; set; }
public DateTime CreatedAt { get; set; }
}
}

@ -43,7 +43,7 @@ namespace Haoliang.Models.System
public DateTime UpdatedAt { get; set; }
}
public class SystemConfig
public class SystemConfigBasic
{
public int Id { get; set; }
public string ConfigKey { get; set; }

@ -1,6 +1,6 @@
namespace Haoliang.Models.System
{
public class SystemConfig
public class SystemConfigDetailed
{
public int ConfigId { get; set; }
public string ConfigKey { get; set; }
@ -12,7 +12,7 @@ namespace Haoliang.Models.System
public bool IsSystem { get; set; }
}
public class ScheduledTask
public class ScheduledTaskDetailed
{
public string TaskId { get; set; }
public string TaskName { get; set; }
@ -26,7 +26,7 @@ namespace Haoliang.Models.System
public string ErrorMessage { get; set; }
}
public class TaskExecutionResult
public class TaskExecutionResultDetailed
{
public string TaskId { get; set; }
public bool IsSuccess { get; set; }
@ -36,7 +36,7 @@ namespace Haoliang.Models.System
public TimeSpan Duration { get; set; }
}
public enum TaskStatus
public enum TaskStatusDetailed
{
Pending = 1,
Running = 2,
@ -56,7 +56,7 @@ namespace Haoliang.Models.System
Dictionary<string, object> Metadata { get; set; }
}
public class SystemHealth
public class SystemHealthDetailed
{
public string Status { get; set; }
public DateTime Timestamp { get; set; }

@ -9,7 +9,7 @@ namespace Haoliang.Models.Template
public string BrandName { get; set; }
public string Description { get; set; }
public bool IsEnabled { get; set; }
public List<TemplateFieldMapping> FieldMappings { get; set; }
public List<TemplateFieldMapping> FieldMappings { get; set; } = new List<TemplateFieldMapping>();
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
}

@ -0,0 +1,17 @@
using System;
namespace Haoliang.Models.Template
{
public class TagMapping
{
public int Id { get; set; }
public int TemplateId { get; set; }
public string SourceFieldPath { get; set; }
public string StandardFieldId { get; set; }
public string StandardFieldDesc { get; set; }
public string DataType { get; set; }
public ConversionRule ConversionRule { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime? UpdatedAt { get; set; }
}
}

@ -1 +1 @@
e646755fc76efe336c702b67be8a443e31ae6973
77a9315ff1d80b1bb2e72d8fd3baedd1d80436db

@ -22,7 +22,6 @@
<PackageReference Include="Moq" Version="4.20.69" />
<PackageReference Include="Moq.AutoMock" Version="3.5.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.0" />
<PackageReference Include="Microsoft.SignalR.Client" Version="6.0.0" />
</ItemGroup>
<ItemGroup>

@ -26,6 +26,9 @@
"net6.0": {
"targetAlias": "net6.0",
"projectReferences": {
"/root/opencode/haoliang/Haoliang.Data/Haoliang.Data.csproj": {
"projectPath": "/root/opencode/haoliang/Haoliang.Data/Haoliang.Data.csproj"
},
"/root/opencode/haoliang/Haoliang.Models/Haoliang.Models.csproj": {
"projectPath": "/root/opencode/haoliang/Haoliang.Models/Haoliang.Models.csproj"
}
@ -41,6 +44,36 @@
"frameworks": {
"net6.0": {
"targetAlias": "net6.0",
"dependencies": {
"BCrypt.Net-Next": {
"target": "Package",
"version": "[4.0.3, )"
},
"Microsoft.AspNetCore.Http.Abstractions": {
"target": "Package",
"version": "[2.2.0, )"
},
"Microsoft.AspNetCore.SignalR": {
"target": "Package",
"version": "[1.1.0, )"
},
"Microsoft.Extensions.Caching.Memory": {
"target": "Package",
"version": "[6.0.0, )"
},
"Microsoft.Extensions.Logging.Abstractions": {
"target": "Package",
"version": "[6.0.0, )"
},
"Microsoft.IdentityModel.Tokens": {
"target": "Package",
"version": "[6.26.0, )"
},
"System.IdentityModel.Tokens.Jwt": {
"target": "Package",
"version": "[6.26.0, )"
}
},
"imports": [
"net461",
"net462",
@ -82,9 +115,6 @@
"net6.0": {
"targetAlias": "net6.0",
"projectReferences": {
"/root/opencode/haoliang/Haoliang.Core/Haoliang.Core.csproj": {
"projectPath": "/root/opencode/haoliang/Haoliang.Core/Haoliang.Core.csproj"
},
"/root/opencode/haoliang/Haoliang.Models/Haoliang.Models.csproj": {
"projectPath": "/root/opencode/haoliang/Haoliang.Models/Haoliang.Models.csproj"
}
@ -103,19 +133,19 @@
"dependencies": {
"Microsoft.EntityFrameworkCore": {
"target": "Package",
"version": "[7.0.2, )"
"version": "[6.0.0, )"
},
"Microsoft.EntityFrameworkCore.Design": {
"target": "Package",
"version": "[7.0.2, )"
"version": "[6.0.0, )"
},
"Microsoft.EntityFrameworkCore.Tools": {
"target": "Package",
"version": "[7.0.2, )"
"version": "[6.0.0, )"
},
"Pomelo.EntityFrameworkCore.MySql": {
"target": "Package",
"version": "[7.0.0, )"
"version": "[6.0.0, )"
}
},
"imports": [
@ -233,6 +263,10 @@
"net6.0": {
"targetAlias": "net6.0",
"dependencies": {
"Microsoft.AspNetCore.Mvc.Testing": {
"target": "Package",
"version": "[6.0.0, )"
},
"Microsoft.EntityFrameworkCore.InMemory": {
"target": "Package",
"version": "[6.0.32, )"
@ -241,6 +275,14 @@
"target": "Package",
"version": "[16.11.0, )"
},
"Moq": {
"target": "Package",
"version": "[4.20.69, )"
},
"Moq.AutoMock": {
"target": "Package",
"version": "[3.5.0, )"
},
"coverlet.collector": {
"include": "Runtime, Build, Native, ContentFiles, Analyzers, BuildTransitive",
"suppressParent": "All",

@ -15,14 +15,13 @@
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<Import Project="$(NuGetPackageRoot)xunit.runner.visualstudio/2.4.3/build/netcoreapp2.1/xunit.runner.visualstudio.props" Condition="Exists('$(NuGetPackageRoot)xunit.runner.visualstudio/2.4.3/build/netcoreapp2.1/xunit.runner.visualstudio.props')" />
<Import Project="$(NuGetPackageRoot)xunit.core/2.4.1/build/xunit.core.props" Condition="Exists('$(NuGetPackageRoot)xunit.core/2.4.1/build/xunit.core.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.entityframeworkcore/7.0.2/buildTransitive/net6.0/Microsoft.EntityFrameworkCore.props" Condition="Exists('$(NuGetPackageRoot)microsoft.entityframeworkcore/7.0.2/buildTransitive/net6.0/Microsoft.EntityFrameworkCore.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.entityframeworkcore/6.0.32/buildTransitive/net6.0/Microsoft.EntityFrameworkCore.props" Condition="Exists('$(NuGetPackageRoot)microsoft.entityframeworkcore/6.0.32/buildTransitive/net6.0/Microsoft.EntityFrameworkCore.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.testplatform.testhost/16.11.0/build/netcoreapp2.1/Microsoft.TestPlatform.TestHost.props" Condition="Exists('$(NuGetPackageRoot)microsoft.testplatform.testhost/16.11.0/build/netcoreapp2.1/Microsoft.TestPlatform.TestHost.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.codecoverage/16.11.0/build/netstandard1.0/Microsoft.CodeCoverage.props" Condition="Exists('$(NuGetPackageRoot)microsoft.codecoverage/16.11.0/build/netstandard1.0/Microsoft.CodeCoverage.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.net.test.sdk/16.11.0/build/netcoreapp2.1/Microsoft.NET.Test.Sdk.props" Condition="Exists('$(NuGetPackageRoot)microsoft.net.test.sdk/16.11.0/build/netcoreapp2.1/Microsoft.NET.Test.Sdk.props')" />
</ImportGroup>
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<Pkgxunit_analyzers Condition=" '$(Pkgxunit_analyzers)' == '' ">/root/.nuget/packages/xunit.analyzers/0.10.0</Pkgxunit_analyzers>
<PkgNewtonsoft_Json Condition=" '$(PkgNewtonsoft_Json)' == '' ">/root/.nuget/packages/newtonsoft.json/9.0.1</PkgNewtonsoft_Json>
<PkgMicrosoft_EntityFrameworkCore_Tools Condition=" '$(PkgMicrosoft_EntityFrameworkCore_Tools)' == '' ">/root/.nuget/packages/microsoft.entityframeworkcore.tools/7.0.2</PkgMicrosoft_EntityFrameworkCore_Tools>
<PkgMicrosoft_EntityFrameworkCore_Tools Condition=" '$(PkgMicrosoft_EntityFrameworkCore_Tools)' == '' ">/root/.nuget/packages/microsoft.entityframeworkcore.tools/6.0.0</PkgMicrosoft_EntityFrameworkCore_Tools>
</PropertyGroup>
</Project>

@ -2,10 +2,9 @@
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<Import Project="$(NuGetPackageRoot)xunit.core/2.4.1/build/xunit.core.targets" Condition="Exists('$(NuGetPackageRoot)xunit.core/2.4.1/build/xunit.core.targets')" />
<Import Project="$(NuGetPackageRoot)system.text.json/7.0.0/buildTransitive/net6.0/System.Text.Json.targets" Condition="Exists('$(NuGetPackageRoot)system.text.json/7.0.0/buildTransitive/net6.0/System.Text.Json.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.extensions.logging.abstractions/7.0.0/buildTransitive/net6.0/Microsoft.Extensions.Logging.Abstractions.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.logging.abstractions/7.0.0/buildTransitive/net6.0/Microsoft.Extensions.Logging.Abstractions.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.codecoverage/16.11.0/build/netstandard1.0/Microsoft.CodeCoverage.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.codecoverage/16.11.0/build/netstandard1.0/Microsoft.CodeCoverage.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.net.test.sdk/16.11.0/build/netcoreapp2.1/Microsoft.NET.Test.Sdk.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.net.test.sdk/16.11.0/build/netcoreapp2.1/Microsoft.NET.Test.Sdk.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.aspnetcore.mvc.testing/6.0.0/buildTransitive/net6.0/Microsoft.AspNetCore.Mvc.Testing.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.aspnetcore.mvc.testing/6.0.0/buildTransitive/net6.0/Microsoft.AspNetCore.Mvc.Testing.targets')" />
<Import Project="$(NuGetPackageRoot)coverlet.collector/3.1.0/build/netstandard1.0/coverlet.collector.targets" Condition="Exists('$(NuGetPackageRoot)coverlet.collector/3.1.0/build/netstandard1.0/coverlet.collector.targets')" />
</ImportGroup>
</Project>

File diff suppressed because it is too large Load Diff

@ -1,42 +1,92 @@
{
"version": 2,
"dgSpecHash": "vhR3s37eZ0JKCSsDdknFHWgEI3WxKpEWEco7km6fI//ih0qiSnXd8nDqT/ZNGzLXv/gF/3itOvSLKFhkCmlPIw==",
"dgSpecHash": "RbyKziyt9NEOWfYZG8HhwGgKNEAU9l8qa1+pOr1zRs8wU3hMPLsvtHDrmaBGHe3/vwjmJWMQiFVqo4FkIKgFNg==",
"success": true,
"projectFilePath": "/root/opencode/haoliang/Haoliang.Tests/Haoliang.Tests.csproj",
"expectedPackageFiles": [
"/root/.nuget/packages/bcrypt.net-next/4.0.3/bcrypt.net-next.4.0.3.nupkg.sha512",
"/root/.nuget/packages/castle.core/5.1.1/castle.core.5.1.1.nupkg.sha512",
"/root/.nuget/packages/coverlet.collector/3.1.0/coverlet.collector.3.1.0.nupkg.sha512",
"/root/.nuget/packages/humanizer.core/2.14.1/humanizer.core.2.14.1.nupkg.sha512",
"/root/.nuget/packages/humanizer.core/2.8.26/humanizer.core.2.8.26.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.authentication.abstractions/2.2.0/microsoft.aspnetcore.authentication.abstractions.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.authorization/2.2.0/microsoft.aspnetcore.authorization.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.authorization.policy/2.2.0/microsoft.aspnetcore.authorization.policy.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.connections.abstractions/2.2.0/microsoft.aspnetcore.connections.abstractions.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.hosting.abstractions/2.2.0/microsoft.aspnetcore.hosting.abstractions.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.hosting.server.abstractions/2.2.0/microsoft.aspnetcore.hosting.server.abstractions.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.http/2.2.0/microsoft.aspnetcore.http.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.http.abstractions/2.2.0/microsoft.aspnetcore.http.abstractions.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.http.connections/1.1.0/microsoft.aspnetcore.http.connections.1.1.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.http.connections.common/1.1.0/microsoft.aspnetcore.http.connections.common.1.1.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.http.extensions/2.2.0/microsoft.aspnetcore.http.extensions.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.http.features/2.2.0/microsoft.aspnetcore.http.features.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.mvc.testing/6.0.0/microsoft.aspnetcore.mvc.testing.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.routing/2.2.0/microsoft.aspnetcore.routing.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.routing.abstractions/2.2.0/microsoft.aspnetcore.routing.abstractions.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.signalr/1.1.0/microsoft.aspnetcore.signalr.1.1.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.signalr.common/1.1.0/microsoft.aspnetcore.signalr.common.1.1.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.signalr.core/1.1.0/microsoft.aspnetcore.signalr.core.1.1.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.signalr.protocols.json/1.1.0/microsoft.aspnetcore.signalr.protocols.json.1.1.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.testhost/6.0.0/microsoft.aspnetcore.testhost.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.websockets/2.2.0/microsoft.aspnetcore.websockets.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.aspnetcore.webutilities/2.2.0/microsoft.aspnetcore.webutilities.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.codecoverage/16.11.0/microsoft.codecoverage.16.11.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.csharp/4.0.1/microsoft.csharp.4.0.1.nupkg.sha512",
"/root/.nuget/packages/microsoft.entityframeworkcore/7.0.2/microsoft.entityframeworkcore.7.0.2.nupkg.sha512",
"/root/.nuget/packages/microsoft.entityframeworkcore.abstractions/7.0.2/microsoft.entityframeworkcore.abstractions.7.0.2.nupkg.sha512",
"/root/.nuget/packages/microsoft.entityframeworkcore.analyzers/7.0.2/microsoft.entityframeworkcore.analyzers.7.0.2.nupkg.sha512",
"/root/.nuget/packages/microsoft.entityframeworkcore.design/7.0.2/microsoft.entityframeworkcore.design.7.0.2.nupkg.sha512",
"/root/.nuget/packages/microsoft.csharp/4.5.0/microsoft.csharp.4.5.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.entityframeworkcore/6.0.32/microsoft.entityframeworkcore.6.0.32.nupkg.sha512",
"/root/.nuget/packages/microsoft.entityframeworkcore.abstractions/6.0.32/microsoft.entityframeworkcore.abstractions.6.0.32.nupkg.sha512",
"/root/.nuget/packages/microsoft.entityframeworkcore.analyzers/6.0.32/microsoft.entityframeworkcore.analyzers.6.0.32.nupkg.sha512",
"/root/.nuget/packages/microsoft.entityframeworkcore.design/6.0.0/microsoft.entityframeworkcore.design.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.entityframeworkcore.inmemory/6.0.32/microsoft.entityframeworkcore.inmemory.6.0.32.nupkg.sha512",
"/root/.nuget/packages/microsoft.entityframeworkcore.relational/7.0.2/microsoft.entityframeworkcore.relational.7.0.2.nupkg.sha512",
"/root/.nuget/packages/microsoft.entityframeworkcore.tools/7.0.2/microsoft.entityframeworkcore.tools.7.0.2.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.caching.abstractions/7.0.0/microsoft.extensions.caching.abstractions.7.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.caching.memory/7.0.0/microsoft.extensions.caching.memory.7.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.configuration.abstractions/7.0.0/microsoft.extensions.configuration.abstractions.7.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.dependencyinjection/7.0.0/microsoft.extensions.dependencyinjection.7.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.dependencyinjection.abstractions/7.0.0/microsoft.extensions.dependencyinjection.abstractions.7.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.dependencymodel/7.0.0/microsoft.extensions.dependencymodel.7.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.logging/7.0.0/microsoft.extensions.logging.7.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.logging.abstractions/7.0.0/microsoft.extensions.logging.abstractions.7.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.options/7.0.0/microsoft.extensions.options.7.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.primitives/7.0.0/microsoft.extensions.primitives.7.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.entityframeworkcore.relational/6.0.0/microsoft.entityframeworkcore.relational.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.entityframeworkcore.tools/6.0.0/microsoft.entityframeworkcore.tools.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.caching.abstractions/6.0.0/microsoft.extensions.caching.abstractions.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.caching.memory/6.0.1/microsoft.extensions.caching.memory.6.0.1.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.configuration/6.0.0/microsoft.extensions.configuration.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.configuration.abstractions/6.0.0/microsoft.extensions.configuration.abstractions.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.configuration.binder/6.0.0/microsoft.extensions.configuration.binder.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.configuration.commandline/6.0.0/microsoft.extensions.configuration.commandline.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.configuration.environmentvariables/6.0.0/microsoft.extensions.configuration.environmentvariables.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.configuration.fileextensions/6.0.0/microsoft.extensions.configuration.fileextensions.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.configuration.json/6.0.0/microsoft.extensions.configuration.json.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.configuration.usersecrets/6.0.0/microsoft.extensions.configuration.usersecrets.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.dependencyinjection/6.0.1/microsoft.extensions.dependencyinjection.6.0.1.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.dependencyinjection.abstractions/6.0.0/microsoft.extensions.dependencyinjection.abstractions.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.dependencymodel/6.0.0/microsoft.extensions.dependencymodel.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.fileproviders.abstractions/6.0.0/microsoft.extensions.fileproviders.abstractions.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.fileproviders.physical/6.0.0/microsoft.extensions.fileproviders.physical.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.filesystemglobbing/6.0.0/microsoft.extensions.filesystemglobbing.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.hosting/6.0.0/microsoft.extensions.hosting.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.hosting.abstractions/6.0.0/microsoft.extensions.hosting.abstractions.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.logging/6.0.0/microsoft.extensions.logging.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.logging.abstractions/6.0.0/microsoft.extensions.logging.abstractions.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.logging.configuration/6.0.0/microsoft.extensions.logging.configuration.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.logging.console/6.0.0/microsoft.extensions.logging.console.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.logging.debug/6.0.0/microsoft.extensions.logging.debug.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.logging.eventlog/6.0.0/microsoft.extensions.logging.eventlog.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.logging.eventsource/6.0.0/microsoft.extensions.logging.eventsource.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.objectpool/2.2.0/microsoft.extensions.objectpool.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.options/6.0.0/microsoft.extensions.options.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.options.configurationextensions/6.0.0/microsoft.extensions.options.configurationextensions.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.extensions.primitives/6.0.0/microsoft.extensions.primitives.6.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.identitymodel.abstractions/6.26.0/microsoft.identitymodel.abstractions.6.26.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.identitymodel.jsonwebtokens/6.26.0/microsoft.identitymodel.jsonwebtokens.6.26.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.identitymodel.logging/6.26.0/microsoft.identitymodel.logging.6.26.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.identitymodel.tokens/6.26.0/microsoft.identitymodel.tokens.6.26.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.net.http.headers/2.2.0/microsoft.net.http.headers.2.2.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.net.test.sdk/16.11.0/microsoft.net.test.sdk.16.11.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.netcore.platforms/1.1.0/microsoft.netcore.platforms.1.1.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.netcore.platforms/2.0.0/microsoft.netcore.platforms.2.0.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.netcore.targets/1.1.0/microsoft.netcore.targets.1.1.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.testplatform.objectmodel/16.11.0/microsoft.testplatform.objectmodel.16.11.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.testplatform.testhost/16.11.0/microsoft.testplatform.testhost.16.11.0.nupkg.sha512",
"/root/.nuget/packages/microsoft.win32.primitives/4.3.0/microsoft.win32.primitives.4.3.0.nupkg.sha512",
"/root/.nuget/packages/mono.texttemplating/2.2.1/mono.texttemplating.2.2.1.nupkg.sha512",
"/root/.nuget/packages/mysqlconnector/2.2.5/mysqlconnector.2.2.5.nupkg.sha512",
"/root/.nuget/packages/moq/4.20.69/moq.4.20.69.nupkg.sha512",
"/root/.nuget/packages/moq.automock/3.5.0/moq.automock.3.5.0.nupkg.sha512",
"/root/.nuget/packages/mysqlconnector/2.0.0/mysqlconnector.2.0.0.nupkg.sha512",
"/root/.nuget/packages/netstandard.library/1.6.1/netstandard.library.1.6.1.nupkg.sha512",
"/root/.nuget/packages/newtonsoft.json/9.0.1/newtonsoft.json.9.0.1.nupkg.sha512",
"/root/.nuget/packages/newtonsoft.json/11.0.2/newtonsoft.json.11.0.2.nupkg.sha512",
"/root/.nuget/packages/nonblocking/2.1.1/nonblocking.2.1.1.nupkg.sha512",
"/root/.nuget/packages/nuget.frameworks/5.0.0/nuget.frameworks.5.0.0.nupkg.sha512",
"/root/.nuget/packages/pomelo.entityframeworkcore.mysql/7.0.0/pomelo.entityframeworkcore.mysql.7.0.0.nupkg.sha512",
"/root/.nuget/packages/pomelo.entityframeworkcore.mysql/6.0.0/pomelo.entityframeworkcore.mysql.6.0.0.nupkg.sha512",
"/root/.nuget/packages/runtime.debian.8-x64.runtime.native.system.security.cryptography.openssl/4.3.0/runtime.debian.8-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"/root/.nuget/packages/runtime.fedora.23-x64.runtime.native.system.security.cryptography.openssl/4.3.0/runtime.fedora.23-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"/root/.nuget/packages/runtime.fedora.24-x64.runtime.native.system.security.cryptography.openssl/4.3.0/runtime.fedora.24-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
@ -54,29 +104,33 @@
"/root/.nuget/packages/runtime.ubuntu.16.04-x64.runtime.native.system.security.cryptography.openssl/4.3.0/runtime.ubuntu.16.04-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"/root/.nuget/packages/runtime.ubuntu.16.10-x64.runtime.native.system.security.cryptography.openssl/4.3.0/runtime.ubuntu.16.10-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.appcontext/4.3.0/system.appcontext.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.buffers/4.3.0/system.buffers.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.codedom/4.4.0/system.codedom.4.4.0.nupkg.sha512",
"/root/.nuget/packages/system.buffers/4.5.1/system.buffers.4.5.1.nupkg.sha512",
"/root/.nuget/packages/system.collections/4.3.0/system.collections.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.collections.concurrent/4.3.0/system.collections.concurrent.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.collections.immutable/6.0.0/system.collections.immutable.6.0.0.nupkg.sha512",
"/root/.nuget/packages/system.console/4.3.0/system.console.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.diagnostics.debug/4.3.0/system.diagnostics.debug.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.diagnostics.diagnosticsource/4.3.0/system.diagnostics.diagnosticsource.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.diagnostics.diagnosticsource/6.0.1/system.diagnostics.diagnosticsource.6.0.1.nupkg.sha512",
"/root/.nuget/packages/system.diagnostics.eventlog/6.0.0/system.diagnostics.eventlog.6.0.0.nupkg.sha512",
"/root/.nuget/packages/system.diagnostics.tools/4.3.0/system.diagnostics.tools.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.diagnostics.tracing/4.3.0/system.diagnostics.tracing.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.dynamic.runtime/4.0.11/system.dynamic.runtime.4.0.11.nupkg.sha512",
"/root/.nuget/packages/system.globalization/4.3.0/system.globalization.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.globalization.calendars/4.3.0/system.globalization.calendars.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.globalization.extensions/4.3.0/system.globalization.extensions.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.identitymodel.tokens.jwt/6.26.0/system.identitymodel.tokens.jwt.6.26.0.nupkg.sha512",
"/root/.nuget/packages/system.io/4.3.0/system.io.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.io.compression/4.3.0/system.io.compression.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.io.compression.zipfile/4.3.0/system.io.compression.zipfile.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.io.filesystem/4.3.0/system.io.filesystem.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.io.filesystem.primitives/4.3.0/system.io.filesystem.primitives.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.io.pipelines/6.0.0/system.io.pipelines.6.0.0.nupkg.sha512",
"/root/.nuget/packages/system.linq/4.3.0/system.linq.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.linq.expressions/4.3.0/system.linq.expressions.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.memory/4.5.4/system.memory.4.5.4.nupkg.sha512",
"/root/.nuget/packages/system.net.http/4.3.0/system.net.http.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.net.primitives/4.3.0/system.net.primitives.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.net.sockets/4.3.0/system.net.sockets.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.net.websockets.websocketprotocol/4.5.1/system.net.websockets.websocketprotocol.4.5.1.nupkg.sha512",
"/root/.nuget/packages/system.objectmodel/4.3.0/system.objectmodel.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.reflection/4.3.0/system.reflection.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.reflection.emit/4.3.0/system.reflection.emit.4.3.0.nupkg.sha512",
@ -94,20 +148,21 @@
"/root/.nuget/packages/system.runtime.interopservices/4.3.0/system.runtime.interopservices.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.runtime.interopservices.runtimeinformation/4.3.0/system.runtime.interopservices.runtimeinformation.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.runtime.numerics/4.3.0/system.runtime.numerics.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.runtime.serialization.primitives/4.1.1/system.runtime.serialization.primitives.4.1.1.nupkg.sha512",
"/root/.nuget/packages/system.security.cryptography.algorithms/4.3.0/system.security.cryptography.algorithms.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.security.cryptography.cng/4.3.0/system.security.cryptography.cng.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.security.cryptography.cng/4.5.0/system.security.cryptography.cng.4.5.0.nupkg.sha512",
"/root/.nuget/packages/system.security.cryptography.csp/4.3.0/system.security.cryptography.csp.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.security.cryptography.encoding/4.3.0/system.security.cryptography.encoding.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.security.cryptography.openssl/4.3.0/system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.security.cryptography.primitives/4.3.0/system.security.cryptography.primitives.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.security.cryptography.x509certificates/4.3.0/system.security.cryptography.x509certificates.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.security.principal.windows/4.5.0/system.security.principal.windows.4.5.0.nupkg.sha512",
"/root/.nuget/packages/system.text.encoding/4.3.0/system.text.encoding.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.text.encoding.extensions/4.3.0/system.text.encoding.extensions.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.text.encodings.web/7.0.0/system.text.encodings.web.7.0.0.nupkg.sha512",
"/root/.nuget/packages/system.text.json/7.0.0/system.text.json.7.0.0.nupkg.sha512",
"/root/.nuget/packages/system.text.encodings.web/6.0.0/system.text.encodings.web.6.0.0.nupkg.sha512",
"/root/.nuget/packages/system.text.json/6.0.0/system.text.json.6.0.0.nupkg.sha512",
"/root/.nuget/packages/system.text.regularexpressions/4.3.0/system.text.regularexpressions.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.threading/4.3.0/system.threading.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.threading.channels/4.5.0/system.threading.channels.4.5.0.nupkg.sha512",
"/root/.nuget/packages/system.threading.tasks/4.3.0/system.threading.tasks.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.threading.tasks.extensions/4.3.0/system.threading.tasks.extensions.4.3.0.nupkg.sha512",
"/root/.nuget/packages/system.threading.timer/4.3.0/system.threading.timer.4.3.0.nupkg.sha512",

@ -0,0 +1,124 @@
{
"ConnectionStrings": {
"DefaultConnection": "server=localhost;database=cnc_business;user=cnc_user;password=your_password;port=3306",
"BusinessDbConnection": "server=localhost;database=cnc_business;user=cnc_user;password=your_password;port=3306",
"LogDbConnection": "server=localhost;database=cnc_log;user=cnc_user;password=your_password;port=3306"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"AppSettings": {
"Name": "CNC Data Collection System",
"Version": "1.0.0",
"Environment": "Development",
"EnableSwagger": true,
"EnableSignalR": true,
"DefaultCollectionInterval": 60,
"MaxRetryAttempts": 3,
"RetryDelaySeconds": 30,
"DevicePingTimeoutSeconds": 5,
"DataRetentionDays": 90,
"EnableHealthChecks": true,
"EnableMetrics": true,
"JwtSettings": {
"SecretKey": "your_super_secret_jwt_key_here",
"Issuer": "CNC_System",
"Audience": "CNC_WebApp",
"ExpirationHours": 24
},
"EmailSettings": {
"SmtpServer": "smtp.gmail.com",
"SmtpPort": 587,
"Username": "your_email@gmail.com",
"Password": "your_app_password",
"UseSsl": true
},
"SmsSettings": {
"Provider": "Twilio",
"AccountSid": "your_account_sid",
"AuthToken": "your_auth_token",
"FromNumber": "+1234567890"
},
"WeChatSettings": {
"AppId": "your_wechat_app_id",
"AppSecret": "your_wechat_app_secret",
"AccessToken": "your_access_token"
}
},
"CollectionSettings": {
"Enabled": true,
"IntervalSeconds": 60,
"MaxRetryAttempts": 3,
"RetryDelaySeconds": 30,
"PingTimeoutSeconds": 5,
"DataRetentionDays": 90,
"ParallelCollections": 10,
"EnableCompression": true,
"BatchSize": 100
},
"ProductionSettings": {
"Enabled": true,
"CalculationIntervalMinutes": 5,
"AutoArchiveDays": 90,
"QualityCheckEnabled": true,
"AnomalyDetectionEnabled": true,
"ForecastDays": 7,
"OeeCalculationEnabled": true
},
"AlarmSettings": {
"Enabled": true,
"AutoResolveHours": 24,
"MaxActiveAlarms": 100,
"NotificationEnabled": true,
"EmailNotifications": true,
"SmsNotifications": false,
"WeChatNotifications": false,
"EscalationEnabled": true,
"EscalationIntervalMinutes": 30
},
"TemplateSettings": {
"Enabled": true,
"DefaultBrand": "FANUC",
"ValidationEnabled": true,
"AutoBackupEnabled": true,
"BackupIntervalDays": 7
},
"RealTimeSettings": {
"Enabled": true,
"UpdateIntervalSeconds": 30,
"MaxConnections": 1000,
"HeartbeatIntervalSeconds": 60,
"EnableCompression": true
},
"CacheSettings": {
"Enabled": true,
"Provider": "Memory",
"ExpirationMinutes": 30,
"SizeLimitMB": 512,
"SlidingExpiration": true
},
"SecuritySettings": {
"JwtExpirationHours": 24,
"PasswordRequireDigit": true,
"PasswordRequireLowercase": true,
"PasswordRequireUppercase": true,
"PasswordRequireNonalphanumeric": true,
"PasswordRequiredLength": 8,
"LoginAttemptLockout": true,
"MaxFailedLoginAttempts": 5,
"LockoutDurationMinutes": 15
},
"PerformanceSettings": {
"EnableMetrics": true,
"EnableProfiling": false,
"SlowQueryThresholdMs": 1000,
"EnableCompression": true,
"EnableCaching": true,
"BatchSize": 100
}
}
Loading…
Cancel
Save