OpenApiController.java 4.19 KB
package com.diligrp.rider.controller;

import com.diligrp.rider.common.exception.BizException;
import com.diligrp.rider.common.result.Result;
import com.diligrp.rider.dto.DeliveryFeeCalcDTO;
import com.diligrp.rider.dto.OpenDeliveryFeeCalcDTO;
import com.diligrp.rider.dto.OpenRouteCalcDTO;
import com.diligrp.rider.entity.OpenApp;
import com.diligrp.rider.service.DeliveryFeeService;
import com.diligrp.rider.service.OpenAppService;
import com.diligrp.rider.service.amap.AmapRouteClient;
import com.diligrp.rider.util.GeoUtil;
import com.diligrp.rider.vo.DeliveryFeeResultVO;
import com.diligrp.rider.vo.RouteCalcVO;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

import java.util.Optional;

/**
 * 开放平台对外接口
 * 路径前缀 /api/open/** 受 OpenApiInterceptor 签名鉴权保护
 * 第三方系统需携带 X-App-Key / X-Timestamp / X-Nonce / X-Sign 请求头
 */
@RestController
@RequestMapping("/api/open")
@RequiredArgsConstructor
public class OpenApiController {

    private final DeliveryFeeService deliveryFeeService;
    private final OpenAppService openAppService;
    private final AmapRouteClient amapRouteClient;

    /**
     * 计算配送费(对外开放版)
     * cityId 由 AppKey 绑定的租户自动确定,不信任外部传参
     */
    @PostMapping("/delivery/fee/calc")
    public Result<DeliveryFeeResultVO> calcFee(@Valid @RequestBody OpenDeliveryFeeCalcDTO dto,
                                               HttpServletRequest request) {
        DeliveryFeeCalcDTO calcDTO = new DeliveryFeeCalcDTO();
        calcDTO.setCityId(resolveCityId(request));
        calcDTO.setOrderType(dto.getOrderType());
        calcDTO.setStartLng(dto.getStartLng());
        calcDTO.setStartLat(dto.getStartLat());
        calcDTO.setEndLng(dto.getEndLng());
        calcDTO.setEndLat(dto.getEndLat());
        calcDTO.setWeight(dto.getWeight());
        calcDTO.setPieces(dto.getPieces());
        calcDTO.setServiceTime(dto.getServiceTime());
        return Result.success(deliveryFeeService.calcFee(calcDTO));
    }

    /**
     * 检查城市服务是否开通
     * cityId 由 AppKey 绑定的租户自动确定
     */
    @GetMapping("/delivery/check")
    public Result<Boolean> check(@RequestParam int orderType, HttpServletRequest request) {
        return Result.success(deliveryFeeService.isServiceEnabled(resolveCityId(request), orderType));
    }

    /**
     * 路线计算:传入起止经纬度,返回距离(米)与导航耗时(秒)。
     * - distance 始终有值:优先高德电动车路径距离,失败时回退到直线距离
     * - duration 高德未命中时为 null
     */
    @PostMapping("/route/calc")
    public Result<RouteCalcVO> routeCalc(@Valid @RequestBody OpenRouteCalcDTO dto) {
        Optional<AmapRouteClient.AmapRoute> route = amapRouteClient.getElectrobikeRoute(
                dto.getStartLng(), dto.getStartLat(), dto.getEndLng(), dto.getEndLat());
        if (route.isPresent()) {
            return Result.success(new RouteCalcVO(route.get().distanceMeters(), route.get().durationSeconds()));
        }
        double km;
        try {
            km = GeoUtil.calcDistanceKm(
                    Double.parseDouble(dto.getStartLat()),
                    Double.parseDouble(dto.getStartLng()),
                    Double.parseDouble(dto.getEndLat()),
                    Double.parseDouble(dto.getEndLng()));
        } catch (Exception e) {
            throw new BizException("起止经纬度格式错误");
        }
        int distanceMeters = (int) Math.round(km * 1000);
        return Result.success(new RouteCalcVO(distanceMeters, null));
    }

    private Long resolveCityId(HttpServletRequest request) {
        String appKey = request.getHeader("X-App-Key");
        OpenApp app = openAppService.getByAppKey(appKey);
        if (app == null || app.getStatus() != 1) {
            throw new BizException("应用不存在或已禁用");
        }
        if (app.getCityId() == null || app.getCityId() < 1) {
            throw new BizException("该应用未绑定租户,请联系平台管理员");
        }
        return app.getCityId();
    }
}