From af5081bc0d0668d526a204076557a171097ddb8d Mon Sep 17 00:00:00 2001
From: zhang <zc857179121@qq.com>
Date: 星期四, 05 二月 2026 14:02:59 +0800
Subject: [PATCH] Merge branch 'refs/heads/rcs_master' into ctu_conveyor

---
 version/db/new.sql                                                                                         |   34 
 zy-acs-manager/src/main/java/integrationRecord.sql                                                         |    7 
 zy-acs-flow/src/page/loc/LocList.jsx                                                                       |   15 
 zy-acs-flow/src/page/sta/StaCreate.jsx                                                                     |   16 
 zy-acs-manager/src/main/java/com/zy/acs/manager/manager/service/impl/IntegrationRecordServiceImpl.java     |   38 
 zy-acs-manager/src/main/java/com/zy/acs/manager/common/constant/Constants.java                             |    6 
 zy-acs-manager/src/main/java/com/zy/acs/manager/common/config/ConveyorProperties.java                      |   26 
 zy-acs-manager/src/main/java/com/zy/acs/manager/core/integrate/dto/TaskUplinkParam.java                    |   14 
 zy-acs-common/src/main/java/com/zy/acs/common/enums/ActuatorDirectionType.java                             |   30 
 zy-acs-flow/src/page/code/CodeList.jsx                                                                     |    8 
 version/doc/RCS开发进度表.xlsx                                                                                  |    0 
 zy-acs-manager/src/main/java/com/zy/acs/manager/manager/entity/Task.java                                   |  102 -
 zy-acs-flow/src/page/integrationRecord/IntegrationRecordEdit.jsx                                           |  180 ++
 zy-acs-manager/src/main/java/com/zy/acs/manager/core/scheduler/test/AutoRunRebootScheduler.java            |   37 
 zy-acs-manager/src/main/java/com/zy/acs/manager/manager/enums/TaskUplinkStateType.java                     |   28 
 zy-acs-manager/src/main/java/com/zy/acs/manager/core/service/MapService.java                               |   15 
 zy-acs-manager/src/main/java/com/zy/acs/manager/manager/service/TaskService.java                           |    6 
 zy-acs-manager/src/main/java/com/zy/acs/manager/manager/entity/Sta.java                                    |    3 
 zy-acs-flow/package-lock.json                                                                              |  106 +
 zy-acs-flow/src/page/loc/LocPanel.jsx                                                                      |    3 
 zy-acs-manager/src/main/java/com/zy/acs/manager/core/integrate/dto/OpenBusCancelParam.java                 |   18 
 zy-acs-manager/src/main/java/com/zy/acs/manager/manager/controller/BusController.java                      |   11 
 zy-acs-manager/src/main/java/com/zy/acs/manager/manager/service/impl/TaskServiceImpl.java                  |  129 +
 zy-acs-flow/src/page/task/TaskListAside.jsx                                                                |    2 
 zy-acs-manager/src/main/java/com/zy/acs/manager/core/HandlerController.java                                |   75 
 zy-acs-flow/public/imports/code_import_template.xlsx                                                       |    0 
 zy-acs-flow/src/page/integrationRecord/IntegrationRecordCreate.jsx                                         |  207 +++
 zy-acs-framework/src/main/java/com/zy/acs/framework/annotations/IntegrationAuth.java                       |   21 
 zy-acs-flow/src/i18n/zh.js                                                                                 |   56 
 zy-acs-manager/src/main/java/com/zy/acs/manager/common/utils/ExcelUtil.java                                |   16 
 zy-acs-flow/src/page/sta/StaEdit.jsx                                                                       |   34 
 zy-acs-manager/src/main/java/com/zy/acs/manager/core/integrate/wms/TaskReportService.java                  |  180 ++
 zy-acs-manager/src/main/java/com/zy/acs/manager/core/service/MainService.java                              |  104 
 zy-acs-manager/src/main/java/com/zy/acs/manager/core/integrate/dto/OpenBusSubmitParam.java                 |    6 
 zy-acs-flow/src/i18n/en.js                                                                                 |   54 
 zy-acs-manager/src/main/java/com/zy/acs/manager/core/scheduler/MaintainScheduler.java                      |   32 
 zy-acs-flow/src/page/ResourceContent.js                                                                    |    3 
 zy-acs-flow/src/page/task/TaskList.jsx                                                                     |  301 ++-
 zy-acs-flow/src/page/integrationRecord/index.jsx                                                           |   18 
 zy-acs-manager/src/main/java/com/zy/acs/manager/common/domain/TaskBoolDto.java                             |   28 
 zy-acs-manager/src/main/java/com/zy/acs/manager/common/config/UplinkProperties.java                        |   40 
 zy-acs-manager/src/main/java/com/zy/acs/manager/core/integrate/conveyor/ConveyorController.java            |    3 
 zy-acs-manager/src/main/resources/mapper/manager/TaskMapper.xml                                            |    3 
 zy-acs-flow/src/page/loc/compDirect.js                                                                     |   15 
 zy-acs-flow/src/page/staReserve/StaReserveList.jsx                                                         |    4 
 zy-acs-manager/src/main/java/com/zy/acs/manager/core/service/ValidService.java                             |   13 
 zy-acs-manager/src/main/java/com/zy/acs/manager/manager/controller/TaskController.java                     |    7 
 zy-acs-manager/src/main/java/com/zy/acs/manager/manager/entity/Loc.java                                    |    4 
 zy-acs-manager/src/main/java/com/zy/acs/manager/core/integrate/conveyor/SiemensConveyorStationService.java |   67 
 zy-acs-manager/src/main/resources/mapper/manager/IntegrationRecordMapper.xml                               |    5 
 zy-acs-manager/src/main/java/com/zy/acs/manager/core/scheduler/test/AutoRunScheduler.java                  |   33 
 zy-acs-manager/src/main/java/com/zy/acs/manager/manager/service/impl/BusServiceImpl.java                   |   21 
 zy-acs-manager/src/main/java/com/zy/acs/manager/common/utils/HttpGo.java                                   |   10 
 zy-acs-flow/src/page/components/useExcelParse.js                                                           |   77 +
 zy-acs-manager/src/main/java/com/zy/acs/manager/manager/controller/IntegrationRecordController.java        |  108 +
 zy-acs-manager/src/main/java/com/zy/acs/manager/manager/mapper/IntegrationRecordMapper.java                |   12 
 zy-acs-manager/src/main/java/com/zy/acs/manager/manager/service/IntegrationRecordService.java              |   10 
 zy-acs-flow/src/page/integrationRecord/IntegrationRecordList.jsx                                           |  173 ++
 zy-acs-manager/src/main/java/com/zy/acs/manager/common/domain/TaskDto.java                                 |    2 
 zy-acs-manager/src/main/java/com/zy/acs/manager/manager/entity/IntegrationRecord.java                      |  196 +++
 zy-acs-manager/src/main/java/com/zy/acs/manager/core/domain/type/NamespaceType.java                        |   15 
 zy-acs-manager/src/main/java/com/zy/acs/manager/manager/service/BusService.java                            |    4 
 zy-acs-flow/package.json                                                                                   |    5 
 zy-acs-flow/src/page/sta/StaPanel.jsx                                                                      |   12 
 zy-acs-manager/src/main/resources/application.yml                                                          |    9 
 zy-acs-flow/src/page/sta/StaList.jsx                                                                       |   17 
 zy-acs-manager/src/main/java/com/zy/acs/manager/common/config/IntegrationRecordAdvice.java                 |   84 +
 zy-acs-flow/src/page/loc/LocCreate.jsx                                                                     |    6 
 zy-acs-flow/src/page/loc/LocInit.jsx                                                                       |    8 
 zy-acs-manager/src/main/java/com/zy/acs/manager/core/integrate/wms/OpenController.java                     |   87 +
 zy-acs-manager/src/main/java/com/zy/acs/manager/manager/enums/IntegrationDirectionType.java                |   16 
 zy-acs-flow/src/page/components/ImportXlsxModal.jsx                                                        |  191 ++
 zy-acs-manager/src/main/java/com/zy/acs/manager/core/scheduler/test/ConveyorAutoRunScheduler.java          |   14 
 zy-acs-flow/src/page/loc/LocEdit.jsx                                                                       |    6 
 zy-acs-flow/src/page/components/ImportTxtModal.jsx                                                         |  213 +++
 zy-acs-flow/src/page/components/ImportButton.jsx                                                           |   17 
 /dev/null                                                                                                  |  149 --
 zy-acs-flow/src/page/integrationRecord/IntegrationRecordPanel.jsx                                          |  129 ++
 zy-acs-manager/src/main/java/com/zy/acs/manager/common/CodeBuilder.java                                    |    5 
 zy-acs-manager/src/main/java/com/zy/acs/manager/manager/controller/CodeController.java                     |    2 
 version/db/sqlIndex                                                                                        |    1 
 zy-acs-manager/src/main/java/com/zy/acs/manager/core/integrate/dto/OpenBusCancelResult.java                |   19 
 82 files changed, 3,076 insertions(+), 705 deletions(-)

diff --git a/version/db/new.sql b/version/db/new.sql
index df955d1..f8396a3 100644
--- a/version/db/new.sql
+++ b/version/db/new.sql
@@ -29,3 +29,37 @@
 
 alter table man_sta
     add outbound_wait int null comment '杩炵画鍑哄簱绛夊緟' after inbound_wait;
+
+
+alter table man_task
+    add uplink_sts varchar(64) null comment '涓婅鐘舵��' after empty_mk;
+
+alter table man_task_log
+    add uplink_sts varchar(64) null comment '涓婅鐘舵��' after empty_mk;
+
+CREATE TABLE `man_integration_record` (
+    `id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
+    `uuid` VARCHAR(255) DEFAULT NULL COMMENT '缂栧彿',
+    `namespace` VARCHAR(255) DEFAULT NULL COMMENT '鍚嶇О绌洪棿(*)',
+    `url` VARCHAR(255) DEFAULT NULL COMMENT '鎺ュ彛鍦板潃',
+    `appkey` VARCHAR(255) DEFAULT NULL COMMENT '骞冲彴瀵嗛挜',
+    `caller` VARCHAR(255) DEFAULT NULL COMMENT '璋冪敤鏂规爣璇�',
+    `direction` int(1) NOT NULL DEFAULT 0 COMMENT '鏂瑰悜{1:琚皟鐢�,2:璋冪敤澶栭儴}',
+    `timestamp` VARCHAR(64) DEFAULT NULL COMMENT '鏃堕棿鎴�',
+    `client_ip` VARCHAR(64) DEFAULT NULL COMMENT '瀹㈡埛绔疘P',
+    `request` TEXT COMMENT '璇锋眰鍐呭',
+    `response` TEXT COMMENT '鍝嶅簲鍐呭',
+    `err` TEXT COMMENT '寮傚父鍐呭',
+    `result` int(1) DEFAULT NULL COMMENT '缁撴灉{1:鎴愬姛,0:澶辫触}',
+    `cost_ms` INT(11) DEFAULT NULL COMMENT '鑰楁椂',
+    `status` int(1) DEFAULT 1 COMMENT '鐘舵�亄1:姝e父,0:鍐荤粨}',
+    `create_time` timestamp DEFAULT CURRENT_TIMESTAMP COMMENT '娣诲姞鏃堕棿',
+    `update_time` timestamp DEFAULT CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
+    `memo` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
+    PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+update man_loc set comp_direct =2  where comp_direct =0
+
+alter table man_sta
+    add act_dir int(1) null comment '璐у弶鏂瑰悜' after angle;
\ No newline at end of file
diff --git a/version/db/sqlIndex b/version/db/sqlIndex
index c3bae29..34b72c7 100644
--- a/version/db/sqlIndex
+++ b/version/db/sqlIndex
@@ -25,6 +25,7 @@
 CREATE INDEX idx_task_seq_num ON man_task(seq_num);
 CREATE INDEX idx_task_agv_id ON man_task(agv_id);
 CREATE INDEX idx_task_agv_id_task_sts ON man_task(agv_id, task_sts);
+CREATE INDEX idx_task_task_sts_uplink_sts ON man_task(task_sts, uplink_sts);
 # man_zone
 CREATE INDEX idx_zone_uuid ON man_zone(uuid);
 # man_agv_detail
diff --git "a/version/doc/RCS\345\274\200\345\217\221\350\277\233\345\272\246\350\241\250.xlsx" "b/version/doc/RCS\345\274\200\345\217\221\350\277\233\345\272\246\350\241\250.xlsx"
index d60d657..949a629 100644
--- "a/version/doc/RCS\345\274\200\345\217\221\350\277\233\345\272\246\350\241\250.xlsx"
+++ "b/version/doc/RCS\345\274\200\345\217\221\350\277\233\345\272\246\350\241\250.xlsx"
Binary files differ
diff --git a/zy-acs-common/src/main/java/com/zy/acs/common/enums/ActuatorDirectionType.java b/zy-acs-common/src/main/java/com/zy/acs/common/enums/ActuatorDirectionType.java
new file mode 100644
index 0000000..df899cf
--- /dev/null
+++ b/zy-acs-common/src/main/java/com/zy/acs/common/enums/ActuatorDirectionType.java
@@ -0,0 +1,30 @@
+package com.zy.acs.common.enums;
+
+import com.zy.acs.framework.exception.CoolException;
+
+public enum ActuatorDirectionType {
+
+    LEFT(1),
+    RIGHT(2),
+    FORWARD(3),
+    ;
+
+    public int val;
+
+    ActuatorDirectionType(int val) {
+        this.val = val;
+    }
+
+    public static ActuatorDirectionType fromVal(Integer val) {
+        if (null == val) {
+            throw new CoolException("actuator direction param val is null");
+        }
+        for (ActuatorDirectionType type : ActuatorDirectionType.values()) {
+            if (type.val == val) {
+                return type;
+            }
+        }
+        throw new IllegalArgumentException("Invalid ActuatorDirectionType: " + val);
+    }
+
+}
diff --git a/zy-acs-common/src/main/java/com/zy/acs/common/enums/AgvDirectionType.java b/zy-acs-common/src/main/java/com/zy/acs/common/enums/AgvDirectionType.java
deleted file mode 100644
index 7454ec5..0000000
--- a/zy-acs-common/src/main/java/com/zy/acs/common/enums/AgvDirectionType.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.zy.acs.common.enums;
-
-public enum AgvDirectionType {
-
-    LEFT(1),
-    RIGHT(2),
-    FORWARD(0),
-    ;
-
-    public int val;
-
-    AgvDirectionType(int val) {
-        this.val = val;
-    }
-
-}
diff --git a/zy-acs-flow/package-lock.json b/zy-acs-flow/package-lock.json
index e6cdf6a..b000d2c 100644
--- a/zy-acs-flow/package-lock.json
+++ b/zy-acs-flow/package-lock.json
@@ -24,7 +24,8 @@
         "react-router-dom": "^6.26.1",
         "react-syntax-highlighter": "^15.5.0",
         "three": "^0.155.0",
-        "tweedle.js": "^2.1.0"
+        "tweedle.js": "^2.1.0",
+        "xlsx": "^0.18.5"
       },
       "devDependencies": {
         "@types/node": "^20.10.7",
@@ -2339,6 +2340,15 @@
         "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
       }
     },
+    "node_modules/adler-32": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz",
+      "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==",
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
     "node_modules/ajv": {
       "version": "6.12.6",
       "resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz",
@@ -2702,6 +2712,19 @@
         }
       ]
     },
+    "node_modules/cfb": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz",
+      "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "adler-32": "~1.3.0",
+        "crc-32": "~1.2.0"
+      },
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
     "node_modules/chalk": {
       "version": "2.4.2",
       "resolved": "https://registry.npmmirror.com/chalk/-/chalk-2.4.2.tgz",
@@ -2748,6 +2771,15 @@
       "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
       "engines": {
         "node": ">=6"
+      }
+    },
+    "node_modules/codepage": {
+      "version": "1.15.0",
+      "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz",
+      "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==",
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=0.8"
       }
     },
     "node_modules/color-convert": {
@@ -2808,6 +2840,18 @@
       },
       "engines": {
         "node": ">=10"
+      }
+    },
+    "node_modules/crc-32": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
+      "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==",
+      "license": "Apache-2.0",
+      "bin": {
+        "crc32": "bin/crc32.njs"
+      },
+      "engines": {
+        "node": ">=0.8"
       }
     },
     "node_modules/cross-spawn": {
@@ -3785,6 +3829,15 @@
       "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==",
       "engines": {
         "node": ">=0.4.x"
+      }
+    },
+    "node_modules/frac": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz",
+      "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==",
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=0.8"
       }
     },
     "node_modules/fs.realpath": {
@@ -5982,6 +6035,18 @@
         "node": ">=6"
       }
     },
+    "node_modules/ssf": {
+      "version": "0.11.2",
+      "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz",
+      "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "frac": "~1.1.2"
+      },
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
     "node_modules/strict-uri-encode": {
       "version": "2.0.0",
       "resolved": "https://registry.npmmirror.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
@@ -6552,6 +6617,24 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/wmf": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz",
+      "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==",
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
+    "node_modules/word": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz",
+      "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==",
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
     "node_modules/word-wrap": {
       "version": "1.2.5",
       "resolved": "https://registry.npmmirror.com/word-wrap/-/word-wrap-1.2.5.tgz",
@@ -6567,6 +6650,27 @@
       "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
       "dev": true
     },
+    "node_modules/xlsx": {
+      "version": "0.18.5",
+      "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz",
+      "integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "adler-32": "~1.3.0",
+        "cfb": "~1.2.1",
+        "codepage": "~1.15.0",
+        "crc-32": "~1.2.1",
+        "ssf": "~0.11.2",
+        "wmf": "~1.0.1",
+        "word": "~0.3.0"
+      },
+      "bin": {
+        "xlsx": "bin/xlsx.njs"
+      },
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
     "node_modules/xtend": {
       "version": "4.0.2",
       "resolved": "https://registry.npmmirror.com/xtend/-/xtend-4.0.2.tgz",
diff --git a/zy-acs-flow/package.json b/zy-acs-flow/package.json
index 4340f1b..77bdb38 100644
--- a/zy-acs-flow/package.json
+++ b/zy-acs-flow/package.json
@@ -28,7 +28,8 @@
     "react-router-dom": "^6.26.1",
     "react-syntax-highlighter": "^15.5.0",
     "three": "^0.155.0",
-    "tweedle.js": "^2.1.0"
+    "tweedle.js": "^2.1.0",
+    "xlsx": "^0.18.5"
   },
   "devDependencies": {
     "@types/node": "^20.10.7",
@@ -46,4 +47,4 @@
     "vite": "^5.3.5"
   },
   "name": "cool-admin-flow"
-}
+}
\ No newline at end of file
diff --git a/zy-acs-flow/public/imports/code_import_template.xlsx b/zy-acs-flow/public/imports/code_import_template.xlsx
new file mode 100644
index 0000000..929295f
--- /dev/null
+++ b/zy-acs-flow/public/imports/code_import_template.xlsx
Binary files differ
diff --git a/zy-acs-flow/src/i18n/en.js b/zy-acs-flow/src/i18n/en.js
index f80d1d6..de01fc6 100644
--- a/zy-acs-flow/src/i18n/en.js
+++ b/zy-acs-flow/src/i18n/en.js
@@ -62,9 +62,9 @@
             import: {
                 title: 'Import',
                 stop: 'Stop import',
-                msg: 'Here is a sample CSV file you can use as a template',
+                msg: 'Here is a sample file you can use as a template',
                 tips: 'The import is running, please do not close this tab.',
-                err: 'Failed to import this file, please make sure your provided a valid CSV file.',
+                err: 'Failed to import this file, please make sure your provided a valid file.',
                 download: 'Download Import Template',
                 result: 'Contacts import complete. Imported %{success} success, with %{error} errors',
             },
@@ -158,6 +158,7 @@
         mission: 'Mission',
         staReserve: 'Sta Reserve',
         lane: 'Lane',
+        integrationRecord: 'Integration',
     },
     table: {
         field: {
@@ -288,11 +289,12 @@
                 staType: "station type",
                 code: "code",
                 offset: "offset",
-                height: "height",
-                depth: "depth",
+                height: "height(mm)",
+                depth: "depth(mm)",
                 angle: 'angle',
-                inboundWait: 'inbound wait(ms)',
-                outboundWait: 'outbound wait(ms)',
+                actDir: 'actuator direction',
+                inboundWait: 'in wait(ms)',
+                outboundWait: 'out wait(ms)',
                 autoing: "autoing",
                 loading: "loading",
                 inEnable: "in enable",
@@ -342,9 +344,9 @@
                 locNo: "loc No.",
                 name: "name",
                 code: "code",
-                compDirect: "code direct",
+                compDirect: "actuator direction",
                 locSts: "loc sts",
-                offset: "offset",
+                offset: "height",
                 row: "row",
                 bay: "bay",
                 lev: "lev",
@@ -485,6 +487,7 @@
                 destLoc: "dest loc",
                 destCode: "dest code",
                 emptyMk: "empty mk",
+                uplinkSts: "uplink status",
                 zpallet: "zpallet",
                 phase: "ideal path",
                 errDesc: "error",
@@ -603,6 +606,22 @@
                 entryAngle: "entry angle",
                 maximum: "maximum",
             },
+            integrationRecord: {
+                uuid: "uuid",
+                namespace: "namespace",
+                url: "url",
+                appkey: "appkey",
+                caller: "caller",
+                direction: "direction",
+                timestamp: "timestamp",
+                clientIp: "clientIp",
+                request: "request",
+                response: "response",
+                err: "error",
+                result: "result",
+                costMs: "costMs",
+            },
+
         }
     },
     page: {
@@ -669,6 +688,13 @@
             },
             levOffset: 'lev offset',
             bottomOffset: 'bottom offset',
+            enums: {
+                compDirect: {
+                    left: 'Left',
+                    right: 'Right',
+                    forward: 'Forward',
+                },
+            },
         },
         sta: {
             depthHint: 'Set depth to 0 to keep the default value.',
@@ -720,6 +746,18 @@
                 reposition: 'clear path reposition',
             }
         },
+        task: {
+            enums: {
+                uplinkSts: {
+                    NONE: 'Unknown',
+                    PENDING: 'Pending',
+                    SENDING: 'Uploading',
+                    SUCCESS: 'Success',
+                    FAILED: 'Failed',
+                    SKIPPED: 'Skipped',
+                },
+            },
+        },
         segment: {
             enums: {
                 state: {
diff --git a/zy-acs-flow/src/i18n/zh.js b/zy-acs-flow/src/i18n/zh.js
index 914a9ce..1f421e4 100644
--- a/zy-acs-flow/src/i18n/zh.js
+++ b/zy-acs-flow/src/i18n/zh.js
@@ -62,9 +62,9 @@
             import: {
                 title: '瀵煎叆',
                 stop: '鍋滄瀵煎叆',
-                msg: '杩欐槸涓�涓彲浠ョ敤浣滄ā鏉跨殑绀轰緥 CSV 鏂囦欢',
+                msg: '杩欐槸涓�涓彲浠ョ敤浣滄ā鏉跨殑绀轰緥鏂囦欢',
                 tips: '姝e湪瀵煎叆涓紝璇蜂笉瑕佸叧闂绐楀彛',
-                err: '鏃犳硶瀵煎叆姝ゆ枃浠讹紝璇风‘淇濇偍鎻愪緵浜嗘湁鏁堢殑 CSV 鏂囦欢',
+                err: '鏃犳硶瀵煎叆姝ゆ枃浠讹紝璇风‘淇濇偍鎻愪緵浜嗘湁鏁堢殑鏂囦欢',
                 download: '涓嬭浇瀵煎叆妯℃澘',
                 result: '瀵煎叆瀹屾垚銆傚凡瀵煎叆 %{success} 鎴愬姛, 鍜� %{error} 澶辫触',
             },
@@ -158,6 +158,7 @@
         mission: '鎵ц',
         staReserve: '绔欑偣棰勭害',
         lane: '宸烽亾绠$悊',
+        integrationRecord: '闆嗘垚浜や簰',
     },
     table: {
         field: {
@@ -288,11 +289,12 @@
                 staType: "绔欑偣绫诲瀷",
                 code: "鍦伴潰鐮�",
                 offset: "鍋忕Щ閲�",
-                height: "浣滀笟楂樺害",
-                depth: "浣滀笟娣卞害",
-                angle: '浣滀笟瑙掑害',
-                inboundWait: '鍏ュ簱绛夊緟(姣)',
-                outboundWait: '鍑哄簱绛夊緟(姣)',
+                height: "浣滀笟楂樺害(mm)",
+                depth: "浣滀笟娣卞害(mm)",
+                angle: '杞︿綋瑙掑害(掳)',
+                actDir: '璐у弶鏂瑰悜',
+                inboundWait: '鍏ュ簱绛�(ms)',
+                outboundWait: '鍑哄簱绛�(ms)',
                 autoing: "鑷姩",
                 loading: "杞借揣",
                 inEnable: "鍙叆",
@@ -342,9 +344,9 @@
                 locNo: "搴撲綅鍙�",
                 name: "鍚嶇О",
                 code: "鍦伴潰鐮�",
-                compDirect: "鐮佹柟鍚�",
+                compDirect: "璐у弶鏂瑰悜",
                 locSts: "搴撲綅鐘舵��",
-                offset: "鍋忕Щ閲�",
+                offset: "楂樺害",
                 row: "鎺�",
                 bay: "鍒�",
                 lev: "灞�",
@@ -485,6 +487,7 @@
                 destLoc: "鐩爣搴撲綅",
                 destCode: "鐩爣鍦伴潰鐮�",
                 emptyMk: "绌烘枡绠�",
+                uplinkSts: "涓婅鐘舵��",
                 zpallet: "鏂欑鐮�",
                 phase: "鐞嗘兂璺緞",
                 errDesc: "寮傚父鎻忚堪",
@@ -603,6 +606,22 @@
                 entryAngle: "杞︿綋瑙掑害",
                 maximum: "鎵胯浇閲�",
             },
+            integrationRecord: {
+                uuid: "缂栧彿",
+                namespace: "鍛藉悕绌洪棿",
+                url: "鎺ュ彛鍦板潃",
+                appkey: "瀵嗛挜",
+                caller: "璋冪敤鏂�",
+                direction: "鏂瑰悜",
+                timestamp: "鏃堕棿鎴�",
+                clientIp: "瀹㈡埛绔疘P",
+                request: "璇锋眰鍐呭",
+                response: "鍝嶅簲鍐呭",
+                err: "寮傚父",
+                result: "璇锋眰缁撴灉",
+                costMs: "鑰楁椂(姣)",
+            },
+
         }
     },
     page: {
@@ -669,6 +688,13 @@
             },
             levOffset: '姣忓眰楂樺害',
             bottomOffset: '搴曢儴鍋忕Щ閲�',
+            enums: {
+                compDirect: {
+                    left: '宸�',
+                    right: '鍙�',
+                    forward: '鍓�',
+                },
+            },
         },
         sta: {
             depthHint: '娣卞害璁剧疆涓� 0 琛ㄧず娌跨敤榛樿鍊笺��',
@@ -720,6 +746,18 @@
                 reposition: '娓呴櫎璺緞閲嶆柊瀹氫綅',
             }
         },
+        task: {
+            enums: {
+                uplinkSts: {
+                    NONE: '鏈煡',
+                    PENDING: '寰呬笂鎶�',
+                    SENDING: '涓婃姤涓�',
+                    SUCCESS: '鎴愬姛',
+                    FAILED: '澶辫触',
+                    SKIPPED: '璺宠繃',
+                },
+            },
+        },
         segment: {
             enums: {
                 state: {
diff --git a/zy-acs-flow/src/page/ResourceContent.js b/zy-acs-flow/src/page/ResourceContent.js
index 7b142bb..e3cdf0f 100644
--- a/zy-acs-flow/src/page/ResourceContent.js
+++ b/zy-acs-flow/src/page/ResourceContent.js
@@ -43,6 +43,7 @@
 import mission from "./mission";
 import staReserve from './staReserve';
 import lane from './lane';
+import integrationRecord from './integrationRecord';
 
 const ResourceContent = (node) => {
     switch (node.component) {
@@ -124,6 +125,8 @@
             return staReserve;
         case 'lane':
             return lane;
+        case 'integrationRecord':
+            return integrationRecord;
         default:
             return {
                 list: ListGuesser,
diff --git a/zy-acs-flow/src/page/code/CodeList.jsx b/zy-acs-flow/src/page/code/CodeList.jsx
index 0746122..797ea44 100644
--- a/zy-acs-flow/src/page/code/CodeList.jsx
+++ b/zy-acs-flow/src/page/code/CodeList.jsx
@@ -46,8 +46,10 @@
 import ImportButton from '../components/ImportButton'
 import { useCodeImport } from './useCodeImport';
 
-import * as importTemp from './importTemp.csv?raw';
-const IMPORT_TEMP_URL = `data:text/csv;name=crm_contacts_sample.csv;charset=utf-8,${encodeURIComponent(importTemp.default)}`;
+// import * as importTemp from './importTemp.csv?raw';
+// const IMPORT_TEMP_URL = `data:text/csv;name=crm_contacts_sample.csv;charset=utf-8,${encodeURIComponent(importTemp.default)}`;
+
+const IMPORT_TEMP_URL = '/imports/code_import_template.xlsx';
 
 const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({
     '& .css-1vooibu-MuiSvgIcon-root': {
@@ -126,7 +128,7 @@
                         <FilterButton />
                         <MyCreateButton onClick={() => { setCreateDialog(true) }} />
                         <SelectColumnsButton preferenceKey='code' />
-                        <ImportButton importTemp={IMPORT_TEMP_URL} useCodeImport={useCodeImport} onceBatch={10} />
+                        <ImportButton type="xlsx" importTemp={IMPORT_TEMP_URL} useImport={useCodeImport} onceBatch={10} />
                         <MyExportButton />
                     </TopToolbar>
                 )}
diff --git a/zy-acs-flow/src/page/components/ImportButton.jsx b/zy-acs-flow/src/page/components/ImportButton.jsx
index 147ec9e..f382b9f 100644
--- a/zy-acs-flow/src/page/components/ImportButton.jsx
+++ b/zy-acs-flow/src/page/components/ImportButton.jsx
@@ -2,11 +2,18 @@
 import { useState } from 'react';
 import { Button } from 'react-admin';
 import ImportModal from './ImportModal';
+import ImportTxtModal from './ImportTxtModal';
+import ImportXlsxModal from './ImportXlsxModal';
 
-const ImportButton = (props) => {
+const ImportButton = ({
+    type = 'csv', // csv, txt, xlsx,
+    variant = 'text',
+    ...props
+}) => {
     const [modalOpen, setModalOpen] = useState(false);
 
-    const handleOpenModal = () => {
+    const handleOpenModal = (e) => {
+        e.stopPropagation();
         setModalOpen(true);
     };
 
@@ -17,12 +24,14 @@
     return (
         <>
             <Button
+                variant={variant}
                 startIcon={<UploadIcon />}
                 label="common.action.import.title"
                 onClick={handleOpenModal}
             />
-
-            <ImportModal open={modalOpen} onClose={handleCloseModal} {...props} />
+            {type === 'csv' && (<ImportModal open={modalOpen} onClose={handleCloseModal} {...props} />)}
+            {type === 'txt' && (<ImportTxtModal open={modalOpen} onClose={handleCloseModal} {...props} />)}
+            {type === 'xlsx' && (<ImportXlsxModal open={modalOpen} onClose={handleCloseModal} {...props} />)}
         </>
     );
 };
diff --git a/zy-acs-flow/src/page/components/ImportTxtModal.jsx b/zy-acs-flow/src/page/components/ImportTxtModal.jsx
new file mode 100644
index 0000000..a42b465
--- /dev/null
+++ b/zy-acs-flow/src/page/components/ImportTxtModal.jsx
@@ -0,0 +1,213 @@
+import { useEffect, useState } from 'react';
+import { Box, CircularProgress, Stack, Typography } from '@mui/material';
+import Alert from '@mui/material/Alert';
+import Dialog from '@mui/material/Dialog';
+import DialogActions from '@mui/material/DialogActions';
+import DialogContent from '@mui/material/DialogContent';
+import DialogTitle from '@mui/material/DialogTitle';
+import MuiLink from '@mui/material/Link';
+import {
+    Button,
+    FileField,
+    FileInput,
+    Form,
+    Toolbar,
+    useRefresh,
+    useTranslate
+} from 'react-admin';
+import { Link } from 'react-router-dom';
+import DialogCloseButton from './DialogCloseButton';
+import { usePapaParse } from './usePapaParse';
+
+const ImportTxtModal = ({ open, onClose, useImport, params, title = '', onceBatch = 10 }) => {
+
+    const refresh = useRefresh();
+    const translate = useTranslate();
+
+    const { processBatch } = useImport();
+    const { importer, parseCsv, reset } = usePapaParse({
+        batchSize: onceBatch,
+        processBatch,
+        params,
+    });
+
+    const [file, setFile] = useState(null);
+
+    useEffect(() => {
+        if (importer.state === 'complete') {
+            refresh();
+        }
+    }, [importer.state, refresh]);
+
+    const handleFileChange = (file) => {
+        setFile(file);
+    };
+
+    const startImport = async () => {
+        if (!file) {
+            return;
+        }
+
+        parseCsv(file);
+    };
+
+    const handleClose = () => {
+        reset();
+        onClose();
+    };
+
+    const handleReset = (e) => {
+        e.preventDefault();
+        reset();
+    };
+
+    return (
+        <Dialog
+            open={open}
+            maxWidth="md"
+            fullWidth
+            onClick={(e) => e.stopPropagation()}
+        >
+            <DialogCloseButton onClose={handleClose} />
+            <DialogTitle>{translate('common.action.import.title')} {title}</DialogTitle>
+            <DialogContent>
+                <Form>
+                    <Stack spacing={2}>
+                        {importer.state === 'running' && (
+                            <Stack gap={2}>
+                                <Alert
+                                    severity="info"
+                                    action={
+                                        <Box
+                                            sx={{
+                                                display: 'flex',
+                                                height: '100%',
+                                                alignItems: 'center',
+                                                padding: '0',
+                                            }}
+                                        >
+                                            <CircularProgress size={20} />
+                                        </Box>
+                                    }
+                                    sx={{
+                                        alignItems: 'center',
+                                        '& .MuiAlert-action': {
+                                            padding: 0,
+                                            marginRight: 0,
+                                        },
+                                    }}
+                                >
+                                    {translate('common.action.import.tips')}
+                                </Alert>
+                                <Typography variant="body2">
+                                    Imported{' '}
+                                    <strong>
+                                        {importer.importCount} /{' '}
+                                        {importer.rowCount}
+                                    </strong>{' '}
+                                    contacts, with{' '}
+                                    <strong>{importer.errorCount}</strong>{' '}
+                                    errors.
+                                    {importer.remainingTime !== null && (
+                                        <>
+                                            {' '}
+                                            Estimated remaining time:{' '}
+                                            <strong>
+                                                {millisecondsToTime(
+                                                    importer.remainingTime
+                                                )}
+                                            </strong>
+                                            .{' '}
+                                            <MuiLink
+                                                href="#"
+                                                onClick={handleReset}
+                                                color="error"
+                                            >
+                                                {translate('common.action.import.stop')}
+                                            </MuiLink>
+                                        </>
+                                    )}
+                                </Typography>
+                            </Stack>
+                        )}
+
+                        {importer.state === 'error' && (
+                            <Alert severity="error">
+                                {translate('common.action.import.err')}
+                            </Alert>
+                        )}
+
+                        {importer.state === 'complete' && (
+                            <>
+                                <Alert severity="success">
+                                    {translate('common.action.import.result', {
+                                        success: importer.importCount,
+                                        error: importer.errorCount
+                                    })}
+                                </Alert>
+                                {importer.errorMsg && (
+                                    <Alert severity="error">
+                                        {importer.errorMsg}
+                                    </Alert>
+                                )}
+                            </>
+                        )}
+
+                        {importer.state === 'idle' && (
+                            <>
+
+                                <FileInput
+                                    source="txt"
+                                    label="Txt File"
+                                    accept={{ 'text/plain': ['.txt'] }}
+                                    onChange={handleFileChange}
+                                >
+                                    <FileField source="src" title="title" />
+                                </FileInput>
+
+                            </>
+                        )}
+                    </Stack>
+                </Form>
+            </DialogContent>
+            <DialogActions
+                sx={{
+                    p: 0,
+                    justifyContent: 'flex-start',
+                }}
+            >
+                <Toolbar
+                    sx={{
+                        width: '100%',
+                    }}
+                >
+                    {importer.state === 'idle' ? (
+                        <>
+                            <Button
+                                label="common.action.import.title"
+                                variant="contained"
+                                onClick={startImport}
+                                disabled={!file}
+                            />
+                        </>
+                    ) : (
+                        <Button
+                            label="ra.action.close"
+                            onClick={handleClose}
+                            disabled={importer.state === 'running'}
+                        />
+                    )}
+                </Toolbar>
+            </DialogActions>
+        </Dialog>
+    );
+}
+
+function millisecondsToTime(ms) {
+    var seconds = Math.floor((ms / 1000) % 60);
+    var minutes = Math.floor((ms / (60 * 1000)) % 60);
+
+    return `${minutes}m ${seconds}s`;
+}
+
+export default ImportTxtModal;
\ No newline at end of file
diff --git a/zy-acs-flow/src/page/components/ImportXlsxModal.jsx b/zy-acs-flow/src/page/components/ImportXlsxModal.jsx
new file mode 100644
index 0000000..9fc24d1
--- /dev/null
+++ b/zy-acs-flow/src/page/components/ImportXlsxModal.jsx
@@ -0,0 +1,191 @@
+// ImportXlsxModal.jsx
+import { useEffect, useState } from 'react';
+import { Box, CircularProgress, Stack, Typography } from '@mui/material';
+import Alert from '@mui/material/Alert';
+import Dialog from '@mui/material/Dialog';
+import DialogActions from '@mui/material/DialogActions';
+import DialogContent from '@mui/material/DialogContent';
+import DialogTitle from '@mui/material/DialogTitle';
+import MuiLink from '@mui/material/Link';
+import {
+    Button,
+    FileField,
+    FileInput,
+    Form,
+    Toolbar,
+    useRefresh,
+    useTranslate,
+} from 'react-admin';
+import DialogCloseButton from './DialogCloseButton';
+import { useExcelParse } from './useExcelParse';
+
+const ImportXlsxModal = ({
+    open,
+    onClose,
+    importTemp,
+    useImport,
+    params,
+    title = '',
+    onceBatch = 10,
+}) => {
+    const refresh = useRefresh();
+    const t = useTranslate();
+
+    const { processBatch } = useImport();
+    const { importer, parseExcel, reset } = useExcelParse({
+        batchSize: onceBatch,
+        processBatch,
+        params,
+    });
+
+    const [file, setFile] = useState(null);
+
+    useEffect(() => {
+        if (importer.state === 'complete') {
+            refresh();
+        }
+    }, [importer.state, refresh]);
+
+    const handleFileChange = (val) => {
+        const f = Array.isArray(val) ? val[0]?.rawFile ?? val[0] : val?.rawFile ?? val;
+        setFile(f || null);
+    };
+
+    const startImport = async () => {
+        if (!file) return;
+        parseExcel(file);
+    };
+
+    const handleClose = () => {
+        reset();
+        setFile(null);
+        onClose();
+    };
+
+    const handleReset = (e) => {
+        e.preventDefault();
+        reset();
+    };
+
+    const nameMatch = importTemp?.split('/').pop() || 'import_template.xlsx';
+
+    return (
+        <Dialog open={open} maxWidth="md" fullWidth onClick={(e) => e.stopPropagation()}>
+            <DialogCloseButton onClose={handleClose} />
+            <DialogTitle>{t('common.action.import.title')} {title}</DialogTitle>
+            <DialogContent>
+                <Form>
+                    <Stack spacing={2}>
+                        <Alert
+                            severity="info"
+                            action={
+                                importTemp ? (
+                                    <Button
+                                        component="a"
+                                        label="common.action.import.download"
+                                        color="info"
+                                        href={importTemp}
+                                        download={nameMatch}
+                                    />
+                                ) : null
+                            }
+                            sx={{
+                                alignItems: 'center',
+                                '& .MuiAlert-action': { p: 0, mr: 0 },
+                            }}
+                        >
+                            {t('common.action.import.msg', { _: '杩欐槸涓�涓彲浠ョ敤浣滄ā鏉跨殑绀轰緥 Excel 鏂囦欢' })}
+                        </Alert>
+
+                        {importer.state === 'running' && (
+                            <Stack gap={2}>
+                                <Alert
+                                    severity="info"
+                                    action={
+                                        <Box sx={{ display: 'flex', alignItems: 'center', p: 0 }}>
+                                            <CircularProgress size={20} />
+                                        </Box>
+                                    }
+                                    sx={{ alignItems: 'center', '& .MuiAlert-action': { p: 0, mr: 0 } }}
+                                >
+                                    {t('common.action.import.tips')}
+                                </Alert>
+                                <Typography variant="body2">
+                                    Imported <strong>{importer.importCount}</strong> /{' '}
+                                    <strong>{importer.rowCount}</strong> rows, with{' '}
+                                    <strong>{importer.errorCount}</strong> errors.
+                                    {importer.remainingTime !== null && (
+                                        <>
+                                            {' '}ETA: <strong>{millisecondsToTime(importer.remainingTime)}</strong>.{' '}
+                                            <MuiLink href="#" onClick={handleReset} color="error">
+                                                {t('common.action.import.stop')}
+                                            </MuiLink>
+                                        </>
+                                    )}
+                                </Typography>
+                            </Stack>
+                        )}
+
+                        {importer.state === 'error' && (
+                            <Alert severity="error">{t('common.action.import.err')}</Alert>
+                        )}
+
+                        {importer.state === 'complete' && (
+                            <>
+                                <Alert severity="success">
+                                    {t('common.action.import.result', {
+                                        success: importer.importCount,
+                                        error: importer.errorCount,
+                                    })}
+                                </Alert>
+                                {importer.errorMsg && <Alert severity="error">{importer.errorMsg}</Alert>}
+                            </>
+                        )}
+
+                        {importer.state === 'idle' && (
+                            <>
+                                <FileInput
+                                    source="xlsx"
+                                    label="Excel File (.xlsx / .xls)"
+                                    accept={{
+                                        'application/vnd.ms-excel': ['.xls'],
+                                        'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': ['.xlsx'],
+                                    }}
+                                    onChange={handleFileChange}
+                                >
+                                    <FileField source="src" title="title" />
+                                </FileInput>
+                            </>
+                        )}
+                    </Stack>
+                </Form>
+            </DialogContent>
+            <DialogActions sx={{ p: 0, justifyContent: 'flex-start' }}>
+                <Toolbar sx={{ width: '100%' }}>
+                    {importer.state === 'idle' ? (
+                        <Button
+                            label="common.action.import.title"
+                            variant="contained"
+                            onClick={startImport}
+                            disabled={!file}
+                        />
+                    ) : (
+                        <Button
+                            label="ra.action.close"
+                            onClick={handleClose}
+                            disabled={importer.state === 'running'}
+                        />
+                    )}
+                </Toolbar>
+            </DialogActions>
+        </Dialog>
+    );
+};
+
+function millisecondsToTime(ms) {
+    const seconds = Math.floor((ms / 1000) % 60);
+    const minutes = Math.floor((ms / (60 * 1000)) % 60);
+    return `${minutes}m ${seconds}s`;
+}
+
+export default ImportXlsxModal;
\ No newline at end of file
diff --git a/zy-acs-flow/src/page/components/useExcelParse.js b/zy-acs-flow/src/page/components/useExcelParse.js
new file mode 100644
index 0000000..1e79d19
--- /dev/null
+++ b/zy-acs-flow/src/page/components/useExcelParse.js
@@ -0,0 +1,77 @@
+import * as XLSX from 'xlsx';
+import { useCallback, useMemo, useRef, useState } from 'react';
+
+export function useExcelParse({ batchSize = 10, processBatch, params }) {
+    const importIdRef = useRef(0);
+    const [importer, setImporter] = useState({ state: 'idle' });
+
+    const reset = useCallback(() => {
+        setImporter({ state: 'idle' });
+        importIdRef.current += 1;
+    }, []);
+
+    const parseExcel = useCallback(async (file) => {
+        if (!file) return;
+        setImporter({ state: 'parsing' });
+
+        const importId = importIdRef.current;
+
+        try {
+            const buf = await file.arrayBuffer();
+            const wb = XLSX.read(buf, { type: 'array' });
+            const sheet = wb.SheetNames[0];
+            const rows = XLSX.utils.sheet_to_json(wb.Sheets[sheet], { defval: '' });
+
+            setImporter({
+                state: 'running',
+                rowCount: rows.length,
+                importCount: 0,
+                errorCount: 0,
+                remainingTime: null,
+            });
+
+            let totalTime = 0;
+            for (let i = 0; i < rows.length; i += batchSize) {
+                if (importIdRef.current !== importId) return;
+
+                const batch = rows.slice(i, i + batchSize);
+                try {
+                    const start = Date.now();
+                    await processBatch(batch, params);
+                    totalTime += Date.now() - start;
+
+                    const mean = totalTime / (i + batch.length);
+                    setImporter((prev) =>
+                        prev.state === 'running'
+                            ? {
+                                ...prev,
+                                importCount: prev.importCount + batch.length,
+                                remainingTime: mean * (rows.length - (prev.importCount + batch.length)),
+                            }
+                            : prev
+                    );
+                } catch (err) {
+                    setImporter((prev) =>
+                        prev.state === 'running'
+                            ? {
+                                ...prev,
+                                errorCount: prev.errorCount + batch.length,
+                                errorMsg: prev.errorMsg
+                                    ? `${prev.errorMsg}\n${err?.message || String(err)}`
+                                    : (err?.message || String(err)),
+                            }
+                            : prev
+                    );
+                }
+            }
+
+            setImporter((prev) =>
+                prev.state === 'running' ? { ...prev, state: 'complete', remainingTime: null } : prev
+            );
+        } catch (error) {
+            setImporter({ state: 'error', error });
+        }
+    }, [batchSize, processBatch, params]);
+
+    return useMemo(() => ({ importer, parseExcel, reset }), [importer, parseExcel, reset]);
+}
\ No newline at end of file
diff --git a/zy-acs-flow/src/page/integrationRecord/IntegrationRecordCreate.jsx b/zy-acs-flow/src/page/integrationRecord/IntegrationRecordCreate.jsx
new file mode 100644
index 0000000..0688a52
--- /dev/null
+++ b/zy-acs-flow/src/page/integrationRecord/IntegrationRecordCreate.jsx
@@ -0,0 +1,207 @@
+import React, { useState, useRef, useEffect, useMemo } from "react";
+import {
+    CreateBase,
+    useTranslate,
+    TextInput,
+    NumberInput,
+    BooleanInput,
+    DateInput,
+    SaveButton,
+    SelectInput,
+    ReferenceInput,
+    ReferenceArrayInput,
+    AutocompleteInput,
+    Toolbar,
+    required,
+    useDataProvider,
+    useNotify,
+    Form,
+    useCreateController,
+} from 'react-admin';
+import {
+    Dialog,
+    DialogActions,
+    DialogContent,
+    DialogTitle,
+    Stack,
+    Grid,
+    Box,
+} from '@mui/material';
+import DialogCloseButton from "../components/DialogCloseButton";
+import StatusSelectInput from "../components/StatusSelectInput";
+import MemoInput from "../components/MemoInput";
+
+const IntegrationRecordCreate = (props) => {
+    const { open, setOpen } = props;
+
+    const translate = useTranslate();
+    const notify = useNotify();
+
+    const handleClose = (event, reason) => {
+        if (reason !== "backdropClick") {
+            setOpen(false);
+        }
+    };
+
+    const handleSuccess = async (data) => {
+        setOpen(false);
+        notify('common.response.success');
+    };
+
+    const handleError = async (error) => {
+        notify(error.message || 'common.response.fail', { type: 'error', messageArgs: { _: error.message } });
+    };
+
+    return (
+        <>
+            <CreateBase
+                record={{}}
+                transform={(data) => {
+                    return data;
+                }}
+                mutationOptions={{ onSuccess: handleSuccess, onError: handleError }}
+            >
+                <Dialog
+                    open={open}
+                    onClose={handleClose}
+                    aria-labelledby="form-dialog-title"
+                    fullWidth
+                    disableRestoreFocus
+                    maxWidth="md"   // 'xs' | 'sm' | 'md' | 'lg' | 'xl'
+                >
+                    <Form>
+                        <DialogTitle id="form-dialog-title" sx={{
+                            position: 'sticky',
+                            top: 0,
+                            backgroundColor: 'background.paper',
+                            zIndex: 1000
+                        }}
+                        >
+                            {translate('create.title')}
+                            <Box sx={{ position: 'absolute', top: 8, right: 8, zIndex: 1001 }}>
+                                <DialogCloseButton onClose={handleClose} />
+                            </Box>
+                        </DialogTitle>
+                        <DialogContent>
+                            <Grid container rowSpacing={2} columnSpacing={2}>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <TextInput
+                                        label="table.field.integrationRecord.uuid"
+                                        source="uuid"
+                                        parse={v => v}
+                                        autoFocus
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <TextInput
+                                        label="table.field.integrationRecord.namespace"
+                                        source="namespace"
+                                        parse={v => v}
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <TextInput
+                                        label="table.field.integrationRecord.url"
+                                        source="url"
+                                        parse={v => v}
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <TextInput
+                                        label="table.field.integrationRecord.appkey"
+                                        source="appkey"
+                                        parse={v => v}
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <TextInput
+                                        label="table.field.integrationRecord.caller"
+                                        source="caller"
+                                        parse={v => v}
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <SelectInput
+                                        label="table.field.integrationRecord.direction"
+                                        source="direction"
+                                        choices={[
+                                            { id: 1, name: '琚皟鐢�' },
+                                            { id: 2, name: '璋冪敤澶栭儴' },
+                                        ]}
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <TextInput
+                                        label="table.field.integrationRecord.timestamp"
+                                        source="timestamp"
+                                        parse={v => v}
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <TextInput
+                                        label="table.field.integrationRecord.clientIp"
+                                        source="clientIp"
+                                        parse={v => v}
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <TextInput
+                                        label="table.field.integrationRecord.request"
+                                        source="request"
+                                        parse={v => v}
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <TextInput
+                                        label="table.field.integrationRecord.response"
+                                        source="response"
+                                        parse={v => v}
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <TextInput
+                                        label="table.field.integrationRecord.err"
+                                        source="err"
+                                        parse={v => v}
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <SelectInput
+                                        label="table.field.integrationRecord.result"
+                                        source="result"
+                                        choices={[
+                                            { id: 1, name: '鎴愬姛' },
+                                            { id: 0, name: '澶辫触' },
+                                        ]}
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <NumberInput
+                                        label="table.field.integrationRecord.costMs"
+                                        source="costMs"
+                                    />
+                                </Grid>
+
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <StatusSelectInput />
+                                </Grid>
+                                <Grid item xs={12} display="flex" gap={1}>
+                                    <Stack direction="column" spacing={1} width={'100%'}>
+                                        <MemoInput />
+                                    </Stack>
+                                </Grid>
+                            </Grid>
+                        </DialogContent>
+                        <DialogActions sx={{ position: 'sticky', bottom: 0, backgroundColor: 'background.paper', zIndex: 1000 }}>
+                            <Toolbar sx={{ width: '100%', justifyContent: 'space-between' }}  >
+                                <SaveButton />
+                            </Toolbar>
+                        </DialogActions>
+                    </Form>
+                </Dialog>
+            </CreateBase>
+        </>
+    )
+}
+
+export default IntegrationRecordCreate;
diff --git a/zy-acs-flow/src/page/integrationRecord/IntegrationRecordEdit.jsx b/zy-acs-flow/src/page/integrationRecord/IntegrationRecordEdit.jsx
new file mode 100644
index 0000000..bfdaa02
--- /dev/null
+++ b/zy-acs-flow/src/page/integrationRecord/IntegrationRecordEdit.jsx
@@ -0,0 +1,180 @@
+import React, { useState, useRef, useEffect, useMemo } from "react";
+import {
+    Edit,
+    SimpleForm,
+    FormDataConsumer,
+    useTranslate,
+    TextInput,
+    NumberInput,
+    BooleanInput,
+    DateInput,
+    SelectInput,
+    ReferenceInput,
+    ReferenceArrayInput,
+    AutocompleteInput,
+    SaveButton,
+    Toolbar,
+    Labeled,
+    NumberField,
+    required,
+    useRecordContext,
+    DeleteButton,
+} from 'react-admin';
+import { useWatch, useFormContext } from "react-hook-form";
+import { Stack, Grid, Box, Typography } from '@mui/material';
+import * as Common from '@/utils/common';
+import { EDIT_MODE, REFERENCE_INPUT_PAGESIZE } from '@/config/setting';
+import EditBaseAside from "../components/EditBaseAside";
+import CustomerTopToolBar from "../components/EditTopToolBar";
+import MemoInput from "../components/MemoInput";
+import StatusSelectInput from "../components/StatusSelectInput";
+
+const FormToolbar = () => {
+    const { getValues } = useFormContext();
+
+    return (
+        <Toolbar sx={{ justifyContent: 'space-between' }}>
+            <SaveButton />
+            <DeleteButton mutationMode="optimistic" />
+        </Toolbar>
+    )
+}
+
+const IntegrationRecordEdit = () => {
+    const translate = useTranslate();
+
+    return (
+        <Edit
+            redirect="list"
+            mutationMode={EDIT_MODE}
+            actions={<CustomerTopToolBar />}
+            aside={<EditBaseAside />}
+        >
+            <SimpleForm
+                shouldUnregister
+                warnWhenUnsavedChanges
+                toolbar={<FormToolbar />}
+                mode="onTouched"
+                defaultValues={{}}
+            // validate={(values) => { }}
+            >
+                <Grid container width={{ xs: '100%', xl: '80%' }} rowSpacing={3} columnSpacing={3}>
+                    <Grid item xs={12} md={8}>
+                        <Typography variant="h6" gutterBottom>
+                            {translate('common.edit.title.main')}
+                        </Typography>
+                        <Stack direction='row' gap={2}>
+                            <TextInput
+                                label="table.field.integrationRecord.uuid"
+                                source="uuid"
+                                parse={v => v}
+                                autoFocus
+                            />
+                        </Stack>
+                        <Stack direction='row' gap={2}>
+                            <TextInput
+                                label="table.field.integrationRecord.namespace"
+                                source="namespace"
+                                parse={v => v}
+                            />
+                        </Stack>
+                        <Stack direction='row' gap={2}>
+                            <TextInput
+                                label="table.field.integrationRecord.url"
+                                source="url"
+                                parse={v => v}
+                            />
+                        </Stack>
+                        <Stack direction='row' gap={2}>
+                            <TextInput
+                                label="table.field.integrationRecord.appkey"
+                                source="appkey"
+                                parse={v => v}
+                            />
+                        </Stack>
+                        <Stack direction='row' gap={2}>
+                            <TextInput
+                                label="table.field.integrationRecord.caller"
+                                source="caller"
+                                parse={v => v}
+                            />
+                        </Stack>
+                        <Stack direction='row' gap={2}>
+                            <SelectInput
+                                label="table.field.integrationRecord.direction"
+                                source="direction"
+                                choices={[
+                                    { id: 1, name: '琚皟鐢�' },
+                                    { id: 2, name: '璋冪敤澶栭儴' },
+                                ]}
+                                validate={required()}
+                            />
+                        </Stack>
+                        <Stack direction='row' gap={2}>
+                            <TextInput
+                                label="table.field.integrationRecord.timestamp"
+                                source="timestamp"
+                                parse={v => v}
+                            />
+                        </Stack>
+                        <Stack direction='row' gap={2}>
+                            <TextInput
+                                label="table.field.integrationRecord.clientIp"
+                                source="clientIp"
+                                parse={v => v}
+                            />
+                        </Stack>
+                        <Stack direction='row' gap={2}>
+                            <TextInput
+                                label="table.field.integrationRecord.request"
+                                source="request"
+                                parse={v => v}
+                            />
+                        </Stack>
+                        <Stack direction='row' gap={2}>
+                            <TextInput
+                                label="table.field.integrationRecord.response"
+                                source="response"
+                                parse={v => v}
+                            />
+                        </Stack>
+                        <Stack direction='row' gap={2}>
+                            <TextInput
+                                label="table.field.integrationRecord.err"
+                                source="err"
+                                parse={v => v}
+                            />
+                        </Stack>
+                        <Stack direction='row' gap={2}>
+                            <SelectInput
+                                label="table.field.integrationRecord.result"
+                                source="result"
+                                choices={[
+                                    { id: 1, name: '鎴愬姛' },
+                                    { id: 0, name: '澶辫触' },
+                                ]}
+                            />
+                        </Stack>
+                        <Stack direction='row' gap={2}>
+                            <NumberInput
+                                label="table.field.integrationRecord.costMs"
+                                source="costMs"
+                            />
+                        </Stack>
+
+                    </Grid>
+                    <Grid item xs={12} md={4}>
+                        <Typography variant="h6" gutterBottom>
+                            {translate('common.edit.title.common')}
+                        </Typography>
+                        <StatusSelectInput />
+                        <Box mt="2em" />
+                        <MemoInput />
+                    </Grid>
+                </Grid>
+            </SimpleForm>
+        </Edit >
+    )
+}
+
+export default IntegrationRecordEdit;
diff --git a/zy-acs-flow/src/page/integrationRecord/IntegrationRecordList.jsx b/zy-acs-flow/src/page/integrationRecord/IntegrationRecordList.jsx
new file mode 100644
index 0000000..ddd87d2
--- /dev/null
+++ b/zy-acs-flow/src/page/integrationRecord/IntegrationRecordList.jsx
@@ -0,0 +1,173 @@
+import React, { useState, useRef, useEffect, useMemo, useCallback } from "react";
+import { useNavigate } from 'react-router-dom';
+import {
+    List,
+    DatagridConfigurable,
+    SearchInput,
+    TopToolbar,
+    SelectColumnsButton,
+    EditButton,
+    FilterButton,
+    CreateButton,
+    ExportButton,
+    BulkDeleteButton,
+    WrapperField,
+    useRecordContext,
+    useTranslate,
+    useNotify,
+    useListContext,
+    FunctionField,
+    TextField,
+    NumberField,
+    DateField,
+    BooleanField,
+    ReferenceField,
+    TextInput,
+    DateTimeInput,
+    DateInput,
+    SelectInput,
+    NumberInput,
+    ReferenceInput,
+    ReferenceArrayInput,
+    AutocompleteInput,
+    DeleteButton,
+} from 'react-admin';
+import { Box, Typography, Card, Stack } from '@mui/material';
+import { styled } from '@mui/material/styles';
+import IntegrationRecordCreate from "./IntegrationRecordCreate";
+import IntegrationRecordPanel from "./IntegrationRecordPanel";
+import EmptyDataLoader from "../components/EmptyDataLoader";
+import MyCreateButton from "../components/MyCreateButton";
+import MyExportButton from '../components/MyExportButton';
+import PageDrawer from "../components/PageDrawer";
+import MyField from "../components/MyField";
+import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting';
+import * as Common from '@/utils/common';
+
+const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({
+    '& .css-1vooibu-MuiSvgIcon-root': {
+        height: '.9em'
+    },
+    '& .RaDatagrid-row': {
+        cursor: 'auto'
+    },
+    '& .column-name': {
+    },
+    '& .opt': {
+        width: 200
+    },
+}));
+
+const filters = [
+    <SearchInput source="condition" alwaysOn />,
+    <DateInput label='common.time.after' source="timeStart" alwaysOn />,
+    <DateInput label='common.time.before' source="timeEnd" alwaysOn />,
+
+    <TextInput source="uuid" label="table.field.integrationRecord.uuid" />,
+    <TextInput source="namespace" label="table.field.integrationRecord.namespace" />,
+    <TextInput source="url" label="table.field.integrationRecord.url" />,
+    <TextInput source="appkey" label="table.field.integrationRecord.appkey" />,
+    <TextInput source="caller" label="table.field.integrationRecord.caller" />,
+    <SelectInput source="direction" label="table.field.integrationRecord.direction"
+        choices={[
+            { id: 1, name: '琚皟鐢�' },
+            { id: 2, name: '璋冪敤澶栭儴' },
+        ]}
+    />,
+    <TextInput source="timestamp" label="table.field.integrationRecord.timestamp" />,
+    <TextInput source="clientIp" label="table.field.integrationRecord.clientIp" />,
+    <SelectInput source="result" label="table.field.integrationRecord.result"
+        choices={[
+            { id: 1, name: '鎴愬姛' },
+            { id: 0, name: '澶辫触' },
+        ]}
+    />,
+
+    <TextInput label="common.field.memo" source="memo" />,
+]
+
+const IntegrationRecordList = () => {
+    const translate = useTranslate();
+
+    const [createDialog, setCreateDialog] = useState(false);
+    const [drawerVal, setDrawerVal] = useState(false);
+
+    return (
+        <Box display="flex">
+            <List
+                sx={{
+                    flexGrow: 1,
+                    transition: (theme) =>
+                        theme.transitions.create(['all'], {
+                            duration: theme.transitions.duration.enteringScreen,
+                        }),
+                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+                }}
+                title={"menu.integrationRecord"}
+                empty={<EmptyDataLoader />}
+                filters={filters}
+                sort={{ field: "create_time", order: "desc" }}
+                actions={(
+                    <TopToolbar>
+                        <FilterButton />
+                        <MyCreateButton onClick={() => { setCreateDialog(true) }} />
+                        <SelectColumnsButton preferenceKey='integrationRecord' />
+                        <MyExportButton />
+                    </TopToolbar>
+                )}
+                perPage={DEFAULT_PAGE_SIZE}
+            >
+                <StyledDatagrid
+                    preferenceKey='integrationRecord'
+                    bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />}
+                    rowClick={(id, resource, record) => false}
+                    expand={() => <IntegrationRecordPanel />}
+                    expandSingle={true}
+                    omit={['id', 'createTime', 'createBy', 'memo']}
+                >
+                    <NumberField source="id" />
+                    <TextField source="uuid" label="table.field.integrationRecord.uuid" />
+                    <TextField source="namespace" label="table.field.integrationRecord.namespace" />
+                    <TextField source="url" label="table.field.integrationRecord.url" />
+                    <TextField source="appkey" label="table.field.integrationRecord.appkey" />
+                    <TextField source="caller" label="table.field.integrationRecord.caller" />
+                    <TextField source="direction$" label="table.field.integrationRecord.direction" sortable={false} />
+                    <TextField source="timestamp" label="table.field.integrationRecord.timestamp" />
+                    <TextField source="clientIp" label="table.field.integrationRecord.clientIp" />
+                    <TextField source="request" label="table.field.integrationRecord.request" />
+                    <TextField source="response" label="table.field.integrationRecord.response" />
+                    <TextField source="err" label="table.field.integrationRecord.err" />
+                    <TextField source="result$" label="table.field.integrationRecord.result" sortable={false} />
+                    <NumberField source="costMs" label="table.field.integrationRecord.costMs" />
+
+                    <ReferenceField source="updateBy" label="common.field.updateBy" reference="user" link={false} sortable={false}>
+                        <TextField source="nickname" />
+                    </ReferenceField>
+                    <DateField source="updateTime" label="common.field.updateTime" showTime />
+                    <ReferenceField source="createBy" label="common.field.createBy" reference="user" link={false} sortable={false}>
+                        <TextField source="nickname" />
+                    </ReferenceField>
+                    <DateField source="createTime" label="common.field.createTime" showTime />
+                    <BooleanField source="statusBool" label="common.field.status" sortable={false} />
+                    <TextField source="memo" label="common.field.memo" sortable={false} />
+                    <WrapperField cellClassName="opt" label="common.field.opt">
+                        <EditButton sx={{ padding: '1px', fontSize: '.75rem' }} />
+                        <DeleteButton sx={{ padding: '1px', fontSize: '.75rem' }} mutationMode={OPERATE_MODE} />
+                    </WrapperField>
+                </StyledDatagrid>
+            </List>
+            <IntegrationRecordCreate
+                open={createDialog}
+                setOpen={setCreateDialog}
+            />
+            <PageDrawer
+                title='IntegrationRecord Detail'
+                drawerVal={drawerVal}
+                setDrawerVal={setDrawerVal}
+            >
+            </PageDrawer>
+        </Box>
+    )
+}
+
+export default IntegrationRecordList;
diff --git a/zy-acs-flow/src/page/integrationRecord/IntegrationRecordPanel.jsx b/zy-acs-flow/src/page/integrationRecord/IntegrationRecordPanel.jsx
new file mode 100644
index 0000000..e9dd786
--- /dev/null
+++ b/zy-acs-flow/src/page/integrationRecord/IntegrationRecordPanel.jsx
@@ -0,0 +1,129 @@
+import React, { useState, useRef, useEffect, useMemo } from "react";
+import { Box, Card, CardContent, Grid, Typography, Tooltip } from '@mui/material';
+import {
+    useTranslate,
+    useRecordContext,
+} from 'react-admin';
+import PanelTypography from "../components/PanelTypography";
+import * as Common from '@/utils/common'
+
+const IntegrationRecordPanel = () => {
+    const record = useRecordContext();
+    if (!record) return null;
+    const translate = useTranslate();
+    return (
+        <>
+            <Card sx={{ width: { xs: 300, sm: 500, md: 600, lg: 800 }, margin: 'auto' }}>
+                <CardContent>
+                    <Grid container spacing={2}>
+                        <Grid item xs={12} sx={{ display: 'flex', justifyContent: 'space-between' }}>
+                            <Typography variant="h6" gutterBottom align="left" sx={{
+                                maxWidth: { xs: '100px', sm: '180px', md: '260px', lg: '360px' },
+                                whiteSpace: 'nowrap',
+                                overflow: 'hidden',
+                                textOverflow: 'ellipsis',
+                            }}>
+                                {Common.camelToPascalWithSpaces(translate('table.field.integrationRecord.namespace'))}: {record.namespace}
+                            </Typography>
+                            {/*  inherit, primary, secondary, textPrimary, textSecondary, error */}
+                            <Typography variant="h6" gutterBottom align="right" >
+                                ID: {record.id}
+                            </Typography>
+                        </Grid>
+                    </Grid>
+                    <Grid container spacing={2}>
+                        <Grid item xs={12} container alignContent="flex-end">
+                            <Typography variant="caption" color="textSecondary" sx={{ wordWrap: 'break-word', wordBreak: 'break-all' }}>
+                                {Common.camelToPascalWithSpaces(translate('common.field.memo'))}:{record.memo}
+                            </Typography>
+                        </Grid>
+                    </Grid>
+                    <Box height={20}>&nbsp;</Box>
+                    <Grid container spacing={2}>
+                        <Grid item xs={6}>
+                            <PanelTypography
+                                title="table.field.integrationRecord.uuid" 
+                                property={record.uuid}
+                            />
+                        </Grid>
+                        <Grid item xs={6}>
+                            <PanelTypography
+                                title="table.field.integrationRecord.namespace" 
+                                property={record.namespace}
+                            />
+                        </Grid>
+                        <Grid item xs={6}>
+                            <PanelTypography
+                                title="table.field.integrationRecord.url" 
+                                property={record.url}
+                            />
+                        </Grid>
+                        <Grid item xs={6}>
+                            <PanelTypography
+                                title="table.field.integrationRecord.appkey" 
+                                property={record.appkey}
+                            />
+                        </Grid>
+                        <Grid item xs={6}>
+                            <PanelTypography
+                                title="table.field.integrationRecord.caller" 
+                                property={record.caller}
+                            />
+                        </Grid>
+                        <Grid item xs={6}>
+                            <PanelTypography
+                                title="table.field.integrationRecord.direction" 
+                                property={record.direction$}
+                            />
+                        </Grid>
+                        <Grid item xs={6}>
+                            <PanelTypography
+                                title="table.field.integrationRecord.timestamp" 
+                                property={record.timestamp}
+                            />
+                        </Grid>
+                        <Grid item xs={6}>
+                            <PanelTypography
+                                title="table.field.integrationRecord.clientIp" 
+                                property={record.clientIp}
+                            />
+                        </Grid>
+                        <Grid item xs={6}>
+                            <PanelTypography
+                                title="table.field.integrationRecord.request" 
+                                property={record.request}
+                            />
+                        </Grid>
+                        <Grid item xs={6}>
+                            <PanelTypography
+                                title="table.field.integrationRecord.response" 
+                                property={record.response}
+                            />
+                        </Grid>
+                        <Grid item xs={6}>
+                            <PanelTypography
+                                title="table.field.integrationRecord.err" 
+                                property={record.err}
+                            />
+                        </Grid>
+                        <Grid item xs={6}>
+                            <PanelTypography
+                                title="table.field.integrationRecord.result" 
+                                property={record.result$}
+                            />
+                        </Grid>
+                        <Grid item xs={6}>
+                            <PanelTypography
+                                title="table.field.integrationRecord.costMs" 
+                                property={record.costMs}
+                            />
+                        </Grid>
+
+                    </Grid>
+                </CardContent>
+            </Card >
+        </>
+    );
+};
+
+export default IntegrationRecordPanel;
diff --git a/zy-acs-flow/src/page/integrationRecord/index.jsx b/zy-acs-flow/src/page/integrationRecord/index.jsx
new file mode 100644
index 0000000..c4f5b87
--- /dev/null
+++ b/zy-acs-flow/src/page/integrationRecord/index.jsx
@@ -0,0 +1,18 @@
+import React, { useState, useRef, useEffect, useMemo } from "react";
+import {
+    ListGuesser,
+    EditGuesser,
+    ShowGuesser,
+} from "react-admin";
+
+import IntegrationRecordList from "./IntegrationRecordList";
+import IntegrationRecordEdit from "./IntegrationRecordEdit";
+
+export default {
+    list: IntegrationRecordList,
+    edit: IntegrationRecordEdit,
+    show: ShowGuesser,
+    recordRepresentation: (record) => {
+        return `${record.namespace}`
+    }
+};
diff --git a/zy-acs-flow/src/page/loc/LocCreate.jsx b/zy-acs-flow/src/page/loc/LocCreate.jsx
index 3270d8b..afebd46 100644
--- a/zy-acs-flow/src/page/loc/LocCreate.jsx
+++ b/zy-acs-flow/src/page/loc/LocCreate.jsx
@@ -30,6 +30,7 @@
 import DialogCloseButton from "../components/DialogCloseButton";
 import StatusSelectInput from "../components/StatusSelectInput";
 import MemoInput from "../components/MemoInput";
+import { compDirectChoices } from "./compDirect";
 
 const LocCreate = (props) => {
     const { open, setOpen } = props;
@@ -156,10 +157,7 @@
                                     <SelectInput
                                         label="table.field.loc.compDirect"
                                         source="compDirect"
-                                        choices={[
-                                            { id: 1, name: '澶т簬' },
-                                            { id: 0, name: '灏忎簬' },
-                                        ]}
+                                        choices={compDirectChoices}
                                     />
                                 </Grid>
                                 <Grid item xs={6} display="flex" gap={1}>
diff --git a/zy-acs-flow/src/page/loc/LocEdit.jsx b/zy-acs-flow/src/page/loc/LocEdit.jsx
index 3867ad0..f502249 100644
--- a/zy-acs-flow/src/page/loc/LocEdit.jsx
+++ b/zy-acs-flow/src/page/loc/LocEdit.jsx
@@ -28,6 +28,7 @@
 import CustomerTopToolBar from "../components/EditTopToolBar";
 import MemoInput from "../components/MemoInput";
 import StatusSelectInput from "../components/StatusSelectInput";
+import { compDirectChoices } from "./compDirect";
 
 const FormToolbar = () => {
     const { getValues } = useFormContext();
@@ -133,10 +134,7 @@
                             <SelectInput
                                 label="table.field.loc.compDirect"
                                 source="compDirect"
-                                choices={[
-                                    { id: 1, name: '澶т簬' },
-                                    { id: 0, name: '灏忎簬' },
-                                ]}
+                                choices={compDirectChoices}
                             />
                         </Stack>
                         <Stack direction='row' gap={2}>
diff --git a/zy-acs-flow/src/page/loc/LocInit.jsx b/zy-acs-flow/src/page/loc/LocInit.jsx
index d57670b..1ca4cb3 100644
--- a/zy-acs-flow/src/page/loc/LocInit.jsx
+++ b/zy-acs-flow/src/page/loc/LocInit.jsx
@@ -28,6 +28,7 @@
 import DialogCloseButton from "../components/DialogCloseButton";
 import CheckIcon from '@mui/icons-material/Check';
 import request from '@/utils/request'
+import { compDirectChoices } from "./compDirect";
 
 const LocInit = (props) => {
     const { open, setOpen } = props;
@@ -166,10 +167,7 @@
                                 <SelectInput
                                     label="table.field.loc.compDirect"
                                     source="compDirect"
-                                    choices={[
-                                        { id: 1, name: '澶т簬' },
-                                        { id: 0, name: '灏忎簬' },
-                                    ]}
+                                    choices={compDirectChoices}
                                 />
                             </Grid>
                             <Grid item xs={6} display="flex" gap={1}>
@@ -197,4 +195,4 @@
     )
 }
 
-export default LocInit;
\ No newline at end of file
+export default LocInit;
diff --git a/zy-acs-flow/src/page/loc/LocList.jsx b/zy-acs-flow/src/page/loc/LocList.jsx
index 83bdbc5..657c561 100644
--- a/zy-acs-flow/src/page/loc/LocList.jsx
+++ b/zy-acs-flow/src/page/loc/LocList.jsx
@@ -32,6 +32,7 @@
     DeleteButton,
     Button,
     Pagination,
+    FunctionField,
 } from 'react-admin';
 import { Box, Typography, Card, Stack } from '@mui/material';
 import { styled } from '@mui/material/styles';
@@ -49,6 +50,7 @@
 import rowSx from "./rowSx";
 import BulkUpdateButton from "../components/BulkUpdateButton";
 import LocBulkUpdateContent from './LocBulkUpdateContent';
+import { getCompDirectLabel } from './compDirect';
 
 const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({
     '& .css-1vooibu-MuiSvgIcon-root': {
@@ -66,6 +68,7 @@
 }));
 
 const filters = [
+    <SearchInput source="condition" alwaysOn />,
     <TextInput source="locNo" label="table.field.loc.locNo" alwaysOn />,
     <ReferenceInput source="locSts" label="table.field.loc.locSts" reference="locSts" alwaysOn>
         <AutocompleteInput label="table.field.loc.locSts" optionText="name" filterToQuery={(val) => ({ name: val })} />
@@ -73,8 +76,7 @@
     <NumberInput source="row" label="table.field.loc.row" alwaysOn />,
     <NumberInput source="bay" label="table.field.loc.bay" alwaysOn />,
     <NumberInput source="lev" label="table.field.loc.lev" alwaysOn />,
-    <SearchInput source="condition" alwaysOn />,
-    <ReferenceInput source="code" label="table.field.loc.code" reference="code" alwaysOn>
+    <ReferenceInput source="code" label="table.field.loc.code" reference="code">
         <AutocompleteInput label="table.field.loc.code" optionText="data" filterToQuery={(val) => ({ data: val })} />
     </ReferenceInput>,
     <DateInput label='common.time.after' source="timeStart" />,
@@ -156,7 +158,8 @@
                     rowClick={(id, resource, record) => false}
                     expand={() => <LocPanel />}
                     expandSingle={true}
-                    omit={['id', 'locType', 'uuid', 'statusBool', 'updateBy', 'createTime', 'createBy', 'memo']}
+                    omit={['id', 'locType', 'uuid', 'zpallet', 'barcode'
+                        , 'statusBool', 'updateBy', 'createTime', 'createBy', 'memo']}
                     rowSx={rowSx(drawerVal || null)}
                 >
                     <NumberField source="id" />
@@ -170,7 +173,6 @@
                     <ReferenceField source="code" label="table.field.loc.code" reference="code" link={false} sortable={false}>
                         <TextField source="data" />
                     </ReferenceField>
-                    {/* <TextField source="compDirect$" label="table.field.loc.compDirect" sortable={false} /> */}
                     <ReferenceField source="locSts" label="table.field.loc.locSts" reference="locSts" link={false} sortable={true}>
                         <TextField source="name" />
                     </ReferenceField>
@@ -178,6 +180,11 @@
                     <NumberField source="bay" label="table.field.loc.bay" />
                     <NumberField source="lev" label="table.field.loc.lev" />
                     <NumberField source="offset" label="table.field.loc.offset" />
+                    <FunctionField
+                        label="table.field.loc.compDirect"
+                        sortable={false}
+                        render={(record) => getCompDirectLabel(translate, record?.compDirect)}
+                    />
                     <TextField source="barcode" label="table.field.loc.barcode" />
                     <TextField source="zpallet" label="table.field.loc.zpallet" />
                     <ReferenceField source="locType" label="table.field.loc.locType" reference="locType" link={false} sortable={false}>
diff --git a/zy-acs-flow/src/page/loc/LocPanel.jsx b/zy-acs-flow/src/page/loc/LocPanel.jsx
index d8a73b8..761be35 100644
--- a/zy-acs-flow/src/page/loc/LocPanel.jsx
+++ b/zy-acs-flow/src/page/loc/LocPanel.jsx
@@ -6,6 +6,7 @@
 } from 'react-admin';
 import PanelTypography from "../components/PanelTypography";
 import * as Common from '@/utils/common'
+import { getCompDirectLabel } from "./compDirect";
 
 const LocPanel = () => {
     const record = useRecordContext();
@@ -73,7 +74,7 @@
                         <Grid item xs={6}>
                             <PanelTypography
                                 title="table.field.loc.compDirect" 
-                                property={record.compDirect$}
+                                property={getCompDirectLabel(translate, record.compDirect)}
                             />
                         </Grid>
                         <Grid item xs={6}>
diff --git a/zy-acs-flow/src/page/loc/compDirect.js b/zy-acs-flow/src/page/loc/compDirect.js
new file mode 100644
index 0000000..697ab1e
--- /dev/null
+++ b/zy-acs-flow/src/page/loc/compDirect.js
@@ -0,0 +1,15 @@
+export const compDirectChoices = [
+    { id: 1, name: 'page.loc.enums.compDirect.left' },
+    { id: 2, name: 'page.loc.enums.compDirect.right' },
+    { id: 3, name: 'page.loc.enums.compDirect.forward' },
+];
+
+export const getCompDirectLabel = (translate, compDirect, fallback = '-') => {
+    const choice = compDirectChoices.find((item) => item.id === compDirect);
+    if (!choice) {
+        return fallback;
+    }
+    return typeof translate === 'function'
+        ? translate(choice.name, { _: fallback })
+        : choice.name;
+};
diff --git a/zy-acs-flow/src/page/sta/StaCreate.jsx b/zy-acs-flow/src/page/sta/StaCreate.jsx
index 848b816..5370934 100644
--- a/zy-acs-flow/src/page/sta/StaCreate.jsx
+++ b/zy-acs-flow/src/page/sta/StaCreate.jsx
@@ -30,6 +30,7 @@
 import DialogCloseButton from "../components/DialogCloseButton";
 import StatusSelectInput from "../components/StatusSelectInput";
 import MemoInput from "../components/MemoInput";
+import { compDirectChoices } from "../loc/compDirect";
 
 const StaCreate = (props) => {
     const { open, setOpen } = props;
@@ -152,7 +153,7 @@
                                         />
                                     </ReferenceInput>
                                 </Grid>
-                                <Grid item xs={4} display="flex" gap={1}>
+                                <Grid item xs={6} display="flex" gap={1}>
                                     <NumberInput
                                         label="table.field.sta.capacity"
                                         source="capacity"
@@ -166,7 +167,7 @@
                                         validate={required()}
                                     />
                                 </Grid> */}
-                                <Grid item xs={4} display="flex" gap={1}>
+                                <Grid item xs={6} display="flex" gap={1}>
                                     <NumberInput
                                         label="table.field.sta.height"
                                         source="height"
@@ -181,7 +182,7 @@
                                         validate={[required(), greaterThanZero]}
                                     />
                                 </Grid> */}
-                                <Grid item xs={4} display="flex" gap={1}>
+                                <Grid item xs={6} display="flex" gap={1}>
                                     <NumberInput
                                         label="table.field.sta.angle"
                                         source="angle"
@@ -189,6 +190,15 @@
                                     />
                                 </Grid>
                                 <Grid item xs={6} display="flex" gap={1}>
+                                    <SelectInput
+                                        label="table.field.sta.actDir"
+                                        source="actDir"
+                                        choices={compDirectChoices}
+                                        translateChoice
+                                        validate={[required(), greaterThanZero]}
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
                                     <NumberInput
                                         label="table.field.sta.inboundWait"
                                         source="inboundWait"
diff --git a/zy-acs-flow/src/page/sta/StaEdit.jsx b/zy-acs-flow/src/page/sta/StaEdit.jsx
index d74a6ed..e79d2da 100644
--- a/zy-acs-flow/src/page/sta/StaEdit.jsx
+++ b/zy-acs-flow/src/page/sta/StaEdit.jsx
@@ -28,6 +28,7 @@
 import CustomerTopToolBar from "../components/EditTopToolBar";
 import MemoInput from "../components/MemoInput";
 import StatusSelectInput from "../components/StatusSelectInput";
+import { compDirectChoices } from "../loc/compDirect";
 
 const FormToolbar = () => {
     const { getValues } = useFormContext();
@@ -136,27 +137,34 @@
                                 validate={[required(), greaterThanZero]}
                             />
                             <NumberInput
+                                label="table.field.sta.height"
+                                source="height"
+                                validate={[required(), greaterThanZero]}
+                            />
+                            {/* <NumberInput
+                                label="table.field.sta.depth"
+                                source="depth"
+                                helperText={translate('page.sta.depthHint')}
+                                validate={[required(), greaterThanZero]}
+                            /> */}
+                        </Stack>
+                        <Stack direction='row' gap={2}>
+                            <NumberInput
                                 label="table.field.sta.angle"
                                 source="angle"
+                                validate={[required(), greaterThanZero]}
+                            />
+                            <SelectInput
+                                label="table.field.sta.actDir"
+                                source="actDir"
+                                choices={compDirectChoices}
+                                translateChoice
                                 validate={[required(), greaterThanZero]}
                             />
                             {/* <NumberInput
                                 label="table.field.sta.offset"
                                 source="offset"
                                 validate={required()}
-                            /> */}
-                            <NumberInput
-                                label="table.field.sta.height"
-                                source="height"
-                                validate={[required(), greaterThanZero]}
-                            />
-                        </Stack>
-                        <Stack direction='row' gap={2}>
-                            {/* <NumberInput
-                                label="table.field.sta.depth"
-                                source="depth"
-                                helperText={translate('page.sta.depthHint')}
-                                validate={[required(), greaterThanZero]}
                             /> */}
                         </Stack>
                         <Stack direction='row' gap={2}>
diff --git a/zy-acs-flow/src/page/sta/StaList.jsx b/zy-acs-flow/src/page/sta/StaList.jsx
index baf38c5..6d91a9a 100644
--- a/zy-acs-flow/src/page/sta/StaList.jsx
+++ b/zy-acs-flow/src/page/sta/StaList.jsx
@@ -30,6 +30,7 @@
     ReferenceArrayInput,
     AutocompleteInput,
     DeleteButton,
+    FunctionField,
 } from 'react-admin';
 import { Box, Typography, Card, Stack } from '@mui/material';
 import { styled } from '@mui/material/styles';
@@ -43,6 +44,7 @@
 import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting';
 import * as Common from '@/utils/common';
 import rowSx from "./rowSx";
+import { getCompDirectLabel } from "../loc/compDirect";
 
 const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({
     '& .css-1vooibu-MuiSvgIcon-root': {
@@ -134,7 +136,7 @@
                     expand={() => <StaPanel />}
                     expandSingle={true}
                     rowSx={rowSx(drawerVal || null)}
-                    omit={['id', 'uuid', 'name', 'offset', 'zpallet', 'depth'
+                    omit={['id', 'uuid', 'name', 'offset', 'zpallet', 'depth', 'capacity'
                         , 'updateTime', 'updateBy', 'createTime', 'createBy', 'memo']}
                 >
                     <NumberField source="id" />
@@ -158,11 +160,16 @@
                     <NumberField source="rsvInCnt" label="table.field.sta.rsvInCnt" />
                     <NumberField source="rsvOutCnt" label="table.field.sta.rsvOutCnt" />
                     <NumberField source="offset" label="table.field.sta.offset" />
-                    <NumberField source="height" label="table.field.sta.height" />
+                    <NumberField source="height" label="table.field.sta.height" sortable={false} />
                     <NumberField source="depth" label="table.field.sta.depth" />
-                    <NumberField source="angle" label="table.field.sta.angle" />
-                    <NumberField source="inboundWait" label="table.field.sta.inboundWait" />
-                    <NumberField source="outboundWait" label="table.field.sta.outboundWait" />
+                    <NumberField source="angle" label="table.field.sta.angle" sortable={false} />
+                    <FunctionField
+                        label="table.field.sta.actDir"
+                        render={(record) => getCompDirectLabel(translate, record?.actDir)}
+                        sortable={false}
+                    />
+                    <NumberField source="inboundWait" label="table.field.sta.inboundWait" sortable={false} />
+                    <NumberField source="outboundWait" label="table.field.sta.outboundWait" sortable={false} />
                     {/* <TextField source="autoing" label="table.field.sta.autoing" />
                     <TextField source="loading" label="table.field.sta.loading" />
                     <TextField source="inEnable" label="table.field.sta.inEnable" />
diff --git a/zy-acs-flow/src/page/sta/StaPanel.jsx b/zy-acs-flow/src/page/sta/StaPanel.jsx
index d73a5bb..382ac5e 100644
--- a/zy-acs-flow/src/page/sta/StaPanel.jsx
+++ b/zy-acs-flow/src/page/sta/StaPanel.jsx
@@ -26,6 +26,7 @@
 } from 'react-admin';
 import { format } from 'date-fns';
 import * as Common from '@/utils/common'
+import { getCompDirectLabel } from "../loc/compDirect";
 
 const STATUS_FIELDS = [
     { key: 'autoing', labelKey: 'table.field.sta.autoing' },
@@ -38,9 +39,14 @@
     { labelKey: 'table.field.sta.zoneId', valueKey: 'zoneId$' },
     { labelKey: 'table.field.sta.staType', valueKey: 'staType$' },
     { labelKey: 'table.field.sta.code', valueKey: 'code$' },
-    { labelKey: 'table.field.sta.capacity', valueKey: 'capacity' },
+    // { labelKey: 'table.field.sta.capacity', valueKey: 'capacity' },
     { labelKey: 'table.field.sta.rsvInCnt', valueKey: 'rsvInCnt' },
     { labelKey: 'table.field.sta.rsvOutCnt', valueKey: 'rsvOutCnt' },
+    { labelKey: 'table.field.sta.angle', valueKey: 'angle' },
+    {
+        labelKey: 'table.field.sta.actDir',
+        getValue: (record, translate) => getCompDirectLabel(translate, record?.actDir),
+    },
     // { labelKey: 'table.field.sta.offset', valueKey: 'offset' },
     { labelKey: 'table.field.sta.height', valueKey: 'height' },
     { labelKey: 'table.field.sta.depth', valueKey: 'depth' },
@@ -148,11 +154,11 @@
                     <Box height={12}>&nbsp;</Box>
 
                     <Grid container spacing={2}>
-                        {INFO_FIELDS.map(({ labelKey, valueKey }) => (
+                        {INFO_FIELDS.map(({ labelKey, valueKey, getValue }) => (
                             <Grid item xs={12} sm={6} md={4} key={labelKey}>
                                 <InfoItem
                                     labelKey={labelKey}
-                                    value={getRecordValue(record, valueKey)}
+                                    value={getValue ? getValue(record, translate) : getRecordValue(record, valueKey)}
                                 />
                             </Grid>
                         ))}
diff --git a/zy-acs-flow/src/page/staReserve/StaReserveList.jsx b/zy-acs-flow/src/page/staReserve/StaReserveList.jsx
index 240026c..a4948d6 100644
--- a/zy-acs-flow/src/page/staReserve/StaReserveList.jsx
+++ b/zy-acs-flow/src/page/staReserve/StaReserveList.jsx
@@ -36,7 +36,7 @@
 import { styled } from '@mui/material/styles';
 import StaReserveCreate from "./StaReserveCreate";
 import StaReservePanel from "./StaReservePanel";
-import EmptyData from "../components/EmptyData";
+import EmptyDataLoader from "../components/EmptyDataLoader";
 import MyCreateButton from "../components/MyCreateButton";
 import MyExportButton from '../components/MyExportButton';
 import PageDrawer from "../components/PageDrawer";
@@ -131,7 +131,7 @@
                     marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                 }}
                 title={"menu.staReserve"}
-                empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
+                empty={<EmptyDataLoader />}
                 filters={filters}
                 sort={{ field: "create_time", order: "desc" }}
                 actions={(
diff --git a/zy-acs-flow/src/page/task/TaskList.jsx b/zy-acs-flow/src/page/task/TaskList.jsx
index b1b4bd3..09e7397 100644
--- a/zy-acs-flow/src/page/task/TaskList.jsx
+++ b/zy-acs-flow/src/page/task/TaskList.jsx
@@ -35,7 +35,7 @@
     useNotify,
     useRefresh,
 } from 'react-admin';
-import { Box, Chip, Card, Stack } from '@mui/material';
+import { Box, Chip, Card, Stack, LinearProgress } from '@mui/material';
 import { styled } from '@mui/material/styles';
 import TaskCreate from "./TaskCreate";
 import TaskPanel from "./TaskPanel";
@@ -70,6 +70,20 @@
         width: 200
     },
 }));
+
+const UPLINK_STATUS_CHOICES = [
+    { id: 'NONE', name: 'page.task.enums.uplinkSts.NONE', color: 'default' },
+    { id: 'PENDING', name: 'page.task.enums.uplinkSts.PENDING', color: 'warning' },
+    { id: 'SENDING', name: 'page.task.enums.uplinkSts.SENDING', color: 'info' },
+    { id: 'SUCCESS', name: 'page.task.enums.uplinkSts.SUCCESS', color: 'success' },
+    { id: 'FAILED', name: 'page.task.enums.uplinkSts.FAILED', color: 'error' },
+    { id: 'SKIPPED', name: 'page.task.enums.uplinkSts.SKIPPED', color: 'secondary' },
+];
+
+const UPLINK_STATUS_MAP = UPLINK_STATUS_CHOICES.reduce((acc, item) => {
+    acc[item.id] = item;
+    return acc;
+}, {});
 
 const filters = [
     // <SearchInput source="condition" alwaysOn />,
@@ -115,6 +129,7 @@
         <AutocompleteInput label="table.field.task.destCode" optionText="data" filterToQuery={(val) => ({ data: val })} />
     </ReferenceInput>,
     <TextInput source="emptyMk" label="table.field.task.emptyMk" />,
+    <SelectInput source="uplinkSts" label="table.field.task.uplinkSts" choices={UPLINK_STATUS_CHOICES} />,
     <TextInput source="zpallet" label="table.field.task.zpallet" />,
     // <TextInput source="phase" label="table.field.task.phase" />,
     <TextInput source="errDesc" label="table.field.task.errDesc" />,
@@ -130,12 +145,12 @@
     />,
 ]
 
-const TaskList = () => {
+const TaskListContent = () => {
     const translate = useTranslate();
     const notify = useNotify();
     const refresh = useRefresh();
-    const [createDialog, setCreateDialog] = useState(false);
-    const [drawerVal, setDrawerVal] = useState(false);
+
+    const { isLoading } = useListContext();
 
     const [taskStsByComplete, setTaskStsByComplete] = useState(null);
     const [taskStsByCancel, setTaskStsByCancel] = useState(null);
@@ -160,6 +175,7 @@
             setTaskStsByCancel(res.data.data[0]?.id);
         })
     }, []);
+
 
     const onComplete = (taskId) => {
         request.get("/task/complete/" + taskId).then(res => {
@@ -190,6 +206,163 @@
     }
 
     return (
+        <Box sx={{ position: 'relative' }}>
+            {isLoading && (
+                <LinearProgress
+                    sx={{
+                        height: "2px",
+                        position: 'absolute',
+                        top: 0,
+                        left: 0,
+                        right: 0,
+                    }}
+                />
+            )}
+            <StyledDatagrid
+                preferenceKey='task'
+                bulkActionButtons={false}
+                rowClick={(id, resource, record) => false}
+                expand={() => <TaskPanel />}
+                expandSingle={true}
+                omit={['id', 'uuid', 'startTime', 'endTime', 'errTime', 'emptyMk', 'zpallet',
+                    'oriSta', 'oriLoc', 'oriCode', 'destSta', 'destLoc', 'destCode', 'errDesc',
+                    'updateTime', 'updateBy', 'ioTime', 'createBy', 'statusBool', 'memo']}
+            >
+                <NumberField source="id" />
+                <TextField source="uuid" label="table.field.task.uuid" sortable={false} />
+                <TextField source="seqNum" label="table.field.task.seqNum" sortable={false} />
+                <ReferenceField source="busId" label="table.field.task.busId" reference="bus" link={false} sortable={false}>
+                    <TextField source="busNo" />
+                </ReferenceField>
+                <ReferenceField source="agvId" label="table.field.task.agvId" reference="agv" link={false} sortable={false}>
+                    <TextField source="uuid" />
+                </ReferenceField>
+                {/* <TextField source="name" label="table.field.task.name" /> */}
+                <ReferenceField source="taskType" label="table.field.task.taskType" reference="taskType" link={false} sortable={false}>
+                    <TextField source="name" />
+                </ReferenceField>
+                {/* <ReferenceField source="taskSts" label="table.field.task.taskSts" reference="taskSts" link={false} sortable={false}>
+                        <TextField source="name" />
+                    </ReferenceField> */}
+                <ReferenceField source="taskSts" label="table.field.task.taskSts" reference="taskSts" link={false} sortable={true}>
+                    <FunctionField render={record => (
+                        <Chip
+                            label={record.name}
+                            variant="outlined"
+                            size="small"
+                            color={getTaskStsChipColor(record.name)}
+                            sx={{ fontSize: '0.75rem' }}
+                        />
+                    )} />
+                    {/* <TextField source="name" /> */}
+                </ReferenceField>
+                <DateField source="ioTime" label="table.field.task.ioTime" showTime sortable={false} />
+                <DateField source="startTime" label="table.field.task.startTime" showTime sortable={false} />
+                <DateField source="endTime" label="table.field.task.endTime" showTime sortable={false} />
+                <DateField source="errTime" label="table.field.task.errTime" showTime sortable={false} />
+                <ReferenceField source="oriSta" label="table.field.task.oriSta" reference="sta" link={false} sortable={false}>
+                    <TextField source="staNo" />
+                </ReferenceField>
+                <ReferenceField source="oriLoc" label="table.field.task.oriLoc" reference="loc" link={false} sortable={false}>
+                    <TextField source="locNo" />
+                </ReferenceField>
+                <ReferenceField source="oriCode" label="table.field.task.oriCode" reference="code" link={false} sortable={false}>
+                    <TextField source="data" />
+                </ReferenceField>
+                <ReferenceField source="destSta" label="table.field.task.destSta" reference="sta" link={false} sortable={false}>
+                    <TextField source="staNo" />
+                </ReferenceField>
+                <ReferenceField source="destLoc" label="table.field.task.destLoc" reference="loc" link={false} sortable={false}>
+                    <TextField source="locNo" />
+                </ReferenceField>
+                <ReferenceField source="destCode" label="table.field.task.destCode" reference="code" link={false} sortable={false}>
+                    <TextField source="data" />
+                </ReferenceField>
+                <TextField source="oriDesc" label="table.field.task.oriDesc" sortable={false} />
+                <TextField source="destDesc" label="table.field.task.destDesc" sortable={false} />
+                <NumberField source="priority" label="table.field.task.priority" sortable={false} />
+                <FunctionField
+                    label="table.field.task.uplinkSts"
+                    sortable={false}
+                    render={record => {
+                        const meta = UPLINK_STATUS_MAP[record?.uplinkSts];
+                        return (
+                            <Chip
+                                label={meta?.name ? translate(meta.name) : translate('common.enums.na')}
+                                variant="outlined"
+                                size="small"
+                                color={meta?.color ?? 'default'}
+                                sx={{ fontSize: '0.75rem' }}
+                            />
+                        );
+                    }}
+                />
+                <TextField source="emptyMk" label="table.field.task.emptyMk" sortable={false} />
+                <TextField source="zpallet" label="table.field.task.zpallet" sortable={false} />
+                <TextField source="errDesc" label="table.field.task.errDesc" sortable={false} />
+
+                <ReferenceField source="updateBy" label="common.field.updateBy" reference="user" link={false} sortable={false}>
+                    <TextField source="nickname" />
+                </ReferenceField>
+                <DateField source="updateTime" label="common.field.updateTime" showTime />
+                <ReferenceField source="createBy" label="common.field.createBy" reference="user" link={false} sortable={false}>
+                    <TextField source="nickname" />
+                </ReferenceField>
+                <DateField source="createTime" label="common.field.createTime" showTime sortable={false} />
+                <BooleanField source="statusBool" label="common.field.status" sortable={false} />
+                <TextField source="memo" label="common.field.memo" sortable={false} />
+                <FunctionField label="common.field.opt" cellClassName="opt" render={record => (
+                    (record.taskSts !== taskStsByComplete && record.taskSts !== taskStsByCancel) && (
+                        <>
+                            <ConfirmButton
+                                label="common.action.complete"
+                                size="small"
+                                color="primary"
+                                startIcon={<CheckIcon />}
+                                sx={{
+                                    padding: '1px',
+                                    fontSize: '.75rem',
+                                    '& .MuiButton-startIcon': {
+                                        marginRight: '2px'
+                                    },
+                                    mr: 1
+                                }}
+                                data={record.seqNum}
+                                onConfirm={() => {
+                                    onComplete(record.id);
+                                }}
+                            />
+                            <ConfirmButton
+                                label="ra.action.cancel"
+                                size="small"
+                                color="error"
+                                startIcon={<ClearIcon />}
+                                sx={{
+                                    padding: '1px',
+                                    fontSize: '.75rem',
+                                    '& .MuiButton-startIcon': {
+                                        marginRight: '1.5px'
+                                    },
+                                }}
+                                data={record.seqNum}
+                                onConfirm={() => {
+                                    onCancel(record.id);
+                                }}
+                            />
+                        </>
+                    )
+                )} />
+            </StyledDatagrid>
+        </Box>
+    )
+}
+
+
+const TaskList = () => {
+    const [createDialog, setCreateDialog] = useState(false);
+    const [drawerVal, setDrawerVal] = useState(false);
+
+    return (
         <Box display="flex">
             <List
                 sx={{
@@ -216,125 +389,7 @@
                 perPage={25}
                 aside={<TaskListAside />}
             >
-                <StyledDatagrid
-                    preferenceKey='task'
-                    bulkActionButtons={false}
-                    rowClick={(id, resource, record) => false}
-                    expand={() => <TaskPanel />}
-                    expandSingle={true}
-                    omit={['id', 'uuid', 'startTime', 'endTime', 'errTime', 'emptyMk', 'zpallet',
-                        'oriSta', 'oriLoc', 'oriCode', 'destSta', 'destLoc', 'destCode', 'errDesc',
-                        'updateTime', 'updateBy', 'ioTime', 'createBy', 'statusBool', 'memo']}
-                >
-                    <NumberField source="id" />
-                    <TextField source="uuid" label="table.field.task.uuid" sortable={false} />
-                    <TextField source="seqNum" label="table.field.task.seqNum" sortable={false} />
-                    <ReferenceField source="busId" label="table.field.task.busId" reference="bus" link={false} sortable={false}>
-                        <TextField source="busNo" />
-                    </ReferenceField>
-                    <ReferenceField source="agvId" label="table.field.task.agvId" reference="agv" link={false} sortable={false}>
-                        <TextField source="uuid" />
-                    </ReferenceField>
-                    {/* <TextField source="name" label="table.field.task.name" /> */}
-                    <ReferenceField source="taskType" label="table.field.task.taskType" reference="taskType" link={false} sortable={false}>
-                        <TextField source="name" />
-                    </ReferenceField>
-                    {/* <ReferenceField source="taskSts" label="table.field.task.taskSts" reference="taskSts" link={false} sortable={false}>
-                        <TextField source="name" />
-                    </ReferenceField> */}
-                    <ReferenceField source="taskSts" label="table.field.task.taskSts" reference="taskSts" link={false} sortable={true}>
-                        <FunctionField render={record => (
-                            <Chip
-                                label={record.name}
-                                variant="outlined"
-                                size="small"
-                                color={getTaskStsChipColor(record.name)}
-                                sx={{ fontSize: '0.75rem' }}
-                            />
-                        )} />
-                        {/* <TextField source="name" /> */}
-                    </ReferenceField>
-                    <DateField source="ioTime" label="table.field.task.ioTime" showTime sortable={false} />
-                    <DateField source="startTime" label="table.field.task.startTime" showTime sortable={false} />
-                    <DateField source="endTime" label="table.field.task.endTime" showTime sortable={false} />
-                    <DateField source="errTime" label="table.field.task.errTime" showTime sortable={false} />
-                    <ReferenceField source="oriSta" label="table.field.task.oriSta" reference="sta" link={false} sortable={false}>
-                        <TextField source="staNo" />
-                    </ReferenceField>
-                    <ReferenceField source="oriLoc" label="table.field.task.oriLoc" reference="loc" link={false} sortable={false}>
-                        <TextField source="locNo" />
-                    </ReferenceField>
-                    <ReferenceField source="oriCode" label="table.field.task.oriCode" reference="code" link={false} sortable={false}>
-                        <TextField source="data" />
-                    </ReferenceField>
-                    <ReferenceField source="destSta" label="table.field.task.destSta" reference="sta" link={false} sortable={false}>
-                        <TextField source="staNo" />
-                    </ReferenceField>
-                    <ReferenceField source="destLoc" label="table.field.task.destLoc" reference="loc" link={false} sortable={false}>
-                        <TextField source="locNo" />
-                    </ReferenceField>
-                    <ReferenceField source="destCode" label="table.field.task.destCode" reference="code" link={false} sortable={false}>
-                        <TextField source="data" />
-                    </ReferenceField>
-                    <TextField source="oriDesc" label="table.field.task.oriDesc" sortable={false} />
-                    <TextField source="destDesc" label="table.field.task.destDesc" sortable={false} />
-                    <NumberField source="priority" label="table.field.task.priority" sortable={false} />
-                    <TextField source="emptyMk" label="table.field.task.emptyMk" sortable={false} />
-                    <TextField source="zpallet" label="table.field.task.zpallet" sortable={false} />
-                    <TextField source="errDesc" label="table.field.task.errDesc" sortable={false} />
-
-                    <ReferenceField source="updateBy" label="common.field.updateBy" reference="user" link={false} sortable={false}>
-                        <TextField source="nickname" />
-                    </ReferenceField>
-                    <DateField source="updateTime" label="common.field.updateTime" showTime />
-                    <ReferenceField source="createBy" label="common.field.createBy" reference="user" link={false} sortable={false}>
-                        <TextField source="nickname" />
-                    </ReferenceField>
-                    <DateField source="createTime" label="common.field.createTime" showTime sortable={false} />
-                    <BooleanField source="statusBool" label="common.field.status" sortable={false} />
-                    <TextField source="memo" label="common.field.memo" sortable={false} />
-                    <FunctionField label="common.field.opt" cellClassName="opt" render={record => (
-                        (record.taskSts !== taskStsByComplete && record.taskSts !== taskStsByCancel) && (
-                            <>
-                                <ConfirmButton
-                                    label="common.action.complete"
-                                    size="small"
-                                    color="primary"
-                                    startIcon={<CheckIcon />}
-                                    sx={{
-                                        padding: '1px',
-                                        fontSize: '.75rem',
-                                        '& .MuiButton-startIcon': {
-                                            marginRight: '2px'
-                                        },
-                                        mr: 1
-                                    }}
-                                    data={record.seqNum}
-                                    onConfirm={() => {
-                                        onComplete(record.id);
-                                    }}
-                                />
-                                <ConfirmButton
-                                    label="ra.action.cancel"
-                                    size="small"
-                                    color="error"
-                                    startIcon={<ClearIcon />}
-                                    sx={{
-                                        padding: '1px',
-                                        fontSize: '.75rem',
-                                        '& .MuiButton-startIcon': {
-                                            marginRight: '1.5px'
-                                        },
-                                    }}
-                                    data={record.seqNum}
-                                    onConfirm={() => {
-                                        onCancel(record.id);
-                                    }}
-                                />
-                            </>
-                        )
-                    )} />
-                </StyledDatagrid>
+                <TaskListContent drawerVal={drawerVal} />
             </List>
             <TaskCreate
                 open={createDialog}
diff --git a/zy-acs-flow/src/page/task/TaskListAside.jsx b/zy-acs-flow/src/page/task/TaskListAside.jsx
index da76b14..00d0eca 100644
--- a/zy-acs-flow/src/page/task/TaskListAside.jsx
+++ b/zy-acs-flow/src/page/task/TaskListAside.jsx
@@ -51,7 +51,7 @@
                 mt: 8,
                 alignSelf: 'flex-start',
                 border: theme[0] === 'light' && '1px solid #e0e0e3',
-                width: 255
+                width: 210
             }}
         >
             <CardContent>
diff --git a/zy-acs-framework/src/main/java/com/zy/acs/framework/annotations/IntegrationAuth.java b/zy-acs-framework/src/main/java/com/zy/acs/framework/annotations/IntegrationAuth.java
new file mode 100644
index 0000000..f3e458f
--- /dev/null
+++ b/zy-acs-framework/src/main/java/com/zy/acs/framework/annotations/IntegrationAuth.java
@@ -0,0 +1,21 @@
+package com.zy.acs.framework.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.TYPE,ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface IntegrationAuth {
+
+	Auth value() default Auth.CHECK;
+
+	String memo() default "";
+
+	public enum Auth{
+		CHECK,
+		NONE
+	}
+
+}
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/common/CodeBuilder.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/common/CodeBuilder.java
index c43b26e..46f5596 100644
--- a/zy-acs-manager/src/main/java/com/zy/acs/manager/common/CodeBuilder.java
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/common/CodeBuilder.java
@@ -22,8 +22,8 @@
 //        generator.username="sa";priority
 //        generator.password="Zoneyung@zy56$";
 
-        generator.table="man_lane";
-        generator.tableDesc="Lane";
+        generator.table="man_integration_record";
+        generator.tableDesc="Integration Record";
         generator.packagePath="com.zy.acs.manager.manager";
 
         generator.build();
@@ -55,6 +55,7 @@
  * TRUNCATE man_jam;
  * TRUNCATE man_action;
  * TRUNCATE man_sta_reserve;
+ * TRUNCATE man_integration_record;
  *
  * TRUNCATE man_code;
  * TRUNCATE man_code_gap;
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/common/config/ConveyorProperties.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/common/config/ConveyorProperties.java
index 438e4f2..ff377ba 100644
--- a/zy-acs-manager/src/main/java/com/zy/acs/manager/common/config/ConveyorProperties.java
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/common/config/ConveyorProperties.java
@@ -1,5 +1,6 @@
 package com.zy.acs.manager.common.config;
 
+import lombok.Data;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 import org.springframework.context.annotation.Configuration;
 
@@ -10,6 +11,7 @@
  * 杈撻�佺嚎plc绯荤粺閰嶇疆
  * Created by luxiaotao on 2018/10/15
  */
+@Data
 @Configuration
 @ConfigurationProperties(prefix = "convey-plc")
 public class ConveyorProperties {
@@ -28,27 +30,9 @@
 
     private Integer port;
 
-    public static String getHostName() {
-        return HOST_NAME;
-    }
+    private String url;
 
-    public static void setHostName(String hostName) {
-        HOST_NAME = hostName;
-    }
+    // millisecond
+    private Integer timeout = 15 * 1000;
 
-    public String getHost() {
-        return host;
-    }
-
-    public void setHost(String host) {
-        this.host = host;
-    }
-
-    public Integer getPort() {
-        return port;
-    }
-
-    public void setPort(Integer port) {
-        this.port = port;
-    }
 }
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/common/config/IntegrationRecordAdvice.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/common/config/IntegrationRecordAdvice.java
new file mode 100644
index 0000000..6a243c4
--- /dev/null
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/common/config/IntegrationRecordAdvice.java
@@ -0,0 +1,84 @@
+package com.zy.acs.manager.common.config;
+
+import com.alibaba.fastjson.JSON;
+import com.zy.acs.framework.common.Cools;
+import com.zy.acs.framework.common.R;
+import com.zy.acs.manager.common.utils.IpTools;
+import com.zy.acs.manager.manager.service.IntegrationRecordService;
+import lombok.extern.slf4j.Slf4j;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.MethodParameter;
+import org.springframework.http.MediaType;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.http.server.ServerHttpRequest;
+import org.springframework.http.server.ServerHttpResponse;
+import org.springframework.http.server.ServletServerHttpRequest;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+
+@Slf4j
+//@ControllerAdvice
+public class IntegrationRecordAdvice implements ResponseBodyAdvice<Object> {
+
+    @Autowired
+    private IntegrationRecordService integrationRecordService;
+
+    @Override
+    public boolean supports(@NotNull MethodParameter methodParameter, @NotNull Class<? extends HttpMessageConverter<?>> aClass) {
+        return true;
+    }
+
+    @Override
+    public Object beforeBodyWrite(Object o
+            , @NotNull MethodParameter methodParameter
+            , @NotNull MediaType mediaType
+            , @NotNull Class<? extends HttpMessageConverter<?>> aClass
+            , @NotNull ServerHttpRequest serverHttpRequest
+            , @NotNull ServerHttpResponse serverHttpResponse) {
+        if (serverHttpRequest instanceof ServletServerHttpRequest) {
+            HttpServletRequest request = ((ServletServerHttpRequest) serverHttpRequest).getServletRequest();
+            Object appAuth = request.getAttribute("appAuth");
+            if (appAuth != null) {
+                if (o instanceof R) {
+                    String appkey = request.getHeader("appkey");
+                    Object reqCache = request.getAttribute("cache");
+                    if (!Cools.isEmpty(appkey)) {
+                        // 淇濆瓨鎺ュ彛鏃ュ織
+//                        apiLogService.save(
+//                                String.valueOf(appAuth),
+//                                request.getRequestURI(),
+//                                appkey,
+//                                IpTools.gainRealIp(request),
+//                                reqCache==null?"": JSON.toJSONString(reqCache),
+//                                JSON.toJSONString(o),
+//                                String.valueOf(((R) o).get("code")).equalsIgnoreCase("200")
+//                        );
+                    }
+                }
+            }
+        }
+        return o;
+    }
+
+    public static String json(HttpServletRequest request) {
+        try {
+            BufferedReader streamReader = new BufferedReader( new InputStreamReader(request.getInputStream(), StandardCharsets.UTF_8));
+            StringBuilder sb = new StringBuilder();
+            String inputStr;
+            while ((inputStr = streamReader.readLine()) != null) {
+                sb.append(inputStr);
+            }
+            return sb.toString();
+        } catch (Exception e) {
+            log.error(e.getMessage());
+            return "";
+        }
+    }
+
+}
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/common/config/UplinkProperties.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/common/config/UplinkProperties.java
new file mode 100644
index 0000000..0ebee69
--- /dev/null
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/common/config/UplinkProperties.java
@@ -0,0 +1,40 @@
+package com.zy.acs.manager.common.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * 涓婃父鏈嶅姟绯荤粺閰嶇疆
+ * Created by luxiaotao on 2018/10/15
+ */
+@Data
+@Configuration
+@ConfigurationProperties(prefix = "uplink")
+public class UplinkProperties {
+
+    public static String HOST_NAME;
+
+    static {
+        try {
+            HOST_NAME = InetAddress.getLocalHost().getHostName();
+        } catch (UnknownHostException e) {
+            System.err.println("find hostname err");
+        }
+    }
+
+    private Boolean enabled;
+
+    private String host;
+
+    private Integer port;
+
+    private String url;
+
+    // millisecond
+    private Integer timeout = 60 * 1000;
+
+}
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/common/constant/Constants.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/common/constant/Constants.java
index 230bd05..289941d 100644
--- a/zy-acs-manager/src/main/java/com/zy/acs/manager/common/constant/Constants.java
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/common/constant/Constants.java
@@ -6,8 +6,14 @@
  */
 public class Constants {
 
+    public static final String UPLINK = "UPLINK";
+
     public static final String HANDLE = "HANDLE";
 
+    public static final String LIMIT_ONE = "limit 1";
+
+    public static final String RCS = "RCS";
+
     /**
      * 榛樿鎴愬姛鐮�
      */
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/common/domain/TaskBoolDto.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/common/domain/TaskBoolDto.java
new file mode 100644
index 0000000..108def5
--- /dev/null
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/common/domain/TaskBoolDto.java
@@ -0,0 +1,28 @@
+package com.zy.acs.manager.common.domain;
+
+import lombok.Data;
+
+@Data
+public class TaskBoolDto {
+
+    private String taskNo;
+
+    private Boolean success;
+
+    private String msg;
+
+    public TaskBoolDto() {
+    }
+
+    public TaskBoolDto(String taskNo, Boolean success) {
+        this.taskNo = taskNo;
+        this.success = success;
+    }
+
+    public TaskBoolDto(String taskNo, Boolean success, String msg) {
+        this.taskNo = taskNo;
+        this.success = success;
+        this.msg = msg;
+    }
+
+}
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/common/domain/TaskDto.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/common/domain/TaskDto.java
index 0ff61bf..5e087da 100644
--- a/zy-acs-manager/src/main/java/com/zy/acs/manager/common/domain/TaskDto.java
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/common/domain/TaskDto.java
@@ -8,7 +8,7 @@
 @Data
 public class TaskDto {
 
-    private String seqNum;
+    private String taskNo;
 
     private String oriLoc;
 
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/common/utils/ExcelUtil.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/common/utils/ExcelUtil.java
index f7f47b6..b7f3266 100644
--- a/zy-acs-manager/src/main/java/com/zy/acs/manager/common/utils/ExcelUtil.java
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/common/utils/ExcelUtil.java
@@ -2,10 +2,10 @@
 
 import com.zy.acs.framework.common.Cools;
 import io.swagger.annotations.ApiModelProperty;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.apache.poi.ss.usermodel.Row;
 import org.apache.poi.ss.usermodel.Sheet;
 import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
@@ -24,19 +24,24 @@
     public static void build(Workbook workbook, HttpServletResponse response) {
         response.reset();
         Http.cors(response);
-        response.setContentType("application/octet-stream; charset=utf-8");
+
+        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; charset=utf-8");
+
         try {
-            response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode("export", "UTF-8"));
+            response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode("export.xlsx", "UTF-8"));
             workbook.write(response.getOutputStream());
+            workbook.close();
+
         } catch (IOException ignore) {}
     }
 
     public static <T> Workbook create(List<T> list, Class<T> clz) {
-        HSSFWorkbook workbook = new HSSFWorkbook();
+        XSSFWorkbook workbook = new XSSFWorkbook();
         Sheet sheet = workbook.createSheet(clz.getSimpleName());
 
         Row header = sheet.createRow(0);
         Field[] fields = Cools.getAllFields(clz);
+
         int headerIdx = 0;
         for (Field field : fields) {
             if (Modifier.isFinal(field.getModifiers())
@@ -44,6 +49,7 @@
                     || Modifier.isTransient(field.getModifiers())) {
                 continue;
             }
+
             String memo = "Undefined";
             if (field.isAnnotationPresent(ApiModelProperty.class)) {
                 memo = field.getAnnotation(ApiModelProperty.class).value();
@@ -83,7 +89,7 @@
             }
         }
 
-        for (int i = 0; i <= fields.length; i++) {
+        for (int i = 0; i <= headerIdx; i++) {
             sheet.autoSizeColumn(i);
         }
 
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/common/utils/HttpGo.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/common/utils/HttpGo.java
index 0bc5e84..73f1d69 100644
--- a/zy-acs-manager/src/main/java/com/zy/acs/manager/common/utils/HttpGo.java
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/common/utils/HttpGo.java
@@ -264,6 +264,16 @@
         }
     }
 
+    // ======================== tools ========================
+    public String buildUrl(String host, Integer port, String path) {
+        return buildUrl(host, port, path, false);
+    }
+
+    public String buildUrl(String host, Integer port, String path, boolean ssl) {
+        String p = (path == null) ? "" : (path.startsWith("/") ? path : ("/" + path));
+        return (ssl ? "https" : "http") + "://" + host + ":" + port + p;
+    }
+
     // ===================== Demo (main) =====================
 
     public static void main(String[] args) throws Exception {
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/core/HandlerController.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/HandlerController.java
index ce8ef78..2e52cda 100644
--- a/zy-acs-manager/src/main/java/com/zy/acs/manager/core/HandlerController.java
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/HandlerController.java
@@ -9,6 +9,7 @@
 import com.zy.acs.framework.common.R;
 import com.zy.acs.framework.common.SnowflakeIdWorker;
 import com.zy.acs.manager.common.annotation.OperationLog;
+import com.zy.acs.manager.common.config.UplinkProperties;
 import com.zy.acs.manager.common.domain.param.HandlerPublishParam;
 import com.zy.acs.manager.common.exception.BusinessException;
 import com.zy.acs.manager.core.service.*;
@@ -18,6 +19,7 @@
 import com.zy.acs.manager.manager.enums.*;
 import com.zy.acs.manager.manager.service.*;
 import com.zy.acs.manager.system.controller.BaseController;
+import com.zy.acs.manager.system.service.ConfigService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.jdbc.core.JdbcTemplate;
@@ -64,7 +66,7 @@
     @Autowired
     private StaService staService;
     @Autowired
-    private TrafficService trafficService;
+    private UplinkProperties uplinkProperties;
     @Autowired
     private ThreadPoolRegulator threadPoolRegulator;
     @Autowired
@@ -77,6 +79,8 @@
     private StaReserveService staReserveService;
     @Autowired
     private AgvAreaDispatcher agvAreaDispatcher;
+    @Autowired
+    private ConfigService configService;
 
     @PreAuthorize("hasAuthority('manager:agv:update')")
     @OperationLog("Locate All Agv")
@@ -140,6 +144,7 @@
             return R.error();
         }
 
+        Boolean maintainLocSts = configService.getVal("maintainLocSts", Boolean.class);
         Date now = new Date();
         Agv agv = agvService.selectByUuid(param.getAgvNo());
         AgvDetail agvDetail = agvDetailService.selectByAgvId(agv.getId());
@@ -164,13 +169,13 @@
         Task task = new Task();
         task.setAgvId(agv.getId());
         task.setUuid(String.valueOf(snowflakeIdWorker.nextId()).substring(3));
-        List<Task> lastTasks = taskService.list(new LambdaQueryWrapper<Task>().orderByDesc(Task::getId));
+//        List<Task> lastTasks = taskService.list(new LambdaQueryWrapper<Task>().orderByDesc(Task::getId));
 //        task.setSeqNum(Utils.generateSeqNum(Cools.isEmpty(lastTasks)?null:lastTasks.get(0).getSeqNum()));
         task.setSeqNum(Base62.encode(snowflakeIdWorker.nextId()));
 
         task.setTaskType(param.getTaskMode().val());
         task.setTaskSts(TaskStsType.WAITING.val());
-
+        task.setUplinkSts(uplinkProperties.getEnabled() ? TaskUplinkStateType.PENDING.toString() : TaskUplinkStateType.SKIPPED.toString());
         task.setPriority(999);
         task.setIoTime(now);
         task.setStartTime(now);
@@ -232,13 +237,15 @@
 //                    throw new BusinessException("AGV " + agv.getUuid() + " failed to reach target code " + oriLoc.getCode$());
                     throw new BusinessException("AGV銆�" + agv.getUuid() + "銆戞棤娉曞埌杈捐捣濮嬪簱浣嶃��" + oriLoc.getLocNo() + "銆�");
                 }
-                if (!oriLoc.getLocSts().equals(LocStsType.STOCK.val())) {
-                    throw new BusinessException("oriLoc锛�" + oriLoc.getLocNo() + " 涓嶆槸鍦ㄥ簱鐘舵��");
-                }
-                oriLoc.setLocSts(LocStsType.PAKOUT.val());
-                oriLoc.setUpdateTime(now);
-                if (!locService.updateById(oriLoc)) {
-                    throw new BusinessException("oriLoc锛�" + oriLoc.getLocNo() + " 淇敼搴撲綅鐘舵�佸け璐�");
+                if (maintainLocSts) {
+                    if (!oriLoc.getLocSts().equals(LocStsType.STOCK.val())) {
+                        throw new BusinessException("oriLoc锛�" + oriLoc.getLocNo() + " 涓嶆槸鍦ㄥ簱鐘舵��");
+                    }
+                    oriLoc.setLocSts(LocStsType.PAKOUT.val());
+                    oriLoc.setUpdateTime(now);
+                    if (!locService.updateById(oriLoc)) {
+                        throw new BusinessException("oriLoc锛�" + oriLoc.getLocNo() + " 淇敼搴撲綅鐘舵�佸け璐�");
+                    }
                 }
 
                 // destLoc
@@ -255,13 +262,15 @@
 //                    throw new BusinessException("AGV " + agv.getUuid() + " failed to reach target code " + destLoc.getCode$());
                     throw new BusinessException("AGV銆�" + agv.getUuid() + "銆戞棤娉曞埌杈剧洰鏍囧簱浣嶃��" + destLoc.getLocNo() + "銆�");
                 }
-                if (!destLoc.getLocSts().equals(LocStsType.IDLE.val())) {
-                    throw new BusinessException("destLoc锛�" + destLoc.getLocNo() + " 涓嶆槸绌洪棽鐘舵��");
-                }
-                destLoc.setLocSts(LocStsType.PAKIN.val());
-                destLoc.setUpdateTime(now);
-                if (!locService.updateById(destLoc)) {
-                    throw new BusinessException("destLoc锛�" + destLoc.getLocNo() + " 淇敼搴撲綅鐘舵�佸け璐�");
+                if (maintainLocSts) {
+                    if (!destLoc.getLocSts().equals(LocStsType.IDLE.val())) {
+                        throw new BusinessException("destLoc锛�" + destLoc.getLocNo() + " 涓嶆槸绌洪棽鐘舵��");
+                    }
+                    destLoc.setLocSts(LocStsType.PAKIN.val());
+                    destLoc.setUpdateTime(now);
+                    if (!locService.updateById(destLoc)) {
+                        throw new BusinessException("destLoc锛�" + destLoc.getLocNo() + " 淇敼搴撲綅鐘舵�佸け璐�");
+                    }
                 }
 
                 // task
@@ -285,13 +294,15 @@
 //                    throw new BusinessException("AGV " + agv.getUuid() + " failed to reach target code " + oriLoc.getCode$());
                     throw new BusinessException("AGV銆�" + agv.getUuid() + "銆戞棤娉曞埌杈捐捣濮嬪簱浣嶃��" + oriLoc.getLocNo() + "銆�");
                 }
-                if (!oriLoc.getLocSts().equals(LocStsType.STOCK.val())) {
-                    throw new BusinessException("oriLoc锛�" + oriLoc.getLocNo() + " 涓嶆槸鍦ㄥ簱鐘舵��");
-                }
-                oriLoc.setLocSts(LocStsType.PAKOUT.val());
-                oriLoc.setUpdateTime(now);
-                if (!locService.updateById(oriLoc)) {
-                    throw new BusinessException("oriLoc锛�" + oriLoc.getLocNo() + " 淇敼搴撲綅鐘舵�佸け璐�");
+                if (maintainLocSts) {
+                    if (!oriLoc.getLocSts().equals(LocStsType.STOCK.val())) {
+                        throw new BusinessException("oriLoc锛�" + oriLoc.getLocNo() + " 涓嶆槸鍦ㄥ簱鐘舵��");
+                    }
+                    oriLoc.setLocSts(LocStsType.PAKOUT.val());
+                    oriLoc.setUpdateTime(now);
+                    if (!locService.updateById(oriLoc)) {
+                        throw new BusinessException("oriLoc锛�" + oriLoc.getLocNo() + " 淇敼搴撲綅鐘舵�佸け璐�");
+                    }
                 }
 
                 // destSta
@@ -352,13 +363,15 @@
 //                    throw new BusinessException("AGV " + agv.getUuid() + " failed to reach target code " + destLoc.getCode$());
                     throw new BusinessException("AGV銆�" + agv.getUuid() + "銆戞棤娉曞埌杈剧洰鏍囧簱浣嶃��" + destLoc.getLocNo() + "銆�");
                 }
-                if (!destLoc.getLocSts().equals(LocStsType.IDLE.val())) {
-                    throw new BusinessException("destLoc锛�" + destLoc.getLocNo() + " 涓嶆槸绌洪棽鐘舵��");
-                }
-                destLoc.setLocSts(LocStsType.PAKIN.val());
-                destLoc.setUpdateTime(now);
-                if (!locService.updateById(destLoc)) {
-                    throw new BusinessException("destLoc锛�" + destLoc.getLocNo() + " 淇敼搴撲綅鐘舵�佸け璐�");
+                if (maintainLocSts) {
+                    if (!destLoc.getLocSts().equals(LocStsType.IDLE.val())) {
+                        throw new BusinessException("destLoc锛�" + destLoc.getLocNo() + " 涓嶆槸绌洪棽鐘舵��");
+                    }
+                    destLoc.setLocSts(LocStsType.PAKIN.val());
+                    destLoc.setUpdateTime(now);
+                    if (!locService.updateById(destLoc)) {
+                        throw new BusinessException("destLoc锛�" + destLoc.getLocNo() + " 淇敼搴撲綅鐘舵�佸け璐�");
+                    }
                 }
 
                 // task
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/core/domain/type/NamespaceType.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/domain/type/NamespaceType.java
new file mode 100644
index 0000000..cf1fcb5
--- /dev/null
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/domain/type/NamespaceType.java
@@ -0,0 +1,15 @@
+package com.zy.acs.manager.core.domain.type;
+
+public enum NamespaceType {
+
+    RCS_TASK_REPORT("浠诲姟瀹屾垚涓婃姤"),
+
+    ;
+
+    public String name;
+
+    NamespaceType(String name) {
+        this.name = name;
+    }
+
+}
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/core/integrate/conveyor/ConveyorController.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/integrate/conveyor/ConveyorController.java
index b4d9a7b..9091852 100644
--- a/zy-acs-manager/src/main/java/com/zy/acs/manager/core/integrate/conveyor/ConveyorController.java
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/integrate/conveyor/ConveyorController.java
@@ -9,7 +9,6 @@
 import com.zy.acs.manager.manager.entity.Task;
 import com.zy.acs.manager.manager.enums.StatusType;
 import com.zy.acs.manager.manager.service.StaService;
-import com.zy.acs.manager.system.controller.BaseController;
 import io.swagger.annotations.Api;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -23,7 +22,7 @@
 @Api(tags = "Open Api")
 @RestController
 @RequestMapping("/api/open")
-public class ConveyorController extends BaseController {
+public class ConveyorController {
 
     @Autowired
     private StaService staService;
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/core/integrate/conveyor/SiemensConveyorStationService.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/integrate/conveyor/SiemensConveyorStationService.java
index 05a08f7..b1c184b 100644
--- a/zy-acs-manager/src/main/java/com/zy/acs/manager/core/integrate/conveyor/SiemensConveyorStationService.java
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/integrate/conveyor/SiemensConveyorStationService.java
@@ -3,24 +3,28 @@
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.TypeReference;
 import com.zy.acs.framework.common.Cools;
+import com.zy.acs.framework.common.SnowflakeIdWorker;
 import com.zy.acs.manager.common.config.ConveyorProperties;
+import com.zy.acs.manager.common.constant.Constants;
 import com.zy.acs.manager.common.utils.HttpGo;
+import com.zy.acs.manager.core.domain.type.NamespaceType;
 import com.zy.acs.manager.core.integrate.dto.ConveyorStaDto;
 import com.zy.acs.manager.core.integrate.dto.HttpResult;
+import com.zy.acs.manager.manager.entity.IntegrationRecord;
 import com.zy.acs.manager.manager.entity.Segment;
 import com.zy.acs.manager.manager.entity.Sta;
 import com.zy.acs.manager.manager.entity.Task;
+import com.zy.acs.manager.manager.enums.IntegrationDirectionType;
 import com.zy.acs.manager.manager.enums.StaReserveType;
+import com.zy.acs.manager.manager.enums.StatusType;
+import com.zy.acs.manager.manager.service.IntegrationRecordService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.PostConstruct;
 import java.time.Duration;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 @Slf4j
 @Service
@@ -28,25 +32,32 @@
 
     @Autowired
     private ConveyorProperties conveyorProperties;
+    @Autowired
+    private SnowflakeIdWorker snowflakeIdWorker;
+    @Autowired
+    private IntegrationRecordService integrationRecordService;
 
     private HttpGo http;
 
     @PostConstruct
     public void init() {
+        int timeoutSeconds = conveyorProperties.getTimeout() / 1000;
         this.http = HttpGo.builder()
-                .connectTimeout(Duration.ofSeconds(8))
-                .readTimeout(Duration.ofSeconds(15))
+                .connectTimeout(Duration.ofSeconds(timeoutSeconds))
+                .readTimeout(Duration.ofSeconds(timeoutSeconds))
 //                .defaultHeader("User-Agent", "HttpGo/1.0")
-                // .trustAllSsl(true) // ONLY if you really need it (self-signed internal)
+//                .trustAllSsl(true) // ONLY if you really need it (self-signed internal)
                 .build();
     }
+
 
     @Override
     public boolean allowAgvWork(Sta sta, Task task, Segment seg, StaReserveType type) {
         final String staNo = sta.getStaNo();
+        Date now = new Date();
 
         // url
-        String url = this.buildUrl("/cv/station/query");
+        String url = this.http.buildUrl(conveyorProperties.getHost(), conveyorProperties.getPort(), conveyorProperties.getUrl());
         // headers
         Map<String, String> headers = new HashMap<>();
         // params
@@ -54,10 +65,33 @@
         List<String> list = new ArrayList<>();
         list.add(staNo);
         params.put("staNos", list);
+
+        IntegrationRecord integrationRecord = new IntegrationRecord(
+                String.valueOf(snowflakeIdWorker.nextId()).substring(3),    // 缂栧彿
+                NamespaceType.RCS_TASK_REPORT.name,    // 鍚嶇О绌洪棿
+                conveyorProperties.getUrl(),    // 鎺ュ彛鍦板潃
+                null,    // 骞冲彴瀵嗛挜
+                Constants.RCS,    // 璋冪敤鏂规爣璇�
+                IntegrationDirectionType.OUTBOUND.value,    // 鏂瑰悜[闈炵┖]
+                String.valueOf(now.getTime()),    // 鏃堕棿鎴�
+                conveyorProperties.getHost(),    // 瀹㈡埛绔疘P
+                JSON.toJSONString(params),    // 璇锋眰鍐呭
+                null,    // 鍝嶅簲鍐呭
+                null,    // 寮傚父鍐呭
+                0,    // 缁撴灉
+                null,    // 鑰楁椂
+                StatusType.ENABLE.val,    // 鐘舵��
+                now,    // 娣诲姞鏃堕棿[闈炵┖]
+                now,    // 淇敼鏃堕棿[闈炵┖]
+                null    // 澶囨敞
+        );
+
         // do request
         HttpResult<List<ConveyorStaDto>> result;
         try {
             result = postForResult(url, headers, params);
+            integrationRecord.setResponse(JSON.toJSONString(result));
+
             Integer code = result.getCode();
             if (null == code || 200 != code) {
                 return false;
@@ -94,28 +128,25 @@
                     return false;
                 }
             }
+
+            integrationRecord.setResult(1);
         } catch (Exception e) {
             log.error("Conveyor query failed, FAIL-OPEN. staNo={}, taskId={}, type={}",
                     sta.getStaNo(),
                     task.getSeqNum(),
                     type,
                     e);
+            integrationRecord.setErr(e.getMessage());
             return false;
+        } finally {
+            integrationRecord.setCostMs((int) (System.currentTimeMillis() - now.getTime()));
+            integrationRecordService.syncRecord(integrationRecord);
         }
         // ok
         return true;
     }
 
-    private String buildUrl(String path) {
-        String host = conveyorProperties.getHost();
-        Integer port = conveyorProperties.getPort();
-
-        String p = (path == null) ? "" : (path.startsWith("/") ? path : ("/" + path));
-        return "http://" + host + ":" + port + p;
-    }
-
-    private HttpResult<List<ConveyorStaDto>> postForResult(String url
-            , Map<String, String> headers, Map<String, Object> params) throws Exception {
+    private HttpResult<List<ConveyorStaDto>> postForResult(String url, Map<String, String> headers, Map<String, Object> params) throws Exception {
         String json = JSON.toJSONString(params);
         HttpGo.HttpResponse response = this.http.postJson(url, headers, json);
 
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/core/integrate/dto/OpenBusCancelParam.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/integrate/dto/OpenBusCancelParam.java
new file mode 100644
index 0000000..017d151
--- /dev/null
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/integrate/dto/OpenBusCancelParam.java
@@ -0,0 +1,18 @@
+package com.zy.acs.manager.core.integrate.dto;
+
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by vincent on 2023/6/12
+ */
+@Data
+public class OpenBusCancelParam {
+
+    private String batchNo;
+
+    private List<String> tasks = new ArrayList<>();
+
+}
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/core/integrate/dto/OpenBusCancelResult.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/integrate/dto/OpenBusCancelResult.java
new file mode 100644
index 0000000..f0b3202
--- /dev/null
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/integrate/dto/OpenBusCancelResult.java
@@ -0,0 +1,19 @@
+package com.zy.acs.manager.core.integrate.dto;
+
+import com.zy.acs.manager.common.domain.TaskBoolDto;
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by vincent on 2023/6/12
+ */
+@Data
+public class OpenBusCancelResult {
+
+    private String batchNo;
+
+    private List<TaskBoolDto> tasks = new ArrayList<>();
+
+}
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/controller/param/OpenBusSubmitParam.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/integrate/dto/OpenBusSubmitParam.java
similarity index 61%
rename from zy-acs-manager/src/main/java/com/zy/acs/manager/manager/controller/param/OpenBusSubmitParam.java
rename to zy-acs-manager/src/main/java/com/zy/acs/manager/core/integrate/dto/OpenBusSubmitParam.java
index 3362fb4..2f9f681 100644
--- a/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/controller/param/OpenBusSubmitParam.java
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/integrate/dto/OpenBusSubmitParam.java
@@ -1,4 +1,4 @@
-package com.zy.acs.manager.manager.controller.param;
+package com.zy.acs.manager.core.integrate.dto;
 
 import com.zy.acs.manager.common.domain.TaskDto;
 import lombok.Data;
@@ -12,8 +12,8 @@
 @Data
 public class OpenBusSubmitParam {
 
-    private String batch;
+    private String batchNo;
 
-    private List<TaskDto> taskList = new ArrayList<>();
+    private List<TaskDto> tasks = new ArrayList<>();
 
 }
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/core/integrate/dto/TaskUplinkParam.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/integrate/dto/TaskUplinkParam.java
new file mode 100644
index 0000000..09ae50d
--- /dev/null
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/integrate/dto/TaskUplinkParam.java
@@ -0,0 +1,14 @@
+package com.zy.acs.manager.core.integrate.dto;
+
+import lombok.Data;
+
+@Data
+public class TaskUplinkParam {
+
+    private String batchNo;
+
+    private String taskNo;
+
+    private Long timestamp;
+
+}
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/core/integrate/wms/OpenController.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/integrate/wms/OpenController.java
index f6060a4..770269d 100644
--- a/zy-acs-manager/src/main/java/com/zy/acs/manager/core/integrate/wms/OpenController.java
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/integrate/wms/OpenController.java
@@ -1,35 +1,108 @@
 package com.zy.acs.manager.core.integrate.wms;
 
-import com.zy.acs.manager.common.annotation.OperationLog;
+import com.zy.acs.framework.common.Cools;
 import com.zy.acs.framework.common.R;
-import com.zy.acs.manager.system.controller.BaseController;
+import com.zy.acs.manager.common.annotation.OperationLog;
+import com.zy.acs.manager.common.constant.Constants;
+import com.zy.acs.manager.common.domain.TaskBoolDto;
+import com.zy.acs.manager.core.integrate.dto.OpenBusCancelParam;
+import com.zy.acs.manager.core.integrate.dto.OpenBusCancelResult;
+import com.zy.acs.manager.core.integrate.dto.OpenBusSubmitParam;
 import com.zy.acs.manager.core.service.MainService;
-import com.zy.acs.manager.manager.controller.param.OpenBusSubmitParam;
+import com.zy.acs.manager.manager.entity.Bus;
+import com.zy.acs.manager.manager.entity.IntegrationRecord;
+import com.zy.acs.manager.manager.entity.Task;
+import com.zy.acs.manager.manager.enums.TaskStsType;
+import com.zy.acs.manager.manager.service.BusService;
+import com.zy.acs.manager.manager.service.TaskService;
 import io.swagger.annotations.Api;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import javax.servlet.http.HttpServletRequest;
+
 /**
  * Created by vincent on 2023/6/12
  */
+@Slf4j
 @Api(tags = "Open Api")
 @RestController
 @RequestMapping("/api/open")
-public class OpenController extends BaseController {
+public class OpenController {
 
     @Autowired
     private MainService mainService;
+    @Autowired
+    private TaskService taskService;
+    @Autowired
+    private BusService busService;
 
-//    @PreAuthorize("hasAuthority('open:bus:submit')")
     @PostMapping("/bus/submit")
     @OperationLog("generate task from open api")
-    public R save(@RequestBody OpenBusSubmitParam param) {
+    public R submit(@RequestBody OpenBusSubmitParam param, HttpServletRequest request) {
+        IntegrationRecord integrationRecord = new IntegrationRecord(
+                null,    // 缂栧彿
+                null,    // 鍚嶇О绌洪棿
+                null,    // 鎺ュ彛鍦板潃
+                null,    // 骞冲彴瀵嗛挜
+                null,    // 璋冪敤鏂规爣璇�
+                null,    // 鏂瑰悜[闈炵┖]
+                null,    // 鏃堕棿鎴�
+                null,    // 瀹㈡埛绔疘P
+                null,    // 璇锋眰鍐呭
+                null,    // 鍝嶅簲鍐呭
+                null,    // 寮傚父鍐呭
+                null,    // 缁撴灉
+                null,    // 鑰楁椂
+                null,    // 鐘舵��
+                null,    // 娣诲姞鏃堕棿[闈炵┖]
+                null,    // 淇敼鏃堕棿[闈炵┖]
+                null    // 澶囨敞
+        );
+        request.setAttribute("integrationRecord", integrationRecord);
+
         mainService.generateBusAndTask(param, null);
         return R.ok("generate tasks success");
     }
 
+    @PostMapping("/task/cancel")
+    @OperationLog("cancel task from open api")
+    public R cancel(@RequestBody OpenBusCancelParam param) {
+        if (Cools.isEmpty(param.getBatchNo())) {
+            return R.error("batchNo is empty");
+        }
+        if (Cools.isEmpty(param.getTasks())) {
+            return R.error("tasks is empty");
+        }
+        Bus bus = busService.selectByBusNo(param.getBatchNo());
+        if (null == bus) {
+            return R.error("batchNo is not exist");
+        }
+        OpenBusCancelResult result = new OpenBusCancelResult();
+        result.setBatchNo(param.getBatchNo());
+        for (String taskNo : param.getTasks()) {
+            Task task = taskService.selectBySeqNum(bus.getId(), taskNo);
+            if (null == task) {
+                result.getTasks().add(new TaskBoolDto(taskNo, Boolean.FALSE, "task " + taskNo + " is not exist"));
+                continue;
+            }
+            if (!task.getTaskSts().equals(TaskStsType.INIT.val())) {
+                result.getTasks().add(new TaskBoolDto(taskNo, Boolean.FALSE,  "task " + taskNo + " has already been assigned"));
+                continue;
+            }
+            Boolean cancel = false;
+            try {
+                cancel = taskService.cancel(task.getId(), null, Constants.UPLINK);
+            } catch (Exception e) {
+                log.error("failed to cancel task {}", taskNo, e);
+            }
+            result.getTasks().add(new TaskBoolDto(taskNo, cancel, "failed to cancel task " + taskNo));
+        }
+        return R.ok("cancel tasks success").add(result);
+    }
+
 }
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/core/integrate/wms/TaskReportService.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/integrate/wms/TaskReportService.java
new file mode 100644
index 0000000..e9df693
--- /dev/null
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/integrate/wms/TaskReportService.java
@@ -0,0 +1,180 @@
+package com.zy.acs.manager.core.integrate.wms;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.TypeReference;
+import com.zy.acs.framework.common.Cools;
+import com.zy.acs.framework.common.R;
+import com.zy.acs.framework.common.SnowflakeIdWorker;
+import com.zy.acs.manager.common.config.UplinkProperties;
+import com.zy.acs.manager.common.constant.Constants;
+import com.zy.acs.manager.common.utils.HttpGo;
+import com.zy.acs.manager.core.domain.type.NamespaceType;
+import com.zy.acs.manager.core.integrate.dto.HttpResult;
+import com.zy.acs.manager.core.integrate.dto.TaskUplinkParam;
+import com.zy.acs.manager.core.service.ThreadPoolRegulator;
+import com.zy.acs.manager.manager.entity.Bus;
+import com.zy.acs.manager.manager.entity.IntegrationRecord;
+import com.zy.acs.manager.manager.entity.Task;
+import com.zy.acs.manager.manager.enums.IntegrationDirectionType;
+import com.zy.acs.manager.manager.enums.StatusType;
+import com.zy.acs.manager.manager.enums.TaskStsType;
+import com.zy.acs.manager.manager.enums.TaskUplinkStateType;
+import com.zy.acs.manager.manager.service.BusService;
+import com.zy.acs.manager.manager.service.IntegrationRecordService;
+import com.zy.acs.manager.manager.service.TaskService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import java.time.Duration;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+
+@Slf4j
+@Service
+public class TaskReportService {
+
+    @Autowired
+    private UplinkProperties uplinkProperties;
+    @Autowired
+    private TaskService taskService;
+    @Autowired
+    private ThreadPoolRegulator threadPoolRegulator;
+    @Autowired
+    private BusService busService;
+    @Autowired
+    private SnowflakeIdWorker snowflakeIdWorker;
+    @Autowired
+    private IntegrationRecordService integrationRecordService;
+
+    private HttpGo http;
+
+    @PostConstruct
+    public void init() {
+        int timeoutSeconds = uplinkProperties.getTimeout() / 1000;
+        this.http = HttpGo.builder()
+                .connectTimeout(Duration.ofSeconds(timeoutSeconds))
+                .readTimeout(Duration.ofSeconds(timeoutSeconds))
+//                .defaultHeader("User-Agent", "HttpGo/1.0")
+//                .trustAllSsl(true) // ONLY if you really need it (self-signed internal)
+                .build();
+    }
+
+    public boolean reportFinished(Task task) {
+        if (Cools.isEmpty(task)) {
+            return false;
+        }
+        if (!uplinkProperties.getEnabled()) {
+            return false;
+        }
+        if (!task.getTaskSts().equals(TaskStsType.COMPLETE.val())) {
+            return false;
+        }
+        TaskUplinkStateType uplinkStateType = TaskUplinkStateType.of(task.getUplinkSts());
+        if (!uplinkStateType.equals(TaskUplinkStateType.PENDING)
+                && !uplinkStateType.equals(TaskUplinkStateType.SENDING)
+                && !uplinkStateType.equals(TaskUplinkStateType.FAILED)
+        ) {
+            return false;
+        }
+        Date now = new Date();
+        // block
+//        Future<R> future = threadPoolRegulator.getInstance().submit(() -> {
+//            mapDataDispatcher.modifyDynamicMatrix(null, null, param.getAgvNo(), true);
+//            return success();
+//        });
+//        System.out.println(JSON.toJSONString(future.get()));
+
+        // non-block
+        CompletableFuture<?> completableFuture = CompletableFuture.supplyAsync(() -> {
+//            mapDataDispatcher.modifyDynamicMatrix(null, null, param.getAgvNo(), true);
+//            avoidWaveCalculator.calcDynamicNodeByVehicle(agv, null);
+            return R.ok();
+        }, threadPoolRegulator.getInstance());
+
+        // url
+        String url = this.http.buildUrl(uplinkProperties.getHost(), uplinkProperties.getPort(), uplinkProperties.getUrl());
+        // headers
+        Map<String, String> headers = new HashMap<>();
+        // params
+        TaskUplinkParam param = new TaskUplinkParam();
+        if (null != task.getBusId()) {
+            Bus bus = busService.getById(task.getBusId());
+            param.setBatchNo(bus.getBusNo());
+        }
+        param.setTaskNo(task.getSeqNum());
+        param.setTimestamp(null == task.getEndTime() ? System.currentTimeMillis() : task.getEndTime().getTime());
+
+        IntegrationRecord integrationRecord = new IntegrationRecord(
+                String.valueOf(snowflakeIdWorker.nextId()).substring(3),    // 缂栧彿
+                NamespaceType.RCS_TASK_REPORT.name,    // 鍚嶇О绌洪棿
+                uplinkProperties.getUrl(),    // 鎺ュ彛鍦板潃
+                null,    // 骞冲彴瀵嗛挜
+                Constants.RCS,    // 璋冪敤鏂规爣璇�
+                IntegrationDirectionType.OUTBOUND.value,    // 鏂瑰悜[闈炵┖]
+                String.valueOf(now.getTime()),    // 鏃堕棿鎴�
+                uplinkProperties.getHost(),    // 瀹㈡埛绔疘P
+                JSON.toJSONString(param),    // 璇锋眰鍐呭
+                null,    // 鍝嶅簲鍐呭
+                null,    // 寮傚父鍐呭
+                0,    // 缁撴灉
+                null,    // 鑰楁椂
+                StatusType.ENABLE.val,    // 鐘舵��
+                now,    // 娣诲姞鏃堕棿[闈炵┖]
+                now,    // 淇敼鏃堕棿[闈炵┖]
+                null    // 澶囨敞
+        );
+        HttpResult<?> result;
+        try {
+            result = postForResult(url, headers, param);
+            integrationRecord.setResponse(JSON.toJSONString(result));
+
+            Integer code = result.getCode();
+            if (null == code || 200 != code) {
+                return false;
+            }
+//            Object data = result.getData();
+//            if (Cools.isEmpty(data)) {
+//                return false;
+//            }
+
+            integrationRecord.setResult(1);
+        } catch (Exception e) {
+            log.error("Uplink report failed, taskId={}",
+                    JSON.toJSONString(task),
+                    e);
+            integrationRecord.setErr(e.getMessage());
+            return false;
+        } finally {
+            integrationRecord.setCostMs((int) (System.currentTimeMillis() - now.getTime()));
+            integrationRecordService.syncRecord(integrationRecord);
+        }
+        return true;
+    }
+
+    private HttpResult<?> postForResult(String url, Map<String, String> headers, TaskUplinkParam param) throws Exception {
+        String json = JSON.toJSONString(param);
+        HttpGo.HttpResponse response = this.http.postJson(url, headers, json);
+
+        int status = response.statusCode();
+        if (status != 200) {
+            throw new RuntimeException("Uplink HTTP error: status=" + status + ", body=" + response.body());
+        }
+
+        String body = response.body();
+        if (Cools.isEmpty(body)) {
+            throw new RuntimeException("Uplink empty response body.");
+        }
+
+        HttpResult<?> result = JSON.parseObject(body, new TypeReference<HttpResult<?>>() {});
+        if (result == null) {
+            throw new RuntimeException("Uplink parse HttpResult failed: body=" + body);
+        }
+        return result;
+    }
+
+
+}
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/core/scheduler/AutoTestDeviationScheduler.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/scheduler/AutoTestDeviationScheduler.java
deleted file mode 100644
index 912f26d..0000000
--- a/zy-acs-manager/src/main/java/com/zy/acs/manager/core/scheduler/AutoTestDeviationScheduler.java
+++ /dev/null
@@ -1,149 +0,0 @@
-package com.zy.acs.manager.core.scheduler;
-
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.zy.acs.common.constant.RedisConstant;
-import com.zy.acs.common.utils.RedisSupport;
-import com.zy.acs.framework.common.Cools;
-import com.zy.acs.framework.common.SnowflakeIdWorker;
-import com.zy.acs.manager.common.domain.TaskDto;
-import com.zy.acs.manager.core.service.AreaGovernService;
-import com.zy.acs.manager.core.service.MainService;
-import com.zy.acs.manager.manager.controller.param.OpenBusSubmitParam;
-import com.zy.acs.manager.manager.entity.*;
-import com.zy.acs.manager.manager.enums.AgvModelType;
-import com.zy.acs.manager.manager.enums.BusStsType;
-import com.zy.acs.manager.manager.enums.LocStsType;
-import com.zy.acs.manager.manager.enums.StatusType;
-import com.zy.acs.manager.manager.service.*;
-import com.zy.acs.manager.manager.service.impl.CodeServiceImpl;
-import com.zy.acs.manager.system.service.ConfigService;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Component;
-
-import java.util.*;
-
-@Slf4j
-@Component
-public class AutoTestDeviationScheduler {
-
-    private static final AgvModelType DEFAULT_AGV_MODEL = AgvModelType.HEAVY_LOAD_STACKING_ROBOT;
-
-    private final RedisSupport redis = RedisSupport.defaultRedisSupport;
-
-    @Autowired
-    private AgvService agvService;
-    @Autowired
-    private BusService busService;
-    @Autowired
-    private MainService mainService;
-    @Autowired
-    private ConfigService configService;
-    @Autowired
-    private LocService locService;
-    @Autowired
-    private StaService staService;
-    @Autowired
-    private AgvModelService agvModelService;
-    @Autowired
-    private SnowflakeIdWorker snowflakeIdWorker;
-    @Autowired
-    private AreaGovernService areaGovernService;
-    @Autowired
-    private CodeServiceImpl codeService;
-
-    /**
-     * 寰幆璺戝簱锛屾祴璇曞亸宸�
-     */
-    //    @Scheduled(fixedRate = 500) // 鍥哄畾棰戠巼鎵ц锛屼笉鍚屾
-    //@Scheduled(fixedDelay = 1000) // 鍥哄畾棰戠巼鎵ц锛屽悓姝�
-//    @Scheduled(cron = "0/1 * * * * ? ")
-    private void execute() {
-        if (!configService.getVal("TestDeviationMode", Boolean.class)) { return; }
-        AgvModel agvModel = agvModelService.getOne(new LambdaQueryWrapper<AgvModel>().eq(AgvModel::getType, DEFAULT_AGV_MODEL.toString()));
-        if (null == agvModel) { return; }
-
-        this.autoRun(agvModel);
-    }
-
-    private void autoRun(AgvModel agvModel) {
-        int availableAgvCount = this.getAvailableAgvCount();
-        if (0 == availableAgvCount) { return; }
-
-//        List<String> staPreNos = getStaPrefixes(staGroupList);
-        List<String> staPreNos = new ArrayList<>();
-        String memo = "DEMO_STA_" + String.join("-", staPreNos);
-
-        // 绉诲簱
-        this.runLocToLoc(agvModel, memo);
-    }
-
-
-    // 绉诲簱
-    private void runLocToLoc(AgvModel agvModel, String staTaskMemo) {
-        String memo = "DEMO_LOC";
-
-        int availableAgvCount = this.getAvailableAgvCount();
-
-        // 鏈�澶� ? 缁刡us杩愯
-        if (availableAgvCount <= busService.count(new LambdaQueryWrapper<Bus>()
-                .in(Bus::getBusSts, BusStsType.RECEIVE.val(), BusStsType.PROGRESS.val())
-                .in(Bus::getMemo, memo, staTaskMemo)
-        )) { return; }
-
-        int maxCapacity = agvModel.getBackpack();
-
-        // STOCK
-        List<Loc> stockLocList = locService.selectRandByLocSts(LocStsType.STOCK.val(), maxCapacity);
-        if (Cools.isEmpty(stockLocList)) {
-            return;
-        }
-        Collections.shuffle(stockLocList);
-
-        // IDLE
-        List<Loc> idleLocList = locService.list(new LambdaQueryWrapper<Loc>().eq(Loc::getStatus,1).eq(Loc::getLocSts,LocStsType.IDLE.val()).ne(Loc::getMemo,"1").orderByAsc(Loc::getRow).orderByAsc(Loc::getBay).orderByAsc(Loc::getLev));
-        if (Cools.isEmpty(idleLocList)) {
-            return;
-        }
-
-        OpenBusSubmitParam param = new OpenBusSubmitParam();
-        param.setBatch(String.valueOf(snowflakeIdWorker.nextId()).substring(13, 19));
-        for (int i = 0; i < Math.min(maxCapacity, Math.min(stockLocList.size(), idleLocList.size())); i++) {
-            Loc stockLoc = stockLocList.get(i);
-            Loc idleLoc = idleLocList.get(i);
-            idleLoc.setMemo("1");
-            locService.updateById(idleLoc);
-            TaskDto taskDto = new TaskDto();
-            taskDto.setOriLoc(stockLoc.getLocNo());
-            taskDto.setDestLoc(idleLoc.getLocNo());
-            taskDto.setSeqNum(String.valueOf(snowflakeIdWorker.nextId()).substring(15, 19));
-
-            param.getTaskList().add(taskDto);
-        }
-        if (Cools.isEmpty(param.getTaskList())) { return; }
-
-        mainService.generateBusAndTask(param, memo);
-    }
-
-
-    private int getAvailableAgvCount() {
-        int res = 0;
-        List<Agv> agvList = agvService.list(new LambdaQueryWrapper<Agv>().eq(Agv::getStatus, StatusType.ENABLE.val));
-        if (Cools.isEmpty(agvList)) {
-            return res;
-        }
-        for (Agv agv : agvList) {
-            if (null == redis.getObject(RedisConstant.AGV_ONLINE_FLAG, agv.getUuid())) {
-                continue;
-            }
-            if (!agv.getStatusBool()) {
-                continue;
-            }
-            res++;
-        }
-
-        return res;
-    }
-
-}
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/core/scheduler/MaintainScheduler.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/scheduler/MaintainScheduler.java
index 4ee2c04..2832d5b 100644
--- a/zy-acs-manager/src/main/java/com/zy/acs/manager/core/scheduler/MaintainScheduler.java
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/scheduler/MaintainScheduler.java
@@ -3,9 +3,11 @@
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.zy.acs.common.enums.AgvStatusType;
 import com.zy.acs.common.utils.RedisSupport;
+import com.zy.acs.framework.common.Cools;
 import com.zy.acs.framework.common.DateUtils;
+import com.zy.acs.manager.common.config.UplinkProperties;
+import com.zy.acs.manager.core.integrate.wms.TaskReportService;
 import com.zy.acs.manager.core.service.MainLockWrapService;
-import com.zy.acs.manager.core.service.MainService;
 import com.zy.acs.manager.manager.entity.*;
 import com.zy.acs.manager.manager.enums.*;
 import com.zy.acs.manager.manager.service.*;
@@ -36,7 +38,7 @@
     @Autowired
     private FuncStaService funcStaService;
     @Autowired
-    private MainService mainService;
+    private UplinkProperties uplinkProperties;
     @Autowired
     private MainLockWrapService mainLockWrapService;
     @Autowired
@@ -47,6 +49,8 @@
     private AgvModelService agvModelService;
     @Autowired
     private SegmentService segmentService;
+    @Autowired
+    private TaskReportService taskReportService;
 
     @Scheduled(cron = "0/5 * * * * ? ")
     private synchronized void autoCharge(){
@@ -148,8 +152,30 @@
         }
     }
 
+    @Scheduled(cron = "0/3 * * * * ? ")
+    private void reportTaskToUplink() {
+        if (!uplinkProperties.getEnabled()) { return; }
+        List<Task> taskList = taskService.list(new LambdaQueryWrapper<Task>()
+                .in(Task::getUplinkSts, TaskUplinkStateType.PENDING.toString(), TaskUplinkStateType.FAILED.toString())
+                .eq(Task::getTaskSts, TaskStsType.COMPLETE.val())
+                .isNotNull(Task::getBusId)
+        );
+        if (Cools.isEmpty(taskList)) { return; }
+        for (Task task : taskList) {
+            boolean finished = taskReportService.reportFinished(task);
+            if (finished) {
+                task.setUplinkSts(TaskUplinkStateType.SUCCESS.toString());
+            } else {
+                log.error("failed to report task to uplink: {}", task.getSeqNum());
+                task.setUplinkSts(TaskUplinkStateType.FAILED.toString());
+            }
+            taskService.updateById(task);
+        }
+
+    }
+
     @Scheduled(cron = "0/5 * * * * ? ")
-    private synchronized void releaseFuncSta(){
+    private synchronized void releaseFuncSta() {
         List<FuncSta> funcStaList = funcStaService.list(new LambdaQueryWrapper<FuncSta>().eq(FuncSta::getState, FuncStaStateType.OCCUPIED.toString()));
         for (FuncSta funcSta : funcStaList) {
             boolean beIdle = funcStaService.isCanBeIdle(funcSta);
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/core/scheduler/AutoRunRebootScheduler.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/scheduler/test/AutoRunRebootScheduler.java
similarity index 90%
rename from zy-acs-manager/src/main/java/com/zy/acs/manager/core/scheduler/AutoRunRebootScheduler.java
rename to zy-acs-manager/src/main/java/com/zy/acs/manager/core/scheduler/test/AutoRunRebootScheduler.java
index bcfde8c..9b79571 100644
--- a/zy-acs-manager/src/main/java/com/zy/acs/manager/core/scheduler/AutoRunRebootScheduler.java
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/scheduler/test/AutoRunRebootScheduler.java
@@ -1,4 +1,4 @@
-package com.zy.acs.manager.core.scheduler;
+package com.zy.acs.manager.core.scheduler.test;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.zy.acs.common.constant.RedisConstant;
@@ -6,10 +6,10 @@
 import com.zy.acs.framework.common.Cools;
 import com.zy.acs.framework.common.SnowflakeIdWorker;
 import com.zy.acs.manager.common.domain.TaskDto;
+import com.zy.acs.manager.core.integrate.dto.OpenBusSubmitParam;
 import com.zy.acs.manager.core.service.AreaGovernService;
 import com.zy.acs.manager.core.service.MainLockWrapService;
 import com.zy.acs.manager.core.service.MainService;
-import com.zy.acs.manager.manager.controller.param.OpenBusSubmitParam;
 import com.zy.acs.manager.manager.entity.*;
 import com.zy.acs.manager.manager.enums.*;
 import com.zy.acs.manager.manager.service.*;
@@ -18,12 +18,11 @@
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Component;
 
 import java.util.*;
 
 @Slf4j
-@Component
+//@Component
 public class AutoRunRebootScheduler {
 
     private static final AgvModelType DEFAULT_AGV_MODEL = AgvModelType.HEAVY_LOAD_STACKING_ROBOT;
@@ -62,6 +61,12 @@
 //    @Scheduled(cron = "0/1 * * * * ? ")
     private void execute() {
         if (!configService.getVal("TaskAssignRebootMode", Boolean.class)) { return; }
+        Boolean maintainLocSts = configService.getVal("maintainLocSts", Boolean.class);
+        if (!maintainLocSts) {
+            log.error("failed to run auto agv task, the maintainLocSts is false");
+            return;
+        }
+
         AgvModel agvModel = agvModelService.getOne(new LambdaQueryWrapper<AgvModel>().eq(AgvModel::getType, DEFAULT_AGV_MODEL.toString()));
         if (null == agvModel) { return; }
 
@@ -118,7 +123,7 @@
         Collections.shuffle(stockList);
 
         OpenBusSubmitParam param = new OpenBusSubmitParam();
-        param.setBatch(String.valueOf(snowflakeIdWorker.nextId()).substring(13, 19));
+        param.setBatchNo(String.valueOf(snowflakeIdWorker.nextId()).substring(13, 19));
         for (int i = 0; i < Math.min(agvModel.getBackpack(), stockList.size()) ; i++) {
             Sta stockSta = stockList.get(i);
             String staCode = codeService.getCacheById(stockSta.getCode()).getData();
@@ -156,11 +161,11 @@
             taskDto.setOriSta(stockSta.getStaNo());
             taskDto.setDestLoc(idleLoc.getLocNo());
             taskDto.setPriority(100);
-            taskDto.setSeqNum(String.valueOf(snowflakeIdWorker.nextId()).substring(15, 19));
+            taskDto.setTaskNo(String.valueOf(snowflakeIdWorker.nextId()).substring(15, 19));
 
-            param.getTaskList().add(taskDto);
+            param.getTasks().add(taskDto);
         }
-        if (Cools.isEmpty(param.getTaskList())) { return; }
+        if (Cools.isEmpty(param.getTasks())) { return; }
 
         mainService.generateBusAndTask(param, memo);
     }
@@ -174,7 +179,7 @@
         Collections.shuffle(idleList);
 
         OpenBusSubmitParam param = new OpenBusSubmitParam();
-        param.setBatch(String.valueOf(snowflakeIdWorker.nextId()).substring(13, 19));
+        param.setBatchNo(String.valueOf(snowflakeIdWorker.nextId()).substring(13, 19));
         for (int i = 0; i < Math.min(agvModel.getBackpack(), idleList.size()) ; i++) {
             Sta idleSta = idleList.get(i);
             String staCode = codeService.getCacheById(idleSta.getCode()).getData();
@@ -212,11 +217,11 @@
             taskDto.setOriLoc(stockLoc.getLocNo());
             taskDto.setDestSta(idleSta.getStaNo());
             taskDto.setPriority(100);
-            taskDto.setSeqNum(String.valueOf(snowflakeIdWorker.nextId()).substring(15, 19));
+            taskDto.setTaskNo(String.valueOf(snowflakeIdWorker.nextId()).substring(15, 19));
 
-            param.getTaskList().add(taskDto);
+            param.getTasks().add(taskDto);
         }
-        if (Cools.isEmpty(param.getTaskList())) { return; }
+        if (Cools.isEmpty(param.getTasks())) { return; }
 
         mainService.generateBusAndTask(param, memo);
     }
@@ -250,7 +255,7 @@
         Collections.shuffle(idleLocList);
 
         OpenBusSubmitParam param = new OpenBusSubmitParam();
-        param.setBatch(String.valueOf(snowflakeIdWorker.nextId()).substring(13, 19));
+        param.setBatchNo(String.valueOf(snowflakeIdWorker.nextId()).substring(13, 19));
         for (int i = 0; i < Math.min(maxCapacity, Math.min(stockLocList.size(), idleLocList.size())); i++) {
             Loc stockLoc = stockLocList.get(i);
             Loc idleLoc = idleLocList.get(i);
@@ -258,11 +263,11 @@
             TaskDto taskDto = new TaskDto();
             taskDto.setOriLoc(stockLoc.getLocNo());
             taskDto.setDestLoc(idleLoc.getLocNo());
-            taskDto.setSeqNum(String.valueOf(snowflakeIdWorker.nextId()).substring(15, 19));
+            taskDto.setTaskNo(String.valueOf(snowflakeIdWorker.nextId()).substring(15, 19));
 
-            param.getTaskList().add(taskDto);
+            param.getTasks().add(taskDto);
         }
-        if (Cools.isEmpty(param.getTaskList())) { return; }
+        if (Cools.isEmpty(param.getTasks())) { return; }
 
         mainService.generateBusAndTask(param, memo);
     }
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/core/scheduler/AutoRunScheduler.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/scheduler/test/AutoRunScheduler.java
similarity index 89%
rename from zy-acs-manager/src/main/java/com/zy/acs/manager/core/scheduler/AutoRunScheduler.java
rename to zy-acs-manager/src/main/java/com/zy/acs/manager/core/scheduler/test/AutoRunScheduler.java
index cbd0707..f0ca5e6 100644
--- a/zy-acs-manager/src/main/java/com/zy/acs/manager/core/scheduler/AutoRunScheduler.java
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/scheduler/test/AutoRunScheduler.java
@@ -1,4 +1,4 @@
-package com.zy.acs.manager.core.scheduler;
+package com.zy.acs.manager.core.scheduler.test;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.zy.acs.common.constant.RedisConstant;
@@ -7,7 +7,7 @@
 import com.zy.acs.framework.common.SnowflakeIdWorker;
 import com.zy.acs.manager.common.domain.TaskDto;
 import com.zy.acs.manager.core.service.*;
-import com.zy.acs.manager.manager.controller.param.OpenBusSubmitParam;
+import com.zy.acs.manager.core.integrate.dto.OpenBusSubmitParam;
 import com.zy.acs.manager.manager.entity.*;
 import com.zy.acs.manager.manager.enums.*;
 import com.zy.acs.manager.manager.service.*;
@@ -54,6 +54,11 @@
 //    @Scheduled(cron = "0/1 * * * * ? ")
     private void execute() {
         if (!configService.getVal("TaskAssignMode", Boolean.class)) { return; }
+        Boolean maintainLocSts = configService.getVal("maintainLocSts", Boolean.class);
+        if (!maintainLocSts) {
+            log.error("failed to run auto agv task, the maintainLocSts is false");
+            return;
+        }
         AgvModel agvModel = agvModelService.getOne(new LambdaQueryWrapper<AgvModel>().eq(AgvModel::getType, DEFAULT_AGV_MODEL.toString()));
         if (null == agvModel) { return; }
 
@@ -86,7 +91,7 @@
         Collections.shuffle(stockList);
 
         OpenBusSubmitParam param = new OpenBusSubmitParam();
-        param.setBatch(String.valueOf(snowflakeIdWorker.nextId()).substring(13, 19));
+        param.setBatchNo(String.valueOf(snowflakeIdWorker.nextId()).substring(13, 19));
         for (int i = 0; i < Math.min(agvModel.getBackpack(), stockList.size()) ; i++) {
             Sta stockSta = stockList.get(i);
             String staCode = codeService.getCacheById(stockSta.getCode()).getData();
@@ -124,11 +129,11 @@
             taskDto.setOriSta(stockSta.getStaNo());
             taskDto.setDestLoc(idleLoc.getLocNo());
             taskDto.setPriority(100);
-            taskDto.setSeqNum(String.valueOf(snowflakeIdWorker.nextId()).substring(15, 19));
+            taskDto.setTaskNo(String.valueOf(snowflakeIdWorker.nextId()).substring(15, 19));
 
-            param.getTaskList().add(taskDto);
+            param.getTasks().add(taskDto);
         }
-        if (Cools.isEmpty(param.getTaskList())) { return; }
+        if (Cools.isEmpty(param.getTasks())) { return; }
 
         mainService.generateBusAndTask(param, memo);
     }
@@ -142,7 +147,7 @@
         Collections.shuffle(idleList);
 
         OpenBusSubmitParam param = new OpenBusSubmitParam();
-        param.setBatch(String.valueOf(snowflakeIdWorker.nextId()).substring(13, 19));
+        param.setBatchNo(String.valueOf(snowflakeIdWorker.nextId()).substring(13, 19));
         for (int i = 0; i < Math.min(agvModel.getBackpack(), idleList.size()) ; i++) {
             Sta idleSta = idleList.get(i);
             String staCode = codeService.getCacheById(idleSta.getCode()).getData();
@@ -180,11 +185,11 @@
             taskDto.setOriLoc(stockLoc.getLocNo());
             taskDto.setDestSta(idleSta.getStaNo());
             taskDto.setPriority(100);
-            taskDto.setSeqNum(String.valueOf(snowflakeIdWorker.nextId()).substring(15, 19));
+            taskDto.setTaskNo(String.valueOf(snowflakeIdWorker.nextId()).substring(15, 19));
 
-            param.getTaskList().add(taskDto);
+            param.getTasks().add(taskDto);
         }
-        if (Cools.isEmpty(param.getTaskList())) { return; }
+        if (Cools.isEmpty(param.getTasks())) { return; }
 
         mainService.generateBusAndTask(param, memo);
     }
@@ -218,7 +223,7 @@
         Collections.shuffle(idleLocList);
 
         OpenBusSubmitParam param = new OpenBusSubmitParam();
-        param.setBatch(String.valueOf(snowflakeIdWorker.nextId()).substring(13, 19));
+        param.setBatchNo(String.valueOf(snowflakeIdWorker.nextId()).substring(13, 19));
         for (int i = 0; i < Math.min(maxCapacity, Math.min(stockLocList.size(), idleLocList.size())); i++) {
             Loc stockLoc = stockLocList.get(i);
             Loc idleLoc = idleLocList.get(i);
@@ -226,11 +231,11 @@
             TaskDto taskDto = new TaskDto();
             taskDto.setOriLoc(stockLoc.getLocNo());
             taskDto.setDestLoc(idleLoc.getLocNo());
-            taskDto.setSeqNum(String.valueOf(snowflakeIdWorker.nextId()).substring(15, 19));
+            taskDto.setTaskNo(String.valueOf(snowflakeIdWorker.nextId()).substring(15, 19));
 
-            param.getTaskList().add(taskDto);
+            param.getTasks().add(taskDto);
         }
-        if (Cools.isEmpty(param.getTaskList())) { return; }
+        if (Cools.isEmpty(param.getTasks())) { return; }
 
         mainService.generateBusAndTask(param, memo);
     }
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/core/scheduler/ConveyorAutoRunScheduler.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/scheduler/test/ConveyorAutoRunScheduler.java
similarity index 93%
rename from zy-acs-manager/src/main/java/com/zy/acs/manager/core/scheduler/ConveyorAutoRunScheduler.java
rename to zy-acs-manager/src/main/java/com/zy/acs/manager/core/scheduler/test/ConveyorAutoRunScheduler.java
index 7c24098..c3b795d 100644
--- a/zy-acs-manager/src/main/java/com/zy/acs/manager/core/scheduler/ConveyorAutoRunScheduler.java
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/scheduler/test/ConveyorAutoRunScheduler.java
@@ -1,4 +1,4 @@
-package com.zy.acs.manager.core.scheduler;
+package com.zy.acs.manager.core.scheduler.test;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.zy.acs.common.constant.RedisConstant;
@@ -8,7 +8,7 @@
 import com.zy.acs.manager.common.domain.TaskDto;
 import com.zy.acs.manager.core.service.AreaGovernService;
 import com.zy.acs.manager.core.service.MainService;
-import com.zy.acs.manager.manager.controller.param.OpenBusSubmitParam;
+import com.zy.acs.manager.core.integrate.dto.OpenBusSubmitParam;
 import com.zy.acs.manager.manager.entity.*;
 import com.zy.acs.manager.manager.enums.AgvModelType;
 import com.zy.acs.manager.manager.enums.BusStsType;
@@ -25,7 +25,7 @@
 import java.util.*;
 
 @Slf4j
-@Component
+//@Component
 public class ConveyorAutoRunScheduler {
 
     private static final AgvModelType DEFAULT_AGV_MODEL = AgvModelType.CTU_BOX_TRANSPORT_AGV;
@@ -97,7 +97,7 @@
         Collections.shuffle(idleList);
 
         OpenBusSubmitParam param = new OpenBusSubmitParam();
-        param.setBatch(String.valueOf(snowflakeIdWorker.nextId()).substring(13, 19));
+        param.setBatchNo(String.valueOf(snowflakeIdWorker.nextId()).substring(13, 19));
         for (int i = 0; i < agvModel.getBackpack() ; i++) {
             Sta idleSta = idleList.get(i);
             String staCode = codeService.getCacheById(idleSta.getCode()).getData();
@@ -135,11 +135,11 @@
             taskDto.setOriLoc(stockLoc.getLocNo());
             taskDto.setDestSta(idleSta.getStaNo());
             taskDto.setPriority(100);
-            taskDto.setSeqNum(String.valueOf(snowflakeIdWorker.nextId()).substring(15, 19));
+            taskDto.setTaskNo(String.valueOf(snowflakeIdWorker.nextId()).substring(15, 19));
 
-            param.getTaskList().add(taskDto);
+            param.getTasks().add(taskDto);
         }
-        if (Cools.isEmpty(param.getTaskList())) { return; }
+        if (Cools.isEmpty(param.getTasks())) { return; }
 
         mainService.generateBusAndTask(param, memo);
     }
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/core/service/MainService.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/service/MainService.java
index 06c0cf1..495193d 100644
--- a/zy-acs-manager/src/main/java/com/zy/acs/manager/core/service/MainService.java
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/service/MainService.java
@@ -23,7 +23,7 @@
 import com.zy.acs.manager.core.domain.TaskPosDto;
 import com.zy.acs.manager.core.integrate.conveyor.ConveyorStationService;
 import com.zy.acs.manager.core.service.astart.MapDataDispatcher;
-import com.zy.acs.manager.manager.controller.param.OpenBusSubmitParam;
+import com.zy.acs.manager.core.integrate.dto.OpenBusSubmitParam;
 import com.zy.acs.manager.manager.entity.*;
 import com.zy.acs.manager.manager.enums.*;
 import com.zy.acs.manager.manager.service.*;
@@ -104,11 +104,12 @@
     @Transactional
     public Bus generateBusAndTask(OpenBusSubmitParam busSubmitParam, String memo) {
         String errorMsg = busService.checkoutValid(busSubmitParam);
+        Boolean maintainLocSts = configService.getVal("maintainLocSts", Boolean.class);
         if (!Cools.isEmpty(errorMsg)) {
             throw new BusinessException(errorMsg);
         }
-        String batch = busSubmitParam.getBatch();
-        List<TaskDto> taskDtoList = busSubmitParam.getTaskList();
+        String batchNo = busSubmitParam.getBatchNo();
+        List<TaskDto> taskDtoList = busSubmitParam.getTasks();
         if (Cools.isEmpty(taskDtoList)) {
             throw new BusinessException("taskList can't be empty!");
         }
@@ -123,7 +124,7 @@
         Date now = new Date();
         Bus bus = new Bus();
         bus.setUuid(String.valueOf(snowflakeIdWorker.nextId()).substring(3));
-        bus.setBusNo(batch);
+        bus.setBusNo(batchNo);
         bus.setStartTime(now);
         bus.setBusSts(BusStsType.RECEIVE.val());
         bus.setMemo(memo);
@@ -147,35 +148,39 @@
             Sta destSta = null;
             switch (TaskTypeType.get(task.getTaskTypeEl())) {
                 case LOC_TO_LOC:
-                    oriLoc = locService.getById(task.getOriLoc());
-                    if (!oriLoc.getLocSts().equals(LocStsType.STOCK.val())) {
-                        throw new BusinessException("oriLoc锛�" + task.getOriLoc$() + " is not in STOCK status");
-                    }
-                    oriLoc.setLocSts(LocStsType.PAKOUT.val());
-                    oriLoc.setUpdateTime(now);
-                    if (!locService.updateById(oriLoc)) {
-                        throw new BusinessException("oriLoc锛�" + task.getOriLoc$() + " failed to update");
-                    }
+                    if (maintainLocSts) {
+                        oriLoc = locService.getById(task.getOriLoc());
+                        if (!oriLoc.getLocSts().equals(LocStsType.STOCK.val())) {
+                            throw new BusinessException("oriLoc锛�" + task.getOriLoc$() + " is not in STOCK status");
+                        }
+                        oriLoc.setLocSts(LocStsType.PAKOUT.val());
+                        oriLoc.setUpdateTime(now);
+                        if (!locService.updateById(oriLoc)) {
+                            throw new BusinessException("oriLoc锛�" + task.getOriLoc$() + " failed to update");
+                        }
 
-                    destLoc = locService.getById(task.getDestLoc());
-                    if (!destLoc.getLocSts().equals(LocStsType.IDLE.val())) {
-                        throw new BusinessException("destLoc锛�" + task.getDestLoc$() + " is not in IDLE status");
-                    }
-                    destLoc.setLocSts(LocStsType.PAKIN.val());
-                    destLoc.setUpdateTime(now);
-                    if (!locService.updateById(destLoc)) {
-                        throw new BusinessException("destLoc锛�" + task.getDestLoc$() + " failed to update");
+                        destLoc = locService.getById(task.getDestLoc());
+                        if (!destLoc.getLocSts().equals(LocStsType.IDLE.val())) {
+                            throw new BusinessException("destLoc锛�" + task.getDestLoc$() + " is not in IDLE status");
+                        }
+                        destLoc.setLocSts(LocStsType.PAKIN.val());
+                        destLoc.setUpdateTime(now);
+                        if (!locService.updateById(destLoc)) {
+                            throw new BusinessException("destLoc锛�" + task.getDestLoc$() + " failed to update");
+                        }
                     }
                     break;
                 case LOC_TO_STA:
-                    oriLoc = locService.getById(task.getOriLoc());
-                    if (!oriLoc.getLocSts().equals(LocStsType.STOCK.val())) {
-                        throw new BusinessException("oriLoc锛�" + task.getOriLoc$() + " is not in STOCK status");
-                    }
-                    oriLoc.setLocSts(LocStsType.PAKOUT.val());
-                    oriLoc.setUpdateTime(now);
-                    if (!locService.updateById(oriLoc)) {
-                        throw new BusinessException("oriLoc锛�" + task.getOriLoc$() + " failed to update");
+                    if (maintainLocSts) {
+                        oriLoc = locService.getById(task.getOriLoc());
+                        if (!oriLoc.getLocSts().equals(LocStsType.STOCK.val())) {
+                            throw new BusinessException("oriLoc锛�" + task.getOriLoc$() + " is not in STOCK status");
+                        }
+                        oriLoc.setLocSts(LocStsType.PAKOUT.val());
+                        oriLoc.setUpdateTime(now);
+                        if (!locService.updateById(oriLoc)) {
+                            throw new BusinessException("oriLoc锛�" + task.getOriLoc$() + " failed to update");
+                        }
                     }
 
                     destSta = staService.getById(task.getDestSta());
@@ -189,14 +194,16 @@
                         throw new BusinessException("oriSta锛�" + task.getOriSta$() + " failed to reserve");
                     }
 
-                    destLoc = locService.getById(task.getDestLoc());
-                    if (!destLoc.getLocSts().equals(LocStsType.IDLE.val())) {
-                        throw new BusinessException("destLoc锛�" + task.getDestLoc$() + " is not in IDLE status");
-                    }
-                    destLoc.setLocSts(LocStsType.PAKIN.val());
-                    destLoc.setUpdateTime(now);
-                    if (!locService.updateById(destLoc)) {
-                        throw new BusinessException("destLoc锛�" + task.getDestLoc$() + " failed to update");
+                    if (maintainLocSts) {
+                        destLoc = locService.getById(task.getDestLoc());
+                        if (!destLoc.getLocSts().equals(LocStsType.IDLE.val())) {
+                            throw new BusinessException("destLoc锛�" + task.getDestLoc$() + " is not in IDLE status");
+                        }
+                        destLoc.setLocSts(LocStsType.PAKIN.val());
+                        destLoc.setUpdateTime(now);
+                        if (!locService.updateById(destLoc)) {
+                            throw new BusinessException("destLoc锛�" + task.getDestLoc$() + " failed to update");
+                        }
                     }
                     break;
                 case STA_TO_STA:
@@ -791,6 +798,7 @@
             task.setPriority(taskType.equals(TaskTypeType.TO_CHARGE)?2:1);
             task.setTaskSts(TaskStsType.ASSIGN.val());
             task.setTaskType(taskType.val());
+            task.setUplinkSts(TaskUplinkStateType.SKIPPED.toString());
             task.setIoTime(now);
             task.setStartTime(now);
             if (!taskService.save(task)) {
@@ -1147,7 +1155,7 @@
                 }
 
                 // 浣滀笟鐐瑰姩浣�
-                AgvDirectionType agvDirectionType;
+                ActuatorDirectionType actuatorDirectionType;
                 Double staWorkDirection;
                 AgvBackpackType backpackType = AgvBackpackType.query(segment.getBackpack());
                 switch (Objects.requireNonNull(TaskPosDto.queryPosType(segment.getPosType()))) {
@@ -1160,7 +1168,8 @@
                         // 璐ф灦鍙栬揣
                         Loc oriLoc = locService.getById(task.getOriLoc());
                         // 璁$畻宸﹀彸鏂瑰悜
-                        agvDirectionType = mapService.calculateAgvWorkDirectionByShelf(oriLoc, lastCode);
+                        actuatorDirectionType = ActuatorDirectionType.fromVal(oriLoc.getCompDirect());
+//                        actuatorDirectionType = mapService.calculateAgvWorkDirectionByShelf(oriLoc, lastCode);
                         actionList.add(new Action(
                                 null,    // 缂栧彿
                                 task.getBusId(),    // 鎬荤嚎
@@ -1168,7 +1177,7 @@
                                 null,    // 鍔ㄤ綔鍙�
                                 null,    // 浼樺厛绾�
                                 ActionTypeType.ReadyTakeFromShelvesLoc.desc,    // 鍚嶇О
-                                (double) agvDirectionType.val,    // 灞炴�у��
+                                (double) actuatorDirectionType.val,    // 灞炴�у��
                                 lastCode.getData(),    // 鍦伴潰鐮�
                                 JSON.toJSONString(new HeightDepthDto(oriLoc.getOffset())),   // 鍔ㄤ綔鍙傛暟
                                 ActionTypeType.ReadyTakeFromShelvesLoc.val(),    // 鍔ㄤ綔绫诲瀷
@@ -1223,7 +1232,8 @@
                         // 璐ф灦鏀捐揣
                         Loc destLoc = locService.getById(task.getDestLoc());
                         // 璁$畻宸﹀彸鏂瑰悜
-                        agvDirectionType = mapService.calculateAgvWorkDirectionByShelf(destLoc, lastCode);
+                        actuatorDirectionType = ActuatorDirectionType.fromVal(destLoc.getCompDirect());
+//                        actuatorDirectionType = mapService.calculateAgvWorkDirectionByShelf(destLoc, lastCode);
                         actionList.add(new Action(
                                 null,    // 缂栧彿
                                 task.getBusId(),    // 鎬荤嚎
@@ -1231,7 +1241,7 @@
                                 null,    // 鍔ㄤ綔鍙�
                                  null,    // 浼樺厛绾�
                                 ActionTypeType.ReadyReleaseToShelvesLoc.desc,    // 鍚嶇О
-                                (double) agvDirectionType.val,    // 灞炴�у��
+                                (double) actuatorDirectionType.val,    // 灞炴�у��
                                 lastCode.getData(),    // 鍦伴潰鐮�
                                 JSON.toJSONString(new HeightDepthDto(destLoc.getOffset())),   // 鍔ㄤ綔鍙傛暟
                                 ActionTypeType.ReadyReleaseToShelvesLoc.val(),    // 鍔ㄤ綔绫诲瀷
@@ -1268,7 +1278,8 @@
                             lastDirection = oriStaWorkDirection;
                         }
                         // 璁$畻璐у弶宸ヤ綔鏂瑰悜
-                        staWorkDirection = mapService.calculateAgvWorkDirectionByStation(oriStaWorkDirection, lastDirection);
+                        actuatorDirectionType = ActuatorDirectionType.fromVal(oriSta.getActDir());
+//                        staWorkDirection = mapService.calculateAgvWorkDirectionByStation(oriStaWorkDirection, lastDirection);
                         actionList.add(new Action(
                                 null,    // 缂栧彿
                                 task.getBusId(),    // 鎬荤嚎
@@ -1276,7 +1287,7 @@
                                 null,    // 鍔ㄤ綔鍙�
                                 null,    // 浼樺厛绾�
                                 ActionTypeType.ReadyTakeFromConveyorSta.desc,    // 鍚嶇О
-                                staWorkDirection,    // 灞炴�у��
+                                (double) actuatorDirectionType.val,    // 灞炴�у��
                                 lastCode.getData(),    // 鍦伴潰鐮�
                                 JSON.toJSONString(new HeightDepthDto(oriSta.getHeight(), Optional.ofNullable(oriSta.getDepth()).orElse((double) 0))),   // 鍔ㄤ綔鍙傛暟
                                 ActionTypeType.ReadyTakeFromConveyorSta.val(),    // 鍔ㄤ綔绫诲瀷
@@ -1351,7 +1362,8 @@
                             ));
                         }
                         // 璁$畻璐у弶宸ヤ綔鏂瑰悜
-                        staWorkDirection = mapService.calculateAgvWorkDirectionByStation(destStaWorkDirection, lastDirection);
+//                        staWorkDirection = mapService.calculateAgvWorkDirectionByStation(destStaWorkDirection, lastDirection);
+                        actuatorDirectionType = ActuatorDirectionType.fromVal(destSta.getActDir());
                         actionList.add(new Action(
                                 null,    // 缂栧彿
                                 task.getBusId(),    // 鎬荤嚎
@@ -1359,7 +1371,7 @@
                                 null,    // 鍔ㄤ綔鍙�
                                 null,    // 浼樺厛绾�
                                 ActionTypeType.ReadyReleaseToConveyorSta.desc,    // 鍚嶇О
-                                staWorkDirection,    // 灞炴�у��
+                                (double) actuatorDirectionType.val,    // 灞炴�у��
                                 lastCode.getData(),    // 鍦伴潰鐮�
                                 JSON.toJSONString(new HeightDepthDto(destSta.getHeight(), Optional.ofNullable(destSta.getDepth()).orElse((double) 0))),   // 鍔ㄤ綔鍙傛暟
                                 ActionTypeType.ReadyReleaseToConveyorSta.val(),    // 鍔ㄤ綔绫诲瀷
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/core/service/MapService.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/service/MapService.java
index 15614f4..ae8ee1c 100644
--- a/zy-acs-manager/src/main/java/com/zy/acs/manager/core/service/MapService.java
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/service/MapService.java
@@ -1,7 +1,7 @@
 package com.zy.acs.manager.core.service;
 
 import com.alibaba.fastjson.JSON;
-import com.zy.acs.common.enums.AgvDirectionType;
+import com.zy.acs.common.enums.ActuatorDirectionType;
 import com.zy.acs.framework.common.Cools;
 import com.zy.acs.manager.core.constant.MapDataConstant;
 import com.zy.acs.manager.core.domain.DirectionDto;
@@ -158,17 +158,10 @@
         return angle;
     }
 
-    // 鍧愭爣璐ф灦闃堝�� todo:luxiaotao
-    public AgvDirectionType calculateAgvWorkDirectionByShelf(Loc loc, Code code) {
+    // 鍧愭爣璐ф灦闃堝��
+    public ActuatorDirectionType calculateAgvWorkDirectionByShelf(Loc loc, Code code) {
         Integer compDirect = loc.getCompDirect();
-        AgvDirectionType agvDirectionType = null;
-        if (compDirect == 0) {
-            agvDirectionType = AgvDirectionType.RIGHT;
-        }
-        if (compDirect == 1) {
-            agvDirectionType = AgvDirectionType.LEFT;
-        }
-        return agvDirectionType;
+        return ActuatorDirectionType.fromVal(compDirect);
     }
 
     public Double getStaAngle(Sta sta, Double workDirection) {
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/core/service/ValidService.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/service/ValidService.java
index 490fddb..6b2caec 100644
--- a/zy-acs-manager/src/main/java/com/zy/acs/manager/core/service/ValidService.java
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/core/service/ValidService.java
@@ -3,6 +3,7 @@
 import com.alibaba.fastjson.JSON;
 import com.zy.acs.framework.common.Cools;
 import com.zy.acs.framework.common.SnowflakeIdWorker;
+import com.zy.acs.manager.common.config.UplinkProperties;
 import com.zy.acs.manager.common.domain.TaskDto;
 import com.zy.acs.manager.common.exception.BusinessException;
 import com.zy.acs.manager.manager.entity.Code;
@@ -10,6 +11,7 @@
 import com.zy.acs.manager.manager.entity.Sta;
 import com.zy.acs.manager.manager.entity.Task;
 import com.zy.acs.manager.manager.enums.TaskTypeType;
+import com.zy.acs.manager.manager.enums.TaskUplinkStateType;
 import com.zy.acs.manager.manager.service.CodeService;
 import com.zy.acs.manager.manager.service.LocService;
 import com.zy.acs.manager.manager.service.StaService;
@@ -36,17 +38,20 @@
     private MapService mapService;
     @Autowired
     private SnowflakeIdWorker snowflakeIdWorker;
+    @Autowired
+    private UplinkProperties uplinkProperties;
 
     public List<Task> validTaskDtoList(List<TaskDto> taskDtoList) {
         List<Task> taskList = new ArrayList<>();
+        String uplinkSts = uplinkProperties.getEnabled() ? TaskUplinkStateType.PENDING.toString() : TaskUplinkStateType.SKIPPED.toString();
         for (TaskDto taskDto : taskDtoList) {
-            if (Cools.isEmpty(taskDto.getSeqNum())) {
+            if (Cools.isEmpty(taskDto.getTaskNo())) {
                 throw new BusinessException("Task seqNum can't be empty!");
             }
             Task task = new Task();
             taskList.add(task);
             task.setUuid(String.valueOf(snowflakeIdWorker.nextId()).substring(3));
-            task.setSeqNum(taskDto.getSeqNum());
+            task.setSeqNum(taskDto.getTaskNo());
             task.setPriority(taskDto.getPriority());
 
             // ori --------------------------
@@ -140,6 +145,7 @@
                         throw new BusinessException("seqNum:" + task.getSeqNum() + " is wrong锛宱riLoc锛�" + task.getOriLoc() + " is unable to reach destLoc" + task.getDestLoc());
                     }
                     task.setPhase(JSON.toJSONString(pathList));
+                    task.setUplinkSts(uplinkSts);
                     break;
                 case LOC_TO_STA:
                     oriLoc = locService.getById(task.getOriLoc());
@@ -158,6 +164,7 @@
                         throw new BusinessException("seqNum:" + task.getSeqNum() + " is wrong锛宱riLoc锛�" + task.getOriLoc() + " can't move to destSta" + task.getDestSta());
                     }
                     task.setPhase(JSON.toJSONString(pathList));
+                    task.setUplinkSts(uplinkSts);
                     break;
                 case STA_TO_LOC:
                     oriSta = staService.getById(task.getOriSta());
@@ -176,6 +183,7 @@
                         throw new BusinessException("seqNum:" + task.getSeqNum() + " is wrong锛宱riSta锛�" + task.getOriSta() + " is unable to react destLoc" + task.getDestLoc());
                     }
                     task.setPhase(JSON.toJSONString(pathList));
+                    task.setUplinkSts(uplinkSts);
                     break;
                 case STA_TO_STA:
                     oriSta = staService.getById(task.getOriSta());
@@ -194,6 +202,7 @@
                         throw new BusinessException("seqNum:" + task.getSeqNum() + " is wrong锛宱riSta锛�" + task.getOriSta() + " can't move to destSta" + task.getDestSta());
                     }
                     task.setPhase(JSON.toJSONString(pathList));
+                    task.setUplinkSts(uplinkSts);
                     break;
                 default:
                     throw new BusinessException("seqNum:" + task.getSeqNum() + " is wrong锛� cause this type not exist");
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/controller/BusController.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/controller/BusController.java
index d959c93..3e01383 100644
--- a/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/controller/BusController.java
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/controller/BusController.java
@@ -6,12 +6,13 @@
 import com.zy.acs.framework.common.Cools;
 import com.zy.acs.framework.common.R;
 import com.zy.acs.manager.common.annotation.OperationLog;
+import com.zy.acs.manager.common.constant.Constants;
 import com.zy.acs.manager.common.domain.*;
 import com.zy.acs.manager.common.utils.BusinessSortService;
 import com.zy.acs.manager.common.utils.ExcelUtil;
 import com.zy.acs.manager.core.service.MainService;
 import com.zy.acs.manager.manager.controller.param.BusCreateParam;
-import com.zy.acs.manager.manager.controller.param.OpenBusSubmitParam;
+import com.zy.acs.manager.core.integrate.dto.OpenBusSubmitParam;
 import com.zy.acs.manager.manager.entity.Bus;
 import com.zy.acs.manager.manager.entity.Task;
 import com.zy.acs.manager.manager.enums.BusStsType;
@@ -94,10 +95,10 @@
     @PostMapping("/bus/save")
     public R save(@RequestBody BusCreateParam param) {
         OpenBusSubmitParam submitParam = new OpenBusSubmitParam();
-        submitParam.setBatch(param.getBusNo());
+        submitParam.setBatchNo(param.getBusNo());
         for (TaskIdByLongDto dto : param.getTaskList()) {
             TaskDto taskDto = new TaskDto();
-            taskDto.setSeqNum(dto.getSeqNum());
+            taskDto.setTaskNo(dto.getSeqNum());
             taskDto.setPriority(dto.getPriority());
             if (!Cools.isEmpty(dto.getOriSta())) {
                 taskDto.setOriSta(staService.getById(dto.getOriSta()).getStaNo());
@@ -111,7 +112,7 @@
             if (!Cools.isEmpty(dto.getDestLoc())) {
                 taskDto.setDestLoc(locService.getById(dto.getDestLoc()).getLocNo());
             }
-            submitParam.getTaskList().add(taskDto);
+            submitParam.getTasks().add(taskDto);
         }
         Bus bus = mainService.generateBusAndTask(submitParam, param.getMemo());
         return R.ok("Save Success").add(bus);
@@ -176,7 +177,7 @@
                 .in(Task::getTaskSts, TaskStsType.INIT.val(), TaskStsType.WAITING.val()));
         if (!Cools.isEmpty(taskList)) {
             for (Task task : taskList) {
-                taskService.cancel(task.getId(), getLoginUserId());
+                taskService.cancel(task.getId(), getLoginUserId(), Constants.HANDLE);
             }
         }
         if (0 == taskService.count(new LambdaQueryWrapper<Task>().eq(Task::getBusId, bus.getId()).eq(Task::getTaskSts, TaskStsType.COMPLETE.val()))) {
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/controller/CodeController.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/controller/CodeController.java
index e4b5621..462d8a3 100644
--- a/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/controller/CodeController.java
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/controller/CodeController.java
@@ -17,6 +17,7 @@
 import com.zy.acs.manager.manager.entity.Code;
 import com.zy.acs.manager.manager.entity.CodeGap;
 import com.zy.acs.manager.manager.entity.Route;
+import com.zy.acs.manager.manager.enums.StatusType;
 import com.zy.acs.manager.manager.service.CodeGapService;
 import com.zy.acs.manager.manager.service.CodeService;
 import com.zy.acs.manager.manager.service.RouteService;
@@ -159,6 +160,7 @@
             code.setUuid("code".concat(code.getData()));
 //            code.setCorner(0);
             code.setScale(GsonUtils.toJson(Cools.add("x", 1).add("y", 1)));
+            code.setStatus(StatusType.ENABLE.val);
             code.setCreateBy(userId);
             code.setCreateTime(now);
             code.setUpdateBy(userId);
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/controller/IntegrationRecordController.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/controller/IntegrationRecordController.java
new file mode 100644
index 0000000..54021e2
--- /dev/null
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/controller/IntegrationRecordController.java
@@ -0,0 +1,108 @@
+package com.zy.acs.manager.manager.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.zy.acs.framework.common.Cools;
+import com.zy.acs.framework.common.R;
+import com.zy.acs.manager.common.utils.ExcelUtil;
+import com.zy.acs.manager.common.annotation.OperationLog;
+import com.zy.acs.manager.common.domain.BaseParam;
+import com.zy.acs.manager.common.domain.KeyValVo;
+import com.zy.acs.manager.common.domain.PageParam;
+import com.zy.acs.manager.manager.entity.IntegrationRecord;
+import com.zy.acs.manager.manager.service.IntegrationRecordService;
+import com.zy.acs.manager.system.controller.BaseController;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.*;
+
+@RestController
+@RequestMapping("/api")
+public class IntegrationRecordController extends BaseController {
+
+    @Autowired
+    private IntegrationRecordService integrationRecordService;
+
+    @PreAuthorize("hasAuthority('manager:integrationRecord:list')")
+    @PostMapping("/integrationRecord/page")
+    public R page(@RequestBody Map<String, Object> map) {
+        BaseParam baseParam = buildParam(map, BaseParam.class);
+        PageParam<IntegrationRecord, BaseParam> pageParam = new PageParam<>(baseParam, IntegrationRecord.class);
+        return R.ok().add(integrationRecordService.page(pageParam, pageParam.buildWrapper(true)));
+    }
+
+    @PreAuthorize("hasAuthority('manager:integrationRecord:list')")
+    @PostMapping("/integrationRecord/list")
+    public R list(@RequestBody Map<String, Object> map) {
+        return R.ok().add(integrationRecordService.list());
+    }
+
+    @PreAuthorize("hasAuthority('manager:integrationRecord:list')")
+    @PostMapping({"/integrationRecord/many/{ids}", "/integrationRecords/many/{ids}"})
+    public R many(@PathVariable Long[] ids) {
+        return R.ok().add(integrationRecordService.listByIds(Arrays.asList(ids)));
+    }
+
+    @PreAuthorize("hasAuthority('manager:integrationRecord:list')")
+    @GetMapping("/integrationRecord/{id}")
+    public R get(@PathVariable("id") Long id) {
+        return R.ok().add(integrationRecordService.getById(id));
+    }
+
+    @PreAuthorize("hasAuthority('manager:integrationRecord:save')")
+    @OperationLog("Create Integration Record")
+    @PostMapping("/integrationRecord/save")
+    public R save(@RequestBody IntegrationRecord integrationRecord) {
+        integrationRecord.setCreateTime(new Date());
+        integrationRecord.setUpdateTime(new Date());
+        if (!integrationRecordService.save(integrationRecord)) {
+            return R.error("Save Fail");
+        }
+        return R.ok("Save Success").add(integrationRecord);
+    }
+
+    @PreAuthorize("hasAuthority('manager:integrationRecord:update')")
+    @OperationLog("Update Integration Record")
+    @PostMapping("/integrationRecord/update")
+    public R update(@RequestBody IntegrationRecord integrationRecord) {
+        integrationRecord.setUpdateTime(new Date());
+        if (!integrationRecordService.updateById(integrationRecord)) {
+            return R.error("Update Fail");
+        }
+        return R.ok("Update Success").add(integrationRecord);
+    }
+
+    @PreAuthorize("hasAuthority('manager:integrationRecord:remove')")
+    @OperationLog("Delete Integration Record")
+    @PostMapping("/integrationRecord/remove/{ids}")
+    public R remove(@PathVariable Long[] ids) {
+        if (!integrationRecordService.removeByIds(Arrays.asList(ids))) {
+            return R.error("Delete Fail");
+        }
+        return R.ok("Delete Success").add(ids);
+    }
+
+    @PreAuthorize("hasAuthority('manager:integrationRecord:list')")
+    @PostMapping("/integrationRecord/query")
+    public R query(@RequestParam(required = false) String condition) {
+        List<KeyValVo> vos = new ArrayList<>();
+        LambdaQueryWrapper<IntegrationRecord> wrapper = new LambdaQueryWrapper<>();
+        if (!Cools.isEmpty(condition)) {
+            wrapper.like(IntegrationRecord::getNamespace, condition);
+        }
+        integrationRecordService.page(new Page<>(1, 30), wrapper).getRecords().forEach(
+                item -> vos.add(new KeyValVo(item.getId(), item.getNamespace()))
+        );
+        return R.ok().add(vos);
+    }
+
+    @PreAuthorize("hasAuthority('manager:integrationRecord:list')")
+    @PostMapping("/integrationRecord/export")
+    public void export(@RequestBody Map<String, Object> map, HttpServletResponse response) throws Exception {
+        ExcelUtil.build(ExcelUtil.create(integrationRecordService.list(), IntegrationRecord.class), response);
+    }
+
+}
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/controller/TaskController.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/controller/TaskController.java
index 77013c1..9469ef4 100644
--- a/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/controller/TaskController.java
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/controller/TaskController.java
@@ -1,11 +1,11 @@
 package com.zy.acs.manager.manager.controller;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.zy.acs.framework.common.Cools;
 import com.zy.acs.framework.common.R;
 import com.zy.acs.manager.common.annotation.OperationLog;
+import com.zy.acs.manager.common.constant.Constants;
 import com.zy.acs.manager.common.domain.BaseParam;
 import com.zy.acs.manager.common.domain.KeyValVo;
 import com.zy.acs.manager.common.domain.PageParam;
@@ -15,7 +15,6 @@
 import com.zy.acs.manager.manager.entity.Task;
 import com.zy.acs.manager.manager.service.TaskService;
 import com.zy.acs.manager.system.controller.BaseController;
-import com.zy.acs.manager.system.entity.User;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
@@ -119,14 +118,14 @@
     @OperationLog("Complete Task")
     @GetMapping("/task/complete/{id}")
     public R complete(@PathVariable Long id) {
-        return taskService.complete(id, getLoginUserId()) ? R.ok("Complete Success") : R.error("Complete Fail");
+        return taskService.complete(id, getLoginUserId(), Constants.HANDLE) ? R.ok("Complete Success") : R.error("Complete Fail");
     }
 
     @PreAuthorize("hasAuthority('manager:task:update')")
     @OperationLog("Cancel Task")
     @GetMapping("/task/cancel/{id}")
     public R cancel(@PathVariable Long id) {
-        return taskService.cancel(id, getLoginUserId()) ? R.ok("Cancel Success") : R.error("Cancel Fail");
+        return taskService.cancel(id, getLoginUserId(), Constants.HANDLE) ? R.ok("Cancel Success") : R.error("Cancel Fail");
     }
 
 }
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/entity/IntegrationRecord.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/entity/IntegrationRecord.java
new file mode 100644
index 0000000..b99f34c
--- /dev/null
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/entity/IntegrationRecord.java
@@ -0,0 +1,196 @@
+package com.zy.acs.manager.manager.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+@TableName("man_integration_record")
+public class IntegrationRecord implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * ID
+     */
+    @ApiModelProperty(value= "ID")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 缂栧彿
+     */
+    @ApiModelProperty(value= "缂栧彿")
+    private String uuid;
+
+    /**
+     * 鍚嶇О绌洪棿
+     */
+    @ApiModelProperty(value= "鍚嶇О绌洪棿")
+    private String namespace;
+
+    /**
+     * 鎺ュ彛鍦板潃
+     */
+    @ApiModelProperty(value= "鎺ュ彛鍦板潃")
+    private String url;
+
+    /**
+     * 骞冲彴瀵嗛挜
+     */
+    @ApiModelProperty(value= "骞冲彴瀵嗛挜")
+    private String appkey;
+
+    /**
+     * 璋冪敤鏂规爣璇�
+     */
+    @ApiModelProperty(value= "璋冪敤鏂规爣璇�")
+    private String caller;
+
+    /**
+     * 鏂瑰悜 1: 琚皟鐢�  2: 璋冪敤澶栭儴  
+     */
+    @ApiModelProperty(value= "鏂瑰悜 1: 琚皟鐢�  2: 璋冪敤澶栭儴  ")
+    private Integer direction;
+
+    /**
+     * 鏃堕棿鎴�
+     */
+    @ApiModelProperty(value= "鏃堕棿鎴�")
+    private String timestamp;
+
+    /**
+     * 瀹㈡埛绔疘P
+     */
+    @ApiModelProperty(value= "瀹㈡埛绔疘P")
+    private String clientIp;
+
+    /**
+     * 璇锋眰鍐呭
+     */
+    @ApiModelProperty(value= "璇锋眰鍐呭")
+    private String request;
+
+    /**
+     * 鍝嶅簲鍐呭
+     */
+    @ApiModelProperty(value= "鍝嶅簲鍐呭")
+    private String response;
+
+    /**
+     * 寮傚父鍐呭
+     */
+    @ApiModelProperty(value= "寮傚父鍐呭")
+    private String err;
+
+    /**
+     * 缁撴灉 1: 鎴愬姛  0: 澶辫触  
+     */
+    @ApiModelProperty(value= "缁撴灉 1: 鎴愬姛  0: 澶辫触  ")
+    private Integer result;
+
+    /**
+     * 鑰楁椂
+     */
+    @ApiModelProperty(value= "鑰楁椂")
+    private Integer costMs;
+
+    /**
+     * 鐘舵�� 1: 姝e父  0: 鍐荤粨  
+     */
+    @ApiModelProperty(value= "鐘舵�� 1: 姝e父  0: 鍐荤粨  ")
+    private Integer status;
+
+    /**
+     * 娣诲姞鏃堕棿
+     */
+    @ApiModelProperty(value= "娣诲姞鏃堕棿")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+
+    /**
+     * 淇敼鏃堕棿
+     */
+    @ApiModelProperty(value= "淇敼鏃堕棿")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    private Date updateTime;
+
+    /**
+     * 澶囨敞
+     */
+    @ApiModelProperty(value= "澶囨敞")
+    private String memo;
+
+    public IntegrationRecord() {}
+
+    public IntegrationRecord(String uuid,String namespace,String url,String appkey,String caller,Integer direction,String timestamp,String clientIp,String request,String response,String err,Integer result,Integer costMs,Integer status,Date createTime,Date updateTime,String memo) {
+        this.uuid = uuid;
+        this.namespace = namespace;
+        this.url = url;
+        this.appkey = appkey;
+        this.caller = caller;
+        this.direction = direction;
+        this.timestamp = timestamp;
+        this.clientIp = clientIp;
+        this.request = request;
+        this.response = response;
+        this.err = err;
+        this.result = result;
+        this.costMs = costMs;
+        this.status = status;
+        this.createTime = createTime;
+        this.updateTime = updateTime;
+        this.memo = memo;
+    }
+
+//    IntegrationRecord integrationRecord = new IntegrationRecord(
+//            null,    // 缂栧彿
+//            null,    // 鍚嶇О绌洪棿
+//            null,    // 鎺ュ彛鍦板潃
+//            null,    // 骞冲彴瀵嗛挜
+//            null,    // 璋冪敤鏂规爣璇�
+//            null,    // 鏂瑰悜[闈炵┖]
+//            null,    // 鏃堕棿鎴�
+//            null,    // 瀹㈡埛绔疘P
+//            null,    // 璇锋眰鍐呭
+//            null,    // 鍝嶅簲鍐呭
+//            null,    // 寮傚父鍐呭
+//            null,    // 缁撴灉
+//            null,    // 鑰楁椂
+//            null,    // 鐘舵��
+//            null,    // 娣诲姞鏃堕棿[闈炵┖]
+//            null,    // 淇敼鏃堕棿[闈炵┖]
+//            null    // 澶囨敞
+//    );
+
+    public Boolean getResultBool(){
+        if (null == this.result){ return null; }
+        switch (this.result){
+            case 1:
+                return true;
+            case 0:
+                return false;
+            default:
+                return null;
+        }
+    }
+
+    public Boolean getStatusBool(){
+        if (null == this.status){ return null; }
+        switch (this.status){
+            case 1:
+                return true;
+            case 0:
+                return false;
+            default:
+                return null;
+        }
+    }
+
+}
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/entity/Loc.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/entity/Loc.java
index d34dc3b..3b73564 100644
--- a/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/entity/Loc.java
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/entity/Loc.java
@@ -57,9 +57,9 @@
     private Long code;
 
     /**
-     * 姣旂爜鏂瑰悜闃� 1:  澶т簬  0    灏忎簬
+     * 姣旂爜鏂瑰悜闃�
      */
-    @ApiModelProperty(value= "姣旂爜鏂瑰悜闃� 1:  澶т簬  0    灏忎簬")
+    @ApiModelProperty(value= "姣旂爜鏂瑰悜闃�")
     private Integer compDirect;
 
     /**
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/entity/Sta.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/entity/Sta.java
index 3b1b259..720cd74 100644
--- a/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/entity/Sta.java
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/entity/Sta.java
@@ -65,6 +65,9 @@
     @ApiModelProperty(value= "浣滀笟瑙掑害")
     private String angle;
 
+    @ApiModelProperty(value= "璐у弶鏂瑰悜")
+    private Integer actDir;
+
     @ApiModelProperty(value= "杩炵画鍏ュ簱绛夊緟(ms)")
     private Integer inboundWait;
 
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/entity/Task.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/entity/Task.java
index af1c34c..9a49997 100644
--- a/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/entity/Task.java
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/entity/Task.java
@@ -18,202 +18,106 @@
 
     private static final long serialVersionUID = 1L;
 
-    /**
-     * ID
-     */
     @ApiModelProperty(value= "ID")
     @TableId(value = "id", type = IdType.AUTO)
     private Long id;
 
-    /**
-     * 缂栧彿
-     */
     @ApiModelProperty(value= "缂栧彿")
     private String uuid;
 
-    /**
-     * 鎬荤嚎
-     */
     @ApiModelProperty(value= "鎬荤嚎")
     private Long busId;
 
-    /**
-     * 浠诲姟鍙�
-     */
     @ApiModelProperty(value= "浠诲姟鍙�")
     private String seqNum;
 
-    /**
-     * 浼樺厛绾�
-     */
     @ApiModelProperty(value= "浼樺厛绾�")
     private Integer priority;
 
-    /**
-     * 鍚嶇О
-     */
     @ApiModelProperty(value= "鍚嶇О")
     private String name;
 
-    /**
-     * 浠诲姟杩涘害
-     */
     @ApiModelProperty(value= "浠诲姟杩涘害")
     private Long taskSts;
 
-    /**
-     * 浠诲姟绫诲瀷
-     */
     @ApiModelProperty(value= "浠诲姟绫诲瀷")
     private Long taskType;
 
-    /**
-     * AGV
-     */
     @ApiModelProperty(value= "AGV")
     private Long agvId;
 
-    /**
-     * 宸ヤ綔鏃堕棿
-     */
     @ApiModelProperty(value= "宸ヤ綔鏃堕棿")
     private Date ioTime;
 
-    /**
-     * 寮�濮嬫椂闂�
-     */
     @ApiModelProperty(value= "寮�濮嬫椂闂�")
     private Date startTime;
 
-    /**
-     * 缁撴潫鏃堕棿
-     */
     @ApiModelProperty(value= "缁撴潫鏃堕棿")
     private Date endTime;
 
-    /**
-     * 寮傚父鏃堕棿
-     */
     @ApiModelProperty(value= "寮傚父鏃堕棿")
     private Date errTime;
 
-    /**
-     * 璧峰绔�
-     */
     @ApiModelProperty(value= "璧峰绔�")
     private Long oriSta;
 
-    /**
-     * 璧峰搴撲綅
-     */
     @ApiModelProperty(value= "璧峰搴撲綅")
     private Long oriLoc;
 
-    /**
-     * 璧峰鐮�
-     */
     @ApiModelProperty(value= "璧峰鐮�")
     private Long oriCode;
 
-    /**
-     * 璧峰宸烽亾鍝堝笇
-     */
     @ApiModelProperty(value= "璧峰宸烽亾鍝堝笇")
     private String oriLaneHash;
 
-    /**
-     * 鐩爣绔�
-     */
     @ApiModelProperty(value= "鐩爣绔�")
     private Long destSta;
 
-    /**
-     * 鐩爣搴撲綅
-     */
     @ApiModelProperty(value= "鐩爣搴撲綅")
     private Long destLoc;
 
-    /**
-     * 鐩爣鐮�
-     */
     @ApiModelProperty(value= "鐩爣鐮�")
     private Long destCode;
 
-    /**
-     * 鐩爣宸烽亾鍝堝笇
-     */
     @ApiModelProperty(value= "鐩爣宸烽亾鍝堝笇")
     private String destLaneHash;
 
-    /**
-     * 绌烘澘
-     */
     @ApiModelProperty(value= "绌烘澘")
     private String emptyMk;
 
-    /**
-     * 鎵樼洏鐮�
-     */
+    @ApiModelProperty(value= "涓婅鐘舵��")
+    private String uplinkSts;
+
     @ApiModelProperty(value= "鎵樼洏鐮�")
     private String zpallet;
 
-    /**
-     * 鐜妭
-     */
     @ApiModelProperty(value= "鐜妭")
     private String phase;
 
-    /**
-     * 寮傚父鎻忚堪
-     */
     @ApiModelProperty(value= "寮傚父鎻忚堪")
     private String errDesc;
 
-    /**
-     * 鐘舵�� 1: 姝e父  0: 鍐荤粨  
-     */
     @ApiModelProperty(value= "鐘舵�� 1: 姝e父  0: 鍐荤粨  ")
     private Integer status;
 
-    /**
-     * 鏄惁鍒犻櫎 1: 鏄�  0: 鍚�  
-     */
     @ApiModelProperty(value= "鏄惁鍒犻櫎 1: 鏄�  0: 鍚�  ")
     private Integer deleted;
 
-    /**
-     * 绉熸埛
-     */
     @ApiModelProperty(value= "绉熸埛")
     private Long tenantId;
 
-    /**
-     * 娣诲姞浜哄憳
-     */
     @ApiModelProperty(value= "娣诲姞浜哄憳")
     private Long createBy;
 
-    /**
-     * 娣诲姞鏃堕棿
-     */
     @ApiModelProperty(value= "娣诲姞鏃堕棿")
     private Date createTime;
 
-    /**
-     * 淇敼浜哄憳
-     */
     @ApiModelProperty(value= "淇敼浜哄憳")
     private Long updateBy;
 
-    /**
-     * 淇敼鏃堕棿
-     */
     @ApiModelProperty(value= "淇敼鏃堕棿")
     private Date updateTime;
 
-    /**
-     * 澶囨敞
-     */
     @ApiModelProperty(value= "澶囨敞")
     private String memo;
 
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/enums/IntegrationDirectionType.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/enums/IntegrationDirectionType.java
new file mode 100644
index 0000000..626cefa
--- /dev/null
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/enums/IntegrationDirectionType.java
@@ -0,0 +1,16 @@
+package com.zy.acs.manager.manager.enums;
+
+public enum IntegrationDirectionType {
+
+    NONE(0),        // 鏈煡
+    INBOUND(1),     // 鎺ユ敹
+    OUTBOUND(2),    // 璋冪敤
+    ;
+
+    public int value;
+
+    IntegrationDirectionType(int value) {
+        this.value = value;
+    }
+
+}
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/enums/TaskUplinkStateType.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/enums/TaskUplinkStateType.java
new file mode 100644
index 0000000..d70d920
--- /dev/null
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/enums/TaskUplinkStateType.java
@@ -0,0 +1,28 @@
+package com.zy.acs.manager.manager.enums;
+
+import com.zy.acs.framework.common.Cools;
+
+public enum TaskUplinkStateType {
+
+    NONE,       // 鏈煡
+    PENDING,    // 寰呬笂鎶�
+    SENDING,    // 涓婃姤涓�
+    SUCCESS,    // 鎴愬姛
+    FAILED,     // 澶辫触
+
+    SKIPPED,    // 璺宠繃
+    ;
+
+    public static TaskUplinkStateType of(String state) {
+        if (Cools.isEmpty(state)) {
+            return NONE;
+        }
+        for (TaskUplinkStateType type : TaskUplinkStateType.values()) {
+            if (type.toString().equals(state)) {
+                return type;
+            }
+        }
+        return NONE;
+    }
+
+}
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/mapper/IntegrationRecordMapper.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/mapper/IntegrationRecordMapper.java
new file mode 100644
index 0000000..fe8344a
--- /dev/null
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/mapper/IntegrationRecordMapper.java
@@ -0,0 +1,12 @@
+package com.zy.acs.manager.manager.mapper;
+
+import com.zy.acs.manager.manager.entity.IntegrationRecord;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.springframework.stereotype.Repository;
+
+@Mapper
+@Repository
+public interface IntegrationRecordMapper extends BaseMapper<IntegrationRecord> {
+
+}
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/service/BusService.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/service/BusService.java
index c385325..617a696 100644
--- a/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/service/BusService.java
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/service/BusService.java
@@ -1,7 +1,7 @@
 package com.zy.acs.manager.manager.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
-import com.zy.acs.manager.manager.controller.param.OpenBusSubmitParam;
+import com.zy.acs.manager.core.integrate.dto.OpenBusSubmitParam;
 import com.zy.acs.manager.manager.entity.Bus;
 import com.zy.acs.manager.manager.enums.BusStsType;
 
@@ -9,6 +9,8 @@
 
 public interface BusService extends IService<Bus> {
 
+    Bus selectByBusNo(String busNo);
+
     Bus selectByUuid(String uuid);
 
     String checkoutValid(OpenBusSubmitParam param);
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/service/IntegrationRecordService.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/service/IntegrationRecordService.java
new file mode 100644
index 0000000..e14cb23
--- /dev/null
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/service/IntegrationRecordService.java
@@ -0,0 +1,10 @@
+package com.zy.acs.manager.manager.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.zy.acs.manager.manager.entity.IntegrationRecord;
+
+public interface IntegrationRecordService extends IService<IntegrationRecord> {
+
+    Boolean syncRecord(IntegrationRecord record);
+
+}
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/service/TaskService.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/service/TaskService.java
index 5505d5f..dec3af8 100644
--- a/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/service/TaskService.java
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/service/TaskService.java
@@ -19,7 +19,7 @@
 
     Task pick(TaskStsType taskStsType);
 
-    Task selectByUuid(String uuid);
+    Task selectBySeqNum(Long busId, String seqNum);
 
     List<Task> selectBySts(TaskStsType taskStsType);
 
@@ -27,9 +27,9 @@
 
     List<Map<String, Object>> selectStatByLastSevenDays();
 
-    Boolean complete(Long taskId, Long userId);
+    Boolean complete(Long taskId, Long userId, String from);
 
-    Boolean cancel(Long taskId, Long userId);
+    Boolean cancel(Long taskId, Long userId, String from);
 
     LaneDto checkoutOriginLane(Task task);
 
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/service/impl/BusServiceImpl.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/service/impl/BusServiceImpl.java
index 0d12a98..6b49886 100644
--- a/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/service/impl/BusServiceImpl.java
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/service/impl/BusServiceImpl.java
@@ -5,8 +5,9 @@
 import com.zy.acs.framework.common.BaseRes;
 import com.zy.acs.framework.common.Cools;
 import com.zy.acs.framework.exception.CoolException;
+import com.zy.acs.manager.common.constant.Constants;
 import com.zy.acs.manager.common.domain.TaskDto;
-import com.zy.acs.manager.manager.controller.param.OpenBusSubmitParam;
+import com.zy.acs.manager.core.integrate.dto.OpenBusSubmitParam;
 import com.zy.acs.manager.manager.entity.Bus;
 import com.zy.acs.manager.manager.entity.Loc;
 import com.zy.acs.manager.manager.entity.Task;
@@ -33,6 +34,14 @@
     private LocService locService;
 
     @Override
+    public Bus selectByBusNo(String busNo) {
+        if (Cools.isEmpty(busNo)) {
+            return null;
+        }
+        return this.getOne(new LambdaQueryWrapper<Bus>().eq(Bus::getBusNo, busNo).last(Constants.LIMIT_ONE));
+    }
+
+    @Override
     public Bus selectByUuid(String uuid) {
         return this.getOne(new LambdaQueryWrapper<Bus>().eq(Bus::getUuid, uuid));
     }
@@ -41,7 +50,7 @@
         if (Cools.isEmpty(param)) {
             return;
         }
-        List<TaskDto> taskList = param.getTaskList();
+        List<TaskDto> taskList = param.getTasks();
         if (Cools.isEmpty(taskList)) {
             return;
         }
@@ -67,7 +76,7 @@
         if (null == param) {
             return BaseRes.PARAM;
         }
-        if (Cools.isEmpty(param.getBatch())) {
+        if (Cools.isEmpty(param.getBatchNo())) {
             return "Batch cannot be empty!";
         }
         this.test(param);
@@ -75,7 +84,7 @@
         Set<String> oriLocNoSet = new HashSet<>();
         Set<String> destStaNoSet = new HashSet<>();
         Set<String> destLocNoSet = new HashSet<>();
-        for (TaskDto dto : param.getTaskList()) {
+        for (TaskDto dto : param.getTasks()) {
             if (!Cools.isEmpty(dto.getOriSta()) && !Cools.isEmpty(dto.getOriLoc())) {
                 return "OriSta and OriLoc cannot exist at the same time!";
             }
@@ -119,8 +128,8 @@
                     destLocNoSet.add(dto.getDestLoc());
                 }
             }
-            if (Cools.isEmpty(dto.getSeqNum())) {
-                dto.setSeqNum(taskService.generateSeqNum());
+            if (Cools.isEmpty(dto.getTaskNo())) {
+                dto.setTaskNo(taskService.generateSeqNum());
             }
 
         }
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/service/impl/IntegrationRecordServiceImpl.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/service/impl/IntegrationRecordServiceImpl.java
new file mode 100644
index 0000000..5c9f300
--- /dev/null
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/service/impl/IntegrationRecordServiceImpl.java
@@ -0,0 +1,38 @@
+package com.zy.acs.manager.manager.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.zy.acs.framework.common.R;
+import com.zy.acs.manager.core.service.ThreadPoolRegulator;
+import com.zy.acs.manager.manager.mapper.IntegrationRecordMapper;
+import com.zy.acs.manager.manager.entity.IntegrationRecord;
+import com.zy.acs.manager.manager.service.IntegrationRecordService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.concurrent.CompletableFuture;
+
+@Slf4j
+@Service("integrationRecordService")
+public class IntegrationRecordServiceImpl extends ServiceImpl<IntegrationRecordMapper, IntegrationRecord> implements IntegrationRecordService {
+
+    @Autowired
+    private ThreadPoolRegulator threadPoolRegulator;
+
+    @Override
+    public Boolean syncRecord(IntegrationRecord record) {
+        CompletableFuture<?> completableFuture = CompletableFuture.supplyAsync(() -> {
+
+            if (!this.save(record)) {
+                log.error("failed to save record {}", JSON.toJSONString(record));
+            }
+//            mapDataDispatcher.modifyDynamicMatrix(null, null, param.getAgvNo(), true);
+//            avoidWaveCalculator.calcDynamicNodeByVehicle(agv, null);
+            return R.ok();
+        }, threadPoolRegulator.getInstance());
+
+        return true;
+    }
+
+}
diff --git a/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/service/impl/TaskServiceImpl.java b/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/service/impl/TaskServiceImpl.java
index 1f0ed1e..2613bdb 100644
--- a/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/service/impl/TaskServiceImpl.java
+++ b/zy-acs-manager/src/main/java/com/zy/acs/manager/manager/service/impl/TaskServiceImpl.java
@@ -17,6 +17,7 @@
 import com.zy.acs.manager.manager.enums.*;
 import com.zy.acs.manager.manager.mapper.TaskMapper;
 import com.zy.acs.manager.manager.service.*;
+import com.zy.acs.manager.system.service.ConfigService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -50,6 +51,8 @@
     private ActionService actionService;
     @Autowired
     private TravelService travelService;
+    @Autowired
+    private ConfigService configService;
 
     @Override
     public PageResult<Task> pageRel(PageParam<Task, BaseParam> pageParam) {
@@ -68,8 +71,16 @@
     }
 
     @Override
-    public Task selectByUuid(String uuid) {
-        return this.getOne(new LambdaQueryWrapper<Task>().eq(Task::getUuid, uuid));
+    public Task selectBySeqNum(Long busId, String seqNum) {
+        if (Cools.isEmpty(seqNum)) {
+            return null;
+        }
+        LambdaQueryWrapper<Task> wrapper = new LambdaQueryWrapper<>();
+        if (null != busId) {
+            wrapper.eq(Task::getBusId, busId);
+        }
+        wrapper.eq(Task::getSeqNum, seqNum);
+        return this.getOne(wrapper.last(Constants.LIMIT_ONE));
     }
 
     @Override
@@ -100,7 +111,7 @@
 
     @Override
     @Transactional
-    public Boolean complete(Long taskId, Long userId) {
+    public Boolean complete(Long taskId, Long userId, String from) {
         Task task = this.getById(taskId);
         if (null == task) {
             return Boolean.FALSE;
@@ -112,7 +123,7 @@
         task.setTaskSts(TaskStsType.COMPLETE.val());
         task.setUpdateTime(now);
         task.setUpdateBy(userId);
-        task.setMemo(Constants.HANDLE + " " + TaskStsType.COMPLETE);
+        task.setMemo(from + " " + TaskStsType.COMPLETE);
         if (!this.updateById(task)) {
             throw new CoolException(BaseRes.ERROR);
         }
@@ -141,7 +152,7 @@
 
     @Override
     @Transactional
-    public Boolean cancel(Long taskId, Long userId) {
+    public Boolean cancel(Long taskId, Long userId, String from) {
         Task task = this.getById(taskId);
         if (null == task) {
             return Boolean.FALSE;
@@ -153,7 +164,7 @@
         task.setTaskSts(TaskStsType.CANCEL.val());
         task.setUpdateTime(now);
         task.setUpdateBy(userId);
-        task.setMemo(Constants.HANDLE + " " + TaskStsType.CANCEL);
+        task.setMemo(from + " " + TaskStsType.CANCEL);
         if (!this.updateById(task)) {
             throw new CoolException(BaseRes.ERROR);
         }
@@ -280,6 +291,7 @@
         if (!task.getTaskSts().equals(TaskStsType.COMPLETE.val())) {
             return;
         }
+        Boolean maintainLocSts = configService.getVal("maintainLocSts", Boolean.class);
         Date now = new Date();
         // loc status
         Loc oriLoc = null;
@@ -288,31 +300,35 @@
         Sta destSta = null;
         switch (Objects.requireNonNull(TaskTypeType.get(task.getTaskTypeEl()))) {
             case LOC_TO_LOC:
-                oriLoc = locService.getById(task.getOriLoc());
-                if (oriLoc.getLocSts().equals(LocStsType.PAKOUT.val())) {
-                    oriLoc.setLocSts(LocStsType.IDLE.val());
-                    oriLoc.setUpdateTime(now);
-                    if (!locService.updateById(oriLoc)) {
-                        log.error("Loc [{}] 搴撲綅淇敼鐘舵�佸け璐�", task.getOriLoc$());
+                if (maintainLocSts) {
+                    oriLoc = locService.getById(task.getOriLoc());
+                    if (oriLoc.getLocSts().equals(LocStsType.PAKOUT.val())) {
+                        oriLoc.setLocSts(LocStsType.IDLE.val());
+                        oriLoc.setUpdateTime(now);
+                        if (!locService.updateById(oriLoc)) {
+                            log.error("Loc [{}] 搴撲綅淇敼鐘舵�佸け璐�", task.getOriLoc$());
+                        }
                     }
-                }
 
-                destLoc = locService.getById(task.getDestLoc());
-                if (destLoc.getLocSts().equals(LocStsType.PAKIN.val())) {
-                    destLoc.setLocSts(LocStsType.STOCK.val());
-                    destLoc.setUpdateTime(now);
-                    if (!locService.updateById(destLoc)) {
-                        log.error("Loc [{}] 搴撲綅淇敼鐘舵�佸け璐�", task.getDestLoc$());
+                    destLoc = locService.getById(task.getDestLoc());
+                    if (destLoc.getLocSts().equals(LocStsType.PAKIN.val())) {
+                        destLoc.setLocSts(LocStsType.STOCK.val());
+                        destLoc.setUpdateTime(now);
+                        if (!locService.updateById(destLoc)) {
+                            log.error("Loc [{}] 搴撲綅淇敼鐘舵�佸け璐�", task.getDestLoc$());
+                        }
                     }
                 }
                 break;
             case LOC_TO_STA:
-                oriLoc = locService.getById(task.getOriLoc());
-                if (oriLoc.getLocSts().equals(LocStsType.PAKOUT.val())) {
-                    oriLoc.setLocSts(LocStsType.IDLE.val());
-                    oriLoc.setUpdateTime(now);
-                    if (!locService.updateById(oriLoc)) {
-                        log.error("Loc [{}] 搴撲綅淇敼鐘舵�佸け璐�", task.getOriLoc$());
+                if (maintainLocSts) {
+                    oriLoc = locService.getById(task.getOriLoc());
+                    if (oriLoc.getLocSts().equals(LocStsType.PAKOUT.val())) {
+                        oriLoc.setLocSts(LocStsType.IDLE.val());
+                        oriLoc.setUpdateTime(now);
+                        if (!locService.updateById(oriLoc)) {
+                            log.error("Loc [{}] 搴撲綅淇敼鐘舵�佸け璐�", task.getOriLoc$());
+                        }
                     }
                 }
 
@@ -323,12 +339,14 @@
                 oriSta = staService.getById(task.getOriSta());
                 staReserveService.confirmStaReserve(oriSta, task, 1, StaReserveType.OUT);
 
-                destLoc = locService.getById(task.getDestLoc());
-                if (destLoc.getLocSts().equals(LocStsType.PAKIN.val())) {
-                    destLoc.setLocSts(LocStsType.STOCK.val());
-                    destLoc.setUpdateTime(now);
-                    if (!locService.updateById(destLoc)) {
-                        log.error("Loc [{}] 搴撲綅淇敼鐘舵�佸け璐�", task.getDestLoc$());
+                if (maintainLocSts) {
+                    destLoc = locService.getById(task.getDestLoc());
+                    if (destLoc.getLocSts().equals(LocStsType.PAKIN.val())) {
+                        destLoc.setLocSts(LocStsType.STOCK.val());
+                        destLoc.setUpdateTime(now);
+                        if (!locService.updateById(destLoc)) {
+                            log.error("Loc [{}] 搴撲綅淇敼鐘舵�佸け璐�", task.getDestLoc$());
+                        }
                     }
                 }
                 break;
@@ -353,31 +371,36 @@
     public void maintainLocAndStaHandler(Task task, Boolean complete) {
         Loc oriLoc = null; Loc destLoc = null;
         Sta oriSta = null; Sta destSta = null;
+        Boolean maintainLocSts = configService.getVal("maintainLocSts", Boolean.class);
         Date now = new Date();
         TaskTypeType typeType = TaskTypeType.get(task.getTaskTypeEl());
         switch (Objects.requireNonNull(typeType)) {
             case LOC_TO_LOC:
-                oriLoc = locService.getById(task.getOriLoc());
-                destLoc = locService.getById(task.getDestLoc());
+                if (maintainLocSts) {
+                    oriLoc = locService.getById(task.getOriLoc());
+                    destLoc = locService.getById(task.getDestLoc());
 
-                oriLoc.setLocSts(complete?LocStsType.IDLE.val():LocStsType.STOCK.val());
-                oriLoc.setUpdateTime(now);
-                if (!locService.updateById(oriLoc)) {
-                    throw new BusinessException("Loc [" + oriLoc.getLocNo() + "] 搴撲綅淇敼鐘舵�佸け璐� 锛侊紒锛�");
-                }
+                    oriLoc.setLocSts(complete?LocStsType.IDLE.val():LocStsType.STOCK.val());
+                    oriLoc.setUpdateTime(now);
+                    if (!locService.updateById(oriLoc)) {
+                        throw new BusinessException("Loc [" + oriLoc.getLocNo() + "] 搴撲綅淇敼鐘舵�佸け璐� 锛侊紒锛�");
+                    }
 
-                destLoc.setLocSts(complete?LocStsType.STOCK.val():LocStsType.IDLE.val());
-                destLoc.setUpdateTime(now);
-                if (!locService.updateById(destLoc)) {
-                    throw new BusinessException("Loc [" + destLoc.getLocNo() + "] 搴撲綅淇敼鐘舵�佸け璐� 锛侊紒锛�");
+                    destLoc.setLocSts(complete?LocStsType.STOCK.val():LocStsType.IDLE.val());
+                    destLoc.setUpdateTime(now);
+                    if (!locService.updateById(destLoc)) {
+                        throw new BusinessException("Loc [" + destLoc.getLocNo() + "] 搴撲綅淇敼鐘舵�佸け璐� 锛侊紒锛�");
+                    }
                 }
                 break;
             case LOC_TO_STA:
-                oriLoc = locService.getById(task.getOriLoc());
-                oriLoc.setLocSts(complete?LocStsType.IDLE.val():LocStsType.STOCK.val());
-                oriLoc.setUpdateTime(now);
-                if (!locService.updateById(oriLoc)) {
-                    throw new BusinessException("Loc [" + oriLoc.getLocNo() + "] 搴撲綅淇敼鐘舵�佸け璐� 锛侊紒锛�");
+                if (maintainLocSts) {
+                    oriLoc = locService.getById(task.getOriLoc());
+                    oriLoc.setLocSts(complete?LocStsType.IDLE.val():LocStsType.STOCK.val());
+                    oriLoc.setUpdateTime(now);
+                    if (!locService.updateById(oriLoc)) {
+                        throw new BusinessException("Loc [" + oriLoc.getLocNo() + "] 搴撲綅淇敼鐘舵�佸け璐� 锛侊紒锛�");
+                    }
                 }
 
                 destSta = staService.getById(task.getDestSta());
@@ -395,11 +418,13 @@
                     staReserveService.cancelStaReserve(oriSta, task, 1, StaReserveType.OUT);
                 }
 
-                destLoc = locService.getById(task.getDestLoc());
-                destLoc.setLocSts(complete?LocStsType.STOCK.val():LocStsType.IDLE.val());
-                destLoc.setUpdateTime(now);
-                if (!locService.updateById(destLoc)) {
-                    throw new BusinessException("Loc [" + destLoc.getLocNo() + "] 搴撲綅淇敼鐘舵�佸け璐� 锛侊紒锛�");
+                if (maintainLocSts) {
+                    destLoc = locService.getById(task.getDestLoc());
+                    destLoc.setLocSts(complete?LocStsType.STOCK.val():LocStsType.IDLE.val());
+                    destLoc.setUpdateTime(now);
+                    if (!locService.updateById(destLoc)) {
+                        throw new BusinessException("Loc [" + destLoc.getLocNo() + "] 搴撲綅淇敼鐘舵�佸け璐� 锛侊紒锛�");
+                    }
                 }
                 break;
             case STA_TO_STA:
diff --git a/zy-acs-manager/src/main/java/integrationRecord.sql b/zy-acs-manager/src/main/java/integrationRecord.sql
new file mode 100644
index 0000000..5ab8b43
--- /dev/null
+++ b/zy-acs-manager/src/main/java/integrationRecord.sql
@@ -0,0 +1,7 @@
+-- save integrationRecord record
+-- mysql
+-- SwapHorizontalCircle
+insert into `sys_menu` ( `name`, `parent_id`, `route`, `component`, `type`, `sort`, `tenant_id`, `status`) values ( 'menu.integrationRecord', '0', '/manager/integrationRecord', 'integrationRecord', '0' , '5', '1' , '1');
+
+insert into `sys_menu` ( `name`, `parent_id`, `type`, `authority`, `sort`, `tenant_id`, `status`) values ( 'Query Integration Record', '', '1', 'manager:integrationRecord:list', '0', '1', '1');
+insert into `sys_menu` ( `name`, `parent_id`, `type`, `authority`, `sort`, `tenant_id`, `status`) values ( 'Delete Integration Record', '', '1', 'manager:integrationRecord:remove', '3', '1', '1');
diff --git a/zy-acs-manager/src/main/resources/application.yml b/zy-acs-manager/src/main/resources/application.yml
index 94987b1..c1aec68 100644
--- a/zy-acs-manager/src/main/resources/application.yml
+++ b/zy-acs-manager/src/main/resources/application.yml
@@ -53,6 +53,15 @@
 convey-plc:
   host: 10.10.10.222
   port: 9090
+  timeout: 15000
+  url: /cv/station/query
+
+uplink:
+  enabled: true
+  host: 10.10.10.251
+  port: 8082
+  timeout: 30000
+  url: /rsf-open-api/rcs/api/open/task/report
 
 floyd:
   enable: false
diff --git a/zy-acs-manager/src/main/resources/mapper/manager/IntegrationRecordMapper.xml b/zy-acs-manager/src/main/resources/mapper/manager/IntegrationRecordMapper.xml
new file mode 100644
index 0000000..0788319
--- /dev/null
+++ b/zy-acs-manager/src/main/resources/mapper/manager/IntegrationRecordMapper.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.zy.acs.manager.manager.mapper.IntegrationRecordMapper">
+
+</mapper>
diff --git a/zy-acs-manager/src/main/resources/mapper/manager/TaskMapper.xml b/zy-acs-manager/src/main/resources/mapper/manager/TaskMapper.xml
index 545034b..84a91dd 100644
--- a/zy-acs-manager/src/main/resources/mapper/manager/TaskMapper.xml
+++ b/zy-acs-manager/src/main/resources/mapper/manager/TaskMapper.xml
@@ -50,6 +50,9 @@
             <if test="param.timeEnd != null">
                 and a.create_time &lt; #{param.timeEnd}
             </if>
+            <if test="param.uplinkSts != null">
+                AND a.uplink_sts = #{param.uplinkSts}
+            </if>
             <if test="param.keywords != null">
                 AND (
                 a.memo LIKE CONCAT('%', #{param.keywords}, '%')

--
Gitblit v1.9.1