| | |
| | | # CLAUDE.md |
| | | |
| | | 本文件为 Claude Code (claude.ai/code) 在此代码库中工作时提供指导。 |
| | | This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| | | |
| | | ## 构建命令 |
| | | ## 项目概述 |
| | | |
| | | **WIDESEAWCS** 是一个仓库控制系统,基于 ASP.NET Core 6.0 构建。用于管理自动化物料处理设备(堆垛机、输送线、机器人、穿梭车等)的工业仓储环境。 |
| | | |
| | | ## 构建与运行命令 |
| | | |
| | | ```bash |
| | | # 构建整个解决方案 |
| | | dotnet build WIDESEAWCS_Server.sln |
| | | |
| | | # 构建并运行服务器 |
| | | cd WIDESEAWCS_Server |
| | | dotnet run |
| | | # 运行服务器(端口 9292) |
| | | dotnet run --project WIDESEAWCS_Server/WIDESEAWCS_Server.csproj |
| | | |
| | | # 运行测试 |
| | | cd WIDESEAWCS_Tests |
| | | dotnet test |
| | | dotnet test WIDESEAWCS_Tests/WIDESEAWCS_Tests.csproj |
| | | ``` |
| | | |
| | | ## 架构概述 |
| | | ## 架构 |
| | | |
| | | 这是一个基于 ASP.NET Core 6.0 构建的 **WCS(仓库控制系统)**,使用以下技术: |
| | | ### 项目结构 |
| | | |
| | | - **Autofac** - 通过 `IDependency` 标记接口实现自动服务发现的依赖注入 |
| | | - **Quartz.NET** - 定时任务执行(设备通信循环) |
| | | - **SqlSugar ORM** - 数据库访问 |
| | | - **Redis**(通过 `WIDESEAWCS_RedisService`)- 采用 L1+L2 混合模式的分布式缓存 |
| | | - **StackExchange.Redis** - Redis 操作 |
| | | - **TCP Socket Server** - 实时设备通信 |
| | | - **HslCommunication** 库 - PLC/硬件通信 |
| | | | 项目 | 用途 | |
| | | | ------------------------- | ----------------------------------- | |
| | | | `WIDESEAWCS_Server` | 主 Web API 入口(端口 9292) | |
| | | | `WIDESEAWCS_Core` | 框架工具(数据库、缓存、依赖注入、日志、认证) | |
| | | | `WIDESEAWCS_Common` | 常量、枚举、Redis 键定义 | |
| | | | `WIDESEAWCS_Model` | 数据库实体模型 | |
| | | | `WIDESEAWCS_DTO` | 数据传输对象 | |
| | | | `WIDESEAWCS_Communicator` | 工业设备通信协议(Modbus、Siemens S7、Omron 等) | |
| | | | `WIDESEAWCS_Tasks` | 后台设备控制作业 | |
| | | | `WIDESEAWCS_QuartzJob` | Quartz.NET 调度和派发逻辑 | |
| | | | `WIDESEAWCS_RedisService` | L1+L2 混合缓存服务 | |
| | | |
| | | ## 项目结构 |
| | | ### 关键设计模式 |
| | | |
| | | ``` |
| | | WIDESEAWCS_Server/ # 主 ASP.NET Core API 服务器 |
| | | WIDESEAWCS_Core/ # 核心基础设施:基类、DI、扩展、中间件 |
| | | WIDESEAWCS_Model/ # 数据模型和 DTO |
| | | WIDESEAWCS_Communicator/ # 硬件通信驱动(Siemens、Omron、Modbus 等) |
| | | WIDESEAWCS_QuartzJob/ # 任务调度基础设施和设备抽象 |
| | | WIDESEAWCS_Tasks/ # Quartz 任务实现(设备通信循环) |
| | | WIDESEAWCS_RedisService/ # Redis 服务:缓存、锁、计数器、发布订阅等 |
| | | WIDESEAWCS_*Repository/ # 数据访问层实现 |
| | | WIDESEAWCS_*Service/ # 业务服务层 |
| | | WIDESEAWCS_Tests/ # 单元测试 |
| | | ``` |
| | | - **仓储模式**:数据访问抽象(`WIDESEAWCS_*Repository` 项目) |
| | | - **服务层**:业务逻辑封装(`WIDESEAWCS_*Service` 项目) |
| | | - **Autofac 依赖注入**:通过 `AutofacModuleRegister` 模块注册 |
| | | - **AOP 拦截**:通过 `UseServiceDIAttribute` 实现缓存和日志切面 |
| | | - **SqlSugar ORM**:支持 MySQL、SQL Server、SQLite、Oracle、PostgreSQL |
| | | |
| | | ## 依赖注入 - IDependency 模式 |
| | | ### 数据流向 |
| | | |
| | | 服务通过实现空的 `IDependency` 标记接口被 Autofac **自动注册**: |
| | | 1. API Controllers → Services → Repositories → SqlSugar → SQL Server |
| | | 2. Quartz Jobs(定时调度) → 设备控制作业 → Communicators → 物理设备 |
| | | 3. Redis L1(内存) + L2(Redis)缓存层位于数据库前方 |
| | | |
| | | ```csharp |
| | | // 在 WIDESEAWCS_Core/IDependency.cs 中 |
| | | public interface IDependency { } |
| | | ## 关键配置(appsettings.json) |
| | | |
| | | // 您的服务会被自动注册 |
| | | public class MyService : IDependency // 自动注册为 scoped |
| | | { |
| | | // ... |
| | | } |
| | | ``` |
| | | - **Web API:** `http://*:9292` |
| | | - **WebSocket:** `http://localhost:9296` |
| | | - **TCP Socket 服务器:** `0.0.0.0:2000` |
| | | - **数据库:** SQL Server,实例 `.\WIDESEAWCS_ShanMei` |
| | | - **Redis:** `127.0.0.1:6379`,密码 `P@ssw0rd` |
| | | - **JWT 过期时间:** 120 分钟 |
| | | - **Quartz:** 自动启动 |
| | | |
| | | 注册在 `AutofacModuleRegister` 中进行,它会扫描所有项目程序集查找 `IDependency` 实现。 |
| | | ## 设备通信 |
| | | |
| | | **重要提示**:向 `IServiceCollection` 添加服务时(例如在 `Program.cs` 中),它们可能会被 Autofac 的注册覆盖。使用 `Remove()` 来替换现有注册: |
| | | `WIDESEAWCS_Communicator` 项目实现了多种工业协议: |
| | | |
| | | ```csharp |
| | | // 在 RedisServiceSetup.cs 中 - 添加 HybridCacheService 之前移除 MemoryCacheService |
| | | var existing = services.FirstOrDefault(d => d.ServiceType == typeof(ICacheService)); |
| | | if (existing != null) services.Remove(existing); |
| | | ``` |
| | | - `ModbusTcpCommunicator` |
| | | - `SiemensS7Communicator`、`SiemensS7200SmartCommunicator` |
| | | - `OmronEtherNetCommunicator` |
| | | - `AllenBrandlyEtherNetCommunicator` |
| | | - `InovanceTcpCommunicator`、`InovanceAMTcp` |
| | | - `SerialPortCommunicator` |
| | | |
| | | ## 缓存 - ICacheService |
| | | 基础接口:`IBaseCommunicator` |
| | | |
| | | 系统通过 `ICacheService` 使用 **L1(内存)+ L2(Redis)混合缓存**模式。存在三种实现: |
| | | ## 后台作业 |
| | | |
| | | - `MemoryCacheService` - 仅内存 |
| | | - `RedisCacheService` - 仅 Redis |
| | | - `HybridCacheService` - L1+L2 带降级(启用 Redis 时的默认选项) |
| | | 设备控制作业位于 `WIDESEAWCS_Tasks/`: |
| | | |
| | | **常用方法**: |
| | | - `StackerCraneJob` - 堆垛机控制 |
| | | - `ConveyorLineJob`、`ConveyorLineNewJob` - 输送线管理 |
| | | - `RobotJob` - 机械手控制 |
| | | - `ShuttleCarJob` - 穿梭车控制 |
| | | - `SocketServer` - 设备通信 TCP 服务器 |
| | | |
| | | - `Add/AddObject` - 添加缓存 |
| | | - `Get/Get<T>` - 获取缓存值 |
| | | - `Remove` - 删除单个键 |
| | | - `RemoveByPrefix/RemoveByPattern` - 按模式批量删除 |
| | | - `GetOrAdd<T>` - 获取或添加(带工厂方法) |
| | | - `TryAdd/TryUpdate/TryUpdateIfChanged` - ConcurrentDictionary 风格的操作 |
| | | ## API 结构 |
| | | |
| | | **配置**(在 `appsettings.json` 中): |
| | | - `QuartzJob/Controllers/` - 设备信息、协议、派发、调度器 |
| | | - `System/Controllers/` - 用户、角色、菜单、字典、日志 |
| | | - `Task/Controllers/` - 任务管理和机器人任务 |
| | | - `BasicInfo/Controllers/` - 路由配置 |
| | | |
| | | ```json |
| | | "RedisConfig": { |
| | | "Enabled": true, |
| | | "ConnectionString": "127.0.0.1:6379,password=P@ssw0rd,...", |
| | | "KeyPrefix": "wcs:" |
| | | } |
| | | ``` |
| | | ## 日志 |
| | | |
| | | ## Quartz 任务 - 设备通信 |
| | | 使用 Serilog,按天滚动保留 30 天日志文件,同时集成 Seq(`http://localhost:5341`)。 |
| | | |
| | | 任务继承 `JobBase` 并实现 Quartz 的 `IJob`: |
| | | ## 重要实现注意事项 |
| | | |
| | | ```csharp |
| | | public class MyDeviceJob : JobBase, IJob |
| | | { |
| | | public async Task Execute(IJobExecutionContext context) |
| | | { |
| | | ExecuteJob(context, async () => { |
| | | // 任务逻辑 |
| | | WriteDebug("MyDevice", "调试信息"); |
| | | WriteInfo("MyDevice", "信息"); |
| | | }); |
| | | } |
| | | } |
| | | ``` |
| | | 1. **启动初始化顺序很重要**:Redis 就绪后才能运行 `ApiRouteCacheWarmupHostedService` |
| | | 2. **Quartz 任务表** 通过 `QuartzJobDataTableHostedService` 在启动时自动创建 |
| | | 3. **Socket 服务器** 作为单例 `TcpSocketServer` 由托管服务运行 |
| | | 4. **Redis 缓存同步**:可配置 `EnableAutoSync` 选项,定期将 Redis 同步到 L1 内存缓存 |
| | | 5. **设备协议配置** 存储在数据库(`Dt_DeviceProtocol` 表),而非配置文件中 |
| | | |
| | | 任务通过 `SchedulerCenterServer` 使用 `Dt_DeviceInfo` 表中的设备信息动态注册。 |
| | | ## 注释与文档 (强制) |
| | | |
| | | **设备类型**: |
| | | - **XML 文档注释**: 所有 `public` 类、接口、方法、属性**必须**包含 XML 文档注释 (`/// <summary>...</summary>`),解释其用途、参数和返回值。 |
| | | - **行内注释**: 对于复杂的业务逻辑、算法实现或非直观的代码块,**必须**添加 `//` 行内注释解释“为什么这么做”。 |
| | | - **TODO 标记**: 如果代码未完成或有临时方案,必须使用 `// TODO: 说明` 标记。 |
| | | |
| | | - `IStackerCrane` - 堆垛机 |
| | | - `IConveyorLine` - 输送线 |
| | | - `IShuttleCar` - 穿梭车 |
| | | - `IRobot` - 机械手 |
| | | ## 通用规范 |
| | | |
| | | ## 硬件通信 |
| | | - **异步编程**: 所有 I/O 操作必须使用 `async/await`。库代码请使用 `ConfigureAwait(false)`。 |
| | | - **命名**: |
| | | - 接口以 "I" 开头 (例如: `IUserService`)。 |
| | | - 类名、方法名使用 **PascalCase**。 |
| | | - 私有字段、局部变量使用 **camelCase**。 |
| | | - **命名空间**: 使用 **文件作用域命名空间** (`namespace MyApp.Api;`)。 |
| | | |
| | | 通信器类封装 `HslCommunication` 库: |
| | | ## 🚫 严禁事项 |
| | | - **严禁** 生成没有注释的代码 (尤其是公共方法)。 |
| | | - **严禁** 使用 `Task.Result` 或 `Task.Wait()`。 |
| | | - **严禁** 在异步上下文中使用 `.ToList()` (必须用 `.ToListAsync()`)。 |
| | | - **严禁** 直接暴露实体 (Entity),必须使用 DTO。 |
| | | - **严禁** 捕获 `Exception` 而不记录日志。 |
| | | |
| | | - `SiemensS7Communicator` / `SiemensS7200SmartCommunicator` - 西门子 PLC |
| | | - `OmronEtherNetCommunicator` - 欧姆龙 PLC |
| | | - `ModbusTcpCommunicator` - Modbus TCP |
| | | - `SerialPortCommunicator` - 串口设备 |
| | | |
| | | ## TCP Socket 服务器 |
| | | |
| | | `TcpSocketServer`(端口 2000)处理实时设备通信: |
| | | |
| | | - 通过 `SocketServerHostedService` 作为 Singleton 管理 |
| | | - 客户端连接存储在 `ConcurrentDictionary<string, TcpClient>` 中 |
| | | - 通过 `OnDataReceived` 事件处理消息 |
| | | |
| | | ## 机械手通信系统 |
| | | |
| | | 机械手系统采用模块化架构,包含专门的组件。 |
| | | |
| | | **组件**: |
| | | |
| | | - `RobotClientManager` - 管理 TCP 客户端连接和订阅 |
| | | - `RobotStateManager` - 管理机械手状态缓存,支持安全的并发更新 |
| | | - `RobotMessageHandler` - 处理来自机械手的 TCP 消息 |
| | | - `RobotTaskProcessor` - 处理任务执行和状态转换 |
| | | - `RobotBarcodeGenerator` - 生成托盘/条码标识符 |
| | | |
| | | **任务类型**(来自 `RobotTaskTypeEnum`): |
| | | |
| | | - `GroupPallet (500)` - 组盘任务 |
| | | - `ChangePallet (510)` - 换盘任务 |
| | | - `SplitPallet (520)` - 拆盘任务 |
| | | |
| | | **状态流转**: |
| | | |
| | | 1. 机械手通过 TCP 连接 → ClientManager 跟踪连接 |
| | | 2. 任务轮询获取任务 → TaskProcessor 获取待处理任务 |
| | | 3. 接收消息 → MessageHandler 解析并更新状态 |
| | | 4. 状态转换 → TaskProcessor 向机械手发送命令 |
| | | |
| | | ## 通用常量 |
| | | |
| | | **通信超时**(`CommunicationConst`): |
| | | |
| | | - `WaitIntervalMs: 500` - 设备等待间隔 |
| | | - `WaitTimeoutBaseMs: 6000` - 超时基数 |
| | | - `WaitTotalTimeoutMs: 60000` - 总超时时间(10 × 基数) |
| | | - `PingIntervalMs: 100` - Ping 检测间隔 |
| | | - `HttpDefaultTimeoutSeconds: 60` - HTTP 超时 |
| | | |
| | | **系统集成 URL**(`BaseAPI`): |
| | | |
| | | - `WMSBaseUrl: "http://localhost:9291/api/"` - WMS 系统 |
| | | - `WCSBaseUrl: "http://localhost:9292/api/"` - WCS 系统(本服务器) |
| | | - `MESBaseUrl: "http://localhost:9293/api/"` - MES 系统 |
| | | - `ERPBaseUrl: "http://localhost:9294/api/"` - ERP 系统 |
| | | |
| | | **Redis 缓存前缀**(`RedisPrefix`): |
| | | |
| | | - `System: "System"` - 系统级缓存 |
| | | - `User: "User"` - 用户特定缓存 |
| | | - `Code: "Code"` - 代码/配置缓存 |
| | | |
| | | 使用这些前缀配合 `ICacheService.RemoveByPrefix()` 进行批量缓存失效。 |
| | | |
| | | ## 配置设置 |
| | | |
| | | `appsettings.json` 中的关键设置: |
| | | |
| | | - `"urls": "http://*:9292"` - 服务器端口 |
| | | - `"QuartzJobAutoStart": true` - 自动启动定时任务 |
| | | - `"SocketServer:Enabled": true` - 启用 TCP 服务器 |
| | | - `"RedisConfig:Enabled": true` - 启用 Redis 缓存 |
| | | - `"LogAOPEnable": false` - 启用 AOP 日志 |
| | | - `"DBType": "SqlServer"` - 数据库类型 |
| | | |
| | | ## 服务层模式 |
| | | |
| | | 服务遵循分层模式: |
| | | |
| | | - **接口**在 `WIDESEAWCS_IService/` 中(例如 `ITaskInfoService`) |
| | | - **实现**在 `WIDESEAWCS_Service/` 中(例如 `TaskInfoService`) |
| | | - 两者都实现 `IDependency` 以进行自动注册 |
| | | |
| | | ## 基类 |
| | | |
| | | - `ServiceBase<T, TKey>` - 带有 CRUD 操作的基础服务 |
| | | - `RepositoryBase<TEntity>` - 基于 SqlSugar ORM 的基础仓储 |
| | | - `ApiBaseController` - 带有通用功能的基础 API 控制器 |
| | | - `JobBase` - 带有日志辅助方法的基础 Quartz 任务 |
| | | |
| | | ## 添加新功能 |
| | | |
| | | 1. **新服务**:在 `I*Service/` 中创建接口,在 `*Service/` 中创建类,实现 `IDependency` |
| | | 2. **新任务**:在 `WIDESEAWCS_Tasks/` 中继承 `JobBase` 和 `IJob` |
| | | 3. **新设备类型**:在 `WIDESEAWCS_QuartzJob/Device/` 中添加接口并实现 |
| | | |
| | | ## 重要说明 |
| | | |
| | | - 应用程序使用 **CamelCase** JSON 序列化 |
| | | - 所有服务默认通过 Autofac 使用 **scoped** 生命周期 |
| | | - Redis 连接使用 **延迟初始化** - 首次访问时触发连接 |
| | | - 在任务中使用 `ConsoleHelper.WriteSuccessLine()` / `WriteErrorLine()` 进行控制台输出 |
| | | - TCP Socket 服务器独立于 HTTP API 运行 |
| | | |
| | | ## 代码风格与命名规范 |
| | | |
| | | - 语言:C#,各项目已启用可空引用(nullable)。 |
| | | - 缩进:4 个空格;大括号换行(与现有代码保持一致)。 |
| | | - 命名:类型/方法/属性使用 `PascalCase`,局部变量/参数使用 `camelCase`,接口以 `I` 前缀命名。 |
| | | - 文件命名与类型名保持一致(例如 `Sys_UserService.cs`、`TaskController.cs`)。 |
| | | - `.editorconfig` 当前对 `*.cs` 抑制 CS8618;未经团队确认不要新增大范围警告抑制。 |
| | | - 为新生成或者修改的代码的每一行添加详细注释,包括: |
| | | - 方法的目的说明 |
| | | - 参数说明 |
| | | - 返回值说明 |
| | | - 每一行代码的作用 |
| | | - 异常情况的说明 |
| | | ## 🛠 技术栈 |
| | | - **框架**: .NET 8.0 (LTS) |
| | | - **语言**: C# 12 |
| | | - **ORM**: SqlSugar |
| | | - **数据库**: SQL Server |
| | | - **验证**: FluentValidation |
| | | - **序列化**: Newtonsoft.Json |