admin/.env.development
@@ -2,7 +2,7 @@ NODE_ENV = 'development' # VUE_APP_API_URL = 'https://atwl.ahzyssl.com/zhyq_interface' VUE_APP_API_URL = 'http://192.168.1.54:10010' VUE_APP_API_URL = 'http://localhost:10010' # VUE_APP_API_URL = 'https://atwl.ahzyssl.com/zhyq_interface' # VUE_APP_API_URL = 'http://10.50.250.253:8088/gateway_interface' admin/src/assets/style/lib.css
@@ -97,8 +97,8 @@ .cY{ display: flex; align-items: center;} .cX{display: flex; justify-content: center} .rowW{ display: flex; flex-wrap: wrap;} .bX{ display: flex; flex-direction: row; justify-content: space-between;} .bY{ display: flex; flex-direction:column; justify-content: space-between;} .bX{ display: flex; flex-direction: row; justify-content: space-between;} .bY{ display: flex; flex-direction:column; justify-content: space-between;} .bcX{ display: flex; justify-content: space-between; align-items: center;} .fx1{ flex: 1; overflow: hidden; } @@ -112,6 +112,7 @@ .green{ color: #65C35D;} .blue{ color: #3C77DA;} .red{ color: #f00;} .grey{ color: #666666;} /* /deep/ .uicon-close .u-icon--right{ position: absolute; right: 30px; top: 30px; z-index: 999;} */ .popCloseBtn{ position: absolute; width:50px; height:50px; right: 20px; top: 20px;} .fixedHeader{ position: absolute; left: 0; top: 0;} admin/src/views/business/jkSketch.vue
@@ -52,7 +52,7 @@ <span v-if="row.status === 0" class="blue">未优化</span> <span v-if="row.status === 1" class="red">优化中 【 {{row.planLineNum||0}} 】条线路</span> <span v-if="row.status === 2" class="green">已优化</span> <span v-if="row.status === 3" class="green">优化失败</span> <span v-if="row.status === 3" class="grey">优化失败</span> </template> </el-table-column> <el-table-column server/system_service/src/main/java/com/doumee/core/utils/Constants.java
@@ -38,6 +38,7 @@ public static final String HK_HTTPS ="HK_HTTPS" ; public static final String HK_PUSH_URL = "HK_PUSH_URL"; public static final String HK_CARS_OPENAPI_ACCESS_KEY = "HK_CARS_OPENAPI_ACCESS_KEY"; public static final String GAODE_DISTANCE_GEOAPI_URL = "GAODE_DISTANCE_GEOAPI_URL"; public static final String HK_CARS_OPENAPI_ACCESS_SECRET = "HK_CARS_OPENAPI_ACCESS_SECRET"; public static final String HK_CARS_OPENAPI_URL = "HK_CARS_OPENAPI_URL"; public static final String HK_ROOTORG_CODE ="HK_ROOTORG_CODE" ; server/visits/dmvisit_service/src/main/java/com/doumee/core/tsp/DistanceCalculator.java
@@ -30,6 +30,7 @@ r.setStart(c1); r.setEnd(c2); r.setDistance(0); r.setCode(0); r.setLocations( new ArrayList<>()); try { String url =urlStr.replace("${lat1}", Constants.formatBigdecimalScale(c1.getLatitude(),6)+"") @@ -47,7 +48,7 @@ JSONArray array = json.getJSONObject("route").getJSONArray("paths"); JSONObject model = array.getJSONObject(0);//取第一个 Long distance = Long.parseLong(model.getString("distance")); r.setDistance(distance*1000); r.setDistance(distance); JSONArray steps = model.getJSONArray("steps"); String tl = ""; if(steps!=null && steps.size()>0){ @@ -61,9 +62,12 @@ tl+= steps.getJSONObject(i).getString("polyline" ); } } r.setPolyline(tl); r.setLocations(Arrays.asList(tl.split(";"))); r.setCode(1); log.error("获取交通规划线路信息成功=============="); }else{ log.error("获取交通规划线路信息成功=============="); log.error("获取交通规划线路信息成功=====失败!!========="); } }catch (Exception e){ log.error("获取交通规划线路信息成功=====失败=========="); server/visits/dmvisit_service/src/main/java/com/doumee/core/tsp/DistanceModel.java
@@ -12,8 +12,10 @@ public class DistanceModel { private long distance; private List<String> locations; private String polyline; private JkSketchCustomer start; private JkSketchCustomer end; private int code;//0失败 1成功 server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/JkCustomerNavigationMapper.java
@@ -2,11 +2,12 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.doumee.dao.business.model.JkCustomerNavigation; import com.github.yulichang.base.MPJBaseMapper; /** * @author 江蹄蹄 * @date 2025/10/13 15:48 */ public interface JkCustomerNavigationMapper extends BaseMapper<JkCustomerNavigation> { public interface JkCustomerNavigationMapper extends MPJBaseMapper<JkCustomerNavigation> { } server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/Category.java
@@ -95,6 +95,15 @@ @ApiModelProperty(value = "完整图片地址 ") @TableField(exist = false) private String imgurlFull; @ApiModelProperty(value = "线路数 ") @TableField(exist = false) private int lineNum; @ApiModelProperty(value = "完成线路计算客户数 ") @TableField(exist = false) private int customerDoneNum; @ApiModelProperty(value = "客户数 ") @TableField(exist = false) private int customerNum; @ApiModelProperty(value = "子集分类") @TableField(exist = false) server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/JkCustomer.java
@@ -89,9 +89,24 @@ @ApiModelProperty(value = "状态 0正常 禁用", example = "1") //@ExcelColumn(name="状态 0正常 禁用") private Integer status; @ApiModelProperty(value = "距离计算状态 0未计算 1已计算", example = "1") //@ExcelColumn(name="状态 0正常 禁用") private Integer distanceStatus; @ApiModelProperty(value = "客户间距离集合", example = "1") //@ExcelColumn(name="状态 0正常 禁用") private String distance; @ApiModelProperty(value = "园区距离该客户的距离(米)", example = "1") //@ExcelColumn(name="状态 0正常 禁用") private Long startDistance; @ApiModelProperty(value = "该客户返回园区的距离(米)", example = "1") //@ExcelColumn(name="状态 0正常 禁用") private Long endDistance; @ApiModelProperty(value = "园区距离该客户的路径经纬度集合,分号隔开", example = "1") //@ExcelColumn(name="状态 0正常 禁用") private String startSteps; @ApiModelProperty(value = "该客户返回园区的路径经纬度集合,分号隔开", example = "1") //@ExcelColumn(name="状态 0正常 禁用") private String endSteps; @ApiModelProperty(value = "排序码", example = "1") //@ExcelColumn(name="排序码") server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/JkCustomerNavigation.java
@@ -54,11 +54,11 @@ @ApiModelProperty(value = "起始客户编码(起点位-1)", example = "1") @ExcelColumn(name="起始客户编码(起点位-1)") private Long startId; private Integer startId; @ApiModelProperty(value = "终端客户编码(起点位-1)", example = "1") @ExcelColumn(name="终端客户编码(起点位-1)") private Long endId; private Integer endId; @ApiModelProperty(value = "距离(米)", example = "1") @ExcelColumn(name="距离(米)") server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/JkSketchCustomer.java
@@ -119,9 +119,26 @@ //@ExcelColumn(name="维度") @TableField(exist = false) private BigDecimal latitude; @ApiModelProperty(value = "线路名称", example = "1") @ApiModelProperty(value = "线路距离", example = "1") @TableField(exist = false) private String distanceJson; @ApiModelProperty(value = "园区距离该客户的距离(米)", example = "1") //@ExcelColumn(name="状态 0正常 禁用") @TableField(exist = false) private Long startDistance; @ApiModelProperty(value = "该客户返回园区的距离(米)", example = "1") @TableField(exist = false) //@ExcelColumn(name="状态 0正常 禁用") private Long endDistance; @ApiModelProperty(value = "园区距离该客户的路径经纬度集合,分号隔开", example = "1") //@ExcelColumn(name="状态 0正常 禁用") @TableField(exist = false) private String startSteps; @ApiModelProperty(value = "该客户返回园区的路径经纬度集合,分号隔开", example = "1") //@ExcelColumn(name="状态 0正常 禁用") @TableField(exist = false) private String endSteps; @ApiModelProperty(value = "同班组间客户位置距离数组,[{a:12,b:100},{a:13,b:200},...],a:客户编码,b:与客户a之间的距离") @TableField(exist = false) private List<Map<String,Object>> distanceList; server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/CategoryServiceImpl.java
@@ -15,6 +15,8 @@ import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.github.yulichang.query.MPJQueryWrapper; import com.github.yulichang.wrapper.MPJLambdaWrapper; import org.apache.commons.lang3.StringUtils; import org.apache.shiro.SecurityUtils; import org.checkerframework.checker.units.qual.C; @@ -156,12 +158,18 @@ @Override public PageData<Category> findPage(PageWrap<Category> pageWrap) { IPage<Category> page = new Page<>(pageWrap.getPage(), pageWrap.getCapacity()); QueryWrapper<Category> queryWrapper = new QueryWrapper<>(); MPJLambdaWrapper<Category> queryWrapper = new MPJLambdaWrapper<>(); Utils.MP.blankToNull(pageWrap.getModel()); String prefixUrl = systemDictDataBiz.queryByCode(Constants.FTP,Constants.FTP_RESOURCE_PATH).getCode() + systemDictDataBiz.queryByCode(Constants.FTP,Constants.BANNER_IMG).getCode(); queryWrapper.lambda().eq(Category::getIsdeleted,Constants.ZERO) queryWrapper.selectAll(Category.class ); if(Constants.equalsInteger(pageWrap.getModel().getType(),Constants.FOUR)){ //如果是主线路,查询线路数和客户数 queryWrapper.select( "(select count(1) from jk_line b where b.isdeleted=0 and b.CATEGORY_ID = t.id)",Category::getLineNum); queryWrapper.select( "(select count(1) from jk_customer b left join jk_line c on b.line_id=c.id where c.isdeleted=0 and b.isdeleted=0 and c.CATEGORY_ID = t.id)",Category::getCustomerNum); queryWrapper.select( "(select count(1) from jk_customer b left join jk_line c on b.line_id=c.id where c.isdeleted=0 and b.isdeleted=0 and c.CATEGORY_ID = t.id b.DISTANCE_STATUS = 1)",Category::getCustomerDoneNum); } queryWrapper.eq(Category::getIsdeleted,Constants.ZERO) .eq(Objects.nonNull(pageWrap.getModel().getType()),Category::getType,pageWrap.getModel().getType()) .like(StringUtils.isNotBlank(pageWrap.getModel().getName()),Category::getName,pageWrap.getModel().getName()) .isNull(Category::getParentId) server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/JkCustomerServiceImpl.java
@@ -390,6 +390,8 @@ tModel.setCreator(loginUserInfo.getId()); tModel.setCreateDate(new Date()); tModel.setIsnew(Constants.ONE); tModel.setStatus(Constants.ZERO); tModel.setDistanceStatus(Constants.ZERO); newList.add(tModel); }else{ tModel.setIsnew(Constants.ZERO); server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/JkSketchServiceImpl.java
@@ -54,6 +54,8 @@ @Autowired private JkCustomerMapper jkCustomerMapper; @Autowired private JkCustomerNavigationMapper jkCustomerNavigationMapper; @Autowired private JkLineMapper jkLineMapper; @Autowired @@ -98,11 +100,11 @@ if( model.getDateInfo() == null){ throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"该线路日期信息不正确,不支持优化!"); } if(Constants.equalsInteger(Constants.ZERO,jkSketch.getForceUpdate()) && Constants.equalsInteger(model.getStatus(),Constants.ONE)){ if(Constants.equalsInteger(Constants.ZERO,jkSketch.getForceUpdate()) && Constants.equalsInteger(model.getStatus(),Constants.ONE)){ throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"该线路存在正在优化中,请耐心等待优化完成或者选择强制优化操作!"); } if( jkSketch.getLineIdList() ==null || jkSketch.getLineIdList().size()==0 ){ if( jkSketch.getLineIdList() ==null || jkSketch.getLineIdList().size()==0 ){ throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(),"请选择有效合理的线路进行优化操作!"); } //当前所有线路(符合条件的线路) @@ -117,7 +119,6 @@ totalCus += Constants.formatIntegerNum(line.getMaxCustomer());//总客户量 totalNum += Constants.formatIntegerNum(line.getMaxOrder());//总送货量 } if( totalCus < Constants.formatIntegerNum(model.getOrderNum()) ){ throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(),"该线路订单客户数量超过了线路总客户量限制,无法进行优化!"); } @@ -151,25 +152,17 @@ long[] demands1 = new long[customerList.size()+1]; //各个点的订单量 long[][] distanceMatrix1 = new long[customerList.size()+1][customerList.size()+1]; demands1[0] =0;//原点 double cLatitude =0; double cLongitude =0; String location = systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.COMPANY_LOCATION).getCode(); try { String[] ss = location.split(","); cLongitude = Double.parseDouble(ss[0]); cLatitude = Double.parseDouble(ss[1]); }catch (Exception e){ } for (int i = 0; i < customerList.size(); i++) { distanceMatrix1[0][i] = DistanceCalculator.calculateDistance(cLatitude,cLongitude,customerList.get(i).getLatitude().doubleValue(),customerList.get(i).getLongitude().doubleValue())/1000; distanceMatrix1[i][0] = distanceMatrix1[0][i]; List<DistanceMapParam> disList = customerList.get(i).getDistanceMapParamList(); distanceMatrix1[0][i] = disList.get(0).getDistance(); distanceMatrix1[i][0] = disList.get(disList.size() -1).getDistance(); demands1[i+1] = Constants.formatBigdecimal( customerList.get(i).getTotalNum()).longValue(); //各个点的订单量 List<Map<String,Object>> disList = customerList.get(i).getDistanceList(); for (int j = 0; j< disList.size(); j++) { if(disList.size()>j){ distanceMatrix1[i+1][j+1] = (Long) disList.get(j).get("b")/1000;//构造距离矩阵 for (int j = 0; j< disList.size()-2; j++) { if(j+1 >=10){ break; } if(disList.size()>j+1){ distanceMatrix1[i+1][j+1] = disList.get(j+1).getDistance()/1000;//构造距离矩阵 }else{ distanceMatrix1[i+1][j+1] = 1l; } @@ -195,20 +188,65 @@ } private void initCustomerDistance(JkSketch model) { String url = systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.GAODE_LOCATION_GEOAPI_URL).getCode(); String url = systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.GAODE_DISTANCE_GEOAPI_URL).getCode(); List<JkCustomer> updateCustomerList = new ArrayList<>(); List<JkCustomerNavigation> navigationList = new ArrayList<>(); List<JkSketchCustomer> customerList = model.getCustomerList(); Date date = new Date(); BigDecimal cLatitude =new BigDecimal(0); BigDecimal cLongitude =new BigDecimal(0); String location = systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.COMPANY_LOCATION).getCode(); try { String[] ss = location.split(","); cLongitude = new BigDecimal(ss[0]); cLatitude = new BigDecimal(ss[1]); }catch (Exception e){ } for(JkSketchCustomer c : customerList){ List<DistanceMapParam> tmpList = new ArrayList<>(); List<DistanceMapParam> distanceMapParamList = getListFromJsonStr(c.getDistanceJson()); boolean isNew = false; JkCustomer u =new JkCustomer(); DistanceMapParam t0 = new DistanceMapParam(); t0.setId(-2);//表示返回园区 t0.setDistance(Constants.formatLongNum(c.getStartDistance()) ); if(Constants.formatLongNum(c.getStartDistance()) <= 0){ //园区前往该客户的距离,如果之前未获取过 isNew = true; JkSketchCustomer start = new JkSketchCustomer(); start.setId(-1); start.setLongitude(cLongitude); start.setLatitude(cLatitude); DistanceModel dm = DistanceCalculator.calculateDistanceGaode(url,start,c); c.setStartDistance(dm.getDistance() ); t0.setDistance(dm.getDistance()); u.setStartDistance(dm.getDistance()); if(dm.getLocations().size()>0){ //如果有路径信息 u.setStartSteps(dm.getPolyline()); } } tmpList.add(t0); for(JkSketchCustomer cm : customerList){ boolean isNew = false; //客户和客户之间的距离信息 DistanceMapParam t = new DistanceMapParam(); t.setId(cm.getId()); DistanceMapParam param = getParamByCustomerIds( cm.getId(),distanceMapParamList); if(param!=null){//如果之前已经获取过 t = param; }else{ JkCustomerNavigation navigation = new JkCustomerNavigation(); navigation.setStartId(c.getId()); navigation.setEndId(cm.getId()); navigation.setIsdeleted(Constants.ZERO); navigation.setCreateDate(date); navigation.setEditDate(date); navigation.setEndLatitude(cm.getLatitude()); navigation.setEndLogitude(cm.getLongitude()); navigation.setStartLatitude(c.getLatitude()); navigation.setStartLogitude(c.getLongitude()); isNew = true; if(Constants.equalsInteger(c.getCustomerId(),cm.getCustomerId())){ t.setDistance(0l); @@ -217,16 +255,40 @@ t.setDistance(dm.getDistance() ); if(dm.getLocations().size()>0){ //如果有路径信息 navigation.setSteps(dm.getPolyline()); } } navigation.setIdIndex(c.getId()+"-"+cm.getId()); navigation.setDistance(t.getDistance()); navigationList.add(navigation); } tmpList.add(t); if(isNew){// JkCustomer u =new JkCustomer(); u.setId(c.getId()); u.setDistance(JSONObject.toJSONString(tmpList)); } DistanceMapParam tt = new DistanceMapParam(); tt.setId(-2);//表示返回园区 tt.setDistance(Constants.formatLongNum(c.getEndDistance())); if(Constants.formatLongNum(c.getEndDistance()) <= 0){ //该客户返回园区的距离 ,如果之前未获取过 isNew = true; JkSketchCustomer start = new JkSketchCustomer(); start.setId(-1); start.setLongitude(cLongitude); start.setLatitude(cLatitude); DistanceModel dm = DistanceCalculator.calculateDistanceGaode(url,c,start); c.setEndDistance(dm.getDistance() ); tt.setDistance(dm.getDistance()); u.setEndDistance(dm.getDistance()); if(dm.getLocations().size()>0){ //如果有路径信息 u.setEndSteps(dm.getPolyline()); } } tmpList.add(tt); if(isNew){// u.setId(c.getCustomerId()); u.setDistance(JSONObject.toJSONString(tmpList)); updateCustomerList.add(u); } c.setDistanceMapParamList(tmpList); } @@ -234,6 +296,9 @@ for(JkCustomer c : updateCustomerList){ jkCustomerMapper.updateById(c);//更新客户与其他点之间的距离 } } if(navigationList.size()>0){ jkCustomerNavigationMapper.insert(navigationList); } } @@ -288,7 +353,7 @@ tModel.setCustomerList( new ArrayList<>()); //有效路径 for (Integer cIndex : routes){ if(cIndex ==0 || cIndex == routes.size()-1){ if(cIndex ==0){ continue; //起始点不处理 } JkSketchCustomer customer = model.getCustomerList().get(cIndex-1); @@ -306,9 +371,7 @@ cModel.setSketchId(model.getId()); cModel.setCustomerId(customer.getCustomerId()); tModel.getCustomerList().add(cModel); if(cIndex ==0 || cIndex == routes.size()-1){ continue; //起始点不处理 } } } } @@ -361,6 +424,8 @@ .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::getSketchId, model.getId()) .eq(JkSketchCustomer::getIsdeleted,Constants.ZERO)