jiangping
2025-02-18 9d67b4462bf494a0b25c1b40be8198f71666131e
jtt808初始化
已添加3个文件
已修改7个文件
350 ■■■■■ 文件已修改
server/services/src/main/java/com/doumee/core/constants/Constants.java 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/core/utils/PositionUtil.java 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/dao/business/model/MemberRides.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/dao/business/web/request/BackElecBikeRequest.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/dao/business/web/request/LocaltionDTO.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/service/business/GoodsorderService.java 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/service/business/impl/GoodsorderServiceImpl.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/service/system/impl/SystemDictDataServiceImpl.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/web/src/main/java/com/doumee/api/web/BusinessApi.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/web/src/main/java/com/doumee/jtt808/web/service/Jtt808Service.java 154 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/core/constants/Constants.java
@@ -1,6 +1,7 @@
package com.doumee.core.constants;
import ch.qos.logback.core.util.COWArrayList;
import com.doumee.dao.business.web.request.LocaltionDTO;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;
@@ -214,11 +215,7 @@
        //钉钉通知地址
        public static final String DINGDING_URL = "DINGDING_URL";
        //钉钉签名
        public static void main(String[] args) {
            double[][] polygon = {{120, 30}, {121, 30}, {121, 31}, {120, 31}}; // ç»çº¬åº¦åˆ—表表示多边形顶点
            boolean isInside = isPointInPolygon(122.5, 30.5, polygon);
            System.out.println("Is inside: " + isInside);
        }
        //小程序满载预警(%)最大值
        public static final String WARN_MAX = "WARN_MAX";
        //小程序满载预警(%)最小值
@@ -606,19 +603,6 @@
            return  Constants.formatDecimalNum(money).divide(new BigDecimal(100), 2, BigDecimal.ROUND_UP);
        }
    public static boolean isPointInPolygon(double px, double py, double[]... polygon) {
        int i, j;
        boolean result = false;
        for (i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
            if ((polygon[i][1] > py) != (polygon[j][1] > py) &&
                    (px < (polygon[j][0] - polygon[i][0]) * (py - polygon[i][1]) / (polygon[j][1] - polygon[i][1]) + polygon[i][0])) {
                result = !result;
            }
        }
        return result;
    }
}
server/services/src/main/java/com/doumee/core/utils/PositionUtil.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,72 @@
package com.doumee.core.utils;
import com.doumee.dao.business.web.request.LocaltionDTO;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
/**
 * è®¡ç®—距离
 */
public class PositionUtil {
    /**
     * åˆ¤æ–­åæ ‡ç‚¹æ˜¯å¦åœ¨å¤šè¾¹å½¢åŒºåŸŸå†…
     *
     * @param pointLon è¦åˆ¤æ–­çš„点的经度
     * @param pointLat è¦åˆ¤æ–­çš„点的纬度
     * @return true:范围内; false:范围外
     */
    public static boolean isInPolygon(double pointLon, double pointLat, List<LocaltionDTO> list) {
        if(list==null ||list.size()==0){
            return false;
        }
        double[] lon = new double[list.size()];
        double[] lat = new double[list.size()];
        for (int i = 0; i < list.size(); i++) {
            lon[i] = list.get(i).getLng() ==null?0:list.get(i).getLng();
            lat[i] = list.get(i).getLat() ==null?0:list.get(i).getLat();
        }
        // å°†è¦åˆ¤æ–­çš„æ¨ªçºµåæ ‡ç»„成一个点
        Point2D.Double point = new Point2D.Double(pointLon, pointLat);
        // å°†åŒºåŸŸå„顶点的横纵坐标放到一个点集合里面
        List<Point2D.Double> pointList = new ArrayList<>();
        double polygonPointToX;
        double polygonPointToY;
        for (int i = 0; i < lon.length; i++) {
            polygonPointToX = lon[i];
            polygonPointToY = lat[i];
            Point2D.Double polygonPoint = new Point2D.Double(polygonPointToX, polygonPointToY);
            pointList.add(polygonPoint);
        }
        return check(point, pointList);
    }
    /**
     * åæ ‡ç‚¹æ˜¯å¦åœ¨å¤šè¾¹å½¢å†…
     *
     * @param point   è¦åˆ¤æ–­çš„点的横纵坐标
     * @param polygon ç»„成的顶点坐标集合
     */
    private static boolean check(Point2D.Double point, List<Point2D.Double> polygon) {
        GeneralPath generalPath = new GeneralPath();
        Point2D.Double first = polygon.get(0);
        // é€šè¿‡ç§»åŠ¨åˆ°æŒ‡å®šåæ ‡ï¼ˆä»¥åŒç²¾åº¦æŒ‡å®šï¼‰ï¼Œå°†ä¸€ä¸ªç‚¹æ·»åŠ åˆ°è·¯å¾„ä¸­
        generalPath.moveTo(first.x, first.y);
        polygon.remove(0);
        for (Point2D.Double d : polygon) {
            // é€šè¿‡ç»˜åˆ¶ä¸€æ¡ä»Žå½“前坐标到新指定坐标(以双精度指定)的直线,将一个点添加到路径中。
            generalPath.lineTo(d.x, d.y);
        }
        // å°†å‡ ä½•多边形封闭
        generalPath.lineTo(first.x, first.y);
        generalPath.closePath();
        // æµ‹è¯•指定的 Point2D æ˜¯å¦åœ¨ Shape çš„边界内。
        return generalPath.contains(point);
    }
}
server/services/src/main/java/com/doumee/dao/business/model/MemberRides.java
@@ -164,6 +164,9 @@
    @ApiModelProperty(value = "骑行时长")
    @TableField(exist = false)
    private Integer rideTime;
    @ApiModelProperty(value = "控制器编码")
    @TableField(exist = false)
    private String deviceSn;
    @ApiModelProperty(value = "排序码(升序)", example = "1")
    @TableField(exist = false)
    private Integer sortnum;
server/services/src/main/java/com/doumee/dao/business/web/request/BackElecBikeRequest.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,30 @@
package com.doumee.dao.business.web.request;
import com.doumee.core.annotation.excel.ExcelColumn;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
/**
 * Created by IntelliJ IDEA.
 *
 * @Author : Rk
 * @create 2023/10/9 11:04
 */
@Data
@ApiModel("电车站点还车请求参数")
public class BackElecBikeRequest {
    @ApiModelProperty(value = "纬度")
    private Double latitude;
    @ApiModelProperty(value = "经度")
    private Double longitude;
    @ApiModelProperty(value = "用户编码(关联member表)",hidden = true)
    private String memberId;
}
server/services/src/main/java/com/doumee/dao/business/web/request/LocaltionDTO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,25 @@
package com.doumee.dao.business.web.request;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
 * Created by IntelliJ IDEA.
 *
 * @Author : Rk
 * @create 2023/10/9 11:04
 */
@Data
@ApiModel("定位地址对象参数")
public class LocaltionDTO {
    @ApiModelProperty(value = "纬度")
    private Double lat;
    @ApiModelProperty(value = "经度")
    private Double lng;
}
server/services/src/main/java/com/doumee/service/business/GoodsorderService.java
@@ -6,14 +6,17 @@
import com.doumee.core.model.PageWrap;
import com.doumee.dao.business.model.Bikes;
import com.doumee.dao.business.model.Goodsorder;
import com.doumee.dao.business.model.MemberRides;
import com.doumee.dao.business.vo.GoodsorderExportVO;
import com.doumee.dao.business.vo.GoodsorderTotalDataVO;
import com.doumee.dao.business.web.request.BackElecBikeRequest;
import com.doumee.dao.business.web.request.GoodsorderBackDTO;
import com.doumee.dao.business.web.request.GoodsorderCanBanlanceDTO;
import com.doumee.dao.business.web.response.HomeResponse;
import com.doumee.dao.business.web.response.GoodsorderDetailDTO;
import com.doumee.dao.business.web.response.RidesDetailResponse;
import com.wechat.pay.java.service.refund.model.RefundNotification;
import io.swagger.models.auth.In;
import java.math.BigDecimal;
import java.util.List;
@@ -147,6 +150,7 @@
     * @return
     */
    void closeGoodsorder(Goodsorder  order,int type );
    void  dealCloseGoodsorderBiz(Goodsorder goodsorder, int type, List<MemberRides> memberRides) ;
    void closeGoodsorderDone(RefundNotification param);
    void forceCloseGoodsorder(String orderId);
@@ -155,7 +159,7 @@
     * @param orderId
     */
    void backGoodsorder(GoodsorderBackDTO goodsorderBackDTO);
    List<MemberRides> getMemberRidesForClose(String orderid );
    /**
     * èŽ·å–å¯é€€æ¬¾ä¿¡æ¯
     * @param orderId
@@ -191,4 +195,5 @@
    void autoCloseOrder();
    void autoCancelRefunOrder();
}
server/services/src/main/java/com/doumee/service/business/impl/GoodsorderServiceImpl.java
@@ -89,6 +89,7 @@
    private SystemDictDataBiz systemDictDataBiz;
    @Autowired
    private MemberMapper memberMapper;
    @Autowired
@@ -531,7 +532,11 @@
        if(r != null){
            throw  new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "该订单存在退款申请正在处理中,请稍后查看订单信息哦~");
        }
        List<MemberRides> memberRides = getMemberRidesForClose(goodsorder.getId());
        List<MemberRides> memberRides = getMemberRidesForClose(goodsorder.getId());//打车骑行记录
        dealCloseGoodsorderBiz(goodsorder,type,memberRides);
    }
    @Override
    public void dealCloseGoodsorderBiz(Goodsorder goodsorder, int type, List<MemberRides> memberRides) {
        //默认结算为押金金额
        BigDecimal closeMoney = new BigDecimal(0.00);
        if (!CollectionUtils.isEmpty(memberRides)){
@@ -563,7 +568,8 @@
            closeGoodsorderDoneNoRefund(goodsorder,type,new BigDecimal(0),null,memberRides);
        }
    }
    public void closeGoodsorderDoneNoRefund(Goodsorder goodsorder,int type,BigDecimal refundMoney,String closeId,List<MemberRides> memberRides ) {
    public void closeGoodsorderDoneNoRefund(Goodsorder goodsorder,int type,BigDecimal refundMoney,String closeId,List<MemberRides> memberRides) {
        log.error("========================================"+JSONObject.toJSONString(goodsorder));
        if(goodsorder ==null || Constants.formatIntegerNum(goodsorder.getStatus()) != Constants.GOODSORDER_STATUS.HAVING_PAY.getKey()){
            return;
@@ -806,19 +812,20 @@
        return ridesDetailResponse;
    }
    private List<MemberRides> getMemberRidesForClose(String id) {
    @Override
    public List<MemberRides> getMemberRidesForClose(String id) {
        MPJLambdaWrapper<MemberRides> wrapper = new MPJLambdaWrapper<>();
        wrapper.eq(MemberRides::getOrdreId,id);
        wrapper.ne(MemberRides::getStatus,Constants.MEMBER_RIDES_STATUS.LOCKING_DEFEAT.getKey());
        wrapper.selectAll(MemberRides.class)
                .select("select b.device_sn from bikes b where b.isdeleted=0 and b.code = t.bike_code limit 1",MemberRides::getDeviceSn)
                .selectAs(BaseParam::getSortnum, MemberRides::getSortnum)
                .selectAs(BaseParam::getName, MemberRides::getParamName);
        wrapper.leftJoin(BaseParam.class, BaseParam::getId, MemberRides::getParamId);
        wrapper.orderByDesc(BaseParam::getSortnum);
        //取最高车型作为计价方案
        //查询所有骑行记录
        List<MemberRides> memberRides = memberRidesJoinMapper.selectList(wrapper);
        List<MemberRides> memberRides = memberRidesJoinMapper.selectJoinList(MemberRides.class,wrapper);
        return memberRides;
    }
@@ -1187,7 +1194,7 @@
    @Override
    public void autoCloseOrder( ) {
         Goodsorder goodsorder = new Goodsorder();
        Goodsorder goodsorder = new Goodsorder();
        goodsorder.setIsdeleted(Constants.ZERO);
        goodsorder.setStatus(Constants.goodsorderStatus.pay);
        List<Goodsorder> list = findList(goodsorder);
server/services/src/main/java/com/doumee/service/system/impl/SystemDictDataServiceImpl.java
@@ -5,6 +5,7 @@
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.doumee.core.constants.ResponseStatus;
import com.doumee.core.exception.BusinessException;
import com.doumee.dao.business.web.request.LocaltionDTO;
import com.doumee.dao.business.web.response.MiniProgrammeDTO;
import com.doumee.dao.system.SystemDictMapper;
import com.doumee.dao.system.model.SystemDict;
@@ -143,8 +144,8 @@
        try {
            if(miniProgrammeDTO.getParkLatLngList()!=null){
                try {
                    TypeReference typeReference =  new TypeReference<List<Map<String,BigDecimal>>>(){};
                    List<Map<String,BigDecimal>> response = JSONObject.parseObject(miniProgrammeDTO.getParkLatLngList(), typeReference.getType());
                    TypeReference typeReference =  new TypeReference<List<LocaltionDTO>>(){};
                    List<LocaltionDTO> response = JSONObject.parseObject(miniProgrammeDTO.getParkLatLngList(), typeReference.getType());
                }catch (Exception e){
                    e.printStackTrace();
                    throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(),"运营区域参数解析有误!");
server/web/src/main/java/com/doumee/api/web/BusinessApi.java
@@ -10,10 +10,12 @@
import com.doumee.core.model.PageData;
import com.doumee.core.model.PageWrap;
import com.doumee.dao.business.model.*;
import com.doumee.dao.business.web.request.BackElecBikeRequest;
import com.doumee.dao.business.web.request.RepairRequest;
import com.doumee.dao.business.web.response.MemberRidesDetailResponse;
import com.doumee.dao.business.web.response.RidesDetailResponse;
import com.doumee.dao.system.model.SystemDictData;
import com.doumee.jtt808.web.service.Jtt808Service;
import com.doumee.service.business.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
@@ -22,6 +24,9 @@
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.yzh.commons.model.APIResult;
import org.yzh.protocol.t808.T0201_0500;
import org.yzh.protocol.t808.T8500;
import java.util.List;
@@ -41,6 +46,8 @@
    @Autowired
    private GoodsorderService goodsorderService;
    @Autowired
    private Jtt808Service jtt808Service;
    @Autowired
    private RentSiteService rentSiteService;
@@ -188,4 +195,12 @@
    public ApiResponse<SystemDictData> getSysDict(@RequestParam String dicCode, @RequestParam String label) {
        return  ApiResponse.success("查询成功",systemDictDataBiz.queryByCode(dicCode,label));
    }
    @ApiOperation(value = "电车站点还车", notes = "电车站点还车")
    @PostMapping("/backElecBike")
    public ApiResponse backElecBike(@RequestBody BackElecBikeRequest param) {
        param.setMemberId(getMemberId());
        jtt808Service.backElecBike(param);
        return  ApiResponse.success( null);
    }
}
server/web/src/main/java/com/doumee/jtt808/web/service/Jtt808Service.java
@@ -1,23 +1,177 @@
package com.doumee.jtt808.web.service;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.doumee.biz.system.SystemDictDataBiz;
import com.doumee.core.constants.Constants;
import com.doumee.core.constants.ResponseStatus;
import com.doumee.core.exception.BusinessException;
import com.doumee.core.utils.PositionUtil;
import com.doumee.core.utils.StringTools;
import com.doumee.core.wx.WxMiniUtilService;
import com.doumee.dao.business.*;
import com.doumee.dao.business.join.GoodsorderJoinMapper;
import com.doumee.dao.business.join.MemberRidesJoinMapper;
import com.doumee.dao.business.join.RefundJoinMapper;
import com.doumee.dao.business.model.*;
import com.doumee.dao.business.web.request.BackElecBikeRequest;
import com.doumee.dao.business.web.request.LocaltionDTO;
import com.doumee.jtt808.web.endpoint.MessageManager;
import com.doumee.service.business.GoodsorderService;
import com.doumee.service.business.PricingRuleService;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;
import org.yzh.commons.model.APIResult;
import org.yzh.protocol.t808.T0201_0500;
import org.yzh.protocol.t808.T8500;
import reactor.core.publisher.Mono;
import java.util.Date;
import java.util.List;
import java.util.Objects;
@Service
public class Jtt808Service {
    @Autowired
    private MessageManager messageManager;
    @Autowired
    private GoodsorderService goodsorderService;
    @Autowired
    private DiscountMemberMapper discountMemberMapper;
    @Autowired
    private DiscountLogMapper discountLogMapper;
    @Autowired
    GoodsorderJoinMapper goodsorderJoinMapper;
    @Autowired
    private SystemDictDataBiz systemDictDataBiz;
    @Autowired
    private MemberMapper memberMapper;
    @Autowired
    private BaseParamMapper baseParamMapper;
    @Autowired
    private RefundMapper refundMapper;
    @Autowired
    private RefundJoinMapper refundJoinMapper;
    @Autowired
    private SitesMapper sitesMapper;
    @Autowired
    private MemberRidesJoinMapper memberRidesJoinMapper;
    @Autowired
    private AdMapper adMapper;
    @Autowired
    private TransactionsMapper transactionsMapper;
    @Autowired
    private WxMiniUtilService wxMiniUtilService;
    @Autowired
    PricingRuleService pricingRuleService;
    public  APIResult<T0201_0500>  bikeControl(@RequestBody T8500 request) {
        Mono<APIResult<T0201_0500>>  result = messageManager.requestR(request, T0201_0500.class);
        APIResult<T0201_0500> data = result.block();
        return  data;
    }
    @Transactional(rollbackFor = {BusinessException.class})
    public   void backElecBike(BackElecBikeRequest param) {
        if (param.getLatitude() == null || param.getLongitude() == null || StringUtils.isBlank(param.getMemberId())) {
                throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "对不起,定位信息有误,请确认定位权限已开启!");
        }
        Member member = memberMapper.selectById(param.getMemberId());
        if (member == null) {
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "对不起,您的账号信息查询失败,请返回重新进入小程序再试!");
        }
        Goodsorder gparam = new Goodsorder();
        gparam.setMemberId(param.getMemberId());
        gparam.setStatus(Constants.goodsorderStatus.pay);
        Goodsorder goodsorder =  goodsorderService.findOne(gparam);
        if(Objects.isNull(goodsorder)){
            throw new BusinessException(ResponseStatus.NO_UNCLOSEED_ORDER.getCode(),"无骑行订单记录");
        }
        if(Constants.formatIntegerNum(goodsorder.getStatus()) != Constants.GOODSORDER_STATUS.HAVING_PAY.getKey() ){
            throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"对不起,该订单当前状态不支持结算操作,请尝试刷新列表重试!" );
        }
        //查询骑行记录
        List<MemberRides>  memberRides = goodsorderService.getMemberRidesForClose(goodsorder.getId());
        if(memberRides!=null && memberRides.size()>0){
            for (MemberRides  rides : memberRides){
                if(Constants.equalsInteger(rides.getStatus(),Constants.MEMBER_RIDES_STATUS.RIDES_RUNNING.getKey())){
                    if(StringUtils.isNotBlank(rides.getDeviceSn()) &&Constants.equalsInteger(rides.getType(),Constants.ONE) ){
                        Sites site = getBackSiteByPostion(param);//查询停车站点信息
                        //如果是电车并且是骑行中 è¿›è¡Œå…³é”å¤„理
                        lockBikes(rides.getDeviceSn(),Constants.ZERO);//发起关锁指令请求
                    }
                }
            }
        }
        //订单结算
        Date date = new Date();
        goodsorder.setEditDate(date);
        goodsorder.setEditor(null);
        goodsorderService.dealCloseGoodsorderBiz( goodsorder,Constants.REFUND_TYPE.NORMAL.getKey(),memberRides);
    }
    /**
     * å‘起关锁、开锁指令请求
     * @param clientId
     */
    private void lockBikes(String clientId,int type) {
        T8500 request = new T8500();
        request.setType(type);//关锁
        request.setClientId(StringTools.leftPad(clientId,12,'0'));
        Mono<APIResult<T0201_0500>>  result = messageManager.requestR(request, T0201_0500.class);
        APIResult<T0201_0500> data = result.block();
        if(!data.isSuccess()){
            //如果开锁失败,则返回异常
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "对不起,还车关锁失败,请稍后重试,或者联系园区管理人员!");
        }
    }
    /**
     * æŸ¥è¯¢åœè½¦ç«™ç‚¹ä¿¡æ¯
     * @param param
     * @return
     */
    private Sites getBackSiteByPostion(BackElecBikeRequest param) {
        Sites site = null;//查询停车站点信息
        List<Sites> sitesList = sitesMapper.selectList(new QueryWrapper<Sites>().lambda()
                .eq(Sites::getStatus,Constants.ZERO)
                .eq(Sites::getIsdeleted,Constants.ZERO)
                .eq(Sites::getType,Constants.ONE));
        if(sitesList ==null ||sitesList.size() ==0){
            throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "对不起,请按照要求前往停车点停车!");
        }
        for(Sites sites :sitesList){
            TypeReference typeReference =  new TypeReference<List<LocaltionDTO>>(){};
            List<LocaltionDTO> array = JSONObject.parseObject(sites.getElectronicFence(), typeReference.getType());
            if(array == null || array.size() ==0){
                continue;
            }
            if(PositionUtil.isInPolygon(param.getLongitude(),param.getLatitude(),array)){
                //如果在停车点范围内;
                site = sites;
                break;
            }
            if(site ==null){
                throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "对不起,请按照要求前往停车点停车!");
            }
        }
        return site;
    }
}