# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## 项目概述 液压马达后盖(A6VM107/160/200)CNC 产线管控系统。控制西门子 PLC 驱动的工业机器人 + 4台CNC + 清洗机 + 去毛刺机 + 检测设备 + 接驳台。 - **后端**: Go 1.25,go-zero v1.8.3,ent ORM v0.14.5,PostgreSQL,Redis(缓存辅助) - **前端**: React 19 + Semi Design UI v2.94 + Zustand + Vite 7(`frontend/`,pnpm) - **PLC**: 西门子 S7 协议 + FANUC FOCAS + OKUMA OspDirect - **数据采集**: `back_cover_dc/`(独立项目,Modbus/S7/Focas/OSP-MC/OSP-LATHE 多协议采集) - **大屏看板**: `dashboard-server/` + `dashboard-client/`(4K 深色大屏,产线概览 + 设备监控 + OEE) ## 关联项目 本仓库位于 `F:\Workspace\Hardman\hougai\`,同级目录还有: | 项目 | 说明 | |------|------| | `back_cover_dc/` | 多协议数据采集服务(Modbus/S7/Focas/OSP),独立 Go 项目,GORM + Fiber | | `dashboard-server/` | 大屏看板后端,Go + Fiber + sqlx,直连 back_cover 数据库只读查询 | | `dashboard-client/` | 大屏看板前端,React + TypeScript + ECharts + Semi Design,4K 深色主题 | | `okuma_dc/` | OKUMA 采集器(已废弃,功能已合并到 back_cover_dc 的 osp 协议) | ## 常用命令 ```bash # 后端 go run hougai.go -c etc/hougai-api.yaml # 开发运行 go run cmd/mockrun/main.go # Mock 模拟完整订单流程 go run cmd/debug/main.go -f etc/hougai-api.yaml # 调试面板(端口 8890) build.bat # 构建 bin/hougai.exe # 前端 cd frontend && pnpm dev # Vite 开发服务器(5173 → 8888) cd frontend && pnpm build # 嵌入 Go 二进制 # 代码生成(修改 schema/api 后必须执行) cd schema && go generate # ent ORM cd apis && go generate # handler/logic/types # 测试 go test ./internal/processor/... # 单包测试 go test -cover ./... # 覆盖率(Windows 上 -race 不可用) go vet ./... # 静态分析 ``` ## 全局规则 - **禁止自动提交 git** - handler 保持薄层,业务逻辑在 logic - 不手动修改 `ent/`、`internal/handler/`、`internal/types/`(自动生成) - 不用 `goctl`/`ent init`,用 `cd apis && go generate` / `cd schema && go generate` - API 变更先改 `apis/*.api`,schema 变更先改 `schema/*.go`,再生成 - **processor 包用 `log/slog`**,不用 `go-zero/core/logx` - 所有命令加 `rtk` 前缀 ## 编码准则 **先想后写**:不确定时停下来提问。有多种解读时列出选项,不要默默选择。有更简单方案时提出反对意见。 **简单优先**:用最少代码解决问题。不为单次使用创建抽象。不写不可能出现的错误处理。200 行能变 50 行就重写。 **精准改动**:只改必须改的部分。不改相邻代码、注释、格式。不改没坏的东西。风格匹配现有代码,即使你本会写成另一种风格。只清理你自己的改动产生的孤儿引用/import/变量。 **目标驱动**:把任务转化为可验证目标。"修 bug" → "先写能复现的测试,再修"。多步骤任务先列简明计划。让成功标准明确,才能独立推进。 ## 架构 ### 核心设计:DB SSOT + 单线程事件循环 PostgreSQL 是唯一运行时真相源。所有状态写入由 `ProductionEventLoop` 单线程串行处理。HTTP handler 直接查询 ent/PostgreSQL(读取无需经过 event loop)。 **状态写入路径**:HTTP handler → EventLoopMessage → ProductionEventLoop → DBState 条件更新 → ent → PostgreSQL;PLC 信号 → SignalRouter → Actor.signalCh → Actor 写 DB + 投递 MACHINE_DONE → EventLoop 推进步骤 + 调度。 ### eventloop 包(`internal/processor/eventloop/`) - **`ProductionEventLoop`**(`loop.go`)— 从 `msgCh`(256)接收消息串行处理,`time.Timer`(60s)触发 `trySchedule`。消息类型:Command(START_ORDER/PAUSE_ORDER/...)、ExternalEvent(MACHINE_DONE/INSPECTION_RESULT/STEP_TIMEOUT)、WorkerResult - **`DBState`**(`dbstate.go`)— ent 条件更新:`AdvanceStep`(链式跳步,上限 100 次防循环)、`CompleteStep`、`FinishJob`、`SetEquipmentSlot`(Actor 独占调用) - **`RecoverOnStartup`**(`recovery.go`)— IN_PROGRESS→PAUSED + 校验 slot 一致性,不一致项创建 manual_action - **`RuntimeSnapshot`** — DB 只读快照,替代旧 JobRuntime 状态机 ### processor 包 - **`scheduler_bridge.go`** — RuntimeSnapshot→JobView→CandidateTask→RobotAction 映射。补料在调度管线**之前**处理。`prePairWasherLoads` 按 TargetID:Category 分组配对。`findExchangePair` 校验同 category - **`Replenisher`** — 接驳台→暂存台补料。硬编码配额(8 槽位按活跃 category 分配:3类→3:3:2,2类→4:4/5:3,单类→8)。触发:占用 ≤ quota/2 - **`RobotWorker`** — 适配 `robot.Controller` → `action.HardwareWorker` 接口。通过 Actor 同步方法操作槽位,不直接写 DB。设备特定 PLC 操作(Load/Unload/Exchange)委托 Station 接口,不再包含 machineID 硬编码 - **`JobProcessor`** — 订单生命周期 + jobs map 跟踪 ### 调度器(三层架构) Generator(步骤→候选任务)→ Filter(链式约束:MachineBusy/TempSlotFull/OrderPaused/...)→ Policy(8 条优先级规则)。`trySchedule` 触发。 ### Actor 系统 每台设备一个 Actor(goroutine + channel),独占槽位状态和 equipment_slot DB 写入权。 **槽位状态机**:`Empty → Occupied → Done → Empty`。外部组件无权直接写 equipment_slot。 **信号流**:PLC → SignalRouter 轮询(上升沿,per-actor 通道容量 4)→ Actor.handleSignal → 标记 DONE + 写 DB → 投递 MACHINE_DONE → EventLoop **通信模式**:RobotWorker→Actor(同步),EventLoop→Actor(异步消息),Actor→EventLoop(异步事件) **TempStoreActor**:暂存台槽位唯一写入口。`AllocateSlot`/`ReleaseSlot`(同步,补料器调用)、异步消息循环处理 ALLOCATE/RELEASE/RESTORE。 ### Recipe Decision/Judge 4 种 `decisionType`:空(无条件设 key)、`negate_bool`、`scan_mismatch`、`signal_true`(需实时读 PLC,只能 in trySchedule 处理)。非 signal_true 由 AdvanceStep 内联链式推进。 ### Category 活跃工单互斥 每个 category 最多一个活跃工单(IN_PROGRESS 或 PAUSED)。创建时后端强制校验 + 前端下拉过滤已占选项。 ### 事件总线与 EventLog `LocalBus`(进程内 channel)。EventLogWriter 订阅所有事件,批量写入 `event_log`(batch 20/1s)。SSE Bridge 推送到前端。 **SSE vs HTTP API 格式差异**:SSE 结构化字段在 `payload` 内,HTTP API 在顶层。前端 `normalizeEventLog()` 统一适配。 ### 补料 & 废料搬运 补料:trySchedule 前检查 → BuildReplenishCandidate → 预分配暂存槽位 → RobotWorker 执行 replenish → EventLoop 处理结果。 扫码失败两条路径:补料扫码失败→保留槽位标记 WAITING_WASTE→ActionLoadWaste 搬运;标准扫码失败→工件直接放废料台→释放槽位+Scrap。ActionLoadWaste 豁免 OrderPaused/JobSuspended 约束。 ### 恢复系统 启动时 `RecoverOnStartup` 将 IN_PROGRESS → PAUSED 并校验一致性(不一致项创建 ManualAction)。工单恢复由用户手动触发。 ### 抽检台 machineID=9,SAMPLING 类型,1槽位。OP100 Decision signal_true 读 SamplingRequest → 分支到 SAMPLING 步骤。onInspect 回调判定合格/不合格。 ## 数据库 PostgreSQL `127.0.0.1:5432`,库 `back_cover`,用户 `postgres`。ent ORM,schema 在 `schema/`,生成在 `ent/`,自动迁移。 核心表:work_order(finishedNum/failNum 原子累加)、job(current_step_id)、equipment/equipment_slot(batch 字段)、dock_slot、product_type(category: A6VM107/160/200)/recipe/recipe_step(step_id: OP10-OP120,next_step_default/branches)、signal(PLC 地址映射)、alarm、manual_action、event_log/task_log。 ## 前端 React 19 + Semi Design UI v2.94 + Zustand + HashRouter。SSE 实时更新。路由:`/dashboard`(主控面板)、`/work-order`、`/workpiece`、`/equipment`、`/alarm`、`/recipe`、`/system`。WorkOrderPanel 通过 SideSheet 弹窗展示详情。 ## 配置 `etc/hougai-api.yaml` — 端口 8888。`Mock.Enable=true` 时使用 MockPLC/MockMarking 无硬件测试。Redis 仅用于缓存辅助。 ## 架构概览 ``` internal/ ├── action/ # RobotAction + HardwareWorker 接口(独立包,避免循环依赖) ├── alarm/ # 报警服务 ├── eventlog/ # EventLog 持久化(订阅 EventBus,批量写入) ├── processor/ # 核心引擎 │ ├── actor/ # Actor 模型(MachineActor + TempStoreActor + SignalRouter) │ ├── station/ # Station 接口(设备特定 PLC 操作:Load/Unload/Exchange + 扩展接口) │ ├── tool/ # 手持工具(Scanner/LaserMarker) │ ├── scheduler/ # Generator/Filter/Policy 三层调度 │ ├── eventloop/ # DB SSOT 事件循环 + 调度桥接 + 恢复 │ ├── factory.go # BuildProductionLine 产线组装(Actor + Station) │ ├── job_processor.go / robot_worker.go / replenisher.go │ └── interface.go ├── svc/ # DI 组装(ServiceContext) ├── robot/ # PLC 机器人控制(dock/machine/temp_station/washer/...) ├── sse/ # SSE 实时推送 └── preload/ # DB 数据内存缓存(PLC 信号映射 + Category 映射) ``` ## 已知问题 - `internal/preload/`、`internal/robot/` 有构建失败的测试 - `internal/camera/` 测试需真实硬件 - Windows 上 `-race` 不可用