# 智能称量监控系统 - 系统架构与部署文档

> **版本**：v2.0  
> **日期**：2026-05-08  
> **适用范围**：云服务端（PHP + MySQL + Nginx）+ 现场一体机 + 微信小程序

---

## 一、系统概述

本系统是一个分布式工业自动化监控系统，采用**现场一体机为核心操作终端**，云端负责**数据存储与API服务**，微信小程序提供**远程监控**能力的三层架构设计。

### 核心设计思想
- **现场自治**：生产控制、配方管理、计划下发等核心操作在本地完成，不依赖网络
- **云端存储**：所有业务数据（配方、计划、报警、报表、曲线）存储在云端 MySQL
- **API服务**：云端提供 PHP REST API，微信端通过 HTTP 轮询读写数据库
- **远程可视**：管理人员通过微信小程序实时查看生产状态
- **数据库中转**：微信端只读写数据库，所有与 PLC 的交互由现场一体机完成

> **架构约束**：微信端（包括小程序 WebView 内的 H5）**不直接连接 PLC**，也不通过 WebSocket 接收实时推送。所有数据交互均通过 **PHP API + MySQL** 完成。

---

## 二、系统架构图

```
┌─────────────────────────────────────────────────────────────────────────────┐
│                              展会现场                                        │
│  ┌─────────────────┐         ┌─────────────────┐         ┌──────────────┐  │
│  │   一体机(本地)   │◄───────►│   Kepware OPC   │◄───────►│ 西门子S7-1500│  │
│  │                 │  OPC    │                 │  S7协议  │              │  │
│  │ • 读取PLC数据    │         │                 │         │              │  │
│  │ • 写入PLC配方    │         └─────────────────┘         └──────────────┘  │
│  │ • 数据存入云端DB │                                                          │
│  └────────┬────────┘                                                          │
│           │ MySQL TCP:3306 (读取待发送配方 / 写入实时数据)                      │
│           ▼                                                                  │
└─────────────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│                              云端服务器                                       │
│  ┌───────────────────────────────────────────────────────────────────────┐  │
│  │                         Nginx + PHP-FPM                               │  │
│  │                                                                        │  │
│  │   ┌──────────────────┐        ┌──────────────────┐                   │  │
│  │   │   静态页面服务    │        │   REST API 服务   │                   │  │
│  │   │  (mobile/)       │        │   (api/)          │                   │  │
│  │   │                  │        │                  │                   │  │
│  │   │ • 监控H5页面     │◄──────►│ • 配方查询       │◄──────┐          │  │
│  │   │ • 报表/记录页    │        │ • 发送配方(写DB) │       │          │  │
│  │   │ • 曲线查询页     │        │ • 生产数据查询   │       │          │  │
│  │   └──────────────────┘        └──────────────────┘       │          │  │
│  │            ▲                          ▲                  │          │  │
│  └────────────┼──────────────────────────┼──────────────────┼──────────┘  │
│               │ HTTPS                    │                  │             │
│   ┌───────────┴──────────────────────────┘                  │             │
│   │                                                         │             │
│   ▼                                                         ▼             │
│  微信小程序(WebView)                                MySQL 8.0 数据库       │
│   • 首屏加载监控H5                                  • M_RECIPE  配方表     │
│   • 底部导航跳转                                     • M_PLAN    计划表     │
│   • 子页面WebView容器                                • M_TRANSFER 待发送中转 │
│                                                      • R_CURVE   曲线数据   │
│                                                      • R_WEIGH   称重记录   │
│                                                      • R_TRANSFER 生产记录  │
│                                                      • M_MONITOR_REALTIME   │
└─────────────────────────────────────────────────────────────────────────────┘
```

---

## 三、数据流向说明

### 3.1 本地操作流向（主要流程）

```
操作员 ──► 现场一体机本地Web ──► scada.js ──► Kepware ──► 西门子S7-1500
              (MiniUI界面)

功能说明：
• 实时监控    → 本地读取PLC，实时显示重量、车数、状态
• 配方管理    → 读写云端MySQL，本地操作界面
• 计划下发    → 写云端MySQL + 写入PLC执行
• 参数设定    → 直接写入PLC
• 控制命令    → 直接写入PLC（清零/去皮/启动等）
```

### 3.2 实时数据上报流向

```
西门子PLC ──► Kepware ──► scada.js ──►【变化检测】──► 写入云端MySQL
                                                              │
                                                              ▼
                                                    ┌──────────────────┐
                                                    │  MySQL 数据库     │
                                                    │  • M_MONITOR_REALTIME
                                                    │  • R_CURVE        │
                                                    │  • R_WEIGH        │
                                                    └────────┬─────────┘
                                                             │
                    ┌────────────────────────────────────────┘
                    ▼
            ┌──────────────┐
            │  微信小程序   │
            │  轮询读取：   │
            │  • 当前重量   │
            │  • 生产进度   │
            │  • 设备状态   │
            │  • 报警信息   │
            └──────────────┘
```

**上报机制**：
- 一体机定时将 PLC 数据写入 MySQL 的 `M_MONITOR_REALTIME`、`R_CURVE`、`R_WEIGH` 等表
- 微信端通过 HTTP 轮询调用 PHP API 读取数据库最新数据
- 监控页建议轮询间隔 3 秒；曲线实时模式建议 2 秒

### 3.3 数据库存取流向

```
现场一体机 ──────────────────────► 云端MySQL
     │                              │
     ├──► M_RECIPE 配方表            │◄── 公众号查询
     ├──► M_PLAN   计划表            │◄── 公众号查询
     ├──► M_TRANSFER 待发送中转       │◄── 公众号写入（发送配方）
     ├──► R_CURVE  曲线数据           │◄── 公众号查询
     ├──► R_WEIGH  称重记录           │◄── 公众号查询
     ├──► R_TRANSFER 生产记录         │◄── 公众号查询
     └──► M_MONITOR_REALTIME 监控快照 │◄── 公众号查询
```

### 3.4 配方下发流向

```
微信小程序
    │
    ▼ 点击"发送配方"
┌─────────────────┐
│ 底部滑出面板     │
│ • 配方选择       │
│ • 批次输入       │
│ • 确认发送       │
└────────┬────────┘
         │ POST /api/exhibition/recipe.php?action=send
         ▼
┌─────────────────┐
│ 云端PHP API      │
│ • 校验参数       │
│ • 生成LOT_ID     │
│ • 写入M_TRANSFER │
└────────┬────────┘
         │
         ▼ MySQL
┌─────────────────┐
│ M_TRANSFER       │◄── 一体机定时轮询（每秒）
└─────────────────┘
         │
         ▼
┌─────────────────┐
│ 现场一体机       │
│ • 读取M_TRANSFER │
│ • 写入PLC        │
│ • 更新执行状态   │
└─────────────────┘
```

---

## 四、技术栈

| 层级 | 组件 | 技术 | 用途 |
|------|------|------|------|
| **现场层** | 操作系统 | Windows 10 IoT | 工控机运行环境 |
| | OPC Server | Kepware | 连接西门子S7-1500 |
| | 通信协议 | OPC/DA 或 OPC/UA | PLC数据交换 |
| | 核心程序 | Node.js + scada.js | 数据采集与本地服务 |
| | Web界面 | MiniUI + HTML5 | 本地操作界面 |
| **传输层** | 实时通信 | HTTP 轮询 (REST API) | 微信端数据读取 |
| | 数据库连接 | MySQL TCP/3306 | 一体机与云端数据同步 |
| **云端层** | Web服务 | Nginx + PHP-FPM | 静态页面与API服务 |
| | 数据库 | MySQL 8.0 | 数据存储 |
| **移动端** | 容器 | 微信小程序WebView | 页面承载 |
| | 前端 | HTML5 + JavaScript + ECharts | 监控界面 |

---

## 五、目录结构

### 5.1 云端服务器目录

```
api/                                    # PHP API服务
├── recipe.php                          # 配方管理API（增删改查）
├── plan.php                            # 计划管理API
├── plc/                                # PLC相关接口（现场一体机使用）
│   ├── DB_Config.php
│   ├── DB_Production.php
│   ├── AjaxService_Production.php
│   └── AjaxService_Sys.php
│
└── exhibition/                         # 小程序展会版专用API（已开发完成）
    ├── config.php                      # 数据库配置
    ├── recipe.php                      # 配方查询 + 发送配方
    ├── send-record.php                 # 发送记录查询
    ├── report.php                      # 生产报表查询
    ├── monitor.php                     # 监控实时数据查询
    ├── chart.php                       # 曲线数据查询
    └── curve.php                       # Canvas曲线查询

mobile/                                 # 移动端H5页面
├── monitor/index.html                  # 现有监控页面（保留备用）
├── recipe/index.html                   # 现有配方页面（保留备用）
└── exhibition/                         # 小程序展会版专用H5（已开发完成）
    ├── monitor/index.html              # 监控主页（带底部5按钮导航）
    ├── send-record/index.html          # 发送记录页
    ├── report/index.html               # 生产报表页
    ├── chart/index.html                # 曲线页（ECharts）
    ├── curve/index.html                # 曲线页（Canvas）
    └── about/index.html                # 关于我们页

web/                                    # Web端管理界面（MiniUI，现场一体机）
├── index.html
├── scripts/
│   ├── scada.ts                        # SCADA核心 - TypeScript
│   ├── tags.ts                         # PLC标签定义 - TypeScript
│   ├── scada.js                        # SCADA核心 - 编译后
│   ├── tags.js                         # PLC标签定义 - 编译后
│   ├── boot.js                         # MiniUI启动脚本
│   ├── core.js                         # MiniUI核心
│   ├── plc.js                          # PLC基础功能
│   ├── jquery.min.js
│   ├── miniui/                         # MiniUI库
│   └── global.d.ts                     # TypeScript全局类型声明
├── common/
│   └── common.ts                       # 公共工具函数
├── forms/cm/
│   ├── module.js                       # 表单公共模块
│   ├── monitor/                        # 自动监控页面
│   ├── recipe/                         # 配方管理
│   ├── plan/                           # 计划管理
│   ├── alarm/                          # 报警管理
│   └── report/                         # 报表管理
└── res/images/                         # 图片资源
```

### 5.2 现场电脑（一体机）目录

```
C:\SiteSystem\                              # 现场系统根目录
│
├── Kepware/                                # Kepware OPC Server
│   ├── servermain.exe
│   └── Siemens_S7_1500.opf                 # S7-1500项目配置
│
├── SiteApp/                                # 现场应用程序
│   ├── package.json                        # Node依赖配置
│   │
│   ├── config/
│   │   └── config.json                     # 现场配置
│   │
│   ├── src/
│   │   ├── index.js                        # 主入口
│   │   ├── plc/                            # PLC通信层
│   │   │   ├── scada.js
│   │   │   ├── tags.js
│   │   │   └── kepware-client.js
│   │   ├── database/                       # 数据库操作（连云端MySQL）
│   │   │   ├── connection.js
│   │   │   ├── recipe.js
│   │   │   ├── plan.js
│   │   │   ├── alarm.js
│   │   │   └── report.js
│   │   ├── cloud-sync/                     # 云端数据同步
│   │   │   ├── monitor-publisher.js        # 监控快照定时写入
│   │   │   ├── curve-publisher.js          # 曲线数据定时写入
│   │   │   └── command-poller.js           # 待执行指令轮询
│   │   ├── local-server/                   # 本地Web服务（Express）
│   │   │   ├── server.js
│   │   │   ├── routes/
│   │   │   └── middleware/
│   │   └── utils/
│   │
│   ├── web/                                # 本地监控界面（MiniUI）
│   │   ├── index.html
│   │   ├── main.html
│   │   ├── pages/
│   │   ├── scripts/
│   │   └── css/
│   │
│   └── logs/                               # 本地日志
│
├── start.bat
└── install-service.bat
```

---

## 六、数据库层架构

### 6.1 表职责划分

#### 【配置类】由现场一体机维护，微信端只读

| 表名 | 职责 | 微信端权限 | 一体机权限 |
|------|------|-----------|-----------|
| `M_RECIPE` | 配方主数据 | 只读（下拉选择） | 读写 |
| `CM_MENU` | 系统菜单配置 | 不使用 | 读写 |

#### 【计划/指令类】微信端写入，一体机读取执行

| 表名 | 职责 | 微信端权限 | 一体机权限 |
|------|------|-----------|-----------|
| `M_PLAN` | 生产计划。`STATE=0`为待下达，微信端创建；一体机读取后改为`STATE=1`执行中 | 读写 | 读写 |
| `M_TRANSFER` | **配方/计划中转表**。微信端"发送配方"时写入此表；一体机读取后下发到PLC，并删除或标记已执行 | 写（插入） | 读+删/改 |

#### 【实时/历史数据类】由一体机写入，微信端只读

| 表名 | 职责 | 微信端权限 | 一体机权限 |
|------|------|-----------|-----------|
| `R_CURVE` | **实时曲线数据**。一体机每秒/每周期将PLC压力数据写入 | 只读（查询历史/实时） | 写（插入） |
| `R_WEIGH` | 称重记录。每批每次称重的实际重量 | 只读 | 写（插入） |
| `R_TRANSFER` | 生产执行汇总。每批生产完成后的汇总数据 | 只读 | 写（插入/更新） |
| `R_RECIPE` | 配方下发记录。记录每次实际下发到PLC的配方参数 | 只读 | 写（插入） |
| `M_PRODUCTION` | 生产批次汇总。LOT级别的生产汇总 | 只读 | 写（插入/更新） |

### 6.2 新增表

#### `M_MONITOR_REALTIME` — 监控实时数据快照表

一体机定时将关键PLC数据写入此表，微信端监控页轮询此表获取最新状态。

```sql
CREATE TABLE `M_MONITOR_REALTIME` (
  `ID` bigint NOT NULL AUTO_INCREMENT,
  `LOT_ID` varchar(20) DEFAULT NULL COMMENT '当前计划号',
  `RECIPE_NAME` varchar(30) DEFAULT NULL COMMENT '当前配方',
  `BATCH_SET` int DEFAULT '0' COMMENT '设定批次',
  `BATCH1_FINISH` int DEFAULT '0' COMMENT '1#完成批次',
  `BATCH2_FINISH` int DEFAULT '0' COMMENT '2#完成批次',
  `BATCH3_FINISH` int DEFAULT '0' COMMENT '3#完成批次',
  `WEIGHT1_ACT` decimal(8,3) DEFAULT '0.000' COMMENT '1#当前重量',
  `WEIGHT2_ACT` decimal(8,3) DEFAULT '0.000' COMMENT '2#当前重量',
  `WEIGHT3_ACT` decimal(8,3) DEFAULT '0.000' COMMENT '3#当前重量',
  `STATUS` tinyint(1) DEFAULT '0' COMMENT '设备状态：0-停机 1-运行 2-报警',
  `ALARM_CODE` varchar(20) DEFAULT NULL COMMENT '当前报警码',
  `UPDATE_TIME` varchar(14) NOT NULL DEFAULT ' ' COMMENT '更新时间',
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='实时监控快照';
```

> **说明**：此表只有1条记录（ID=1），每次更新即`REPLACE INTO`或`UPDATE`。

---

## 七、一体机交互协议

### 7.1 一体机 → 云端（写入实时数据）

#### A. 写入实时监控快照

```sql
-- 每 1~3 秒执行一次
REPLACE INTO M_MONITOR_REALTIME (
  ID, LOT_ID, RECIPE_NAME, BATCH_SET,
  BATCH1_FINISH, BATCH2_FINISH, BATCH3_FINISH,
  WEIGHT1_ACT, WEIGHT2_ACT, WEIGHT3_ACT,
  STATUS, ALARM_CODE, UPDATE_TIME
) VALUES (
  1, '{当前LOT_ID}', '{当前配方}', {设定批次},
  {1#完成}, {2#完成}, {3#完成},
  {1#重量}, {2#重量}, {3#重量},
  {状态码}, {报警码}, DATE_FORMAT(NOW(),'%Y%m%d%H%i%s')
);
```

#### B. 写入曲线数据

```sql
-- 每秒执行一次（或根据PLC扫描周期）
INSERT INTO R_CURVE (
  LOT_ID, BATCH_SET, BATCH, SYS_NO, RECIPE_NAME,
  MAX_PRESSURE, FEED_PRESSURE, SAVE_TIME
) VALUES (
  '{LOT_ID}', {设定批次}, {当前批次}, {系统号}, '{配方名}',
  {最大压力}, {喂料压力}, DATE_FORMAT(NOW(),'%Y%m%d%H%i%s')
);
```

#### C. 写入称重记录

```sql
-- 每批次称重完成后执行
INSERT INTO R_WEIGH (
  LOT_ID, BATCH, SYS_NO, RECIPE_NAME,
  WEIGHT_SET, TOLERANCE_SET, WEIGHT, SAVE_TIME, BATCH_SET
) VALUES (...);
```

### 7.2 一体机 → 云端（读取待执行指令）

一体机每 1~2 秒轮询以下逻辑：

```sql
-- 查询待发送的配方/计划
SELECT * FROM M_TRANSFER 
WHERE LOCAL_FLAG = 0 OR LOCAL_FLAG IS NULL
ORDER BY SAVE_TIME ASC LIMIT 1;
```

读取到记录后：
1. 将配方参数写入PLC
2. 更新 `M_TRANSFER.LOCAL_FLAG = 1`（已执行）
3. 更新 `M_PLAN.STATE = 1`（执行中）
4. 同时插入 `R_RECIPE` 记录实际下发的配方

### 7.3 生产完成同步

当PLC报告某批次/计划完成时：
1. 更新 `R_TRANSFER` 的完成数量和完成时间
2. 更新 `M_PLAN.STATE = 2`（已完成）
3. 插入或更新 `M_PRODUCTION`

---

## 八、部署说明

### 8.1 云端部署（Nginx + PHP + MySQL）

```bash
# 1. 数据库
mysql -u dev -p miniprogram_exhibition < sql/exhibition_new_tables.sql

# 2. API文件
rsync -av api/exhibition/ /var/www/html/api/exhibition/

# 3. H5页面
rsync -av mobile/exhibition/ /var/www/html/mobile/exhibition/

# 4. Nginx 确保移动端路径可访问
# location /mobile/exhibition/ { ... }

# 5. 配置SSL证书（HTTPS必需）
mkdir -p /etc/ssl/certs /etc/ssl/private
cp cert.pem /etc/ssl/certs/
cp key.pem /etc/ssl/private/
```

### 8.2 现场电脑部署

```batch
REM 1. 安装Node.js (Windows)
REM 下载并安装 https://nodejs.org/dist/v18.17.1/node-v18.17.1-x64.msi

REM 2. 安装依赖
cd C:\SiteSystem\SiteApp
npm install

REM 3. 配置config.json
REM 修改siteId、云端服务器地址、MySQL连接信息
REM 特别注意配置 cloud.sync 参数：
REM   - realtimeInterval: 2000  (监控快照写入间隔)
REM   - curveInterval: 1000     (曲线数据写入间隔)
REM   - commandPollInterval: 1000 (待执行指令轮询间隔)

REM 4. 启动
cd C:\SiteSystem
start.bat

REM 5. 设置为开机启动（可选）
install-service.bat
```

---

## 九、启动流程

### 现场一体机上电启动顺序

```
1. Windows 启动
   │
   ▼
2. Kepware 服务启动
   │   └──► 连接西门子 S7-1500 (S7协议)
   │
   ▼
3. SiteApp 启动
   │   ├──► 连接 Kepware (OPC/DA)
   │   ├──► 连接云端 MySQL (TCP:3306)
   │   │       ├──► 定时写入 M_MONITOR_REALTIME（监控快照，每2秒）
   │   │       ├──► 定时写入 R_CURVE（曲线数据，每1秒）
   │   │       └──► 定时轮询 M_TRANSFER（读取待发送配方，每1秒）
   │   └──► 启动本地 Web 服务 (HTTP:8080)
   │
   ▼
4. Chrome 全屏启动
       └──► 访问 http://localhost:8080
```

---

## 十、关键设计说明

### 10.1 为什么配方/计划管理以现场操作为主？

- **可靠性**：网络中断不影响生产操作
- **实时性**：本地操作延迟 < 10ms
- **安全性**：关键操作在封闭内网完成
- **便利性**：操作员直接使用工控机，无需手机

> **小程序端发送配方说明**：展会版小程序允许用户从移动端"发送配方"，但其实现方式是**将配方参数写入云端 MySQL 的 `M_TRANSFER` 表**，由现场一体机轮询读取后写入PLC。实际的PLC写入操作仍然由一体机完成，微信端不直接触碰PLC。

### 10.2 为什么使用云端MySQL？

- **数据集中**：多个现场的数据统一管理
- **远程可查**：小程序随时查询历史记录
- **数据安全**：云端备份，防止现场数据丢失
- **扩展性**：便于后续数据分析、报表统计

### 10.3 为什么微信端不直接连接PLC？

- **安全性**：PLC 属于工业控制网络，不应暴露给公网访问
- **稳定性**：数据库比直接 PLC 通信更稳定，支持断线重连和缓存
- **简化架构**：微信端只需处理 HTTP 请求，无需维护 OPC/WebSocket 连接
- **职责分离**：云端只做数据存储，PLC 交互由现场一体机专业处理

---

## 十一、技术要点

1. **数据库轮询频率**：微信端监控页建议 3 秒轮询一次；曲线实时模式建议 2 秒轮询一次
2. **数据量控制**：R_CURVE 表数据增长快，建议一体机保留最近 7 天详细数据，历史数据归档或降采样
3. **并发写入控制**：M_MONITOR_REALTIME 只有 1 条记录，一体机使用 `REPLACE INTO` 避免锁竞争
4. **配方下发延迟**：一体机轮询 M_TRANSFER 间隔建议 1 秒，展会演示前可预先下发测试配方
5. **状态同步**：M_PLAN 的 STATE 字段由一体机主导变更；微信端只创建 STATE=0（待执行）的记录
6. **MySQL连接池**：现场使用连接池管理数据库连接，避免频繁创建
7. **跨域处理**：云端API需配置CORS允许现场域名访问
8. **断线重连**：现场MySQL客户端需实现自动重连机制
9. **数据缓存**：微信端可缓存最近一次的API响应，在断网时显示最后已知状态
10. **时间同步**：一体机与云端服务器需保持时间同步，确保 SAVE_TIME 字段准确

---

## 十二、联系方式

- **公司**：北京翔远同创科技有限公司
- **客服电话**：400-810-0069转3676
- **公司地址**：北京市丰台区大成里秀园13号楼东侧楼
