From 54910626b11f84ab8e93bdfb07f685ff1dd84a5b Mon Sep 17 00:00:00 2001
From: haoliang <821644@qq.com>
Date: Tue, 12 May 2026 16:17:15 +0800
Subject: [PATCH] =?UTF-8?q?=E9=87=87=E9=9B=86=E6=9C=8D=E5=8A=A1=E4=BA=A7?=
=?UTF-8?q?=E9=87=8F=E7=BB=9F=E8=AE=A1=E5=85=A8=E6=B5=81=E7=A8=8B=E6=B5=8B?=
=?UTF-8?q?=E8=AF=95=E9=AA=8C=E8=AF=81=EF=BC=9ADB=20Schema=E5=90=8C?=
=?UTF-8?q?=E6=AD=A5=E3=80=81=E5=93=81=E7=89=8C=E6=98=A0=E5=B0=84=E4=BF=AE?=
=?UTF-8?q?=E6=AD=A3=E3=80=81=E9=87=87=E9=9B=86/=E6=A8=A1=E6=8B=9F?=
=?UTF-8?q?=E5=99=A8=E4=BB=A3=E7=A0=81=E4=BF=AE=E6=94=B9=E3=80=8110?=
=?UTF-8?q?=E5=9C=BA=E6=99=AF=E6=B5=8B=E8=AF=95=E5=85=A8=E9=80=9A=E8=BF=87?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
database/01-init-schema.sql | 2 +
database/02-init-data.sql | 26 +-
docs/00-需求与设计文档.md | 3 +
docs/01-数据库设计.md | 3 +
docs/07-发那科数据结构变更调整方案.md | 508 ++++++++++++++++++
frontend/mock/brand.ts | 29 +-
frontend/mock/machine.ts | 4 +-
frontend/mock/simulator.ts | 8 +-
frontend/src/api/simulator.ts | 7 +-
frontend/src/types/index.ts | 22 +-
.../src/views/machine/MachineDetailPage.vue | 5 +-
simulator.json | 10 +-
src/CncCollector/Core/CollectRecordWriter.cs | 27 +-
src/CncCollector/Core/CollectWorker.cs | 24 +-
src/CncCollector/Core/DataParser.cs | 36 +-
src/CncModels/Entity/CollectRecord.cs | 3 +
src/CncSimulator/Config/SimulatorConfig.cs | 4 +
src/CncSimulator/Core/SimulatorEngine.cs | 61 +++
src/CncSimulator/Core/SimulatorServer.cs | 65 ++-
src/CncSimulator/Device/DeviceSimulator.cs | 49 +-
src/CncSimulator/Device/DeviceState.cs | 30 +-
.../Generator/FanucDataGenerator.cs | 16 +-
src/CncWebApi/Global.asax.cs | 8 +-
src/CncWebApi/Web.config | 34 ++
发那科系统采集示例.txt | 2 +-
25 files changed, 789 insertions(+), 197 deletions(-)
create mode 100644 docs/07-发那科数据结构变更调整方案.md
diff --git a/database/01-init-schema.sql b/database/01-init-schema.sql
index 978c604..c3e29c4 100644
--- a/database/01-init-schema.sql
+++ b/database/01-init-schema.sql
@@ -83,6 +83,7 @@ CREATE TABLE IF NOT EXISTS cnc_machine (
last_run_status VARCHAR(20) NULL,
last_program_name VARCHAR(200) NULL,
last_part_count DECIMAL(15,5) NULL,
+ last_total_part_count DECIMAL(15,5) NULL,
last_operate_mode VARCHAR(20) NULL,
last_machining_status VARCHAR(20) NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
@@ -128,6 +129,7 @@ CREATE TABLE IF NOT EXISTS cnc_collect_record (
device_time DATETIME NULL,
program_name VARCHAR(200) NULL,
part_count DECIMAL(15,5) NULL,
+ total_part_count DECIMAL(15,5) NULL,
device_status VARCHAR(20) NULL,
run_status VARCHAR(20) NULL,
operate_mode VARCHAR(20) NULL,
diff --git a/database/02-init-data.sql b/database/02-init-data.sql
index f58b0d3..aef1fca 100644
--- a/database/02-init-data.sql
+++ b/database/02-init-data.sql
@@ -15,26 +15,18 @@ INSERT IGNORE INTO cnc_workshop (name, sort_order, is_enabled) VALUES
INSERT IGNORE INTO cnc_brand (brand_name, device_field, tags_path, is_enabled) VALUES
('FANUC', 'device', 'tags', 1);
--- FANUC字段映射预置
+-- FANUC字段映射预置(field_name = 实际FANUC采集JSON中的tag id)
SET @fanuc_brand_id = (SELECT id FROM cnc_brand WHERE brand_name = 'FANUC');
INSERT IGNORE INTO cnc_brand_field_mapping (brand_id, standard_field, field_name, match_by, data_type, is_required) VALUES
-(@fanuc_brand_id, 'program_name', 'program_name', 'id', 'string', 1),
-(@fanuc_brand_id, 'part_count', 'part_count', 'id', 'number', 1),
-(@fanuc_brand_id, 'device_status', 'device_status', 'id', 'number', 0),
-(@fanuc_brand_id, 'run_status', 'run_status', 'id', 'number', 0),
-(@fanuc_brand_id, 'operate_mode', 'operate_mode', 'id', 'number', 0),
-(@fanuc_brand_id, 'spindle_speed_set', 'spindle_speed_set', 'id', 'number', 0),
-(@fanuc_brand_id, 'feed_speed_set', 'feed_speed_set', 'id', 'number', 0),
-(@fanuc_brand_id, 'spindle_speed_actual', 'spindle_speed_actual', 'id', 'number', 0),
-(@fanuc_brand_id, 'feed_speed_actual', 'feed_speed_actual', 'id', 'number', 0),
-(@fanuc_brand_id, 'spindle_load', 'spindle_load', 'id', 'number', 0),
-(@fanuc_brand_id, 'spindle_override', 'spindle_override', 'id', 'number', 0),
-(@fanuc_brand_id, 'power_on_time', 'power_on_time', 'id', 'number', 0),
-(@fanuc_brand_id, 'run_time', 'run_time', 'id', 'number', 0),
-(@fanuc_brand_id, 'cutting_time', 'cutting_time', 'id', 'number', 0),
-(@fanuc_brand_id, 'cycle_time', 'cycle_time', 'id', 'number', 0),
-(@fanuc_brand_id, 'machining_status', 'machining_status', 'id', 'string', 0);
+(@fanuc_brand_id, 'program_name', 'Tag5', 'id', 'string', 1),
+(@fanuc_brand_id, 'part_count', 'Tag8', 'id', 'number', 1),
+(@fanuc_brand_id, 'total_part_count', 'Tag1', 'id', 'number', 0),
+(@fanuc_brand_id, 'device_status', '_io_status', 'id', 'number', 0),
+(@fanuc_brand_id, 'run_status', 'Tag9', 'id', 'number', 0),
+(@fanuc_brand_id, 'operate_mode', 'Tag11', 'id', 'number', 0),
+(@fanuc_brand_id, 'power_on_time', 'Tag22', 'id', 'number', 0),
+(@fanuc_brand_id, 'run_time', 'Tag23', 'id', 'number', 0);
-- 系统配置预置
INSERT IGNORE INTO cnc_sys_config (config_key, config_value, value_type, description) VALUES
diff --git a/docs/00-需求与设计文档.md b/docs/00-需求与设计文档.md
index d966815..dea637e 100644
--- a/docs/00-需求与设计文档.md
+++ b/docs/00-需求与设计文档.md
@@ -63,6 +63,9 @@
| 原始数据 | 存原始JSON到日志库,解析后结构化数据存业务库 |
| 时间标准 | 以服务器时间为准,机床时间仅存为参考字段 |
| 数值处理 | 自动去除.00000尾缀,转换为数值/字符串 |
+| 数据有效性 | quality≠0的tag无效;time以1970-01-01开头的tag无效(采集失败);_io_status始终有效不受quality/time约束 |
+| 总零件数 | Tag1(加工零件总数)为历史终身累计值,与Tag8(当前程序零件数)不同维度 |
+| 变更检测 | 采集服务对比tag的value值判断变化,不依赖time字段(time和value独立变化) |
### 4.3 零件产量统计
diff --git a/docs/01-数据库设计.md b/docs/01-数据库设计.md
index d15a363..72d3767 100644
--- a/docs/01-数据库设计.md
+++ b/docs/01-数据库设计.md
@@ -88,6 +88,7 @@ CREATE TABLE cnc_brand_field_mapping (
| cutting_time | 切削时间 | number |
| cycle_time | 循环时间 | number |
| machining_status | 加工状态 | string |
+| total_part_count | 历史累计加工零件总数 | number |
索引:uk_brand_standard唯一约束同时作为索引,保证同一品牌下标准字段不重复,采集时按brand_id查询所有映射规则。
@@ -137,6 +138,7 @@ CREATE TABLE cnc_machine (
last_run_status VARCHAR(20) NULL,
last_program_name VARCHAR(200) NULL,
last_part_count DECIMAL(15,5) NULL,
+ last_total_part_count DECIMAL(15,5) NULL,
last_operate_mode VARCHAR(20) NULL,
last_machining_status VARCHAR(20) NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
@@ -208,6 +210,7 @@ CREATE TABLE cnc_collect_record (
device_time DATETIME NULL,
program_name VARCHAR(200) NULL,
part_count DECIMAL(15,5) NULL,
+ total_part_count DECIMAL(15,5) NULL,
device_status VARCHAR(20) NULL,
run_status VARCHAR(20) NULL,
operate_mode VARCHAR(20) NULL,
diff --git a/docs/07-发那科数据结构变更调整方案.md b/docs/07-发那科数据结构变更调整方案.md
new file mode 100644
index 0000000..a43564d
--- /dev/null
+++ b/docs/07-发那科数据结构变更调整方案.md
@@ -0,0 +1,508 @@
+# 发那科采集数据结构变更 - 系统调整方案
+
+> 创建时间:2026-05-11
+> 触发原因:发那科系统采集示例文件(根目录 `发那科系统采集示例.txt`)更新,实际FANUC采集数据结构与系统原有设计存在差异
+> 涉及模块:CncSimulator模拟器、数据库设计、采集服务设计、后台管理功能
+
+---
+
+## 一、实际FANUC数据结构(2026-05-11 采自生产环境)
+
+### 1.1 顶层结构
+
+```json
+[
+ {
+ "device": "fanake-1.2_1.2", // 设备编码,匹配 cnc_machine.device_code
+ "desc": "西-1.2", // 设备描述
+ "tags": [ ... ] // 10个Tag
+ },
+ ...
+]
+```
+
+共32台设备,每台10个Tag。其中25台在线、7台离线。
+
+### 1.2 Tag清单(10个)
+
+| # | Tag ID | desc(中文) | 类型 | 示例值 | 备注 |
+|---|--------|-------------|------|--------|------|
+| 1 | `_io_status` | 设备状态 | 数值 | 0.00000 / 1.00000 | 0=离线, 1=在线;**始终有效** |
+| 2 | `Tag5` | 执行的NC主程序名 | 字符串 | O1, O9001, 1370.NC, 7, 1027, O2, 037.NC | 可为空 |
+| 3 | `Tag6` | 执行的NC主程序号 | 字符串 | N0, N1, N9, N20 | |
+| 4 | `Tag7` | 当前加工程序内容 | 字符串 | G代码片段 | 可为空 |
+| 5 | `Tag8` | 当前加工零件数 | 数值 | 35.00000 | 当前程序的零件计数 |
+| 6 | `Tag9` | 运行状态 | 数值 | 0.00000 / 1.00000 / 3.00000 | 0=待机, 1=运行, 3=加工中 |
+| 7 | `Tag11` | 操作模式 | 数值 | 1 / 4 / 5 / 10 | 1=MEM, 4=?, 5=?, 10=JOG |
+| 8 | `Tag22` | 开机时间 | 数值 | 45129840.00000 | 秒,历史累计 |
+| 9 | `Tag23` | 运行时间 | 数值 | 12201.00000 | 秒,历史累计 |
+| 10 | `Tag1` | 加工零件总数 | 数值 | 45930.00000 | **历史终身累计,新增字段** |
+
+### 1.3 数据有效性规则
+
+#### 规则1:Quality字段
+
+| quality值 | 含义 | 处理方式 |
+|-----------|------|---------|
+| `"0"` | 数据有效 | 正常解析 |
+| `"1"` | 数据无效(采集失败/设备离线) | 忽略该tag的value |
+
+#### 规则2:Time字段(采集失败标记)
+
+| time值 | 含义 | 处理方式 |
+|--------|------|---------|
+| `1970-01-01 08:00:00` | 采集失败 | 忽略该tag的value |
+| 其他正常时间 | 数据时间戳 | 正常使用 |
+
+#### 规则3:_io_status 特殊处理
+
+`_io_status` tag **不受规则1和规则2约束**,始终读取value判断设备在线/离线:
+- 即使设备离线,`_io_status` 的 quality=0、time=真实时间、value=0
+
+#### 规则4:Time与Value独立变化
+
+每个tag的 `time` 和 `value` 更新频率不固定:
+- time变了、value没变
+- value变了、time没变
+- 都变了
+- 都没变
+
+**采集服务的变更检测必须对比value值,不能依赖time变化作为变更信号。**
+
+### 1.4 离线设备特征
+
+以 fanake-1.10 为例:
+
+```
+_io_status: quality=0, value=0.00000, time=2026-05-11 17:06:34 ← 始终有效
+Tag5: quality=1, value="", time=1970-01-01 08:00:00 ← 无效
+Tag6: quality=1, value="", time=1970-01-01 08:00:00 ← 无效
+Tag7: quality=1, value="", time=1970-01-01 08:00:00 ← 无效
+Tag8: quality=1, value=0.00000, time=1970-01-01 08:00:00 ← 无效
+Tag9: quality=1, value=0.00000, time=1970-01-01 08:00:00 ← 无效
+Tag11: quality=1, value=0.00000, time=1970-01-01 08:00:00 ← 无效
+Tag22: quality=1, value=0.00000, time=1970-01-01 08:00:00 ← 无效
+Tag23: quality=1, value=0.00000, time=1970-01-01 08:00:00 ← 无效
+Tag1: quality=1, value=0.00000, time=1970-01-01 08:00:00 ← 无效
+```
+
+---
+
+## 二、与现有设计的差异对比
+
+### 2.1 模拟器(FanucDataGenerator)差异
+
+| 差异项 | 现有模拟器(18个Tag) | 实际FANUC(10个Tag) | 影响 |
+|--------|----------------------|---------------------|------|
+| Tag2 (当前轴数) | ✅ 有 | ❌ 不存在 | 模拟器多余 |
+| Tag14 (主轴倍率) | ✅ 有 | ❌ 不存在 | 模拟器多余 |
+| Tag17 (主轴设定速度) | ✅ 有 | ❌ 不存在 | 模拟器多余 |
+| Tag18 (进给设定速度) | ✅ 有 | ❌ 不存在 | 模拟器多余 |
+| Tag19 (主轴实际速度) | ✅ 有 | ❌ 不存在 | 模拟器多余 |
+| Tag20 (进给实际转速) | ✅ 有 | ❌ 不存在 | 模拟器多余 |
+| Tag21 (主轴负载) | ✅ 有 | ❌ 不存在 | 模拟器多余 |
+| Tag24 (切削时间) | ✅ 有 | ❌ 不存在 | 模拟器多余 |
+| Tag25 (循环时间) | ✅ 有 | ❌ 不存在 | 模拟器多余 |
+| Tag26 (加工状态) | ✅ 有 | ❌ 不存在 | 模拟器多余 |
+| **Tag1 (加工零件总数)** | ❌ 缺少 | ✅ 有 | **模拟器缺少,需新增** |
+| Tag6 desc | "执行的NC主程序号" | "执行的NC主程序号" | 一致 |
+
+### 2.2 数据库设计差异
+
+| 差异项 | 现有设计 | 实际需求 |
+|--------|---------|---------|
+| 标准字段 total_part_count | ❌ 无 | ✅ 需要新增,对应Tag1 |
+| cnc_collect_record.total_part_count | ❌ 无 | ✅ 需要新增列 |
+| cnc_machine.last_total_part_count | ❌ 无 | ✅ 需要新增列 |
+
+### 2.3 采集服务设计差异
+
+| 差异项 | 现有设计假设 | 实际行为 |
+|--------|-------------|---------|
+| 数据有效性判断 | 未明确quality处理 | 需按quality+time双规则过滤 |
+| _io_status处理 | 未明确特殊性 | 始终有效,不受quality/time约束 |
+| 变更检测 | 未明确time/value独立性 | 必须对比value,不看time |
+| Tag1(总零件数) | 无此字段 | 需解析并存储 |
+
+### 2.4 后台管理差异
+
+| 差异项 | 现有设计 | 实际需求 |
+|--------|---------|---------|
+| 速度/倍率/负载字段 | 设计了展示 | FANUC设备这些字段为NULL,需处理空值 |
+| 加工零件总数 | 未设计展示 | 可选展示 |
+| 操作模式枚举 | 仅定义1=MEM, 10=JOG | 实际还有4、5值,需补充定义 |
+
+---
+
+## 三、调整方案
+
+### 3.1 CncSimulator 模拟器调整(优先级:高)
+
+> 目标:让模拟器生成的数据结构与实际FANUC完全一致
+
+#### 3.1.1 DeviceState.cs 修改
+
+```diff
+ public class DeviceState
+ {
+ // ===== 固定信息(来自配置) =====
+ public string DeviceCode { get; set; }
+ public string Desc { get; set; }
+
+ // ===== 动态状态 =====
+ public string CurrentScenario { get; set; } = "idle";
+ public bool IsOnline { get; set; } = true;
+ public string ProgramName { get; set; } = "O0001";
+ public int PartCount { get; set; } = 0;
++ /// 历史终身累计零件总数(对应Tag1)
++ public decimal TotalPartCount { get; set; } = 0;
+ public int DeviceStatus { get; set; } = 1;
+ public int RunStatus { get; set; } = 0;
+ public int OperateMode { get; set; } = 1;
+- public decimal SpindleSpeedSet { get; set; } = 450;
+- public decimal FeedSpeedSet { get; set; } = 60;
+- public decimal SpindleSpeedActual { get; set; } = 0;
+- public decimal FeedSpeedActual { get; set; } = 0;
+- public decimal SpindleLoad { get; set; } = 0;
+- public decimal SpindleOverride { get; set; } = 100;
+ public decimal PowerOnTime { get; set; } = 0;
+ public decimal RunTime { get; set; } = 0;
+- public decimal CuttingTime { get; set; } = 0;
+- public decimal CycleTime { get; set; } = 0;
+- public string MachiningStatus { get; set; } = "";
+ public string ProgramContent { get; set; } = "";
+ // ... 其余字段保留不变
+ }
+```
+
+**说明**:移除实际FANUC不存在的字段(SpindleSpeedSet、FeedSpeedSet、SpindleSpeedActual、FeedSpeedActual、SpindleLoad、SpindleOverride、CuttingTime、CycleTime、MachiningStatus),新增TotalPartCount。
+
+#### 3.1.2 FanucDataGenerator.cs 修改
+
+```diff
+ private JArray GenerateTags(DeviceState state)
+ {
+ var tags = new JArray();
+ DateTime baseTime = DateTime.Now;
+
+ // 每个tag的时间基准上随机偏移 -5~0 秒
+ DateTime TagTime()
+ {
+ return baseTime.AddSeconds(-_rng.Next(0, 6));
+ }
+
+ void AddNumericTag(string id, string desc, decimal value) { /* 不变 */ }
+ void AddStringTag(string id, string desc, string value) { /* 不变 */ }
+
+- // 18个tag → 10个tag,与实际FANUC完全一致
+ AddNumericTag("_io_status", "设备状态", state.DeviceStatus);
+- AddNumericTag("Tag2", "当前轴数", 4);
++ AddNumericTag("Tag1", "加工零件总数", state.TotalPartCount);
+ AddStringTag("Tag5", "执行的NC主程序名", state.ProgramName);
+ AddStringTag("Tag6", "执行的NC主程序号", "N0");
+ AddStringTag("Tag7", "当前加工程序内容", /* ... */);
+ AddNumericTag("Tag8", "当前加工零件数", state.PartCount);
+ AddNumericTag("Tag9", "运行状态", state.RunStatus);
+ AddNumericTag("Tag11", "操作模式", state.OperateMode);
+- AddNumericTag("Tag14", "当前主轴倍率", state.SpindleOverride);
+- AddNumericTag("Tag17", "主轴设定速度", state.SpindleSpeedSet);
+- AddNumericTag("Tag18", "进给设定速度", state.FeedSpeedSet);
+- AddNumericTag("Tag19", "主轴实际速度", state.SpindleSpeedActual);
+- AddNumericTag("Tag20", "进给实际转速", state.FeedSpeedActual);
+- AddNumericTag("Tag21", "主轴负载", state.SpindleLoad);
+ AddNumericTag("Tag22", "开机时间", state.PowerOnTime);
+ AddNumericTag("Tag23", "运行时间", state.RunTime);
+- AddNumericTag("Tag24", "切削时间", state.CuttingTime);
+- AddNumericTag("Tag25", "循环时间", state.CycleTime);
+- AddStringTag("Tag26", "加工状态", state.MachiningStatus);
+
+ return tags;
+ }
+```
+
+#### 3.1.3 DeviceSimulator.cs 修改
+
+- 构造函数:新增 `TotalPartCount` 初始值配置(从simulator.json读取)
+- `machining` 场景:`TotalPartCount++`
+- `ApplyProgramChange()`:TotalPartCount 不清零(终身累计)
+- `ApplyManualReset()`:TotalPartCount 不清零
+- `ApplyPowerOn()`:TotalPartCount 不清零
+- 移除所有已删除字段(SpindleSpeed*、SpindleLoad、SpindleOverride、CuttingTime、CycleTime、MachiningStatus)的模拟逻辑
+
+#### 3.1.4 simulator.json 修改
+
+devices配置中新增 `initialTotalPartCount` 字段:
+
+```json
+{
+ "deviceCode": "CNC-A001",
+ "desc": "西栋1号",
+ "initialProgram": "O0001",
+ "initialPartCount": 50,
+ "initialTotalPartCount": 45000
+}
+```
+
+#### 3.1.5 模拟器离线行为
+
+当设备断电(power_off)时,需要生成与实际一致的离线数据:
+- `_io_status`:quality=0, value=0, time=当前时间
+- 其他所有tag:quality=1, value="" 或 "0.00000", time="1970-01-01 08:00:00"
+
+---
+
+### 3.2 数据库设计调整(优先级:高)
+
+#### 3.2.1 cnc_brand_field_mapping 标准字段约定
+
+在 `docs/01-数据库设计.md` 的标准字段约定表中新增:
+
+| standard_field | 含义 | data_type |
+|----------------|------|-----------|
+| **total_part_count** | **历史累计加工零件总数** | **number** |
+
+#### 3.2.2 cnc_collect_record 表
+
+新增列:
+
+```sql
+ALTER TABLE cnc_collect_record
+ ADD COLUMN total_part_count DECIMAL(15,5) NULL COMMENT '历史累计加工零件总数'
+ AFTER part_count;
+```
+
+完整DDL变更位置:在 `part_count` 列之后增加 `total_part_count` 列。
+
+#### 3.2.3 cnc_machine 表
+
+新增列:
+
+```sql
+ALTER TABLE cnc_machine
+ ADD COLUMN last_total_part_count DECIMAL(15,5) NULL COMMENT '最新历史累计加工零件总数'
+ AFTER last_part_count;
+```
+
+#### 3.2.4 FANUC品牌预置映射数据
+
+在 `database/` 预置数据脚本中,FANUC品牌的 field_mapping 新增一行:
+
+| brand_id | standard_field | field_name | match_by | data_type | is_required |
+|----------|---------------|------------|----------|-----------|-------------|
+| (FANUC) | total_part_count | Tag1 | id | number | 0 |
+
+同时,以下标准字段在实际FANUC中不存在,映射记录应标记 `is_required=0` 或不创建映射(由采集服务按实际数据决定):
+- spindle_speed_set → 无对应Tag
+- feed_speed_set → 无对应Tag
+- spindle_speed_actual → 无对应Tag
+- feed_speed_actual → 无对应Tag
+- spindle_load → 无对应Tag
+- spindle_override → 无对应Tag
+- cutting_time → 无对应Tag
+- cycle_time → 无对应Tag
+- machining_status → 无对应Tag
+
+---
+
+### 3.3 采集服务设计调整(优先级:高)
+
+#### 3.3.1 采集循环核心逻辑(伪代码)
+
+```
+每次采集循环(按采集地址配置的间隔):
+
+1. Ping目标地址
+ - Ping失败 → 更新 cnc_collect_address.fail_count++
+ - 连续5次失败 → 写告警
+ - 跳过本次采集
+
+2. HTTP GET 拉取JSON数组
+
+3. 原始JSON存日志库(cnc_raw_log,每次都存,不管有没有变化)
+
+4. 逐设备处理JSON数组中的每个元素:
+
+ 4.1 用 device 值匹配 cnc_machine.device_code
+ - 未匹配到 → 记录告警"发现未知设备",跳过
+
+ 4.2 解析 _io_status(特殊处理):
+ → 直接读取 value,不管 quality 和 time
+ → value=1 → 设备在线
+ → value=0 → 设备离线
+
+ 4.3 解析其他tag(标准处理):
+ for each tag in tags (排除 _io_status):
+ if tag.quality != "0" → 跳过(数据无效)
+ if tag.time 以 "1970-01-01" 开头 → 跳过(采集失败)
+ 否则 → 按 brand_field_mapping 映射为标准字段,解析 value
+
+ 4.4 写入结构化采集记录:
+ → INSERT INTO cnc_collect_record (每台设备每次采集一条)
+ → total_part_count 列写入 Tag1 的值(如果有效)
+ → 速度/倍率/负载等字段写 NULL(FANUC无此数据)
+
+ 4.5 业务变更检测(只对比 value,不看 time):
+
+ a. NC程序名变更检测:
+ if 新Tag5.value != 旧 cnc_machine.last_program_name:
+ → 结账当前产量段 (close_reason='program_change')
+ → 开新产量段
+
+ b. 零件数下降检测(手动清零):
+ if 新Tag8.value < 旧 cnc_machine.last_part_count
+ AND 新Tag5.value == 旧 cnc_machine.last_program_name:
+ → 结账当前产量段 (close_reason='manual_reset')
+ → 开新产量段,part_count 从新值开始
+
+ c. 运行状态变更:
+ if 新Tag9.value != 旧 cnc_machine.last_run_status:
+ → 仅更新实时状态,不触发产量段逻辑
+
+ d. 总零件数:仅记录,不触发任何业务逻辑
+
+ 4.6 更新机床实时状态(cnc_machine 的 last_* 字段):
+ → last_program_name = Tag5.value
+ → last_part_count = Tag8.value
+ → last_total_part_count = Tag1.value
+ → last_run_status = Tag9.value
+ → last_operate_mode = Tag11.value
+ → last_device_status = _io_status.value
+ → is_online = (_io_status.value == 1)
+ → last_collect_time = 当前服务器时间
+
+5. 更新采集地址状态:
+ → last_collect_time = 当前时间
+ → last_collect_status = 'success'
+ → fail_count = 0
+```
+
+#### 3.3.2 数据有效性判断流程图
+
+```
+收到一个tag
+ │
+ ├── tag.id == "_io_status" ?
+ │ ├── YES → 始终有效,直接读 value
+ │ └── NO → 进入标准判断 ↓
+ │
+ ├── tag.quality != "0" ?
+ │ ├── YES → 无效,跳过
+ │ └── NO → 继续判断 ↓
+ │
+ └── tag.time 以 "1970-01-01" 开头 ?
+ ├── YES → 无效,跳过
+ └── NO → 有效,解析 tag.value
+```
+
+---
+
+### 3.4 后台管理功能调整(优先级:中)
+
+#### 3.4.1 设备状态展示
+
+`cnc_machine` 表已有 `last_device_status`、`last_run_status` 等字段,展示逻辑不变。新增:
+- 设备详情中可选展示"累计加工总数"(来自 `last_total_part_count`)
+
+#### 3.4.2 大屏看板空值处理
+
+FANUC设备的以下字段恒为NULL:
+- 主轴设定速度、进给设定速度
+- 主轴实际速度、进给实际速度
+- 主轴负载、主轴倍率
+- 切削时间、循环时间
+- 加工状态
+
+大屏如果展示这些指标:
+- 数值型 → 显示 `--` 或 `N/A`
+- 图表型 → 该FANUC设备的线不画
+
+#### 3.4.3 品牌字段映射管理
+
+映射配置页面需支持新增的 `total_part_count` 标准字段。FANUC品牌预置映射中需包含 `Tag1 → total_part_count`。
+
+#### 3.4.4 前端Mock数据同步
+
+前端Mock数据中与FANUC相关的设备状态Mock,应同步为10个Tag的字段集(移除速度/负载等,新增total_part_count)。
+
+---
+
+### 3.5 设计文档更新(优先级:中)
+
+| 文档 | 更新内容 |
+|------|---------|
+| `docs/01-数据库设计.md` | 标准字段约定表增加 total_part_count;cnc_collect_record 和 cnc_machine 的DDL增加新列 |
+| `docs/00-需求与设计文档.md` | 4.2数据格式章节补充quality/1970-time/Tag1说明 |
+| `docs/03-API接口设计.md` | 如果有涉及采集记录字段的API响应格式,需同步增加 total_part_count |
+| `database/` | ALTER TABLE脚本 + FANUC预置映射数据新增 |
+
+---
+
+## 四、不需要调整的部分
+
+| 项目 | 原因 |
+|------|------|
+| 顶层JSON结构 `[{device, desc, tags}]` | 实际数据与设计一致 |
+| device字段匹配机床逻辑 | 设计正确,device值匹配device_code |
+| 零件分段计数核心逻辑(基于Tag8) | 不受影响,仍基于NC程序名切换+清零 |
+| 产量分段记录表 cnc_production_segment | 结构不变,total_part_count不影响分段计算 |
+| 采集地址/品牌管理配置架构 | 不变 |
+| 双库分离设计(原始JSON存日志库) | 不变 |
+| 采集间隔配置(地址级统一间隔) | 不变 |
+| 日终汇总逻辑 | 不变 |
+
+---
+
+## 五、执行顺序
+
+```
+阶段1:模拟器适配(让测试数据与实际一致)
+ ├── 1.1 DeviceState.cs 新增 TotalPartCount,移除多余字段
+ ├── 1.2 FanucDataGenerator.cs 改为10个Tag
+ ├── 1.3 DeviceSimulator.cs 调整场景逻辑
+ ├── 1.4 simulator.json 新增 initialTotalPartCount
+ └── 1.5 编译验证
+
+阶段2:数据库变更(数据基础)
+ ├── 2.1 cnc_collect_record 增加 total_part_count 列
+ ├── 2.2 cnc_machine 增加 last_total_part_count 列
+ ├── 2.3 标准字段约定表增加 total_part_count
+ ├── 2.4 FANUC预置映射数据增加 Tag1 映射
+ └── 2.5 设计文档同步更新
+
+阶段3:采集服务设计定稿(核心逻辑)
+ ├── 3.1 编写采集服务数据解析逻辑(含quality/time过滤)
+ ├── 3.2 编写变更检测逻辑(只看value不看time)
+ └── 3.3 编写Tag1存储逻辑(total_part_count仅记录不触发业务)
+
+阶段4:后台管理适配(展示层)
+ ├── 4.1 大屏空值处理(FANUC设备速度/负载为NULL时显示N/A)
+ ├── 4.2 前端Mock数据同步为10个Tag结构
+ └── 4.3 品牌映射管理支持total_part_count字段
+```
+
+---
+
+## 六、补充说明
+
+### 6.1 操作模式枚举值
+
+实际数据中出现了以下操作模式值,具体含义需与现场确认:
+
+| 值 | 已知含义 | 出现设备 |
+|----|---------|---------|
+| 1 | MEM(内存运行) | 加工中的设备 |
+| 4 | 待确认 | fanake-1.19(运行状态=1) |
+| 5 | 待确认 | fanake-1.24(运行状态=0) |
+| 10 | JOG(手动) | 待机中的设备 |
+
+### 6.2 device字段格式
+
+实际数据格式为 `fanake-1.2_1.2`(品牌-编号_编号),机床表的 `device_code` 需按此格式录入。
+
+### 6.3 数值精度
+
+所有数值型Tag的value都带5位小数(如 `35.00000`),采集服务解析时需 `Convert.ToDecimal` 后存储到 `DECIMAL(15,5)` 列。
+
+### 6.4 time字段格式
+
+统一格式 `yyyy-MM-dd HH:mm:ss`,需要按此格式解析。设备离线时为 `1970-01-01 08:00:00`(UTC+8时区下的epoch时间)。
diff --git a/frontend/mock/brand.ts b/frontend/mock/brand.ts
index 70b7027..3df9cb7 100644
--- a/frontend/mock/brand.ts
+++ b/frontend/mock/brand.ts
@@ -1,35 +1,26 @@
import type { MockMethod } from './types'
const brands = [
- { id: 1, brandName: 'FANUC', deviceField: 'device', tagsPath: 'tags', isEnabled: 1, fieldCount: 16 },
+ { id: 1, brandName: 'FANUC', deviceField: 'device', tagsPath: 'tags', isEnabled: 1, fieldCount: 8 },
{ id: 2, brandName: 'SIEMENS', deviceField: 'device', tagsPath: 'tags', isEnabled: 1, fieldCount: 12 },
{ id: 3, brandName: 'MITSUBISHI', deviceField: 'device', tagsPath: 'tags', isEnabled: 0, fieldCount: 8 },
]
const standardFields = [
- 'program_name', 'part_count', 'device_status', 'run_status', 'operate_mode',
- 'spindle_speed_set', 'feed_speed_set', 'spindle_speed_actual', 'feed_speed_actual',
- 'spindle_load', 'spindle_override', 'power_on_time', 'run_time', 'cutting_time',
- 'cycle_time', 'machining_status',
+ 'program_name', 'part_count', 'total_part_count', 'device_status', 'run_status', 'operate_mode',
+ 'power_on_time', 'run_time',
]
+// FANUC字段映射(与实际FANUC采集JSON中的tag id一致)
const fanucMappings = [
{ id: 1, standardField: 'program_name', fieldName: 'Tag5', matchBy: 'id', dataType: 'string', isRequired: 1 },
{ id: 2, standardField: 'part_count', fieldName: 'Tag8', matchBy: 'id', dataType: 'number', isRequired: 1 },
- { id: 3, standardField: 'device_status', fieldName: '_io_status', matchBy: 'id', dataType: 'number', isRequired: 1 },
- { id: 4, standardField: 'run_status', fieldName: 'Tag9', matchBy: 'id', dataType: 'number', isRequired: 0 },
- { id: 5, standardField: 'operate_mode', fieldName: 'Tag10', matchBy: 'id', dataType: 'number', isRequired: 0 },
- { id: 6, standardField: 'spindle_speed_set', fieldName: 'Tag11', matchBy: 'id', dataType: 'number', isRequired: 0 },
- { id: 7, standardField: 'feed_speed_set', fieldName: 'Tag12', matchBy: 'id', dataType: 'number', isRequired: 0 },
- { id: 8, standardField: 'spindle_speed_actual', fieldName: 'Tag13', matchBy: 'id', dataType: 'number', isRequired: 0 },
- { id: 9, standardField: 'feed_speed_actual', fieldName: 'Tag14', matchBy: 'id', dataType: 'number', isRequired: 0 },
- { id: 10, standardField: 'spindle_load', fieldName: 'Tag15', matchBy: 'id', dataType: 'number', isRequired: 0 },
- { id: 11, standardField: 'spindle_override', fieldName: 'Tag16', matchBy: 'id', dataType: 'number', isRequired: 0 },
- { id: 12, standardField: 'power_on_time', fieldName: 'Tag17', matchBy: 'id', dataType: 'number', isRequired: 0 },
- { id: 13, standardField: 'run_time', fieldName: 'Tag18', matchBy: 'id', dataType: 'number', isRequired: 0 },
- { id: 14, standardField: 'cutting_time', fieldName: 'Tag19', matchBy: 'id', dataType: 'number', isRequired: 0 },
- { id: 15, standardField: 'cycle_time', fieldName: 'Tag20', matchBy: 'id', dataType: 'number', isRequired: 0 },
- { id: 16, standardField: 'machining_status', fieldName: 'Tag21', matchBy: 'id', dataType: 'string', isRequired: 0 },
+ { id: 3, standardField: 'total_part_count', fieldName: 'Tag1', matchBy: 'id', dataType: 'number', isRequired: 0 },
+ { id: 4, standardField: 'device_status', fieldName: '_io_status', matchBy: 'id', dataType: 'number', isRequired: 1 },
+ { id: 5, standardField: 'run_status', fieldName: 'Tag9', matchBy: 'id', dataType: 'number', isRequired: 0 },
+ { id: 6, standardField: 'operate_mode', fieldName: 'Tag11', matchBy: 'id', dataType: 'number', isRequired: 0 },
+ { id: 7, standardField: 'power_on_time', fieldName: 'Tag22', matchBy: 'id', dataType: 'number', isRequired: 0 },
+ { id: 8, standardField: 'run_time', fieldName: 'Tag23', matchBy: 'id', dataType: 'number', isRequired: 0 },
]
const mock: MockMethod[] = [
diff --git a/frontend/mock/machine.ts b/frontend/mock/machine.ts
index d0afb7a..2c752f6 100644
--- a/frontend/mock/machine.ts
+++ b/frontend/mock/machine.ts
@@ -59,7 +59,7 @@ const mock: MockMethod[] = [
method: 'get',
response: () => ({
code: 0,
- data: { programName: '1566.NC', partCount: 580, runStatus: '运行中', operateMode: '自动', spindleSpeedSet: 3000, feedSpeedSet: 500, spindleSpeedActual: 2980, feedSpeedActual: 480, spindleLoad: 65, machiningStatus: 'G01', lastCollectTime: '2026-04-25T17:36:38' },
+ data: { programName: '1566.NC', partCount: 580, totalPartCount: 88624, runStatus: '运行中', operateMode: '自动', lastCollectTime: '2026-04-25T17:36:38' },
}),
},
{
@@ -68,7 +68,7 @@ const mock: MockMethod[] = [
method: 'get',
response: () => ({
code: 0,
- data: { programName: '1566.NC', partCount: 580, runStatus: '运行中', operateMode: '自动', spindleSpeedSet: 3000, feedSpeedSet: 500, spindleSpeedActual: 2980, feedSpeedActual: 480, spindleLoad: 65, machiningStatus: 'G01', lastCollectTime: '2026-04-25T17:36:38' },
+ data: { programName: '1566.NC', partCount: 580, totalPartCount: 88624, runStatus: '运行中', operateMode: '自动', lastCollectTime: '2026-04-25T17:36:38' },
}),
},
{
diff --git a/frontend/mock/simulator.ts b/frontend/mock/simulator.ts
index c513110..1f6d7a1 100644
--- a/frontend/mock/simulator.ts
+++ b/frontend/mock/simulator.ts
@@ -45,11 +45,11 @@ const mockStatusList = [
}
]
-// 模拟设备状态
+// 模拟设备状态(与实际FANUC 10个Tag结构一致)
const mockDevices = [
- { deviceCode: 'fanake_1.2', desc: '西-1.2', scenario: 'machining', isOnline: true, programName: 'O504', partCount: 14, runStatus: 3, operateMode: 10, spindleSpeedSet: 3000, spindleSpeedActual: 2980, feedSpeedSet: 500, feedSpeedActual: 490, spindleLoad: 65, machiningStatus: 'cutting', scenarioTick: 45, scenarioDuration: 120 },
- { deviceCode: 'fanake_1.3', desc: '西-1.3', scenario: 'idle', isOnline: true, programName: 'O1', partCount: 53, runStatus: 1, operateMode: 10, spindleSpeedSet: 0, spindleSpeedActual: 0, feedSpeedSet: 0, feedSpeedActual: 0, spindleLoad: 5, machiningStatus: 'idle', scenarioTick: 12, scenarioDuration: 60 },
- { deviceCode: 'fanake_1.4', desc: '西-1.4', scenario: 'offline', isOnline: false, programName: 'O200', partCount: 0, runStatus: 0, operateMode: 0, spindleSpeedSet: 0, spindleSpeedActual: 0, feedSpeedSet: 0, feedSpeedActual: 0, spindleLoad: 0, machiningStatus: 'offline', scenarioTick: 0, scenarioDuration: 0 }
+ { deviceCode: 'fanake_1.2', desc: '西-1.2', scenario: 'machining', isOnline: true, programName: 'O504', partCount: 14, totalPartCount: 45930, runStatus: 3, operateMode: 1, scenarioTick: 45, scenarioDuration: 120 },
+ { deviceCode: 'fanake_1.3', desc: '西-1.3', scenario: 'idle', isOnline: true, programName: 'O1', partCount: 53, totalPartCount: 62324, runStatus: 0, operateMode: 10, scenarioTick: 12, scenarioDuration: 60 },
+ { deviceCode: 'fanake_1.4', desc: '西-1.4', scenario: 'offline', isOnline: false, programName: '', partCount: 0, totalPartCount: 0, runStatus: 0, operateMode: 0, scenarioTick: 0, scenarioDuration: 0 }
]
// 模拟请求日志
diff --git a/frontend/src/api/simulator.ts b/frontend/src/api/simulator.ts
index 4448c9c..2decb12 100644
--- a/frontend/src/api/simulator.ts
+++ b/frontend/src/api/simulator.ts
@@ -40,14 +40,9 @@ export interface DeviceStatus {
isOnline: boolean
programName: string
partCount: number
+ totalPartCount: number
runStatus: number
operateMode: number
- spindleSpeedSet: number
- spindleSpeedActual: number
- feedSpeedSet: number
- feedSpeedActual: number
- spindleLoad: number
- machiningStatus: string
scenarioTick: number
scenarioDuration: number
}
diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts
index 7354950..33bbf61 100644
--- a/frontend/src/types/index.ts
+++ b/frontend/src/types/index.ts
@@ -53,18 +53,20 @@ export interface Machine {
export interface MachineStatus {
programName: string
partCount: number
+ /** 历史累计加工零件总数(FANUC Tag1) */
+ totalPartCount?: number
runStatus: string
operationMode: string
- /** 主轴设定转速 */
- spindleSpeedSet?: number
- /** 进给设定速度 */
- feedSpeedSet?: number
- /** 主轴实际转速 */
- spindleSpeedActual?: number
- spindleSpeed: number
- feedRate: number
- spindleLoad: number
- machiningStatus: string
+ /** 主轴设定转速(部分品牌无此数据时为null) */
+ spindleSpeedSet?: number | null
+ /** 进给设定速度(部分品牌无此数据时为null) */
+ feedSpeedSet?: number | null
+ /** 主轴实际转速(部分品牌无此数据时为null) */
+ spindleSpeedActual?: number | null
+ spindleSpeed?: number | null
+ feedRate?: number | null
+ spindleLoad?: number | null
+ machiningStatus?: string | null
lastCollectTime: string
}
diff --git a/frontend/src/views/machine/MachineDetailPage.vue b/frontend/src/views/machine/MachineDetailPage.vue
index e6373c0..11cafa2 100644
--- a/frontend/src/views/machine/MachineDetailPage.vue
+++ b/frontend/src/views/machine/MachineDetailPage.vue
@@ -27,12 +27,9 @@
{{status.programName||'-'}}
{{status.partCount??'-'}}
+ {{status.totalPartCount??'-'}}
{{status.runStatus||'-'}}
{{status.operationMode||'-'}}
- {{status.spindleSpeedSet??'-'}}
- {{status.feedSpeedSet??'-'}}
- {{status.spindleSpeedActual??'-'}}
- {{status.spindleLoad??'-'}}%
diff --git a/simulator.json b/simulator.json
index 914d815..ed8876b 100644
--- a/simulator.json
+++ b/simulator.json
@@ -8,9 +8,9 @@
"dataChangeInterval": 10,
"scenarioMode": "auto",
"devices": [
- { "deviceCode": "CNC-A001", "desc": "西栋1号", "initialProgram": "O0001", "initialPartCount": 50 },
- { "deviceCode": "CNC-006", "desc": "6号机床", "initialProgram": "O0002", "initialPartCount": 120 },
- { "deviceCode": "CNC-008", "desc": "8号机床", "initialProgram": "O0003", "initialPartCount": 0 }
+ { "deviceCode": "CNC-A001", "desc": "西栋1号", "initialProgram": "O0001", "initialPartCount": 50, "initialTotalPartCount": 45000 },
+ { "deviceCode": "CNC-006", "desc": "6号机床", "initialProgram": "O0002", "initialPartCount": 120, "initialTotalPartCount": 88000 },
+ { "deviceCode": "CNC-008", "desc": "8号机床", "initialProgram": "O0003", "initialPartCount": 0, "initialTotalPartCount": 126000 }
]
},
{
@@ -20,8 +20,8 @@
"dataChangeInterval": 15,
"scenarioMode": "auto",
"devices": [
- { "deviceCode": "CNC-B002", "desc": "B栋2号", "initialProgram": "1566.NC", "initialPartCount": 80 },
- { "deviceCode": "CNC-005", "desc": "验证机床", "initialProgram": "TEST001", "initialPartCount": 10 }
+ { "deviceCode": "CNC-B002", "desc": "B栋2号", "initialProgram": "1566.NC", "initialPartCount": 80, "initialTotalPartCount": 67000 },
+ { "deviceCode": "CNC-005", "desc": "验证机床", "initialProgram": "TEST001", "initialPartCount": 10, "initialTotalPartCount": 23000 }
]
}
]
diff --git a/src/CncCollector/Core/CollectRecordWriter.cs b/src/CncCollector/Core/CollectRecordWriter.cs
index bf18699..80ae98f 100644
--- a/src/CncCollector/Core/CollectRecordWriter.cs
+++ b/src/CncCollector/Core/CollectRecordWriter.cs
@@ -84,13 +84,11 @@ namespace CncCollector.Core
foreach (var r in records)
{
conn.Execute(@"INSERT INTO cnc_collect_record (machine_id, collect_time, device_time, program_name, part_count,
- device_status, run_status, operate_mode, spindle_speed_set, feed_speed_set,
- spindle_speed_actual, feed_speed_actual, spindle_load, spindle_override,
- power_on_time, run_time, cutting_time, cycle_time, machining_status, extra_data, created_at)
+ total_part_count, device_status, run_status, operate_mode,
+ power_on_time, run_time, extra_data, created_at)
VALUES (@MachineId, @CollectTime, @DeviceTime, @ProgramName, @PartCount,
- @DeviceStatus, @RunStatus, @OperateMode, @SpindleSpeedSet, @FeedSpeedSet,
- @SpindleSpeedActual, @FeedSpeedActual, @SpindleLoad, @SpindleOverride,
- @PowerOnTime, @RunTime, @CuttingTime, @CycleTime, @MachiningStatus, @ExtraData, @CreatedAt)",
+ @TotalPartCount, @DeviceStatus, @RunStatus, @OperateMode,
+ @PowerOnTime, @RunTime, @ExtraData, @CreatedAt)",
new
{
r.MachineId,
@@ -98,20 +96,12 @@ namespace CncCollector.Core
DeviceTime = r.DeviceTime,
ProgramName = r.ProgramName ?? (string)null,
PartCount = r.PartCount,
+ TotalPartCount = r.TotalPartCount,
DeviceStatus = r.DeviceStatus ?? (string)null,
RunStatus = r.RunStatus ?? (string)null,
OperateMode = r.OperateMode ?? (string)null,
- SpindleSpeedSet = r.SpindleSpeedSet,
- FeedSpeedSet = r.FeedSpeedSet,
- SpindleSpeedActual = r.SpindleSpeedActual,
- FeedSpeedActual = r.FeedSpeedActual,
- SpindleLoad = r.SpindleLoad,
- SpindleOverride = r.SpindleOverride,
PowerOnTime = r.PowerOnTime,
RunTime = r.RunTime,
- CuttingTime = r.CuttingTime,
- CycleTime = r.CycleTime,
- MachiningStatus = r.MachiningStatus ?? (string)null,
ExtraData = r.ExtraData ?? (string)null,
CreatedAt = now
}, tran);
@@ -133,7 +123,8 @@ namespace CncCollector.Core
conn.Execute(@"UPDATE cnc_machine SET last_collect_time = @CollectTime,
last_device_status = @DeviceStatus, last_run_status = @RunStatus,
last_program_name = @ProgramName, last_part_count = @PartCount,
- last_operate_mode = @OperateMode, last_machining_status = @MachiningStatus
+ last_total_part_count = @TotalPartCount,
+ last_operate_mode = @OperateMode
WHERE id = @MachineId",
new
{
@@ -143,8 +134,8 @@ namespace CncCollector.Core
RunStatus = r.RunStatus ?? (string)null,
ProgramName = r.ProgramName ?? (string)null,
r.PartCount,
- OperateMode = r.OperateMode ?? (string)null,
- MachiningStatus = r.MachiningStatus ?? (string)null
+ r.TotalPartCount,
+ OperateMode = r.OperateMode ?? (string)null
});
}
catch (Exception ex)
diff --git a/src/CncCollector/Core/CollectWorker.cs b/src/CncCollector/Core/CollectWorker.cs
index 17ad956..66748c6 100644
--- a/src/CncCollector/Core/CollectWorker.cs
+++ b/src/CncCollector/Core/CollectWorker.cs
@@ -447,32 +447,32 @@ namespace CncCollector.Core
// 解析字段
var parsed = DataParser.ParseDevice(deviceObj, brand, mappings);
- // 构建 CollectRecord
+ // 构建 CollectRecord(仅包含实际FANUC数据中存在的字段)
var record = new CollectRecord
{
MachineId = machine.Id,
CollectTime = collectTime,
ProgramName = GetStringValue(parsed, "program_name"),
PartCount = GetDecimalValue(parsed, "part_count"),
+ TotalPartCount = GetDecimalValue(parsed, "total_part_count"),
DeviceStatus = GetStringValue(parsed, "device_status"),
RunStatus = GetStringValue(parsed, "run_status"),
OperateMode = GetStringValue(parsed, "operate_mode"),
- SpindleSpeedSet = GetDecimalValue(parsed, "spindle_speed_set"),
- FeedSpeedSet = GetDecimalValue(parsed, "feed_speed_set"),
- SpindleSpeedActual = GetDecimalValue(parsed, "spindle_speed_actual"),
- FeedSpeedActual = GetDecimalValue(parsed, "feed_speed_actual"),
- SpindleLoad = GetDecimalValue(parsed, "spindle_load"),
- SpindleOverride = GetDecimalValue(parsed, "spindle_override"),
PowerOnTime = GetDecimalValue(parsed, "power_on_time"),
- RunTime = GetDecimalValue(parsed, "run_time"),
- CuttingTime = GetDecimalValue(parsed, "cutting_time"),
- CycleTime = GetDecimalValue(parsed, "cycle_time"),
- MachiningStatus = GetStringValue(parsed, "machining_status")
+ RunTime = GetDecimalValue(parsed, "run_time")
};
+ // 断电设备过滤:如果program_name和part_count都被过滤为空,
+ // 说明设备处于断电状态(quality≠0),跳过此设备不生成记录
+ if (string.IsNullOrEmpty(record.ProgramName) && !record.PartCount.HasValue)
+ {
+ _log.Debug($"设备{deviceCode}所有有效tag为空(可能断电),跳过记录");
+ continue;
+ }
+
records.Add(record);
- // 产量跟踪
+ // 产量跟踪(program_name为空时不触发分段逻辑)
_tracker.Track(machine.Id, record.ProgramName, record.PartCount, collectTime);
}
diff --git a/src/CncCollector/Core/DataParser.cs b/src/CncCollector/Core/DataParser.cs
index 7dcae5b..aa0f68a 100644
--- a/src/CncCollector/Core/DataParser.cs
+++ b/src/CncCollector/Core/DataParser.cs
@@ -33,7 +33,9 @@ namespace CncCollector.Core
}
///
- /// 解析单台设备的 JSON tags 数据
+ /// 解析单台设备的 JSON tags 数据。
+ /// 根据数据有效性规则过滤无效tag:quality≠0 或 time以1970-01-01开头的tag视为无效。
+ /// _io_status 始终有效,不受quality/time约束。
///
/// 设备 JSON 对象
/// 品牌配置
@@ -57,16 +59,35 @@ namespace CncCollector.Core
var tagsArray = tagsToken as JArray;
- // 构建 tag id → value 的快速查找字典
+ // 构建 tag id → rawValue 的快速查找字典(经过有效性过滤)
var tagDict = new Dictionary(StringComparer.OrdinalIgnoreCase);
foreach (var tag in tagsArray)
{
string id = tag["id"]?.ToString() ?? "";
- string value = tag["value"]?.ToString() ?? "";
- if (!string.IsNullOrEmpty(id))
+ if (string.IsNullOrEmpty(id)) continue;
+
+ // _io_status 始终有效,跳过过滤
+ if (string.Equals(id, "_io_status", StringComparison.OrdinalIgnoreCase))
+ {
+ tagDict[id] = tag["value"]?.ToString() ?? "";
+ continue;
+ }
+
+ // 数据有效性规则1:quality ≠ 0 → 无效,忽略
+ string qualityStr = tag["quality"]?.ToString() ?? "0";
+ if (qualityStr != "0")
{
- tagDict[id] = value;
+ continue;
}
+
+ // 数据有效性规则2:time 以 1970-01-01 开头 → 采集失败标记,忽略
+ string timeStr = tag["time"]?.ToString() ?? "";
+ if (timeStr.StartsWith("1970-01-01", StringComparison.OrdinalIgnoreCase))
+ {
+ continue;
+ }
+
+ tagDict[id] = tag["value"]?.ToString() ?? "";
}
// 按字段映射表提取
@@ -79,7 +100,7 @@ namespace CncCollector.Core
string rawValue;
if (!tagDict.TryGetValue(tagId, out rawValue))
{
- // 字段不存在,跳过(非必填字段可能不存在)
+ // 字段不存在或被过滤为无效,跳过
continue;
}
@@ -90,10 +111,9 @@ namespace CncCollector.Core
StringValue = rawValue
};
- // 数值型:去除 .00000 尾缀
+ // 数值型:解析为 decimal
if (dataType == "number" && !string.IsNullOrEmpty(rawValue))
{
- // 尝试解析为 decimal
string cleanValue = rawValue.Trim();
decimal numVal;
if (decimal.TryParse(cleanValue, System.Globalization.NumberStyles.Float,
diff --git a/src/CncModels/Entity/CollectRecord.cs b/src/CncModels/Entity/CollectRecord.cs
index 430299b..fbba2bf 100644
--- a/src/CncModels/Entity/CollectRecord.cs
+++ b/src/CncModels/Entity/CollectRecord.cs
@@ -25,6 +25,9 @@ namespace CncModels.Entity
/// 零件计数
public decimal? PartCount { get; set; }
+ /// 历史终身累计零件总数(Tag1)
+ public decimal? TotalPartCount { get; set; }
+
/// 设备状态
public string DeviceStatus { get; set; }
diff --git a/src/CncSimulator/Config/SimulatorConfig.cs b/src/CncSimulator/Config/SimulatorConfig.cs
index 36b3549..f7276c2 100644
--- a/src/CncSimulator/Config/SimulatorConfig.cs
+++ b/src/CncSimulator/Config/SimulatorConfig.cs
@@ -73,5 +73,9 @@ namespace CncSimulator.Config
/// 初始零件数
[JsonProperty("initialPartCount")]
public int InitialPartCount { get; set; } = 0;
+
+ /// 初始历史累计零件总数
+ [JsonProperty("initialTotalPartCount")]
+ public int InitialTotalPartCount { get; set; } = 0;
}
}
diff --git a/src/CncSimulator/Core/SimulatorEngine.cs b/src/CncSimulator/Core/SimulatorEngine.cs
index 11b3194..ae66166 100644
--- a/src/CncSimulator/Core/SimulatorEngine.cs
+++ b/src/CncSimulator/Core/SimulatorEngine.cs
@@ -326,6 +326,67 @@ namespace CncSimulator.Core
_dbAddresses = _dbReader.ReadAddresses();
SendResponse(ctx, 200, "{\"ok\":true,\"count\":" + _dbAddresses.Count + "}", "application/json");
}
+ else if (path == "/admin/api/event")
+ {
+ // 转发事件到对应的SimulatorServer(数据端口)
+ string eventBody = ReadRequestBody(ctx);
+ var eventObj = JObject.Parse(eventBody);
+ string deviceId = eventObj["deviceId"]?.ToString();
+ string eventType = eventObj["eventType"]?.ToString();
+ if (string.IsNullOrEmpty(deviceId) || string.IsNullOrEmpty(eventType))
+ {
+ SendResponse(ctx, 400, "{\"error\":\"缺少deviceId或eventType\"}", "application/json");
+ return;
+ }
+ // 在所有server中查找目标设备并触发事件
+ bool found = false;
+ foreach (var server in _servers)
+ {
+ server.TriggerDeviceEvent(deviceId, eventType);
+ found = true;
+ break; // TriggerDeviceEvent内部只处理第一个匹配的设备
+ }
+ SendResponse(ctx, 200, found ? "{\"ok\":true}" : "{\"ok\":false,\"error\":\"设备未找到\"}", "application/json");
+ }
+ else if (path == "/admin/api/event-history")
+ {
+ // 转发事件历史查询
+ var allEvents = new JArray();
+ foreach (var server in _servers)
+ {
+ // 利用server的HandleEventHistoryApi逻辑提取数据
+ foreach (var dev in server.Devices)
+ {
+ foreach (var evt in dev.State.EventHistory)
+ {
+ allEvents.Add(new JObject
+ {
+ ["timestamp"] = evt.Timestamp.ToString("yyyy-MM-dd HH:mm:ss"),
+ ["deviceCode"] = evt.DeviceCode,
+ ["eventType"] = evt.EventType,
+ ["oldProgram"] = evt.OldProgram,
+ ["newProgram"] = evt.NewProgram,
+ ["partCountBefore"] = evt.PartCountBefore,
+ ["partCountAfter"] = evt.PartCountAfter,
+ ["detail"] = evt.Detail
+ });
+ }
+ }
+ }
+ SendResponse(ctx, 200, allEvents.ToString(), "application/json");
+ }
+ else if (path == "/admin/api/mode")
+ {
+ // 转发模式切换到所有SimulatorServer
+ string modeBody = ReadRequestBody(ctx);
+ var modeObj = JObject.Parse(modeBody);
+ string mode = modeObj["mode"]?.ToString() ?? "auto";
+ foreach (var server in _servers)
+ {
+ server.SetMode(mode);
+ }
+ SendResponse(ctx, 200, "{\"ok\":true,\"mode\":\"" + mode + "\"}", "application/json");
+ }
else
{
SendResponse(ctx, 200, "CNC模拟采集服务网关。请访问 /admin 管理页面。", "text/plain");
diff --git a/src/CncSimulator/Core/SimulatorServer.cs b/src/CncSimulator/Core/SimulatorServer.cs
index c41695e..0b7f9b2 100644
--- a/src/CncSimulator/Core/SimulatorServer.cs
+++ b/src/CncSimulator/Core/SimulatorServer.cs
@@ -285,14 +285,9 @@ namespace CncSimulator.Core
["isOnline"] = s.IsOnline,
["programName"] = s.ProgramName,
["partCount"] = s.PartCount,
+ ["totalPartCount"] = s.TotalPartCount,
["runStatus"] = s.RunStatus,
["operateMode"] = s.OperateMode,
- ["spindleSpeedSet"] = s.SpindleSpeedSet,
- ["spindleSpeedActual"] = s.SpindleSpeedActual,
- ["feedSpeedSet"] = s.FeedSpeedSet,
- ["feedSpeedActual"] = s.FeedSpeedActual,
- ["spindleLoad"] = s.SpindleLoad,
- ["machiningStatus"] = s.MachiningStatus,
["scenarioTick"] = s.ScenarioTick,
["scenarioDuration"] = s.ScenarioDuration
});
@@ -318,7 +313,7 @@ namespace CncSimulator.Core
}
}
- /// 生成当前JSON响应
+ /// 生成当前JSON响应(包括在线和离线设备)
private string GenerateCurrentJson()
{
var devices = new JArray();
@@ -328,10 +323,66 @@ namespace CncSimulator.Core
{
devices.Add(_generator.GenerateDevice(dev.State));
}
+ else
+ {
+ // 离线设备:生成带有quality=1和1970时间的tag
+ devices.Add(GenerateOfflineDevice(dev.State));
+ }
}
return devices.ToString(Formatting.None);
}
+ /// 生成离线设备的JSON(_io_status有效,其余tag quality=1)
+ private JObject GenerateOfflineDevice(DeviceState state)
+ {
+ var tags = new JArray();
+ DateTime now = DateTime.Now;
+
+ // _io_status 始终有效
+ tags.Add(new JObject
+ {
+ ["id"] = "_io_status",
+ ["desc"] = "设备状态",
+ ["quality"] = "0",
+ ["value"] = "0.00000",
+ ["time"] = now.ToString("yyyy-MM-dd HH:mm:ss")
+ });
+
+ // 其余tag全部标记为无效(quality=1, time=1970)
+ string epoch = "1970-01-01 08:00:00";
+ var offlineTags = new[]
+ {
+ new { id = "Tag1", desc = "加工零件总数", value = "0.00000" },
+ new { id = "Tag5", desc = "执行的NC主程序名", value = "" },
+ new { id = "Tag6", desc = "执行的NC主程序号", value = "" },
+ new { id = "Tag7", desc = "当前加工程序内容", value = "" },
+ new { id = "Tag8", desc = "当前加工零件数", value = "0.00000" },
+ new { id = "Tag9", desc = "运行状态", value = "0.00000" },
+ new { id = "Tag11", desc = "操作模式", value = "0.00000" },
+ new { id = "Tag22", desc = "开机时间", value = "0.00000" },
+ new { id = "Tag23", desc = "运行时间", value = "0.00000" }
+ };
+
+ foreach (var t in offlineTags)
+ {
+ tags.Add(new JObject
+ {
+ ["id"] = t.id,
+ ["desc"] = t.desc,
+ ["quality"] = "1",
+ ["value"] = t.value,
+ ["time"] = epoch
+ });
+ }
+
+ return new JObject
+ {
+ ["device"] = state.DeviceCode,
+ ["desc"] = state.Desc,
+ ["tags"] = tags
+ };
+ }
+
/// 生成关键数据摘要
private string GenerateKeyData()
{
diff --git a/src/CncSimulator/Device/DeviceSimulator.cs b/src/CncSimulator/Device/DeviceSimulator.cs
index 0672f26..6d8a9e8 100644
--- a/src/CncSimulator/Device/DeviceSimulator.cs
+++ b/src/CncSimulator/Device/DeviceSimulator.cs
@@ -4,13 +4,13 @@ namespace CncSimulator.Device
{
///
/// 单台设备的状态机。
- /// 维护设备当前状态,根据场景规则更新各字段。
+ /// 维护设备当前状态,根据场景规则更新字段。
+ /// 仅包含实际FANUC采集数据中存在的字段。
///
public class DeviceSimulator
{
private readonly DeviceState _state;
private readonly Random _rng;
- private static readonly string[] MachiningStatusOptions = { "G01", "G01", "G01", "G02", "G00" };
private static readonly string[] ProgramPool = { "O0001", "O0002", "1566.NC", "PART-A", "TEST-03" };
private int _programPoolIndex;
@@ -26,23 +26,17 @@ namespace CncSimulator.Device
Desc = config.Desc,
ProgramName = config.InitialProgram,
PartCount = config.InitialPartCount,
- // LastPartCount removed - not in DeviceState
+ // 历史累计零件总数:配置值优先,否则随机
+ TotalPartCount = config.InitialTotalPartCount > 0
+ ? config.InitialTotalPartCount
+ : _rng.Next(40000, 50000),
DataChangeInterval = dataChangeInterval,
IsOnline = true,
DeviceStatus = 1,
RunStatus = 0,
OperateMode = 10,
- SpindleSpeedSet = 450,
- FeedSpeedSet = 60,
- SpindleSpeedActual = 0,
- FeedSpeedActual = 0,
- SpindleLoad = 0,
- SpindleOverride = 100,
PowerOnTime = _rng.Next(20000000, 24000000),
RunTime = _rng.Next(15000, 20000),
- CuttingTime = _rng.Next(6000000, 7000000),
- CycleTime = _rng.Next(500, 800),
- MachiningStatus = "",
ProgramContent = "",
CurrentScenario = "idle",
ScenarioTick = 0,
@@ -117,6 +111,7 @@ namespace CncSimulator.Device
{
case "machining":
_state.PartCount++;
+ _state.TotalPartCount++;
_state.TotalPartsSinceStart++;
// 按NC程序名累计零件数
if (!_state.PartsByProgram.ContainsKey(_state.ProgramName))
@@ -125,16 +120,8 @@ namespace CncSimulator.Device
_state.RunStatus = 3;
_state.DeviceStatus = 1;
_state.OperateMode = 1;
- // 主轴实际速度 = 设定 ± 10%随机波动
- _state.SpindleSpeedActual = _state.SpindleSpeedSet * (1m + (decimal)(_rng.NextDouble() * 0.2 - 0.1));
- _state.FeedSpeedActual = _state.FeedSpeedSet * (1m + (decimal)(_rng.NextDouble() * 0.1 - 0.05));
- _state.SpindleLoad = _rng.Next(15, 46);
- _state.SpindleOverride = 100;
- _state.MachiningStatus = MachiningStatusOptions[_rng.Next(MachiningStatusOptions.Length)];
- _state.CuttingTime += interval;
_state.RunTime += interval;
_state.PowerOnTime += interval;
- _state.CycleTime += interval;
_state.ProgramContent = "<" + _state.ProgramName + ">\nG40G49G80\n( SIMULATOR )";
break;
@@ -147,21 +134,12 @@ namespace CncSimulator.Device
case "idle":
_state.RunStatus = 0;
_state.OperateMode = 10;
- _state.SpindleSpeedActual = 0;
- _state.FeedSpeedActual = 0;
- _state.SpindleLoad = 0;
- _state.FeedSpeedSet = 0;
- _state.MachiningStatus = "";
_state.PowerOnTime += interval;
_state.RunTime += interval;
break;
case "pause":
_state.RunStatus = 1;
- _state.SpindleSpeedActual = 0;
- _state.FeedSpeedActual = 0;
- _state.SpindleLoad = 0;
- _state.MachiningStatus = "";
_state.PowerOnTime += interval;
_state.RunTime += interval;
break;
@@ -182,15 +160,11 @@ namespace CncSimulator.Device
_programPoolIndex = (_programPoolIndex + 1) % ProgramPool.Length;
_state.ProgramName = ProgramPool[_programPoolIndex];
_state.PartCount = 0;
- _state.CycleTime = 0;
_state.RunStatus = 3;
_state.DeviceStatus = 1;
_state.OperateMode = 1;
- _state.MachiningStatus = "G01";
- _state.SpindleSpeedSet = _rng.Next(200, 801);
- _state.FeedSpeedSet = _rng.Next(30, 151);
- _state.SpindleOverride = 100;
_state.ProgramContent = "<" + _state.ProgramName + ">\nG40G49G80\n( SIMULATOR )";
+ // TotalPartCount不清零(终身累计)
// 记录事件历史
_state.RecordEvent("program_change", oldProgram, _state.ProgramName, oldPartCount, 0);
}
@@ -202,6 +176,7 @@ namespace CncSimulator.Device
_state.PartCount = 0;
_state.RunStatus = 3;
_state.DeviceStatus = 1;
+ // TotalPartCount不清零(终身累计)
// 记录事件历史
_state.RecordEvent("manual_reset", _state.ProgramName, _state.ProgramName, oldPartCount, 0);
}
@@ -222,13 +197,9 @@ namespace CncSimulator.Device
_state.IsOnline = true;
_state.DeviceStatus = 1;
_state.PartCount = 0;
- _state.CycleTime = 0;
_state.RunStatus = 0;
_state.OperateMode = 10;
- _state.SpindleSpeedActual = 0;
- _state.FeedSpeedActual = 0;
- _state.SpindleLoad = 0;
- _state.MachiningStatus = "";
+ // TotalPartCount不清零(终身累计)
// 记录事件历史
_state.RecordEvent("power_on", _state.ProgramName, _state.ProgramName, oldPartCount, 0, "设备开机,零件数清零");
}
diff --git a/src/CncSimulator/Device/DeviceState.cs b/src/CncSimulator/Device/DeviceState.cs
index 52ede52..57d9a2c 100644
--- a/src/CncSimulator/Device/DeviceState.cs
+++ b/src/CncSimulator/Device/DeviceState.cs
@@ -26,6 +26,9 @@ namespace CncSimulator.Device
/// 当前零件数
public int PartCount { get; set; } = 0;
+ /// 历史终身累计零件总数(对应Tag1)
+ public decimal TotalPartCount { get; set; } = 0;
+
/// 设备状态 _io_status: 0=离线, 1=在线
public int DeviceStatus { get; set; } = 1;
@@ -35,39 +38,12 @@ namespace CncSimulator.Device
/// 操作模式: 1=MEM, 10=JOG
public int OperateMode { get; set; } = 1;
- /// 主轴设定速度
- public decimal SpindleSpeedSet { get; set; } = 450;
-
- /// 进给设定速度
- public decimal FeedSpeedSet { get; set; } = 60;
-
- /// 主轴实际速度
- public decimal SpindleSpeedActual { get; set; } = 0;
-
- /// 进给实际速度
- public decimal FeedSpeedActual { get; set; } = 0;
-
- /// 主轴负载
- public decimal SpindleLoad { get; set; } = 0;
-
- /// 主轴倍率
- public decimal SpindleOverride { get; set; } = 100;
-
/// 开机累计时间(秒)
public decimal PowerOnTime { get; set; } = 0;
/// 运行累计时间(秒)
public decimal RunTime { get; set; } = 0;
- /// 切削累计时间(秒)
- public decimal CuttingTime { get; set; } = 0;
-
- /// 循环时间(秒)
- public decimal CycleTime { get; set; } = 0;
-
- /// 加工状态: G01/G00/G02/等
- public string MachiningStatus { get; set; } = "";
-
/// 加工程序内容片段
public string ProgramContent { get; set; } = "";
diff --git a/src/CncSimulator/Generator/FanucDataGenerator.cs b/src/CncSimulator/Generator/FanucDataGenerator.cs
index 7fc04ca..57f2b33 100644
--- a/src/CncSimulator/Generator/FanucDataGenerator.cs
+++ b/src/CncSimulator/Generator/FanucDataGenerator.cs
@@ -6,7 +6,7 @@ namespace CncSimulator.Generator
{
///
/// FANUC品牌JSON数据生成器。
- /// 根据设备状态生成18个Tag的FANUC格式JSON。
+ /// 根据设备状态生成10个Tag的FANUC格式JSON,与实际FANUC采集数据结构一致。
///
public class FanucDataGenerator : IBrandGenerator
{
@@ -27,7 +27,7 @@ namespace CncSimulator.Generator
return device;
}
- /// 生成18个Tag的JArray
+ /// 生成10个Tag的JArray
private JArray GenerateTags(DeviceState state)
{
var tags = new JArray();
@@ -65,8 +65,9 @@ namespace CncSimulator.Generator
});
}
+ // 严格按实际FANUC采集数据的10个Tag生成
AddNumericTag("_io_status", "设备状态", state.DeviceStatus);
- AddNumericTag("Tag2", "当前轴数", 4);
+ AddNumericTag("Tag1", "加工零件总数", state.TotalPartCount);
AddStringTag("Tag5", "执行的NC主程序名", state.ProgramName);
AddStringTag("Tag6", "执行的NC主程序号", "N0");
AddStringTag("Tag7", "当前加工程序内容",
@@ -76,17 +77,8 @@ namespace CncSimulator.Generator
AddNumericTag("Tag8", "当前加工零件数", state.PartCount);
AddNumericTag("Tag9", "运行状态", state.RunStatus);
AddNumericTag("Tag11", "操作模式", state.OperateMode);
- AddNumericTag("Tag14", "当前主轴倍率", state.SpindleOverride);
- AddNumericTag("Tag17", "主轴设定速度", state.SpindleSpeedSet);
- AddNumericTag("Tag18", "进给设定速度", state.FeedSpeedSet);
- AddNumericTag("Tag19", "主轴实际速度", state.SpindleSpeedActual);
- AddNumericTag("Tag20", "进给实际转速", state.FeedSpeedActual);
- AddNumericTag("Tag21", "主轴负载", state.SpindleLoad);
AddNumericTag("Tag22", "开机时间", state.PowerOnTime);
AddNumericTag("Tag23", "运行时间", state.RunTime);
- AddNumericTag("Tag24", "切削时间", state.CuttingTime);
- AddNumericTag("Tag25", "循环时间", state.CycleTime);
- AddStringTag("Tag26", "加工状态", state.MachiningStatus);
return tags;
}
diff --git a/src/CncWebApi/Global.asax.cs b/src/CncWebApi/Global.asax.cs
index fe60f5c..64abcad 100644
--- a/src/CncWebApi/Global.asax.cs
+++ b/src/CncWebApi/Global.asax.cs
@@ -18,12 +18,8 @@ namespace CncWebApi
///
protected void Application_Start()
{
- // 初始化 log4net
- var logConfig = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "log4net.config");
- if (File.Exists(logConfig))
- {
- log4net.Config.XmlConfigurator.Configure(new FileInfo(logConfig));
- }
+ // 初始化 log4net(从 Web.config 的 节读取)
+ log4net.Config.XmlConfigurator.Configure();
GlobalConfiguration.Configure(WebApiConfig.Register);
}
diff --git a/src/CncWebApi/Web.config b/src/CncWebApi/Web.config
index 5f7333d..bd7b4c8 100644
--- a/src/CncWebApi/Web.config
+++ b/src/CncWebApi/Web.config
@@ -4,6 +4,40 @@
部署到 IIS 时,需要将此文件复制到站点根目录
-->
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\nG40G49G80\n( NAME: Administrator )\n( M","time":"2026-05-06 15:06:46"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"5.00000","time":"2026-05-06 15:07:14"},{"id":"Tag9","desc":"״̬","quality":"0","value":"1.00000","time":"2026-05-06 15:04:00"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"4.00000","time":"2026-05-06 15:04:00"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"26481840.00000","time":"2026-05-06 15:04:27"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"16611.00000","time":"2026-05-06 15:04:55"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"12225.00000","time":"2026-05-06 15:05:23"}]},{"device":"fanake_1.7","desc":"-1.7","tags":[{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O1","time":"2026-05-06 15:05:51"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N20","time":"2026-05-06 15:06:19"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"X-7.450 \nX-5.850 \nZ6.900 \nG00 Z42.000 \nY7.000 \n","time":"2026-05-06 15:06:46"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"12.00000","time":"2026-05-06 15:07:14"},{"id":"Tag9","desc":"״̬","quality":"0","value":"3.00000","time":"2026-05-06 15:04:00"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-06 15:04:00"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"29563620.00000","time":"2026-05-06 15:04:27"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"14635.00000","time":"2026-05-06 15:04:55"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"18112.00000","time":"2026-05-06 15:05:23"}]},{"device":"fanake_1.9","desc":"-1.9","tags":[{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O1","time":"2026-05-06 15:05:51"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N20","time":"2026-05-06 15:06:19"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"M1 \nG90A90.\nX-105.Y-48.303\nG43Z41.738H01\nM10\nZ2","time":"2026-05-06 15:06:47"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"18.00000","time":"2026-05-06 15:07:14"},{"id":"Tag9","desc":"״̬","quality":"0","value":"0.00000","time":"2026-05-06 15:04:00"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"5.00000","time":"2026-05-06 15:04:00"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"24744120.00000","time":"2026-05-06 15:04:28"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"1121.00000","time":"2026-05-06 15:04:55"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"16472.00000","time":"2026-05-06 15:05:24"}]},{"device":"fanake_1.10","desc":"-1.10","tags":[{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O88","time":"2026-05-06 15:05:51"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N380","time":"2026-05-06 15:06:19"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"G01 X-115.000 \nG02 X-130.100 Y-127.500 I0.000 J","time":"2026-05-06 15:06:47"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"1789.00000","time":"2026-05-06 15:07:14"},{"id":"Tag9","desc":"״̬","quality":"0","value":"3.00000","time":"2026-05-06 15:04:00"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-06 15:04:00"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"83095080.00000","time":"2026-05-06 15:04:28"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"953670.00000","time":"2026-05-06 15:04:56"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"61675.00000","time":"2026-05-06 15:05:24"}]},{"device":"fanake_1.11","desc":"-1.11","tags":[{"id":"Tag5","desc":"ִеNC","quality":"0","value":"","time":"2026-05-06 15:05:52"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N170","time":"2026-05-06 15:06:19"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"N178 Y-132.000 F1000. \nN180 X-131.500 \nN182 Y35","time":"2026-05-06 15:06:47"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"1153.00000","time":"2026-05-06 15:07:14"},{"id":"Tag9","desc":"״̬","quality":"0","value":"3.00000","time":"2026-05-06 15:04:00"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-06 15:04:00"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"81371460.00000","time":"2026-05-06 15:04:28"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"1784670.00000","time":"2026-05-06 15:04:56"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"51653.00000","time":"2026-05-06 15:05:24"}]},{"device":"fanake_1.12","desc":"-1.12","tags":[{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O2","time":"2026-05-06 15:05:52"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N0","time":"2026-05-06 15:06:19"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":".189%","time":"2026-05-06 15:06:47"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"1162.00000","time":"2026-05-06 15:07:15"},{"id":"Tag9","desc":"״̬","quality":"0","value":"0.00000","time":"2026-05-06 15:04:00"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-06 15:04:00"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"57159300.00000","time":"2026-05-06 15:04:28"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"2611091.00000","time":"2026-05-06 15:04:56"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"52058.00000","time":"2026-05-06 15:05:24"}]},{"device":"fanake_1.13","desc":"-1.13","tags":[{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O1","time":"2026-05-06 15:05:52"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N20","time":"2026-05-06 15:06:19"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"G91 G28 Y0.000 \nM30\n%","time":"2026-05-06 15:06:47"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"150.00000","time":"2026-05-06 15:07:15"},{"id":"Tag9","desc":"״̬","quality":"0","value":"0.00000","time":"2026-05-06 15:04:00"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-06 15:04:00"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"60468480.00000","time":"2026-05-06 15:04:28"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"52678.00000","time":"2026-05-06 15:04:56"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"58791.00000","time":"2026-05-06 15:05:24"}]},{"device":"fanake_1.14","desc":"-1.14","tags":[{"id":"Tag5","desc":"ִеNC","quality":"0","value":"","time":"2026-05-06 15:05:52"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N0","time":"2026-05-06 15:06:20"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"","time":"2026-05-06 15:06:47"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"173.00000","time":"2026-05-06 15:07:15"},{"id":"Tag9","desc":"״̬","quality":"0","value":"0.00000","time":"2026-05-06 15:04:00"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-06 15:04:00"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"63446160.00000","time":"2026-05-06 15:04:28"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"55461.00000","time":"2026-05-06 15:04:56"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"69633.00000","time":"2026-05-06 15:05:24"}]},{"device":"fanake_1.15","desc":"-1.15","tags":[{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O506","time":"2026-05-06 15:05:52"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N20","time":"2026-05-06 15:06:20"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"G01 X20.775 \nY-8.284 \nX4.800 \nY8.284 \nX36.750 \n","time":"2026-05-06 15:06:47"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"4.00000","time":"2026-05-06 15:07:15"},{"id":"Tag9","desc":"״̬","quality":"0","value":"3.00000","time":"2026-05-06 15:04:01"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-06 15:04:01"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"54781260.00000","time":"2026-05-06 15:04:28"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"6403.00000","time":"2026-05-06 15:04:56"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"32442.00000","time":"2026-05-06 15:05:24"}]},{"device":"fanake_1.16","desc":"-1.16","tags":[{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O1","time":"2026-05-06 15:05:52"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N20","time":"2026-05-06 15:06:20"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"G02 X-60.570 Y47.947 I-0.989 J4.973 \nG01 X-60.6","time":"2026-05-06 15:06:47"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"103.00000","time":"2026-05-06 15:07:15"},{"id":"Tag9","desc":"״̬","quality":"0","value":"3.00000","time":"2026-05-06 15:04:01"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-06 15:04:01"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"56446080.00000","time":"2026-05-06 15:04:28"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"71194.00000","time":"2026-05-06 15:04:56"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"43958.00000","time":"2026-05-06 15:05:24"}]},{"device":"fanake_1.17","desc":"-1.17","tags":[{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O1","time":"2026-05-06 15:05:52"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N20","time":"2026-05-06 15:06:20"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"Y-12.865 \nY-12.269 \nY-11.673 \nY-11.077 \nY-10.48","time":"2026-05-06 15:06:47"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"193.00000","time":"2026-05-06 15:07:15"},{"id":"Tag9","desc":"״̬","quality":"0","value":"3.00000","time":"2026-05-06 15:04:01"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-06 15:04:01"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"53566620.00000","time":"2026-05-06 15:04:29"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"78701.00000","time":"2026-05-06 15:04:57"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"25609.00000","time":"2026-05-06 15:05:25"}]},{"device":"fanake_1.18","desc":"-1.18","tags":[{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O2","time":"2026-05-06 15:05:52"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N20","time":"2026-05-06 15:06:20"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"X-187.885 Y-28.629 \nG02 X-192.115 I-2.115 J3.66","time":"2026-05-06 15:06:48"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"0.00000","time":"2026-05-06 15:07:15"},{"id":"Tag9","desc":"״̬","quality":"0","value":"3.00000","time":"2026-05-06 15:04:01"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-06 15:04:01"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"86160480.00000","time":"2026-05-06 15:04:29"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"0.00000","time":"2026-05-06 15:04:57"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"113856.00000","time":"2026-05-06 15:05:25"}]},{"device":"fanake_1.19","desc":"-1.19","tags":[{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O1","time":"2026-05-06 15:05:53"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N9","time":"2026-05-06 15:06:20"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"Z-4.500 \nG00 Z33.000 \nG90 X-90.641 Y-28.053 \nZ-","time":"2026-05-06 15:06:48"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"0.00000","time":"2026-05-06 15:07:15"},{"id":"Tag9","desc":"״̬","quality":"0","value":"3.00000","time":"2026-05-06 15:04:01"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-06 15:04:01"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"136464540.00000","time":"2026-05-06 15:04:29"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"68.00000","time":"2026-05-06 15:04:57"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"144029.00000","time":"2026-05-06 15:05:25"}]},{"device":"fanake_1.20","desc":"-1.20","tags":[{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O1","time":"2026-05-06 15:05:53"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N9","time":"2026-05-06 15:06:20"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"G01 X-2.200 Y14.549 \nX-4.200 Y18.013 \nX-2.100 Y","time":"2026-05-06 15:06:48"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"0.00000","time":"2026-05-06 15:07:15"},{"id":"Tag9","desc":"״̬","quality":"0","value":"0.00000","time":"2026-05-06 15:04:01"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-06 15:04:01"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"141877620.00000","time":"2026-05-06 15:04:29"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"0.00000","time":"2026-05-06 15:04:57"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"139788.00000","time":"2026-05-06 15:05:25"}]},{"device":"fanake_1.21","desc":"-1.21","tags":[{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O1","time":"2026-05-06 15:05:53"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N9","time":"2026-05-06 15:06:20"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"G02 X-114.170 I2.830 J-4.902 \nG01 X-108.900 Y27","time":"2026-05-06 15:06:48"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"0.00000","time":"2026-05-06 15:07:16"},{"id":"Tag9","desc":"״̬","quality":"0","value":"3.00000","time":"2026-05-06 15:04:01"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-06 15:04:01"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"140563920.00000","time":"2026-05-06 15:04:29"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"639.00000","time":"2026-05-06 15:04:57"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"127265.00000","time":"2026-05-06 15:05:25"}]},{"device":"fanake_1.22","desc":"-1.22","tags":[{"id":"Tag5","desc":"ִеNC","quality":"0","value":"1027","time":"2026-05-06 15:05:53"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N9","time":"2026-05-06 15:06:20"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"","time":"2026-05-06 15:06:48"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"24.00000","time":"2026-05-06 15:07:16"},{"id":"Tag9","desc":"״̬","quality":"0","value":"0.00000","time":"2026-05-06 15:04:01"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-06 15:04:01"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"130547880.00000","time":"2026-05-06 15:04:29"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"7936.00000","time":"2026-05-06 15:04:57"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"161742.00000","time":"2026-05-06 15:05:25"}]},{"device":"fanake_1.23","desc":"-1.23","tags":[{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O2","time":"2026-05-06 15:05:53"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N0","time":"2026-05-06 15:06:21"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"G01 X-235. M8 F39. \nG00 Z200.000 M9 \nM5 \nG28 Y0","time":"2026-05-06 15:06:48"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"38.00000","time":"2026-05-06 15:07:16"},{"id":"Tag9","desc":"״̬","quality":"0","value":"0.00000","time":"2026-05-06 15:04:02"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"1.00000","time":"2026-05-06 15:04:02"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"124760580.00000","time":"2026-05-06 15:04:29"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"14200.00000","time":"2026-05-06 15:04:57"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"106705.00000","time":"2026-05-06 15:05:25"}]},{"device":"fanake_1.24","desc":"-1.24","tags":[{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O1","time":"2026-05-06 15:05:53"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N1","time":"2026-05-06 15:06:21"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"X-60.000 \nY-67.700 F500. \nG00 Z155.000 \nM9 \nM5 ","time":"2026-05-06 15:06:48"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"15.00000","time":"2026-05-06 15:07:16"},{"id":"Tag9","desc":"״̬","quality":"0","value":"3.00000","time":"2026-05-06 15:04:02"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-06 15:04:02"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"117256500.00000","time":"2026-05-06 15:04:29"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"12020.00000","time":"2026-05-06 15:04:58"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"106460.00000","time":"2026-05-06 15:05:25"}]},{"device":"fanake_1.25","desc":"-1.25","tags":[{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O1","time":"2026-05-06 15:05:53"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N20","time":"2026-05-06 15:06:21"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"G99 G83 Z-12.980 Q1.000 R9.020 F20. \nG80\nG0Z56.","time":"2026-05-06 15:06:48"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"13.00000","time":"2026-05-06 15:07:16"},{"id":"Tag9","desc":"״̬","quality":"0","value":"3.00000","time":"2026-05-06 15:04:02"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-06 15:04:02"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"107630700.00000","time":"2026-05-06 15:04:29"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"18953.00000","time":"2026-05-06 15:04:58"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"88768.00000","time":"2026-05-06 15:05:26"}]},{"device":"fanake_1.26","desc":"-1.26","tags":[{"id":"Tag5","desc":"ִеNC","quality":"1","value":"","time":"1970-01-01 08:00:00"},{"id":"Tag6","desc":"ִеNC","quality":"1","value":"","time":"1970-01-01 08:00:00"},{"id":"Tag7","desc":"ǰӹ","quality":"1","value":"","time":"1970-01-01 08:00:00"},{"id":"Tag8","desc":"ǰӹ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag9","desc":"״̬","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag11","desc":"ģʽ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag22","desc":"ʱ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag23","desc":"ʱ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag1","desc":"ӹ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"}]},{"device":"fanake_1.27","desc":"-1.27","tags":[{"id":"Tag5","desc":"ִеNC","quality":"1","value":"","time":"1970-01-01 08:00:00"},{"id":"Tag6","desc":"ִеNC","quality":"1","value":"","time":"1970-01-01 08:00:00"},{"id":"Tag7","desc":"ǰӹ","quality":"1","value":"","time":"1970-01-01 08:00:00"},{"id":"Tag8","desc":"ǰӹ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag9","desc":"״̬","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag11","desc":"ģʽ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag22","desc":"ʱ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag23","desc":"ʱ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag1","desc":"ӹ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"}]},{"device":"fanake_1.28","desc":"-1.28","tags":[{"id":"Tag5","desc":"ִеNC","quality":"1","value":"","time":"1970-01-01 08:00:00"},{"id":"Tag6","desc":"ִеNC","quality":"1","value":"","time":"1970-01-01 08:00:00"},{"id":"Tag7","desc":"ǰӹ","quality":"1","value":"","time":"1970-01-01 08:00:00"},{"id":"Tag8","desc":"ǰӹ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag9","desc":"״̬","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag11","desc":"ģʽ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag22","desc":"ʱ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag23","desc":"ʱ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag1","desc":"ӹ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"}]},{"device":"fanake_1.29","desc":"-1.29","tags":[{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O1","time":"2026-05-06 15:06:18"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N9","time":"2026-05-06 15:06:45"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"G02 X-17.910 I-1.910 J3.308 \nG01 X-26.800 Y-18.","time":"2026-05-06 15:07:13"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"19.00000","time":"2026-05-06 15:03:59"},{"id":"Tag9","desc":"״̬","quality":"0","value":"3.00000","time":"2026-05-06 15:04:26"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-06 15:04:26"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"54806160.00000","time":"2026-05-06 15:04:54"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"20654.00000","time":"2026-05-06 15:05:22"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"57603.00000","time":"2026-05-06 15:05:50"}]},{"device":"fanake_1.30","desc":"-1.30","tags":[{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O1","time":"2026-05-06 15:06:18"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N9","time":"2026-05-06 15:06:45"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"G91 G28 Y0.000 \nM30\n%","time":"2026-05-06 15:07:13"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"31.00000","time":"2026-05-06 15:03:59"},{"id":"Tag9","desc":"״̬","quality":"0","value":"3.00000","time":"2026-05-06 15:04:26"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-06 15:04:26"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"62122620.00000","time":"2026-05-06 15:04:54"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"17469.00000","time":"2026-05-06 15:05:22"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"62111.00000","time":"2026-05-06 15:05:50"}]},{"device":"fanake_1.31","desc":"-1.31","tags":[{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O1","time":"2026-05-06 15:06:18"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N1","time":"2026-05-06 15:06:45"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"X0.000 \nX8.000 \nZ1.100 \nG00 Z50.000 \nM9 \nG91G28","time":"2026-05-06 15:07:13"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"0.00000","time":"2026-05-06 15:03:59"},{"id":"Tag9","desc":"״̬","quality":"0","value":"3.00000","time":"2026-05-06 15:04:26"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-06 15:04:26"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"63428160.00000","time":"2026-05-06 15:04:54"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"1001.00000","time":"2026-05-06 15:05:22"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"85647.00000","time":"2026-05-06 15:05:50"}]},{"device":"fanake_1.32","desc":"-1.32","tags":[{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O1","time":"2026-05-06 15:06:18"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N0","time":"2026-05-06 15:06:46"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"","time":"2026-05-06 15:07:13"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"90.00000","time":"2026-05-06 15:03:59"},{"id":"Tag9","desc":"״̬","quality":"0","value":"0.00000","time":"2026-05-06 15:04:27"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"5.00000","time":"2026-05-06 15:04:27"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"67187760.00000","time":"2026-05-06 15:04:54"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"23644.00000","time":"2026-05-06 15:05:23"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"86248.00000","time":"2026-05-06 15:05:50"}]},{"device":"fanake_1.33","desc":"-1.33","tags":[{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O1","time":"2026-05-06 15:06:18"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N20","time":"2026-05-06 15:06:46"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"Y0.000 \nY4.792 \nG02 X-10.400 Y8.429 I4.200 J0.0","time":"2026-05-06 15:07:13"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"3.00000","time":"2026-05-06 15:03:59"},{"id":"Tag9","desc":"״̬","quality":"0","value":"0.00000","time":"2026-05-06 15:04:27"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-06 15:04:27"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"85447860.00000","time":"2026-05-06 15:04:54"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"577.00000","time":"2026-05-06 15:05:23"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"99421.00000","time":"2026-05-06 15:05:50"}]}]
\ No newline at end of file
+[{"device":"fanake-1.2_1.2","desc":"-1.2","tags":[{"id":"_io_status","desc":"豸״̬","quality":"0","value":"1.00000","time":"2026-05-11 17:33:12"},{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O1","time":"2026-05-11 17:33:11"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N20","time":"2026-05-11 17:33:11"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"X-23.000 \nG02 X-20.400 Y14.780 I5.200 J0.000 \nG","time":"2026-05-11 17:33:12"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"35.00000","time":"2026-05-11 17:33:12"},{"id":"Tag9","desc":"״̬","quality":"0","value":"3.00000","time":"2026-05-11 17:33:12"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-11 17:33:12"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"45129840.00000","time":"2026-05-11 17:33:12"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"12201.00000","time":"2026-05-11 17:33:12"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"45930.00000","time":"2026-05-11 17:33:12"}]},{"device":"fanake-1.3_1.3","desc":"-1.3","tags":[{"id":"_io_status","desc":"豸״̬","quality":"0","value":"1.00000","time":"2026-05-11 17:33:13"},{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O1","time":"2026-05-11 17:33:12"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N20","time":"2026-05-11 17:33:12"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"G01 Y2.955 \nG03 X-15.947 Y3.637 I-1.000 J0.000 ","time":"2026-05-11 17:33:13"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"31.00000","time":"2026-05-11 17:33:13"},{"id":"Tag9","desc":"״̬","quality":"0","value":"3.00000","time":"2026-05-11 17:33:13"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-11 17:33:13"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"45420840.00000","time":"2026-05-11 17:33:13"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"26722.00000","time":"2026-05-11 17:33:13"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"49652.00000","time":"2026-05-11 17:33:13"}]},{"device":"fanake-1.4_1.4","desc":"-1.4","tags":[{"id":"_io_status","desc":"豸״̬","quality":"0","value":"1.00000","time":"2026-05-11 17:33:12"},{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O1","time":"2026-05-11 17:33:11"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N20","time":"2026-05-11 17:33:12"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"X-200.454 \nX-210.454 \nZ-4.500 \nG00 Z33.000 \nG90","time":"2026-05-11 17:33:12"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"17.00000","time":"2026-05-11 17:33:12"},{"id":"Tag9","desc":"״̬","quality":"0","value":"3.00000","time":"2026-05-11 17:33:12"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-11 17:33:12"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"46104660.00000","time":"2026-05-11 17:33:12"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"19609.00000","time":"2026-05-11 17:33:12"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"40607.00000","time":"2026-05-11 17:33:12"}]},{"device":"fanake-1.5_1.5","desc":"-1.5","tags":[{"id":"_io_status","desc":"豸״̬","quality":"0","value":"1.00000","time":"2026-05-11 17:33:14"},{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O9001","time":"2026-05-11 17:33:12"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N20","time":"2026-05-11 17:33:13"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"G43 Z100.000 H2 \nZ64.300 \nG41 D2 \nG01 Z63.300 F","time":"2026-05-11 17:33:13"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"30.00000","time":"2026-05-11 17:33:13"},{"id":"Tag9","desc":"״̬","quality":"0","value":"3.00000","time":"2026-05-11 17:33:13"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-11 17:33:13"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"42139260.00000","time":"2026-05-11 17:33:14"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"26286.00000","time":"2026-05-11 17:33:14"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"44113.00000","time":"2026-05-11 17:33:14"}]},{"device":"fanake-1.6_1.6","desc":"-1.6","tags":[{"id":"_io_status","desc":"豸״̬","quality":"0","value":"1.00000","time":"2026-05-11 17:33:13"},{"id":"Tag5","desc":"ִеNC","quality":"0","value":"1370.NC","time":"2026-05-11 17:33:12"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N0","time":"2026-05-11 17:33:12"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"<1370.NC>\nG40G49G80\n( NAME: Administrator )\n( M","time":"2026-05-11 17:33:12"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"88.00000","time":"2026-05-11 17:33:12"},{"id":"Tag9","desc":"״̬","quality":"0","value":"0.00000","time":"2026-05-11 17:33:13"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"1.00000","time":"2026-05-11 17:33:13"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"26697720.00000","time":"2026-05-11 17:33:13"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"21227.00000","time":"2026-05-11 17:33:13"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"12323.00000","time":"2026-05-11 17:33:13"}]},{"device":"fanake-1.7_1.7","desc":"-1.7","tags":[{"id":"_io_status","desc":"豸״̬","quality":"0","value":"1.00000","time":"2026-05-11 17:33:12"},{"id":"Tag5","desc":"ִеNC","quality":"0","value":"037.NC","time":"2026-05-11 17:33:11"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N0","time":"2026-05-11 17:33:11"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"","time":"2026-05-11 17:33:11"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"83.00000","time":"2026-05-11 17:33:12"},{"id":"Tag9","desc":"״̬","quality":"0","value":"0.00000","time":"2026-05-11 17:33:12"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-11 17:33:12"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"29783220.00000","time":"2026-05-11 17:33:12"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"102938.00000","time":"2026-05-11 17:33:12"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"18221.00000","time":"2026-05-11 17:33:12"}]},{"device":"fanake-1.8_1.8","desc":"-1.8","tags":[{"id":"_io_status","desc":"豸״̬","quality":"0","value":"1.00000","time":"2026-05-11 17:33:13"},{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O1","time":"2026-05-11 17:33:12"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N20","time":"2026-05-11 17:33:12"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"G03 I-4.200 J0.000 \nG01 X-37.800 \nZ26.000 \nG00 ","time":"2026-05-11 17:33:12"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"77.00000","time":"2026-05-11 17:33:13"},{"id":"Tag9","desc":"״̬","quality":"0","value":"3.00000","time":"2026-05-11 17:33:13"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-11 17:33:13"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"24738120.00000","time":"2026-05-11 17:33:13"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"19332.00000","time":"2026-05-11 17:33:13"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"16243.00000","time":"2026-05-11 17:33:13"}]},{"device":"fanake-1.9_1.9","desc":"-1.9","tags":[{"id":"_io_status","desc":"豸״̬","quality":"0","value":"1.00000","time":"2026-05-11 17:33:21"},{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O1","time":"2026-05-11 17:33:20"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N20","time":"2026-05-11 17:33:20"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"G98 G83 Z21.346 Q0.800 R35.498 F25. \nG80 \nG00 Z","time":"2026-05-11 17:33:20"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"10.00000","time":"2026-05-11 17:33:20"},{"id":"Tag9","desc":"״̬","quality":"0","value":"3.00000","time":"2026-05-11 17:33:20"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-11 17:33:20"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"24958740.00000","time":"2026-05-11 17:33:21"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"18760.00000","time":"2026-05-11 17:33:21"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"16558.00000","time":"2026-05-11 17:33:21"}]},{"device":"fanake-1.10_1.10","desc":"-1.10","tags":[{"id":"_io_status","desc":"豸״̬","quality":"0","value":"0.00000","time":"2026-05-11 17:06:34"},{"id":"Tag5","desc":"ִеNC","quality":"1","value":"","time":"1970-01-01 08:00:00"},{"id":"Tag6","desc":"ִеNC","quality":"1","value":"","time":"1970-01-01 08:00:00"},{"id":"Tag7","desc":"ǰӹ","quality":"1","value":"","time":"1970-01-01 08:00:00"},{"id":"Tag8","desc":"ǰӹ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag9","desc":"״̬","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag11","desc":"ģʽ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag22","desc":"ʱ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag23","desc":"ʱ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag1","desc":"ӹ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"}]},{"device":"fanake-1.11_1.11","desc":"-1.11","tags":[{"id":"_io_status","desc":"豸״̬","quality":"0","value":"0.00000","time":"2026-05-11 17:06:34"},{"id":"Tag5","desc":"ִеNC","quality":"1","value":"","time":"1970-01-01 08:00:00"},{"id":"Tag6","desc":"ִеNC","quality":"1","value":"","time":"1970-01-01 08:00:00"},{"id":"Tag7","desc":"ǰӹ","quality":"1","value":"","time":"1970-01-01 08:00:00"},{"id":"Tag8","desc":"ǰӹ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag9","desc":"״̬","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag11","desc":"ģʽ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag22","desc":"ʱ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag23","desc":"ʱ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag1","desc":"ӹ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"}]},{"device":"fanake-1.12_1.12","desc":"-1.12","tags":[{"id":"_io_status","desc":"豸״̬","quality":"0","value":"0.00000","time":"2026-05-11 17:06:34"},{"id":"Tag5","desc":"ִеNC","quality":"1","value":"","time":"1970-01-01 08:00:00"},{"id":"Tag6","desc":"ִеNC","quality":"1","value":"","time":"1970-01-01 08:00:00"},{"id":"Tag7","desc":"ǰӹ","quality":"1","value":"","time":"1970-01-01 08:00:00"},{"id":"Tag8","desc":"ǰӹ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag9","desc":"״̬","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag11","desc":"ģʽ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag22","desc":"ʱ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag23","desc":"ʱ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag1","desc":"ӹ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"}]},{"device":"fanake-1.13_1.13","desc":"-1.13","tags":[{"id":"_io_status","desc":"豸״̬","quality":"0","value":"1.00000","time":"2026-05-11 17:33:20"},{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O1","time":"2026-05-11 17:33:19"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N0","time":"2026-05-11 17:33:20"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"","time":"2026-05-11 17:33:20"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"297.00000","time":"2026-05-11 17:33:20"},{"id":"Tag9","desc":"״̬","quality":"0","value":"0.00000","time":"2026-05-11 17:33:20"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-11 17:33:20"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"60710880.00000","time":"2026-05-11 17:33:20"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"70372.00000","time":"2026-05-11 17:33:20"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"59265.00000","time":"2026-05-11 17:33:20"}]},{"device":"fanake-1.14_1.14","desc":"-1.14","tags":[{"id":"_io_status","desc":"豸״̬","quality":"0","value":"1.00000","time":"2026-05-11 17:33:14"},{"id":"Tag5","desc":"ִеNC","quality":"0","value":"","time":"2026-05-11 17:33:13"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N0","time":"2026-05-11 17:33:13"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"","time":"2026-05-11 17:33:13"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"112.00000","time":"2026-05-11 17:33:14"},{"id":"Tag9","desc":"״̬","quality":"0","value":"0.00000","time":"2026-05-11 17:33:14"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-11 17:33:14"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"63688860.00000","time":"2026-05-11 17:33:14"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"124322.00000","time":"2026-05-11 17:33:14"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"69813.00000","time":"2026-05-11 17:33:14"}]},{"device":"fanake-1.15_1.15","desc":"-1.15","tags":[{"id":"_io_status","desc":"豸״̬","quality":"0","value":"1.00000","time":"2026-05-11 17:33:14"},{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O506","time":"2026-05-11 17:33:13"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N20","time":"2026-05-11 17:33:13"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"G02 X30.141 Y12.351 I2.350 J17.341 \nX38.650 Y2.","time":"2026-05-11 17:33:14"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"130.00000","time":"2026-05-11 17:33:14"},{"id":"Tag9","desc":"״̬","quality":"0","value":"3.00000","time":"2026-05-11 17:33:14"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-11 17:33:14"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"55027680.00000","time":"2026-05-11 17:33:14"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"206904.00000","time":"2026-05-11 17:33:14"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"32568.00000","time":"2026-05-11 17:33:14"}]},{"device":"fanake-1.16_1.16","desc":"-1.16","tags":[{"id":"_io_status","desc":"豸״̬","quality":"0","value":"1.00000","time":"2026-05-11 17:33:15"},{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O1","time":"2026-05-11 17:33:13"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N1","time":"2026-05-11 17:33:13"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"X0.000 \nX8.000 \nZ2.200 \nG00 Z50.000 \nS350 M3 \nG","time":"2026-05-11 17:33:13"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"8.00000","time":"2026-05-11 17:33:14"},{"id":"Tag9","desc":"״̬","quality":"0","value":"3.00000","time":"2026-05-11 17:33:14"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-11 17:33:14"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"85741920.00000","time":"2026-05-11 17:33:14"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"5808.00000","time":"2026-05-11 17:33:14"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"99897.00000","time":"2026-05-11 17:33:15"}]},{"device":"fanake-1.17_1.17","desc":"-1.17","tags":[{"id":"_io_status","desc":"豸״̬","quality":"0","value":"1.00000","time":"2026-05-11 17:33:14"},{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O1","time":"2026-05-11 17:33:13"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N1","time":"2026-05-11 17:33:13"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"X0.000 \nX8.000 \nZ2.200 \nG00 Z50.000 \nS350 M3 \nG","time":"2026-05-11 17:33:13"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"8.00000","time":"2026-05-11 17:33:13"},{"id":"Tag9","desc":"״̬","quality":"0","value":"3.00000","time":"2026-05-11 17:33:14"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-11 17:33:14"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"85741920.00000","time":"2026-05-11 17:33:14"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"5807.00000","time":"2026-05-11 17:33:14"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"99897.00000","time":"2026-05-11 17:33:14"}]},{"device":"fanake-1.18_1.18","desc":"-1.18","tags":[{"id":"_io_status","desc":"豸״̬","quality":"0","value":"1.00000","time":"2026-05-11 17:33:13"},{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O1","time":"2026-05-11 17:33:12"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N20","time":"2026-05-11 17:33:12"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"G03 X18.353 Y11.342 I3.767 J-3.288 \nX19.000 Y11","time":"2026-05-11 17:33:12"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"25.00000","time":"2026-05-11 17:33:12"},{"id":"Tag9","desc":"״̬","quality":"0","value":"3.00000","time":"2026-05-11 17:33:12"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-11 17:33:12"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"86459280.00000","time":"2026-05-11 17:33:13"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"5429.00000","time":"2026-05-11 17:33:13"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"114209.00000","time":"2026-05-11 17:33:13"}]},{"device":"fanake-1.19_1.19","desc":"-1.19","tags":[{"id":"_io_status","desc":"豸״̬","quality":"0","value":"1.00000","time":"2026-05-11 17:33:13"},{"id":"Tag5","desc":"ִеNC","quality":"0","value":"7","time":"2026-05-11 17:33:12"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N9","time":"2026-05-11 17:33:12"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"<7>\nG21\nG40G17G49G80G90G69G54\nM05\nM09\nT01M06\n(n","time":"2026-05-11 17:33:13"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"2.00000","time":"2026-05-11 17:33:13"},{"id":"Tag9","desc":"״̬","quality":"0","value":"1.00000","time":"2026-05-11 17:33:13"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"4.00000","time":"2026-05-11 17:33:13"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"136902000.00000","time":"2026-05-11 17:33:13"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"2261.00000","time":"2026-05-11 17:33:13"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"144261.00000","time":"2026-05-11 17:33:13"}]},{"device":"fanake-1.20_1.20","desc":"-1.20","tags":[{"id":"_io_status","desc":"豸״̬","quality":"0","value":"1.00000","time":"2026-05-11 17:33:15"},{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O1","time":"2026-05-11 17:33:13"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N1","time":"2026-05-11 17:33:13"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"X0.000 \nX8.000 \nZ2.200 \nG00 Z50.000 \nS350 M3 \nG","time":"2026-05-11 17:33:14"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"8.00000","time":"2026-05-11 17:33:14"},{"id":"Tag9","desc":"״̬","quality":"0","value":"3.00000","time":"2026-05-11 17:33:14"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-11 17:33:14"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"85741920.00000","time":"2026-05-11 17:33:14"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"5808.00000","time":"2026-05-11 17:33:14"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"99897.00000","time":"2026-05-11 17:33:15"}]},{"device":"fanake-1.21_1.21","desc":"-1.21","tags":[{"id":"_io_status","desc":"豸״̬","quality":"0","value":"1.00000","time":"2026-05-11 17:33:13"},{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O1","time":"2026-05-11 17:33:12"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N9","time":"2026-05-11 17:33:12"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"G01 X2.800 Y-17.321 \nG02 X-2.800 I-2.800 J4.850","time":"2026-05-11 17:33:12"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"16.00000","time":"2026-05-11 17:33:12"},{"id":"Tag9","desc":"״̬","quality":"0","value":"3.00000","time":"2026-05-11 17:33:12"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-11 17:33:12"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"141001800.00000","time":"2026-05-11 17:33:12"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"2492.00000","time":"2026-05-11 17:33:13"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"127537.00000","time":"2026-05-11 17:33:13"}]},{"device":"fanake-1.22_1.22","desc":"-1.22","tags":[{"id":"_io_status","desc":"豸״̬","quality":"0","value":"1.00000","time":"2026-05-11 17:33:13"},{"id":"Tag5","desc":"ִеNC","quality":"0","value":"1027","time":"2026-05-11 17:33:12"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N9","time":"2026-05-11 17:33:12"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"G90 G54 X-1.691 Y0.054 A0.000 S5000 M3 \nG43 Z50","time":"2026-05-11 17:33:12"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"15.00000","time":"2026-05-11 17:33:12"},{"id":"Tag9","desc":"״̬","quality":"0","value":"3.00000","time":"2026-05-11 17:33:13"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-11 17:33:13"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"130986840.00000","time":"2026-05-11 17:33:13"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"2691.00000","time":"2026-05-11 17:33:13"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"162236.00000","time":"2026-05-11 17:33:13"}]},{"device":"fanake-1.23_1.23","desc":"-1.23","tags":[{"id":"_io_status","desc":"豸״̬","quality":"0","value":"1.00000","time":"2026-05-11 17:33:13"},{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O2","time":"2026-05-11 17:33:12"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N0","time":"2026-05-11 17:33:13"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"","time":"2026-05-11 17:33:13"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"33.00000","time":"2026-05-11 17:33:13"},{"id":"Tag9","desc":"״̬","quality":"0","value":"0.00000","time":"2026-05-11 17:33:13"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-11 17:33:13"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"125015280.00000","time":"2026-05-11 17:33:13"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"26808.00000","time":"2026-05-11 17:33:13"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"107000.00000","time":"2026-05-11 17:33:13"}]},{"device":"fanake-1.24_1.24","desc":"-1.24","tags":[{"id":"_io_status","desc":"豸״̬","quality":"0","value":"1.00000","time":"2026-05-11 17:33:14"},{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O1","time":"2026-05-11 17:33:13"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N0","time":"2026-05-11 17:33:13"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"O0001S100M3\nG0G90X0Y0Z200.\nG0Z0\nG1X-238.M8F37\nG","time":"2026-05-11 17:33:13"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"0.00000","time":"2026-05-11 17:33:14"},{"id":"Tag9","desc":"״̬","quality":"0","value":"0.00000","time":"2026-05-11 17:33:14"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"5.00000","time":"2026-05-11 17:33:14"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"117511200.00000","time":"2026-05-11 17:33:14"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"0.00000","time":"2026-05-11 17:33:14"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"106743.00000","time":"2026-05-11 17:33:14"}]},{"device":"fanake-1.25_1.25","desc":"-1.25","tags":[{"id":"_io_status","desc":"豸״̬","quality":"0","value":"1.00000","time":"2026-05-11 17:33:13"},{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O1","time":"2026-05-11 17:33:12"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N20","time":"2026-05-11 17:33:12"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"G02 X-5.085 Y-9.221 I-5.020 J7.745 \nG01 X-25.04","time":"2026-05-11 17:33:12"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"20.00000","time":"2026-05-11 17:33:12"},{"id":"Tag9","desc":"״̬","quality":"0","value":"3.00000","time":"2026-05-11 17:33:12"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-11 17:33:12"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"107923020.00000","time":"2026-05-11 17:33:13"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"27780.00000","time":"2026-05-11 17:33:13"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"88902.00000","time":"2026-05-11 17:33:13"}]},{"device":"fanake-1.26_1.26","desc":"-1.26","tags":[{"id":"_io_status","desc":"豸״̬","quality":"0","value":"0.00000","time":"2026-05-11 17:06:34"},{"id":"Tag5","desc":"ִеNC","quality":"1","value":"","time":"1970-01-01 08:00:00"},{"id":"Tag6","desc":"ִеNC","quality":"1","value":"","time":"1970-01-01 08:00:00"},{"id":"Tag7","desc":"ǰӹ","quality":"1","value":"","time":"1970-01-01 08:00:00"},{"id":"Tag8","desc":"ǰӹ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag9","desc":"״̬","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag11","desc":"ģʽ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag22","desc":"ʱ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag23","desc":"ʱ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag1","desc":"ӹ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"}]},{"device":"fanake-1.27_1.27","desc":"-1.27","tags":[{"id":"_io_status","desc":"豸״̬","quality":"0","value":"0.00000","time":"2026-05-11 17:06:34"},{"id":"Tag5","desc":"ִеNC","quality":"1","value":"","time":"1970-01-01 08:00:00"},{"id":"Tag6","desc":"ִеNC","quality":"1","value":"","time":"1970-01-01 08:00:00"},{"id":"Tag7","desc":"ǰӹ","quality":"1","value":"","time":"1970-01-01 08:00:00"},{"id":"Tag8","desc":"ǰӹ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag9","desc":"״̬","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag11","desc":"ģʽ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag22","desc":"ʱ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag23","desc":"ʱ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag1","desc":"ӹ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"}]},{"device":"fanake-1.28_1.28","desc":"-1.28","tags":[{"id":"_io_status","desc":"豸״̬","quality":"0","value":"0.00000","time":"2026-05-11 17:06:34"},{"id":"Tag5","desc":"ִеNC","quality":"1","value":"","time":"1970-01-01 08:00:00"},{"id":"Tag6","desc":"ִеNC","quality":"1","value":"","time":"1970-01-01 08:00:00"},{"id":"Tag7","desc":"ǰӹ","quality":"1","value":"","time":"1970-01-01 08:00:00"},{"id":"Tag8","desc":"ǰӹ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag9","desc":"״̬","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag11","desc":"ģʽ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag22","desc":"ʱ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag23","desc":"ʱ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"},{"id":"Tag1","desc":"ӹ","quality":"1","value":"0.00000","time":"1970-01-01 08:00:00"}]},{"device":"fanake-1.29_1.29","desc":"-1.29","tags":[{"id":"_io_status","desc":"豸״̬","quality":"0","value":"1.00000","time":"2026-05-11 17:33:12"},{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O1","time":"2026-05-11 17:33:11"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N9","time":"2026-05-11 17:33:12"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"X-124.090 Y-23.839 \nG02 X-127.910 I-1.910 J3.30","time":"2026-05-11 17:33:12"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"24.00000","time":"2026-05-11 17:33:12"},{"id":"Tag9","desc":"״̬","quality":"0","value":"3.00000","time":"2026-05-11 17:33:12"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-11 17:33:12"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"55003260.00000","time":"2026-05-11 17:33:12"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"26610.00000","time":"2026-05-11 17:33:12"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"57744.00000","time":"2026-05-11 17:33:12"}]},{"device":"fanake-1.30_1.30","desc":"-1.30","tags":[{"id":"_io_status","desc":"豸״̬","quality":"0","value":"1.00000","time":"2026-05-11 17:33:13"},{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O1","time":"2026-05-11 17:33:12"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N9","time":"2026-05-11 17:33:12"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"G01 X-7.000 Y-6.351 \nG02 X-9.000 Y-2.887 I2.000","time":"2026-05-11 17:33:12"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"37.00000","time":"2026-05-11 17:33:12"},{"id":"Tag9","desc":"״̬","quality":"0","value":"3.00000","time":"2026-05-11 17:33:12"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-11 17:33:12"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"62319300.00000","time":"2026-05-11 17:33:13"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"20687.00000","time":"2026-05-11 17:33:13"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"62324.00000","time":"2026-05-11 17:33:13"}]},{"device":"fanake-1.31_1.31","desc":"-1.31","tags":[{"id":"_io_status","desc":"豸״̬","quality":"0","value":"1.00000","time":"2026-05-11 17:33:12"},{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O1","time":"2026-05-11 17:33:11"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N1","time":"2026-05-11 17:33:12"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"X-205.000 \nX-213.000 \nZ1.100 \nG00 Z50.000 \nY35.","time":"2026-05-11 17:33:12"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"7.00000","time":"2026-05-11 17:33:12"},{"id":"Tag9","desc":"״̬","quality":"0","value":"3.00000","time":"2026-05-11 17:33:12"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-11 17:33:12"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"63867120.00000","time":"2026-05-11 17:33:12"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"8597.00000","time":"2026-05-11 17:33:12"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"85846.00000","time":"2026-05-11 17:33:12"}]},{"device":"fanake-1.32_1.32","desc":"-1.32","tags":[{"id":"_io_status","desc":"豸״̬","quality":"0","value":"1.00000","time":"2026-05-11 17:33:13"},{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O1","time":"2026-05-11 17:33:11"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N9","time":"2026-05-11 17:33:12"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"X-207.000 \nX-214.300 \nZ-4.930 \nG00 Z40.000 \nG40","time":"2026-05-11 17:33:12"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"12.00000","time":"2026-05-11 17:33:12"},{"id":"Tag9","desc":"״̬","quality":"0","value":"3.00000","time":"2026-05-11 17:33:12"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-11 17:33:12"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"67540320.00000","time":"2026-05-11 17:33:12"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"5144.00000","time":"2026-05-11 17:33:12"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"87814.00000","time":"2026-05-11 17:33:13"}]},{"device":"fanake-1.33_1.33","desc":"-1.33","tags":[{"id":"_io_status","desc":"豸״̬","quality":"0","value":"1.00000","time":"2026-05-11 17:33:15"},{"id":"Tag5","desc":"ִеNC","quality":"0","value":"O1","time":"2026-05-11 17:33:13"},{"id":"Tag6","desc":"ִеNC","quality":"0","value":"N1","time":"2026-05-11 17:33:13"},{"id":"Tag7","desc":"ǰӹ","quality":"0","value":"X0.000 \nX8.000 \nZ2.200 \nG00 Z50.000 \nS350 M3 \nG","time":"2026-05-11 17:33:14"},{"id":"Tag8","desc":"ǰӹ","quality":"0","value":"8.00000","time":"2026-05-11 17:33:14"},{"id":"Tag9","desc":"״̬","quality":"0","value":"3.00000","time":"2026-05-11 17:33:14"},{"id":"Tag11","desc":"ģʽ","quality":"0","value":"10.00000","time":"2026-05-11 17:33:14"},{"id":"Tag22","desc":"ʱ","quality":"0","value":"85741920.00000","time":"2026-05-11 17:33:14"},{"id":"Tag23","desc":"ʱ","quality":"0","value":"5808.00000","time":"2026-05-11 17:33:15"},{"id":"Tag1","desc":"ӹ","quality":"0","value":"99897.00000","time":"2026-05-11 17:33:15"}]}]
\ No newline at end of file