puzhibing
2023-05-23 abf1d55dab11baeed5f989a273a776abce50cfc6
新增订单添加功能
6个文件已修改
25个文件已添加
2100 ■■■■■ 已修改文件
management/guns-admin/pom.xml 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/controller/general/TOrderController.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/dao/TYouTuiDriverMapper.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/dao/WeatherCityMapper.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/dao/mapping/TYouTuiDriverMapper.xml 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/dao/mapping/WeatherCityMapper.xml 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/model/TOrder.java 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/model/TYouTuiDriver.java 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/model/WeatherCity.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/service/ITYouTuiDriverService.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/service/IWeatherCityService.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/service/impl/TOrderServiceImpl.java 408 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/service/impl/TYouTuiDriverServiceImpl.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/service/impl/WeatherCityServiceImpl.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/GaoDe/MapConfig.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/GaoDe/MapUtil.java 137 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/GaoDe/model/District.java 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/GeodesyUtil.java 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/PushUtil.java 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/httpClinet/HttpClientUtil.java 267 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/httpClinet/HttpResult.java 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/juhe/OCRUtil.java 269 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/juhe/Realtime.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/juhe/WeatherCityInfo.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/juhe/WeatherUtil.java 119 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/mongodb/MongoUtils.java 166 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/mongodb/model/GeoJson.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/mongodb/model/Location.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/mongodb/model/LocationQuery.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/guns-admin/src/main/resources/application.yml 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/guns-admin/src/main/webapp/static/modular/system/tOrder/tOrder_info.js 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/guns-admin/pom.xml
@@ -221,7 +221,22 @@
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!--引入本地工行支付jar end-->
        <!-- 计算两坐标间的直线距离 -->
        <dependency>
            <groupId>org.gavaghan</groupId>
            <artifactId>geodesy</artifactId>
            <version>1.1.3</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.20</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>
    </dependencies>
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/controller/general/TOrderController.java
@@ -19,6 +19,7 @@
import com.stylefeng.guns.modular.system.service.ITAppUserService;
import com.stylefeng.guns.modular.system.service.ITCancelOrderService;
import com.stylefeng.guns.modular.system.service.ITOrderService;
import com.stylefeng.guns.modular.system.util.ResultUtil;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
@@ -244,9 +245,9 @@
     */
    @RequestMapping(value = "/add")
    @ResponseBody
    public Object add(TOrder tOrder) {
        return SUCCESS_TIP;
    public ResultUtil add(TOrder tOrder) {
        ResultUtil add = tOrderService.add(tOrder);
        return add;
    }
    /**
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/dao/TYouTuiDriverMapper.java
New file
@@ -0,0 +1,7 @@
package com.stylefeng.guns.modular.system.dao;
import com.baomidou.mybatisplus.mapper.BaseMapper;
import com.stylefeng.guns.modular.system.model.TYouTuiDriver;
public interface TYouTuiDriverMapper extends BaseMapper<TYouTuiDriver> {
}
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/dao/WeatherCityMapper.java
New file
@@ -0,0 +1,7 @@
package com.stylefeng.guns.modular.system.dao;
import com.baomidou.mybatisplus.mapper.BaseMapper;
import com.stylefeng.guns.modular.system.model.WeatherCity;
public interface WeatherCityMapper extends BaseMapper<WeatherCity> {
}
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/dao/mapping/TYouTuiDriverMapper.xml
New file
@@ -0,0 +1,20 @@
<?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.stylefeng.guns.modular.system.dao.TYouTuiDriverMapper">
    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.stylefeng.guns.modular.system.model.TYouTuiDriver">
        <id column="id" property="id" />
        <result column="driverId" property="driverId" />
        <result column="youTuiId" property="youTuiId" />
        <result column="integral" property="integral" />
        <result column="type" property="type"/>
        <result column="surplusQuantity" property="surplusQuantity"/>
        <result column="endTime" property="endTime"/>
        <result column="state" property="state"/>
        <result column="failureTime" property="failureTime" />
        <result column="createTime" property="createTime" />
    </resultMap>
</mapper>
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/dao/mapping/WeatherCityMapper.xml
New file
@@ -0,0 +1,12 @@
<?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.stylefeng.guns.modular.system.dao.WeatherCityMapper">
    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.stylefeng.guns.modular.system.model.WeatherCity">
        <id column="id" property="id" />
        <result column="province" property="province" />
        <result column="city" property="city" />
        <result column="district" property="district" />
    </resultMap>
</mapper>
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/model/TOrder.java
@@ -1,5 +1,6 @@
package com.stylefeng.guns.modular.system.model;
import com.baomidou.mybatisplus.annotations.TableField;
import com.baomidou.mybatisplus.enums.IdType;
import java.math.BigDecimal;
import java.util.Date;
@@ -138,7 +139,16 @@
     * 添加时间
     */
    private Date createTime;
    /**
     * 预估里程
     */
    @TableField("estimatedMileage")
    private Double estimatedMileage;
    /**
     * 预估时间
     */
    @TableField("estimatedTime")
    private Integer estimatedTime;
    /**
     * 行程录音
     */
@@ -196,9 +206,18 @@
    private BigDecimal discountAmount;
    @ApiModelProperty(value = "实际里程(米)")
    private Integer actualMileage;
    /**
     * 折扣0.01
     */
    @TableField("discount")
    private Double discount;
    @ApiModelProperty(value = "是否已开票 1是 0否")
    private Integer isInvoice;
    /**
     * 大厅订单(0=否,1=是)
     */
    @TableField("hallOrder")
    private Integer hallOrder;
    public String getUserPhone() {
        return userPhone;
@@ -584,6 +603,38 @@
        this.createTime = createTime;
    }
    public Double getEstimatedMileage() {
        return estimatedMileage;
    }
    public void setEstimatedMileage(Double estimatedMileage) {
        this.estimatedMileage = estimatedMileage;
    }
    public Integer getEstimatedTime() {
        return estimatedTime;
    }
    public void setEstimatedTime(Integer estimatedTime) {
        this.estimatedTime = estimatedTime;
    }
    public Double getDiscount() {
        return discount;
    }
    public void setDiscount(Double discount) {
        this.discount = discount;
    }
    public Integer getHallOrder() {
        return hallOrder;
    }
    public void setHallOrder(Integer hallOrder) {
        this.hallOrder = hallOrder;
    }
    @Override
    protected Serializable pkVal() {
        return this.id;
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/model/TYouTuiDriver.java
New file
@@ -0,0 +1,70 @@
package com.stylefeng.guns.modular.system.model;
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 lombok.Data;
import java.util.Date;
/**
* 司机优推数据
* @author pzb
* @Date 2023/2/22 14:01
*/
@Data
@TableName("t_you_tui_driver")
public class TYouTuiDriver {
    /**
     * 主键
     */
    @TableId(value = "id", type = IdType.AUTO)
    @TableField("id")
    private Integer id;
    /**
     * 司机id
     */
    @TableField("driverId")
    private Integer driverId;
    /**
     * 优推id
     */
    @TableField("youTuiId")
    private Integer youTuiId;
    /**
     * 积分
     */
    @TableField("integral")
    private Integer integral;
    /**
     * 优推类型(1=次数,2=小时)
     */
    @TableField("type")
    private Integer type;
    /**
     * 优推剩余数量
     */
    @TableField("surplusQuantity")
    private Integer surplusQuantity;
    /**
     * 优推结束时间
     */
    @TableField("endTime")
    private Date endTime;
    /**
     * 状态(1=未使用,2=使用中,3=已结束)
     */
    @TableField("state")
    private Integer state;
    /**
     * 失效时间
     */
    @TableField("failureTime")
    private Date failureTime;
    /**
     * 添加时间
     */
    @TableField("createTime")
    private Date createTime;
}
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/model/WeatherCity.java
New file
@@ -0,0 +1,38 @@
package com.stylefeng.guns.modular.system.model;
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 lombok.Data;
/**
* 天气相关城市
* @author pzb
* @Date 2023/2/25 10:56
*/
@Data
@TableName("t_weather_city")
public class WeatherCity {
    /**
     * 主键
     */
    @TableId(value = "id", type = IdType.INPUT)
    @TableField("id")
    private Integer id;
    /**
     * 省
     */
    @TableField("province")
    private String province;
    /**
     * 市
     */
    @TableField("city")
    private String city;
    /**
     * 区
     */
    @TableField("district")
    private String district;
}
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/service/ITYouTuiDriverService.java
New file
@@ -0,0 +1,8 @@
package com.stylefeng.guns.modular.system.service;
import com.baomidou.mybatisplus.service.IService;
import com.stylefeng.guns.modular.system.model.TYouTuiDriver;
public interface ITYouTuiDriverService extends IService<TYouTuiDriver> {
}
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/service/IWeatherCityService.java
New file
@@ -0,0 +1,7 @@
package com.stylefeng.guns.modular.system.service;
import com.baomidou.mybatisplus.service.IService;
import com.stylefeng.guns.modular.system.model.WeatherCity;
public interface IWeatherCityService extends IService<WeatherCity> {
}
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/service/impl/TOrderServiceImpl.java
@@ -1,6 +1,7 @@
package com.stylefeng.guns.modular.system.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
@@ -16,15 +17,21 @@
import com.stylefeng.guns.modular.system.dao.TDriverMapper;
import com.stylefeng.guns.modular.system.dao.TOrderMapper;
import com.stylefeng.guns.modular.system.enums.OrderStateEnum;
import com.stylefeng.guns.modular.system.model.TAppUser;
import com.stylefeng.guns.modular.system.model.TBranchOffice;
import com.stylefeng.guns.modular.system.model.TDriver;
import com.stylefeng.guns.modular.system.model.TOrder;
import com.stylefeng.guns.modular.system.service.ITAppUserService;
import com.stylefeng.guns.modular.system.service.ITOrderService;
import com.stylefeng.guns.modular.system.util.DateUtil;
import com.stylefeng.guns.modular.system.util.ResultUtil;
import com.stylefeng.guns.modular.system.model.*;
import com.stylefeng.guns.modular.system.service.*;
import com.stylefeng.guns.modular.system.util.*;
import com.stylefeng.guns.modular.system.util.GaoDe.MapUtil;
import com.stylefeng.guns.modular.system.util.GaoDe.model.District;
import com.stylefeng.guns.modular.system.util.juhe.WeatherUtil;
import com.stylefeng.guns.modular.system.util.mongodb.model.Location;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.Circle;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.Metrics;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
import org.springframework.util.CollectionUtils;
@@ -32,9 +39,12 @@
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;
/**
 * <p>
@@ -61,6 +71,27 @@
    @Autowired
    private ITAppUserService appUserService;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private ITSystemConfigService systemConfigService;
    @Autowired
    private ITYouTuiDriverService youTuiDriverService;
    @Resource
    private MongoTemplate mongoTemplate;
    @Autowired
    private IWeatherCityService weatherCityService;
    @Autowired
    private PushUtil pushUtil;
    @Override
    public List<TOrderResp> getOrderList(String createTime, String code, Integer source, String userName, String userPhone, Integer state, String driverName,Integer isException) {
@@ -381,13 +412,19 @@
            tOrder.setUserId(tAppUser.getId());
        }
        JSONObject jsonObject = JSON.parseObject(startAddress);
        tOrder.setStartAddress(jsonObject.getString("address"));
        String address = jsonObject.getString("address");
        address = address.replaceAll("& #40;", "(");
        address = address.replaceAll("& #41;", ")");
        tOrder.setStartAddress(address);
        tOrder.setStartLat(jsonObject.getString("lat"));
        tOrder.setStartLng(jsonObject.getString("lon"));
        tOrder.setSource(3);
        if(ToolUtil.isNotEmpty(endAddress)){
            jsonObject = JSON.parseObject(endAddress);
            tOrder.setEndAddress(jsonObject.getString("address"));
            String address1 = jsonObject.getString("address");
            address1 = address1.replaceAll("& #40;", "(");
            address1 = address1.replaceAll("& #41;", ")");
            tOrder.setEndAddress(address1);
            tOrder.setEndLat(jsonObject.getString("lat"));
            tOrder.setEndLng(jsonObject.getString("lon"));
        }
@@ -399,35 +436,350 @@
                return ResultUtil.error("获取预估距离出错", "");
            }
            d = Double.valueOf(distance.get("distance")) / 1000;
            order.setEstimatedMileage(d);
            order.setEstimatedTime(Integer.valueOf(distance.get("duration")) / 60);
            tOrder.setEstimatedMileage(d);
            tOrder.setEstimatedTime(Integer.valueOf(distance.get("duration")) / 60);
        }
        String city = "";
        District geocode = MapUtil.geocode(order.getStartLng(), order.getStartLat());
        District geocode = MapUtil.geocode(tOrder.getStartLng(), tOrder.getStartLat());
        if(null != geocode){
            WeatherCity weatherCity = weatherCityService.selectOne(new EntityWrapper<WeatherCity>()
                    .where("'" + geocode.getCity() + "' like CONCAT('%', city, '%') and '" + geocode.getDistrict() + "' like CONCAT('%', district, '%') "));
            city = null != weatherCity ? weatherCity.getId().toString() : "";
        }
        order = getOrderPrice(1, d, 0, order, city);
        order.setState(null == order.getDriverId() ? 101 : 102);
        order.setStatus(1);
        order.setCreateTime(new Date());
        this.insert(order);
        driverService.updateById(driver);
        tOrder = getOrderPrice(1, d, 0, tOrder, city);
        tOrder.setState(101);
        tOrder.setStatus(1);
        tOrder.setCreateTime(new Date());
        this.insert(tOrder);
        //推送状态
        if(null != order.getDriverId()){
            pushUtil.pushOrderStatus(uid, 2, order.getId(), order.getStatus());
        }else{
            //开始推单
            Order finalOrder = order;
            new Thread(new Runnable() {
        pushOrder(tOrder);
        return ResultUtil.success();
    }
    /**
     * 获取订单价格
     * @param type          计算类型(1=预估价,2=订单费)
     * @param distance      行驶公里
     * @param waitTime      等待时长
     * @param order         订单数据
     * @param city          查询天气的城市
     * @return
     */
    public TOrder getOrderPrice(Integer type, Double distance, Integer waitTime, TOrder order, String city){
        order = getOrderInitialPrice(order);
        TSystemConfig systemConfig = systemConfigService.selectOne(new EntityWrapper<TSystemConfig>().eq("type", 5));
        if(null == systemConfig){
            if(type == 1){//预估金额
                order.setEstimatedPrice(new BigDecimal(0));
            }
            if(type == 2){//订单金额
                order.setOrderMoney(new BigDecimal(0));
            }
            return order;
        }
        JSONObject jsonObject = JSON.parseObject(systemConfig.getContent());
        JSONArray chargeStandard = jsonObject.getJSONArray("ChargeStandard");
        JSONObject extraCost = jsonObject.getJSONObject("ExtraCost");
        Date date = new Date();
        for (int i = 0; i < chargeStandard.size(); i++) {
            JSONObject jsonObject1 = chargeStandard.getJSONObject(i);
            String num1 = jsonObject1.getString("num1");
            String num2 = jsonObject1.getString("num2");
            Double num3 = jsonObject1.getDouble("num3");//起步里程
            Double num4 = jsonObject1.getDouble("num4");//起步价格
            Double num5 = jsonObject1.getDouble("num5");//超过公里
            Double num6 = jsonObject1.getDouble("num6");//超过num3每num5公里收取num6
            Double num7 = jsonObject1.getDouble("num7");//长途起始公里
            Double num8 = jsonObject1.getDouble("num8");//长途结束公里
            Double num9 = jsonObject1.getDouble("num9");//长途费
            Double num10 = jsonObject1.getDouble("num10");//超出长途里程每num10公里
            Double num11 = jsonObject1.getDouble("num11");//超过num8每num10公里收取num11
            String[] split = num1.split(":");
            Calendar s = Calendar.getInstance();
            s.setTime(date);
            s.set(Calendar.HOUR_OF_DAY, Integer.valueOf(split[0]));
            s.set(Calendar.MINUTE, Integer.valueOf(split[1]));
            s.set(Calendar.SECOND, 0);
            split = num2.split(":");
            Calendar e = Calendar.getInstance();
            e.setTime(date);
            e.set(Calendar.HOUR_OF_DAY, Integer.valueOf(split[0]));
            e.set(Calendar.MINUTE, Integer.valueOf(split[1]));
            e.set(Calendar.SECOND, 0);
            if(date.getTime() >= s.getTimeInMillis() && date.getTime() < e.getTimeInMillis()){
                if(num3.compareTo(distance) >= 0){//起步里程内
                    order.setStartDistance(distance);//起步里程
                    order.setStartPrice(new BigDecimal(num4));//起步价
                }else{
                    BigDecimal subtract = new BigDecimal(distance).subtract(new BigDecimal(num3));//超出起步里程
                    BigDecimal divide = subtract.divide(new BigDecimal(num5), new MathContext(2, RoundingMode.HALF_EVEN));
                    BigDecimal multiply = divide.multiply(new BigDecimal(num6));
                    order.setStartDistance(num3);//起步里程
                    order.setStartPrice(new BigDecimal(num4));//起步价
                    order.setOverDriveDistance(subtract.doubleValue());//超出起步里程
                    order.setOverDrivePrice(multiply);//超出起步里程费
                    //计算长途费
                    if(distance.compareTo(num7) > 0){
                        order.setLongDistance(num7 + "-" + num8);//长途里程
                        order.setLongDistancePrice(new BigDecimal(num9));//长途费
                    }
                    //计算长途里程超出的部分
                    if(distance.compareTo(num8) > 0){
                        BigDecimal subtract1 = new BigDecimal(distance).subtract(new BigDecimal(num8));
                        BigDecimal divide1 = subtract1.divide(new BigDecimal(num10), new MathContext(2, RoundingMode.HALF_EVEN));
                        BigDecimal multiply1 = divide1.multiply(new BigDecimal(num11));
                        order.setOverLongDistance(subtract1.doubleValue());//超出长途里程
                        order.setOverLongDistancePrice(multiply1);//超出长途里程费
                    }
                }
                break;
            }
        }
        //计算额外费用
        Integer num1 = extraCost.getInteger("num1");//等待时长
        Double num2 = extraCost.getDouble("num2");//等待费
        Integer num3 = extraCost.getInteger("num3");//等待超出时长
        Double num4 = extraCost.getDouble("num4");//等到超出时长费用单价 X/分钟
        Double num5 = extraCost.getDouble("num5");//恶劣天气公里
        Double num6 = extraCost.getDouble("num6");//恶劣天气费
        Double num7 = extraCost.getDouble("num7");//恶劣天气超出公里
        Double num8 = extraCost.getDouble("num8");//恶劣天气超出公里单价 X/公里
        Double num9 = extraCost.getDouble("num9");//恶劣天气最高收取金额
        //等待费用
        if(waitTime.compareTo(num1) >= 0){
            order.setWaitTime(num1);//等待时长
            order.setWaitTimePrice(new BigDecimal(num2));//等待费用
            Integer w = waitTime - num3;
            BigDecimal multiply = new BigDecimal(w).multiply(new BigDecimal(num4));
            order.setOutWaitTime(w);//等待时长超出分钟
            order.setOutWaitTimePrice(multiply);//等待时长超出费用
        }
        //恶劣天气
        systemConfig = systemConfigService.selectOne(new EntityWrapper<TSystemConfig>().eq("type", 8));
        if(null != systemConfig) {
            JSONObject jsonObject1 = JSON.parseObject(systemConfig.getContent());
            Integer num11 = jsonObject1.getInteger("num1");//开启恶劣天气计价
            if(1 == num11){
                boolean badWeather = WeatherUtil.isBadWeather(city);
                if(badWeather){
                    order.setBadWeatherDistance(new BigDecimal(num5));//恶劣天气公里
                    order.setBadWeatherPrice(new BigDecimal(num6));//恶劣天气费
                    if(distance.compareTo(num7) > 0){
                        BigDecimal subtract = new BigDecimal(distance).subtract(new BigDecimal(num7));
                        BigDecimal multiply = subtract.multiply(new BigDecimal(num8));
                        order.setOverBadWeatherDistance(subtract.doubleValue());//恶劣天气超出公里
                        order.setOverBadWeatherPrice(multiply);//恶劣天气超出公里费
                    }
                    double add = order.getOverBadWeatherPrice().add(order.getBadWeatherPrice()).setScale(2, BigDecimal.ROUND_HALF_EVEN).doubleValue();
                    if(num9.compareTo(add) < 0){//超出最高金额(重新调整金额)
                        if(num9.compareTo(num6) < 0){//如果恶劣天气费大于最高金额
                            order.setBadWeatherPrice(new BigDecimal(num9));//恶劣天气费
                            order.setOverBadWeatherPrice(new BigDecimal(0));//恶劣天气超出公里费
                        }else{
                            BigDecimal subtract = new BigDecimal(num9).subtract(new BigDecimal(add));
                            order.setOverBadWeatherPrice(subtract);//恶劣天气超出公里费
                        }
                    }
                }
            }
        }
        //计算折扣
        if(null != order.getUserId()){
        }
        //计算总金额
        BigDecimal bigDecimal = order.getStartPrice().add(order.getOverDrivePrice()).add(order.getLongDistancePrice()).add(order.getOverLongDistancePrice())
                .add(order.getWaitTimePrice()).add(order.getOutWaitTimePrice()).add(order.getBadWeatherPrice()).add(order.getOverBadWeatherPrice()).subtract(order.getDiscountAmount()).setScale(2, BigDecimal.ROUND_HALF_EVEN);
        if(type == 1){//预估价
            order.setEstimatedPrice(bigDecimal);
        }
        if(type == 2){//订单金额
            order.setOrderMoney(bigDecimal);
        }
        return order;
    }
    /**
     * 初始订单费用
     * @param order
     * @return
     */
    public TOrder getOrderInitialPrice(TOrder order){
        order.setStartDistance(0D);//起步里程
        order.setStartPrice(new BigDecimal(0));//起步价
        order.setOverDriveDistance(0D);//超出起步里程
        order.setOverDrivePrice(new BigDecimal(0));//超出起步里程费
        order.setLongDistance("");//长途里程
        order.setLongDistancePrice(new BigDecimal(0));//长途里程费
        order.setOverLongDistance(0D);//超出长途里程
        order.setOverLongDistancePrice(new BigDecimal(0));//超出长途里程费
        order.setWaitTime(0);//等待时长
        order.setWaitTimePrice(new BigDecimal(0));//等待费
        order.setOutWaitTime(0);//超出等待时长
        order.setOutWaitTimePrice(new BigDecimal(0));//超出等待时长费
        order.setBadWeatherDistance(new BigDecimal(0));//恶劣天气里程
        order.setBadWeatherPrice(new BigDecimal(0));//恶劣天气里程费
        order.setOverBadWeatherDistance(0D);//恶劣天气超出里程
        order.setOverBadWeatherPrice(new BigDecimal(0));//恶劣天气超出里程费
        order.setDiscountedPrice(new BigDecimal(0));//优惠金额
        order.setCouponId(null);//优惠券
        order.setDiscountAmount(new BigDecimal(0));//折扣优惠金额
        order.setDiscount(0D);//折扣
        return order;
    }
    /**
     * 订单推送逻辑
     * @param order
     */
    public void pushOrder(TOrder order){
        /**
         * 1.先找最大推单范围内的优推司机 -》 距离最近
         * 没有1 - 》
         *      2.按照后台推送配置在范围内查找合适司机
         *        合适司:积分 > 评分 > 距离
         *      3.司机没有接单直接将订单置入大厅
         */
        TSystemConfig systemConfig = systemConfigService.selectOne(new EntityWrapper<TSystemConfig>().eq("type", 1));
        if(null == systemConfig){
            return;
        }
        JSONObject jsonObject = JSON.parseObject(systemConfig.getContent());
        Double num3 = jsonObject.getDouble("num3");//推单最大范围
        Integer num4 = jsonObject.getInteger("num4");//接单时间
        String startLat = order.getStartLat();
        String startLng = order.getStartLng();
        //1
        //找到中心点
        GeoJsonPoint geoJsonPoint = new GeoJsonPoint(Double.valueOf(startLng), Double.valueOf(startLat));
        Double num = num3 / 1000;//范围公里
        //构造半径
        Distance distanceR = new Distance(num, Metrics.KILOMETERS);
        //画圆
        Circle circle = new Circle(geoJsonPoint, distanceR);
        // 构造query对象
        Query query = Query.query(Criteria.where("location").withinSphere(circle));
        List<Location> locations = mongoTemplate.find(query, Location.class);
        List<Integer> driverIds = locations.stream().map(Location::getDriverId).collect(Collectors.toList());
        Integer driver = null;
        TYouTuiDriver youTuiDriver1 = null;
        if(driverIds.size() > 0){
            List<TYouTuiDriver> youTuiDrivers = youTuiDriverService.selectList(new EntityWrapper<TYouTuiDriver>().in("driverId", driverIds)
                    .eq("state", 2).last(" and (surplusQuantity > 0 or now() < endTime) and now() < failureTime"));
            Double d = null;
            for (TYouTuiDriver youTuiDriver : youTuiDrivers) {
                String value = redisUtil.getValue("DRIVER" + youTuiDriver.getDriverId());
                if(ToolUtil.isEmpty(value)){
                    continue;
                }
                Map<String, Double> distance = GeodesyUtil.getDistance(value, order.getStartLng() + "," + order.getStartLat());
                Double wgs84 = distance.get("WGS84");
                if(d == null || d.compareTo(wgs84) > 0){
                    d = wgs84;
                    driver = youTuiDriver.getDriverId();
                    youTuiDriver1 = youTuiDriver;
                }
            }
        }
        if(null != youTuiDriver1 && youTuiDriver1.getType() == 1){
            youTuiDriver1.setSurplusQuantity(youTuiDriver1.getSurplusQuantity() - 1);
            youTuiDriverService.updateById(youTuiDriver1);
        }
        //开始范围查找
        if(null == driver){
            for (int i = 1; i < 4; i++) {
                if(null != driver){
                    break;
                }
                num = jsonObject.getDouble("num" + i) / 1000;//范围公里
                //构造半径
                distanceR = new Distance(num, Metrics.KILOMETERS);
                //画圆
                circle = new Circle(geoJsonPoint, distanceR);
                // 构造query对象
                query = Query.query(Criteria.where("location").withinSphere(circle));
                locations = mongoTemplate.find(query, Location.class);
                driverIds = locations.stream().map(Location::getDriverId).collect(Collectors.toList());
                if(driverIds.size() > 0){
                    List<TDriver> drivers = tDriverMapper.selectList(new EntityWrapper<TDriver>().eq("approvalStatus", 2).eq("serverStatus", 1).eq("status", 1).in("id", driverIds));
                    if(drivers.size() == 0){
                        continue;
                    }
                    Integer integral = null;
                    Double score = null;
                    Double d = null;
                    for (TDriver driver1 : drivers) {
                        if(integral == null || integral.compareTo(driver1.getIntegral()) < 0){//积分大
                            integral = driver1.getIntegral();
                            score = driver1.getScore();
                            driver = driver1.getId();
                            continue;
                        }
                        if(integral.compareTo(driver1.getIntegral()) == 0 && score.compareTo(driver1.getScore()) < 0){//积分相同对比评分
                            integral = driver1.getIntegral();
                            score = driver1.getScore();
                            driver = driver1.getId();
                            continue;
                        }
                        if(integral.compareTo(driver1.getIntegral()) == 0 && score.compareTo(driver1.getScore()) == 0){//积分相同/评分相同对比距离
                            String value = redisUtil.getValue("DRIVER" + driver1.getId());
                            if(ToolUtil.isEmpty(value)){
                                continue;
                            }
                            Map<String, Double> distance = GeodesyUtil.getDistance(value, order.getStartLng() + "," + order.getStartLat());
                            Double wgs84 = distance.get("WGS84");
                            if(d == null || d.compareTo(wgs84) > 0){
                                d = wgs84;
                                driver = driver1.getId();
                                continue;
                            }
                        }
                    }
                }
            }
        }
        if(null != driver){
            pushUtil.pushGrabOrder(driver, 2, order.getId(), num4);
            //创建定时任务处理订单到大厅
            new Timer().schedule(new TimerTask() {
                @Override
                public void run() {
                    pushOrder(finalOrder);
                    TOrder order1 = TOrderServiceImpl.this.selectById(order.getId());
                    if(order1.getState() == 101 || order1.getState() == 201){
                        order1.setHallOrder(1);
                        TOrderServiceImpl.this.updateById(order1);
                    }
                }
            }).start();
            }, num4 * 1000);
        }else{
            order.setHallOrder(1);
            this.updateById(order);
        }
        return ResultUtil.success(order.getState() == 102 ? order.getId() : null);
    }
}
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/service/impl/TYouTuiDriverServiceImpl.java
New file
@@ -0,0 +1,17 @@
package com.stylefeng.guns.modular.system.service.impl;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.stylefeng.guns.modular.system.dao.TYouTuiDriverMapper;
import com.stylefeng.guns.modular.system.model.TYouTuiDriver;
import com.stylefeng.guns.modular.system.service.ITYouTuiDriverService;
import org.springframework.stereotype.Service;
/**
* 用户优推数据
* @author pzb
* @Date 2023/2/22 14:06
*/
@Service
public class TYouTuiDriverServiceImpl extends ServiceImpl<TYouTuiDriverMapper, TYouTuiDriver> implements ITYouTuiDriverService {
}
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/service/impl/WeatherCityServiceImpl.java
New file
@@ -0,0 +1,11 @@
package com.stylefeng.guns.modular.system.service.impl;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.stylefeng.guns.modular.system.dao.WeatherCityMapper;
import com.stylefeng.guns.modular.system.model.WeatherCity;
import com.stylefeng.guns.modular.system.service.IWeatherCityService;
import org.springframework.stereotype.Service;
@Service
public class WeatherCityServiceImpl extends ServiceImpl<WeatherCityMapper, WeatherCity> implements IWeatherCityService {
}
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/GaoDe/MapConfig.java
New file
@@ -0,0 +1,14 @@
package com.stylefeng.guns.modular.system.util.GaoDe;
/**
* 高德地图配置
* @author pzb
* @Date 2023/2/16 18:52
*/
public interface MapConfig {
    /**
     * 高德key
     */
    String key = "e0370a9a4d10739045fb0b8f4742a67e";
}
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/GaoDe/MapUtil.java
New file
@@ -0,0 +1,137 @@
package com.stylefeng.guns.modular.system.util.GaoDe;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.stylefeng.guns.modular.system.util.GaoDe.model.District;
import com.stylefeng.guns.modular.system.util.httpClinet.HttpClientUtil;
import com.stylefeng.guns.modular.system.util.httpClinet.HttpResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 地图工具类
* @author pzb
* @Date 2023/2/16 18:48
*/
public class MapUtil {
    public static Logger logger = LoggerFactory.getLogger("ServiceLog");
    /**
     * 获取两点的距离
     * @param origins       起点坐标
     * @param destination   终点坐标
     * @param type          计算类型:0:直线距离 1:驾车导航距离(仅支持国内坐标)。
     * @return
     */
    public static Map<String, String> getDistance(String origins, String destination, Integer type){
        try {
            String url = "https://restapi.amap.com/v3/distance?key=" + MapConfig.key + "&origins=" + origins + "&destination=" + destination +
                    "&type=" + type;
            HttpResult httpResult = HttpClientUtil.pushHttpRequset("GET", url, null, null, "json");
            if(httpResult.getCode() != 200){
                logger.debug(httpResult.getData());
                return null;
            }
            String data = httpResult.getData();
            JSONObject jsonObject = JSON.parseObject(data);
            String status = jsonObject.getString("status");
            if(status.equals("1")){
                JSONArray results = jsonObject.getJSONArray("results");
                JSONObject jsonObject1 = results.getJSONObject(0);
                Map<String, String> map = new HashMap<>();
                map.put("distance", jsonObject1.getString("distance"));//距离(米)
                map.put("duration", jsonObject1.getString("duration"));//预计时间(秒)
                return map;
            }else{
                logger.debug(data);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 地址转换经纬度
     * @param address
     * @return
     */
    public static List<String> geocoding(String address){
        try {
            String url = "https://restapi.amap.com/v3/geocode/geo?key=" + MapConfig.key + "&output=JSON&address=" + address;
            HttpResult httpResult = HttpClientUtil.pushHttpRequset("GET", url, null, null, "json");
            if(httpResult.getCode() != 200){
                return null;
            }
            JSONObject jsonObject = JSON.parseObject(httpResult.getData());
            String status = jsonObject.getString("status");
            List<String> list = new ArrayList<>();
            if(status.equals("1")){
                JSONArray geocodes = jsonObject.getJSONArray("geocodes");
                for(int i = 0; i < geocodes.size(); i++){
                    String location = geocodes.getJSONObject(i).getString("location");
                    list.add(location);
                }
            }
            return list;
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 根据经纬度获取行政区域信息
     * @param lon
     * @param lan
     * @return
     * @throws Exception
     */
    public static District geocode(String lon, String lan) {
        try {
            String url = "https://restapi.amap.com/v3/geocode/regeo?key=" + MapConfig.key + "&location=" + lon + "," + lan;
            HttpResult httpResult = HttpClientUtil.pushHttpRequset("GET", url, null, null, "json");
            if(httpResult.getCode() != 200){
                return null;
            }
            JSONObject jsonObject = JSON.parseObject(httpResult.getData());
            Map<String, String> map = new HashMap<>();
            if(jsonObject.getString("status").equals("1")){
                JSONObject regeocode = jsonObject.getJSONObject("regeocode");
                JSONObject addressComponent = regeocode.getJSONObject("addressComponent");
                String address = regeocode.getString("formatted_address");
                map.put("address", address);
                String code = addressComponent.getString("adcode");
                String province = addressComponent.getString("province");
                String city = addressComponent.getString("city");
                String district = addressComponent.getString("district");
                District district1 = new District();
                district1.setProvince(province);
                district1.setProvinceCode(code.substring(0, 2) + "0000");
                district1.setCity(city);
                district1.setCityCode(code.substring(0, 4) + "00");
                district1.setDistrict(district);
                district1.setDistrictCode(code);
                return district1;
            }
            logger.debug(httpResult.getData());
            return null;
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }
}
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/GaoDe/model/District.java
New file
@@ -0,0 +1,83 @@
package com.stylefeng.guns.modular.system.util.GaoDe.model;
/**
* 行政区域
* @author pzb
* @Date 2023/2/25 11:40
*/
public class District {
    /**
     * 省名称
     */
    private String province;
    /**
     * 省编号
     */
    private String provinceCode;
    /**
     * 市名称
     */
    private String city;
    /**
     * 市编号
     */
    private String cityCode;
    /**
     * 区县名称
     */
    private String district;
    /**
     * 区县编号
     */
    private String districtCode;
    public String getProvince() {
        return province;
    }
    public void setProvince(String province) {
        this.province = province;
    }
    public String getProvinceCode() {
        return provinceCode;
    }
    public void setProvinceCode(String provinceCode) {
        this.provinceCode = provinceCode;
    }
    public String getCity() {
        return city;
    }
    public void setCity(String city) {
        this.city = city;
    }
    public String getCityCode() {
        return cityCode;
    }
    public void setCityCode(String cityCode) {
        this.cityCode = cityCode;
    }
    public String getDistrict() {
        return district;
    }
    public void setDistrict(String district) {
        this.district = district;
    }
    public String getDistrictCode() {
        return districtCode;
    }
    public void setDistrictCode(String districtCode) {
        this.districtCode = districtCode;
    }
}
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/GeodesyUtil.java
New file
@@ -0,0 +1,63 @@
package com.stylefeng.guns.modular.system.util;
import org.gavaghan.geodesy.Ellipsoid;
import org.gavaghan.geodesy.GeodeticCalculator;
import org.gavaghan.geodesy.GeodeticCurve;
import org.gavaghan.geodesy.GlobalCoordinates;
import java.util.HashMap;
import java.util.Map;
/**
 * 计算两个金纬度坐标之间的直线距离
 */
public class GeodesyUtil {
    /**
     * 获取直线距离
     * @param fromLonLat
     * @param toLonLat
     * @return
     */
    public static Map<String, Double> getDistance(String fromLonLat, String toLonLat){
        String[] from = fromLonLat.split(",");
        String[] to = toLonLat.split(",");
        GlobalCoordinates source = new GlobalCoordinates(Double.valueOf(from[1]), Double.valueOf(from[0]));
        GlobalCoordinates target = new GlobalCoordinates(Double.valueOf(to[1]), Double.valueOf(to[0]));
        double Sphere = getDistanceMeter(source, target, Ellipsoid.Sphere);
        double WGS84 = getDistanceMeter(source, target, Ellipsoid.WGS84);
        double GRS80 = getDistanceMeter(source, target, Ellipsoid.GRS80);
        double GRS67 = getDistanceMeter(source, target, Ellipsoid.GRS67);
        double ANS = getDistanceMeter(source, target, Ellipsoid.ANS);
        double WGS72 = getDistanceMeter(source, target, Ellipsoid.WGS72);
        double Clarke1858 = getDistanceMeter(source, target, Ellipsoid.Clarke1858);
        double Clarke1880 = getDistanceMeter(source, target, Ellipsoid.Clarke1880);
//        System.out.println("Sphere坐标系计算结果:"+Sphere + "米");
//        System.out.println("WGS84坐标系计算结果:"+WGS84 + "米");
//        System.out.println("GRS80坐标系计算结果:"+GRS80 + "米");
//        System.out.println("GRS67坐标系计算结果:"+GRS67 + "米");
//        System.out.println("ANS坐标系计算结果:"+ANS + "米");
//        System.out.println("WGS72坐标系计算结果:"+WGS72 + "米");
//        System.out.println("Clarke1858坐标系计算结果:"+Clarke1858 + "米");
//        System.out.println("Clarke1880坐标系计算结果:"+Clarke1880 + "米");
        Map<String, Double> map = new HashMap<>();
        map.put("Sphere", Sphere);
        map.put("WGS84", WGS84);
        map.put("GRS80", GRS80);
        map.put("GRS67", GRS67);
        map.put("ANS", ANS);
        map.put("WGS72", WGS72);
        map.put("Clarke1858", Clarke1858);
        map.put("Clarke1880", Clarke1880);
        return map;
    }
    private static double getDistanceMeter(GlobalCoordinates gpsFrom, GlobalCoordinates gpsTo, Ellipsoid ellipsoid){
        //创建GeodeticCalculator,调用计算方法,传入坐标系、经纬度用于计算距离
        GeodeticCurve geoCurve = new GeodeticCalculator().calculateGeodeticCurve(ellipsoid, gpsFrom, gpsTo);
        return geoCurve.getEllipsoidalDistance();
    }
}
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/PushUtil.java
New file
@@ -0,0 +1,72 @@
package com.stylefeng.guns.modular.system.util;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import java.util.HashMap;
import java.util.Map;
/**
 * socket推单处理类
 */
@Component
public class PushUtil {
    Logger logger = LoggerFactory.getLogger("ServiceLog");
    @Autowired
    private RestTemplate internalRestTemplate;
    /**
     * 系统推单推送
     * @param id            接受对象id
     * @param type          接受对象类型(1=用户,2=司机)
     * @param orderId       订单id
     * @param countdown     抢单倒计时(秒)
     */
    public void pushGrabOrder(Integer id, Integer type, Integer orderId, Integer countdown){
        JSONObject msg = new JSONObject();
        msg.put("code", 200);
        msg.put("msg", "SUCCESS");
        msg.put("method", "GRAB_ORDER");
        Map<String, Object> map = new HashMap<>();
        map.put("orderId", orderId);
        map.put("countdown", countdown);
        msg.put("data", map);
        //调用推送
        HttpHeaders headers = new HttpHeaders();
        // 以表单的方式提交
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        //将请求头部和参数合成一个请求
        MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
        params.add("msg", msg.toJSONString());
        params.add("id", id.toString());
        params.add("type", type.toString());
        HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(params, headers);
        String s = internalRestTemplate.postForObject("http://zuul-gateway/netty/sendMsgToClient",requestEntity , String.class);
        JSONObject jsonObject1 = JSON.parseObject(s, JSONObject.class);
        if(jsonObject1.getIntValue("code") != 200){
            logger.debug(jsonObject1.getString("msg"));
            System.err.println(jsonObject1.getString("msg"));
        }
    }
}
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/httpClinet/HttpClientUtil.java
New file
@@ -0,0 +1,267 @@
package com.stylefeng.guns.modular.system.util.httpClinet;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.security.KeyStore;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
 * http工具类
 */
public class HttpClientUtil {
    private static Logger logger = LoggerFactory.getLogger(HttpClientUtil.class);
    private static PoolingHttpClientConnectionManager connectionManager;
    {
        //1.创建连接池管理器
        connectionManager = new PoolingHttpClientConnectionManager(60000,
                TimeUnit.MILLISECONDS);
        connectionManager.setMaxTotal(1000);
        connectionManager.setDefaultMaxPerRoute(50);
    }
    /**
     * 创建一个httpClient对象
     */
    private static CloseableHttpClient getHttpCline(){
        return  HttpClients.custom()
                .setConnectionManager(connectionManager)
                .disableAutomaticRetries()
                .build();
    }
    private static RequestConfig getRequestConfig(){
        RequestConfig.Builder builder = RequestConfig.custom();
        builder.setSocketTimeout(60000)//3.1设置客户端等待服务端返回数据的超时时间
                .setConnectTimeout(30000)//3.2设置客户端发起TCP连接请求的超时时间
                .setExpectContinueEnabled(true)
                .setConnectionRequestTimeout(30000);//3.3设置客户端从连接池获取链接的超时时间
        return builder.build();
    }
    /**
     * 创建一个POST请求实例
     * @param url       请求地址
     * @param params    请求参数
     */
    private static CloseableHttpResponse setPostHttpRequset(String url, Map<String, Object> params, Map<String, String> header, String contentType) throws Exception{
        HttpPost httpPost = new HttpPost(url);
        httpPost.setConfig(getRequestConfig());
        if(null != header){
            for(String key : header.keySet()){
                httpPost.setHeader(key, header.get(key));
            }
        }
        List<NameValuePair> list = new ArrayList<>();
        if(null != params){
            Set<String> keys = params.keySet();
            for(String key : keys){
                list.add(new BasicNameValuePair(key, null == params.get(key) ? null : params.get(key).toString()));
            }
        }
        switch (contentType){
            case "form":
                httpPost.setEntity(new UrlEncodedFormEntity(list, "UTF-8"));
                break;
            case "json":
                ObjectMapper objectMapper = new ObjectMapper();
                String s =objectMapper.writeValueAsString(params);
                httpPost.setEntity(new StringEntity(s, ContentType.create(ContentType.APPLICATION_JSON.getMimeType(), Charset.forName("UTF-8"))));
                break;
        }
        return getHttpCline().execute(httpPost);
    }
    /**
     * 获取get请求实例
     * @param url       请求地址
     * @param params    请求参数
     */
    private static CloseableHttpResponse setGetHttpRequset(String url, Map<String, Object> params, Map<String, String> header) throws Exception{
        StringBuffer sb = new StringBuffer();
        String p = "";
        if(null != params){
            Set<String> keys = params.keySet();
            for(String key : keys){
                sb.append(key + "=" + params.get(key) + "&");
            }
            p = "?" + sb.substring(0, sb.length() - 1);
        }
        HttpGet httpGet = new HttpGet(url + p);
        httpGet.setConfig(getRequestConfig());
        if(null != header){
            for(String key : header.keySet()){
                httpGet.setHeader(key, header.get(key));
            }
        }
        return getHttpCline().execute(httpGet);
    }
    /**
     * 发送http请求
     * @param mothed        "GET、POST、PUT、HEAD、DELETE、HEAD、OPTIONS"
     * @param url           请求地址
     * @param params        请求参数
     * @param header        请求头
     * @param contentType   参数请求方式form/json
     * @return
     */
    public static HttpResult pushHttpRequset(String mothed, String url, Map<String, Object> params, Map<String, String> header, String contentType) throws Exception{
        String randome = UUID.randomUUID().toString();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S");
        logger.info(sdf.format(new Date()) + "----(" + randome + ")请求参数:" + JSON.toJSONString(params));
        CloseableHttpResponse httpResponse = null;
        switch (mothed){
            case "GET":
                httpResponse = setGetHttpRequset(url, params, header);
                break;
            case "POST":
                httpResponse = setPostHttpRequset(url, params, header, contentType);
                break;
        }
        int statusCode = httpResponse.getStatusLine().getStatusCode();
        String content = EntityUtils.toString(httpResponse.getEntity(), "UTF-8");
        logger.info(sdf.format(new Date()) + "----(" + randome + ")返回结果:" + content);
        HttpResult httpResult = HttpResult.getHttpResult(statusCode, content);
        close(httpResponse);
        return httpResult;
    }
    /**
     * 发送XML请求
     * @param url       请求地址
     * @param xml       XML数据
     * @param header    自定义请求头
     * @return
     */
    public static HttpResult pushHttpRequsetXml(String url, String xml, Map<String, String> header) throws Exception{
        HttpPost httpPost = new HttpPost(url);
        httpPost.setConfig(getRequestConfig());
        for(String key : header.keySet()){
            httpPost.setHeader(key, header.get(key));
        }
        httpPost.setHeader("Content-Type", "application/xml");
        httpPost.setEntity(new StringEntity(xml, "UTF-8"));
        CloseableHttpResponse httpResponse = getHttpCline().execute(httpPost);
        int statusCode = httpResponse.getStatusLine().getStatusCode();
        String content = EntityUtils.toString(httpResponse.getEntity(), "UTF-8");
        HttpResult httpResult = HttpResult.getHttpResult(statusCode, content);
        close(httpResponse);
        return httpResult;
    }
    /**
     * 请求https发送XML请求
     * @param url           接口路径
     * @param xml           内容
     * @param header        请求头
     * @param certPassword      证书密码
     * @param certPath      证书路径
     * @param certType      证书类型
     * @return
     * @throws Exception
     */
    public String pushHttpsRequsetXml(String url, String xml, Map<String, String> header, String certPassword, String certPath, String certType) throws Exception{
        HttpPost httpPost = new HttpPost(url);
        for(String key : header.keySet()){
            httpPost.setHeader(key, header.get(key));
        }
        httpPost.setHeader("Content-Type", "application/xml");
        httpPost.setEntity(new StringEntity(xml, "UTF-8"));
        CloseableHttpClient httpCline = this.initCert(certPassword, certPath, certType);
        CloseableHttpResponse httpResponse = httpCline.execute(httpPost);
        String content = null;
        if(httpResponse.getStatusLine().getStatusCode() == 200){
            content = EntityUtils.toString(httpResponse.getEntity(), "UTF-8");
        }else{
            content = "返回状态码:" + httpResponse.getStatusLine() + "。" + EntityUtils.toString(httpResponse.getEntity());
        }
        this.close(httpResponse);
        httpCline.close();
        return content;
    }
    /**
     * 初始化https对象(带证书)
     * @param key       证书密码
     * @param certPath  证书路径
     * @param certType  证书类型
     * @throws Exception
     */
    private CloseableHttpClient initCert(String key, String certPath, String certType) throws Exception {
        KeyStore keyStore = KeyStore.getInstance(certType);
        InputStream inputStream = new FileInputStream(new File(certPath));
        try {
            keyStore.load(inputStream, key.toCharArray());
        } finally {
            inputStream.close();
        }
        SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, key.toCharArray()).build();
        SSLConnectionSocketFactory sslsf =
                new SSLConnectionSocketFactory(sslcontext, new String[] {"TLSv1"}, null,
                        SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
        return HttpClients.custom().setSSLSocketFactory(sslsf).build();
    }
    /**
     * 关闭资源
     */
    private static void close(CloseableHttpResponse httpResponse){
        try {
            if(null != httpResponse){
                EntityUtils.consume(httpResponse.getEntity());//此处高能,通过源码分析,由EntityUtils是否回收HttpEntity
                httpResponse.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                if(null != httpResponse){
                    httpResponse.close();
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
}
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/httpClinet/HttpResult.java
New file
@@ -0,0 +1,45 @@
package com.stylefeng.guns.modular.system.util.httpClinet;
/**
 * http请求返回封装
 */
public class HttpResult {
    /**
     * 返回状态码
     */
    private Integer code;
    /**
     * 返回结果
     */
    private String data;
    public Integer getCode() {
        return code;
    }
    public void setCode(Integer code) {
        this.code = code;
    }
    public String getData() {
        return data;
    }
    public void setData(String data) {
        this.data = data;
    }
    /**
     * 返回封装结果
     * @param code
     * @param data
     * @return
     */
    public static HttpResult getHttpResult(Integer code, String data){
        HttpResult httpResult = new HttpResult();
        httpResult.setCode(code);
        httpResult.setData(data);
        return httpResult;
    }
}
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/juhe/OCRUtil.java
New file
@@ -0,0 +1,269 @@
package com.stylefeng.guns.modular.system.util.juhe;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.stylefeng.guns.modular.system.util.httpClinet.HttpClientUtil;
import com.stylefeng.guns.modular.system.util.httpClinet.HttpResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;
import java.util.HashMap;
import java.util.Map;
/**
 * @author zhibing.pu
 * @date 2023/4/10 15:35
 */
public class OCRUtil {
    static Logger logger = LoggerFactory.getLogger("ServiceLog");
    private final static String key = "5cc9622f299335639dbc046f3812c52a";
    private static HttpClientUtil httpClientUtil = new HttpClientUtil();
    /**
     * OCR证件识别
     * @param cardType
     *          "1": "一代身份证",
     *         "2": "二代身份证正面",
     *         "3": "二代身份证证背面",
     *         "4": "临时身份证",
     *         "5": "驾照",
     *         "6": "行驶证",
     *         "7": "军官证1998版",
     *         "9": "中华人民共和国往来港澳通行证2005版",
     *         "10": "台湾居民往来大陆通行证1992版-照片页",
     *         "11": "大陆居民往来台湾通行证1992版-照片页",
     *         "12": "签证(护照幅面)",
     *         "13": "护照(护照幅面)",
     *         "14": "港澳居民来往内地通行证-照片页",
     *         "15": "港澳居民来往内地通行证-机读码页",
     *         "16": "户口本",
     *         "17": "银行卡",
     *         "22": "往来港澳通行证2014版-照片页(卡式港澳通行证)",
     *         "25": "台湾居民来往大陆通行证2015版-照片页",
     *         "26": "台湾居民往来大陆通行证2015版-机读码页",
     *         "28": "中国驾驶证副页",
     *         "29": "往来台湾通行证2017版-照片页",
     *         "30": "行驶证副页",
     *         "31": "港澳台居民居住证正面",
     *         "32": "港澳台居民居住证反面",
     *         "33": "外国人永久居留身份证",
     *         "101": "二代身份证正面背面自动分类",
     *         "102": "驾驶证正副页自动分类",
     *         "103": "行驶证正副页自动分类",
     *         "104": "身份证、驾驶证、行驶证自动分类",
     *         "1000": "居住证",
     *         "1001": "香港永久性居民身份证",
     *         "1002": "登机牌(拍照设备目前不支持登机牌的识别)",
     *         "1003": "边民证(A)(照片页)",
     *         "2008":"营业执照"
     * @param file  图片文件
     * @return
     */
    public static JSONObject certificate(Integer cardType, MultipartFile file){
        String url = "http://v.juhe.cn/certificates/query";
        HttpResult httpResult = null;
        try {
            Map<String, Object> params = new HashMap<>();
            params.put("key", key);
            params.put("cardType", cardType.toString());
            params.put("pic", file);
            httpResult = httpClientUtil.pushHttpRequset("POST", url, params, null, "form");
        } catch (Exception e) {
            e.printStackTrace();
        }
        if(httpResult.getCode() != 200){
            logger.debug("查询证件失败:" + httpResult.getData());
            return null;
        }
        String data = httpResult.getData();
        JSONObject jsonObject = JSON.parseObject(data);
        Integer error_code = jsonObject.getInteger("error_code");
        if(0 != error_code){
            logger.debug("查询证件失败:" + jsonObject.getString("reason"));
            return null;
        }
        JSONObject result = jsonObject.getJSONObject("result");
        return result;
    }
    ////身份证识别返回示例
    //{
    //    "error_code": 0,
    //    "reason": "操作成功",
    //    "result": {
    //        "住址": "武汉市江岸区永清路****",
    //        "保留": "",
    //        "公民身份号码": "42010619510609****",
    //        "出生": "1951-06-09",
    //        "头像": "",/*Base64字符串*/
    //        "姓名": "彭*",
    //        "性别": "男",
    //        "民族": "汉",
    //        "orderid":"JH1531180126114835937669",
    //        "userid":"1234567"
    //    }
    //}
    //
    ////车牌识别返回示例
    //{
    //  "reason": "操作成功",
    //  "result": {
    //    "车牌号": "粤N0***81",
    //    "车牌颜色": "1",
    //    "车牌类型": "1",
    //    "整牌可信度": "86",
    //    "亮度评价": "215",
    //    "车牌运动方向": "0",
    //    "车牌位置(left_top_right_bottom)": "30_118_498_222",
    //        "orderid":"JH1531180126114835937669",
    //        "userid":"1234567"
    //  },
    //  "error_code": 0
    //}
    ////港澳台居民居住证正面
    //{
    //   "reason": "操作成功",
    //   "result":{
    //     "保留" : "",
    //     "姓名" : "",
    //     "性别" : "",
    //     "民族" : "",
    //     "住址" : "",
    //     "出生" : "",
    //     "公民身份号码" : "",
    //     "复印件判别" : "",
    //     "头像" : ""
    //   }
    //}
    ////港澳台居民居住证反面
    //{
    //   "reason": "操作成功",
    //   "result":{
    //     "保留" : "",
    //     "签发机关" : "",
    //     "有效期限" : "",
    //     "签发日期" : "",
    //     "有效期至" : "",
    //     "通行证号码" : ""
    //   }
    //}
    ////港澳居民来往内地通行证-照片页
    //{
    //   "reason": "操作成功",
    //   "result":{
    //     "保留" : "",
    //     "证件号码" : "",
    //     "中文姓名" : "",
    //     "英文姓名" : "",
    //     "性别" : "",
    //     "出生日期" : "",
    //     "本证有效期至" : "",
    //     "英文姓" : "",
    //     "英文名" : "",
    //    "港澳证件号码" : "",
    //    "签发日期" : "",
    //    "有效期限" : "",
    //    "签发机关" : "",
    //    "换证次数" : "",
    //    "其他姓名" : "",
    //    "归属地" : "",
    //    "头像" : "",
    //   }
    //}
    ////中国台湾居民来往内地通行证照片页
    //{
    //   "reason": "操作成功",
    //   "result":{
    //     "保留" : "",
    //     "中文姓名" : "",
    //     "英文姓名" : "",
    //     "出生日期" : "",
    //     "性别" : "",
    //     "有效期限" : "",
    //     "签发地点" : "",
    //     "证件号码" : "",
    //     "签发次数" : "",
    //     "签发机关" : "",
    //     "头像" : "",
    //   }
    //}
    ////针对车牌的信息:
    //1.车牌颜色类型:
    //     0 //未知车牌
    //     1 //蓝牌
    //     2 //黑牌
    //     3 //单排黄牌
    //     4 //双排黄牌(大车尾牌,农用车)
    //     5 //警车车牌
    //     6 //武警车牌
    //     7 //个性化车牌
    //     8 //单排军车
    //     9 //双排军车
    //     10 //使馆牌
    //     11 //香港牌
    //     12 //拖拉机
    //     13 //澳门牌
    //     14 //厂内牌
    //     15 //民航牌
    //     16 //领事馆车牌
    //     17 //新能源车牌-小型车
    //     18 //新能源车牌-大型车
    //
    //2.车牌可信度:
    //    当前识别结果的分数,分数越高识别对的可能越大
    //3.车牌位置:
    //    是指车牌在图像中的坐标值
    //4.车牌运动方向:
    //    0 unknown, 1 left, 2 right, 3 up , 4 down
    //
    ////行驶证查询返回:
    //{
    //    "保留": "",
    //    "号牌号码": "粤A4****",
    //    "车辆类型": "小型轿车",
    //    "所有人": "黄**",
    //    "住址": "广东省从化市城郊街东风***********",
    //    "品牌型号": "别克1B*******71801S",
    //    "车辆识别代号": "LSGJ********44832",
    //    "发动机号码": "T18S********C",
    //    "注册日期": "2000-06-13",
    //    "发证日期": "2020-07-11",
    //    "使用性质": "非营运",
    //        "orderid":"JH1531180126114835937669",
    //        "userid":"1234567"
    //}
    ////VIN识别
    //{
    //    "vin": "WBAFR7103BC727722",
    //    "orderid": "JH1531180524123006771818"
    //}
    ////营业执照
    //{
    //"reason": "操作成功",
    //"result":{
    //"统一社会信用代码": "91110105MA01AMC6Q",
    //"组织机构代码": "",
    //"税务登记证号": "",
    //"社保登记号": "",
    //"统计证证号": "",
    //"名称": "北京数字传奇网络科技有限公司",
    //"类型": "有限责任公司(自然人投资或控股)",
    //"住所": "北京市朝阳区将台乡驼房营路8号新华科技大厦21层2106室",
    //"法定代表人": "吴发强",
    //"组成形式": "",
    //"注册资本": "100万元",
    //"成立日期": "2018年03月21日",
    //"营业期限": "2018年03月21日至长期",
    //"经营范围": "技术开发、技术推广、技术咨询、技术服务。(企业依法自主\n选择经营项目,开展经营活班依法须经批准的顼目,经相关\n部门批准后依批准的内容开展经营活班不得从事本市产业政\n策禁止和限制类顼目的经营活动。)",
    //"登记机关": "",
    //"登记日期": "",
    //"二维码": "http://qyxy.baic.gov.cn/wap/wap/creditWapAction!qr.dhtml?id=ff8080816242f1250162463d9d3168f3",
    //"副本": ""
    //},
}
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/juhe/Realtime.java
New file
@@ -0,0 +1,40 @@
package com.stylefeng.guns.modular.system.util.juhe;
import lombok.Data;
/**
* 天气实况
* @author pzb
* @Date 2023/2/20 11:38
*/
@Data
public class Realtime {
    /**
     * 天气情况,如:晴、多云
     */
    private String info;
    /**
     * 天气标识id,可参考小接口2
     */
    private String wid;
    /**
     * 温度,可能为空
     */
    private String temperature;
    /**
     * 湿度,可能为空
     */
    private String humidity;
    /**
     * 风向,可能为空
     */
    private String direct;
    /**
     * 风力,可能为空
     */
    private String power;
    /**
     * 空气质量指数,可能为空
     */
    private String aqi;
}
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/juhe/WeatherCityInfo.java
New file
@@ -0,0 +1,38 @@
package com.stylefeng.guns.modular.system.util.juhe;
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 lombok.Data;
/**
* 天气相关城市
* @author pzb
* @Date 2023/2/25 10:56
*/
@Data
@TableName("t_weather_city")
public class WeatherCityInfo {
    /**
     * 主键
     */
    @TableId(value = "id", type = IdType.INPUT)
    @TableField("id")
    private Integer id;
    /**
     * 省
     */
    @TableField("province")
    private String province;
    /**
     * 市
     */
    @TableField("city")
    private String city;
    /**
     * 区
     */
    @TableField("district")
    private String district;
}
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/juhe/WeatherUtil.java
New file
@@ -0,0 +1,119 @@
package com.stylefeng.guns.modular.system.util.juhe;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.stylefeng.guns.core.util.ToolUtil;
import com.stylefeng.guns.modular.system.util.httpClinet.HttpClientUtil;
import com.stylefeng.guns.modular.system.util.httpClinet.HttpResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
/**
* 天气工具类
* @author pzb
* @Date 2023/2/18 16:54
*/
public class WeatherUtil {
    static Logger logger = LoggerFactory.getLogger("ServiceLog");
    private final static String weather_type = "[{\"wid\":\"00\",\"weather\":\"晴\"},{\"wid\":\"01\",\"weather\":\"多云\"},{\"wid\":\"02\",\"weather\":\"阴\"},{\"wid\":\"03\",\"weather\":\"阵雨\"},{\"wid\":\"04\",\"weather\":\"雷阵雨\"},{\"wid\":\"05\",\"weather\":\"雷阵雨伴有冰雹\"},{\"wid\":\"06\",\"weather\":\"雨夹雪\"},{\"wid\":\"07\",\"weather\":\"小雨\"},{\"wid\":\"08\",\"weather\":\"中雨\"},{\"wid\":\"09\",\"weather\":\"大雨\"},{\"wid\":\"10\",\"weather\":\"暴雨\"},{\"wid\":\"11\",\"weather\":\"大暴雨\"},{\"wid\":\"12\",\"weather\":\"特大暴雨\"},{\"wid\":\"13\",\"weather\":\"阵雪\"},{\"wid\":\"14\",\"weather\":\"小雪\"},{\"wid\":\"15\",\"weather\":\"中雪\"},{\"wid\":\"16\",\"weather\":\"大雪\"},{\"wid\":\"17\",\"weather\":\"暴雪\"},{\"wid\":\"18\",\"weather\":\"雾\"},{\"wid\":\"19\",\"weather\":\"冻雨\"},{\"wid\":\"20\",\"weather\":\"沙尘暴\"},{\"wid\":\"21\",\"weather\":\"小到中雨\"},{\"wid\":\"22\",\"weather\":\"中到大雨\"},{\"wid\":\"23\",\"weather\":\"大到暴雨\"},{\"wid\":\"24\",\"weather\":\"暴雨到大暴雨\"},{\"wid\":\"25\",\"weather\":\"大暴雨到特大暴雨\"},{\"wid\":\"26\",\"weather\":\"小到中雪\"},{\"wid\":\"27\",\"weather\":\"中到大雪\"},{\"wid\":\"28\",\"weather\":\"大到暴雪\"},{\"wid\":\"29\",\"weather\":\"浮尘\"},{\"wid\":\"30\",\"weather\":\"扬沙\"},{\"wid\":\"31\",\"weather\":\"强沙尘暴\"},{\"wid\":\"53\",\"weather\":\"霾\"}]";
    private final static String bad_weather = "[{\"wid\":\"03\",\"weather\":\"阵雨\"},{\"wid\":\"04\",\"weather\":\"雷阵雨\"},{\"wid\":\"05\",\"weather\":\"雷阵雨伴有冰雹\"},{\"wid\":\"06\",\"weather\":\"雨夹雪\"},{\"wid\":\"07\",\"weather\":\"小雨\"},{\"wid\":\"08\",\"weather\":\"中雨\"},{\"wid\":\"09\",\"weather\":\"大雨\"},{\"wid\":\"10\",\"weather\":\"暴雨\"},{\"wid\":\"11\",\"weather\":\"大暴雨\"},{\"wid\":\"12\",\"weather\":\"特大暴雨\"},{\"wid\":\"13\",\"weather\":\"阵雪\"},{\"wid\":\"14\",\"weather\":\"小雪\"},{\"wid\":\"15\",\"weather\":\"中雪\"},{\"wid\":\"16\",\"weather\":\"大雪\"},{\"wid\":\"17\",\"weather\":\"暴雪\"},{\"wid\":\"19\",\"weather\":\"冻雨\"},{\"wid\":\"20\",\"weather\":\"沙尘暴\"},{\"wid\":\"21\",\"weather\":\"小到中雨\"},{\"wid\":\"22\",\"weather\":\"中到大雨\"},{\"wid\":\"23\",\"weather\":\"大到暴雨\"},{\"wid\":\"24\",\"weather\":\"暴雨到大暴雨\"},{\"wid\":\"25\",\"weather\":\"大暴雨到特大暴雨\"},{\"wid\":\"26\",\"weather\":\"小到中雪\"},{\"wid\":\"27\",\"weather\":\"中到大雪\"},{\"wid\":\"28\",\"weather\":\"大到暴雪\"},{\"wid\":\"30\",\"weather\":\"扬沙\"},{\"wid\":\"31\",\"weather\":\"强沙尘暴\"},{\"wid\":\"53\",\"weather\":\"霾\"}]";
    private final static String key = "aaebb3e5c18fd371257a2ab6b5670efe";
    private static HttpClientUtil httpClientUtil = new HttpClientUtil();
    /**
     * 获取天气实况数据
     * @param city  要查询的城市名称/id,城市名称如:温州、上海、北京,需要utf8 urlencode
     * @return
     */
    public static Realtime queryNowWeather(String city){
        if(ToolUtil.isEmpty(city)){
            return null;
        }
        String url = "http://apis.juhe.cn/simpleWeather/query?city=" + city + "&key=" + key;
        HttpResult httpResult = null;
        try {
            httpResult = httpClientUtil.pushHttpRequset("GET", url, null, null, "json");
        } catch (Exception e) {
            e.printStackTrace();
        }
        if(httpResult.getCode() != 200){
            logger.debug("查询天气失败:" + httpResult.getData());
            return null;
        }
        String data = httpResult.getData();
        JSONObject jsonObject = JSON.parseObject(data);
        Integer error_code = jsonObject.getInteger("error_code");
        if(0 != error_code){
            logger.debug("查询天气失败:" + jsonObject.getString("reason"));
            return null;
        }
        Realtime realtime = jsonObject.getObject("realtime", Realtime.class);
        return realtime;
    }
    /**
     * 查询是否是恶劣天气
     * @param city
     * @return
     */
    public static boolean isBadWeather(String city){
        if(null == city){
            return false;
        }
        Realtime realtime = queryNowWeather(city);
        if(null == realtime){
            return false;
        }
        String wid = realtime.getWid();
        JSONArray badWeather = JSON.parseArray(bad_weather);
        for (int i = 0; i < badWeather.size(); i++) {
            JSONObject jsonObject = badWeather.getJSONObject(i);
            String wid1 = jsonObject.getString("wid");
            if(wid.equals(wid1)){
                return true;
            }
        }
        return false;
    }
    /**
     * 获取支持城市列表
     * @return
     */
    public static List<WeatherCityInfo> queryCityList(){
        String url = "http://apis.juhe.cn/simpleWeather/cityList?key=" + key;
        HttpResult httpResult = null;
        try {
            httpResult = httpClientUtil.pushHttpRequset("GET", url, null, null, "json");
        } catch (Exception e) {
            e.printStackTrace();
        }
        if(httpResult.getCode() != 200){
            logger.debug("查询支持城市失败:" + httpResult.getData());
            return null;
        }
        String data = httpResult.getData();
        JSONObject jsonObject = JSON.parseObject(data);
        Integer error_code = jsonObject.getInteger("error_code");
        if(0 != error_code){
            logger.debug("查询支持城失败:" + jsonObject.getString("reason"));
            return null;
        }
        JSONArray result = jsonObject.getJSONArray("result");
        List<WeatherCityInfo> weatherCities = result.toJavaList(WeatherCityInfo.class);
        return weatherCities;
    }
}
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/mongodb/MongoUtils.java
New file
@@ -0,0 +1,166 @@
package com.stylefeng.guns.modular.system.util.mongodb;
import com.alibaba.fastjson.JSONObject;
import com.mongodb.BasicDBObject;
import com.mongodb.client.AggregateIterable;
import com.mongodb.client.MongoCursor;
import com.stylefeng.guns.modular.system.util.mongodb.model.Location;
import com.stylefeng.guns.modular.system.util.mongodb.model.LocationQuery;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.Map.Entry;
import java.util.function.Supplier;
@Component
public class MongoUtils<T> {
    @Autowired
    private MongoTemplate mongoTemplate;
    /**
     * lambda
     * @param data 添加数据
     * @param collectionName 表名
     */
    public void insert(Supplier<T> data,String collectionName){
        mongoTemplate.insert(data.get(),collectionName);
    }
    public void insert(Object data, String collectionName){
        mongoTemplate.insert(data,collectionName);
    }
    /**
     *
     * @param sp 查询条件lambda
     * @param sets 更新的字段
     * @param collectionName 表名
     */
    public void update(Supplier<Criteria> sp, Supplier<Map<String,Object>> sets, String collectionName){
        Query query = Query.query(sp.get());
        Update update = new Update();
        sets.get().forEach((key,value) ->{
            //System.out.println(key);
            //System.out.println(value);
            update.set(key,value);
        });
        mongoTemplate.updateFirst(query, update, collectionName);
    }
    public void update(Criteria sp, Supplier<Map<String,Object>> sets, String collectionName){
        Query query = Query.query(sp);
        Update update = new Update();
        sets.get().forEach((key,value) ->{
            //System.out.println(key);
            //System.out.println(value);
            update.set(key,value);
        });
        mongoTemplate.updateFirst(query, update, collectionName);
    }
    /**lambda
     * @param sp 查询条件lambda
     * @param collectionName 表名
     * @return
     */
    public List<T> query(Supplier<Criteria> sp, String collectionName, Class entityClass){
        Query query = Query.query(sp.get());
        List<T> ts = mongoTemplate.find(query,entityClass,collectionName);
        return ts;
    }
    public List<T> query(Criteria sp, String collectionName, Class entityClass){
        Query query = Query.query(sp);
        List<T> ts = mongoTemplate.find(query,entityClass,collectionName);
        return ts;
    }
    /**
     * @param sp 查询条件lambda
     * @param collectionName 表名
     * @return
     */
    public void delete(Supplier<Criteria> sp, String collectionName){
        Query query = Query.query(sp.get());
        mongoTemplate.remove(query, collectionName);
    }
    public void delete(Criteria sp, String collectionName){
        Query query = Query.query(sp);
        mongoTemplate.remove(query, collectionName);
    }
    /**
     * 查询符合条件总条数
     * @return
     * @throws Exception
     */
    public long findLogCount(HashMap<String,Object> paras,Class entityClass,String collectionName) throws Exception {
        Query query = new Query();
        Criteria criteria = new Criteria();
        if (null != paras ) {
            Iterator<Entry<String, Object>> iterator = paras.entrySet().iterator();
            while(iterator.hasNext()) {
                Entry<String, Object> entry = iterator.next();
                String key = entry.getKey();
                Object value =  entry.getValue();
                criteria.and(key).is(value);
            }
            query.addCriteria(criteria);
        }
        long count = mongoTemplate.count(query, entityClass,collectionName);
        return count;
    }
    /**
     * 查询附近的对象
     * @param model
     * @return
     */
    public List<Location> geoNear(LocationQuery model){
        List<Location> resultList = new ArrayList<>();
        try{
            List<BasicDBObject> pipeLine = new ArrayList<>();
            BasicDBObject aggregate = new BasicDBObject("$geoNear",
                    new BasicDBObject("near"
                            , new BasicDBObject("type", "Point")
                            .append("coordinates", model.getCoordinates()))
                            .append("distanceField", "distance")
                            .append("maxDistance", model.getDistance())
                            .append("spherical", true)
            );
            pipeLine.add(aggregate);
            AggregateIterable<Document> location = mongoTemplate.getCollection("location").aggregate(pipeLine);
            MongoCursor<Document> cursor = location.iterator();
            //将查询的结果,封装成对象返回出去
            while (cursor.hasNext()) {
                org.bson.Document document = cursor.next();
                Location node = JSONObject.parseObject(JSONObject.toJSONString(document),Location.class);
                resultList.add(node);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return resultList;
    }
}
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/mongodb/model/GeoJson.java
New file
@@ -0,0 +1,9 @@
package com.stylefeng.guns.modular.system.util.mongodb.model;
import lombok.Data;
@Data
public class GeoJson {
    private String type;
    private Double[] coordinates;
}
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/mongodb/model/Location.java
New file
@@ -0,0 +1,50 @@
package com.stylefeng.guns.modular.system.util.mongodb.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
import org.springframework.data.mongodb.core.index.CompoundIndex;
import org.springframework.data.mongodb.core.mapping.Document;
import java.io.Serializable;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "driver_location")
@CompoundIndex(name = "location_index", def = "{'location': '2dsphere'}")
public class Location implements Serializable {
    private static final long serialVersionUID = 4508868382007529970L;
    @Id
    private String id;
    /**
     * 司机id
     */
    private Integer driverId;
    /**
     * x:经度 y:纬度
     */
    private GeoJsonPoint location;
    /**
     * 位置名称
     **/
    private String name;
    /**
     * 创建时间
     */
    private Long created;
    /**
     * 更新时间
     */
    private Long updated;
    /**
     * 上次更新时间
     */
    private Long lastUpdated;
}
management/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/mongodb/model/LocationQuery.java
New file
@@ -0,0 +1,23 @@
package com.stylefeng.guns.modular.system.util.mongodb.model;
import lombok.Data;
@Data
public class LocationQuery {
    /**
     * 当前经纬度[xxx,xxx]
     **/
    private Double[] coordinates;
    /**
     * 距离,如:200,500,1,3,5,10,20
     **/
    private Double distance;
    /**
     * 距离单位,如:m,km
     **/
    private String unit;
    /**
     * 位置类型:1-景点,2-加油站,3-酒店
     **/
    private Integer type;
}
management/guns-admin/src/main/resources/application.yml
@@ -77,6 +77,15 @@
      - dataSourceGuns
      - dataSourceBiz
---
spring:
  data:
    mongodb:
#      uri: mongodb://root:bv@_N36o+cTe1LpS@127.0.0.1:27017/admin
      uri: mongodb://127.0.0.1:27017/admin
---
filePath: /usr/local/server/app/orderPostionFile/ #存储订单轨迹文件路径
management/guns-admin/src/main/webapp/static/modular/system/tOrder/tOrder_info.js
@@ -71,15 +71,19 @@
    }
    //提交信息
    var ajax = new $ax(Feng.ctxPath + "/tOrder/add", function(data){
        Feng.success("添加成功!");
        window.parent.TOrder.table.refresh();
        TOrderInfoDlg.close();
        if(data.code == 200){
            Feng.success("添加成功!");
            window.parent.TOrder.table.refresh();
            TOrderInfoDlg.close();
        }else{
            Feng.error(data.msg);
        }
    },function(data){
        Feng.error("添加失败!" + data.responseJSON.message + "!");
    });
    ajax.set(this.tOrderInfoData);
    ajax.set('startAddress', JSON.stringify(TOrderInfoDlg.startAddress));
    ajax.set('endAddress', null == endAddress ? "" : JSON.stringify(TOrderInfoDlg.endAddress));
    ajax.set('endAddress', null == TOrderInfoDlg.endAddress ? "" : JSON.stringify(TOrderInfoDlg.endAddress));
    ajax.start();
}