xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/controller/XpAppUserCollectAddrController.java
@@ -1,71 +1,71 @@ //package com.xiaopeng.account.controller; // //import com.xiaopeng.account.model.dto.CollectAddrDTO; //import com.xiaopeng.account.model.query.XpUserCollectAddrListQuery; //import com.xiaopeng.account.model.vo.XpAppUserCollectAddrVO; //import com.xiaopeng.account.service.IXpAppUserCollectAddrService; //import com.xiaopeng.common.core.domain.R; //import com.xiaopeng.common.core.web.page.PageInfo; //import com.xiaopeng.unifiedverification.interceptor.XpClientCheck; //import io.swagger.annotations.ApiOperation; //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.servlet.http.HttpServletRequest; // ///** // * <p> // * 用户收藏地址 前端控制器 // * </p> // * // * @author ck // * @since 2026-04-10 // */ //@RestController //@RequestMapping("") //public class XpAppUserCollectAddrController { // // private final IXpAppUserCollectAddrService xpAppUserCollectAddrService; // // public XpAppUserCollectAddrController(IXpAppUserCollectAddrService xpAppUserCollectAddrService) { // this.xpAppUserCollectAddrService = xpAppUserCollectAddrService; // } // // // /** // * 收藏地址/取消收藏地址 // */ // @PostMapping("/api/v1/mini-program/collect/addr") // @ApiOperation(value = "收藏/取消收藏地址", tags = {"小程序-收藏/取消收藏地址"}) // @XpClientCheck(checkToken = false, checkOtpToken = true) // public R<String> collectAddr(@Validated @RequestBody CollectAddrDTO dto, HttpServletRequest request) { // // uid已通过拦截器otp校验,可以直接使用 // String uid = request.getHeader("XP-Uid"); // boolean result = xpAppUserCollectAddrService.collectAddr(dto, uid); // if (result) { // return R.ok(); // } // return R.fail(); // } // // // /** // * 获取收藏夹收藏地址列表 // */ // @PostMapping("/api/v1/mini-program/collect/addrlist") // @ApiOperation(value = "收藏夹", tags = {"小程序-获取用户收藏夹收藏地址列表"}) // @XpClientCheck(checkToken = false, checkOtpToken = true) // public R<PageInfo<XpAppUserCollectAddrVO>> collectAddrlist(@RequestBody XpUserCollectAddrListQuery query, HttpServletRequest request) { // // uid已通过拦截器otp校验,可以直接使用 // String uid = request.getHeader("XP-Uid"); // return R.ok(xpAppUserCollectAddrService.userCollectAddrList(query, uid)); // } // // // // // //} package com.xiaopeng.account.controller; import com.xiaopeng.account.model.dto.CollectAddrDTO; import com.xiaopeng.account.model.query.XpUserCollectAddrListQuery; import com.xiaopeng.account.model.vo.XpAppUserCollectAddrVO; import com.xiaopeng.account.service.IXpAppUserCollectAddrService; import com.xiaopeng.common.core.domain.R; import com.xiaopeng.common.core.web.page.PageInfo; import com.xiaopeng.unifiedverification.interceptor.XpClientCheck; import io.swagger.annotations.ApiOperation; 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.servlet.http.HttpServletRequest; /** * <p> * 用户收藏地址 前端控制器 * </p> * * @author ck * @since 2026-04-10 */ @RestController @RequestMapping("") public class XpAppUserCollectAddrController { private final IXpAppUserCollectAddrService xpAppUserCollectAddrService; public XpAppUserCollectAddrController(IXpAppUserCollectAddrService xpAppUserCollectAddrService) { this.xpAppUserCollectAddrService = xpAppUserCollectAddrService; } /** * 收藏地址/取消收藏地址 */ @PostMapping("/api/v1/mini-program/collect/addr") @ApiOperation(value = "收藏/取消收藏地址", tags = {"小程序-收藏/取消收藏地址"}) @XpClientCheck(checkToken = false, checkOtpToken = true) public R<String> collectAddr(@Validated @RequestBody CollectAddrDTO dto, HttpServletRequest request) { // uid已通过拦截器otp校验,可以直接使用 String uid = request.getHeader("XP-Uid"); boolean result = xpAppUserCollectAddrService.collectAddr(dto, uid); if (result) { return R.ok(); } return R.fail(); } /** * 获取收藏夹收藏地址列表 */ @PostMapping("/api/v1/mini-program/collect/addrlist") @ApiOperation(value = "收藏夹", tags = {"小程序-获取用户收藏夹收藏地址列表"}) @XpClientCheck(checkToken = false, checkOtpToken = true) public R<PageInfo<XpAppUserCollectAddrVO>> collectAddrlist(@RequestBody XpUserCollectAddrListQuery query, HttpServletRequest request) { // uid已通过拦截器otp校验,可以直接使用 String uid = request.getHeader("XP-Uid"); return R.ok(xpAppUserCollectAddrService.userCollectAddrList(query, uid)); } } xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/mapper/XpAppUserCollectAddrMapper.java
@@ -1,21 +1,26 @@ //package com.xiaopeng.account.mapper; // //import com.baomidou.mybatisplus.core.mapper.BaseMapper; //import com.baomidou.mybatisplus.extension.plugins.pagination.Page; //import com.xiaopeng.account.model.query.XpUserCollectAddrListQuery; //import com.xiaopeng.account.model.vo.XpAppUserCollectAddrVO; //import com.xiaopeng.api.model.account.XpAppUserCollectAddr; //import org.apache.ibatis.annotations.Param; // // ///** // * <p> // * 用户收藏地址Mapper 接口 // * </p> // * // * @author mitao // * @since 2026-02-03 // */ //public interface XpAppUserCollectAddrMapper extends BaseMapper<XpAppUserCollectAddr> { // Page<XpAppUserCollectAddrVO> userCollectAddrPageList(@Param("page") Page<XpAppUserCollectAddrVO> page, @Param("query") XpUserCollectAddrListQuery query, @Param("uid") Long uid); //} package com.xiaopeng.account.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.xiaopeng.account.model.query.XpUserCollectAddrListQuery; import com.xiaopeng.account.model.vo.CollectAddrTargetVO; import com.xiaopeng.account.model.vo.XpAppUserCollectAddrVO; import com.xiaopeng.api.model.account.XpAppUserCollectAddr; import org.apache.ibatis.annotations.Param; /** * <p> * 用户收藏地址Mapper 接口 * </p> * * @author mitao * @since 2026-02-03 */ public interface XpAppUserCollectAddrMapper extends BaseMapper<XpAppUserCollectAddr> { Page<XpAppUserCollectAddrVO> userCollectAddrPageList(@Param("page") Page<XpAppUserCollectAddrVO> page, @Param("query") XpUserCollectAddrListQuery query, @Param("uid") Long uid); CollectAddrTargetVO selectPointCollectTarget(@Param("pointId") Long pointId); CollectAddrTargetVO selectStationCollectTarget(@Param("stationId") Long stationId); } xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/model/dto/CollectAddrDTO.java
@@ -1,25 +1,34 @@ //package com.xiaopeng.account.model.dto; // // //import io.swagger.annotations.ApiModel; //import io.swagger.annotations.ApiModelProperty; //import lombok.Data; // //import javax.validation.constraints.NotNull; // //@Data //@ApiModel("收藏地址/取消收藏参数") //public class CollectAddrDTO { // // @ApiModelProperty("1=收藏 2=取消收藏") // @NotNull(message = "类型不能为空") // private Integer type; // // @ApiModelProperty(value = "经度") // @NotNull(message = "经度不能为空") // private Double longitude; // // @ApiModelProperty(value = "纬度") // @NotNull(message = "纬度不能为空") // private Double latitude; //} package com.xiaopeng.account.model.dto; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import javax.validation.constraints.NotNull; @Data @ApiModel("收藏地址/取消收藏参数") public class CollectAddrDTO { @ApiModelProperty("1=收藏 2=取消收藏") @NotNull(message = "类型不能为空") private Integer type; @ApiModelProperty("收藏对象类型 1=站点 2=场站,不传时默认按站点处理") private Integer itemType; @ApiModelProperty(value = "经度") @NotNull(message = "经度不能为空") private Double longitude; @ApiModelProperty(value = "纬度") @NotNull(message = "纬度不能为空") private Double latitude; @ApiModelProperty(value = "站点id") private Long pointId; @ApiModelProperty("场站id。收藏/取消收藏场站时传入") private Long stationId; } xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/model/query/XpUserCollectAddrListQuery.java
@@ -1,11 +1,11 @@ //package com.xiaopeng.account.model.query; // //import com.xiaopeng.common.core.web.page.BasePage; //import io.swagger.annotations.ApiModel; //import lombok.Data; // //@Data //@ApiModel(value = "用户收藏地址列表查询参数") //public class XpUserCollectAddrListQuery extends BasePage { // //} package com.xiaopeng.account.model.query; import com.xiaopeng.common.core.web.page.BasePage; import io.swagger.annotations.ApiModel; import lombok.Data; @Data @ApiModel(value = "用户收藏地址列表查询参数") public class XpUserCollectAddrListQuery extends BasePage { } xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/service/IXpAppUserCollectAddrService.java
@@ -1,39 +1,39 @@ //package com.xiaopeng.account.service; // //import com.baomidou.mybatisplus.extension.service.IService; //import com.xiaopeng.account.model.dto.CollectAddrDTO; //import com.xiaopeng.account.model.query.XpUserCollectAddrListQuery; //import com.xiaopeng.account.model.vo.XpAppUserCollectAddrVO; //import com.xiaopeng.api.model.account.XpAppUserCollectAddr; //import com.xiaopeng.common.core.web.page.PageInfo; // ///** // * <p> // * 用户收藏地址 服务类 // * </p> // * // * @author ck // * @since 2026-04-10 // */ //public interface IXpAppUserCollectAddrService extends IService<XpAppUserCollectAddr> { // // // /** // * 收藏地址 // * // * @param dto // * @param uid // * @return // */ // Boolean collectAddr(CollectAddrDTO dto, String uid); // // // /** // * 收藏地址分页列表 // * // * @param uid // * @return // */ // PageInfo<XpAppUserCollectAddrVO> userCollectAddrList(XpUserCollectAddrListQuery query, String uid); // //} package com.xiaopeng.account.service; import com.baomidou.mybatisplus.extension.service.IService; import com.xiaopeng.account.model.dto.CollectAddrDTO; import com.xiaopeng.account.model.query.XpUserCollectAddrListQuery; import com.xiaopeng.account.model.vo.XpAppUserCollectAddrVO; import com.xiaopeng.api.model.account.XpAppUserCollectAddr; import com.xiaopeng.common.core.web.page.PageInfo; /** * <p> * 用户收藏地址 服务类 * </p> * * @author ck * @since 2026-04-10 */ public interface IXpAppUserCollectAddrService extends IService<XpAppUserCollectAddr> { /** * 收藏地址 * * @param dto * @param uid * @return */ Boolean collectAddr(CollectAddrDTO dto, String uid); /** * 收藏地址分页列表 * * @param uid * @return */ PageInfo<XpAppUserCollectAddrVO> userCollectAddrList(XpUserCollectAddrListQuery query, String uid); } xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/service/impl/XpAppUserCollectAddrServiceImpl.java
New file @@ -0,0 +1,138 @@ package com.xiaopeng.account.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.xiaopeng.account.mapper.XpAppUserCollectAddrMapper; import com.xiaopeng.account.model.dto.CollectAddrDTO; import com.xiaopeng.account.model.query.XpUserCollectAddrListQuery; import com.xiaopeng.account.model.vo.CollectAddrTargetVO; import com.xiaopeng.account.model.vo.XpAppUserCollectAddrVO; import com.xiaopeng.account.service.IXpAppUserCollectAddrService; import com.xiaopeng.api.model.account.XpAppUserCollectAddr; import com.xiaopeng.common.core.exception.ServiceException; import com.xiaopeng.common.core.web.page.PageInfo; import org.springframework.stereotype.Service; /** * <p> * 用户收藏地址 服务实现类 * </p> * * @author ck * @since 2026-04-10 */ @Service public class XpAppUserCollectAddrServiceImpl extends ServiceImpl<XpAppUserCollectAddrMapper, XpAppUserCollectAddr> implements IXpAppUserCollectAddrService { private static final int COLLECT_TYPE_ADD = 1; private static final int COLLECT_TYPE_CANCEL = 2; private static final int ITEM_TYPE_STATION = 2; private static final int COLLECT_LIMIT = 50; /** * 收藏地址。 * 收藏表显式保存 item_type / station_id: * 1. 站点收藏:item_type=1,point_id 保存站点自身。 * 2. 场站收藏:item_type=2,station_id 保存场站id,point_id 保存代表点位id。 * 这样取消收藏、列表回显和后续扩展都不需要再做隐式推断。 */ @Override public Boolean collectAddr(CollectAddrDTO dto, String uid) { Long userId = Long.parseLong(uid); CollectAddrTargetVO target = resolveCollectTarget(dto); if (target == null || target.getPointId() == null || target.getItemType() == null) { throw new ServiceException("收藏目标不存在"); } LambdaQueryWrapper<XpAppUserCollectAddr> sameTargetWrapper = buildSameTargetWrapper(userId, target); if (COLLECT_TYPE_ADD == dto.getType()) { Long count = this.count(new LambdaQueryWrapper<XpAppUserCollectAddr>() .eq(XpAppUserCollectAddr::getAppUserId, userId) .eq(XpAppUserCollectAddr::getDeleted, 0)); if (count >= COLLECT_LIMIT) { throw new ServiceException("收藏夹已满,请先删除旧地址"); } if (this.count(sameTargetWrapper) > 0) { return true; } XpAppUserCollectAddr collectAddr = new XpAppUserCollectAddr(); collectAddr.setAppUserId(userId); collectAddr.setItemType(target.getItemType()); collectAddr.setPointId(target.getPointId()); collectAddr.setStationId(target.getStationId()); collectAddr.setLongitude(target.getLongitude()); collectAddr.setLatitude(target.getLatitude()); return this.save(collectAddr); } if (COLLECT_TYPE_CANCEL == dto.getType()) { XpAppUserCollectAddr collectAddr = this.getOne(sameTargetWrapper.last("limit 1")); if (collectAddr == null) { return true; } return this.removeById(collectAddr.getId()); } throw new ServiceException("不支持的操作类型"); } /** * 收藏地址列表。 * 列表查询直接联表回显,场站/站点通过 item_type 直接区分。 */ @Override public PageInfo<XpAppUserCollectAddrVO> userCollectAddrList(XpUserCollectAddrListQuery query, String uid) { Page<XpAppUserCollectAddrVO> page = new Page<>(query.getPageNum(), query.getPageSize()); Page<XpAppUserCollectAddrVO> pageData = this.baseMapper.userCollectAddrPageList(page, query, Long.parseLong(uid)); PageInfo<XpAppUserCollectAddrVO> resultPage = new PageInfo<>(query.getPageNum(), query.getPageSize()); resultPage.setTotal(pageData.getTotal()); resultPage.setRecords(pageData.getRecords()); return resultPage; } /** * 将前端传入的站点/场站目标解析成统一收藏目标。 * 优先按 itemType 判断,未传时兼容旧逻辑按 pointId 处理。 */ private CollectAddrTargetVO resolveCollectTarget(CollectAddrDTO dto) { if (isStationItem(dto)) { if (dto.getStationId() == null) { throw new ServiceException("场站id不能为空"); } return this.baseMapper.selectStationCollectTarget(dto.getStationId()); } if (dto.getPointId() == null && dto.getStationId() != null) { return this.baseMapper.selectStationCollectTarget(dto.getStationId()); } if (dto.getPointId() == null) { throw new ServiceException("站点id不能为空"); } return this.baseMapper.selectPointCollectTarget(dto.getPointId()); } /** * 收藏唯一键规则: * 1. 站点收藏按 user_id + item_type + point_id 去重。 * 2. 场站收藏按 user_id + item_type + station_id 去重。 * point_id 在场站收藏里仍保留,方便联动现有“已收藏点位”能力。 */ private LambdaQueryWrapper<XpAppUserCollectAddr> buildSameTargetWrapper(Long userId, CollectAddrTargetVO target) { LambdaQueryWrapper<XpAppUserCollectAddr> wrapper = new LambdaQueryWrapper<XpAppUserCollectAddr>() .eq(XpAppUserCollectAddr::getAppUserId, userId) .eq(XpAppUserCollectAddr::getDeleted, 0) .eq(XpAppUserCollectAddr::getItemType, target.getItemType()); if (target.getItemType() == ITEM_TYPE_STATION) { wrapper.eq(XpAppUserCollectAddr::getStationId, target.getStationId()); } else { wrapper.eq(XpAppUserCollectAddr::getPointId, target.getPointId()); } return wrapper; } private boolean isStationItem(CollectAddrDTO dto) { return dto.getItemType() != null && dto.getItemType() == ITEM_TYPE_STATION; } } xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/operation/XpPoint.java
@@ -26,7 +26,7 @@ @Accessors(chain = true) @TableName("xp_point") @ApiModel(value="XpPoint对象", description="点位管理") public class XpPoint extends c { public class XpPoint extends BaseModel { private static final long serialVersionUID = 1L; xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/controller/HttpTestController.java
New file @@ -0,0 +1,36 @@ package com.xiaopeng.vehicleConvoy.controller; import com.xiaopeng.common.core.domain.R; import com.xiaopeng.vehicleConvoy.util.MinistryOfTransport; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; @RestController @RequestMapping("/") public class HttpTestController { @Resource private MinistryOfTransport ministryOfTransport; /** * 测试上传数据接口 * 用于验证上传数据的准确性 * 模拟交通部接口 */ @ResponseBody @RequestMapping("/base/v0.1/testPush") public R<String> testPush(){ try { String token = ministryOfTransport.getToken(); return R.ok(token); }catch (Exception e){ e.printStackTrace(); return R.fail(e.getMessage()); } } } xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/util/MinistryOfTransport.java
New file @@ -0,0 +1,109 @@ package com.xiaopeng.vehicleConvoy.util; import cn.hutool.core.io.FileUtil; import cn.hutool.crypto.digest.MD5; import cn.hutool.http.HttpRequest; import cn.hutool.http.HttpResponse; import cn.hutool.http.HttpUtil; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson2.JSON; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; /** * 交通部接口对接 */ @Slf4j @Component public class MinistryOfTransport { /** * 公司名称:广州易点智慧出行科技有限公司 * * 平台简称:“有鹏出行” * 标识:XPQCB67N * key:gEhROt7lg4DEBanR * * 对接ip:127.0.0.1,125.71.236.64,47.98.173.145,116.62.136.48,39.108.249.22,47.105.208.135,47.112.126.81,114.55.179.11,39.170.77.50,120.26.242.215 * * 接口地址:https://wycapi.jtj.gz.gov.cn/api/app/common/binapi */ private final String companyId = "4401XPQCB67N";//公司标识 private final String platform = "XPQC"; private final String key = "gEhROt7lg4DEBanR"; private final String url = "https://wycapi.jtj.gz.gov.cn/api/app/common/binapi"; private final String filePath = "src/main/resources/files/"; /** * 获取token * @return */ public String getToken(){ //通过上传文件的方式获取token String format = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS")); String fileName = platform + "_TOKEN_ACCESS_REQ_" + format + ".json"; File file = FileUtil.file(filePath + fileName); if(!file.exists()){ file.getParentFile().mkdirs(); try { file.createNewFile(); } catch (IOException e) { throw new RuntimeException(e); } } JSONObject body = new JSONObject(); JSONArray items = new JSONArray(); JSONObject jsonObject = new JSONObject(); jsonObject.put("platform", platform); jsonObject.put("key", key); items.add(jsonObject); body.put("items", items); file = FileUtil.writeUtf8String(body.toJSONString(), file); String md5 = MD5.create().digestHex(file); HttpRequest post = HttpUtil.createPost(url); post.header("binfile-md5", md5); // post.header("binfile-auth", "5cd4be8cf03842a6b4c3246011e3482e"); post.header("binfile-gzip", "false"); post.header("binfile-reqlen", file.length() + ""); post.header("Transfer-Encoding", "chunked"); post.contentType("multipart/form-data;boundary=inputstream"); post.header("Connection", "Keep-Alive"); post.form("binFile", file); post.form("filename", fileName); log.info("获取token请求url {}", url); log.info("获取token请求header {}", JSON.toJSONString(post.headers())); log.info("获取token请求参数 {}", FileUtil.readUtf8String(file)); log.info("获取token请求body {}", JSON.toJSONString(post.form())); HttpResponse execute = post.execute(); if(!execute.isOk()){ log.info("获取token失败:{} {}", execute.getStatus(), execute.body()); return execute.body(); } InputStream inputStream = execute.bodyStream(); //读取inputStream流转成file文件 File resultFile = FileUtil.file(filePath + "token_response_" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS")) + ".json"); resultFile.getParentFile().mkdirs(); FileUtil.writeFromStream(inputStream, resultFile); String responseContent = FileUtil.readUtf8String(resultFile); log.info("获取token成功 {}", responseContent); return responseContent; } }