# PLC 配置页面原始功能详细规格

> 基于原工程 libplc C 引擎 + Reclose_logic.xml 完整分析
> 分析日期: 2026-07-10
> 目标: 重构前端 PLC Config 页面，做到比原工程更好

---

## 一、PLC 系统架构

```
┌─────────────────────────────────────────────────────────────────┐
│                     RTU 运行时                                    │
│                                                                  │
│  config/PLC/Reclose_logic.xml ──→ pls.cpp parse_reclose_logic   │
│  (mtime 文件变化检测, stat)          │                            │
│                                     ↓                            │
│                              LogicGraph[] (最多4个)               │
│                                     │                            │
│                              EV_TIMER3 (1s)                      │
│                                     ↓                            │
│                              PLC_Logic() 执行:                   │
│                              1. 读取 datacenter input 信号        │
│                              2. Kahn 拓扑排序                    │
│                              3. 按拓扑序执行各门逻辑               │
│                              4. 写入 datacenter output 信号       │
└─────────────────────────────────────────────────────────────────┘
```

## 二、XML 格式完全规格 (Reclose_logic.xml)

### 顶层结构

```xml
<?xml version="1.0" encoding="UTF-8"?>
<PLCConfig name="PLC Logic" key="1783070862205" checksum="3486BE04">
    <Chain gates="N" inputs="N" outputs="N">
        <!-- 简单 Chain 无 Comb: Inputs → Gates → Outputs 顺序 -->
        <Inputs>   <Signal no="ID" x="X" y="Y"/> ... </Inputs>
        <Gate type="TYPE" id="N" x="X" y="Y" [delayMs="MS"] [S="src"] [R="src"]/>
        ...
        <!-- 含 Comb 的 Chain: Comb 可嵌套, 位置不固定 -->
        <Comb id="N">
            <Inputs> ... </Inputs>
            <Gate .../>
            <Comb id="N">  <!-- 嵌套 Comb -->
                <Inputs> ... </Inputs>
                <Gate .../>
                <Outputs> ... </Outputs>
            </Comb>
            <Gate .../>
            <Outputs> ... </Outputs>
        </Comb>
        <Outputs>  <Signal no="ID" x="X" y="Y"/> ... </Outputs>
    </Chain>
    <Chain ...> ... </Chain>
</PLCConfig>
```

###  关键节点类型 (10 种)

| type | Name | 功能 | 参数 | 输入引脚 | 输出引脚 |
|------|------|------|------|:---:|:---:|
| 0 | INPUT | 硬件输入, 从 datacenter 读取值 | no=信号ID | 0 | 1 |
| 1 | OUTPUT | 硬件输出, 写入 datacenter | no=信号ID | 1 | 0 |
| 2 | OR | 或门, 任意输入=1→输出1 | id=门ID | 2 | 1 |
| 3 | AND | 与门, 全部输入=1→输出1 | id=门ID | 2 | 1 |
| 4 | NOT | 非门, 取反 | id=门ID | 1 | 1 |
| 5 | T62P | 延时导通 (IN=1 等待 delayMs ms 后 OUT=1) | id, delayMs | 1 | 1 |
| 6 | T62D | 延时关断 (IN=0 等待 delayMs ms 后 OUT=0) | id, delayMs | 1 | 1 |
| 7 | RISING | 上升沿检测 (0→1 产生一周期脉冲) | id | 1 | 1 |
| 8 | SR | SR 触发器 (S优先: S=1置位, R=1& S=0复位) | id, S, R | 2 (S=0, R=1) | 1 |
| 9 | RS | RS 触发器 (R优先: R=1复位, S=1& R=0置位) | id, S, R | 2 (S=0, R=1) | 1 |
| 10 | FALLING | 下降沿检测 (1→0 产生一周期脉冲) | id | 1 | 1 |

### Comb 的 C 引擎自动检测逻辑

```
parse_xml_comb(comb_el, graph):
  1. 遍历 comb_el 的子元素 (<Inputs>, <Gate>, <Comb>, <Outputs>)
  2. 遇到子 <Comb> → 递归调用 parse_xml_comb()  ← 这就是嵌套自动检测
  3. 子 Comb 的 Gate 输出 → 父 Comb 的 Gate 输入 (自动连线)
  4. 遇到 <Inputs> → 创建 HW_INPUT 节点 → 连线到同层 Gate
  5. 遇到 <Gate> → 创建门节点 + 解析 R/S 属性
     - R="Comb#N" → 查找子 Comb 中对应 Gate 的输出
     - S="Comb#N" → 同上
     - R="Input#N" / S="Input#N" → 创建对应 Input 节点
  6. 遇到 <Outputs> → 创建 HW_OUTPUT 节点 → 连线从同层 Gate

链级别 Comb 处理 (第二遍布线):
  1. Comb 的 Gate 输出 → 链级 Gate 输入
  2. 链级 Input → 链级 Gate
  3. 链级 Gate → 链级 Output
```

**核心结论: Comb 是 XML 中天然存在的嵌套结构，C 引擎自动递归解析。前端应该:**
- 加载 XML 时自动识别 Comb 嵌套关系
- 渲染为视觉分组容器 (矩形框)
- 允许用户通过拖拽节点入框来创建 Comb
- 不允许手动添加空 Comb

---

## 三、原工程 PLC Config 前端功能详细清单

### 3.1 导航与入口

- Hash 路由: `#plc_config`
- 导航标签: "PLC 配置" / "PLC Config"
- 导航图标: 原工程用 emoji 🧩, 当前用 SVG cpu

### 3.2 多 Chain 管理

| 功能 | 描述 | 实现方式 |
|------|------|---------|
| **Chain 标签切换** | 顶部标签栏，每个 Chain 一个标签 | 点击切换当前编辑的 Chain |
| **Chain 标签内容** | 显示 "Chain N (节点数)" | 实时更新 |
| **添加 Chain** | +Chain 按钮 | 创建空 Chain, 自动切换 |
| **删除 Chain** | -Chain 按钮 | 删除当前 Chain (≥2个时可用) |

### 3.3 节点类型工具栏

每种节点类型一个按钮，点击后在 Canvas 随机位置添加:

```
[+INPUT] [+OUTPUT] [+OR] [+AND] [+NOT] [+T62P] [+T62D] [+RISING] [+SR] [+RS] [+FALLING]
```

### 3.4 Canvas 画布编辑器

| 功能 | 描述 | 交互 |
|------|------|------|
| **节点渲染** | 圆角矩形 + 类型名 + ID号 + 颜色区分 | 11种颜色方案 |
| **引脚圆点** | 输入引脚(左, 彩色), 输出引脚(右, 绿色) | 5px 半径 |
| **连线渲染** | 节点间实线, 从输出引脚→输入引脚 | 深灰 #2c3e50 |
| **拖拽节点** | 按住节点拖动 | 20px 网格吸附 |
| **连线操作** | 从输出引脚拖出虚线→目标输入引脚释放 | 红色虚线 |
| **选中节点** | 单击节点高亮 | 白色填充 + 红色边框 |
| **删除节点** | 选中 + 删除按钮 | 同时删除关联连线 + 重编号 Gate ID |
| **平移画布** | 拖拽空白区域 | 平移 |
| **缩放** | 滚轮缩放 0.5x-2.0x | 缩放栏显示百分比 |
| **缩放栏** | [放大] [缩小] [适应] 100% | 适应 = zoom=1, pan=0 |
| **双击编辑** | 双击节点弹出属性 Modal | 编辑 saddr/desc/delayMs/spin/rpin |

### 3.5 Comb 组合块

| 功能 | 描述 |
|------|------|
| **自动识别** | 加载 XML 时自动解析 Comb 嵌套结构 |
| **视觉渲染** | 虚线圆角矩形，标签 "Comb #N" |
| **嵌套 Comb** | 视觉上子 Comb 在父 Comb 内部 |
| **节点归属** | Comb 内节点在视觉上位于 Comb 矩形内 |
| **创建 Comb** | 选中多个节点 → "成组为 Comb" 创建 |
| **解散 Comb** | 选中 Comb → "解散 Comb" → 节点回到链级别 |

### 3.6 XML 查看与持久化

| 功能 | 描述 |
|------|------|
| **XML 实时预览** | 只读 `<pre>` 标签, 随编辑实时更新 |
| **加载 XML** | 从 RTU 读取 `cat config/PLC/Reclose_logic.xml` |
| **保存 XML** | 通过 WS `set_file` 写回 RTU |
| **checksum** | 根节点自动计算 XOR checksum |

### 3.7 操作按钮栏

```
[加载 XML] [保存 XML] [清空] [删除选中节点]
```

---

## 四、原工程 UI 设计参考

### 4.1 设计风格

| 参数 | 原设计值 | 当前值 |
|------|---------|--------|
| 风格 | 暗色工业主题 (Dark Industrial Dashboard) | 暗色工业主题 |
| 主色调 | Cyan/Teal (#00E5FF / #1DE9B6) | Teal (#00d4aa) |
| 背景 | #0F1923 (deep navy) | #0a0f16 (更深) |
| 卡片背景 | #1A2332 | #111922 |
| 字体 | Inter + JetBrains Mono | 同 |
| 图标 | Emoji (原工程) → SVG Lucide (重构目标) | SVG 内联 Lucide |
| Canvas 背景 | 浅色网格 (#f0f2f5) | 同 |

### 4.2 导航图标规格

| 页面 | 原 Emoji | Lucide SVG 图标名 | 说明 |
|------|---------|------------------|------|
| 仪表盘 | 📊 | dashboard | 四象限网格 |
| 开出信号 | 📡 | signal | 信号波形 |
| 开入信号 | 🔗 | link | 链接 |
| 遥控信号 | ⚡ | zap | 闪电 |
| 参数设置 | 🎚️ | sliders | 滑块 |
| 定值管理 | ⚙️ | settings | 齿轮 |
| 数据中心 | 📋 | database | 数据库 |
| PLC 调试 | 🔌 | bug | Bug/调试 |
| PLC 配置 | 🧩 | cpu | CPU/芯片 |
| 实时监控 | 📈 | activity | 心电图 |
| 命令终端 | 💻 | terminal | 终端 |

---

## 五、重构目标与要求

### 5.1 必须保留/增强的功能

- [x] 多 Chain 标签切换
- [x] 11 种节点类型完整支持
- [x] Canvas 拖拽、连线、缩放、平移
- [x] 节点属性双击编辑 (含 SR/RS R/S 引脚, T62P/D delayMs)
- [x] XML 实时预览
- [x] 从 RTU 加载/保存

### 5.2 必须修复的问题

- [ ] **Comb 改为自动识别** — 加载 XML 时检测，不允许手动添加空 Comb
- [ ] **Comb 创建方式** — 选中多个节点 → "成组为 Comb"
- [ ] **导航图标风格** — 恢复工业风格，尺寸与文字匹配
- [ ] **set_file 后端实现** — 确保保存功能真正可用

### 5.3 必须优于原工程的新功能

- [ ] Comb 视觉边界框正确嵌套
- [ ] SR/RS 引脚 S/R 标签显示
- [ ] 节点颜色方案保持一致性
- [ ] 更好的错误处理 (XML 解析失败提示)
- [ ] 键盘快捷键 (Delete 删除, Ctrl+S 保存)

---

## 六、Comb 自动检测算法 (前端)

```javascript
// 加载 XML 时的 Comb 自动检测伪代码
function detectCombsFromXml(xmlDoc):
  for each <Chain> in <PLCConfig>:
    chain.nodes = []   // 扁平存储所有节点
    chain.combs = []   // 存储 Comb 容器定义
    chain.links = []   // 存储连线

    // 1. 解析顶层元素
    parseChainElements(chainEl, chain, parentId=-1)

function parseChainElements(parentEl, chain, parentId):
  for each child in parentEl.children:
    if child.tag == 'Inputs' or 'Outputs':
      parseSignals(child, chain)
    if child.tag == 'Gate':
      parseGate(child, chain)
    if child.tag == 'Comb':
      combId = child.getAttribute('id')
      // 创建 Comb 容器 (位置由内部节点包围盒计算)
      comb = { id: combId, parentId: parentId }
      chain.combs.push(comb)
      // 递归解析 Comb 内部元素
      parseChainElements(child, chain, combId)

  // 2. Comb 位置自动计算 (后处理)
  for each comb in chain.combs:
    var nodesInComb = chain.nodes.filter(n => 位于 comb 区域)
    // 包围盒 = min/max of nodesInComb 的 x,y
    comb.x = minX - margin
    comb.y = minY - margin
    comb.w = maxX - minX + 2*margin
    comb.h = maxY - minY + 2*margin
```

### Comb 归属判断

节点属于哪个 Comb 由以下规则确定:

1. **来自 <Comb> 内 <Inputs>/<Gate>/<Outputs>** → 属于该 Comb
2. **来自 <Comb> 内子 <Comb> 的元素** → 属于子 Comb (嵌套)
3. **来自 <Chain> 顶层元素** → 不属于任何 Comb (parentId=-1)

---

## 七、节点样式与颜色方案

| 节点 | 填充色 | 描边色 | 尺寸 |
|------|--------|--------|------|
| INPUT | #e8f5e9 浅绿 | #27ae60 绿 | 110×34 |
| OUTPUT | #fce4ec 浅粉 | #e74c3c 红 | 110×34 |
| OR | #fff3e0 浅橙 | #e67e22 橙 | 76×46 |
| AND | #e3f2fd 浅蓝 | #2980b9 蓝 | 76×46 |
| NOT | #f3e5f5 浅紫 | #8e44ad 紫 | 76×46 |
| T62P | #fce4ec 浅粉 | #c0392b 深红 | 86×46 |
| T62D | #fff3e0 浅橙 | #d35400 深橙 | 86×46 |
| RISING | #e8f5e9 浅绿 | #1abc9c 青绿 | 86×46 |
| SR | #e3f2fd 浅蓝 | #3498db 亮蓝 | 86×52 |
| RS | #fce4ec 浅粉 | #9b59b6 紫 | 86×52 |
| FALLING | #fff3e0 浅橙 | #16a085 青 | 86×46 |

引脚颜色: 输入=同节点描边色, 输出=#27ae60 绿

### Comb 视觉

- 描边: #95a5a6 灰色虚线 (8px dash, 4px gap)
- 填充: rgba(149,165,166,0.05) 极浅灰
- 标签: 左上角 "Comb #N"
- 圆角: 6px

---

## 八、文件结构

```
web/js/pages/plc.js        ← PLC Debug + PLC Config (重构目标)
web/css/style.css           ← PLC 相关 CSS (.chain-tabs, .plc-canvas-wrap, etc.)
web/js/i18n.js              ← PLC 相关翻译 key
config/PLC/Reclose_logic.xml ← XML 配置文件 (数据源)
```
