增加配件主单下的服务主单退单逻辑 增加商品列表按距离排序

This commit is contained in:
cb 2025-06-20 11:20:03 +08:00
parent 037b1b5b5e
commit 708d2f12f5
4 changed files with 353 additions and 22 deletions

View File

@ -11,6 +11,9 @@ import java.util.List;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import com.ghy.common.utils.LocationUtils;
import java.util.stream.Collectors;
import java.util.Comparator;
/** /**
* 店铺管理接口 * 店铺管理接口
@ -125,23 +128,23 @@ public class ShopController extends BaseController {
return AjaxResult.success(shops); return AjaxResult.success(shops);
} }
/** // /**
* 通过地址获取经纬度坐标 // * 通过地址获取经纬度坐标
*/ // */
@PostMapping("/getCoordinates") // @PostMapping("/getCoordinates")
public AjaxResult getCoordinatesByAddress(@RequestBody Shop shop) { // public AjaxResult getCoordinatesByAddress(@RequestBody Shop shop) {
try { // try {
Map<String, Double> coordinates = getCoordinatesByAddress(shop); // Map<String, Double> coordinates = getCoordinatesByAddress(shop);
if (coordinates != null) { // if (coordinates != null) {
return AjaxResult.success("获取坐标成功", coordinates); // return AjaxResult.success("获取坐标成功", coordinates);
} else { // } else {
return AjaxResult.error("无法获取该地址的坐标信息"); // return AjaxResult.error("无法获取该地址的坐标信息");
} // }
} catch (Exception e) { // } catch (Exception e) {
logger.error("获取坐标失败: {}", e.getMessage(), e); // logger.error("获取坐标失败: {}", e.getMessage(), e);
return AjaxResult.error("获取坐标失败: " + e.getMessage()); // return AjaxResult.error("获取坐标失败: " + e.getMessage());
} // }
} // }
/** /**
* 通过经纬度逆解析获取地址信息并保存到店铺 * 通过经纬度逆解析获取地址信息并保存到店铺
@ -329,4 +332,160 @@ public class ShopController extends BaseController {
return AjaxResult.error("查询失败: " + e.getMessage()); return AjaxResult.error("查询失败: " + e.getMessage());
} }
} }
/**
* 查询附近的店铺
*/
@PostMapping("/nearby")
public AjaxResult getNearbyShops(@RequestBody Map<String, Object> params) {
try {
Double latitude = Double.valueOf(params.get("latitude").toString());
Double longitude = Double.valueOf(params.get("longitude").toString());
Double radiusKm = params.containsKey("radiusKm") ?
Double.valueOf(params.get("radiusKm").toString()) : 5.0; // 默认5公里
// 验证坐标有效性
if (!LocationUtils.isValidCoordinate(latitude, longitude)) {
return AjaxResult.error("无效的坐标参数");
}
// 获取所有店铺
List<Shop> allShops = shopService.listShops();
// 筛选出有坐标的店铺并计算距离
List<Map<String, Object>> nearbyShops = allShops.stream()
.filter(shop -> LocationUtils.isValidCoordinate(shop.getLatitude(), shop.getLongitude()))
.map(shop -> {
double distance = LocationUtils.getDistanceInKilometers(
latitude, longitude, shop.getLatitude(), shop.getLongitude());
Map<String, Object> shopWithDistance = new HashMap<>();
shopWithDistance.put("shop", shop);
shopWithDistance.put("distance", distance);
shopWithDistance.put("distanceText", LocationUtils.formatDistance(distance * 1000));
// 计算方向
double bearing = LocationUtils.getBearing(latitude, longitude,
shop.getLatitude(), shop.getLongitude());
shopWithDistance.put("direction", LocationUtils.getDirectionDescription(bearing));
shopWithDistance.put("bearing", bearing);
return shopWithDistance;
})
.filter(shopMap -> (Double) shopMap.get("distance") <= radiusKm)
.sorted(Comparator.comparingDouble(shopMap -> (Double) shopMap.get("distance")))
.collect(Collectors.toList());
Map<String, Object> result = new HashMap<>();
result.put("centerLatitude", latitude);
result.put("centerLongitude", longitude);
result.put("radiusKm", radiusKm);
result.put("totalCount", nearbyShops.size());
result.put("shops", nearbyShops);
return AjaxResult.success("查询成功", result);
} catch (Exception e) {
logger.error("查询附近店铺失败: {}", e.getMessage(), e);
return AjaxResult.error("查询失败: " + e.getMessage());
}
}
/**
* 计算两个店铺之间的距离
*/
@PostMapping("/distance")
public AjaxResult getShopsDistance(@RequestBody Map<String, Object> params) {
try {
Long shopId1 = Long.valueOf(params.get("shopId1").toString());
Long shopId2 = Long.valueOf(params.get("shopId2").toString());
Shop shop1 = shopService.getShop(shopId1);
Shop shop2 = shopService.getShop(shopId2);
if (shop1 == null || shop2 == null) {
return AjaxResult.error("店铺不存在");
}
if (!LocationUtils.isValidCoordinate(shop1.getLatitude(), shop1.getLongitude()) ||
!LocationUtils.isValidCoordinate(shop2.getLatitude(), shop2.getLongitude())) {
return AjaxResult.error("店铺坐标信息不完整");
}
double distanceKm = LocationUtils.getDistanceInKilometers(
shop1.getLatitude(), shop1.getLongitude(),
shop2.getLatitude(), shop2.getLongitude());
double bearing = LocationUtils.getBearing(
shop1.getLatitude(), shop1.getLongitude(),
shop2.getLatitude(), shop2.getLongitude());
Map<String, Object> result = new HashMap<>();
result.put("shop1", shop1);
result.put("shop2", shop2);
result.put("distanceKm", distanceKm);
result.put("distanceText", LocationUtils.formatDistance(distanceKm * 1000));
result.put("direction", LocationUtils.getDirectionDescription(bearing));
result.put("bearing", bearing);
return AjaxResult.success("计算成功", result);
} catch (Exception e) {
logger.error("计算店铺距离失败: {}", e.getMessage(), e);
return AjaxResult.error("计算失败: " + e.getMessage());
}
}
// /**
// * 获取店铺覆盖范围内的其他店铺
// */
// @PostMapping("/coverage")
// public AjaxResult getShopsCoverage(@RequestBody Map<String, Object> params) {
// try {
// Long shopId = Long.valueOf(params.get("shopId").toString());
// Double radiusKm = params.containsKey("radiusKm") ?
// Double.valueOf(params.get("radiusKm").toString()) : 10.0; // 默认10公里
//
// Shop centerShop = shopService.getShop(shopId);
// if (centerShop == null) {
// return AjaxResult.error("店铺不存在");
// }
//
// if (!LocationUtils.isValidCoordinate(centerShop.getLatitude(), centerShop.getLongitude())) {
// return AjaxResult.error("中心店铺坐标信息不完整");
// }
//
// // 获取附近的店铺
// Map<String, Object> nearbyParams = new HashMap<>();
// nearbyParams.put("latitude", centerShop.getLatitude());
// nearbyParams.put("longitude", centerShop.getLongitude());
// nearbyParams.put("radiusKm", radiusKm);
//
// AjaxResult nearbyResult = getNearbyShops(nearbyParams);
// if (nearbyResult.isSuccess()) {
// Map<String, Object> data = (Map<String, Object>) nearbyResult.get("data");
// List<Map<String, Object>> shops = (List<Map<String, Object>>) data.get("shops");
//
// // 排除自己
// shops = shops.stream()
// .filter(shopMap -> {
// Shop shop = (Shop) shopMap.get("shop");
// return !shop.getShopId().equals(shopId);
// })
// .collect(Collectors.toList());
//
// data.put("centerShop", centerShop);
// data.put("shops", shops);
// data.put("totalCount", shops.size());
//
// return AjaxResult.success("查询成功", data);
// } else {
// return nearbyResult;
// }
//
// } catch (Exception e) {
// logger.error("查询店铺覆盖范围失败: {}", e.getMessage(), e);
// return AjaxResult.error("查询失败: " + e.getMessage());
// }
// }
} }

View File

@ -10,8 +10,11 @@ import com.ghy.common.utils.ShiroUtils;
import com.ghy.common.utils.StringUtils; import com.ghy.common.utils.StringUtils;
import com.ghy.common.utils.bean.BeanUtils; import com.ghy.common.utils.bean.BeanUtils;
import com.ghy.common.utils.poi.ExcelUtil; import com.ghy.common.utils.poi.ExcelUtil;
import com.ghy.common.utils.LocationUtils;
import com.ghy.goods.domain.*; import com.ghy.goods.domain.*;
import com.ghy.goods.service.*; import com.ghy.goods.service.*;
import com.ghy.shop.domain.Shop;
import com.ghy.shop.service.ShopService;
import com.ghy.system.domain.SysArea; import com.ghy.system.domain.SysArea;
import com.ghy.system.service.ISysAreaService; import com.ghy.system.service.ISysAreaService;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
@ -51,6 +54,8 @@ public class GoodsController extends BaseController {
private IInsuranceManagerService insuranceManagerService; private IInsuranceManagerService insuranceManagerService;
@Resource @Resource
private IDeptCategoryInsuranceRelationService deptCategoryInsuranceRelationService; private IDeptCategoryInsuranceRelationService deptCategoryInsuranceRelationService;
@Resource
private ShopService shopService;
@RequiresPermissions("goods:goods:view") @RequiresPermissions("goods:goods:view")
@GetMapping() @GetMapping()
@ -168,6 +173,11 @@ public class GoodsController extends BaseController {
if (type==null){ if (type==null){
goods.setType(1); goods.setType(1);
} }
// 获取用户当前位置
Double userLatitude = goods.getLatitude();
Double userLongitude = goods.getLongitude();
// 判断类目id是否为第三级不是的话需要找到所有符合条件的第三级类目id作为新的条件 // 判断类目id是否为第三级不是的话需要找到所有符合条件的第三级类目id作为新的条件
if (goods.getDeptGoodsCategoryId() != null) { if (goods.getDeptGoodsCategoryId() != null) {
logger.info("入参:" + goods.getDeptGoodsCategoryId()); logger.info("入参:" + goods.getDeptGoodsCategoryId());
@ -210,6 +220,10 @@ public class GoodsController extends BaseController {
List<Goods> list = goodsService.selectGoodsList(goods); List<Goods> list = goodsService.selectGoodsList(goods);
logger.info("传入的类目id汇总{},获取到的所有商品{}",goods.getDeptGoodsCategoryIds(),list); logger.info("传入的类目id汇总{},获取到的所有商品{}",goods.getDeptGoodsCategoryIds(),list);
// 用于缓存店铺信息避免重复查询
Map<Long, Shop> shopCache = new HashMap<>();
list.forEach(one -> { list.forEach(one -> {
// 补全商品服务区域 // 补全商品服务区域
List<GoodsArea> goodsAreas = goodsAreaService.selectByGoodsId(one.getGoodsId()); List<GoodsArea> goodsAreas = goodsAreaService.selectByGoodsId(one.getGoodsId());
@ -227,10 +241,89 @@ public class GoodsController extends BaseController {
one.setParGoodsCategoryId(parGoodsCategory.getGoodsCategoryId()); one.setParGoodsCategoryId(parGoodsCategory.getGoodsCategoryId());
one.setParGoodsCategoryName(parGoodsCategory.getGoodsCategoryName()); one.setParGoodsCategoryName(parGoodsCategory.getGoodsCategoryName());
} }
// 计算距离逻辑
if (LocationUtils.isValidCoordinate(userLatitude, userLongitude) && one.getShopId() != null) {
try {
// 从缓存获取店铺信息避免重复查询
Shop shop = shopCache.computeIfAbsent(one.getShopId(),
shopId -> shopService.getShop(shopId));
if (shop != null && LocationUtils.isValidCoordinate(shop.getLatitude(), shop.getLongitude())) {
// 计算距离
double distanceInMeters = LocationUtils.getDistanceInMeters(
userLatitude, userLongitude,
shop.getLatitude(), shop.getLongitude()
);
// 格式化距离并设置到商品对象
one.setDistance(LocationUtils.formatDistance(distanceInMeters));
logger.debug("商品[{}]距离用户: {}", one.getGoodsName(), one.getDistance());
} else {
// 店铺坐标不完整
one.setDistance(null);
}
} catch (Exception e) {
logger.warn("计算商品[{}]距离失败: {}", one.getGoodsName(), e.getMessage());
// 计算异常时设为null
one.setDistance(null);
}
} else {
// 用户未提供位置或商品无店铺信息
one.setDistance(null);
}
}); });
// 如果用户提供了位置信息按距离排序距离为null的排在最后
if (LocationUtils.isValidCoordinate(userLatitude, userLongitude)) {
list.sort((goods1, goods2) -> {
String distance1 = goods1.getDistance();
String distance2 = goods2.getDistance();
// 距离为null的排在最后
if (distance1 == null && distance2 == null) return 0;
if (distance1 == null) return 1;
if (distance2 == null) return -1;
// 解析距离数值进行比较
try {
double dist1 = parseDistanceToMeters(distance1);
double dist2 = parseDistanceToMeters(distance2);
return Double.compare(dist1, dist2);
} catch (Exception e) {
// 解析失败时保持原顺序
return 0;
}
});
logger.info("已按距离排序,用户位置: 纬度={}, 经度={}", userLatitude, userLongitude);
}
return getDataTable(list); return getDataTable(list);
} }
/**
* 解析距离字符串为米数用于排序
*/
private double parseDistanceToMeters(String distanceText) {
if (distanceText == null || distanceText.trim().isEmpty()) {
return Double.MAX_VALUE;
}
try {
if (distanceText.endsWith("")) {
return Double.parseDouble(distanceText.replace("", ""));
} else if (distanceText.endsWith("公里")) {
return Double.parseDouble(distanceText.replace("公里", "")) * 1000;
}
} catch (NumberFormatException e) {
logger.warn("无法解析距离字符串: {}", distanceText);
}
return Double.MAX_VALUE;
}
@PostMapping("/hot/list") @PostMapping("/hot/list")
@ResponseBody @ResponseBody
public TableDataInfo hotList(@RequestBody Goods goods) { public TableDataInfo hotList(@RequestBody Goods goods) {

View File

@ -1760,25 +1760,94 @@ public class OrderMasterController extends BaseController {
* */ * */
@PostMapping("/console/cancel") @PostMapping("/console/cancel")
@ResponseBody @ResponseBody
@Transactional(rollbackFor = Exception.class)
public AjaxResult consoleCancel(Long id) { public AjaxResult consoleCancel(Long id) {
if(id == null){ if(id == null){
return AjaxResult.error("订单编码id不能为空!"); return AjaxResult.error("订单编码id不能为空!");
} }
// 判断该主单状态 // 判断该主单状态
OrderMaster orderMaster = orderMasterService.selectById(id); OrderMaster orderMaster = orderMasterService.selectById(id);
if(!orderMaster.getOrderStatus().equals(OrderStatus.PLAIN.code()) && !orderMaster.getOrderStatus().equals(OrderStatus.RECEIVE.code())){ if(!orderMaster.getOrderStatus().equals(OrderStatus.PLAIN.code()) && !orderMaster.getOrderStatus().equals(OrderStatus.RECEIVE.code())){
return AjaxResult.error("该订单处于无法退单状态!"); return AjaxResult.error("该订单处于无法退单状态!");
} }
// 含有子单 // 含有子单
List<OrderDetail> orderDetails = orderDetailService.selectByOrderMasterId(id); List<OrderDetail> orderDetails = orderDetailService.selectByOrderMasterId(id);
if(CollectionUtils.isNotEmpty(orderDetails)){ if(CollectionUtils.isNotEmpty(orderDetails)){
return AjaxResult.error("该订单已经派发过子单,无法退单状态!"); return AjaxResult.error("该订单已经派发过子单,无法退单状态!");
} }
// 清空id
orderMasterService.removeWorker(orderMaster.getId()); try {
// 更新状态待接单 // 判断是否为服务订单且需要退还服务金额
orderMasterService.updateStatus(orderMaster.getId(), OrderStatus.RECEIVE.code()); if (isServiceOrder(orderMaster) &&
return AjaxResult.success(); orderMaster.getGoodsOrderMasterId() != null &&
orderMaster.getServerGoodsMoney() != null &&
orderMaster.getServerGoodsMoney().compareTo(BigDecimal.ZERO) > 0) {
logger.info("检测到服务订单退单,开始退还服务金额:订单[{}],金额[{}],目标商品订单[{}]",
orderMaster.getId(), orderMaster.getServerGoodsMoney(), orderMaster.getGoodsOrderMasterId());
// 退还服务金额到商品订单
refundServerMoneyToGoodsOrder(orderMaster.getGoodsOrderMasterId(), orderMaster.getServerGoodsMoney());
}
// 清空id
orderMasterService.removeWorker(orderMaster.getId());
// 更新状态待接单
orderMasterService.updateStatus(orderMaster.getId(), OrderStatus.RECEIVE.code());
return AjaxResult.success("退单成功");
} catch (Exception e) {
logger.error("退单失败订单ID={}, 错误信息={}", id, e.getMessage(), e);
return AjaxResult.error("退单失败:" + e.getMessage());
}
}
/**
* 判断是否为服务订单
*/
private boolean isServiceOrder(OrderMaster orderMaster) {
return orderMaster.getOrderType() != null && orderMaster.getOrderType() == 0;
}
/**
* 服务订单退单时退还服务金额给商品订单
*
* @param goodsOrderMasterId 商品订单主单ID
* @param serverGoodsMoney 需要退还的服务金额
*/
private void refundServerMoneyToGoodsOrder(Long goodsOrderMasterId, BigDecimal serverGoodsMoney) {
try {
// 1. 查询商品订单
OrderMaster goodsOrder = orderMasterService.selectById(goodsOrderMasterId);
if (goodsOrder == null) {
logger.error("商品订单不存在无法退还服务金额goodsOrderMasterId={}", goodsOrderMasterId);
throw new RuntimeException("商品订单不存在");
}
// 2. 查询商品订单的财务记录
FinancialMaster goodsFinancial = financialMasterService.selectByOrderMasterId(goodsOrderMasterId);
if (goodsFinancial == null) {
logger.error("商品订单财务记录不存在无法退还服务金额goodsOrderMasterId={}", goodsOrderMasterId);
throw new RuntimeException("商品订单财务记录不存在");
}
// 3. 更新商品订单的可用金额增加退还的服务金额
BigDecimal currentPayMoney = goodsFinancial.getPayMoney();
BigDecimal newPayMoney = currentPayMoney.add(serverGoodsMoney);
goodsFinancial.setPayMoney(newPayMoney);
financialMasterService.updateFinancialMaster(goodsFinancial);
logger.info("服务订单退单成功,已退还{}元服务金额到商品订单[{}]", serverGoodsMoney, goodsOrderMasterId);
} catch (Exception e) {
logger.error("退还服务金额失败goodsOrderMasterId={}, serverGoodsMoney={}, error={}",
goodsOrderMasterId, serverGoodsMoney, e.getMessage(), e);
throw new RuntimeException("退还服务金额失败:" + e.getMessage());
}
} }
/** /**

View File

@ -100,4 +100,14 @@ public class Goods extends BaseEntity {
private Integer type; private Integer type;
private List<InsuranceManager> insuranceManagers; private List<InsuranceManager> insuranceManagers;
private String distance;
/** 纬度 */
private Double latitude;
/** 经度 */
private Double longitude;
} }