package com.ltgk.boat.controller;


import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.ltgk.boat.domain.dto.ArrivedPortDTO;
import com.ltgk.boat.domain.dto.FindPointListByTwoPointDTO;
import com.ltgk.boat.domain.dto.GetRegressPortDTO;
import com.ltgk.boat.domain.entity.DsBoatData;
import com.ltgk.boat.domain.entity.DsEnterPort;
import com.ltgk.boat.domain.entity.DsRegressPort;
import com.ltgk.boat.domain.vo.PointListByTwoPointVO;
import com.ltgk.boat.service.DsBoatDataService;
import com.ltgk.boat.service.IDsEnterPortService;
import com.ltgk.boat.service.IDsRegressPortService;
import com.ltgk.boat.utils.AStarPathfinder;
import com.ltgk.boat.utils.ComputeGreatCircle;
import com.ltgk.boat.utils.GeoJsonLandChecker;
import com.ltgk.boat.utils.JudgePointInArea;
import com.ltgk.common.annotation.Log;
import com.ltgk.common.core.controller.BaseController;
import com.ltgk.common.core.domain.AjaxResult;
import com.ltgk.common.core.page.TableDataInfo;
import com.ltgk.common.enums.BusinessType;
import com.ltgk.common.enums.DsMainAreaMarkTypeEnums;
import com.ltgk.common.enums.WarnAreaInfoAreaTypeEnums;
import com.ltgk.common.utils.DateUtils;
import com.ltgk.common.utils.SecurityUtils;
import com.ltgk.common.utils.StringUtils;
import com.ltgk.common.utils.poi.ExcelUtil;
import com.ltgk.common.validation.groups.Add;
import com.ltgk.common.validation.groups.Detail;
import com.ltgk.common.validation.groups.Update;
import com.ltgk.port.domain.entity.DsMainArea;
import com.ltgk.port.domain.entity.WarnAreaInfo;
import com.ltgk.port.domain.vo.ParkedAreaForAppVO;
import com.ltgk.port.service.IDsMainAreaService;
import com.ltgk.port.service.WarnAreaInfoService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import net.sf.geographiclib.Geodesic;
import net.sf.geographiclib.GeodesicData;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.Point;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import static com.ltgk.common.core.domain.AjaxResult.DATA_TAG;

/**
 * 归港指引通知表 (DsRegressPort) Controller控制器
 *
 * @author Qi ChengBin
 * @date 2025-06-03
 */
@RestController
@RequestMapping("/fishingPort/regressPort")
@Api(tags = "归港指引")
public class DsRegressPortController extends BaseController {
    @Resource
    private IDsRegressPortService dsRegressPortService;
    @Resource
    private IDsEnterPortService dsEnterPortService;
    @Resource
    private IDsMainAreaService dsMainAreaService;
    @Resource
    private DsBoatDataService dsBoatDataService;
    @Resource
    private WarnAreaInfoService warnAreaInfoService;

    @Value("${china.yuhuan}")
    private String yuhuan;

    /**
     * 分页查询归港指引通知表列表
     * 接口权限: fishingPort:regressPort:page
     *
     * @param req: 归港指引通知表 实体对象
     * @return com.ltgk.common.core.page.TableDataInfo
     * @author Qi ChengBin
     * @date 2025-06-03
     */
    @PostMapping("/page")
    @ApiOperation(value = "分页查询归港指引通知表列表")
    public TableDataInfo page(@RequestBody DsRegressPort req) {
        LambdaQueryWrapper<DsRegressPort> wrapper = getLambdaQueryWrapperByReq(req);
        startPage(req.getPageNum(), req.getPageSize());
        List<DsRegressPort> list = dsRegressPortService.list(wrapper);
        return getDataTable(list);
    }

    /**
     * 获取归港指引通知表详细数据
     * 接口权限: fishingPort:regressPort:detail
     *
     * @param req: 归港指引通知表 实体对象
     * @return com.ltgk.common.core.domain.AjaxResult
     * @author Qi ChengBin
     * @date 2025-06-03
     */
    @PostMapping(value = "/detail")
    @ApiOperation(value = "获取归港指引通知表详细数据")
    public AjaxResult detail(@Validated(Detail.class) @RequestBody DsRegressPort req) {
        return AjaxResult.success(dsRegressPortService.getById(req.getId()));
    }

    /**
     * 新增归港指引通知表数据
     * 接口权限: fishingPort:regressPort:add
     *
     * @param dsRegressPort: 归港指引通知表实体对象
     * @return com.ltgk.common.core.domain.AjaxResult
     * @author Qi ChengBin
     * @date 2025-06-03
     */
    @Log(title = "新增归港指引通知表数据", businessType = BusinessType.INSERT)
    @PostMapping("/add")
    @ApiOperation(value = "新增归港指引通知表数据")
    public AjaxResult add(@Validated(Add.class) @RequestBody DsRegressPort dsRegressPort) {
        String userName = SecurityUtils.getLoginUser().getUser().getNickName();
        dsRegressPort.setCreateBy(userName)
                .setCreateAt(new Date())
                .setUpdateBy(userName)
                .setUpdateAt(new Date());
        return toAjax(dsRegressPortService.save(dsRegressPort));
    }

    /**
     * 修改归港指引通知表数据
     * 接口权限: fishingPort:regressPort:edit
     *
     * @param dsRegressPort: 归港指引通知表实体对象
     * @return com.ltgk.common.core.domain.AjaxResult
     * @author Qi ChengBin
     * @date 2025-06-03
     */
    @Log(title = "修改归港指引通知表", businessType = BusinessType.UPDATE)
    @PostMapping("/edit")
    @ApiOperation(value = "修改归港指引通知表数据")
    public AjaxResult edit(@Validated(Update.class) @RequestBody DsRegressPort dsRegressPort) {
        String userName = SecurityUtils.getLoginUser().getUser().getNickName();
        dsRegressPort.setUpdateBy(userName)
                .setUpdateAt(new Date());
        return toAjax(dsRegressPortService.updateById(dsRegressPort));
    }

    /**
     * 删除归港指引通知表数据
     * 接口权限: fishingPort:regressPort:remove
     *
     * @param req: 归港指引通知表 实体对象
     * @return com.ltgk.common.core.domain.AjaxResult
     * @author Qi ChengBin
     * @date 2025-06-03
     */
    @Log(title = "删除归港指引通知表数据", businessType = BusinessType.DELETE)
    @PostMapping("/delete")
    @ApiOperation(value = "删除归港指引通知表数据")
    public AjaxResult delete(@Validated(Detail.class) @RequestBody DsRegressPort req) {
        return toAjax(dsRegressPortService.removeById(req.getId()));
    }

    /**
     * 导出归港指引通知表数据
     * 接口权限: fishingPort:regressPort:export
     *
     * @param response:
     * @param req:      归港指引通知表 实体对象
     * @author Qi ChengBin
     * @date 2025-06-03
     */
    @Log(title = "导出归港指引通知表数据", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    @ApiOperation(value = "导出归港指引通知表数据")
    public void export(HttpServletResponse response, DsRegressPort req) {
        LambdaQueryWrapper<DsRegressPort> wrapper = getLambdaQueryWrapperByReq(req);
        List<DsRegressPort> list = dsRegressPortService.list(wrapper);
        ExcelUtil<DsRegressPort> util = new ExcelUtil<>(DsRegressPort.class);
        util.exportExcel(response, list, "归港指引通知表数据");
    }

    /**
     * 根据请求参数转换成 LambdaQueryWrapper
     *
     * @param req: 归港指引通知表 实体对象
     * @return com.ltgk.common.core.page.TableDataInfo
     * @author Qi ChengBin
     * @date 2025-06-03
     */
    private static LambdaQueryWrapper<DsRegressPort> getLambdaQueryWrapperByReq(DsRegressPort req) {
        req.queryCheck();
        String startTime = req.getStartTime();
        String endTime = req.getEndTime();
        boolean beNotBlankTime = StringUtils.isNotBlank(startTime) && StringUtils.isNotBlank(endTime);
        return new LambdaQueryWrapper<>(req)
                .between(beNotBlankTime, DsRegressPort::getNoticeTime, startTime, endTime);
    }

    /**
     * 根据起点的点位数据和终点的点位数据获取之间一定间隔下的坐标，用来做到导航信息
     * -- 1. 计算大圆航线
     * -- 2. 加载陆地数据
     * -- 3. 检测是否经过陆地
     * ---- 4. 未经过陆地 -> 大圆航线则未航线路径
     * ---- 4. 经过陆地
     * ------ 5. A* 算法规划新路径
     * ------ 5. 平滑路径
     *
     * @param dto: 查询两个点之间的航线的请求参数
     * @return com.ltgk.common.core.domain.AjaxResult
     * @author Qi ChengBin
     * @date 2025/5/26
     */
    @PostMapping("/findPointListByTwoPoint")
    public AjaxResult findPointListByTwoPoint(@RequestBody FindPointListByTwoPointDTO dto) {
        // 判断是否在3海里海岸线内
        boolean pointInThreeNauticalMile = this.isPointInThreeNauticalMile(dto);

        // 判断是否在泊区内
        boolean pointInRegressPort = false;

        // 靠港状态
        int regressPortStatus = 2;

        // 航线数据
        List<ParkedAreaForAppVO.Point> nauticalRouteList = Collections.emptyList();

        if (!pointInThreeNauticalMile) {
            // 不在3海里海岸线内 返回大圆航线
            nauticalRouteList = ComputeGreatCircle.computeGreatCircle(
                    // 纬度
                    dto.getStartPoint().getLatitude(),
                    // 经度
                    dto.getStartPoint().getLongitude(),
                    // 纬度
                    dto.getEndPoint().getLatitude(),
                    // 经度
                    dto.getEndPoint().getLongitude(),
                    // 间隔 1000米
                    1000);
        } else {
            // 在3海里海岸线内，判断点位是否在泊区内；在返回true ，不在返回 false
            pointInRegressPort = this.isPointInRegressPort(dto);
            regressPortStatus = dsRegressPortService.lambdaQuery()
                    .eq(DsRegressPort::getEnterPortId, dto.getEnterPortId())
                    .last("limit 1")
                    .one()
                    .getRegressPortStatus();
            if (regressPortStatus != 3) {
                // 靠港状态：1-待靠港，2-靠港中，3-已靠港  在不是已靠港的时候进行更新更新时间，定时任务修改靠港状态使用
                dsRegressPortService.lambdaUpdate()
                        .eq(DsRegressPort::getEnterPortId, dto.getEnterPortId())
                        .set(DsRegressPort::getUpdateBy, SecurityUtils.getLoginUser().getUser().getNickName())
                        .set(DsRegressPort::getUpdateAt, new Date())
                        .update();
            }
            if (!pointInRegressPort) {
                // TODO： 在3海里之内， 并且不在泊区内 根据航道进行返回  TODO：此处暂时使用大圆航线替代
                nauticalRouteList = ComputeGreatCircle.computeGreatCircle(
                        // 纬度
                        dto.getStartPoint().getLatitude(),
                        // 经度
                        dto.getStartPoint().getLongitude(),
                        // 纬度
                        dto.getEndPoint().getLatitude(),
                        // 经度
                        dto.getEndPoint().getLongitude(),
                        // 间隔 1000米
                        1000);
            }
        }

        // 根据航线数据 获取 时间
        String beArrivedTime = this.getBeArrivedTime(nauticalRouteList, dto);

        PointListByTwoPointVO vo = new PointListByTwoPointVO()
                // 在3海里海岸线内 返回 true
                .setBePointInThreeNauticalMile(pointInThreeNauticalMile)
                // 航线
                .setNauticalRouteList(nauticalRouteList)
                // 返回是否在泊区内，在泊区内 返回 true
                .setBeArrivedStatus(pointInRegressPort)
                // 靠港状态
                .setRegressPortStatus(regressPortStatus)
                // 所需时间
                .setBeArrivedTime(beArrivedTime);
        return success(vo);
    }

    /**
     * 根据航线数据获取当前点位到终点的时间
     *
     * @param nauticalRouteList : 航线数据
     * @param dto:              查询两个点之间的航线的请求参数
     * @return java.lang.String
     * @author Qi ChengBin
     * @date 2025/6/3
     */
    private String getBeArrivedTime(List<ParkedAreaForAppVO.Point> nauticalRouteList, FindPointListByTwoPointDTO dto) {

        if (CollectionUtils.isEmpty(nauticalRouteList) || nauticalRouteList.size() < 2) {
            // 无效航线直接返回0
            return "1分钟";
        }

        Geodesic geod = Geodesic.WGS84;
        double totalDistanceMeters = 0.0;

        // 遍历相邻航点计算分段距离
        for (int i = 0; i < nauticalRouteList.size() - 1; i++) {
            ParkedAreaForAppVO.Point p1 = nauticalRouteList.get(i);
            ParkedAreaForAppVO.Point p2 = nauticalRouteList.get(i + 1);

            // 计算两点间的大圆距离（单位：米）
            GeodesicData seg = geod.Inverse(
                    p1.getLatitude(), p1.getLongitude(),
                    p2.getLatitude(), p2.getLongitude()
            );
            totalDistanceMeters += seg.s12;
        }

        // 假设当前船速为10节  1节 = 1852米/h
        double speedKnots = 10;

        // 计算时间（小时）
        final double METERS_PER_NAUTICAL_MILE = 1852;
        // 分钟数据
        double timeDouble = totalDistanceMeters / (speedKnots * METERS_PER_NAUTICAL_MILE) / 60.0;
        String resTime;
        if (timeDouble < 1.00) {
            // 低于1分钟 展示1分钟
            resTime = "1分钟";
        } else if (timeDouble >= 60.00) {
            // 转换为小时
            timeDouble = timeDouble / 60.00;
            int hours = (int) Math.floor(timeDouble);
            String minutes = String.format("%.2f", (timeDouble - hours) * 60.00);
            resTime = hours + "小时" + minutes + "分钟";
        } else {
            resTime = String.format("%.2f", timeDouble) + "分钟";
        }
        // 将时间 保留小数点后两位
        return resTime;
    }

    /**
     * 判断当前点位是否在三海里之内
     *
     * @param dto:
     * @return boolean
     * @author Qi ChengBin
     * @date 2025/5/30
     */
    private boolean isPointInThreeNauticalMile(FindPointListByTwoPointDTO dto) {
        // 获取三海里数据
        WarnAreaInfo warnAreaInfo = warnAreaInfoService.lambdaQuery()
                .eq(WarnAreaInfo::getAreaType, WarnAreaInfoAreaTypeEnums.THREE_NAUTICAL_MILE_AREA.getCode())
                .one();

        // 1. 解析区域字符串
        String[] points = warnAreaInfo.getPoints().split(";");
        // 判断点位是否在区域内  判断点位是否在区域内 point in area
        return JudgePointInArea.judgePointInArea(dto.getStartPoint(), points);
    }

    /**
     * 判断点位是否在泊区内
     *
     * @param dto:
     * @return boolean
     * @author Qi ChengBin
     * @date 2025/6/3
     */
    private boolean isPointInRegressPort(FindPointListByTwoPointDTO dto) {
        // 获取推荐停泊区域
        DsMainArea dsMainArea = dsMainAreaService.getById(dto.getParkedAreaId());

        // 修正JSON数组格式
        String positionInfo = dsMainArea.getPositionInfo();
        if (!positionInfo.startsWith("[") && !positionInfo.endsWith("]")) {
            positionInfo = "[" + positionInfo + "]";
        }

        JSONArray jsonArray = JSONUtil.parseArray(positionInfo);
        String[] points = jsonArray.stream()
                .map(obj -> (JSONObject) obj)
                .map(obj -> obj.getDouble("x") + "," + obj.getDouble("y"))
                .toArray(String[]::new);
        // 判断点位是否在区域内  判断点位是否在区域内 point in area
        return JudgePointInArea.judgePointInArea(dto.getStartPoint(), points);
    }

    /**
     * 获取推荐泊区接口
     *
     * @param dto: 根据进港主键获取泊区推荐接口数据传输参数
     * @return com.ltgk.common.core.domain.AjaxResult
     * @author Qi ChengBin
     * @date 2025/5/26
     */
    @PostMapping("/getRegressPort")
    public AjaxResult getRegressPort(@RequestBody GetRegressPortDTO dto) {
        DsRegressPort dbDsRegressPort = dsRegressPortService.lambdaQuery()
                .eq(DsRegressPort::getEnterPortId, dto.getEnterPortId())
                .last("limit 1")
                .one();

        if (Objects.nonNull(dbDsRegressPort) && !dbDsRegressPort.getRegressPortStatus().equals(1)) {
            // 是前往停泊状态时，不可修改推荐泊区
            DsMainArea regressPort = dsMainAreaService.lambdaQuery()
                    .eq(DsMainArea::getId, dbDsRegressPort.getParkedAreaId())
                    .last("limit 1")
                    .one();
            regressPort.setCenter(dsMainAreaService.assembledCenter(regressPort));
            regressPort.setNowBoatCount(dsMainAreaService.getParkedAreaBoatNum(regressPort.getPositionInfo()));
            return success(regressPort);
        } else {
            return regressPortData(dto);
        }
    }

    private AjaxResult regressPortData(GetRegressPortDTO dto) {
        DsMainArea regressPort;
        // 不是前往停泊状态时，可以更换推荐泊区
        // 从数据库获取进港信息
        DsEnterPort dsEnterPort = dsEnterPortService.getById(dto.getEnterPortId());

        // 根据进港信息获取泊区信息
        List<DsMainArea> dsMainAreaList = dsMainAreaService.lambdaQuery()
                .eq(DsMainArea::getMarkType, DsMainAreaMarkTypeEnums.PORT.getCode())
                .eq(DsMainArea::getPortId, dsEnterPort.getPortId())
                .list();
        if (CollectionUtils.isEmpty(dsMainAreaList)) {
            return error("暂无泊区推荐");
        }

        // 获取渔船的功率
        DsBoatData dsBoatData = dsBoatDataService.lambdaQuery()
                .eq(DsBoatData::getBoatId, dsEnterPort.getBoatId())
                .one();
        // 获取渔船的功率
        BigDecimal power = dsBoatData.getMainPower();
        if (power == null) {
            return error("暂无渔船功率信息，无法进行泊区推荐");
        }

        List<DsMainArea> regressPortList = dsMainAreaList.stream()
                .filter(dsMainArea -> dsMainArea.getMinPower().compareTo(power) <= 0 && dsMainArea.getMaxPower().compareTo(power) > 0)
                .collect(Collectors.toList());

        if (CollectionUtils.isEmpty(regressPortList)) {
            return error("暂无符合渔船功率泊区信息，无法进行泊区推荐");
        }

        if (regressPortList.size() == 1) {
            regressPort = regressPortList.get(0);
        } else {
            // 多个停泊区域时，根据当前泊区停泊了多少渔船来进行判断，选择停泊少的泊区; 如果泊区当前停泊渔船数量相同，则获取第一个泊区
            int minBoatCount = Integer.MAX_VALUE;
            List<DsMainArea> minBoatCountAreas = new ArrayList<>();

            for (DsMainArea area : regressPortList) {
                int currentCount = Integer.parseInt(dsMainAreaService.getParkedAreaBoatNum(area.getPositionInfo()));
                area.setNowBoatCount(String.valueOf(currentCount));
                if (currentCount < minBoatCount) {
                    minBoatCount = currentCount;
                    minBoatCountAreas.clear();
                    minBoatCountAreas.add(area);
                } else if (currentCount == minBoatCount) {
                    minBoatCountAreas.add(area);
                }
            }
            // 不同的泊区停泊渔船数量相同，则获取第一个
            regressPort = minBoatCountAreas.get(0);
        }
        regressPort.setCenter(dsMainAreaService.assembledCenter(regressPort));

        // 获取泊区数据之后更新归港指引通知表
        dsRegressPortService.lambdaUpdate()
                .eq(DsRegressPort::getEnterPortId, dto.getEnterPortId())
                .set(DsRegressPort::getParkedAreaId, regressPort.getId())
                .set(DsRegressPort::getParkedAreaName, regressPort.getMarkName())
                .update();
        return success(regressPort);
    }

    /**
     * 重新获取泊区推荐
     *
     * @param dto:
     * @return com.ltgk.common.core.domain.AjaxResult
     * @author Qi ChengBin
     * @date 2025/6/10
     */
    @PostMapping("/anewGetRegressPort")
    public AjaxResult anewGetRegressPort(@RequestBody GetRegressPortDTO dto) {
        DsRegressPort dbDsRegressPort = dsRegressPortService.lambdaQuery()
                .eq(DsRegressPort::getEnterPortId, dto.getEnterPortId())
                .last("limit 1")
                .one();

        AjaxResult regressPortData = regressPortData(dto);

        if (regressPortData.isSuccess() && dbDsRegressPort.getParkedAreaId().equals(((DsMainArea) regressPortData.get(DATA_TAG)).getId())) {
            return error("当前泊区为最优泊区");
        } else {
            return regressPortData;
        }
    }

    /**
     * 前往停泊，修改状态接口
     * -- 将状态修改为靠港中
     *
     * @param dto:
     * @return com.ltgk.common.core.domain.AjaxResult
     * @author Qi ChengBin
     * @date 2025/6/9
     */
    @PostMapping("/goToTheMooring")
    public AjaxResult goToTheMooring(@RequestBody GetRegressPortDTO dto) {
        return toAjax(dsRegressPortService.lambdaUpdate()
                .eq(DsRegressPort::getEnterPortId, dto.getEnterPortId())
                // 设置靠港状态为靠港中
                .set(DsRegressPort::getRegressPortStatus, 2)
                .update());
    }

    @PostMapping("/test")
    public AjaxResult test(@RequestBody FindPointListByTwoPointDTO dto) throws Exception {

        // 计算大圆航线
        List<ParkedAreaForAppVO.Point> initialPath = ComputeGreatCircle.computeGreatCircle(
                // 纬度
                dto.getStartPoint().getLatitude(),
                // 经度
                dto.getStartPoint().getLongitude(),
                // 纬度
                dto.getEndPoint().getLatitude(),
                // 经度
                dto.getEndPoint().getLongitude(), 1000);

        GeometryFactory geometryFactory = new GeometryFactory();
        // 创建 Point 对象
        Point start = geometryFactory.createPoint(new Coordinate(dto.getStartPoint().getLatitude(), dto.getStartPoint().getLongitude()));
        Point end = geometryFactory.createPoint(new Coordinate(dto.getEndPoint().getLatitude(), dto.getEndPoint().getLongitude()));

        // 加载陆地数据
        GeoJsonLandChecker geoJsonLandChecker = new GeoJsonLandChecker(yuhuan);
        // 3. 检查路径是否经过陆地
        boolean hasLand = initialPath.stream().anyMatch(p -> geoJsonLandChecker.isLand(p.getLongitude(), p.getLatitude()));

//        // 4. 如果存在陆地则重新规划路径
        List<Point> finalPath;
        if (hasLand) {
            AStarPathfinder pathfinder = new AStarPathfinder(geoJsonLandChecker);
            finalPath = pathfinder.findPath(start, end);
            logger.info("存在陆地，重新规划路径>>>>>><<<<<::::{}", finalPath);
        } else {
            finalPath = null;
        }
        return success(finalPath);
    }

    /**
     * 移动端手动点击 我已到港按钮
     *
     * @param dto: 移动端点击我已到港按钮数据传输参数
     * @return com.ltgk.common.core.domain.AjaxResult
     * @author Qi ChengBin
     * @date 2025/6/4
     */
    @PostMapping("/arrivedPort")
    public AjaxResult arrivedPort(@RequestBody ArrivedPortDTO dto) {
        return toAjax(dsRegressPortService.lambdaUpdate()
                .eq(DsRegressPort::getEnterPortId, dto.getEnterPortId())
                .set(DsRegressPort::getRegressPortStatus, 3)
                .set(DsRegressPort::getUpdateBy, SecurityUtils.getLoginUser().getUser().getNickName())
                .set(DsRegressPort::getUpdateAt, new Date())
                .update());
    }

    // 定时任务更新 我已到港状态   表中更新时间 在5分钟之前，状态为2 的数据
    @Scheduled(cron = "0 0/5 * * * ?")
    public void updateArrivedPortStatus() {
        dsRegressPortService.lambdaUpdate()
                .eq(DsRegressPort::getRegressPortStatus, 2)
                .lt(DsRegressPort::getUpdateAt, DateUtils.addMinutes(new Date(), -5))
                .set(DsRegressPort::getRegressPortStatus, 3)
                .set(DsRegressPort::getUpdateBy, "SYS")
                .set(DsRegressPort::getUpdateAt, new Date())
                .update();
    }

}

