doum
2025-11-24 c6056167b5d95a666a42fae7d948e45b0a049960
最新版本541200007
已修改5个文件
493 ■■■■■ 文件已修改
server/system_service/src/main/java/com/doumee/core/utils/Constants.java 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/core/tsp/ClusterCustomKMeans.java 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/core/tsp/Clustering.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/core/tsp/TspSolver.java 42 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/JkSketchServiceImpl.java 303 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_service/src/main/java/com/doumee/core/utils/Constants.java
@@ -1,9 +1,7 @@
package com.doumee.core.utils;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -25,9 +23,7 @@
    public static final String HEADER_USER_TOKEN = "dm_user_token";
    public static final String REDIS_USER_KEY = "user_token_list_";
    public static final String REDIS_TOKEN_KEY = "token_";
    public static final String WMS_IN_REPERTOTY_CODE_LIST = "WMS_IN_REPERTOTY_CODE_LIST";
    public static final String REDIS_HK_TOKEN_KEY = "hk_token_";
    public static   boolean IS_AUTOCALL_WORKING = false;
    public static final String HK_TOKEN_VALIDITY = "HK_TOKEN_VALIDITY";
    public static final String[]  ALL_SPELL_LIST_FIRST = new String[]{"A", "B", "C", "D", "E", "F", "G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"};
    public static final int ZERO = 0 ;
@@ -38,8 +34,6 @@
    public static final String HK_PARAM ="HK_PARAM" ;
    public static final String HK_WEBSITE_DOMAIN_URL ="HK_WEBSITE_DOMAIN_URL" ;
    public static final String LED_CONTENT_SPEED ="LED_CONTENT_SPEED" ;
    public static final String SYSTEM_TITLE ="SYSTEM_TITLE" ;
    public static final String SYSTEM_SUBTITLE ="SYSTEM_SUBTITLE" ;
    public static final String HK_HOST ="HK_HOST" ;
    public static final String HK_APPKEY ="HK_APPKEY" ;
    public static final String LOGIN_OUT_URL ="LOGIN_OUT" ;
@@ -64,19 +58,6 @@
    public static final String SIGN_IN_ATTENTION ="SIGN_IN_ATTENTION" ;
    public static final String SIGN_IN_QRCODE_PREFIX ="SIGN_IN_QRCODE_PREFIX" ;
    public static final String JK_PLAN_MAX_CLUSTER ="JK_PLAN_MAX_CLUSTER" ;
    public static final String JK_PLAN_DISTANCE_CLUSTER ="JK_PLAN_DISTANCE_CLUSTER" ;
    public static final String HK_PUSH_THIRD_URL ="HK_PUSH_THIRD_URL" ;
    public static final String API_KEY ="API_KEY" ;
    public static final String JDY_APPID = "JDY_APPID";
    public static final String JDY_ENTRY_ID ="JDY_ENTRY_ID";
    public static final String JDY_API_KEY ="JDY_API_KEY" ;
    public static final String JDY_CONFIG ="JDY_CONFIG" ;
    public static final String JDY_COMPANY_ROOT_NO ="JDY_COMPANY_ROOT_NO" ;
    public static final String JDY_SECRET ="JDY_SECRET";
    public static final String JDY_MEMBER_PUSH_STATUS_URL ="JDY_MEMBER_PUSH_STATUS_URL";
    public static final String JDY_API_HOST = "JDY_API_HOST";
    /**
     * 操作类型,用于做接口验证分组
@@ -102,6 +83,7 @@
    public static final String WEATHER_CONFIG ="WEATHER_CONFIG" ;
    public static final String REQUEST_URL ="REQUEST_URL" ;
    public static final String LOCATION ="LOCATION" ;
    public static final String API_KEY ="API_KEY" ;
    public static final String CABINET_CONFIG ="CABINET_CONFIG" ;
    public static final String BLOW_TIME ="BLOW_TIME" ;
    public static final String PRESSURE ="PRESSURE" ;
@@ -234,7 +216,6 @@
    public static  boolean DEALING_HK_NOTICE_LIST = false;
    public static  boolean DEALING_FROM_HK_VISIT = false;
    public static  boolean DEALING_HK_EMPOWER = false;
    public static  boolean DEALING_DUANLUQI_CLOSE = false;
    public static  boolean DEALING_HK_EMPOWER_DETAIL = false;
    public static  boolean DEALING_HK_EMPOWER_RESULT = false;
    public static  boolean DEALING_HK_PARKBOOK = false;
@@ -305,15 +286,6 @@
        public static final  int depart = 3;
        public static final  int custom = 4;
        public static final  int self = -1;
    }
    //类型 0门禁 1车库 2LED 3广播点 4广播设备 5断路器空开
    public interface DEVICE_TYPE{
        public static final  int door = 0;
        public static final  int park = 1;
        public static final  int led = 2;
        public static final  int broadcaset = 3;
        public static final  int broadcasetChannel = 4;
        public static final  int duanluqi = 5;
    }
    /**
@@ -560,7 +532,6 @@
    public static final String COFFEE_BEAN_TASK ="COFFEE_BEAN_TASK";
    public static final String IN_REPERTOTY_CODE ="IN_REPERTOTY_CODE";
    public static final String HOME_IMAGE ="HOME_IMAGE";
    public static final String DD_TALK ="DD_TALK";
@@ -568,6 +539,8 @@
    public static final String APP_SECRET ="APP_SECRET";
    public static final String ACCESS_TOKEN ="ACCESS_TOKEN";
    public static final String AGENT_ID ="AGENT_ID";
    public static final String WX_PLATFORM = "WX_PLATFORM";
@@ -598,11 +571,6 @@
        public static final String BIGSCREEN_UUID ="BIGSCREEN_UUID";
        public static final String IMPORTING_GAS ="IMPORTING_GAS";
        public static final String ERP_TOKEN ="ERP_TOKEN";
        public static final String HK_REGIONS ="HK_REGIONS";
        public static final String HK_CAMERAS ="HK_CAMERAS";
        public static final String HK_REGIONS_TREE ="HK_REGIONS_TREE";
        public static final String HK_FIRE_DEVICE="HK_FIRE_DEVICE";
        public static final String HK_SENSOR="HK_SENSOR";
        public static final long EXPIRE_TIME = 7200;
        public static final String INTERNAL_TOKEN ="INTERNAL_TOKEN";
@@ -797,73 +765,14 @@
        }
    }
    public static  String getWmsAreasNameByCode(String listStr,String code) {
        try {
            JSONArray list = JSONObject.parseArray(listStr );
            if(list!=null && list.size()>0){
                for (int i = 0; i < list.size(); i++) {
                    if(StringUtils.equals(list.getJSONObject(i).getString("code"),code)){
                        return  list.getJSONObject(i).getString("name");
                    }
                }
            }
        }catch (Exception e){
        }
        return null;
    }
    public static   List<JSONObject> getWmsAreasList(){
        List<JSONObject>  list = new ArrayList<>();
        JSONObject t = new JSONObject();
        t.put("code","01");
        t.put("name","蚌埠菴烟厂");
        list.add(t);
        t = new JSONObject();
        t.put("code","02");
        t.put("name","芜湖卷烟厂");
        list.add(t);
        t = new JSONObject();
        t.put("code","03");
        t.put("name","合肥卷烟厂");
        list.add(t);
        t = new JSONObject();
        t.put("code","04");
        t.put("name","阜阳卷烟厂");
        list.add(t);
        t = new JSONObject();
        t.put("code","04206");
        t.put("name","合肥卷烟厂鞍山库");
        list.add(t);
        t = new JSONObject();
        t.put("code","05");
        t.put("name","滁州卷烟厂");
        list.add(t);
        t = new JSONObject();
        t.put("code","06");
        t.put("name","蒙城香茄生产部");
        list.add(t);
        t = new JSONObject();
        t.put("code","07");
        t.put("name","重庆中烟工业有限责任公司");
        list.add(t);
        t = new JSONObject();
        t.put("code","08");
        t.put("name","陕西中烟工业有限责任公司");
        list.add(t);
        t = new JSONObject();
        t.put("code","09");
        t.put("name","特殊纪念版");
        list.add(t);
        return list;
    }
    public static void main(String[] args) {
        System.out.println(JSONObject.toJSONString(getWmsAreasList()));
//        getChinesePingyin("DDaa江萍的对对对");
//        System.out.println(DateUtil.getShortTime(new Date()));
//        System.out.println( "2025-01-14 10:50:56".substring(0,10));
//        System.out.println(Constants.checkCarNo("皖AA10991"));
//        System.out.println(Constants.getVehiclePlateNo("湘B140D17").getDescription());
//        System.out.println(Constants.getVehiclePlateNo("宿AP0637").getDescription());
//        0789150665 C97B092F 0789150561
@@ -1024,7 +933,6 @@
        LEAVED(10, "已离园 ","车辆从{data}离场 " ),
        OVER_NUMBER(11, "已过号","超时未到指定月台自动过号" ),
        CHANGE_GROUP(12, "更换月台组","从【{data}】更换到【{data1}】" ),
        BACK_TO_WAIT_SIGNIN(13, "重新签到","重新签到" ),
        ;
        // 成员变量
@@ -1614,14 +1522,6 @@
        return JSONObject.toJSONString(map);
    }
    public  interface MqttTopic{
        String mts_attr = "/dev/+/+/attr/json";//属性topic
        String mts_status = "/dev/+/+/status/json";//状态topic
        String mts_event= "/dev/+/+/event/json";//事件topic
        String mts_echo= "/dev/+/+/echo/json";//消息回复topic
        String mts_cmd= "/dev/$CATE/$DEVID/cmd/json";//命令topic
        String mts_resp= "/dev/+/+/resp/json";//命令响应topic
    }
    public  enum WarningConfig {
@@ -1629,17 +1529,12 @@
        GRID_TIME_OUT_INFO(10003, "【钥匙柜】开门超时未关闭",0),
        KEY_TIME_OUT_BACK(10004, "【钥匙柜】钥匙超时未归还",0),
        AF_QYRQ(131588, "【安防事件】区域入侵",1),
        AF_QUPD(131668, "【安防事件】区域跑动",1),
        AF_RYLG(422000001, "【安防事件】人员离岗",1),
        AF_RYLG_CUSTOM(-422000001, "【安防事件】人员离岗(定制后)",1),
        AF_QUPD(131592, "【安防事件】区域跑动",1),
        AF_RYLG(131603, "【安防事件】人员离岗",1),
        AF_KYSCX(131585, "【安防事件】跨越生产线",1),
        AF_XFTDZS(422000000, "【安防事件】消防通道阻塞",1),
        XF_SYGDBJ(254215, "【消防事件】水压过低报警",1),
        XF_SYGGBJ(254216, "【消防事件】水压过高报警",1),
        XF_HZBJ(254047, "【消防事件】火灾报警",1),
        XF_YWGDBJ(254331, "【消防事件】液位过低报警",1),
        XF_YWGGBJ(254332, "【消防事件】液位过高报警",1),
        AF_DZWL(327681, "【安防事件】电子围栏",1),
        XF_SYBJ(253956, "【消防事件】水压报警",1),
        XF_HZBJ(253999, "【消防事件】火灾报警",1),
        XF_YWBJ(254047, "【消防事件】液位报警",1),
        ;
        // 成员变量
        private int key;
server/visits/dmvisit_service/src/main/java/com/doumee/core/tsp/ClusterCustomKMeans.java
@@ -1,7 +1,9 @@
package com.doumee.core.tsp;
import java.math.BigDecimal;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.doumee.core.utils.Constants;
import com.doumee.dao.admin.request.SketchCateModel;
@@ -76,28 +78,12 @@
                    cList.add(doublePointNew.getCustomer());
                    sketchCateModel.setTotalNum(Constants.formatBigdecimal(sketchCateModel.getTotalNum()).add(Constants.formatBigdecimal(doublePointNew.getCustomer().getTotalNum())));
                }
                sortPointByCenterPoint(cluster,cList);
                sketchCateModel.setCustomerList(cList);
                sketchCateModel.setStartPoint(cList.get(0));
                sketchCateModel.setTotalCustomer(cList.size());
                list.add(sketchCateModel);
            }
            return list;
        }
    private void sortPointByCenterPoint(CentroidCluster<DoublePointNew> cluster, List<JkSketchCustomer> cList) {
        double clat = Constants.formatBigdecimal(cList.get(0).getLatitude()).doubleValue();
        double clong = Constants.formatBigdecimal(cList.get(0).getLongitude()).doubleValue();
        if(cluster!=null || cluster.getCenter() != null || cluster.getCenter().getPoint() != null && cluster.getCenter().getPoint().length>=2){
            clong = cluster.getCenter().getPoint()[1];
            clat = cluster.getCenter().getPoint()[0];
        }
        for(JkSketchCustomer c : cList){
            double latDiff = Constants.formatBigdecimal(c.getLatitude()).doubleValue() - clat;
            double lonDiff = Constants.formatBigdecimal(c.getLongitude()).doubleValue() - clong;
            c.setDistanceCenter(Math.sqrt(latDiff * latDiff + lonDiff * lonDiff)); // 欧氏距离
        }
        Collections.sort(cList, (p1, p2) -> Double.compare(p1.getDistanceCenter(), p2.getDistanceCenter()));
    }
    public  class  DoublePointNew extends  DoublePoint{
server/visits/dmvisit_service/src/main/java/com/doumee/core/tsp/Clustering.java
@@ -40,12 +40,11 @@
        return  clusters;
    }
    public static double distanceTo(JkSketchCustomer self, JkSketchCustomer other) {
        // ====标记==忽略交通规划距离=====
        /*List<DistanceMapParam> distanceMapParamList  =JkSketchServiceImpl.getListFromJsonStr(self.getDistanceJson());
        List<DistanceMapParam> distanceMapParamList  =JkSketchServiceImpl.getListFromJsonStr(self.getDistanceJson());
        DistanceMapParam param = JkSketchServiceImpl.getParamByCustomerIds( other.getId(),distanceMapParamList);
        if(param!=null && param.getDistance()!=0){//如果之前已经获取过
          return (param.getDistance());
        }*/
        }
        return DistanceCalculator.calculateDistance(Constants.formatBigdecimal(self.getLatitude()).doubleValue()
                ,Constants.formatBigdecimal(self.getLongitude()).doubleValue()
                ,Constants.formatBigdecimal(other.getLatitude()).doubleValue()
server/visits/dmvisit_service/src/main/java/com/doumee/core/tsp/TspSolver.java
@@ -25,7 +25,7 @@
        data.initDataList();//构造数据
        long start =System.currentTimeMillis();
        System.out.println("=============start=========="+start);
       log.error("=============start=========="+start);
        //创建求解器manager对象,初始化求解器数据
        RoutingIndexManager manager =  new RoutingIndexManager(data.distanceMatrix.length, data.vehicleNumber, data.depot);
@@ -71,15 +71,15 @@
        // 打印路线
        printSolution(data, routing, manager, solution);
        long end =System.currentTimeMillis();
        System.out.println("=============end=========="+end);
       log.error("=============end=========="+end);
        System.out.println("=============耗时=========="+(end -start)+"(ms)"+(end -start)/1000 +"s"+(end -start)/60/1000 +"m");
       log.error("=============耗时=========="+(end -start)+"(ms)"+(end -start)/1000 +"s"+(end -start)/60/1000 +"m");
    */}
    public static void startSearch(DataModel data) {
        // 初始化数据模型
        Loader.loadNativeLibraries();
        long start =System.currentTimeMillis();
        System.out.println("=============start=========="+start);
       log.error("开始规划=============start=========="+start);
        //创建求解器manager对象,初始化求解器数据
        RoutingIndexManager manager =  new RoutingIndexManager(data.distanceMatrix.length, data.vehicleNumber, data.depot);
@@ -87,7 +87,7 @@
        RoutingModel routing = new RoutingModel(manager);
        // 注册回调函数
       /* final int transitCallbackIndex =
       final int transitCallbackIndex =
                routing.registerTransitCallback((long fromIndex, long toIndex) -> {
                    int fromNode = manager.indexToNode(fromIndex);
                    int toNode = manager.indexToNode(toIndex);
@@ -96,7 +96,7 @@
        // 定义回调函数至每条路线
        routing.setArcCostEvaluatorOfAllVehicles(transitCallbackIndex);
        routing.addDimension(transitCallbackIndex, 0, 30000000,
  /*      routing.addDimension(transitCallbackIndex, 0, 30000000,
                true,
                "Distance");
        RoutingDimension distanceDimension = routing.getMutableDimension("Distance");
@@ -104,7 +104,8 @@
        // 注册回调函数
        final int transitCallbackIndex1 =
                routing.registerTransitCallback((long fromIndex, long toIndex) -> {
                    return 1;
                    int fromNode = manager.indexToNode(fromIndex);
                    return data.customerDemands[fromNode];
                });
        for (int d = 0; d < data.vehicleMaxNodes.length; d++) {
            // 增加距离维度约束
@@ -121,20 +122,12 @@
        });
        routing.addDimensionWithVehicleCapacity(demandCallbackIndex, 0, data.vehicleCapacities, true, "Capacity");
/*
        // 添加容量限制
        final int demandCallbackIndex1 = routing.registerUnaryTransitCallback((long fromIndex) -> {
            return 1;
        });
        routing.addDimensionWithVehicleCapacity(demandCallbackIndex1, 0, data.vehicleMaxNodes, true, "Capacity");
*/
        Solver solver = routing.solver();
        //设置搜索方法(
        RoutingSearchParameters searchParameters =
                main.defaultRoutingSearchParameters()
                        .toBuilder()
//                        .setTimeLimit(Duration.newBuilder().setSeconds(60*60).build())//最久1小时
                        .setTimeLimit(Duration.newBuilder().setSeconds(60*60*6).build())//最久1小时
                        .setFirstSolutionStrategy(FirstSolutionStrategy.Value.PATH_CHEAPEST_ARC)
                        .build();
@@ -146,8 +139,7 @@
        // 打印路线
        resultSolution(data, routing, manager, solution);
        long end =System.currentTimeMillis();
        System.out.println("=============end=========="+end);
        System.out.println("=============耗时=========="+(end -start)+"(ms)"+(end -start)/1000 +"s"+(end -start)/60/1000 +"m");
       log.error("规划结束=============耗时=========="+(end -start)+"(ms)"+(end -start)/1000 +"s"+(end -start)/60/1000 +"m");
    }
    static void resultSolution( DataModel data, RoutingModel routing, RoutingIndexManager manager, Assignment solution) {
        long maxRouteDistance = 0;
@@ -223,6 +215,7 @@
        //每一个点的商品的数量
        public   long[] demands;
        public   long[] customerDemands;
        //车辆最大容载
        public   long[] vehicleCapacities ;
        public   long[] vehicleMaxNodes ;
@@ -236,17 +229,19 @@
           this.solutions = solutions;
       }
       public  void initDataInfo(int vehicleNumber1, long[] demands1, long[] vehicleCapacities1, long[][] distanceMatrix1,long[] vehicleMaxNodes){
       public  void initDataInfo(int vehicleNumber1, long[] demands1,long[] demands2, long[] vehicleCapacities1, long[][] distanceMatrix1,long[] vehicleMaxNodes){
            this.demands = demands1;
            this.customerDemands = demands2;
            this.vehicleNumber = vehicleNumber1;
            this.vehicleCapacities=vehicleCapacities1;
            this.distanceMatrix=distanceMatrix1;
            this.vehicleMaxNodes =vehicleMaxNodes;
        }
        public   void initDataList(){
            lenght = 20;
            lenght = 10;
            vehicleNumber = 5;
            demands = new long[lenght];
            customerDemands = new long[lenght];
            vehicleCapacities =new long[vehicleNumber];
            vehicleMaxNodes =new long[vehicleNumber];
            distanceMatrix =  new long[lenght][lenght];
@@ -254,15 +249,16 @@
            for (int i = 0; i <vehicleNumber ; i++) {
                long tem = (long) (Math.random() * 1000 + 20000);
                vehicleCapacities[i] = tem;
                vehicleMaxNodes[i] =5;
                vehicleMaxNodes[i] =50;
                total0+=tem;
                System.out.print(tem+" ,");
            }
            System.out.println( "\ntotal Capacity:"+total0+"=====================");
           log.error( "\ntotal Capacity:"+total0+"=====================");
            long total = 0;
            for (int i = 0; i <lenght ; i++) {
                long tem =  (int)(Math.random()*100+100);
                demands[i] =tem;
                customerDemands[i] =1;
                total+=tem;
                System.out.print(tem+" ,");
                for (int j = 0; j <lenght ; j++) {
@@ -276,7 +272,7 @@
                }
            }
            System.out.println( "\ntotal Demands:"+total+"=====================");
           log.error( "\ntotal Demands:"+total+"=====================");
        }
       /* public final long[][] distanceMatrix = {
                {0, 548, 776, 696, 582, 274, 502, 194, 308, 194, 536, 502, 388, 354, 468, 776, 662},
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/JkSketchServiceImpl.java
@@ -12,6 +12,7 @@
import com.doumee.core.wms.model.response.WmsBaseDataResponse;
import com.doumee.core.wms.model.response.WmsBaseResponse;
import com.doumee.dao.admin.request.JkOrdersImport;
import com.doumee.dao.admin.request.SketchCateModel;
import com.doumee.dao.business.*;
import com.doumee.dao.business.dto.TelecomLineInfoDTO;
import com.doumee.dao.business.model.*;
@@ -508,6 +509,69 @@
    @Async
    public void startUpdateLineAsync(JkSketch model) {
        try {
            int maxnum =100;
            try {
                maxnum = Integer.parseInt(systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.JK_PLAN_MAX_CLUSTER).getCode());
            }catch (Exception e){
            }
            List<JkSketchCustomer> allCustomerList = model.getCustomerList();
            //两公里内数据客户合并
//            List<SketchCateModel> customerList =Clustering.clusterPoints(allCustomerList,1000);
            List<SketchCateModel> customerList = new ClusterCustomKMeans().clusterPoints(allCustomerList,maxnum,500);
            List<JkLine> lineList = model.getLineList();
            TspSolver.DataModel dataModel = new TspSolver.DataModel();
            int vehicleNumber1 = lineList.size();//线路数量
            long[] vehicleCapacities1=new long[lineList.size()];//每辆车的最大订单量限制
            long[] vehicleMaxNodes=new long[lineList.size()];//每辆车的最大订单量限制
            long[] demands1 = new long[customerList.size()+1]; //各个点的订单量
            long[] demands2 = new long[customerList.size()+1]; //各个点的客戶量
            long[][] distanceMatrix1 = new long[customerList.size()+1][customerList.size()+1];
            distanceMatrix1[0][0] = 0;
            demands1[0] =0;//原点
            demands2[0] =0;//原点
            for (int i = 0; i < customerList.size(); i++) {
                List<DistanceMapParam>  disList =  customerList.get(i).getStartPoint().getDistanceMapParamList();
                distanceMatrix1[0][i+1] =  disList.get(0).getDistance();
                distanceMatrix1[i+1][0] = disList.get(disList.size() -1).getDistance();
                demands1[i+1] = Constants.formatBigdecimal( customerList.get(i).getTotalNum()).longValue();  //各个点的订单量
                demands2[i+1] = customerList.get(i).getTotalCustomer();  //各个点的订单量
                for (int j = 0; j < customerList.size(); j++) {
                    distanceMatrix1[i+1][j+1] =disList.get(j+1).getDistance() ;
                }
            }
            for (int i = 0; i < lineList.size(); i++) {
                vehicleCapacities1[i] = lineList.get(i).getMaxOrder();//每辆车的最大订单量限制
                vehicleMaxNodes[i] =lineList.get(i).getMaxCustomer();//最大客户数
            }
            //构造优化数据模型
            dataModel.initDataInfo(vehicleNumber1,demands1,demands2,vehicleCapacities1,distanceMatrix1,vehicleMaxNodes);
            TspSolver.startSearch(dataModel);
            dealSearchSolution(model,  customerList,dataModel);
        }catch (Exception e){
            e.printStackTrace();
            jkSketchMapper.update(null,new UpdateWrapper<JkSketch>().lambda()
                    .eq(JkSketch::getId,model.getId() )
                    .eq(JkSketch::getJobId,model.getJobId() )
                    .set(JkSketch::getPlanLineInfo,"最近一次线路优化失败!")
                    .set(JkSketch::getStatus,Constants.THREE)
                    .set(JkSketch::getPlanLineEndDate,new Date()));
        }
    }
    private List<JkSketchCustomer> getCustomerCateList(List<JkSketchCustomer> allCustomerList) {
        List<JkSketchCustomer>  list = new ArrayList<>();
        return  list;
    }
    /**
     * 开始异步执行线路优化任务
     * @param model
     */
    @Override
    @Async
    public void startUpdateLineAsyncOld(JkSketch model) {
        try {
            List<JkSketchCustomer> customerList = model.getCustomerList();
            List<JkLine> lineList = model.getLineList();
            TspSolver.DataModel dataModel = new TspSolver.DataModel();
@@ -515,6 +579,7 @@
            long[] vehicleCapacities1=new long[lineList.size()];//每辆车的最大订单量限制
            long[] vehicleMaxNodes=new long[lineList.size()];//每辆车的最大订单量限制
            long[] demands1 = new long[customerList.size()+1]; //各个点的订单量
            long[] demands2 = new long[customerList.size()+1]; //各个点的客户量
            long[][] distanceMatrix1 = new long[customerList.size()+1][customerList.size()+1];
            distanceMatrix1[0][0] = 0;
            demands1[0] =0;//原点
@@ -523,6 +588,7 @@
                distanceMatrix1[0][i+1] =  disList.get(0).getDistance();
                distanceMatrix1[i+1][0] = disList.get(disList.size() -1).getDistance();
                demands1[i+1] = Constants.formatBigdecimal( customerList.get(i).getTotalNum()).longValue();  //各个点的订单量
                demands2[i+1] =1;  //各个点的订单量
                for (int j = 0; j < customerList.size(); j++) {
                    distanceMatrix1[i+1][j+1] =disList.get(j+1).getDistance() ;
                }
@@ -542,9 +608,9 @@
                vehicleMaxNodes[i] =lineList.get(i).getMaxCustomer();//最大客户数
            }
            //构造优化数据模型
            dataModel.initDataInfo(vehicleNumber1,demands1,vehicleCapacities1,distanceMatrix1,vehicleMaxNodes);
            dataModel.initDataInfo(vehicleNumber1,demands1,demands2,vehicleCapacities1,distanceMatrix1,vehicleMaxNodes);
            TspSolver.startSearch(dataModel);
            dealSearchSolution(model,dataModel);
            dealSearchSolutionOld(model,dataModel);
        }catch (Exception e){
            e.printStackTrace();
            jkSketchMapper.update(null,new UpdateWrapper<JkSketch>().lambda()
@@ -563,6 +629,126 @@
    @Override
    @Async
    public  void startEditSketchLineAsync(JkSketch model) {
        boolean success = true;
        int totalDistance = 0;
        List<JkSketchLine> lineList = model.getSketchLineList();
        try {
            MPJLambdaWrapper<JkSketchCustomer> queryWrapper = new MPJLambdaWrapper<>();
            queryWrapper.selectAll(JkSketchCustomer.class )
                    .selectAs(JkCustomer::getName,JkSketchCustomer::getName)
                    .selectAs(JkCustomer::getCode,JkSketchCustomer::getCode)
                    .selectAs(JkCustomer::getDistance,JkSketchCustomer::getDistanceJson)
                    .selectAs(JkCustomer::getLongitude,JkSketchCustomer::getLongitude)
                    .selectAs(JkCustomer::getLatitude,JkSketchCustomer::getLatitude)
                    .selectAs(JkCustomer::getStartDistance,JkSketchCustomer::getStartDistance)
                    .selectAs(JkCustomer::getEndDistance,JkSketchCustomer::getEndDistance)
                    .leftJoin(JkCustomer.class,JkCustomer::getId,JkSketchCustomer::getCustomerId )
                    .eq(JkSketchCustomer::getType, Constants.equalsInteger(model.getOptStatus(),Constants.ONE)?1:0)
                    .eq(JkSketchCustomer::getSketchId, model.getId())
                    .eq(JkSketchCustomer::getIsdeleted,Constants.ZERO)
                    .orderByAsc(JkSketchCustomer::getSortnum);
            List<JkSketchCustomer> customerList = jkSketchCustomerMapper.selectJoinList(JkSketchCustomer.class,queryWrapper);
            if(customerList == null ||customerList.size() ==0){
                throw  new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"该线路客户信息为空,不满足优化条件!");
            }
            int maxnum =100;
            try {
                maxnum = Integer.parseInt(systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.JK_PLAN_MAX_CLUSTER).getCode());
            }catch (Exception e){
            }
            int totalNum = 0;
            for(JkSketchLine line : lineList){
                //完善线路客户优化参数
                List<JkSketchCustomer> customerListParam =  line.getCustomerList() ;
                if(customerListParam ==null || customerListParam.size()==0){
                    throw  new BusinessException(ResponseStatus.BAD_REQUEST);
                }
                initSketchCustomerListParam(line.getCustomerList(),customerList) ;
                totalNum += customerListParam.size();
            }
            if(totalNum != Constants.formatIntegerNum(model.getOrderNum())){
                throw  new BusinessException(ResponseStatus.BAD_REQUEST);
            }
            for(JkSketchLine line : lineList){
                //逐个路线优化
                List<JkSketchCustomer> allCustomerListParam =  line.getCustomerList() ;
//                List<SketchCateModel> customerListParam = Clustering.clusterPoints(allCustomerListParam,1000);
                List<SketchCateModel> customerListParam = new ClusterCustomKMeans().clusterPoints(allCustomerListParam,maxnum,500);
                TspSolver.DataModel dataModel = new TspSolver.DataModel();
                int vehicleNumber1 = 1;//线路数量
                long[] vehicleCapacities1=new long[]{line.getMaxOrder()};//每辆车的最大订单量限制
                long[] vehicleMaxNodes=new long[]{line.getMaxCustomer()};//每辆车的最大订单量限制
                long[] demands1 = new long[customerListParam.size()+1]; //各个点的订单量
                long[] demands2 = new long[customerListParam.size()+1]; //各个点的订单量
                long[][] distanceMatrix1 = new long[customerListParam.size()+1][customerListParam.size()+1];
                distanceMatrix1[0][0] = 0;
                demands1[0] =0;//原点
                for (int i = 0; i < customerListParam.size(); i++) {
                    List<DistanceMapParam>  disList =  customerListParam.get(i).getStartPoint().getDistanceMapParamList();
                    distanceMatrix1[0][i+1] =  disList.get(0).getDistance();
                    distanceMatrix1[i+1][0] = disList.get(disList.size() -1).getDistance();
                    demands1[i+1] = Constants.formatBigdecimal( customerListParam.get(i).getTotalNum()).longValue();  //各个点的订单量
                    demands2[i+1] =   customerListParam.get(i).getTotalCustomer() ;  //各个点的订单量
                    for (int j = 0; j < customerListParam.size(); j++) {
                        distanceMatrix1[i+1][j+1] =disList.get(j+1).getDistance() ;
                    }
                }
                //构造优化数据模型
                dataModel.initDataInfo(vehicleNumber1,demands1,demands2,vehicleCapacities1,distanceMatrix1,vehicleMaxNodes);
                TspSolver.startSearch(dataModel);
                if(dataModel.getSolutions()==null || dataModel.getSolutions().size()==0){
                    throw  new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"线路【"+line.getLineName()+"】调整失败 ,未获得最优交通规划方案!");
                }
                TspSolverSolutions so = dataModel.getSolutions().get(0);
                List<Integer> routes = so.getRouteIndex();
                totalDistance += so.getDistance();
                if(routes.size() <=2) {
                    throw  new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"线路【"+line.getLineName()+"】调整失败 ,未获得最优交通规划方案!");
                }
                int index = 0;
                line.setDistance(so.getDistance());
                //有效路径
                for (Integer cIndex : routes){
                    if(cIndex ==0){
                        continue; //起始点不处理
                    }
                    SketchCateModel cateModel = customerListParam.get(cIndex-1);
                    for(int t=0;t<cateModel.getCustomerList().size();t++){
                        JkSketchCustomer customer = cateModel.getCustomerList().get(t);
                        customer.setSortnum(index++);
                        if(t < cateModel.getCustomerList().size()-1){
                            long tdistance = (long)Clustering.distanceTo(customer, cateModel.getCustomerList().get(t+1));
                            line.setDistance(Constants.formatLongNum(line.getDistance()) +tdistance);
                            totalDistance  += tdistance;
                        }
                    }
                }
            }
        }catch (Exception e){
            e.printStackTrace();
            success =false;
        }finally {
            if(success){
                List<JkSketchCustomer> allList = new ArrayList<>();
                for(JkSketchLine line : lineList){
                    allList.addAll(line.getCustomerList());
                }
                jkSketchLineMapper.updateById(lineList);
                jkSketchCustomerMapper.updateById(allList);
            }
            jkSketchMapper.update(null,new UpdateWrapper<JkSketch>().lambda()
//                    .eq(JkSketch::getId,model.getId() )
                    .eq(JkSketch::getJobId,model.getJobId() )
                    .set(success,JkSketch::getDistance,totalDistance)
                    .set(JkSketch::getPlanLineInfo,success?"最近一次线路调整成功":"最近一次线路调整失败!")
                    .set(JkSketch::getStatus,success?Constants.TWO:Constants.THREE)
                    .set(JkSketch::getPlanLineEndDate,new Date()));
        }
    }
    @Override
    @Async
    public  void startEditSketchLineAsyncOld(JkSketch model) {
        boolean success = true;
        int totalDistance = 0;
        List<JkSketchLine> lineList = model.getSketchLineList();
@@ -607,6 +793,7 @@
                long[] vehicleCapacities1=new long[]{line.getMaxOrder()};//每辆车的最大订单量限制
                long[] vehicleMaxNodes=new long[]{line.getMaxCustomer()};//每辆车的最大订单量限制
                long[] demands1 = new long[customerListParam.size()+1]; //各个点的订单量
                long[] demands2 = new long[customerListParam.size()+1]; //各个点的订单量
                long[][] distanceMatrix1 = new long[customerListParam.size()+1][customerListParam.size()+1];
                distanceMatrix1[0][0] = 0;
                demands1[0] =0;//原点
@@ -615,12 +802,13 @@
                    distanceMatrix1[0][i+1] =  disList.get(0).getDistance();
                    distanceMatrix1[i+1][0] = disList.get(disList.size() -1).getDistance();
                    demands1[i+1] = Constants.formatBigdecimal( customerListParam.get(i).getTotalNum()).longValue();  //各个点的订单量
                    demands2[i+1] = 1;  //各个点的订单量
                    for (int j = 0; j < customerListParam.size(); j++) {
                        distanceMatrix1[i+1][j+1] =disList.get(j+1).getDistance() ;
                    }
                }
                //构造优化数据模型
                dataModel.initDataInfo(vehicleNumber1,demands1,vehicleCapacities1,distanceMatrix1,vehicleMaxNodes);
                dataModel.initDataInfo(vehicleNumber1,demands1,demands2,vehicleCapacities1,distanceMatrix1,vehicleMaxNodes);
                TspSolver.startSearch(dataModel);
                if(dataModel.getSolutions()==null || dataModel.getSolutions().size()==0){
                    throw  new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"线路【"+line.getLineName()+"】调整失败 ,未获得最优交通规划方案!");
@@ -828,7 +1016,114 @@
        return new ArrayList<>();
    }
    private void dealSearchSolution(JkSketch model, TspSolver.DataModel dataModel) {
    private void dealSearchSolution(JkSketch model, List<SketchCateModel> customerList,TspSolver.DataModel dataModel) {
        Date date = new Date();
        List<TspSolverSolutions> solutions = dataModel.getSolutions();
        List<JkSketchLine> sketchLineList = new ArrayList<>();
        List<JkSketchCustomer> sketchCustomerList  = new ArrayList<>();
        long totalDistance = 0l;
        if(solutions!=null && solutions.size()>0){
            for(TspSolverSolutions so : solutions){
                List<Integer> routes = so.getRouteIndex();
                totalDistance+= so.getDistance();
                if(routes.size() <=2) {
                    continue;//无客户的非有效路线
                }
                JkLine  line =model.getLineList().get(so.getLineIndex());
                JkSketchLine tModel =  new JkSketchLine();
                tModel.setSketchId(model.getId());
                tModel.setCreator(model.getEditor());
                tModel.setCreateDate(date);
                tModel.setLineId(line.getId());
                tModel.setTotalNum(new BigDecimal(0));
                tModel.setDateInfo(model.getDateInfo());
                tModel.setType(Constants.ONE);
                tModel.setSortnum(sketchLineList.size()+1);
                tModel.setEditDate(tModel.getCreateDate());
                tModel.setEditor(tModel.getCreator());
                tModel.setIsdeleted(Constants.ZERO);
                tModel.setDistance(so.getDistance());//
                sketchLineList.add(tModel);
                tModel.setCustomerList( new ArrayList<>());
                //有效路径
                for (Integer cIndex : routes){
                    if(cIndex ==0){
                        continue; //起始点不处理
                    }
//                    JkSketchCustomer customer = model.getCustomerList().get(cIndex-1);
//                    tModel.setTotalNum(tModel.getTotalNum().add(Constants.formatBigdecimal(customer.getTotalNum())));//送货量
                    SketchCateModel cateModel = customerList.get(cIndex-1);
                    tModel.setTotalNum(tModel.getTotalNum().add(Constants.formatBigdecimal(cateModel.getTotalNum())));//送货量
                    for(int t=0;t<cateModel.getCustomerList().size();t++){
                        JkSketchCustomer customer = cateModel.getCustomerList().get(t);
                        JkSketchCustomer cModel =  new JkSketchCustomer();
                        cModel.setCreator(tModel.getCreator());
                        cModel.setOrderId(customer.getOrderId());
                        cModel.setCreateDate(tModel.getCreateDate());
                        cModel.setType(Constants.ONE);
                        cModel.setTotalNum(customer.getTotalNum());
                        cModel.setDateInfo(model.getDateInfo());
                        cModel.setSortnum(tModel.getCustomerList().size()+1);
                        cModel.setEditDate(tModel.getCreateDate());
                        cModel.setEditor(tModel.getCreator());
                        cModel.setIsdeleted(Constants.ZERO);
                        cModel.setSketchId(model.getId());
                        cModel.setCustomerId(customer.getCustomerId());
                        if(t < cateModel.getCustomerList().size()-1){
                            long tdistance = (long)Clustering.distanceTo(customer, cateModel.getCustomerList().get(t+1));
                            tModel.setDistance(Constants.formatLongNum(tModel.getDistance()) +tdistance);
                            totalDistance  += tdistance;
                        }
                        tModel.getCustomerList().add(cModel);
                    }
                    tModel.setOrderNum( tModel.getCustomerList().size());
                }
            }
        }
        if(sketchLineList!=null && sketchLineList.size()>0){
            jkSketchLineMapper.update(null,new UpdateWrapper<JkSketchLine>().lambda()
                    .set(JkSketchLine::getIsdeleted,Constants.ONE)
                    .eq(JkSketchLine::getIsdeleted,Constants.ZERO)
                    .eq(JkSketchLine::getType,Constants.ONE)
                    .eq(JkSketchLine::getDateInfo,model.getDateInfo()));
            jkSketchCustomerMapper.update(null,new UpdateWrapper<JkSketchCustomer>().lambda()
                    .set(JkSketchCustomer::getIsdeleted,Constants.ONE)
                    .eq(JkSketchCustomer::getIsdeleted,Constants.ZERO)
                    .eq(JkSketchCustomer::getType,Constants.ONE)
                    .eq(JkSketchCustomer::getDateInfo,model.getDateInfo()));
            if(sketchLineList.size()>0){
                jkSketchLineMapper.insert(sketchLineList);
            }
            for(JkSketchLine l : sketchLineList){
                if(l.getCustomerList()!=null ){
                    for(JkSketchCustomer c :l.getCustomerList()){
                        c.setSketchLineId(l.getId());
                    }
                    sketchCustomerList.addAll(l.getCustomerList());
                }
            }
            if(sketchCustomerList.size()>0){
                jkSketchCustomerMapper.insert(sketchCustomerList);
            }
            jkSketchMapper.update(null,new UpdateWrapper<JkSketch>().lambda()
                    .eq(JkSketch::getId,model.getId() )
                    .eq(JkSketch::getJobId,model.getJobId() )
                    .set(JkSketch::getLineNum,sketchLineList.size() )
                    .set(JkSketch::getOptStatus,Constants.ONE)//已生成优化线路
                    .set(JkSketch::getDistance,totalDistance)
                    .set(JkSketch::getPlanLineInfo,"最近一次线路优化成功,优化后总距离:"+(totalDistance/1000)+"公里!")
                    .set(JkSketch::getStatus,Constants.TWO)
                    .set(JkSketch::getPlanLineEndDate,date));
        }else{
            jkSketchMapper.update(null,new UpdateWrapper<JkSketch>().lambda()
                    .eq(JkSketch::getId,model.getId() )
                    .eq(JkSketch::getJobId,model.getJobId() )
                    .set(JkSketch::getPlanLineInfo,"最近一次线路优化失败,未找到最优路线!")
                    .set(JkSketch::getStatus,Constants.THREE)
                    .set(JkSketch::getPlanLineEndDate,date));
        }
    }
    private void dealSearchSolutionOld(JkSketch model, TspSolver.DataModel dataModel) {
        Date date = new Date();
        List<TspSolverSolutions> solutions = dataModel.getSolutions();
        List<JkSketchLine> sketchLineList = new ArrayList<>();