From 01fa93b5dd9f20286ef8f22515caf55307f76a9d Mon Sep 17 00:00:00 2001
From: lty <876263681@qq.com>
Date: 星期五, 20 三月 2026 09:52:20 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/jxhcasrs' into jxhcasrs

---
 src/main/webapp/views/locDetl/locDetl.html                            |    9 
 src/main/java/com/zy/api/service/impl/HmesApiServiceImpl.java         |   82 +
 src/main/java/com/zy/common/config/AdminInterceptor.java              |    2 
 src/main/resources/mapper/LocDetlMapper.xml                           |    2 
 src/main/java/com/zy/system/mapper/LicenseInfosMapper.java            |   14 
 src/main/resources/application-prod.yml                               |    3 
 src/main/webapp/static/js/wrkMast/wrkMast.js                          |    2 
 src/main/webapp/views/basDevice/basDevice.html                        |   10 
 src/main/java/com/zy/asrs/service/impl/WorkServiceImpl.java           |   37 
 src/main/java/com/zy/system/service/LicenseInfosService.java          |    9 
 src/main/resources/application-dev.yml                                |    3 
 src/main/java/com/zy/system/timer/LicenseTimer.java                   |  128 ++
 src/main/java/com/zy/common/service/CommonService.java                |  249 ----
 src/main/java/com/zy/system/entity/license/LicenseCheckListener.java  |  110 +-
 src/main/java/com/zy/system/config/LicenseSchemaInitializer.java      |   79 +
 src/main/java/com/zy/asrs/task/handler/WorkMastHandler.java           |    2 
 src/main/java/com/zy/system/entity/license/LicenseVerify.java         |   76 -
 src/main/java/com/zy/asrs/task/WorkMastScheduler.java                 |  166 ++-
 src/main/java/com/zy/asrs/task/OrderSyncScheduler.java                |   51 
 src/main/java/com/zy/system/entity/license/LinuxServerInfos.java      |   65 +
 src/main/java/com/zy/system/entity/license/LicenseBindingSupport.java |  176 +++
 src/main/java/com/zy/asrs/service/impl/WrkMastServiceImpl.java        |    6 
 src/main/java/com/zy/system/entity/license/AbstractServerInfos.java   |   22 
 src/main/resources/mapper/OrderDetlPakoutMapper.xml                   |    8 
 src/main/webapp/views/login.html                                      |  664 ++++++++++++
 src/main/java/com/zy/asrs/entity/LocAroundBind.java                   |   11 
 src/main/java/com/zy/system/controller/LicenseCreatorController.java  |  176 ++-
 src/main/java/com/zy/system/entity/license/CustomLicenseManager.java  |   98 -
 src/main/java/com/zy/api/service/impl/WcsApiServiceImpl.java          |   37 
 src/main/java/com/zy/common/web/BaseController.java                   |   91 +
 src/main/webapp/static/js/locAroundBind/locAroundBind.js              |    7 
 src/main/java/com/zy/common/web/WcsController.java                    |   25 
 src/main/java/com/zy/api/controller/HWmsApiController.java            |    2 
 src/main/webapp/views/index.html                                      |   36 
 src/main/java/com/zy/api/controller/HmesApiController.java            |    4 
 src/main/java/com/zy/asrs/controller/OutController.java               |   62 
 src/main/java/com/zy/system/service/impl/LicenseInfosServiceImpl.java |   16 
 license.lic                                                           |    0 
 src/main/java/com/zy/asrs/service/WorkService.java                    |    3 
 src/main/java/com/zy/system/entity/license/LicenseUtils.java          |  121 ++
 src/main/java/com/zy/system/entity/license/LicenseVerifyParam.java    |    8 
 src/main/java/com/zy/system/entity/LicenseInfos.java                  |   42 
 src/main/java/com/zy/system/entity/license/LicenseNodeCheck.java      |   22 
 src/main/java/com/zy/asrs/controller/LocDetlController.java           |   25 
 src/main/java/com/zy/system/entity/license/LicenseUploadParam.java    |    9 
 src/main/java/com/zy/asrs/entity/WrkMast.java                         |    2 
 src/main/resources/mapper/LicenseInfosMapper.xml                      |   17 
 src/main/resources/mapper/WrkMastMapper.xml                           |    9 
 src/main/java/com/zy/system/entity/license/LicenseBindModel.java      |   21 
 src/main/webapp/static/js/locDetl/locDetl.js                          |    9 
 /dev/null                                                             |    1 
 src/main/java/com/zy/asrs/service/WrkMastService.java                 |    3 
 src/main/java/com/zy/asrs/mapper/WrkMastMapper.java                   |    6 
 src/main/java/com/zy/system/entity/license/WindowsServerInfos.java    |  107 +
 54 files changed, 2,205 insertions(+), 740 deletions(-)

diff --git a/license.lic b/license.lic
index 22364dc..1c35635 100644
--- a/license.lic
+++ b/license.lic
Binary files differ
diff --git a/src/main/java/com/zy/api/controller/HWmsApiController.java b/src/main/java/com/zy/api/controller/HWmsApiController.java
index a154d8d..a7d5f81 100644
--- a/src/main/java/com/zy/api/controller/HWmsApiController.java
+++ b/src/main/java/com/zy/api/controller/HWmsApiController.java
@@ -1,6 +1,7 @@
 package com.zy.api.controller;
 
 
+import com.alibaba.fastjson.JSONObject;
 import com.zy.api.controller.params.PageRequestParams;
 import com.zy.api.entity.PubOrderParams;
 import com.zy.api.entity.ReportOrderParam;
@@ -44,6 +45,7 @@
     @ApiOperation("鍏ュ簱鍗曚笅鍙�")
     @PostMapping("/sendInDispatch")
     public XSR receiveOrders(@RequestBody List<PubOrderParams> params) {
+        log.info(JSONObject.toJSONString(params));
         if (Objects.isNull(params)) {
             return XSR.error("鍙傛暟涓嶈兘涓虹┖锛侊紒");
         }
diff --git a/src/main/java/com/zy/api/controller/HmesApiController.java b/src/main/java/com/zy/api/controller/HmesApiController.java
index dcbc9aa..cff31d2 100644
--- a/src/main/java/com/zy/api/controller/HmesApiController.java
+++ b/src/main/java/com/zy/api/controller/HmesApiController.java
@@ -1,6 +1,7 @@
 package com.zy.api.controller;
 
 
+import com.alibaba.fastjson.JSONObject;
 import com.core.annotations.ManagerAuth;
 import com.core.common.Cools;
 import com.core.common.R;
@@ -9,6 +10,7 @@
 import com.zy.asrs.entity.param.OpenOrderPakoutParam;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
@@ -19,6 +21,7 @@
 
 @Api(value = "HMES瀵规帴")
 @RestController
+@Slf4j
 @RequestMapping("/api")
 public class HmesApiController {
 
@@ -35,6 +38,7 @@
     @ApiOperation("涓嬪彂鐢熶骇浠诲姟")
     @PostMapping("/work/tasks")
     public R menauWork(@RequestBody OpenOrderPakoutParam params) {
+        log.info("涓嬪彂鐢熶骇浠诲姟={}", JSONObject.toJSONString(params));
         if (Objects.isNull(params)) {
             return R.error("鍙傛暟涓嶈兘涓虹┖锛侊紒");
         }
diff --git a/src/main/java/com/zy/api/service/impl/HmesApiServiceImpl.java b/src/main/java/com/zy/api/service/impl/HmesApiServiceImpl.java
index 4bd4a81..f00ac7f 100644
--- a/src/main/java/com/zy/api/service/impl/HmesApiServiceImpl.java
+++ b/src/main/java/com/zy/api/service/impl/HmesApiServiceImpl.java
@@ -17,6 +17,7 @@
 import com.zy.asrs.service.impl.OrderDetlPakoutServiceImpl;
 import com.zy.asrs.service.impl.OrderPakoutServiceImpl;
 import com.zy.common.model.DetlDto;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -25,6 +26,7 @@
 import java.util.stream.Collectors;
 
 @Service
+@Slf4j
 public class HmesApiServiceImpl implements HmesApiService {
 
     @Autowired
@@ -75,12 +77,60 @@
         // 濡傛灉鍗曟嵁涓嶅瓨鍦ㄥ垯娣诲姞锛涘鏋滃崟鎹瓨鍦紝浣滀笟涓棤娉曚慨鏀癸紝鍙嶄箣鍒欎慨鏀瑰崟鎹�
         if (!Cools.isEmpty(order)) {
             if (order.getSettle() > 1L) {
+                log.error(param.getOrderNo() + "姝e湪鍑哄簱锛屾棤娉曚慨鏀瑰崟鎹�");
                 throw new CoolException(param.getOrderNo() + "姝e湪鍑哄簱锛屾棤娉曚慨鏀瑰崟鎹�");
             }
             orderPakoutService.remove(order.getId());
         }
         DocType docType = docTypeService.selectOrAdd(param.getBillType(), Boolean.FALSE);
         Date now = new Date();
+
+        // 鍗曟嵁鏄庣粏妗�
+        List<DetlDto> list = new ArrayList<>();
+        List<DetlDto> orderDetails = param.getMatList();
+        for (DetlDto detail : orderDetails) {
+            DetlDto dto = new DetlDto(detail.getMatnr(), detail.getBatch(),detail.getBrand(),detail.getDevNo(),detail.getStandby2(),detail.getStandby3(),detail.getLineNumber(),
+                    detail.getBoxType1(),detail.getBoxType2(),detail.getBoxType3(), detail.getAnfme());
+            if (DetlDto.hasLineNumber(list, dto)) {
+                DetlDto detlDto = DetlDto.findLineNumber(list, dto.getMatnr(), dto.getBatch(),dto.getBrand(),dto.getDevNo(),dto.getStandby2(),dto.getStandby3(),dto.getLineNumber(),
+                        dto.getBoxType1(),dto.getBoxType2(),dto.getBoxType3());
+                assert detlDto != null;
+                detlDto.setAnfme(detlDto.getAnfme() + detail.getAnfme());
+            } else {
+                list.add(dto);
+            }
+        }
+
+        //涓嬪彂鐨勮鍗曟槑缁嗭紝鏌ョ湅搴撳瓨鏄惁鏈夎冻澶熺殑搴撳瓨锛屾帓闄ゆ満鍙扮殑搴撲綅
+         for (DetlDto detail : list) {
+            List<LocDetl> matnr = locDetlService.selectList(new EntityWrapper<LocDetl>().eq("matnr", detail.getMatnr()));
+            Double count=0.0;
+            for (LocDetl detl : matnr) {
+                LocMast locMast = locMastService.selectOne(new EntityWrapper<LocMast>().eq("loc_no", detl.getLocNo()).eq("loc_sts","F"));
+                if (locMast != null) {
+                    LocAroundBind bLocNo = locAroundBindService.selectOne(new EntityWrapper<LocAroundBind>().eq("b_loc_no", locMast.getLocNo()));
+                    if (Cools.isEmpty(bLocNo)) {
+                        count=detl.getAnfme()+count;
+                    }
+                }
+            }
+            if (count<detail.getAnfme()) {
+                return R.error("鐗╂枡="+detail.getMatnr()+"搴撳瓨涓嶈冻鏃犳硶鐢熸垚璁㈠崟");
+            }
+            //鏈哄彴鏈夊喕缁撴椂绂佹鍛煎彨鐗╂枡
+            BasDevice basDevice = basDeviceService.selectOne(new EntityWrapper<BasDevice>()
+                    .eq("status", 1)
+                    .eq("dev_no", detail.getStandby1()));
+            if (Objects.isNull(basDevice)) {
+                return R.error(detail.getStandby1()+"鏈哄彴淇℃伅涓嶅瓨鍦ㄦ垨宸茬鐢紒锛�");
+            }
+            List<LocAroundBind> binds = locAroundBindService.selectList(new EntityWrapper<LocAroundBind>()
+                    .eq("dev_no", basDevice.getType())
+                    .eq("freeze", 1));
+            if (!Cools.isEmpty(binds)) {
+                return  R.error(detail.getStandby1()+"鏈哄彴琚喕缁撴棤娉曞懠鍙墿鏂�");
+            }
+        }
         // 鍗曟嵁涓绘。
         order = new OrderPakout(
                 String.valueOf(snowflakeIdWorker.nextId()),    // 缂栧彿[闈炵┖]
@@ -120,38 +170,6 @@
         );
         if (!orderPakoutService.insert(order)) {
             throw new CoolException("鐢熸垚鍗曟嵁涓绘。澶辫触锛岃鑱旂郴绠$悊鍛�");
-        }
-        // 鍗曟嵁鏄庣粏妗�
-        List<DetlDto> list = new ArrayList<>();
-        List<DetlDto> orderDetails = param.getMatList();
-        for (DetlDto detail : orderDetails) {
-            DetlDto dto = new DetlDto(detail.getMatnr(), detail.getBatch(),detail.getBrand(),detail.getDevNo(),detail.getStandby2(),detail.getStandby3(),detail.getLineNumber(),
-                    detail.getBoxType1(),detail.getBoxType2(),detail.getBoxType3(), detail.getAnfme());
-            if (DetlDto.hasLineNumber(list, dto)) {
-                DetlDto detlDto = DetlDto.findLineNumber(list, dto.getMatnr(), dto.getBatch(),dto.getBrand(),dto.getDevNo(),dto.getStandby2(),dto.getStandby3(),dto.getLineNumber(),
-                        dto.getBoxType1(),dto.getBoxType2(),dto.getBoxType3());
-                assert detlDto != null;
-                detlDto.setAnfme(detlDto.getAnfme() + detail.getAnfme());
-            } else {
-                list.add(dto);
-            }
-        }
-        //涓嬪彂鐨勮鍗曟槑缁嗭紝鏌ョ湅搴撳瓨鏄惁鏈夎冻澶熺殑搴撳瓨锛屾帓闄ゆ満鍙扮殑搴撲綅
-        for (DetlDto detail : list) {
-            List<LocDetl> matnr = locDetlService.selectList(new EntityWrapper<LocDetl>().eq("matnr", detail.getMatnr()));
-            Double count=0.0;
-            for (LocDetl detl : matnr) {
-                LocMast locMast = locMastService.selectOne(new EntityWrapper<LocMast>().eq("loc_no", detl.getLocNo()).eq("loc_sts","F"));
-                if (locMast != null) {
-                    LocAroundBind bLocNo = locAroundBindService.selectOne(new EntityWrapper<LocAroundBind>().eq("b_loc_no", locMast.getLocNo()));
-                    if (Cools.isEmpty(bLocNo)) {
-                        count=detl.getAnfme()+count;
-                    }
-                }
-            }
-            if (count<detail.getAnfme()) {
-                return R.error("鐗╂枡="+detail.getMatnr()+"搴撳瓨涓嶈冻鏃犳硶鐢熸垚璁㈠崟");
-            }
         }
         for (DetlDto detlDto : list) {
             Mat mat = matService.selectByMatnr(detlDto.getMatnr());
diff --git a/src/main/java/com/zy/api/service/impl/WcsApiServiceImpl.java b/src/main/java/com/zy/api/service/impl/WcsApiServiceImpl.java
index 3b3fc44..b546436 100644
--- a/src/main/java/com/zy/api/service/impl/WcsApiServiceImpl.java
+++ b/src/main/java/com/zy/api/service/impl/WcsApiServiceImpl.java
@@ -123,9 +123,9 @@
 //       if (!wrkMastService.updateById(mast)) {
 //           throw new CoolException("浠诲姟鐘舵�佹洿鏂板け璐ワ紒锛�");
 //       }
-        workService.backLocOperation(mast.getWrkNo() + "", mast.getAppeUser());
 
-        return R.ok("鎺ユ敹鎴愬姛锛屾墽琛屽洖搴撲腑...");
+        return workService.backLocOperation(mast.getWrkNo() + "", mast.getAppeUser());
+
     }
 
     /**
@@ -153,7 +153,7 @@
         }else if (!Objects.isNull(params.getType()) && params.getType().equals("move")) {
             url = createLocMoveTask;
         }
-        String response;
+        String response = null;
         R r = R.ok();
         try {
             log.info("涓嬪彂鎼繍浠诲姟缁檞cs="+JSON.toJSONString(params));
@@ -201,7 +201,7 @@
                                 }
                             }
                         }
-                    }else if (wrkMast.getIoType()==101){
+                    }else if (wrkMast.getIoType()==101 || wrkMast.getIoType()==110) {
                         wrkMast.setWrkSts(12L);
                         wrkMast.setModiTime(new Date());
                         wrkMastService.updateById(wrkMast);
@@ -233,15 +233,21 @@
                 }
                 //TODO 涓婃姤鏄惁鎴愬姛
             }else {
-                r =R.error();
+                String msg = jsonObject.getString("msg");
+                if (Cools.isEmpty(msg)) {
+                    msg = jsonObject.getString("message");
+                }
+                r = R.error(Cools.isEmpty(msg) ? "涓嬪彂浠诲姟澶辫触" : msg);
             }
         } catch (IOException e) {
-            throw new RuntimeException(e);
+            log.error("涓嬪彂浠诲姟缁檞cs寮傚父, request={}", JSON.toJSONString(params), e);
+            return R.error("璋冪敤WCS鎺ュ彛澶辫触锛�" + e.getMessage());
+        } catch (Exception e) {
+            log.error("瑙f瀽WCS涓嬪彂缁撴灉寮傚父, request={}, response={}", JSON.toJSONString(params), response, e);
+            return R.error("WCS杩斿洖缁撴灉寮傚父锛�" + e.getMessage());
         }
         return r;
     }
-
-
     /**
      * 涓婃姤閿佸畾/閲婃斁搴撲綅淇℃伅
      *
@@ -258,7 +264,7 @@
                 url = MesConstant.RELEASE_LOCS_URL;
             }
         }
-        String response;
+        String response = null;
         try {
             response = new HttpHandler.Builder()
                     .setUri(MesConstant.URL)
@@ -370,6 +376,17 @@
                                     }
                                 } else {
                                     throw new CoolException("浠诲姟鍙锋埅鍙栧け璐ワ紝璇锋鏌ヤ富浠诲姟妗d换妗rkCode瀛楁");
+                                }
+                            }else{
+                                String wrkNo = mast.getWrkCode();
+                                WrkMast orgWrk = wrkMastService.selectOne(new EntityWrapper<WrkMast>().eq("wrk_no", wrkNo));
+                                if (Objects.isNull(orgWrk)) {
+                                    throw new CoolException("鏁版嵁閿欒锛屼富浠诲姟妗d笉瀛樺湪鎴栧凡鍒犻櫎锛侊紒");
+                                }
+                                mast.setOveMk("Y");
+                                orgWrk.setOveMk("Y");
+                                if (!wrkMastService.updateById(orgWrk)) {
+                                    throw new CoolException("浠诲姟妗d慨鏀瑰け璐ワ紒锛�");
                                 }
                             }
                         }
@@ -509,3 +526,5 @@
         return locAround;
     }
 }
+
+
diff --git a/src/main/java/com/zy/asrs/controller/LocDetlController.java b/src/main/java/com/zy/asrs/controller/LocDetlController.java
index 8ade3a7..e43ff55 100644
--- a/src/main/java/com/zy/asrs/controller/LocDetlController.java
+++ b/src/main/java/com/zy/asrs/controller/LocDetlController.java
@@ -189,6 +189,7 @@
 //            }
 //        }
         excludeTrash(param);
+        applyBeBatchFilter(param, wrapper);
         convert(param, wrapper);
         allLike(LocDetl.class, param.keySet(), wrapper, condition);
         if (!Cools.isEmpty(orderByField)){wrapper.orderBy(humpToLine(orderByField), "asc".equals(orderByType));}
@@ -215,6 +216,29 @@
                 }
             }
         }
+    }
+
+    private <T> void applyBeBatchFilter(Map<String, Object> map, EntityWrapper<T> wrapper) {
+        Object beBatchObj = map.remove("beBatch");
+        if (beBatchObj == null) {
+            beBatchObj = map.remove("be_batch");
+        }
+        if (beBatchObj == null) {
+            return;
+        }
+        String beBatch = String.valueOf(beBatchObj).trim();
+        if (Cools.isEmpty(beBatch)) {
+            return;
+        }
+        if ("1".equals(beBatch)) {
+            wrapper.eq("be_batch", 1);
+            return;
+        }
+        if ("0".equals(beBatch)) {
+            wrapper.andNew().isNull("be_batch").or().eq("be_batch", 0);
+            return;
+        }
+        wrapper.eq("be_batch", beBatch);
     }
 
     @RequestMapping(value = "/locDetl/add/auth")
@@ -290,6 +314,7 @@
                 map.remove("row");
             }
         }
+        applyBeBatchFilter(map, wrapper);
         convert(map, wrapper);
         if (!row.equals("")) {
             wrapper.and()
diff --git a/src/main/java/com/zy/asrs/controller/OutController.java b/src/main/java/com/zy/asrs/controller/OutController.java
index c32005b..09d2037 100644
--- a/src/main/java/com/zy/asrs/controller/OutController.java
+++ b/src/main/java/com/zy/asrs/controller/OutController.java
@@ -14,8 +14,8 @@
 import com.zy.common.model.LocDto;
 import com.zy.common.model.TaskDto;
 import com.zy.common.web.BaseController;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestParam;
@@ -29,6 +29,7 @@
  * Created by vincent on 2022/3/26
  */
 
+@Slf4j
 @RestController
 public class OutController extends BaseController {
 
@@ -88,8 +89,8 @@
                 if (issued <= 0.0D) {
                     continue;
                 }
-                List<LocDetl> locDetls = locDetlService.queryStockAll(null, exist,orderDetl.getMatnr(), orderDetl.getBatch(),
-                        orderDetl.getBrand(),orderDetl.getStandby1(),orderDetl.getStandby2(),orderDetl.getStandby3(),orderDetl.getBoxType1(),orderDetl.getBoxType2(),orderDetl.getBoxType3());
+                List<LocDetl> locDetls = locDetlService.queryStockAll(null, exist, orderDetl.getMatnr(), orderDetl.getBatch(),
+                        orderDetl.getBrand(), orderDetl.getStandby1(), orderDetl.getStandby2(), orderDetl.getStandby3(), orderDetl.getBoxType1(), orderDetl.getBoxType2(), orderDetl.getBoxType3());
                 for (LocDetl locDetl : locDetls) {
                     if (issued > 0) {
                         LocDto locDto = new LocDto(locDetl.getLocNo(), locDetl.getMatnr(), locDetl.getMaktx(), locDetl.getBatch(), orderDetl.getOrderNo(),
@@ -136,8 +137,8 @@
                 if (issued <= 0.0D) {
                     continue;
                 }
-                List<LocDetl> locDetls = locDetlService.queryStockAll(null, exist,orderDetl.getMatnr(), orderDetl.getBatch(),
-                        orderDetl.getBrand(),orderDetl.getStandby1(),orderDetl.getStandby2(),orderDetl.getStandby3(),orderDetl.getBoxType1(),orderDetl.getBoxType2(),orderDetl.getBoxType3());
+                List<LocDetl> locDetls = locDetlService.queryStockAll(null, exist, orderDetl.getMatnr(), orderDetl.getBatch(),
+                        orderDetl.getBrand(), orderDetl.getStandby1(), orderDetl.getStandby2(), orderDetl.getStandby3(), orderDetl.getBoxType1(), orderDetl.getBoxType2(), orderDetl.getBoxType3());
                 for (LocDetl locDetl : locDetls) {
                     if (issued > 0) {
                         LocDto locDto = new LocDto(locDetl.getLocNo(), locDetl.getMatnr(), locDetl.getMaktx(), locDetl.getBatch(), orderDetl.getOrderNo(),
@@ -181,14 +182,13 @@
 
     @PostMapping("/out/pakout/auth")
     @ManagerAuth(memo = "璁㈠崟鍑哄簱")
-    @Transactional
     public synchronized R pakout(@RequestBody List<LocDto> locDtos) throws InterruptedException {
         if (Cools.isEmpty(locDtos)) {
             return R.parse(BaseRes.PARAM);
         }
         List<LocDto> locDtoArrayList = new ArrayList<>();
-        for (LocDto locDto : locDtos){
-            if (locDto.getFrozen()!=1 && locDto.getFrozenLoc()!=1){
+        for (LocDto locDto : locDtos) {
+            if (locDto.getFrozen() != 1 && locDto.getFrozenLoc() != 1) {
                 locDtoArrayList.add(locDto);
             }
         }
@@ -212,7 +212,9 @@
         List<TaskDto> taskDtos = new ArrayList<>();
         // 鏍规嵁 锛堝簱浣� & 鍑哄簱绔欙級 鍒嗙粍锛� 鐞嗘兂鐘舵�侊細涓�缁勪负涓�娆″嚭搴撲换鍔�
         for (LocDto locDto : locDtos) {
-            if (locDto.isLack()) { continue; }
+            if (locDto.isLack()) {
+                continue;
+            }
             TaskDto taskDto = new TaskDto(locDto.getLocNo(), locDto.getStaNo(), locDto, locDto.getStandby1());
             if (TaskDto.has(taskDtos, taskDto)) {
                 TaskDto dto = TaskDto.find(taskDtos, taskDto);
@@ -223,16 +225,46 @@
             }
         }
         // -----------------------------------------------------------------------------------------------
+        int failCount = 0;
         for (TaskDto taskDto : taskDtos) {
-            BasDevp staNo = basDevpService.checkSiteStatus(taskDto.getStaNo());
-            if (!Objects.isNull(taskDto.getDeviceNo())) {
-                //鐢熸垚鍑哄簱浠诲姟
-                workService.stockOut(staNo, taskDto, taskDto.getDeviceNo(), getUserId());
-            } else  {
-                workService.stockOut(staNo, taskDto, null, getUserId());
+            if (!stockOutSafely(taskDto, getUserId(), "鎵嬪姩璁㈠崟鍑哄簱")) {
+                failCount++;
             }
+        }
+        if (failCount > 0) {
+            return R.ok("閮ㄥ垎鍑哄簱浠诲姟宸茬敓鎴愶紝鎴愬姛" + (taskDtos.size() - failCount) + "鏉★紝澶辫触" + failCount + "鏉★紝璇锋煡鐪嬫棩蹇�");
         }
         return R.ok();
     }
 
+    private boolean stockOutSafely(TaskDto taskDto, Long userId, String scene) {
+        try {
+            BasDevp staNo = basDevpService.checkSiteStatus(taskDto.getStaNo());
+            workService.stockOut(staNo, taskDto, taskDto.getDeviceNo(), userId);
+            return true;
+        } catch (Exception e) {
+            log.error("{}澶辫触[locNo={}, staNo={}, deviceNo={}, orderNos={}]锛屽師鍥�: {}",
+                    scene,
+                    taskDto.getLocNo(),
+                    taskDto.getStaNo(),
+                    taskDto.getDeviceNo(),
+                    collectOrderNos(taskDto),
+                    getErrorMessage(e));
+            return false;
+        }
+    }
+
+    private String collectOrderNos(TaskDto taskDto) {
+        Set<String> orderNos = new LinkedHashSet<>();
+        for (LocDto locDto : taskDto.getLocDtos()) {
+            if (!Cools.isEmpty(locDto.getOrderNo())) {
+                orderNos.add(locDto.getOrderNo());
+            }
+        }
+        return orderNos.toString();
+    }
+
+    private String getErrorMessage(Exception e) {
+        return Cools.isEmpty(e.getMessage()) ? e.getClass().getSimpleName() : e.getMessage();
+    }
 }
diff --git a/src/main/java/com/zy/asrs/entity/LocAroundBind.java b/src/main/java/com/zy/asrs/entity/LocAroundBind.java
index 02f3873..ec077df 100644
--- a/src/main/java/com/zy/asrs/entity/LocAroundBind.java
+++ b/src/main/java/com/zy/asrs/entity/LocAroundBind.java
@@ -2,9 +2,11 @@
 
 import com.baomidou.mybatisplus.annotations.TableId;
 import com.baomidou.mybatisplus.enums.IdType;
+import com.baomidou.mybatisplus.mapper.EntityWrapper;
 import com.core.common.Cools;import com.baomidou.mybatisplus.annotations.TableField;
 
 import com.core.common.SpringUtils;
+import com.zy.asrs.service.BasDeviceService;
 import com.zy.asrs.service.BasLocStsService;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
@@ -85,6 +87,15 @@
             return "榛樿";
         }
     }
+    public String getDevNo$() {
+        BasDeviceService bean = SpringUtils.getBean(BasDeviceService.class);
+        BasDevice type = bean.selectOne(new EntityWrapper<BasDevice>().eq("type", devNo));
+        if (type == null) {
+            return "<UNK>";
+        }else {
+            return type.getDevNo();
+        }
+    }
 
     public String getLocType$() {
         if (this.locType == null) {
diff --git a/src/main/java/com/zy/asrs/entity/WrkMast.java b/src/main/java/com/zy/asrs/entity/WrkMast.java
index a389c76..4f21fd1 100644
--- a/src/main/java/com/zy/asrs/entity/WrkMast.java
+++ b/src/main/java/com/zy/asrs/entity/WrkMast.java
@@ -32,6 +32,8 @@
     private Integer wrkNo;
 
     @ApiModelProperty("浠诲姟绫诲瀷锛� agv, crn")
+    @TableField("task_type")
+    @TableId(value = "task_type")
     private String taskType;
 
     @ApiModelProperty("浠诲姟缂栫爜")
diff --git a/src/main/java/com/zy/asrs/mapper/WrkMastMapper.java b/src/main/java/com/zy/asrs/mapper/WrkMastMapper.java
index 8d0111e..2a968d8 100644
--- a/src/main/java/com/zy/asrs/mapper/WrkMastMapper.java
+++ b/src/main/java/com/zy/asrs/mapper/WrkMastMapper.java
@@ -7,6 +7,7 @@
 import org.apache.ibatis.annotations.Select;
 import org.springframework.stereotype.Repository;
 
+import java.util.Date;
 import java.util.List;
 
 @Mapper
@@ -25,4 +26,9 @@
             , @Param("standby1")String standby1, @Param("standby2")String standby2, @Param("standby3")String standby3
             , @Param("boxType1")String boxType1, @Param("boxType2")String boxType2, @Param("boxType3")String boxType3, @Param("crnNo") Integer crnNo);
 
+    int updatePublishError(@Param("wrkNo") Integer wrkNo,
+                           @Param("updMk") String updMk,
+                           @Param("errorTime") Date errorTime,
+                           @Param("errorMemo") String errorMemo);
+
 }
diff --git a/src/main/java/com/zy/asrs/service/WorkService.java b/src/main/java/com/zy/asrs/service/WorkService.java
index 5701b4a..c024dd5 100644
--- a/src/main/java/com/zy/asrs/service/WorkService.java
+++ b/src/main/java/com/zy/asrs/service/WorkService.java
@@ -1,5 +1,6 @@
 package com.zy.asrs.service;
 
+import com.core.common.R;
 import com.zy.asrs.entity.BasDevp;
 import com.zy.asrs.entity.WaitPakin;
 import com.zy.asrs.entity.WrkMast;
@@ -97,7 +98,7 @@
      * @param workNo
      * @param userId
      */
-    void backLocOperation(String workNo, Long userId);
+    R backLocOperation(String workNo, Long userId);
 
     /**
      * 閫氱煡妗f墜鍔ㄧ敓鎴愪换鍔�
diff --git a/src/main/java/com/zy/asrs/service/WrkMastService.java b/src/main/java/com/zy/asrs/service/WrkMastService.java
index 0329de3..69bcbd1 100644
--- a/src/main/java/com/zy/asrs/service/WrkMastService.java
+++ b/src/main/java/com/zy/asrs/service/WrkMastService.java
@@ -4,6 +4,7 @@
 import com.zy.asrs.entity.WrkMast;
 import com.zy.asrs.entity.result.FindLocNoAttributeVo;
 
+import java.util.Date;
 import java.util.List;
 
 public interface WrkMastService extends IService<WrkMast> {
@@ -27,4 +28,6 @@
 
     List<WrkMast> selectWrkMastWrkDetl(Integer ioType, FindLocNoAttributeVo findLocNoAttributeVo, Integer crnNo);
 
+    int updatePublishError(Integer wrkNo, String updMk, Date errorTime, String errorMemo);
+
 }
diff --git a/src/main/java/com/zy/asrs/service/impl/WorkServiceImpl.java b/src/main/java/com/zy/asrs/service/impl/WorkServiceImpl.java
index 6298d71..a285935 100644
--- a/src/main/java/com/zy/asrs/service/impl/WorkServiceImpl.java
+++ b/src/main/java/com/zy/asrs/service/impl/WorkServiceImpl.java
@@ -2,10 +2,7 @@
 
 import com.baomidou.mybatisplus.mapper.EntityWrapper;
 import com.baomidou.mybatisplus.mapper.Wrapper;
-import com.core.common.BaseRes;
-import com.core.common.Cools;
-import com.core.common.DateUtils;
-import com.core.common.SnowflakeIdWorker;
+import com.core.common.*;
 import com.core.exception.CoolException;
 import com.zy.asrs.entity.*;
 import com.zy.asrs.entity.param.EmptyPlateOutParam;
@@ -350,6 +347,7 @@
             wrkMast.setCrnNo(locMast.getCrnNo());
             wrkMast.setSourceStaNo(staDesc.getCrnStn() + ""); // 婧愮珯
             wrkMast.setStaNo(staDesc.getStnNo() + ""); // 鐩爣绔�
+            wrkMast.setOveMk(staDesc.getStnNo()==1076? "Y":"N");
             wrkMast.setSourceLocNo(dto.getLocNo()); // 婧愬簱浣�
             wrkMast.setFullPlt("Y"); // 婊℃澘锛歒
             wrkMast.setPicking("N"); // 鎷f枡
@@ -458,7 +456,8 @@
                 .eq("dev_no", basDevice.getType()).orderBy("order_no"));
 
         if (Objects.isNull(binds)) {
-            throw new CoolException("鏈哄彴鏈缃粯璁ゅ伐浣滀綅锛侊紒");
+            log.error(deviceNo+"---"+basDevice.getType()+"--娌℃湁鍙敤鏈哄彴");
+            return;
         }
 //
 //        Set<String> locs = binds.stream().map(LocAroundBind::getBlocNo).collect(Collectors.toSet());
@@ -723,6 +722,8 @@
             wrkMast.setExitMk("N"); // 閫�鍑�
             wrkMast.setEmptyMk("Y"); // 绌烘澘
             wrkMast.setLinkMis("N");
+            wrkMast.setOveMk("Y");
+            wrkMast.setBarcode(locMast.getBarcode());
             wrkMast.setAppeUser(userId);
             wrkMast.setAppeTime(now);
             wrkMast.setModiUser(userId);
@@ -1441,13 +1442,13 @@
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public void backLocOperation(String workNo, Long userId) {
+    public R backLocOperation(String workNo, Long userId) {
         WrkMast wrkMast = wrkMastService.selectById(workNo);
         if (Cools.isEmpty(wrkMast)) {
-            throw new CoolException(workNo + "宸ヤ綔妗d笉瀛樺湪");
+            return R.error(workNo+"宸ヤ綔妗d笉瀛樺湪");
         }
         if (wrkMast.getWrkSts() != 15) {
-            throw new CoolException("褰撳墠浠诲姟鐘舵�佷笉鑳芥墽琛屾鎿嶄綔锛�");
+            return R.error("褰撳墠浠诲姟鐘舵�佷笉鑳芥墽琛屾鎿嶄綔锛�");
         }
 
         Integer ioType = wrkMast.getIoType() - 50;
@@ -1459,7 +1460,7 @@
 //            ioType = 10;
 //        }
         if (Objects.isNull(wrkMast.getIsSuplus())) {
-            throw new CoolException("鍥炲簱绫诲瀷涓嶈兘涓虹┖锛侊紒");
+            return R.error("鍥炲簱绫诲瀷涓嶈兘涓虹┖锛侊紒");
         }
 
         if (wrkMast.getIsSuplus() == 0) {
@@ -1477,12 +1478,12 @@
                 .eq("crn_no", locMast1.getCrnNo()); // 鍫嗗灈鏈哄彿
         StaDesc staDesc = staDescService.selectOne(wrapper);
         if (Cools.isEmpty(staDesc)) {
-            throw new CoolException("鍏ュ簱璺緞涓嶅瓨鍦�");
+            return R.error("鍏ュ簱璺緞涓嶅瓨鍦�");
         }
 
         int count = wrkMastService.selectCount(new EntityWrapper<WrkMast>().eq("barcode", wrkMast.getBarcode()));
         if (count >= 2) {
-            throw new CoolException("浠诲姟妗e凡鐢熸垚锛屼笉鍙互閲嶅鐢熸垚鐩稿悓鐨勫瓙浠诲姟锛侊紒");
+            return R.error("浠诲姟妗e凡鐢熸垚锛屼笉鍙互閲嶅鐢熸垚鐩稿悓鐨勫瓙浠诲姟锛侊紒");
         }
 
         WrkDetl detl = wrkDetlService.selectOne(new EntityWrapper<WrkDetl>().eq("wrk_no", wrkMast.getWrkNo()));
@@ -1512,11 +1513,11 @@
         mast.setModiTime(now);
         mast.setModiUser(userId);
         if (!wrkMastService.insert(mast)) {
-            throw new CoolException("鏇存柊宸ヤ綔妗f暟鎹姸鎬佸け璐�");
+            return R.error("鏇存柊宸ヤ綔妗f暟鎹姸鎬佸け璐�");
         }
         List<WrkDetl> wrkDetls = wrkDetlService.selectList(new EntityWrapper<WrkDetl>().eq("wrk_no", wrkMast.getWrkNo()));
         if (Cools.isEmpty(wrkDetls)) {
-            throw new CoolException("鏁版嵁閿欒锛屼换鍔℃。鏄庣粏涓嶅瓨鍦� 锛侊紒");
+            return R.error("鏁版嵁閿欒锛屼换鍔℃。鏄庣粏涓嶅瓨鍦� 锛侊紒");
         }
 
         // 淇敼搴撲綅鐘舵�� Q.鎷f枡/鐩樼偣/骞舵澘鍐嶅叆搴�
@@ -1525,14 +1526,14 @@
         inLoc.setModiTime(now);
         inLoc.setModiUser(userId);
         if (!locMastService.updateById(inLoc)) {
-            throw new CoolException("淇敼搴撲綅鐘舵�佸け璐�");
+            return R.error("淇敼搴撲綅鐘舵�佸け璐�");
         }
 
         LocAroundBind aroundBind = locAroundBindService.selectOne(new EntityWrapper<LocAroundBind>().eq("b_loc_no", mast.getSourceLocNo()));
         if (!Objects.isNull(aroundBind)) {
             aroundBind.setLocType(LocStsType.LOC_STS_TYPE_R.type);
             if (!locAroundBindService.updateById(aroundBind)) {
-                throw new CoolException("宸ヤ綅鐘舵�佷慨鏀瑰け璐ワ紒锛�");
+                return R.error("宸ヤ綅鐘舵�佷慨鏀瑰け璐ワ紒锛�");
             }
         }
 
@@ -1555,7 +1556,7 @@
         locMast.setModiTime(now);
         locMast.setModiUser(userId);
         if (!locMastService.updateById(locMast)) {
-            throw new CoolException("淇敼搴撲綅鐘舵�佸け璐�");
+            return R.error("淇敼搴撲綅鐘舵�佸け璐�");
         }
 
 //        wrkMast.setWrkCode(null);
@@ -1563,6 +1564,10 @@
 //        if (!wrkMastService.updateById(wrkMast)) {
 //            throw new CoolException("浠诲姟妗f洿鏂板け璐ワ紒锛�");
 //        }
+        if (Cools.isEmpty(mast)) {
+            return R.error("娌℃湁鐢熸垚浠诲姟");
+        }
+        return R.ok("鐢熸垚鍥炲簱浠诲姟鎴愬姛锛侊紒");
     }
 
 
diff --git a/src/main/java/com/zy/asrs/service/impl/WrkMastServiceImpl.java b/src/main/java/com/zy/asrs/service/impl/WrkMastServiceImpl.java
index d8ad458..a9b3acb 100644
--- a/src/main/java/com/zy/asrs/service/impl/WrkMastServiceImpl.java
+++ b/src/main/java/com/zy/asrs/service/impl/WrkMastServiceImpl.java
@@ -10,6 +10,7 @@
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 
+import java.util.Date;
 import java.util.List;
 
 @Slf4j
@@ -58,4 +59,9 @@
                 ,findLocNoAttributeVo.getBoxType1(),findLocNoAttributeVo.getBoxType2(),findLocNoAttributeVo.getBoxType3()
                 ,crnNo);
     }
+
+    @Override
+    public int updatePublishError(Integer wrkNo, String updMk, Date errorTime, String errorMemo) {
+        return this.baseMapper.updatePublishError(wrkNo, updMk, errorTime, errorMemo);
+    }
 }
diff --git a/src/main/java/com/zy/asrs/task/OrderSyncScheduler.java b/src/main/java/com/zy/asrs/task/OrderSyncScheduler.java
index ebf389c..0bd578b 100644
--- a/src/main/java/com/zy/asrs/task/OrderSyncScheduler.java
+++ b/src/main/java/com/zy/asrs/task/OrderSyncScheduler.java
@@ -2,7 +2,6 @@
 
 import com.baomidou.mybatisplus.mapper.EntityWrapper;
 import com.core.common.Cools;
-import com.core.common.R;
 import com.zy.asrs.entity.*;
 import com.zy.asrs.service.*;
 import com.zy.asrs.task.core.ReturnT;
@@ -90,7 +89,7 @@
                             List<LocDetl> locDetls = locDetlService.queryStockAll(null, exist, detl.getMatnr(), detl.getBatch(),
                                     detl.getBrand(), detl.getStandby1(), detl.getStandby2(), detl.getStandby3(), detl.getBoxType1(), detl.getBoxType2(), detl.getBoxType3());
                             for (LocDetl locDetl : locDetls) {
-                                LocMast locMast = locMastService.selectOne(new EntityWrapper<LocMast>().eq("loc_no", locDetl.getLocNo()).eq("loc_sts","F"));
+                                LocMast locMast = locMastService.selectOne(new EntityWrapper<LocMast>().eq("loc_no", locDetl.getLocNo()).eq("loc_sts", "F"));
                                 if (locMast != null) {
                                     LocAroundBind bLocNo = locAroundBindService.selectOne(new EntityWrapper<LocAroundBind>().eq("b_loc_no", locMast.getLocNo()));
                                     if (!Cools.isEmpty(bLocNo)) {
@@ -132,7 +131,9 @@
                         List<TaskDto> taskDtos = new ArrayList<>();
                         // 鏍规嵁 锛堝簱浣� & 鍑哄簱绔欙級 鍒嗙粍锛� 鐞嗘兂鐘舵�侊細涓�缁勪负涓�娆″嚭搴撲换鍔�
                         for (LocDto locDto : locDtos) {
-                            if (locDto.isLack()) { continue; }
+                            if (locDto.isLack()) {
+                                continue;
+                            }
                             TaskDto taskDto = new TaskDto(locDto.getLocNo(), locDto.getStaNo(), locDto, locDto.getStandby1());
                             if (TaskDto.has(taskDtos, taskDto)) {
                                 TaskDto dto = TaskDto.find(taskDtos, taskDto);
@@ -143,14 +144,15 @@
                             }
                         }
                         // -----------------------------------------------------------------------------------------------
+                        int failCount = 0;
                         for (TaskDto taskDto : taskDtos) {
-                            BasDevp staNo = basDevpService.checkSiteStatus(taskDto.getStaNo());
-                            if (!Objects.isNull(taskDto.getDeviceNo())) {
-                                //鐢熸垚鍑哄簱浠诲姟
-                                workService.stockOut(staNo, taskDto, taskDto.getDeviceNo(), 9995L);
-                            } else  {
-                                workService.stockOut(staNo, taskDto, null, 9995L);
+                            if (!stockOutSafely(taskDto, 9995L, "鑷姩璁㈠崟鍑哄簱")) {
+                                failCount++;
                             }
+                        }
+                        if (failCount > 0) {
+                            log.warn("鑷姩璁㈠崟鍑哄簱閮ㄥ垎澶辫触[orderNo={}]锛屾垚鍔焮}鏉★紝澶辫触{}鏉�",
+                                    order.getOrderNo(), taskDtos.size() - failCount, failCount);
                         }
                     }
                 }
@@ -201,4 +203,35 @@
             }
         }
     }
+
+    private boolean stockOutSafely(TaskDto taskDto, Long userId, String scene) {
+        try {
+            BasDevp staNo = basDevpService.checkSiteStatus(taskDto.getStaNo());
+            workService.stockOut(staNo, taskDto, taskDto.getDeviceNo(), userId);
+            return true;
+        } catch (Exception e) {
+            log.error("{}澶辫触[locNo={}, staNo={}, deviceNo={}, orderNos={}]锛屽師鍥�: {}",
+                    scene,
+                    taskDto.getLocNo(),
+                    taskDto.getStaNo(),
+                    taskDto.getDeviceNo(),
+                    collectOrderNos(taskDto),
+                    getErrorMessage(e));
+            return false;
+        }
+    }
+
+    private String collectOrderNos(TaskDto taskDto) {
+        Set<String> orderNos = new LinkedHashSet<>();
+        for (LocDto locDto : taskDto.getLocDtos()) {
+            if (!Cools.isEmpty(locDto.getOrderNo())) {
+                orderNos.add(locDto.getOrderNo());
+            }
+        }
+        return orderNos.toString();
+    }
+
+    private String getErrorMessage(Exception e) {
+        return Cools.isEmpty(e.getMessage()) ? e.getClass().getSimpleName() : e.getMessage();
+    }
 }
diff --git a/src/main/java/com/zy/asrs/task/WorkMastScheduler.java b/src/main/java/com/zy/asrs/task/WorkMastScheduler.java
index df0a5de..9121617 100644
--- a/src/main/java/com/zy/asrs/task/WorkMastScheduler.java
+++ b/src/main/java/com/zy/asrs/task/WorkMastScheduler.java
@@ -8,9 +8,7 @@
 import com.zy.api.service.WcsApiService;
 import com.zy.asrs.entity.LocAroundBind;
 import com.zy.asrs.entity.LocMast;
-import com.zy.asrs.entity.Task;
 import com.zy.asrs.entity.WrkMast;
-import com.zy.asrs.mapper.TaskMapper;
 import com.zy.asrs.service.LocAroundBindService;
 import com.zy.asrs.service.TaskService;
 import com.zy.asrs.service.WrkMastService;
@@ -88,77 +86,115 @@
         }
         Collections.shuffle(wrkMasts);
         for (WrkMast wrkMast : wrkMasts) {
-            //鏌ョ湅涓嬪彂浠诲姟鏄惁涓哄喕缁撳簱浣嶏紝鏄喕缁撳簱浣嶅垯璺宠繃涓嬪彂浠诲姟
-            LocAroundBind locAroundBind = locAroundBindService.selectOne(new EntityWrapper<LocAroundBind>()
-                    .eq("b_loc_no", wrkMast.getLocNo())
-                    .eq("freeze", 1));
-            if (Cools.isEmpty(locAroundBind)) {
-                locAroundBind = locAroundBindService.selectOne(new EntityWrapper<LocAroundBind>()
-                        .eq("b_loc_no", wrkMast.getSourceLocNo())
+            try {
+                //鏌ョ湅涓嬪彂浠诲姟鏄惁涓哄喕缁撳簱浣嶏紝鏄喕缁撳簱浣嶅垯璺宠繃涓嬪彂浠诲姟
+                LocAroundBind locAroundBind = locAroundBindService.selectOne(new EntityWrapper<LocAroundBind>()
+                        .eq("b_loc_no", wrkMast.getLocNo())
                         .eq("freeze", 1));
-                if (!Cools.isEmpty(locAroundBind)) {
+                if (Cools.isEmpty(locAroundBind)) {
+                    locAroundBind = locAroundBindService.selectOne(new EntityWrapper<LocAroundBind>()
+                            .eq("b_loc_no", wrkMast.getSourceLocNo())
+                            .eq("freeze", 1));
+                    if (!Cools.isEmpty(locAroundBind)) {
+                        markPublishError(wrkMast.getWrkNo(), String.valueOf("婧愬簱浣嶈鍐荤粨"));
+                        continue;
+                    }
+                } else {
+                    markPublishError(wrkMast.getWrkNo(), String.valueOf("鐩爣搴撲綅琚喕缁�"));
                     continue;
                 }
-            }else {
-                continue;
-            }
             Integer crnNo = wrkMast.getCrnNo();
-            //璇ュ爢鍨涙満宸茬粡涓嬪彂浠诲姟缁檞cs鍚庝笉鍐嶄笅鍙戞柊鐨勬惉杩愪换鍔�
-            List<WrkMast> wrkMasts1 = wrkMastService.selectList(new EntityWrapper<WrkMast>().eq("crn_no", crnNo).in("wrk_sts", Arrays.asList(2L, 12L)));
-            if (!wrkMasts1.isEmpty()) {
-                continue;
-            }
-            //婧愬簱浣嶄负鍐荤粨搴撲綅鏃剁姝笅鍙戞惉杩愪换鍔$粰鍫嗗灈鏈�
-            if (!Cools.isEmpty(wrkMast.getSourceLocNo())){
-                LocMast locMast = locMastService.selectOne(new EntityWrapper<LocMast>()
-                        .eq("loc_no", wrkMast.getSourceLocNo())
-                        .eq("frozen",0));
-                if (Cools.isEmpty(locMast)) {
-                    continue;
-                }
-            }
+            //濡傛灉浠诲姟鏄Щ搴撲换鍔℃椂锛氳鍫嗗灈鏈哄凡缁忎笅鍙戜换鍔$粰wcs鍚庝笉鍐嶄笅鍙戞柊鐨勬惉杩愪换鍔�
+                if(wrkMast.getIoType()==101&&!Cools.isEmpty(wrkMast.getLocNo())){
+                    LocMast locMast = locMastService.selectOne(new EntityWrapper<LocMast>().eq("crn_no", crnNo).eq("loc_no", wrkMast.getLocNo()));
+                    if (!Cools.isEmpty(locMast)) {
+                        List<WrkMast> wrkMasts1 = wrkMastService.selectList(new EntityWrapper<WrkMast>().eq("crn_no", crnNo).in("wrk_sts", Arrays.asList(12L)));
+                        if (!wrkMasts1.isEmpty()) {
+                            continue;
+                        }
+                    }
 
-            //鐩爣搴撲綅涓哄喕缁撳簱浣嶆椂绂佹涓嬪彂鎼繍浠诲姟缁欏爢鍨涙満
-            if (!Cools.isEmpty(wrkMast.getLocNo())){
-                LocMast locMast = locMastService.selectOne(new EntityWrapper<LocMast>()
-                        .eq("loc_no", wrkMast.getLocNo())
-                        .eq("frozen",0));
-                if (Cools.isEmpty(locMast)) {
-                    continue;
                 }
-            }
 
-            String wcsSourceLocNo = Cools.isEmpty(wrkMast.getSourceLocNo()) ? "" : Utils.WMSLocToWCSLoc(wrkMast.getSourceLocNo());
-            String wcsLocNo = Cools.isEmpty(wrkMast.getLocNo()) ? "" : Utils.WMSLocToWCSLoc(wrkMast.getLocNo());
-            WorkTaskParams params = new WorkTaskParams();
-            //鍑哄簱鍜岀Щ搴�
-            if(wrkMast.getIoType()==101&&!Cools.isEmpty(wrkMast.getStaNo())&& !wrkMast.getStaNo().equals("0")) {
-                params.setType("out")
-                        .setTaskNo(wrkMast.getWrkNo()+"")
-                        .setSourceLocNo(wcsSourceLocNo)
-                        .setLocNo(wcsLocNo)
-                        .setStaNo(wrkMast.getStaNo())
-                        .setTaskPri(wrkMast.getIoPri().intValue())
-                        .setBarcode(wrkMast.getBarcode());
-            }else if(wrkMast.getIoType()==2&& !Cools.isEmpty(wrkMast.getSourceStaNo())){
-                params.setType("in")
-                        .setTaskNo(wrkMast.getWrkNo()+"")
-                        .setSourceStaNo(wrkMast.getSourceStaNo())
-                        .setLocNo(wcsLocNo)
-                        .setTaskPri(wrkMast.getIoPri().intValue())
-                        .setBarcode(wrkMast.getBarcode());
-            } else {
-                params.setType("move")
-                        .setTaskNo(wrkMast.getWrkNo()+"")
-                        .setSourceLocNo(wcsSourceLocNo)
-                        .setLocNo(wcsLocNo)
-                        .setBarcode(wrkMast.getBarcode());
+                //婧愬簱浣嶄负鍐荤粨搴撲綅鏃剁姝笅鍙戞惉杩愪换鍔$粰鍫嗗灈鏈�
+                if (!Cools.isEmpty(wrkMast.getSourceLocNo())) {
+                    LocMast locMast = locMastService.selectOne(new EntityWrapper<LocMast>()
+                            .eq("loc_no", wrkMast.getSourceLocNo())
+                            .eq("frozen", 0));
+                    if (Cools.isEmpty(locMast)) {
+                        continue;
+                    }
+                }
+
+                //鐩爣搴撲綅涓哄喕缁撳簱浣嶆椂绂佹涓嬪彂鎼繍浠诲姟缁欏爢鍨涙満
+                if (!Cools.isEmpty(wrkMast.getLocNo())) {
+                    LocMast locMast = locMastService.selectOne(new EntityWrapper<LocMast>()
+                            .eq("loc_no", wrkMast.getLocNo())
+                            .eq("frozen", 0));
+                    if (Cools.isEmpty(locMast)) {
+                        continue;
+                    }
+                }
+
+                String wcsSourceLocNo = Cools.isEmpty(wrkMast.getSourceLocNo()) ? "" : Utils.WMSLocToWCSLoc(wrkMast.getSourceLocNo());
+                String wcsLocNo = Cools.isEmpty(wrkMast.getLocNo()) ? "" : Utils.WMSLocToWCSLoc(wrkMast.getLocNo());
+                Integer taskPri = wrkMast.getIoPri() == null ? null : wrkMast.getIoPri().intValue();
+                WorkTaskParams params = new WorkTaskParams();
+                //鍑哄簱鍜岀Щ搴�
+                if ((wrkMast.getIoType() == 101 || wrkMast.getIoType() == 110) && !Cools.isEmpty(wrkMast.getStaNo()) && !wrkMast.getStaNo().equals("0")) {
+                    params.setType("out")
+                            .setTaskNo(wrkMast.getWrkNo() + "")
+                            .setSourceLocNo(wcsSourceLocNo)
+                            .setLocNo(wcsLocNo)
+                            .setStaNo(wrkMast.getStaNo())
+                            .setTaskPri(taskPri)
+                            .setBarcode(wrkMast.getBarcode());
+                } else if (wrkMast.getIoType() == 2 && !Cools.isEmpty(wrkMast.getSourceStaNo())) {
+                    params.setType("in")
+                            .setTaskNo(wrkMast.getWrkNo() + "")
+                            .setSourceStaNo(wrkMast.getSourceStaNo())
+                            .setStaNo(wrkMast.getStaNo())
+                            .setLocNo(wcsLocNo)
+                            .setTaskPri(taskPri)
+                            .setBarcode(wrkMast.getBarcode());
+                } else {
+                    params.setType("move")
+                            .setTaskNo(wrkMast.getWrkNo() + "")
+                            .setSourceLocNo(wcsSourceLocNo)
+                            .setLocNo(wcsLocNo)
+                            .setBarcode(wrkMast.getBarcode());
+                }
+                R r = wcsApiService.pubWrkToWcs(params);
+                if (isSuccess(r)) {
+                    clearPublishError(wrkMast.getWrkNo());
+                    break;
+                }
+                markPublishError(wrkMast.getWrkNo(), String.valueOf(r.get("msg")));
+            } catch (Exception e) {
+                log.error("宸ヤ綔妗wrkNo={}]涓嬪彂浠诲姟寮傚父", wrkMast.getWrkNo(), e);
+                markPublishError(wrkMast.getWrkNo(), e.getMessage());
             }
-            R r = wcsApiService.pubWrkToWcs(params);
-            if (r.get("code").equals(200)){
-                break;
-            }
-        };
+        }
+    }
+
+    private boolean isSuccess(R r) {
+        return r != null && "200".equals(String.valueOf(r.get("code")));
+    }
+
+    private void markPublishError(Integer wrkNo, String msg) {
+        if (wrkMastService.updatePublishError(wrkNo, "X", new Date(), buildPublishErrorMsg(msg)) <= 0) {
+            log.error("宸ヤ綔妗wrkNo={}]鍥炲啓涓嬪彂寮傚父澶辫触", wrkNo);
+        }
+    }
+
+    private void clearPublishError(Integer wrkNo) {
+        if (wrkMastService.updatePublishError(wrkNo, null, null, null) <= 0) {
+            log.error("宸ヤ綔妗wrkNo={}]娓呯悊涓嬪彂寮傚父澶辫触", wrkNo);
+        }
+    }
+
+    private String buildPublishErrorMsg(String msg) {
+        return Cools.isEmpty(msg) || "null".equalsIgnoreCase(msg) ? "涓嬪彂浠诲姟澶辫触" : "涓嬪彂浠诲姟澶辫触锛�" + msg;
     }
 
     /**
diff --git a/src/main/java/com/zy/asrs/task/handler/WorkMastHandler.java b/src/main/java/com/zy/asrs/task/handler/WorkMastHandler.java
index c3c92c3..12d8020 100644
--- a/src/main/java/com/zy/asrs/task/handler/WorkMastHandler.java
+++ b/src/main/java/com/zy/asrs/task/handler/WorkMastHandler.java
@@ -145,7 +145,7 @@
 
                             Double v = Math.round((selectOne.getStockQty() - selectOne.getAnfme()) * 10000) / 10000.0;
 
-                            OrderDetlPakout orderDetlPakout = orderDetlPakoutService.selectItem(wrkDetl.getOrderNo(), wrkDetl.getMatnr(), wrkDetl.getBatch(), null, null, null, null,
+                            OrderDetlPakout orderDetlPakout = orderDetlPakoutService.selectItem(wrkDetl.getOrderNo(), wrkDetl.getMatnr(), wrkDetl.getBatch(), "", "", "", "",
                                     null, null, null);
 
                             if (!Objects.isNull(orderDetlPakout)) {
diff --git a/src/main/java/com/zy/common/config/AdminInterceptor.java b/src/main/java/com/zy/common/config/AdminInterceptor.java
index 795e7a1..ea13bb7 100644
--- a/src/main/java/com/zy/common/config/AdminInterceptor.java
+++ b/src/main/java/com/zy/common/config/AdminInterceptor.java
@@ -123,7 +123,7 @@
 //            String deToken = Cools.deTokn(token, user.getPassword());
 //            long timestamp = Long.parseLong(deToken.substring(0, 13));
             // 15鍒嗛挓鍚庤繃鏈�
-            if (System.currentTimeMillis() - userLogin.getCreateTime().getTime() > 900000){
+            if (System.currentTimeMillis() - userLogin.getCreateTime().getTime() > 3600000){
                 Http.response(response, BaseRes.DENIED);
                 return false;
             }
diff --git a/src/main/java/com/zy/common/service/CommonService.java b/src/main/java/com/zy/common/service/CommonService.java
index b62242a..f3cf41c 100644
--- a/src/main/java/com/zy/common/service/CommonService.java
+++ b/src/main/java/com/zy/common/service/CommonService.java
@@ -162,8 +162,8 @@
     public StartupDto getLocNo1(Integer crnNo) {
         LocMast locMast = locMastService.selectOne(new EntityWrapper<LocMast>()
                 .eq("crn_no", crnNo)
-                .eq("loc_sts","O")
-                .eq("whs_type",1)
+                .eq("loc_sts", "O")
+                .eq("whs_type", 1)
                 .orderBy("lev1,bay1"));
         if (Cools.isEmpty(locMast)) {
             return null;
@@ -196,239 +196,51 @@
      */
     @Transactional
     public StartupDto getLocNoRun(Integer whsType, Integer staDescId, Integer sourceStaNo, FindLocNoAttributeVo findLocNoAttributeVo, Integer moveCrnNo, LocTypeDto locTypeDto, int times) {
+        StartupDto startupDto = new StartupDto();
 
         // 鍒濆鍖栧弬鏁�
         int crnNo = 0;      //鍫嗗灈鏈哄彿
-        int nearRow = 0;    //鏈�娴呭簱浣嶆帓
-        int curRow = 0;     //鏈�娣卞簱浣嶆帓
-        int rowCount = 0;   //杞杞
         LocMast locMast = null;     // 鐩爣搴撲綅
-
-        StartupDto startupDto = new StartupDto();
-        RowLastno rowLastno = rowLastnoService.selectById(whsType);
-        if (Cools.isEmpty(rowLastno)) {
-            throw new CoolException("鏁版嵁寮傚父锛岃鑱旂郴绠$悊鍛�===>搴撲綅瑙勫垯鏈煡");
-        }
-        RowLastnoType rowLastnoType = rowLastnoTypeService.selectById(rowLastno.getTypeId());
-        if (Cools.isEmpty(rowLastnoType)) {
-            throw new CoolException("鏁版嵁寮傚父锛岃鑱旂郴绠$悊鍛�===銆嬪簱浣嶈鍒欑被鍨嬫湭鐭�");
-        }
-        int sRow = rowLastno.getsRow();
-        int eRow = rowLastno.geteRow();
-        int crnNumber = rowLastno.getCrnQty();
-
-
-        // ===============>>>> 寮�濮嬫墽琛�
-        curRow = rowLastno.getCurrentRow();
-
-        if (!Cools.isEmpty(moveCrnNo) && moveCrnNo != 0) {
-            crnNumber = moveCrnNo;
-            if (times == 0) {
-                curRow = moveCrnNo * 4 - 1;
-            } else {
-                curRow = moveCrnNo * 4 - 2;
-            }
-        }
-
-        //姝ょ▼搴忕敤浜庝紭鍖栧爢鍨涙満寮傚父鏃剁殑杩愯鏃堕棿
-        for (int i = times; i < crnNumber * 2; i++) {
-            int[] locNecessaryParameters = Utils.LocNecessaryParameters(rowLastno, curRow, crnNumber);
-            curRow = locNecessaryParameters[1];
-            crnNo = locNecessaryParameters[2];
-            if (basCrnpService.checkSiteError(crnNo, true)) {
-                rowCount = locNecessaryParameters[0];
-                nearRow = locNecessaryParameters[3];
-                List<LocMast> locMasts = locMastService.selectList(new EntityWrapper<LocMast>()
-                        .eq("row1", nearRow)
-                        .eq("loc_sts", "O")
-                        .eq("frozen", 0)
-                        .eq("deleted", 0)
-                        .eq("whs_type", rowLastnoType.getType().longValue()));
-                int crnCountO = wrkMastService.selectCount(new EntityWrapper<WrkMast>().eq("crn_no", crnNo).le("io_type", 100));
-                if (locMasts.size() - crnCountO <= 2) {
-                    log.error(crnNo + "鍙峰爢鍨涙満娌℃湁绌哄簱浣嶏紒锛侊紒 灏哄瑙勬牸锛� {}锛� 杞娆℃暟锛歿}", JSON.toJSONString(locTypeDto), times);
-                    nearRow = 0;
-                    times++;
-                    continue;
-                }
-                break;
-            } else {
-                times++;
-            }
-        }
-        if (nearRow == 0) {
-            throw new CoolException("鏃犲彲鐢ㄥ爢鍨涙満");
-        }
-
-        boolean signRule1 = false;
-        boolean signRule2 = false;
-
-
-        if (Utils.BooleanWhsTypeStaIoType(rowLastno)) {
-            // 闈犺繎鎽嗘斁瑙勫垯 --- 鍚屽ぉ鍚岃鏍肩墿鏂� //鍒嗙鐗�
-            if (!Cools.isEmpty(findLocNoAttributeVo.getMatnr()) && staDescId == 1) {
-                signRule1 = true;
-            }
-            // 闈犺繎鎽嗘斁瑙勫垯 --- 鍚屽ぉ鍚岃鏍肩墿鏂� //浜掗�氱増
-            if (!Cools.isEmpty(findLocNoAttributeVo.getMatnr()) && staDescId == 1) {
-                signRule2 = true;
-            }
-
-            if (!Cools.isEmpty(findLocNoAttributeVo.getMatnr()) && (staDescId == 11 || staDescId == 111)) {
-                signRule1 = true;
-            }
-        }
-
-        if (signRule1) {
-            if (nearRow != curRow) {
-                List<LocMast> locMasts = locMastService.selectList(new EntityWrapper<LocMast>()
-                        .eq("row1", nearRow)
-                        .eq("frozen", 0).eq("deleted", 0)
-                        .eq("loc_sts", "O")
-                        .eq("whs_type", rowLastnoType.getType().longValue()));
-                for (LocMast locMast1 : locMasts) {
-                    //鑾峰彇宸烽亾
-//                    List<String> groupOutsideLocCrn = Utils.getGroupOutLocCrn(curRow,nearRow,locMast1.getLocNo(), curRow>nearRow);
-//                    LocMast locMastGro = locMastService.selectById(wrkMast.getLocNo());
-                    //鑾峰彇鐩爣搴撲綅鎵�鍦ㄥ贩閬撴渶娴呴潪绌哄簱浣�
-                    LocMast locMastF = locMastService.selectLocByLocStsPakInF(curRow, nearRow, locMast1, rowLastnoType.getType().longValue());
-                    if (!Cools.isEmpty(locMastF) && locMastF.getLocSts().equals("F")) {
-                        LocDetl locDetl = locDetlService.selectOne(new EntityWrapper<LocDetl>().eq("loc_no", locMastF.getLocNo()));
-                        if (!Cools.isEmpty(locDetl) && findLocNoAttributeVo.beSimilar(locDetl)) {
-                            //鑾峰彇鐩爣搴撲綅鎵�鍦ㄥ贩閬撴渶娣辩┖搴撲綅
-                            locMast = locMastService.selectLocByLocStsPakInO(curRow, nearRow, locMast1, rowLastnoType.getType().longValue());
-                            break;
-                        }
-                    }
-                }
-            }
-        } else if (signRule2) {
-            List<String> locNos = locDetlService.getSameDetlToday(findLocNoAttributeVo.getMatnr(), sRow, eRow);
-            for (String locNo : locNos) {
-                if (Utils.isShallowLoc(slaveProperties, locNo)) {
-                    continue;
-                }
-                String shallowLocNo = Utils.getShallowLoc(slaveProperties, locNo);
-                // 妫�娴嬬洰鏍囧簱浣嶆槸鍚︿负绌哄簱浣�
-                LocMast shallowLoc = locMastService.selectById(shallowLocNo);
-                if (shallowLoc != null && shallowLoc.getLocSts().equals("O")) {
-                    if (VersionUtils.locMoveCheckLocTypeComplete(shallowLoc, locTypeDto)) {
-                        if (basCrnpService.checkSiteError(shallowLoc.getCrnNo(), true)) {
-                            locMast = shallowLoc;
-                            crnNo = locMast.getCrnNo();
-                            break;
-                        }
-                    }
-                }
-            }
-        }
-
-//        // 闈犺繎鎽嗘斁瑙勫垯 --- 绌烘墭  //鍒嗙鐗�
-//        if (staDescId == 10 && Utils.BooleanWhsTypeStaIoType(whsType)) {
-//            List<LocMast> locMasts = locMastService.selectList(new EntityWrapper<LocMast>().eq("row1", nearRow).eq("loc_sts", "O"));
-//            for (LocMast locMast1:locMasts){
-//                if (VersionUtils.locMoveCheckLocTypeComplete(locMast1, locTypeDto)) {
-//                    continue;
-//                }
-//                String shallowLoc = Utils.getDeepLoc(slaveProperties,locMast1.getLocNo());
-//                LocMast locMast2 = locMastService.selectOne(new EntityWrapper<LocMast>().eq("loc_no",shallowLoc));
-//                if (!Cools.isEmpty(locMast2) && locMast2.getLocSts().equals("D")){
-//                    locMast = locMast1;
-//                    break;
-//                }
-//            }
-//        }
-
-        // 闈犺繎鎽嗘斁瑙勫垯 --- 绌烘墭 //浜掗�氱増
-        if (staDescId == 10 && Utils.BooleanWhsTypeStaIoType(rowLastno)) {
+        RowLastno whsType1 = rowLastnoService.selectOne(new EntityWrapper<RowLastno>().eq("whs_type", 2));
+        crnNo = whsType1.getCrnQty();
+        if (basCrnpService.checkSiteError(crnNo, true)) {
+            BasCrnp basCrnp = basCrnpService.selectById(crnNo);
             List<LocMast> locMasts = locMastService.selectList(new EntityWrapper<LocMast>()
-                    .eq("loc_sts", "D").eq("frozen", 0).eq("deleted", 0)
-                    .ge("row1", sRow).le("row1", eRow).eq("whs_type", rowLastnoType.getType().longValue()));
-            if (!locMasts.isEmpty()) {
-                for (LocMast loc : locMasts) {
-                    if (Utils.isShallowLoc(slaveProperties, loc.getLocNo())) {
-                        continue;
-                    }
-                    String shallowLocNo = Utils.getShallowLoc(slaveProperties, loc.getLocNo());
-                    // 妫�娴嬬洰鏍囧簱浣嶆槸鍚︿负绌哄簱浣�
-                    LocMast shallowLoc = locMastService.selectById(shallowLocNo);
-                    if (shallowLoc != null && shallowLoc.getLocSts().equals("O")) {
-                        if (VersionUtils.locMoveCheckLocTypeComplete(shallowLoc, locTypeDto)) {
-                            if (basCrnpService.checkSiteError(shallowLoc.getCrnNo(), true)) {
-                                locMast = shallowLoc;
-                                crnNo = locMast.getCrnNo();
-                                break;
-                            }
-                        }
-                    }
-                }
+                    .eq("crn_no", basCrnp.getCrnNo())
+                    .eq("loc_sts", "O")
+                    .eq("frozen", 0)
+                    .eq("deleted", 0)
+                    .eq("whs_type", 1)
+                    .orderBy("lev1,bay1"));
+            if (Cools.isEmpty(locMasts) || locMasts.size() > 15) {
+                locMast = locMasts.get(0);
             }
         }
+        int crnNo1 = crnNo + 1;
+        if (crnNo1> whsType1.geteCrnNo()) {
+            crnNo1 = whsType1.getsCrnNo();
+        }
+        whsType1.setCrnQty(crnNo1);
+        rowLastnoService.updateById(whsType1);
 
         Wrapper<StaDesc> wrapper = null;
         StaDesc staDesc = null;
-        BasDevp staNo = null;
-
-        if (Utils.BooleanWhsTypeSta(rowLastno, staDescId)) {
-            // 鑾峰彇鐩爣绔�
-            wrapper = new EntityWrapper<StaDesc>()
-                    .eq("type_no", staDescId)
-                    .eq("stn_no", sourceStaNo)
-                    .eq("crn_no", crnNo);
-            staDesc = staDescService.selectOne(wrapper);
-            if (Cools.isEmpty(staDesc)) {
-                log.error("type_no={},stn_no={},crn_no={}", staDescId, sourceStaNo, crnNo);
-//                throw new CoolException("鍏ュ簱璺緞涓嶅瓨鍦�");
-                crnNo = 0;
-            } else {
-                staNo = basDevpService.selectById(staDesc.getCrnStn());
-                if (!staNo.getAutoing().equals("Y")) {
-                    log.error("鐩爣绔�" + staDesc.getCrnStn() + "涓嶅彲鐢�");
-//                throw new CoolException("鐩爣绔�"+staDesc.getCrnStn()+"涓嶅彲鐢�");
-                    crnNo = 0;
-                }
-                startupDto.setStaNo(staNo.getDevNo());
-            }
-            // 鏇存柊搴撲綅鎺掑彿
-            if (Cools.isEmpty(locMast)) {
-                rowLastno.setCurrentRow(curRow);
-                rowLastnoService.updateById(rowLastno);
-            }
+        // 鑾峰彇鐩爣绔�
+        wrapper = new EntityWrapper<StaDesc>()
+                .eq("type_no", staDescId)
+                .eq("stn_no", sourceStaNo)
+                .eq("crn_no", crnNo);
+        staDesc = staDescService.selectOne(wrapper);
+        if (Cools.isEmpty(staDesc)) {
+            log.error("鍏ュ簱璺緞涓嶅瓨鍦╰ype_no={},stn_no={},crn_no={}", staDescId, sourceStaNo, crnNo);
         }
-
-        // 寮�濮嬫煡鎵惧簱浣� ==============================>>
-
-        // 1.鎸夎鍒欐煡鎵惧簱浣�
-        if (Cools.isEmpty(locMast) && crnNo != 0) {
-            List<LocMast> locMasts = locMastService.selectList(new EntityWrapper<LocMast>().eq("loc_sts", "O").eq("crn_no", crnNo).eq("whs_type", rowLastnoType.getType().longValue()).orderBy("lev1").orderBy("bay1"));
-            if (!locMasts.isEmpty()) {
-                for (LocMast locMast1 : locMasts) {
-                    if (basCrnpService.checkSiteError(crnNo, true)) {
-                        locMast = locMast1;
-                        break;
-                    }
-                }
-
-            }
-        }
-
-        if (!Cools.isEmpty(locMast) && !basCrnpService.checkSiteError(crnNo, true)) {
-            locMast = null;
-        }
-
         // 閫掑綊鏌ヨ
         if (Cools.isEmpty(locMast) || !locMast.getLocSts().equals("O")) {
             // 褰撳墠宸烽亾鏃犵┖搴撲綅鏃讹紝閫掑綊璋冩暣鑷充笅涓�宸烽亾锛屾绱㈠叏閮ㄥ贩閬撴棤鏋滃悗锛岃烦鍑洪�掑綊
-            if (times < rowCount * 2) {
+            if (times < 5) {
                 times = times + 1;
                 return getLocNoRun(whsType, staDescId, sourceStaNo, findLocNoAttributeVo, moveCrnNo, locTypeDto, times);
             }
-//            // 2.搴撲綅褰撳墠鎵�灞炲昂瀵告棤绌哄簱浣嶆椂锛岃皟鏁村昂瀵稿弬鏁帮紝鍚戜笂鍏煎妫�绱㈠簱浣�
-//            if (locTypeDto.getLocType1() < 2) {
-//                int i = locTypeDto.getLocType1() + 1;
-//                locTypeDto.setLocType1((short)i);
-//                return getLocNo(1, staDescId, sourceStaNo, matnr,batch,grade, locTypeDto, 0);
-//            }
             log.error("绯荤粺娌℃湁绌哄簱浣嶏紒锛侊紒 灏哄瑙勬牸锛� {}锛� 杞娆℃暟锛歿}", JSON.toJSONString(locTypeDto), times);
             throw new CoolException("娌℃湁绌哄簱浣�");
         }
@@ -441,6 +253,7 @@
         startupDto.setCrnNo(crnNo);
         startupDto.setSourceStaNo(sourceStaNo);
         startupDto.setLocNo(locNo);
+        startupDto.setStaNo(staDesc.getCrnStn());
         return startupDto;
     }
 
diff --git a/src/main/java/com/zy/common/web/BaseController.java b/src/main/java/com/zy/common/web/BaseController.java
index 995c3d9..0c43dad 100644
--- a/src/main/java/com/zy/common/web/BaseController.java
+++ b/src/main/java/com/zy/common/web/BaseController.java
@@ -21,6 +21,9 @@
 import javax.servlet.http.HttpServletRequest;
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.time.temporal.Temporal;
 import java.util.*;
 
 /**
@@ -154,7 +157,11 @@
         if (Cools.isEmpty(condition)) {
             return;
         }
-        List<String> columns = new ArrayList<>();
+        String keyword = String.valueOf(condition).trim();
+        if (keyword.isEmpty()) {
+            return;
+        }
+        boolean appended = false;
         for (Field field :Cools.getAllFields(cls)){
             if (Modifier.isFinal(field.getModifiers())
                     || Modifier.isStatic(field.getModifiers())
@@ -169,19 +176,83 @@
                 column = field.getName();
             }
             if (!set.contains(column)) {
-                columns.add(column);
+                if (supportsLikeSearch(field.getType())) {
+                    if (!appended) {
+                        wrapper.andNew();
+                    } else {
+                        wrapper.or();
+                    }
+                    wrapper.like(column, keyword);
+                    appended = true;
+                    continue;
+                }
+                Object exactValue = parseExactSearchValue(field.getType(), keyword);
+                if (exactValue != null) {
+                    if (!appended) {
+                        wrapper.andNew();
+                    } else {
+                        wrapper.or();
+                    }
+                    wrapper.eq(column, exactValue);
+                    appended = true;
+                }
             }
         }
-        if (columns.isEmpty()) {
-            return;
+    }
+
+    private boolean supportsLikeSearch(Class<?> fieldType) {
+        return CharSequence.class.isAssignableFrom(fieldType)
+                || fieldType == Character.class
+                || fieldType == char.class
+                || Date.class.isAssignableFrom(fieldType)
+                || Temporal.class.isAssignableFrom(fieldType);
+    }
+
+    private Object parseExactSearchValue(Class<?> fieldType, String keyword) {
+        if (!isNumericField(fieldType)) {
+            return null;
         }
-        for (int i=0;i<columns.size();i++){
-            if (i==0){
-                wrapper.andNew();
-            } else {
-                wrapper.or();
+        try {
+            BigDecimal numericValue = new BigDecimal(keyword);
+            if (fieldType == Integer.class || fieldType == int.class) {
+                return numericValue.stripTrailingZeros().scale() <= 0 ? numericValue.intValueExact() : null;
             }
-            wrapper.like(columns.get(i), condition);
+            if (fieldType == Long.class || fieldType == long.class) {
+                return numericValue.stripTrailingZeros().scale() <= 0 ? numericValue.longValueExact() : null;
+            }
+            if (fieldType == Short.class || fieldType == short.class) {
+                return numericValue.stripTrailingZeros().scale() <= 0 ? numericValue.shortValueExact() : null;
+            }
+            if (fieldType == Byte.class || fieldType == byte.class) {
+                return numericValue.stripTrailingZeros().scale() <= 0 ? numericValue.byteValueExact() : null;
+            }
+            if (fieldType == BigInteger.class) {
+                return numericValue.stripTrailingZeros().scale() <= 0 ? numericValue.toBigIntegerExact() : null;
+            }
+            if (fieldType == Float.class || fieldType == float.class) {
+                float value = numericValue.floatValue();
+                return Float.isFinite(value) ? value : null;
+            }
+            if (fieldType == Double.class || fieldType == double.class) {
+                double value = numericValue.doubleValue();
+                return Double.isFinite(value) ? value : null;
+            }
+            if (fieldType == BigDecimal.class) {
+                return numericValue;
+            }
+        } catch (Exception ignored) {
+            return null;
         }
+        return null;
+    }
+
+    private boolean isNumericField(Class<?> fieldType) {
+        return Number.class.isAssignableFrom(fieldType)
+                || fieldType == byte.class
+                || fieldType == short.class
+                || fieldType == int.class
+                || fieldType == long.class
+                || fieldType == float.class
+                || fieldType == double.class;
     }
 }
diff --git a/src/main/java/com/zy/common/web/WcsController.java b/src/main/java/com/zy/common/web/WcsController.java
index 607bd5b..73510d7 100644
--- a/src/main/java/com/zy/common/web/WcsController.java
+++ b/src/main/java/com/zy/common/web/WcsController.java
@@ -62,6 +62,7 @@
     @PostMapping("/pakin/loc/v1")
     @ResponseBody
     public synchronized R getLocNo(@RequestBody SearchLocParam param) {
+        StartupDto dto = null;
         log.info("鏀跺埌WCS鍏ュ簱鎺ュ彛璇锋眰====>>鍏ュ弬:{}", param);
         if (Cools.isEmpty(param.getIoType())) {
             return R.error("鍏ュ嚭搴撶被鍨嬩笉鑳戒负绌�");
@@ -75,7 +76,7 @@
             //3S19000677895,M22003772,3  ,KP, 0A2030  ,0A2030202306050023
             //3S绠辩爜鍙�      ,绔瓙鐗╂枡鍙� ,鏁伴噺,鍗曚綅,渚涘簲鍟嗙紪鍙�,渚涘簲鍟嗘壒娆″彿
             //鏁伴噺鍜岄噸閲忚浆鎹㈠嚭鏉ョ殑鏄惁宸笉澶�
-            //weight 涓� 43.39  鍘荤毊2.35  = 41.05
+            //weight 涓� 43.39  鍘荤毊2.45  = 40.95
             //鎵樼洏鐮佷緥瀛�  845000820308,M11000787,1000,MT,0A1263,0A126320260120
             //鎹㈢畻闇�瑕�41.05*24.36绾︾瓑浜�1000
             if (Cools.isEmpty(param.getBarcode())) {
@@ -91,8 +92,22 @@
             String threeCode = param.getBarcode();
             param.setBarcode(barcode);
             //瀹為檯绉伴噸鏁伴噺
-            Double m = param.getWeight() -2.35;
+            Double m = param.getWeight() -2.45;
 
+
+            WrkMast wrkMast1 = wrkMastService.selectByBarcode(barcode);
+            if (!Cools.isEmpty(wrkMast1)&&wrkMast1.getWrkSts()==2) {
+                StartupDto dto1 =new StartupDto();
+                dto1.setBarcode(barcode);
+                dto1.setSourceStaNo(Integer.valueOf(wrkMast1.getSourceStaNo()));
+                dto1.setStaNo(Integer.valueOf(wrkMast1.getStaNo()));
+                String s = Utils.WMSLocToWCSLoc(wrkMast1.getLocNo());
+                dto1.setLocNo(s);
+                dto1.setCrnNo(wrkMast1.getCrnNo());
+                dto1.setTaskNo(wrkMast1.getWrkNo());
+                dto1.setTaskPri((int) Math.round(wrkMast1.getIoPri()));
+                return R.ok(dto1);
+            }
             Mat mat = matService.selectByMatnr(matnr);
             if(mat==null){
                 log.info("娌℃湁鎵惧埌璇ョ墿鏂欐。妗�--"+matnr+"缁勬墭鏃惰嚜鍔ㄦ柊澧炵墿鏂欙紝榛樿24.36KG/M");
@@ -132,6 +147,7 @@
                 waitPakin.setZpallet(param.getBarcode());
                 waitPakin.setAnfme(m);
                 waitPakin.setThreeCode(threeCode);
+                waitPakins.add(waitPakin);
                 waitPakinService.insert(waitPakin);
             }else {
                 for(WaitPakin waitPakin : waitPakins){
@@ -148,7 +164,9 @@
             if(Cools.isEmpty(waitPakin.getBeBatch())||waitPakin.getBeBatch()!=1){
                 flag = true;
             }
-            if (flag && (weight - m < -2.0 || weight - m > 2.0)) {
+            //2.5KG * 姣忓叕鏂ら暱搴� = 璇樊鍊�
+            Double dou= 2.5*mat.getVolume();
+            if (flag && (weight - m < -dou || weight - m > dou)) {
                 return R.error("浜岀淮鐮�="+threeCode+"鐨勭墿鏂欏疄闄呯О閲嶈浆鎹㈡垚鐨勭背鏁板拰鐗╂枡鏍囩鎻愪緵鐨勭背鏁扮浉宸緝澶ч渶瑕侀��鍥炴垨鑰呮爣璁板悗鎵嶈兘鍏ュ簱锛�");
             }
 
@@ -167,7 +185,6 @@
         sourceStaNo.setLocType1(param.getLocType1());
         LocTypeDto locTypeDto = new LocTypeDto(sourceStaNo);
 
-        StartupDto dto = null;
         switch (param.getIoType()) {
             case 1://婊℃墭鐩樺叆搴�
                 assert waitPakins != null;
diff --git a/src/main/java/com/zy/system/config/LicenseSchemaInitializer.java b/src/main/java/com/zy/system/config/LicenseSchemaInitializer.java
new file mode 100644
index 0000000..ee7204c
--- /dev/null
+++ b/src/main/java/com/zy/system/config/LicenseSchemaInitializer.java
@@ -0,0 +1,79 @@
+package com.zy.system.config;
+
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.Statement;
+
+@Component
+public class LicenseSchemaInitializer {
+
+    private final DataSource dataSource;
+
+    public LicenseSchemaInitializer(DataSource dataSource) {
+        this.dataSource = dataSource;
+    }
+
+    @PostConstruct
+    public void init() {
+        ensureTable();
+        ensureColumn("sys_license_infos", "request_code", "NVARCHAR(2048) NULL");
+    }
+
+    private void ensureTable() {
+        try (Connection connection = dataSource.getConnection()) {
+            if (hasTable(connection, "sys_license_infos")) {
+                return;
+            }
+            try (Statement statement = connection.createStatement()) {
+                statement.executeUpdate("CREATE TABLE sys_license_infos ("
+                        + "id INT IDENTITY(1,1) NOT NULL PRIMARY KEY, "
+                        + "[license] NVARCHAR(MAX) NULL, "
+                        + "license_time NVARCHAR(255) NULL, "
+                        + "request_code NVARCHAR(2048) NULL, "
+                        + "create_time DATETIME NULL)");
+            }
+        } catch (Exception ignored) {
+        }
+    }
+
+    private void ensureColumn(String tableName, String columnName, String columnDefinition) {
+        try (Connection connection = dataSource.getConnection()) {
+            if (!hasTable(connection, tableName) || hasColumn(connection, tableName, columnName)) {
+                return;
+            }
+            try (Statement statement = connection.createStatement()) {
+                statement.executeUpdate("ALTER TABLE " + tableName + " ADD " + columnName + " " + columnDefinition);
+            }
+        } catch (Exception ignored) {
+        }
+    }
+
+    private boolean hasTable(Connection connection, String tableName) throws Exception {
+        DatabaseMetaData metaData = connection.getMetaData();
+        try (ResultSet resultSet = metaData.getTables(connection.getCatalog(), null, tableName, new String[]{"TABLE"})) {
+            while (resultSet.next()) {
+                if (tableName.equalsIgnoreCase(resultSet.getString("TABLE_NAME"))) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private boolean hasColumn(Connection connection, String tableName, String columnName) throws Exception {
+        DatabaseMetaData metaData = connection.getMetaData();
+        try (ResultSet resultSet = metaData.getColumns(connection.getCatalog(), null, tableName, columnName)) {
+            while (resultSet.next()) {
+                if (columnName.equalsIgnoreCase(resultSet.getString("COLUMN_NAME"))) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+}
diff --git a/src/main/java/com/zy/system/controller/LicenseCreatorController.java b/src/main/java/com/zy/system/controller/LicenseCreatorController.java
index ba27337..e949e1f 100644
--- a/src/main/java/com/zy/system/controller/LicenseCreatorController.java
+++ b/src/main/java/com/zy/system/controller/LicenseCreatorController.java
@@ -1,109 +1,161 @@
 package com.zy.system.controller;
 
-import com.core.common.Cools;
+import com.core.annotations.ManagerAuth;
 import com.core.common.R;
-import com.zy.system.entity.license.*;
+import com.zy.system.entity.LicenseInfos;
+import com.zy.system.entity.license.LicenseCheckListener;
+import com.zy.system.entity.license.LicenseUploadParam;
+import com.zy.system.entity.license.LicenseUtils;
+import com.zy.system.entity.license.LicenseVerify;
+import com.zy.system.entity.license.LicenseVerifyParam;
+import com.zy.system.service.LicenseInfosService;
 import com.zy.system.timer.LicenseTimer;
 import de.schlichtherle.license.LicenseContent;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.multipart.MultipartFile;
 
-import java.io.File;
-import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Base64;
 import java.util.Date;
 
 /**
- *
- * 鐢ㄤ簬鐢熸垚璇佷功鏂囦欢锛屼笉鑳芥斁鍦ㄧ粰瀹㈡埛閮ㄧ讲鐨勪唬鐮侀噷
+ * 璁稿彲璇佽繍琛屾椂绠$悊
  */
 @RestController
 @RequestMapping("/license")
 public class LicenseCreatorController {
 
-    @Value("${license.licensePath}")
-    private String licensePath;
-
+    @Value("${license.subject}")
+    private String licenseSubject;
+    @Value("${license.publicAlias}")
+    private String publicAlias;
+    @Value("${license.storePass}")
+    private String storePass;
+    @Value("${license.publicKeysStorePath}")
+    private String publicKeysStorePath;
     @Autowired
     private LicenseCheckListener licenseCheckListener;
     @Autowired
     private LicenseTimer licenseTimer;
+    @Autowired
+    private LicenseInfosService licenseInfosService;
+
     /**
-     * 鑾峰彇鏈嶅姟鍣ㄧ‖浠朵俊鎭�
-     * @param osName 鎿嶄綔绯荤粺绫诲瀷锛屽鏋滀负绌哄垯鑷姩鍒ゆ柇
+     * 鑾峰彇璇锋眰鐮併��
      */
-    @RequestMapping(value = "/getServerInfos",produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
-    public LicenseCheck getServerInfos(@RequestParam(value = "osName",required = false) String osName) {
-        //鎿嶄綔绯荤粺绫诲瀷
-        if(Cools.isEmpty(osName)){
-            osName = System.getProperty("os.name");
-        }
-        osName = osName.toLowerCase();
+    @ManagerAuth(value = ManagerAuth.Auth.NONE)
+    @RequestMapping(value = "/getRequestCode", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
+    public R getRequestCode() {
+        return R.ok(LicenseUtils.buildRequestCode(licenseSubject));
+    }
 
-        AbstractServerInfos abstractServerInfos = null;
-
-        //鏍规嵁涓嶅悓鎿嶄綔绯荤粺绫诲瀷閫夋嫨涓嶅悓鐨勬暟鎹幏鍙栨柟娉�
-        if (osName.startsWith("windows")) {
-            abstractServerInfos = new WindowsServerInfos();
-        } else if (osName.startsWith("linux")) {
-//            abstractServerInfos = new LinuxServerInfos();
-        }else{//鍏朵粬鏈嶅姟鍣ㄧ被鍨�
-            abstractServerInfos = new WindowsServerInfos();
-        }
-
-        return abstractServerInfos.getServerInfos();
+    /**
+     * 鑾峰彇绯荤粺閰嶇疆銆�
+     */
+    @ManagerAuth(value = ManagerAuth.Auth.NONE)
+    @RequestMapping(value = "/getServerInfos", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
+    public Object getServerInfos(@RequestParam(value = "osName", required = false) String osName) {
+        return LicenseUtils.getServerInfos();
     }
 
     /**
      * 鑾峰彇璁稿彲璇佹湁鏁堟湡澶╂暟
      */
-    @RequestMapping(value = "/getLicenseDays")
+    @ManagerAuth(value = ManagerAuth.Auth.NONE)
+    @RequestMapping(value = "/getLicenseDays", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
     public R getLicenseDays() {
-        return R.ok(licenseTimer.getLicenseDays());
+        int licenseDays = licenseTimer.getLicenseDays();
+        if (!licenseTimer.getSystemSupport()) {
+            licenseDays = -1;
+        }
+        return R.ok(licenseDays);
     }
 
-    @RequestMapping(value = "/updateLicense")
-    public R updateLicense(@RequestParam("file") MultipartFile[] files){
-        MultipartFile file = files[0];
-
-        String licensePathFileName = this.getClass().getClassLoader().getResource(licensePath).getPath();
-        File licensePathFile = new File(licensePathFileName);
-        //鏈嶅姟鍣ㄧ淇濆瓨鐨勬枃浠跺璞�
-        File serverFile = new File(licensePathFile.getPath());
-        if (serverFile.exists()) {
-            try {
-                serverFile.delete();//瀛樺湪鏂囦欢锛屽垹闄�
-            } catch (Exception e) {
-                e.printStackTrace();
-            }
+    @ManagerAuth(value = ManagerAuth.Auth.NONE)
+    @RequestMapping(value = "/updateLicense", consumes = MediaType.APPLICATION_JSON_VALUE, produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
+    public R updateLicense(@RequestBody LicenseUploadParam param){
+        if (param == null || param.getLicense() == null || param.getLicense().trim().isEmpty()) {
+            return R.error("璁稿彲璇佸唴瀹逛笉鑳戒负绌�");
         }
+        return saveAndActivateLicense(param.getLicense().trim());
+    }
 
+    @ManagerAuth(value = ManagerAuth.Auth.NONE)
+    @RequestMapping(value = "/updateLicense", consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
+    public R updateLicense(@RequestParam("file") MultipartFile[] files) {
+        if (files == null || files.length == 0 || files[0] == null || files[0].isEmpty()) {
+            return R.error("璁稿彲璇佹枃浠朵笉鑳戒负绌�");
+        }
         try {
-            //鍒涘缓鏂囦欢
-            serverFile.createNewFile();
-            //灏嗕笂浼犵殑鏂囦欢鍐欏叆鍒版湇鍔″櫒绔枃浠跺唴
-            file.transferTo(serverFile);
-        } catch (IOException e) {
-            e.printStackTrace();
+            String licenseBase64 = Base64.getEncoder().encodeToString(files[0].getBytes());
+            return saveAndActivateLicense(licenseBase64);
+        } catch (Exception e) {
+            return R.error("璁稿彲璇佽鍙栧け璐�");
         }
-
-        //閲嶆柊鍔犺浇璁稿彲璇�
-        boolean loadedLicense = licenseCheckListener.loadLicense();
-        if (loadedLicense) {
-            return R.ok();
-        }
-        return R.error("璁稿彲璇佹洿鏂板け璐�");
     }
 
-
-    @RequestMapping(value = "/activate")
+    @ManagerAuth(value = ManagerAuth.Auth.NONE)
+    @RequestMapping(value = "/activate", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
     public R activate() {
         licenseTimer.timer();
+        if (!licenseTimer.getSystemSupport()) {
+            return R.error("璁稿彲璇佹縺娲诲け璐�");
+        }
         return R.ok();
     }
 
-}
\ No newline at end of file
+    @ManagerAuth(value = ManagerAuth.Auth.NONE)
+    @RequestMapping(value = "/getProjectName", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
+    public R getProjectName() {
+        return R.ok(licenseSubject);
+    }
+
+    private R saveAndActivateLicense(String licenseBase64) {
+        LicenseVerifyParam verifyParam = buildVerifyParam();
+        LicenseVerify licenseVerify = new LicenseVerify();
+        LicenseContent install = licenseVerify.install(verifyParam, licenseBase64);
+        if (install == null) {
+            return R.error("璁稿彲璇佸唴瀹规棤鏁�");
+        }
+
+        LicenseInfos licenseInfos = new LicenseInfos();
+        licenseInfos.setLicense(licenseBase64);
+        licenseInfos.setLicenseTime(formatLicenseTime(install));
+        licenseInfos.setRequestCode(LicenseUtils.buildRequestCode(licenseSubject));
+        licenseInfos.setCreateTime(new Date());
+        if (!licenseInfosService.insert(licenseInfos)) {
+            return R.error("璁稿彲璇佷繚瀛樺け璐�");
+        }
+
+        boolean loadedLicense = licenseCheckListener.loadLicense(false);
+        if (!loadedLicense) {
+            return R.error("璁稿彲璇佹縺娲诲け璐�");
+        }
+        licenseTimer.verify();
+        if (!licenseTimer.getSystemSupport()) {
+            return R.error("璁稿彲璇佹牎楠屽け璐�");
+        }
+        return R.ok();
+    }
+
+    private LicenseVerifyParam buildVerifyParam() {
+        LicenseVerifyParam param = new LicenseVerifyParam();
+        param.setSubject(licenseSubject);
+        param.setPublicAlias(publicAlias);
+        param.setStorePass(storePass);
+        param.setPublicKeysStorePath(publicKeysStorePath);
+        return param;
+    }
+
+    private String formatLicenseTime(LicenseContent install) {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        return format.format(install.getNotBefore()) + "  -  " + format.format(install.getNotAfter());
+    }
+
+}
diff --git a/src/main/java/com/zy/system/entity/LicenseInfos.java b/src/main/java/com/zy/system/entity/LicenseInfos.java
new file mode 100644
index 0000000..6fa8f88
--- /dev/null
+++ b/src/main/java/com/zy/system/entity/LicenseInfos.java
@@ -0,0 +1,42 @@
+package com.zy.system.entity;
+
+import com.baomidou.mybatisplus.annotations.TableField;
+import com.baomidou.mybatisplus.annotations.TableId;
+import com.baomidou.mybatisplus.annotations.TableName;
+import com.baomidou.mybatisplus.enums.IdType;
+import com.core.common.Cools;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+@Data
+@TableName("sys_license_infos")
+public class LicenseInfos implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    private String license;
+
+    @TableField("license_time")
+    private String licenseTime;
+
+    @TableField("request_code")
+    private String requestCode;
+
+    @TableField("create_time")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+
+    public String getCreateTime$() {
+        if (Cools.isEmpty(this.createTime)) {
+            return "";
+        }
+        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.createTime);
+    }
+}
diff --git a/src/main/java/com/zy/system/entity/license/AbstractServerInfos.java b/src/main/java/com/zy/system/entity/license/AbstractServerInfos.java
index f771d16..0b50b5e 100644
--- a/src/main/java/com/zy/system/entity/license/AbstractServerInfos.java
+++ b/src/main/java/com/zy/system/entity/license/AbstractServerInfos.java
@@ -24,11 +24,26 @@
 
         try {
             result.setIpAddress(this.getIpAddress());
+        }catch (Exception e){
+            logger.error("鑾峰彇鏈嶅姟鍣↖P澶辫触",e);
+        }
+
+        try {
             result.setMacAddress(this.getMacAddress());
+        }catch (Exception e){
+            logger.error("鑾峰彇鏈嶅姟鍣∕AC澶辫触",e);
+        }
+
+        try {
             result.setCpuSerial(this.getCPUSerial());
+        }catch (Exception e){
+            logger.error("鑾峰彇鏈嶅姟鍣–PU搴忓垪鍙峰け璐�",e);
+        }
+
+        try {
             result.setMainBoardSerial(this.getMainBoardSerial());
         }catch (Exception e){
-            logger.error("鑾峰彇鏈嶅姟鍣ㄧ‖浠朵俊鎭け璐�",e);
+            logger.error("鑾峰彇鏈嶅姟鍣ㄤ富鏉垮簭鍒楀彿澶辫触",e);
         }
 
         return result;
@@ -84,6 +99,9 @@
     protected String getMacByInetAddress(InetAddress inetAddr){
         try {
             byte[] mac = NetworkInterface.getByInetAddress(inetAddr).getHardwareAddress();
+            if (mac == null) {
+                return null;
+            }
             StringBuffer stringBuffer = new StringBuffer();
 
             for(int i=0;i<mac.length;i++){
@@ -108,4 +126,4 @@
         return null;
     }
 
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/zy/system/entity/license/CustomLicenseManager.java b/src/main/java/com/zy/system/entity/license/CustomLicenseManager.java
index 1ad2cc1..5d8a404 100644
--- a/src/main/java/com/zy/system/entity/license/CustomLicenseManager.java
+++ b/src/main/java/com/zy/system/entity/license/CustomLicenseManager.java
@@ -1,6 +1,5 @@
 package com.zy.system.entity.license;
 
-import com.core.common.Cools;
 import de.schlichtherle.license.*;
 import de.schlichtherle.xml.GenericCertificate;
 import org.apache.logging.log4j.LogManager;
@@ -11,7 +10,6 @@
 import java.io.ByteArrayInputStream;
 import java.io.UnsupportedEncodingException;
 import java.util.Date;
-import java.util.List;
 
 /**
  * 鑷畾涔塋icenseManager锛岀敤浜庡鍔犻澶栫殑鏈嶅姟鍣ㄧ‖浠朵俊鎭牎楠�
@@ -120,34 +118,20 @@
         //1. 棣栧厛璋冪敤鐖剁被鐨剉alidate鏂规硶
         super.validate(content);
 
-        //2. 鐒跺悗鏍¢獙鑷畾涔夌殑License鍙傛暟
-        //License涓彲琚厑璁哥殑鍙傛暟淇℃伅
-        LicenseCheck expectedCheckModel = (LicenseCheck) content.getExtra();
-        //褰撳墠鏈嶅姟鍣ㄧ湡瀹炵殑鍙傛暟淇℃伅
-        LicenseCheck serverCheckModel = getServerInfos();
+        Object extra = content.getExtra();
+        LicenseCheck serverCheckModel = LicenseUtils.getServerInfos();
 
-        if(expectedCheckModel != null && serverCheckModel != null){
-            //鏍¢獙IP鍦板潃
-            if(!checkIpAddress(expectedCheckModel.getIpAddress(),serverCheckModel.getIpAddress())){
-                throw new LicenseContentException("褰撳墠鏈嶅姟鍣ㄧ殑IP娌″湪鎺堟潈鑼冨洿鍐�");
-            }
-
-            //鏍¢獙Mac鍦板潃
-            if(!checkIpAddress(expectedCheckModel.getMacAddress(),serverCheckModel.getMacAddress())){
-                throw new LicenseContentException("褰撳墠鏈嶅姟鍣ㄧ殑Mac鍦板潃娌″湪鎺堟潈鑼冨洿鍐�");
-            }
-
-            //鏍¢獙涓绘澘搴忓垪鍙�
-            if(!checkSerial(expectedCheckModel.getMainBoardSerial(),serverCheckModel.getMainBoardSerial())){
-                throw new LicenseContentException("褰撳墠鏈嶅姟鍣ㄧ殑涓绘澘搴忓垪鍙锋病鍦ㄦ巿鏉冭寖鍥村唴");
-            }
-
-            //鏍¢獙CPU搴忓垪鍙�
-            if(!checkSerial(expectedCheckModel.getCpuSerial(),serverCheckModel.getCpuSerial())){
-                throw new LicenseContentException("褰撳墠鏈嶅姟鍣ㄧ殑CPU搴忓垪鍙锋病鍦ㄦ巿鏉冭寖鍥村唴");
-            }
-        }else{
+        if (serverCheckModel == null) {
             throw new LicenseContentException("涓嶈兘鑾峰彇鏈嶅姟鍣ㄧ‖浠朵俊鎭�");
+        }
+
+        if (!LicenseBindingSupport.isV2Extra(extra)) {
+            throw new LicenseContentException("璁稿彲璇佹牸寮忎笉鏀寔");
+        }
+
+        LicenseBindModel bindModel = LicenseBindingSupport.parseBindModel(extra);
+        if (!LicenseBindingSupport.matches(bindModel, serverCheckModel)) {
+            throw new LicenseContentException("褰撳墠鏈嶅姟鍣ㄤ笉鍦ㄦ巿鏉冭妭鐐硅寖鍥村唴");
         }
     }
 
@@ -182,60 +166,4 @@
         return null;
     }
 
-    /**
-     * 鑾峰彇褰撳墠鏈嶅姟鍣ㄩ渶瑕侀澶栨牎楠岀殑License鍙傛暟
-     */
-    private LicenseCheck getServerInfos(){
-        //鎿嶄綔绯荤粺绫诲瀷
-        String osName = System.getProperty("os.name").toLowerCase();
-        AbstractServerInfos abstractServerInfos = null;
-
-        //鏍规嵁涓嶅悓鎿嶄綔绯荤粺绫诲瀷閫夋嫨涓嶅悓鐨勬暟鎹幏鍙栨柟娉�
-        if (osName.startsWith("windows")) {
-            abstractServerInfos = new WindowsServerInfos();
-        } else if (osName.startsWith("linux")) {
-//            abstractServerInfos = new LinuxServerInfos();
-        }else{//鍏朵粬鏈嶅姟鍣ㄧ被鍨�
-            abstractServerInfos = new WindowsServerInfos();
-        }
-
-        return abstractServerInfos.getServerInfos();
-    }
-
-    /**
-     * 鏍¢獙褰撳墠鏈嶅姟鍣ㄧ殑IP/Mac鍦板潃鏄惁鍦ㄥ彲琚厑璁哥殑IP鑼冨洿鍐�<br/>
-     * 濡傛灉瀛樺湪IP鍦ㄥ彲琚厑璁哥殑IP/Mac鍦板潃鑼冨洿鍐咃紝鍒欒繑鍥瀟rue
-     */
-    private boolean checkIpAddress(List<String> expectedList,List<String> serverList){
-        if(expectedList != null && expectedList.size() > 0){
-            if(serverList != null && serverList.size() > 0){
-                for(String expected : expectedList){
-                    if(serverList.contains(expected.trim())){
-                        return true;
-                    }
-                }
-            }
-
-            return false;
-        }else {
-            return true;
-        }
-    }
-
-    /**
-     * 鏍¢獙褰撳墠鏈嶅姟鍣ㄧ‖浠讹紙涓绘澘銆丆PU绛夛級搴忓垪鍙锋槸鍚﹀湪鍙厑璁歌寖鍥村唴
-     */
-    private boolean checkSerial(String expectedSerial,String serverSerial){
-        if(!Cools.isEmpty(expectedSerial)){
-            if(!Cools.isEmpty(serverSerial)){
-                if(expectedSerial.equals(serverSerial)){
-                    return true;
-                }
-            }
-            return false;
-        }else{
-            return true;
-        }
-    }
-
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/zy/system/entity/license/LicenseBindModel.java b/src/main/java/com/zy/system/entity/license/LicenseBindModel.java
new file mode 100644
index 0000000..cfe4d5a
--- /dev/null
+++ b/src/main/java/com/zy/system/entity/license/LicenseBindModel.java
@@ -0,0 +1,21 @@
+package com.zy.system.entity.license;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+@Data
+public class LicenseBindModel implements Serializable {
+
+    private static final long serialVersionUID = 7064744215406459726L;
+
+    private Integer version = 2;
+
+    private String bindMode = "MULTI_NODE";
+
+    private String matchMode = "ANY";
+
+    private List<LicenseNodeCheck> nodes = new ArrayList<>();
+}
diff --git a/src/main/java/com/zy/system/entity/license/LicenseBindingSupport.java b/src/main/java/com/zy/system/entity/license/LicenseBindingSupport.java
new file mode 100644
index 0000000..d983c85
--- /dev/null
+++ b/src/main/java/com/zy/system/entity/license/LicenseBindingSupport.java
@@ -0,0 +1,176 @@
+package com.zy.system.entity.license;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public final class LicenseBindingSupport {
+
+    private LicenseBindingSupport() {
+    }
+
+    public static boolean isV2Extra(Object extra) {
+        if (extra == null) {
+            return false;
+        }
+        if (extra instanceof LicenseBindModel) {
+            return true;
+        }
+        if (extra instanceof JSONObject) {
+            return isV2Json((JSONObject) extra);
+        }
+        if (extra instanceof String) {
+            String text = ((String) extra).trim();
+            if (isBlank(text) || !text.startsWith("{")) {
+                return false;
+            }
+            return isV2Json(JSON.parseObject(text));
+        }
+        return false;
+    }
+
+    public static LicenseBindModel parseBindModel(Object extra) {
+        if (extra == null) {
+            return null;
+        }
+        if (extra instanceof LicenseBindModel) {
+            return normalizeBindModel((LicenseBindModel) extra);
+        }
+        if (extra instanceof JSONObject) {
+            return normalizeBindModel(((JSONObject) extra).toJavaObject(LicenseBindModel.class));
+        }
+        if (extra instanceof String) {
+            String text = ((String) extra).trim();
+            if (isBlank(text)) {
+                return null;
+            }
+            return normalizeBindModel(JSON.parseObject(text, LicenseBindModel.class));
+        }
+        return normalizeBindModel(JSON.parseObject(JSON.toJSONString(extra), LicenseBindModel.class));
+    }
+
+    public static boolean matches(LicenseBindModel licenseBind, LicenseCheck serverCheck) {
+        if (licenseBind == null) {
+            return false;
+        }
+        if ("UNLIMITED".equalsIgnoreCase(trimToEmpty(licenseBind.getBindMode()))) {
+            return true;
+        }
+        List<LicenseNodeCheck> nodes = licenseBind.getNodes();
+        if (nodes == null || nodes.isEmpty()) {
+            return true;
+        }
+        for (LicenseNodeCheck node : nodes) {
+            if (matchesNode(node, serverCheck)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static boolean isV2Json(JSONObject jsonObject) {
+        if (jsonObject == null) {
+            return false;
+        }
+        return jsonObject.containsKey("nodes")
+                || jsonObject.containsKey("bindMode")
+                || jsonObject.containsKey("matchMode")
+                || Integer.valueOf(2).equals(jsonObject.getInteger("version"));
+    }
+
+    private static LicenseBindModel normalizeBindModel(LicenseBindModel source) {
+        if (source == null) {
+            return null;
+        }
+        LicenseBindModel target = new LicenseBindModel();
+        target.setVersion(source.getVersion() == null ? 2 : source.getVersion());
+        target.setBindMode(isBlank(source.getBindMode()) ? "MULTI_NODE" : source.getBindMode().trim());
+        target.setMatchMode(isBlank(source.getMatchMode()) ? "ANY" : source.getMatchMode().trim());
+
+        List<LicenseNodeCheck> normalizedNodes = new ArrayList<>();
+        if (source.getNodes() != null) {
+            for (LicenseNodeCheck node : source.getNodes()) {
+                if (node == null) {
+                    continue;
+                }
+                LicenseNodeCheck normalizedNode = new LicenseNodeCheck();
+                normalizedNode.setNodeId(trimToEmpty(node.getNodeId()));
+                normalizedNode.setIpAddress(normalizeList(node.getIpAddress(), false));
+                normalizedNode.setMacAddress(normalizeList(node.getMacAddress(), true));
+                normalizedNode.setCpuSerial(trimToEmpty(node.getCpuSerial()));
+                normalizedNode.setMainBoardSerial(trimToEmpty(node.getMainBoardSerial()));
+                normalizedNodes.add(normalizedNode);
+            }
+        }
+        target.setNodes(normalizedNodes);
+        return target;
+    }
+
+    private static boolean matchesNode(LicenseNodeCheck node, LicenseCheck serverCheck) {
+        if (node == null || serverCheck == null) {
+            return false;
+        }
+        if (!checkList(node.getIpAddress(), serverCheck.getIpAddress())) {
+            return false;
+        }
+        if (!checkList(node.getMacAddress(), serverCheck.getMacAddress())) {
+            return false;
+        }
+        if (!checkSerial(node.getMainBoardSerial(), serverCheck.getMainBoardSerial())) {
+            return false;
+        }
+        return checkSerial(node.getCpuSerial(), serverCheck.getCpuSerial());
+    }
+
+    private static boolean checkList(List<String> expectedList, List<String> actualList) {
+        if (expectedList == null || expectedList.isEmpty()) {
+            return true;
+        }
+        if (actualList == null || actualList.isEmpty()) {
+            return false;
+        }
+        for (String expected : expectedList) {
+            if (!isBlank(expected) && actualList.contains(expected.trim())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static boolean checkSerial(String expectedSerial, String actualSerial) {
+        if (isBlank(expectedSerial)) {
+            return true;
+        }
+        return !isBlank(actualSerial) && expectedSerial.equals(actualSerial);
+    }
+
+    private static List<String> normalizeList(List<String> values, boolean upperCase) {
+        List<String> result = new ArrayList<>();
+        if (values == null || values.isEmpty()) {
+            return result;
+        }
+        for (String value : values) {
+            if (isBlank(value)) {
+                continue;
+            }
+            String normalized = value.trim();
+            normalized = upperCase ? normalized.toUpperCase() : normalized.toLowerCase();
+            if (!result.contains(normalized)) {
+                result.add(normalized);
+            }
+        }
+        Collections.sort(result);
+        return result;
+    }
+
+    private static boolean isBlank(String value) {
+        return value == null || value.trim().isEmpty();
+    }
+
+    private static String trimToEmpty(String value) {
+        return value == null ? "" : value.trim();
+    }
+}
diff --git a/src/main/java/com/zy/system/entity/license/LicenseCheckListener.java b/src/main/java/com/zy/system/entity/license/LicenseCheckListener.java
index 99d99cc..653d493 100644
--- a/src/main/java/com/zy/system/entity/license/LicenseCheckListener.java
+++ b/src/main/java/com/zy/system/entity/license/LicenseCheckListener.java
@@ -1,6 +1,7 @@
 package com.zy.system.entity.license;
 
-import com.core.common.Cools;
+import com.zy.system.entity.LicenseInfos;
+import com.zy.system.service.LicenseInfosService;
 import com.zy.system.timer.LicenseTimer;
 import de.schlichtherle.license.LicenseContent;
 import org.apache.logging.log4j.LogManager;
@@ -12,7 +13,6 @@
 import org.springframework.context.event.ContextRefreshedEvent;
 import org.springframework.stereotype.Component;
 
-import java.io.File;
 import java.util.Date;
 
 /**
@@ -40,19 +40,12 @@
     @Value("${license.storePass}")
     private String storePass;
 
-    /**
-     * 璇佷功鐢熸垚璺緞
-     */
-    @Value("${license.licensePath}")
-    private String licensePath;
-
-    /**
-     * 瀵嗛挜搴撳瓨鍌ㄨ矾寰�
-     */
     @Value("${license.publicKeysStorePath}")
     private String publicKeysStorePath;
     @Autowired
     private LicenseTimer licenseTimer;
+    @Autowired
+    private LicenseInfosService licenseInfosService;
 
     @Override
     public void onApplicationEvent(ContextRefreshedEvent event) {
@@ -65,53 +58,58 @@
 
     //鍔犺浇璇佷功
     public boolean loadLicense() {
-        if(!Cools.isEmpty(licensePath)){
-            logger.info("++++++++ 寮�濮嬪姞杞借鍙瘉 ++++++++");
+        return loadLicense(true);
+    }
 
+    public boolean loadLicense(boolean fetchRemote) {
+        logger.info("++++++++ 寮�濮嬪姞杞借鍙瘉 ++++++++");
+
+        if (fetchRemote) {
             try {
-//                String publicKeysStoreFileName = this.getClass().getClassLoader().getResource(publicKeysStorePath).getPath();
-//                File publicKeysStoreFile = new File(publicKeysStoreFileName);
-//
-//                String licensePathFileName = this.getClass().getClassLoader().getResource(licensePath).getPath();
-//                File licensePathFile = new File(licensePathFileName);
-
-                LicenseVerifyParam param = new LicenseVerifyParam();
-                param.setSubject(subject);
-                param.setPublicAlias(publicAlias);
-                param.setStorePass(storePass);
-                param.setLicensePath(licensePath);
-                param.setPublicKeysStorePath(publicKeysStorePath);
-
-                LicenseVerify licenseVerify = new LicenseVerify();
-                //瀹夎璇佷功
-//                LicenseContent install = licenseVerify.install(param);
-
-                logger.info("++++++++ 璁稿彲璇佸姞杞界粨鏉� ++++++++");
-
-                logger.info("++++++++ 璁稿彲璇佸姞杞芥爣璁帮紝鎼滅储淇敼 ++++++++");
-                licenseTimer.setSystemSupport(true);
-                licenseTimer.setLicenseDays(9999);
-                return true;
-
-//                licenseTimer.setSystemSupport(install!=null);
-//
-//                if (install != null) {
-//                    Date start = new Date();
-//                    Date end = install.getNotAfter();
-//                    Long starTime = start.getTime();
-//                    Long endTime = end.getTime();
-//                    Long num = endTime - starTime;//鏃堕棿鎴崇浉宸殑姣鏁�
-//                    int day = (int) (num / 24 / 60 / 60 / 1000);
-//                    licenseTimer.setLicenseDays(day);
-//                }
-//
-//
-//                return install != null;
-            } catch (Exception e) {
-                return false;
+                licenseTimer.getRemoteLicense();
+            } catch (Exception ignored) {
             }
         }
-        licenseTimer.setSystemSupport(false);
-        return false;
+
+        try {
+            LicenseVerifyParam param = new LicenseVerifyParam();
+            param.setSubject(subject);
+            param.setPublicAlias(publicAlias);
+            param.setStorePass(storePass);
+            param.setPublicKeysStorePath(publicKeysStorePath);
+
+            LicenseVerify licenseVerify = new LicenseVerify();
+            String requestCode = LicenseUtils.buildRequestCode(subject);
+            LicenseInfos latestLicense = licenseInfosService.getLatestLicenseByRequestCode(requestCode);
+
+            LicenseContent install = null;
+            if (latestLicense != null && latestLicense.getLicense() != null && !latestLicense.getLicense().trim().isEmpty()) {
+                install = licenseVerify.install(param, latestLicense.getLicense().trim());
+            }
+            if (install == null) {
+                logger.info("璁稿彲璇佷笉瀛樺湪");
+                licenseTimer.setSystemSupport(false);
+                licenseTimer.setLicenseDays(0);
+                return false;
+            }
+
+            logger.info("++++++++ 璁稿彲璇佸姞杞界粨鏉� ++++++++");
+
+            licenseTimer.setSystemSupport(true);
+
+            Date start = new Date();
+            Date end = install.getNotAfter();
+            Long starTime = start.getTime();
+            Long endTime = end.getTime();
+            Long num = endTime - starTime;//鏃堕棿鎴崇浉宸殑姣鏁�
+            int day = (int) (num / 24 / 60 / 60 / 1000);
+            licenseTimer.setLicenseDays(day);
+            return true;
+        } catch (Exception e) {
+            logger.error("璁稿彲璇佸姞杞藉け璐�", e);
+            licenseTimer.setSystemSupport(false);
+            licenseTimer.setLicenseDays(0);
+            return false;
+        }
     }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/zy/system/entity/license/LicenseCreator.java b/src/main/java/com/zy/system/entity/license/LicenseCreator.java
deleted file mode 100644
index 01f2ad1..0000000
--- a/src/main/java/com/zy/system/entity/license/LicenseCreator.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package com.zy.system.entity.license;
-
-import de.schlichtherle.license.*;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-
-import javax.security.auth.x500.X500Principal;
-import java.io.File;
-import java.text.MessageFormat;
-import java.util.prefs.Preferences;
-
-/**
- * License鐢熸垚绫�
- */
-public class LicenseCreator {
-    private static Logger logger = LogManager.getLogger(LicenseCreator.class);
-    private final static X500Principal DEFAULT_HOLDER_AND_ISSUER = new X500Principal("CN=localhost, OU=localhost, O=localhost, L=SH, ST=SH, C=CN");
-    private LicenseCreatorParam param;
-
-    public LicenseCreator(LicenseCreatorParam param) {
-        this.param = param;
-    }
-
-    /**
-     * 鐢熸垚License璇佷功
-     */
-    public boolean generateLicense(){
-        try {
-            LicenseManager licenseManager = new CustomLicenseManager(initLicenseParam());
-            LicenseContent licenseContent = initLicenseContent();
-
-            licenseManager.store(licenseContent,new File(param.getLicensePath()));
-
-            return true;
-        }catch (Exception e){
-            logger.error(MessageFormat.format("璇佷功鐢熸垚澶辫触锛歿0}",param),e);
-            return false;
-        }
-    }
-
-    /**
-     * 鍒濆鍖栬瘉涔︾敓鎴愬弬鏁�
-     */
-    private LicenseParam initLicenseParam(){
-        Preferences preferences = Preferences.userNodeForPackage(LicenseCreator.class);
-
-        //璁剧疆瀵硅瘉涔﹀唴瀹瑰姞瀵嗙殑绉橀挜
-        CipherParam cipherParam = new DefaultCipherParam(param.getStorePass());
-
-        KeyStoreParam privateStoreParam = new CustomKeyStoreParam(LicenseCreator.class
-                ,param.getPrivateKeysStorePath()
-                ,param.getPrivateAlias()
-                ,param.getStorePass()
-                ,param.getKeyPass());
-
-        LicenseParam licenseParam = new DefaultLicenseParam(param.getSubject()
-                ,preferences
-                ,privateStoreParam
-                ,cipherParam);
-
-        return licenseParam;
-    }
-
-    /**
-     * 璁剧疆璇佷功鐢熸垚姝f枃淇℃伅
-     */
-    private LicenseContent initLicenseContent(){
-        LicenseContent licenseContent = new LicenseContent();
-        licenseContent.setHolder(DEFAULT_HOLDER_AND_ISSUER);
-        licenseContent.setIssuer(DEFAULT_HOLDER_AND_ISSUER);
-
-        licenseContent.setSubject(param.getSubject());
-        licenseContent.setIssued(param.getIssuedTime());
-        licenseContent.setNotBefore(param.getIssuedTime());
-        licenseContent.setNotAfter(param.getExpiryTime());
-        licenseContent.setConsumerType(param.getConsumerType());
-        licenseContent.setConsumerAmount(param.getConsumerAmount());
-        licenseContent.setInfo(param.getDescription());
-
-        //鎵╁睍鏍¢獙鏈嶅姟鍣ㄧ‖浠朵俊鎭�
-        licenseContent.setExtra(param.getLicenseCheck());
-
-        return licenseContent;
-    }
-
-}
\ No newline at end of file
diff --git a/src/main/java/com/zy/system/entity/license/LicenseCreatorParam.java b/src/main/java/com/zy/system/entity/license/LicenseCreatorParam.java
deleted file mode 100644
index 5a3915d..0000000
--- a/src/main/java/com/zy/system/entity/license/LicenseCreatorParam.java
+++ /dev/null
@@ -1,96 +0,0 @@
-package com.zy.system.entity.license;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-import lombok.Data;
-
-import java.io.Serializable;
-import java.util.Date;
-
-/**
- * License鐢熸垚绫婚渶瑕佺殑鍙傛暟
- */
-@Data
-public class LicenseCreatorParam implements Serializable {
-
-    private static final long serialVersionUID = -7793154252684580872L;
-    /**
-     * 璇佷功subject
-     */
-    private String subject;
-
-    /**
-     * 瀵嗛挜鍒О
-     */
-    private String privateAlias;
-
-    /**
-     * 瀵嗛挜瀵嗙爜锛堥渶瑕佸Ε鍠勪繚绠★紝涓嶈兘璁╀娇鐢ㄨ�呯煡閬擄級
-     */
-    private String keyPass;
-
-    /**
-     * 璁块棶绉橀挜搴撶殑瀵嗙爜
-     */
-    private String storePass;
-
-    /**
-     * 璇佷功鐢熸垚璺緞
-     */
-    private String licensePath;
-
-    /**
-     * 瀵嗛挜搴撳瓨鍌ㄨ矾寰�
-     */
-    private String privateKeysStorePath;
-
-    /**
-     * 璇佷功鐢熸晥鏃堕棿
-     */
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    private Date issuedTime = new Date();
-
-    /**
-     * 璇佷功澶辨晥鏃堕棿
-     */
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    private Date expiryTime;
-
-    /**
-     * 鐢ㄦ埛绫诲瀷
-     */
-    private String consumerType = "user";
-
-    /**
-     * 鐢ㄦ埛鏁伴噺
-     */
-    private Integer consumerAmount = 1;
-
-    /**
-     * 鎻忚堪淇℃伅
-     */
-    private String description = "";
-
-    /**
-     * 棰濆鐨勬湇鍔″櫒纭欢鏍¢獙淇℃伅
-     */
-    private LicenseCheck licenseCheck;
-
-    @Override
-    public String toString() {
-        return "LicenseCreatorParam{" +
-                "subject='" + subject + '\'' +
-                ", privateAlias='" + privateAlias + '\'' +
-                ", keyPass='" + keyPass + '\'' +
-                ", storePass='" + storePass + '\'' +
-                ", licensePath='" + licensePath + '\'' +
-                ", privateKeysStorePath='" + privateKeysStorePath + '\'' +
-                ", issuedTime=" + issuedTime +
-                ", expiryTime=" + expiryTime +
-                ", consumerType='" + consumerType + '\'' +
-                ", consumerAmount=" + consumerAmount +
-                ", description='" + description + '\'' +
-                ", licenseCheck=" + licenseCheck +
-                '}';
-    }
-
-}
diff --git a/src/main/java/com/zy/system/entity/license/LicenseNodeCheck.java b/src/main/java/com/zy/system/entity/license/LicenseNodeCheck.java
new file mode 100644
index 0000000..a0f6857
--- /dev/null
+++ b/src/main/java/com/zy/system/entity/license/LicenseNodeCheck.java
@@ -0,0 +1,22 @@
+package com.zy.system.entity.license;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+public class LicenseNodeCheck implements Serializable {
+
+    private static final long serialVersionUID = 3629488116939928951L;
+
+    private String nodeId;
+
+    private List<String> ipAddress;
+
+    private List<String> macAddress;
+
+    private String cpuSerial;
+
+    private String mainBoardSerial;
+}
diff --git a/src/main/java/com/zy/system/entity/license/LicenseUploadParam.java b/src/main/java/com/zy/system/entity/license/LicenseUploadParam.java
new file mode 100644
index 0000000..ffd9963
--- /dev/null
+++ b/src/main/java/com/zy/system/entity/license/LicenseUploadParam.java
@@ -0,0 +1,9 @@
+package com.zy.system.entity.license;
+
+import lombok.Data;
+
+@Data
+public class LicenseUploadParam {
+
+    private String license;
+}
diff --git a/src/main/java/com/zy/system/entity/license/LicenseUtils.java b/src/main/java/com/zy/system/entity/license/LicenseUtils.java
new file mode 100644
index 0000000..c1874bf
--- /dev/null
+++ b/src/main/java/com/zy/system/entity/license/LicenseUtils.java
@@ -0,0 +1,121 @@
+package com.zy.system.entity.license;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+
+import java.net.InetAddress;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.List;
+
+public class LicenseUtils {
+
+    public static LicenseCheck getServerInfos() {
+        String osName = System.getProperty("os.name").toLowerCase();
+        AbstractServerInfos abstractServerInfos;
+
+        if (osName.startsWith("windows")) {
+            abstractServerInfos = new WindowsServerInfos();
+        } else if (osName.startsWith("linux")) {
+            abstractServerInfos = new LinuxServerInfos();
+        } else {
+            abstractServerInfos = new LinuxServerInfos();
+        }
+
+        return abstractServerInfos.getServerInfos();
+    }
+
+    public static String buildRequestCode(String subject) {
+        return buildRequestCode(subject, getServerInfos());
+    }
+
+    public static String buildRequestCode(String subject, LicenseCheck licenseCheck) {
+        if (isBlank(subject)) {
+            throw new IllegalArgumentException("璁稿彲璇佸悕绉颁笉鑳戒负绌�");
+        }
+
+        LicenseCheck normalized = normalizeLicenseCheck(licenseCheck == null ? new LicenseCheck() : licenseCheck);
+        JSONObject payload = new JSONObject(true);
+        payload.put("version", 2);
+        payload.put("subject", subject);
+        payload.put("licenseBind", buildBindModel(normalized));
+        return Base64.getEncoder().encodeToString(JSON.toJSONString(payload).getBytes(StandardCharsets.UTF_8));
+    }
+
+    private static JSONObject buildBindModel(LicenseCheck licenseCheck) {
+        JSONObject bindModel = new JSONObject(true);
+        bindModel.put("version", 2);
+        bindModel.put("bindMode", "MULTI_NODE");
+        bindModel.put("matchMode", "ANY");
+
+        JSONObject node = new JSONObject(true);
+        node.put("nodeId", getNodeId());
+        node.put("ipAddress", toJsonArray(licenseCheck.getIpAddress()));
+        node.put("macAddress", toJsonArray(licenseCheck.getMacAddress()));
+        node.put("cpuSerial", trimToEmpty(licenseCheck.getCpuSerial()));
+        node.put("mainBoardSerial", trimToEmpty(licenseCheck.getMainBoardSerial()));
+
+        JSONArray nodes = new JSONArray();
+        nodes.add(node);
+        bindModel.put("nodes", nodes);
+        return bindModel;
+    }
+
+    private static LicenseCheck normalizeLicenseCheck(LicenseCheck source) {
+        LicenseCheck target = new LicenseCheck();
+        target.setIpAddress(normalizeList(source.getIpAddress(), false));
+        target.setMacAddress(normalizeList(source.getMacAddress(), true));
+        target.setCpuSerial(trimToEmpty(source.getCpuSerial()));
+        target.setMainBoardSerial(trimToEmpty(source.getMainBoardSerial()));
+        return target;
+    }
+
+    private static List<String> normalizeList(List<String> values, boolean upperCase) {
+        List<String> result = new ArrayList<>();
+        if (values == null || values.isEmpty()) {
+            return result;
+        }
+        for (String value : values) {
+            if (isBlank(value)) {
+                continue;
+            }
+            String normalized = value.trim();
+            normalized = upperCase ? normalized.toUpperCase() : normalized.toLowerCase();
+            if (!result.contains(normalized)) {
+                result.add(normalized);
+            }
+        }
+        Collections.sort(result);
+        return result;
+    }
+
+    private static JSONArray toJsonArray(List<String> values) {
+        JSONArray array = new JSONArray();
+        if (values != null && !values.isEmpty()) {
+            array.addAll(values);
+        }
+        return array;
+    }
+
+    private static String getNodeId() {
+        try {
+            String hostName = InetAddress.getLocalHost().getHostName();
+            if (!isBlank(hostName)) {
+                return hostName.trim();
+            }
+        } catch (Exception ignored) {
+        }
+        return "node-1";
+    }
+
+    private static boolean isBlank(String value) {
+        return value == null || value.trim().isEmpty();
+    }
+
+    private static String trimToEmpty(String value) {
+        return value == null ? "" : value.trim();
+    }
+}
diff --git a/src/main/java/com/zy/system/entity/license/LicenseVerify.java b/src/main/java/com/zy/system/entity/license/LicenseVerify.java
index fd95fca..1e319a1 100644
--- a/src/main/java/com/zy/system/entity/license/LicenseVerify.java
+++ b/src/main/java/com/zy/system/entity/license/LicenseVerify.java
@@ -3,14 +3,15 @@
 import de.schlichtherle.license.*;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
-import org.apache.tomcat.util.http.fileupload.IOUtils;
 
 import java.io.File;
-import java.io.FileOutputStream;
-import java.io.InputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.text.DateFormat;
 import java.text.MessageFormat;
 import java.text.SimpleDateFormat;
+import java.util.Base64;
 import java.util.prefs.Preferences;
 
 /**
@@ -22,25 +23,19 @@
     /**
      * 瀹夎License璇佷功
      */
-    public synchronized LicenseContent install(LicenseVerifyParam param){
+    public synchronized LicenseContent install(LicenseVerifyParam param, String license) {
         LicenseContent result = null;
         DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 
-        //1. 瀹夎璇佷功
-        try{
+        try {
             LicenseManager licenseManager = LicenseManagerHolder.getInstance(initLicenseParam(param));
             licenseManager.uninstall();
 
-            InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(param.getLicensePath());
-            File file = new File(param.getLicensePath());
-            try (FileOutputStream out = new FileOutputStream(file)) {
-                IOUtils.copy(inputStream, out);
-            }
-
-            result = licenseManager.install(new File(param.getLicensePath()));
-            logger.info(MessageFormat.format("璁稿彲璇佸姞杞芥垚鍔燂紝璁稿彲璇佹湁鏁堟湡锛歿0} - {1}",format.format(result.getNotBefore()),format.format(result.getNotAfter())));
-        }catch (Exception e){
-            logger.error("璁稿彲璇佸姞杞藉け璐ワ紒",e);
+            File tempFileFromBase64 = createTempFileFromBase64(license);
+            result = licenseManager.install(tempFileFromBase64);
+            logger.info(MessageFormat.format("璁稿彲璇佸姞杞芥垚鍔燂紝璁稿彲璇佹湁鏁堟湡锛歿0} - {1}", format.format(result.getNotBefore()), format.format(result.getNotAfter())));
+        } catch (Exception e) {
+            logger.error("璁稿彲璇佸姞杞藉け璐ワ紒", e);
         }
 
         return result;
@@ -53,11 +48,6 @@
         try {
             LicenseManager licenseManager = LicenseManagerHolder.getInstance(null);
             DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-
-            if (!updateSystemTime()) {
-                //鏃堕棿鏇存柊澶辫触锛岀郴缁熸椂闂磋鏇存敼
-                return false;
-            }
 
             LicenseContent licenseContent = licenseManager.verify();
             logger.info(MessageFormat.format("璁稿彲璇佹牎楠岄�氳繃锛岃鍙瘉鏈夋晥鏈燂細{0} - {1}",format.format(licenseContent.getNotBefore()),format.format(licenseContent.getNotAfter())));
@@ -73,11 +63,6 @@
      */
     public LicenseContent getVerifyInfo(){
         LicenseManager licenseManager = LicenseManagerHolder.getInstance(null);
-
-        if (!updateSystemTime()) {
-            //鏃堕棿鏇存柊澶辫触锛岀郴缁熸椂闂磋鏇存敼
-            return null;
-        }
 
         //鏍¢獙璇佷功
         try {
@@ -111,32 +96,17 @@
                 ,cipherParam);
     }
 
-    /**
-     * 鏇存柊鏃堕棿鍒版敞鍐岃〃涓�
-     */
-    private boolean updateSystemTime() {
-        // 鑾峰彇鐢ㄦ埛鏍硅妭鐐�
-        Preferences userRoot = Preferences.userRoot();
-        // 鑾峰彇鎸囧畾璺緞涓嬬殑鑺傜偣
-        Preferences node = userRoot.node("/zhongyang");
-        String key = "time";
-        // 璇诲彇娉ㄥ唽琛�
-        String value = node.get(key, null);
-        if (value != null) {
-            long originTime = Long.parseLong(value);
-            long now = System.currentTimeMillis();
-            long diff = now - originTime;//鐜板湪鏃堕棿 - 婧愭椂闂� = 鏃堕棿宸�
-            if (diff > 0) {
-                //鏃堕棿宸ぇ浜�0鎵嶅厑璁告洿鏂版敞鍐岃〃鏃堕棿
-                node.put(key, String.valueOf(System.currentTimeMillis()));
-                return true;
-            }
-        }else {
-            // 鍐欏叆娉ㄥ唽琛�
-            node.put(key, String.valueOf(System.currentTimeMillis()));
-            return true;
-        }
-        return false;
+    public File base64ToTempFile(String base64String, String filePrefix, String fileSuffix)
+            throws IOException {
+        byte[] decodedBytes = Base64.getDecoder().decode(base64String);
+        Path tempPath = Files.createTempFile(filePrefix, fileSuffix);
+        Files.write(tempPath, decodedBytes);
+        tempPath.toFile().deleteOnExit();
+        return tempPath.toFile();
     }
 
-}
\ No newline at end of file
+    public File createTempFileFromBase64(String base64Data) throws IOException {
+        return base64ToTempFile(base64Data, "temp_license_", ".bin");
+    }
+
+}
diff --git a/src/main/java/com/zy/system/entity/license/LicenseVerifyParam.java b/src/main/java/com/zy/system/entity/license/LicenseVerifyParam.java
index 33806e5..d5d2521 100644
--- a/src/main/java/com/zy/system/entity/license/LicenseVerifyParam.java
+++ b/src/main/java/com/zy/system/entity/license/LicenseVerifyParam.java
@@ -24,11 +24,6 @@
     private String storePass;
 
     /**
-     * 璇佷功鐢熸垚璺緞
-     */
-    private String licensePath;
-
-    /**
      * 瀵嗛挜搴撳瓨鍌ㄨ矾寰�
      */
     private String publicKeysStorePath;
@@ -37,11 +32,10 @@
 
     }
 
-    public LicenseVerifyParam(String subject, String publicAlias, String storePass, String licensePath, String publicKeysStorePath) {
+    public LicenseVerifyParam(String subject, String publicAlias, String storePass, String publicKeysStorePath) {
         this.subject = subject;
         this.publicAlias = publicAlias;
         this.storePass = storePass;
-        this.licensePath = licensePath;
         this.publicKeysStorePath = publicKeysStorePath;
     }
 
diff --git a/src/main/java/com/zy/system/entity/license/LinuxServerInfos.java b/src/main/java/com/zy/system/entity/license/LinuxServerInfos.java
new file mode 100644
index 0000000..7e03b16
--- /dev/null
+++ b/src/main/java/com/zy/system/entity/license/LinuxServerInfos.java
@@ -0,0 +1,65 @@
+package com.zy.system.entity.license;
+
+import com.core.common.Cools;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.net.InetAddress;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class LinuxServerInfos extends AbstractServerInfos {
+
+    @Override
+    protected List<String> getIpAddress() throws Exception {
+        List<InetAddress> inetAddresses = getLocalAllInetAddress();
+        if (inetAddresses == null || inetAddresses.isEmpty()) {
+            return null;
+        }
+        return inetAddresses.stream()
+                .map(InetAddress::getHostAddress)
+                .distinct()
+                .map(String::toLowerCase)
+                .collect(Collectors.toList());
+    }
+
+    @Override
+    protected List<String> getMacAddress() throws Exception {
+        List<InetAddress> inetAddresses = getLocalAllInetAddress();
+        if (inetAddresses == null || inetAddresses.isEmpty()) {
+            return null;
+        }
+        return inetAddresses.stream()
+                .map(this::getMacByInetAddress)
+                .filter(mac -> mac != null && !mac.trim().isEmpty())
+                .distinct()
+                .collect(Collectors.toList());
+    }
+
+    @Override
+    protected String getCPUSerial() throws Exception {
+        return readFirstNonBlankLine(new String[]{"/bin/bash", "-c", "dmidecode -t processor | grep 'ID' | awk -F ':' '{print $2}' | head -n 1"});
+    }
+
+    @Override
+    protected String getMainBoardSerial() throws Exception {
+        return readFirstNonBlankLine(new String[]{"/bin/bash", "-c", "dmidecode | grep 'Serial Number' | awk -F ':' '{print $2}' | head -n 1"});
+    }
+
+    private String readFirstNonBlankLine(String[] shell) throws Exception {
+        Process process = Runtime.getRuntime().exec(shell);
+        process.getOutputStream().close();
+
+        try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
+            String line;
+            while ((line = reader.readLine()) != null) {
+                line = line.trim();
+                if (!Cools.isEmpty(line)) {
+                    return line;
+                }
+            }
+        }
+
+        return "";
+    }
+}
diff --git a/src/main/java/com/zy/system/entity/license/WindowsServerInfos.java b/src/main/java/com/zy/system/entity/license/WindowsServerInfos.java
index c575e6d..7ae9d96 100644
--- a/src/main/java/com/zy/system/entity/license/WindowsServerInfos.java
+++ b/src/main/java/com/zy/system/entity/license/WindowsServerInfos.java
@@ -1,8 +1,10 @@
 package com.zy.system.entity.license;
 
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
 import java.net.InetAddress;
+import java.nio.charset.Charset;
 import java.util.List;
-import java.util.Scanner;
 import java.util.stream.Collectors;
 
 /**
@@ -33,7 +35,11 @@
 
         if(inetAddresses != null && inetAddresses.size() > 0){
             //2. 鑾峰彇鎵�鏈夌綉缁滄帴鍙g殑Mac鍦板潃
-            result = inetAddresses.stream().map(this::getMacByInetAddress).distinct().collect(Collectors.toList());
+            result = inetAddresses.stream()
+                    .map(this::getMacByInetAddress)
+                    .filter(mac -> mac != null && !mac.trim().isEmpty())
+                    .distinct()
+                    .collect(Collectors.toList());
         }
 
         return result;
@@ -41,45 +47,72 @@
 
     @Override
     protected String getCPUSerial() throws Exception {
-        //搴忓垪鍙�
-        String serialNumber = "";
-
-        //浣跨敤WMIC鑾峰彇CPU搴忓垪鍙�
-        Process process = Runtime.getRuntime().exec("wmic cpu get processorid");
-        process.getOutputStream().close();
-        Scanner scanner = new Scanner(process.getInputStream());
-
-        if(scanner.hasNext()){
-            scanner.next();
+        String serialNumber = readCommandValue("wmic", "cpu", "get", "processorid");
+        if (!isBlank(serialNumber)) {
+            return serialNumber;
         }
-
-        if(scanner.hasNext()){
-            serialNumber = scanner.next().trim();
-        }
-
-        scanner.close();
-        return serialNumber;
+        return readCommandValue("powershell", "-NoProfile", "-Command",
+                "(Get-CimInstance Win32_Processor | Select-Object -First 1 -ExpandProperty ProcessorId)");
     }
 
     @Override
     protected String getMainBoardSerial() throws Exception {
-        //搴忓垪鍙�
-        String serialNumber = "";
-
-        //浣跨敤WMIC鑾峰彇涓绘澘搴忓垪鍙�
-        Process process = Runtime.getRuntime().exec("wmic baseboard get serialnumber");
-        process.getOutputStream().close();
-        Scanner scanner = new Scanner(process.getInputStream());
-
-        if(scanner.hasNext()){
-            scanner.next();
+        String serialNumber = readCommandValue("wmic", "baseboard", "get", "serialnumber");
+        if (!isBlank(serialNumber)) {
+            return serialNumber;
         }
-
-        if(scanner.hasNext()){
-            serialNumber = scanner.next().trim();
-        }
-
-        scanner.close();
-        return serialNumber;
+        return readCommandValue("powershell", "-NoProfile", "-Command",
+                "(Get-CimInstance Win32_BaseBoard | Select-Object -First 1 -ExpandProperty SerialNumber)");
     }
-}
\ No newline at end of file
+
+    private String readCommandValue(String... command) {
+        try {
+            ProcessBuilder processBuilder = new ProcessBuilder(command);
+            processBuilder.redirectErrorStream(true);
+            Process process = processBuilder.start();
+            process.getOutputStream().close();
+
+            try (BufferedReader reader = new BufferedReader(
+                    new InputStreamReader(process.getInputStream(), Charset.forName("GBK")))) {
+                String line;
+                while ((line = reader.readLine()) != null) {
+                    String value = normalizeCommandOutput(line);
+                    if (!isBlank(value)) {
+                        return value;
+                    }
+                }
+            }
+        } catch (Exception ignored) {
+        }
+        return "";
+    }
+
+    private String normalizeCommandOutput(String line) {
+        if (line == null) {
+            return "";
+        }
+        String value = line.trim();
+        if (isBlank(value)) {
+            return "";
+        }
+        String lower = value.toLowerCase();
+        if ("processorid".equals(lower) || "serialnumber".equals(lower)) {
+            return "";
+        }
+        if (lower.contains("access denied")
+                || lower.contains("鎷掔粷璁块棶")
+                || lower.contains("get-ciminstance")
+                || lower.contains("fullyqualifiederrorid")
+                || lower.contains("at line:")
+                || lower.contains("categoryinfo")
+                || lower.contains("cimexception")
+                || lower.contains("createprocess error")) {
+            return "";
+        }
+        return value;
+    }
+
+    private boolean isBlank(String value) {
+        return value == null || value.trim().isEmpty();
+    }
+}
diff --git a/src/main/java/com/zy/system/mapper/LicenseInfosMapper.java b/src/main/java/com/zy/system/mapper/LicenseInfosMapper.java
new file mode 100644
index 0000000..df9bc09
--- /dev/null
+++ b/src/main/java/com/zy/system/mapper/LicenseInfosMapper.java
@@ -0,0 +1,14 @@
+package com.zy.system.mapper;
+
+import com.baomidou.mybatisplus.mapper.BaseMapper;
+import com.zy.system.entity.LicenseInfos;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+
+@Mapper
+@Repository
+public interface LicenseInfosMapper extends BaseMapper<LicenseInfos> {
+
+    LicenseInfos getLatestLicenseByRequestCode(@Param("requestCode") String requestCode);
+}
diff --git a/src/main/java/com/zy/system/service/LicenseInfosService.java b/src/main/java/com/zy/system/service/LicenseInfosService.java
new file mode 100644
index 0000000..0571605
--- /dev/null
+++ b/src/main/java/com/zy/system/service/LicenseInfosService.java
@@ -0,0 +1,9 @@
+package com.zy.system.service;
+
+import com.baomidou.mybatisplus.service.IService;
+import com.zy.system.entity.LicenseInfos;
+
+public interface LicenseInfosService extends IService<LicenseInfos> {
+
+    LicenseInfos getLatestLicenseByRequestCode(String requestCode);
+}
diff --git a/src/main/java/com/zy/system/service/impl/LicenseInfosServiceImpl.java b/src/main/java/com/zy/system/service/impl/LicenseInfosServiceImpl.java
new file mode 100644
index 0000000..9cb805b
--- /dev/null
+++ b/src/main/java/com/zy/system/service/impl/LicenseInfosServiceImpl.java
@@ -0,0 +1,16 @@
+package com.zy.system.service.impl;
+
+import com.baomidou.mybatisplus.service.impl.ServiceImpl;
+import com.zy.system.entity.LicenseInfos;
+import com.zy.system.mapper.LicenseInfosMapper;
+import com.zy.system.service.LicenseInfosService;
+import org.springframework.stereotype.Service;
+
+@Service("licenseInfosService")
+public class LicenseInfosServiceImpl extends ServiceImpl<LicenseInfosMapper, LicenseInfos> implements LicenseInfosService {
+
+    @Override
+    public LicenseInfos getLatestLicenseByRequestCode(String requestCode) {
+        return this.baseMapper.getLatestLicenseByRequestCode(requestCode);
+    }
+}
diff --git a/src/main/java/com/zy/system/timer/LicenseTimer.java b/src/main/java/com/zy/system/timer/LicenseTimer.java
index 1f0190d..48acdce 100644
--- a/src/main/java/com/zy/system/timer/LicenseTimer.java
+++ b/src/main/java/com/zy/system/timer/LicenseTimer.java
@@ -1,24 +1,142 @@
 package com.zy.system.timer;
 
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.core.common.Cools;
+import com.zy.common.utils.HttpHandler;
+import com.zy.system.entity.LicenseInfos;
+import com.zy.system.entity.license.LicenseUtils;
 import com.zy.system.entity.license.LicenseVerify;
+import com.zy.system.entity.license.LicenseVerifyParam;
+import com.zy.system.service.LicenseInfosService;
+import de.schlichtherle.license.LicenseContent;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
+
+import java.util.Date;
+import java.util.HashMap;
 
 @Component
 public class LicenseTimer {
 
-    private static boolean SYSTEM_SUPPORT = true;//绯荤粺婵�娲荤姸鎬侊紝榛樿鍏抽棴
+    private static boolean SYSTEM_SUPPORT = false;//绯荤粺婵�娲荤姸鎬侊紝榛樿鍏抽棴
 
     private static int LICENSE_DAYS = 0;//璁稿彲璇佸ぉ鏁�
+
+    @Value("${license.subject}")
+    private String subject;
+
+    @Value("${license.publicAlias}")
+    private String publicAlias;
+
+    @Value("${license.storePass}")
+    private String storePass;
+
+    @Value("${license.publicKeysStorePath}")
+    private String publicKeysStorePath;
+
+    @Value("${license.remoteServerUrl:http://net.zoneyung.net:9999/license}")
+    private String remoteServerUrl;
+
+    @Autowired
+    private LicenseInfosService licenseInfosService;
 
     //姣忓ぉ鏅氫笂11鐐规洿鏂扮郴缁熸縺娲荤姸鎬�
     @Scheduled(cron = "0 0 23 * * ? ")
     public void timer() {
-//        System.out.println(SYSTEM_SUPPORT);
-        //楠岃瘉璁稿彲璇佹槸鍚︽湁鏁�
+        try {
+            getRemoteLicense();
+        } catch (Exception ignored) {
+        }
+
+        try {
+            verify();
+        } catch (Exception ignored) {
+        }
+    }
+
+    public void getRemoteLicense() {
+        try {
+            String requestCode = LicenseUtils.buildRequestCode(subject);
+            JSONObject response = requestRemoteLicense(buildRequestCodePayload(requestCode));
+            if (isSuccess(response)) {
+                String license = response.getString("data");
+                if (Cools.isEmpty(license)) {
+                    return;
+                }
+                LicenseInfos latestLicense = licenseInfosService.getLatestLicenseByRequestCode(requestCode);
+                if (latestLicense != null && Cools.eq(latestLicense.getLicense(), license)) {
+                    return;
+                }
+                LicenseInfos licenseInfos = new LicenseInfos();
+                licenseInfos.setLicense(license);
+                licenseInfos.setCreateTime(new Date());
+                licenseInfos.setLicenseTime(response.getString("licenseTime"));
+                licenseInfos.setRequestCode(requestCode);
+                licenseInfosService.insert(licenseInfos);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    private JSONObject requestRemoteLicense(String json) {
+        try {
+            String response = new HttpHandler.Builder()
+                    .setUri(remoteServerUrl)
+                    .setPath("/remoteQueryLicense")
+                    .setJson(json)
+                    .build()
+                    .doPost();
+            if (response == null || response.trim().isEmpty()) {
+                return null;
+            }
+            return JSON.parseObject(response);
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    private String buildRequestCodePayload(String requestCode) {
+        HashMap<String, Object> map = new HashMap<>();
+        map.put("subject", subject);
+        map.put("requestCode", requestCode);
+        return JSON.toJSONString(map);
+    }
+
+    private boolean isSuccess(JSONObject jsonObject) {
+        return jsonObject != null && "ok".equalsIgnoreCase(jsonObject.getString("result"));
+    }
+
+    public void verify() {
+        LicenseVerifyParam param = new LicenseVerifyParam();
+        param.setSubject(subject);
+        param.setPublicAlias(publicAlias);
+        param.setStorePass(storePass);
+        param.setPublicKeysStorePath(publicKeysStorePath);
+
+        String requestCode = LicenseUtils.buildRequestCode(subject);
+        LicenseInfos latestLicense = licenseInfosService.getLatestLicenseByRequestCode(requestCode);
+
         LicenseVerify licenseVerify = new LicenseVerify();
-        boolean verify = licenseVerify.verify();
-        setSystemSupport(verify);//鏇存柊绯荤粺婵�娲荤姸鎬�
+        LicenseContent install = null;
+        if (latestLicense != null && !Cools.isEmpty(latestLicense.getLicense())) {
+            install = licenseVerify.install(param, latestLicense.getLicense());
+        }
+
+        if (install != null) {
+            Date start = new Date();
+            Date end = install.getNotAfter();
+            long num = end.getTime() - start.getTime();
+            int day = (int) (num / 24 / 60 / 60 / 1000);
+            setLicenseDays(day);
+            setSystemSupport(true);
+        } else {
+            setLicenseDays(0);
+            setSystemSupport(false);
+        }
     }
 
     public boolean getSystemSupport() {
diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml
index 18599c6..76d4e70 100644
--- a/src/main/resources/application-dev.yml
+++ b/src/main/resources/application-dev.yml
@@ -48,10 +48,9 @@
 
 #License鐩稿叧閰嶇疆
 license:
-  subject: integrationasrs
+  subject: jxhcasrs
   publicAlias: publicCert
   storePass: public_zhongyang_123456789
-  licensePath: license.lic
   publicKeysStorePath: publicCerts.keystore
 
 # 涓嬩綅鏈洪厤缃�
diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml
index 890bdc6..299e1ae 100644
--- a/src/main/resources/application-prod.yml
+++ b/src/main/resources/application-prod.yml
@@ -63,7 +63,6 @@
   subject: integrationasrs
   publicAlias: publicCert
   storePass: public_zhongyang_123456789
-  licensePath: license.lic
   publicKeysStorePath: publicCerts.keystore
 
 # 涓嬩綅鏈洪厤缃�
@@ -122,4 +121,4 @@
     acctID: "647e849ab6fa0f"
     username: "llw"
     password: "666666"
-    lcid: 2052
\ No newline at end of file
+    lcid: 2052
diff --git a/src/main/resources/license.lic b/src/main/resources/license.lic
deleted file mode 100644
index 22364dc..0000000
--- a/src/main/resources/license.lic
+++ /dev/null
@@ -1 +0,0 @@
-�!�;蓧嚡页僶}>菥m熂l簝�&蹻摜ズャDYw漛�<
烻-唖賳3鬕J 辴迟*疀専el龍魌�6�+�"徥H釛H|�観J_�7	i瓋I%欑�"閑�'6_堜r%�9蠤奇A疡p�鎟�眙�/讧� 頺�)�hb@s蜉C_:4驦5嶥詥嬋Yd靪齐CJ澩g厛oV�#硫?�茞f滂k齠%跏#m梲rD菰:�z啥炣蕶& 槺�$\嶋d閧'&昬7卶縎�p渓罷��cu3*崌U丫x窜鞓�3胅渆]K�&匤h烷a3GL�暼蠖伜堩{崸]r2羮�v�P湧|棖話g^�佾��?z秚井7嬇!恀�!齤-F.玬{��+纁0齇xM胡S蟱tK錺�8-z(�;J贿@lvE8逯~xЬ糍�喎潵R虷覹q閧瑾I]熧鞲|唼	D钥`輂齱⒔嗢�2纐5鎸+�
�+vt姰�罹访!栿襁场済L殞搃��\LG誒峮_厸肭�f艟�nx�	硯咧w蘼唌�"]}簟5嗳o梋a� 処P�%檞l+�C绚v3鈔闞3�繎飇�)粓篍屉蘻]綨/図gCbm�8��D/�浈豗舕酵羣�0胆臚〆�珪&ヒR弌�:@颶�兂誙綽R:g
DV3P偭U=嵆镣!�f隧�7àdrd舷[4烿凞`F酞`I彫椱柤籒r郯嵑PqE霮?Y1/!�9陔k$0an哲也嵍樗妍5譛紁驭3圢�<�(揍鬞#�掺镧翄$眕V�<霄6�?I卬��悕x�:lLm鍭�9�荳��
\ No newline at end of file
diff --git a/src/main/resources/mapper/LicenseInfosMapper.xml b/src/main/resources/mapper/LicenseInfosMapper.xml
new file mode 100644
index 0000000..44c0a49
--- /dev/null
+++ b/src/main/resources/mapper/LicenseInfosMapper.xml
@@ -0,0 +1,17 @@
+<?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.system.mapper.LicenseInfosMapper">
+
+    <resultMap id="BaseResultMap" type="com.zy.system.entity.LicenseInfos">
+        <id column="id" property="id"/>
+        <result column="license" property="license"/>
+        <result column="license_time" property="licenseTime"/>
+        <result column="request_code" property="requestCode"/>
+        <result column="create_time" property="createTime"/>
+    </resultMap>
+
+    <select id="getLatestLicenseByRequestCode" resultMap="BaseResultMap">
+        select top 1 * from sys_license_infos where request_code = #{requestCode} order by create_time desc
+    </select>
+
+</mapper>
diff --git a/src/main/resources/mapper/LocDetlMapper.xml b/src/main/resources/mapper/LocDetlMapper.xml
index 0072278..7729c7c 100644
--- a/src/main/resources/mapper/LocDetlMapper.xml
+++ b/src/main/resources/mapper/LocDetlMapper.xml
@@ -51,6 +51,8 @@
         <result column="box_type1" property="boxType1" />
         <result column="box_type2" property="boxType2" />
         <result column="box_type3" property="boxType3" />
+        <result column="area_id" property="areaId" />
+
     </resultMap>
 
     <sql id="batchSeq">
diff --git a/src/main/resources/mapper/OrderDetlPakoutMapper.xml b/src/main/resources/mapper/OrderDetlPakoutMapper.xml
index 96844e9..2dde019 100644
--- a/src/main/resources/mapper/OrderDetlPakoutMapper.xml
+++ b/src/main/resources/mapper/OrderDetlPakoutMapper.xml
@@ -60,9 +60,9 @@
         <if test="brand != null and brand != ''">
             and brand = #{brand}
         </if>
-<!--        <if test="standby1 != null and standby1 != ''">-->
-<!--            and standby1 = #{standby1}-->
-<!--        </if>-->
+        <if test="standby1 != null and standby1 != ''">
+            and standby1 = #{standby1}
+        </if>
         <if test="standby2 != null and standby2 != ''">
             and standby2 = #{standby2}
         </if>
@@ -84,7 +84,7 @@
     </select>
 
     <select id="selectItemByOrderNo" resultMap="BaseResultMap">
-        select * from man_order_detl_pakout
+        select top 1 * from man_order_detl_pakout
         where 1=1
         and order_no = #{orderNo}
         and matnr = #{matnr}
diff --git a/src/main/resources/mapper/WrkMastMapper.xml b/src/main/resources/mapper/WrkMastMapper.xml
index 02a13e6..eeb0ead 100644
--- a/src/main/resources/mapper/WrkMastMapper.xml
+++ b/src/main/resources/mapper/WrkMastMapper.xml
@@ -60,6 +60,7 @@
         <result column="full_plt" property="fullPlt" />
         <result column="pre_have" property="preHave" />
         <result column="take_none" property="takeNone" />
+        <result column="task_type" property="taskType" />
     </resultMap>
 
     <select id="selectToBeCompleteData" resultMap="BaseResultMap">
@@ -148,4 +149,12 @@
         </choose>
     </select>
 
+    <update id="updatePublishError">
+        update asr_wrk_mast
+        set upd_mk = #{updMk},
+            error_time = #{errorTime},
+            error_memo = #{errorMemo}
+        where wrk_no = #{wrkNo}
+    </update>
+
 </mapper>
diff --git a/src/main/webapp/static/js/locAroundBind/locAroundBind.js b/src/main/webapp/static/js/locAroundBind/locAroundBind.js
index 9361d1f..b18f984 100644
--- a/src/main/webapp/static/js/locAroundBind/locAroundBind.js
+++ b/src/main/webapp/static/js/locAroundBind/locAroundBind.js
@@ -23,13 +23,14 @@
         cols: [[
             {type: 'checkbox'}
             , {field: 'id', align: 'center', title: 'ID', hide: true}
-            , {field: 'devId', align: 'center', title: '鏈哄彴ID', hide: true}
-            , {field: 'devNo', align: 'center', title: '鏈哄彴鍙�'}
-            , {field: 'devName', align: 'center', title: '璁惧鍚嶇О'}
+            , {field: 'devNo$', align: 'center', title: '鏈哄彴鍙�'}
+            , {field: 'devId', align: 'center', title: '鏈哄彴ID'}
+            , {field: 'devName', align: 'center', title: '璁惧鍚嶇О', hide: true }
             , {field: 'blocId', align: 'center', title: '搴撲綅ID', hide: true}
             , {field: 'blocNo', align: 'center', title: '宸ヤ綅'}
             , {field: 'locType$', align: 'center', title: '宸ヤ綅鐘舵��'}
             , {field: 'def$', align: 'center', title: '宸ヤ綅绫诲瀷'}
+            , {field: 'freeze', align: 'center', title: '鏄惁鍐荤粨'}
             , {fixed: 'right', title: '鎿嶄綔', align: 'center', toolbar: '#operate', width: 240}
         ]],
         request: {
diff --git a/src/main/webapp/static/js/locDetl/locDetl.js b/src/main/webapp/static/js/locDetl/locDetl.js
index 1d927c7..355a82f 100644
--- a/src/main/webapp/static/js/locDetl/locDetl.js
+++ b/src/main/webapp/static/js/locDetl/locDetl.js
@@ -1,4 +1,9 @@
 var pageCurr;
+
+function formatBeBatch(beBatch) {
+    return beBatch === 1 ? '寮哄埗鍏ュ簱' : '姝e父鍏ュ簱';
+}
+
 function getCol() {
     var cols = [
         {type: 'checkbox'},
@@ -8,6 +13,9 @@
         ,{field: 'maktx', align: 'center',title: '鍟嗗搧鍚嶇О', sort:true}
         ,{field: 'orderNo', align: 'center',title: '鍗曟嵁缂栧彿', hide: true}
         ,{field: 'batch', align: 'center',title: '鎵瑰彿', sort:true}
+        ,{field: 'beBatch', align: 'center',title: '鍏ュ簱绫诲瀷', templet: function(d) {
+                return formatBeBatch(d.beBatch);
+            }}
         ,{field: 'anfme', align: 'center',title: '鏁伴噺'}
         ,{field: 'zpallet', align: 'center',title: 'SN'}
         ,{field: 'specs', align: 'center',title: '瑙勬牸'}
@@ -533,6 +541,7 @@
     form.on('submit(reset)', function (data) {
         pageCurr = 1;
         clearFormVal($('#search-box'));
+        form.render('select');
         tableReload(false);
     });
 
diff --git a/src/main/webapp/static/js/wrkMast/wrkMast.js b/src/main/webapp/static/js/wrkMast/wrkMast.js
index c1e41cb..dd64486 100644
--- a/src/main/webapp/static/js/wrkMast/wrkMast.js
+++ b/src/main/webapp/static/js/wrkMast/wrkMast.js
@@ -36,6 +36,7 @@
             ,{field: 'preHave', align: 'center',title: '鍏堝叆鍝�', hide: true}
             ,{field: 'takeNone', align: 'center',title: '绌烘搷浣�', hide: true}
             ,{field: 'isSuplus$', align: 'center', title: '鍥炲簱绫诲瀷', hide: false, width: 120}
+            ,{field: 'errorMemo', align: 'center',title: '涓嬪彂/寮傚父淇℃伅', minWidth: 220}
             ,{field: 'modiUser$', align: 'center',title: '淇敼浜哄憳', hide:true}
             ,{field: 'modiTime$', align: 'center',title: '淇敼鏃堕棿', hide:true, width: 160}
             ,{fixed: 'right', title:'鎿嶄綔', align: 'center', toolbar: '#operate', width:350}
@@ -683,3 +684,4 @@
         $("#search").click();
     }
 });
+
diff --git a/src/main/webapp/views/basDevice/basDevice.html b/src/main/webapp/views/basDevice/basDevice.html
index a2b9041..472ff71 100644
--- a/src/main/webapp/views/basDevice/basDevice.html
+++ b/src/main/webapp/views/basDevice/basDevice.html
@@ -18,9 +18,15 @@
             <div class="layui-form toolbar" id="search-box">
                 <div class="layui-form-item">
                     <div class="layui-inline">
-                        <label class="layui-form-label">缂栧彿:</label>
+                        <label class="layui-form-label">鏈哄彴鍙�:</label>
                         <div class="layui-input-inline">
-                            <input class="layui-input" type="text" name="id" placeholder="缂栧彿" autocomplete="off">
+                            <input class="layui-input" type="text" name="dev_no" placeholder="鏈哄彴鍙�" autocomplete="off">
+                        </div>
+                    </div>
+                    <div class="layui-inline">
+                        <label class="layui-form-label">鍐呴儴缂栧彿:</label>
+                        <div class="layui-input-inline">
+                            <input class="layui-input" type="text" name="type" placeholder="鍐呴儴缂栧彿" autocomplete="off">
                         </div>
                     </div>
                     <div class="layui-inline">&emsp;
diff --git a/src/main/webapp/views/index.html b/src/main/webapp/views/index.html
index ede1192..106292b 100644
--- a/src/main/webapp/views/index.html
+++ b/src/main/webapp/views/index.html
@@ -92,6 +92,31 @@
 <script type="text/javascript" src="../static/js/common.js"></script>
 <script>
   // console.log('%c 涓壃绔嬪簱骞冲彴 %c 1.0.0','background-color:rgb(53,73,94);color: #fff;border-radius:2px 0 0 2px;padding:2px 4px;','background-color:rgb(25,190,107);color: #fff;border-radius:0 2px 2px 0;padding:2px 4px;font: 9pt "Apercu Regular", Georgia, "Times New Roman", Times, serif;');
+  function getResponseValue(res) {
+    if (!res) {
+      return "";
+    }
+    if (typeof res.data !== "undefined" && res.data !== null && res.data !== "") {
+      return res.data;
+    }
+    if (typeof res.msg !== "undefined" && res.msg !== null && res.msg !== "") {
+      return res.msg;
+    }
+    return "";
+  }
+
+  function redirectToLicensePage(message) {
+    sessionStorage.setItem("licensePanelAutoOpen", "1");
+    sessionStorage.setItem("licenseInvalidReason", message || "绯荤粺褰撳墠璁稿彲璇佹棤鏁堬紝璇烽噸鏂板鍏ユ柊璁稿彲璇併��");
+    localStorage.removeItem('token');
+    top.location.href = "login.html?license=invalid";
+  }
+
+  function clearLicensePromptState() {
+    sessionStorage.removeItem("licensePanelAutoOpen");
+    sessionStorage.removeItem("licenseInvalidReason");
+  }
+
   $(function () {
     if ("" === localStorage.getItem('token')) {
       top.location.href = baseUrl + "/login";
@@ -146,13 +171,20 @@
       method: 'POST',
       success: function (res) {
         if (res.code == 200) {
-          let days = res.data
+          let days = Number(getResponseValue(res))
+          if (days < 0) {
+            redirectToLicensePage('绯荤粺褰撳墠鏈娴嬪埌鍙敤璁稿彲璇侊紝璇烽噸鏂板鍏ユ柊鐨勮鍙瘉銆�');
+            return;
+          }
+          clearLicensePromptState();
           if (days <= 30) {
             $("#licenseShow").show()
             $("#licenseDays").html(days)
+          } else {
+            $("#licenseShow").hide()
           }
         }else {
-          top.location.href = baseUrl + "/login";
+          redirectToLicensePage(res.msg || '璁稿彲璇佹牎楠屽け璐ワ紝璇烽噸鏂板鍏ユ柊鐨勮鍙瘉銆�');
         }
       }
     });
diff --git a/src/main/webapp/views/locDetl/locDetl.html b/src/main/webapp/views/locDetl/locDetl.html
index 29c1502..bdf0ccf 100644
--- a/src/main/webapp/views/locDetl/locDetl.html
+++ b/src/main/webapp/views/locDetl/locDetl.html
@@ -44,6 +44,15 @@
     </div>
     <div class="layui-inline">
         <div class="layui-input-inline">
+            <select name="beBatch" class="layui-input" autocomplete="off">
+                <option value="">鍏ュ簱绫诲瀷</option>
+                <option value="1">寮哄埗鍏ュ簱</option>
+                <option value="0">姝e父鍏ュ簱</option>
+            </select>
+        </div>
+    </div>
+    <div class="layui-inline">
+        <div class="layui-input-inline">
             <select name="frozen" class="layui-input" type="text" autocomplete="off">
                 <!--                    <option style="display: none"></option>-->
                 <option value="">鍐荤粨鍚�</option>
diff --git a/src/main/webapp/views/login.html b/src/main/webapp/views/login.html
index a113203..b89c4c4 100644
--- a/src/main/webapp/views/login.html
+++ b/src/main/webapp/views/login.html
@@ -46,6 +46,178 @@
             text-align: center;
         }
 
+        .license-entry-text {
+            width: 80%;
+            margin: 0 auto 12px;
+            color: #5e5e5e;
+            font-size: 12px;
+            line-height: 1.7;
+            text-align: left;
+        }
+
+        .system-tool-shell {
+            background: #ffffff;
+            border-radius: 22px;
+            overflow: hidden;
+        }
+
+        .system-tool-header {
+            display: flex;
+            align-items: center;
+            justify-content: space-between;
+            padding: 14px 20px;
+            border-bottom: 1px solid #dbe4ef;
+        }
+
+        .system-tool-title {
+            color: #243447;
+            font-size: 18px;
+            font-weight: 700;
+        }
+
+        .system-tool-close {
+            color: #97a5b4;
+            font-size: 24px;
+            line-height: 1;
+            cursor: pointer;
+            user-select: none;
+        }
+
+        .system-tool-body {
+            padding: 18px 20px 22px;
+            background: #ffffff;
+        }
+
+        .system-tool-group + .system-tool-group {
+            margin-top: 18px;
+            padding-top: 18px;
+            border-top: 1px solid #e8eef5;
+        }
+
+        .system-tool-group-title {
+            color: #34495e;
+            font-size: 14px;
+            font-weight: 700;
+            margin-bottom: 14px;
+        }
+
+        .system-tool-actions {
+            display: flex;
+            flex-wrap: wrap;
+            gap: 12px 18px;
+        }
+
+        .system-tool-btn {
+            min-width: 104px;
+            height: 34px;
+            padding: 0 18px;
+            border: 1px solid #d7dfea;
+            border-radius: 4px;
+            background: #ffffff;
+            color: #4d5d6d;
+            font-size: 14px;
+            cursor: pointer;
+            box-sizing: border-box;
+        }
+
+        .system-tool-btn.primary {
+            color: #ffffff;
+            background: #5da8ff;
+            border-color: #5da8ff;
+        }
+
+        .system-tool-btn.secondary {
+            color: #7eb4ef;
+            background: #d9ecff;
+            border-color: #aed4ff;
+        }
+
+        .system-tool-desc {
+            margin-top: 12px;
+            color: #9aa8b6;
+            font-size: 12px;
+            line-height: 1.7;
+        }
+
+        .system-dialog-shell {
+            background: #ffffff;
+            border-radius: 18px;
+            overflow: hidden;
+        }
+
+        .system-dialog-header {
+            display: flex;
+            align-items: center;
+            justify-content: space-between;
+            padding: 14px 18px;
+            border-bottom: 1px solid #e1e8f0;
+            background: #f8fbff;
+        }
+
+        .system-dialog-title {
+            color: #243447;
+            font-size: 16px;
+            font-weight: 700;
+        }
+
+        .system-dialog-close {
+            color: #97a5b4;
+            font-size: 22px;
+            line-height: 1;
+            cursor: pointer;
+            user-select: none;
+        }
+
+        .system-dialog-body {
+            padding: 18px;
+            background: #ffffff;
+        }
+
+        .system-dialog-label {
+            color: #43576b;
+            font-size: 13px;
+            font-weight: 700;
+            margin-bottom: 8px;
+        }
+
+        .system-dialog-tip {
+            margin-bottom: 10px;
+            color: #8c9aac;
+            font-size: 12px;
+            line-height: 1.7;
+        }
+
+        .system-dialog-textarea {
+            width: 100%;
+            min-height: 220px;
+            resize: none;
+            border: 1px solid #d7dfea;
+            border-radius: 8px;
+            padding: 10px 12px;
+            box-sizing: border-box;
+            color: #4d5d6d;
+            background: #fbfdff;
+            font-size: 13px;
+            line-height: 1.7;
+        }
+
+        .system-dialog-footer {
+            display: flex;
+            justify-content: flex-end;
+            gap: 10px;
+            margin-top: 14px;
+        }
+
+        body .system-tool-popup {
+            border-radius: 22px !important;
+            overflow: hidden !important;
+        }
+
+        body .system-tool-popup .layui-layer-content {
+            overflow: hidden !important;
+            background: transparent;
+        }
+
     </style>
 </head>
 <body>
@@ -90,10 +262,8 @@
                 <button class="login100-form-btn login-btn">Login</button>
             </div>
             <div class="container-login100-form-btn p-t-10" style="display: none;margin-top: 50px;" id="updateLicense">
-                <form enctype="multipart/form-data" style="display: none;">
-                    <input id="license" type="file" name="file">
-                </form>
-                <button class="login100-form-btn" id="submitLicense">鏇存柊璁稿彲璇�</button>
+                <div class="license-entry-text" id="licenseEntryMessage">绯荤粺褰撳墠鏈娴嬪埌鍙敤璁稿彲璇侊紝璇锋墦寮�绯荤粺宸ュ叿澶勭悊璁稿彲璇併��</div>
+                <button class="login100-form-btn" id="openLicenseTool" type="button">绯荤粺宸ュ叿</button>
             </div>
         </div>
     </div>
@@ -115,10 +285,458 @@
         if (oldPass) {
             $('#password').val(oldPass);
         }
+        autoShowLicenseTool();
     })
 
     window.onload = function () {
         document.getElementById("username").focus();
+    }
+
+    var licenseToolState = {
+        toolLayerIndex: null,
+        textLayerIndex: null,
+        uploadLayerIndex: null
+    };
+
+    function getQueryValue(name) {
+        var query = window.location.search.substring(1).split("&");
+        for (var i = 0; i < query.length; i++) {
+            var item = query[i].split("=");
+            if (item[0] === name) {
+                return decodeURIComponent(item[1] || "");
+            }
+        }
+        return "";
+    }
+
+    function autoShowLicenseTool() {
+        var needOpen = getQueryValue("license") === "invalid" || sessionStorage.getItem("licensePanelAutoOpen") === "1";
+        if (!needOpen) {
+            return;
+        }
+        verifyLicenseAvailability(function (isValid) {
+            if (isValid) {
+                clearLicensePromptState();
+                hideLicenseEntry();
+                clearLicenseQueryFlag();
+                return;
+            }
+            var message = sessionStorage.getItem("licenseInvalidReason") || "绯荤粺褰撳墠鏈娴嬪埌鍙敤璁稿彲璇侊紝璇峰厛瀵煎叆鏂扮殑璁稿彲璇併��";
+            showLicenseEntry(message);
+            openLicenseTool(message);
+        });
+    }
+
+    function showLicenseEntry(message) {
+        $("#updateLicense").show();
+        if (message) {
+            $("#licenseEntryMessage").text(message);
+        }
+    }
+
+    function hideLicenseEntry() {
+        $("#updateLicense").hide();
+    }
+
+    function clearLicensePromptState() {
+        sessionStorage.removeItem("licensePanelAutoOpen");
+        sessionStorage.removeItem("licenseInvalidReason");
+    }
+
+    function clearLicenseQueryFlag() {
+        if (window.history && window.history.replaceState && getQueryValue("license") === "invalid") {
+            window.history.replaceState(null, document.title, window.location.pathname);
+        }
+    }
+
+    function verifyLicenseAvailability(callback) {
+        $.ajax({
+            url: baseUrl + "/license/getLicenseDays",
+            method: 'GET',
+            success: function (res) {
+                if (res.code == 200) {
+                    var days = Number(getResponseValue(res));
+                    callback(!isNaN(days) && days >= 0);
+                    return;
+                }
+                callback(false);
+            },
+            error: function () {
+                callback(false);
+            }
+        });
+    }
+
+    function escapeHtml(text) {
+        return String(text || "")
+            .replace(/&/g, "&amp;")
+            .replace(/</g, "&lt;")
+            .replace(/>/g, "&gt;")
+            .replace(/\"/g, "&quot;")
+            .replace(/'/g, "&#39;");
+    }
+
+    function buildLicenseToolContent() {
+        return ''
+            + '<div class="system-tool-shell">'
+            + '  <div class="system-tool-header">'
+            + '    <div class="system-tool-title">绯荤粺宸ュ叿</div>'
+            + '    <span class="system-tool-close" id="toolClose">脳</span>'
+            + '  </div>'
+            + '  <div class="system-tool-body">'
+            + '    <div class="system-tool-group">'
+            + '      <div class="system-tool-group-title">鎺ㄨ崘鎿嶄綔</div>'
+            + '      <div class="system-tool-actions">'
+            + '        <button type="button" class="system-tool-btn primary" id="toolRequestCode">鑾峰彇璇锋眰鐮�</button>'
+            + '        <button type="button" class="system-tool-btn secondary" id="toolActivate">涓�閿縺娲�</button>'
+            + '      </div>'
+            + '      <div class="system-tool-desc">浼樺厛浣跨敤鈥滆幏鍙栬姹傜爜鈥濆拰鈥滀竴閿縺娲烩�濆畬鎴愯鍙瘉鐢宠涓庢縺娲汇��</div>'
+            + '    </div>'
+            + '    <div class="system-tool-group">'
+            + '      <div class="system-tool-group-title">鍏朵粬宸ュ叿</div>'
+            + '      <div class="system-tool-actions">'
+            + '        <button type="button" class="system-tool-btn" id="toolProjectName">鑾峰彇椤圭洰鍚嶇О</button>'
+            + '        <button type="button" class="system-tool-btn" id="toolServerInfo">鑾峰彇绯荤粺閰嶇疆</button>'
+            + '        <button type="button" class="system-tool-btn" id="toolInputLicense">褰曞叆璁稿彲璇�</button>'
+            + '      </div>'
+            + '    </div>'
+            + '  </div>'
+            + '</div>';
+    }
+
+    function openLicenseTool(message) {
+        var toolMessage = message || $("#licenseEntryMessage").text() || "绯荤粺褰撳墠鏈娴嬪埌鍙敤璁稿彲璇侊紝璇峰厛瀵煎叆鏂扮殑璁稿彲璇併��";
+        var toolWidth = Math.min($(window).width() - 32, 760);
+        showLicenseEntry(toolMessage);
+        if (licenseToolState.toolLayerIndex !== null) {
+            layer.close(licenseToolState.toolLayerIndex);
+        }
+        licenseToolState.toolLayerIndex = layer.open({
+            type: 1,
+            title: false,
+            closeBtn: 0,
+            area: [Math.min(toolWidth, 560) + 'px', 'auto'],
+            shadeClose: false,
+            skin: 'system-tool-popup',
+            content: buildLicenseToolContent(),
+            success: function (layero, index) {
+                licenseToolState.toolLayerIndex = index;
+                bindLicenseToolEvents(layero);
+            },
+            end: function () {
+                licenseToolState.toolLayerIndex = null;
+            }
+        });
+    }
+
+    function bindLicenseToolEvents(layero) {
+        layero.find("#toolClose").on("click", function () {
+            layer.close(licenseToolState.toolLayerIndex);
+        });
+        layero.find("#toolRequestCode").on("click", function () {
+            requestCode();
+        });
+        layero.find("#toolActivate").on("click", function () {
+            activateLicense();
+        });
+        layero.find("#toolProjectName").on("click", function () {
+            getProjectName();
+        });
+        layero.find("#toolServerInfo").on("click", function () {
+            getServerInfo();
+        });
+        layero.find("#toolInputLicense").on("click", function () {
+            openLicenseInputDialog();
+        });
+    }
+
+    function getResponseValue(res) {
+        if (!res) {
+            return "";
+        }
+        if (typeof res.data !== "undefined" && res.data !== null && res.data !== "") {
+            return res.data;
+        }
+        if (typeof res.msg !== "undefined" && res.msg !== null && res.msg !== "") {
+            return res.msg;
+        }
+        return "";
+    }
+
+    function openTextDialog(title, label, text, tip) {
+        var prettyText = "";
+        try {
+            prettyText = typeof text === "string" ? text : JSON.stringify(text, null, 2);
+        } catch (e) {
+            prettyText = String(text || "");
+        }
+        if (licenseToolState.textLayerIndex !== null) {
+            layer.close(licenseToolState.textLayerIndex);
+        }
+        licenseToolState.textLayerIndex = layer.open({
+            type: 1,
+            title: false,
+            closeBtn: 0,
+            area: [Math.min($(window).width() - 32, 720) + 'px', 'auto'],
+            shadeClose: false,
+            skin: 'system-tool-popup',
+            content: ''
+                + '<div class="system-dialog-shell">'
+                + '  <div class="system-dialog-header">'
+                + '    <div class="system-dialog-title">' + escapeHtml(title) + '</div>'
+                + '    <span class="system-dialog-close" id="systemTextClose">脳</span>'
+                + '  </div>'
+                + '  <div class="system-dialog-body">'
+                + '    <div class="system-dialog-label">' + escapeHtml(label) + '</div>'
+                + (tip ? '<div class="system-dialog-tip">' + escapeHtml(tip) + '</div>' : '')
+                + '    <textarea class="system-dialog-textarea" id="systemDialogText" readonly></textarea>'
+                + '    <div class="system-dialog-footer">'
+                + '      <button type="button" class="system-tool-btn" id="systemTextCloseBtn">鍏抽棴</button>'
+                + '      <button type="button" class="system-tool-btn primary" id="systemTextCopy">澶嶅埗</button>'
+                + '    </div>'
+                + '  </div>'
+                + '</div>',
+            success: function (layero, index) {
+                licenseToolState.textLayerIndex = index;
+                layero.find("#systemDialogText").val(prettyText);
+                layero.find("#systemTextClose, #systemTextCloseBtn").on("click", function () {
+                    layer.close(index);
+                });
+                layero.find("#systemTextCopy").on("click", function () {
+                    copyRequestCodeText(prettyText);
+                });
+            },
+            end: function () {
+                licenseToolState.textLayerIndex = null;
+            }
+        });
+    }
+
+    function openLicenseInputDialog() {
+        if (licenseToolState.uploadLayerIndex !== null) {
+            layer.close(licenseToolState.uploadLayerIndex);
+        }
+        licenseToolState.uploadLayerIndex = layer.open({
+            type: 1,
+            title: false,
+            closeBtn: 0,
+            area: [Math.min($(window).width() - 32, 760) + 'px', 'auto'],
+            shadeClose: false,
+            skin: 'system-tool-popup',
+            content: ''
+                + '<div class="system-dialog-shell">'
+                + '  <div class="system-dialog-header">'
+                + '    <div class="system-dialog-title">褰曞叆璁稿彲璇�</div>'
+                + '    <span class="system-dialog-close" id="licenseInputClose">脳</span>'
+                + '  </div>'
+                + '  <div class="system-dialog-body">'
+                + '    <div class="system-dialog-label">璁稿彲璇� Base64</div>'
+                + '    <div class="system-dialog-tip">灏嗚鍙瘉鏈嶅姟绔繑鍥炵殑 license 瀛楁瀹屾暣绮樿创鍒拌繖閲屻��</div>'
+                + '    <textarea class="system-dialog-textarea" id="licenseInputValue"></textarea>'
+                + '    <div class="system-dialog-footer">'
+                + '      <button type="button" class="system-tool-btn" id="licenseInputCancel">鍙栨秷</button>'
+                + '      <button type="button" class="system-tool-btn primary" id="licenseInputSubmit">鎻愪氦</button>'
+                + '    </div>'
+                + '  </div>'
+                + '</div>',
+            success: function (layero, index) {
+                licenseToolState.uploadLayerIndex = index;
+                layero.find("#licenseInputClose, #licenseInputCancel").on("click", function () {
+                    layer.close(index);
+                });
+                layero.find("#licenseInputSubmit").on("click", function () {
+                    submitLicense(layero.find("#licenseInputValue").val());
+                });
+            },
+            end: function () {
+                licenseToolState.uploadLayerIndex = null;
+            }
+        });
+    }
+
+    function requestCode() {
+        fetchRequestCode(function (value, errorMsg) {
+            if (value) {
+                openTextDialog("鑾峰彇璇锋眰鐮�", "璇锋眰鐮�", value, "璇锋眰鐮佷腑宸插寘鍚」鐩悕绉帮紝鐩存帴鍙戠粰璁稿彲璇佹湇鍔$鍗冲彲銆�");
+                return;
+            }
+            layer.msg(errorMsg || '鑾峰彇璇锋眰鐮佸け璐�', {time: 2000});
+        });
+    }
+
+    function fetchRequestCode(callback) {
+        $.ajax({
+            url: baseUrl + "/license/getRequestCode",
+            method: 'GET',
+            success: function (res) {
+                var value = getResponseValue(res);
+                if (res.code == 200) {
+                    callback(value ? String(value) : "", "");
+                    return;
+                }
+                callback("", res.msg || '鑾峰彇璇锋眰鐮佸け璐�');
+            },
+            error: function (xhr) {
+                callback("", xhr && xhr.status === 404 ? "鑾峰彇璇锋眰鐮佹帴鍙d笉瀛樺湪" : "鑾峰彇璇锋眰鐮佸け璐�");
+            }
+        })
+    }
+
+    function getProjectName() {
+        $.ajax({
+            url: baseUrl + "/license/getProjectName",
+            method: 'GET',
+            success: function (res) {
+                var value = getResponseValue(res);
+                if (res.code == 200 && value) {
+                    layer.alert(escapeHtml(String(value)), {
+                        title: '椤圭洰鍚嶇О'
+                    });
+                    return;
+                }
+                layer.msg(res.msg || '鑾峰彇椤圭洰鍚嶇О澶辫触', {time: 2000});
+            },
+            error: function () {
+                layer.msg('鑾峰彇椤圭洰鍚嶇О澶辫触', {time: 2000});
+            }
+        })
+    }
+
+    function getServerInfo() {
+        $.ajax({
+            url: baseUrl + "/license/getServerInfos",
+            method: 'GET',
+            success: function (res) {
+                openTextDialog("鑾峰彇绯荤粺閰嶇疆", "绯荤粺閰嶇疆淇℃伅", res, "鏂拌鍙瘉妯″紡涓嬪彲鐢ㄤ簬鎺掓煡褰撳墠鑺傜偣纭欢缁戝畾淇℃伅銆�");
+            },
+            error: function () {
+                fallbackServerInfoFromRequestCode();
+            }
+        })
+    }
+
+    function fallbackServerInfoFromRequestCode() {
+        fetchRequestCode(function (requestCode, errorMsg) {
+            if (!requestCode) {
+                layer.msg(errorMsg || '鑾峰彇绯荤粺閰嶇疆淇℃伅澶辫触', {time: 2000});
+                return;
+            }
+            try {
+                var decoded = decodeRequestCodePayload(requestCode);
+                var node = (((decoded || {}).licenseBind || {}).nodes || [])[0] || {};
+                var serverInfo = {
+                    subject: decoded.subject || "",
+                    nodeId: node.nodeId || "",
+                    ipAddress: node.ipAddress || [],
+                    macAddress: node.macAddress || [],
+                    cpuSerial: node.cpuSerial || "",
+                    mainBoardSerial: node.mainBoardSerial || ""
+                };
+                openTextDialog("鑾峰彇绯荤粺閰嶇疆", "绯荤粺閰嶇疆淇℃伅", serverInfo, "褰撳墠鎺ュ彛涓嶅彲鐢紝宸叉寜璇锋眰鐮佽В鏋愬嚭鏈満鑺傜偣閰嶇疆銆�");
+            } catch (e) {
+                layer.msg('鑾峰彇绯荤粺閰嶇疆淇℃伅澶辫触', {time: 2000});
+            }
+        });
+    }
+
+    function decodeRequestCodePayload(requestCode) {
+        var normalized = String(requestCode || "").replace(/\s+/g, "");
+        if (!normalized) {
+            return {};
+        }
+        var binary = window.atob(normalized);
+        var bytes = [];
+        for (var i = 0; i < binary.length; i++) {
+            bytes.push("%" + ("00" + binary.charCodeAt(i).toString(16)).slice(-2));
+        }
+        return JSON.parse(decodeURIComponent(bytes.join("")));
+    }
+
+    function activateLicense() {
+        layer.confirm('纭畾鎵ц涓�閿縺娲诲悧锛�', {
+            title: '鎻愮ず'
+        }, function (index) {
+            layer.close(index);
+            $.ajax({
+                url: baseUrl + "/license/activate",
+                method: 'POST',
+                success: function (res) {
+                    if (res.code == 200) {
+                        layer.msg('婵�娲绘垚鍔�', {time: 1500});
+                        return;
+                    }
+                    layer.msg(res.msg || '婵�娲诲け璐�', {time: 2000});
+                },
+                error: function () {
+                    layer.msg('婵�娲诲け璐�', {time: 2000});
+                }
+            })
+        });
+    }
+
+    function submitLicense(licenseBase64) {
+        if (!licenseBase64 || !licenseBase64.trim()) {
+            layer.msg('璁稿彲璇佸唴瀹逛笉鑳戒负绌�', {time: 1500});
+            return;
+        }
+        $.ajax({
+            url: baseUrl + "/license/updateLicense",
+            headers: {'Content-Type': 'application/json'},
+            data: JSON.stringify({license: licenseBase64.trim()}),
+            method: 'POST',
+            success: function (res) {
+                if (res.code == 200) {
+                    clearLicensePromptState();
+                    clearLicenseQueryFlag();
+                    if (licenseToolState.uploadLayerIndex !== null) {
+                        layer.close(licenseToolState.uploadLayerIndex);
+                    }
+                    layer.msg('璁稿彲璇佹洿鏂版垚鍔�', {time: 1000}, function () {
+                        parent.location.reload();
+                    });
+                    return;
+                }
+                layer.msg(res.msg || '璁稿彲璇佹洿鏂板け璐�', {time: 2000});
+            },
+            error: function (xhr) {
+                if (xhr && xhr.status === 403) {
+                    layer.msg('璁稿彲璇佸綍鍏ユ帴鍙h鎷︽埅锛岃閲嶅惎鏈嶅姟鍚庨噸璇�', {time: 2500});
+                    return;
+                }
+                layer.msg('璁稿彲璇佸綍鍏ュけ璐�', {time: 2000});
+            }
+        });
+    }
+
+    function copyRequestCodeText(text) {
+        if (!text) {
+            layer.msg('璇锋眰鐮佷负绌�', {time: 1500});
+            return;
+        }
+        if (navigator.clipboard && window.isSecureContext) {
+            navigator.clipboard.writeText(text).then(function () {
+                layer.msg('璇锋眰鐮佸凡澶嶅埗', {time: 1200});
+            }, function () {
+                fallbackCopy(text);
+            });
+            return;
+        }
+        fallbackCopy(text);
+    }
+
+    function fallbackCopy(text) {
+        var copyInput = $("<textarea>").val(text).css({
+            position: "fixed",
+            top: "-1000px"
+        }).appendTo("body");
+        copyInput[0].select();
+        try {
+            document.execCommand("copy");
+            layer.msg('璇锋眰鐮佸凡澶嶅埗', {time: 1200});
+        } catch (e) {
+            layer.msg('澶嶅埗澶辫触锛岃鎵嬪姩澶嶅埗', {time: 1500});
+        }
+        copyInput.remove();
     }
 
     $(document).on('click', '.login-btn', function () {
@@ -140,6 +758,8 @@
             method: 'POST',
             success: function (res) {
                 if (res.code === 200) {
+                    clearLicensePromptState();
+                    clearLicenseQueryFlag();
                     localStorage.setItem("token", res.data.token);
                     localStorage.setItem("username", res.data.username);
                     window.location.href = "index.html";
@@ -151,7 +771,8 @@
                     layer.tips(res.msg, '#password', {tips: [4, '#ff0000']});
                 } else if (res.code == 20001) {
                     layer.tips(res.msg, '.login-btn', {tips: [3, '#ff0000']});
-                    $("#updateLicense").show()
+                    showLicenseEntry(res.msg)
+                    openLicenseTool(res.msg)
                 } else {
                     layer.tips(res.msg, '.login-btn', {tips: [3, '#ff0000']});
                 }
@@ -165,37 +786,8 @@
         }
     });
 
-
-    //鏇存柊璁稿彲璇�
-    $("#submitLicense").on("click", () => {
-        $("#license").click()
-    })
-
-    //涓婁紶骞舵洿鏂拌鍙瘉
-    $("#license").on("change", (evt) => {
-        var files = evt.target.files;
-        let formData = new FormData();
-        formData.append("file", files[0])
-        $.ajax({
-            url: baseUrl + "/license/updateLicense",
-            headers: {'token': localStorage.getItem('token')},
-            data: formData,
-            method: 'POST',
-            cache: false,
-            processData: false,
-            contentType: false,
-            success: function (res) {
-                if (res.code == 200) {
-                    layer.msg('鏇存柊鎴愬姛', {time: 1000}, () => {
-                        parent.location.reload()
-                    });
-                } else {
-                    layer.msg(res.msg, {time: 2000}, () => {
-                        parent.location.reload()
-                    })
-                }
-            }
-        })
+    $("#openLicenseTool").on("click", () => {
+        openLicenseTool($("#licenseEntryMessage").text());
     })
 </script>
 </body>

--
Gitblit v1.9.1