1、调整微信消息推送模板业务

2、增加普通商品配送自动发单功能
3、增加核销员管理功能
4、开发配送员转单功能
5、优化送水订单查询业务
6、优化配送订单自动分配配送师傅业务
7、增加普通商品下单配送支付步梯费功能
This commit is contained in:
2026-05-25 18:08:47 +08:00
parent 18148ddb8d
commit ba3748d2f9
32 changed files with 940 additions and 72 deletions

View File

@@ -80,6 +80,7 @@ public class MybatisPlusConfig {
@Override @Override
public boolean ignoreTable(String tableName) { public boolean ignoreTable(String tableName) {
TenantContext.setIgnoreTenant(Boolean.TRUE);
// 如果当前上下文设置了忽略租户隔离,则忽略所有表的租户隔离 // 如果当前上下文设置了忽略租户隔离,则忽略所有表的租户隔离
if (TenantContext.isIgnoreTenant()) { if (TenantContext.isIgnoreTenant()) {
return true; return true;

View File

@@ -70,4 +70,11 @@ public interface UserMapper extends BaseMapper<User> {
@InterceptorIgnore(tenantLine = "true") @InterceptorIgnore(tenantLine = "true")
List<User> listByAlert(); List<User> listByAlert();
/**
* 批量查询用户信息
* @param userIdList 用户ID集合
* @return
*/
List<User> selectByUserIdList(@Param("userIdList") List<Integer> userIdList);
} }

View File

@@ -263,5 +263,22 @@
<select id="getById" resultType="com.gxwebsoft.common.system.entity.User"> <select id="getById" resultType="com.gxwebsoft.common.system.entity.User">
SELECT * FROM gxwebsoft_core.sys_user WHERE user_id = #{userId} and deleted = 0 SELECT * FROM gxwebsoft_core.sys_user WHERE user_id = #{userId} and deleted = 0
</select> </select>
<select id="selectByUserIdList" resultType="com.gxwebsoft.common.system.entity.User">
SELECT
user_id,
username,
nickname,
phone,
real_name,
create_time
FROM
gxwebsoft_core.sys_user
WHERE
deleted = 0
AND user_id IN
<foreach collection="userIdList" item="item" index="index" open="(" close=")" separator=",">
#{item}
</foreach>
</select>
</mapper> </mapper>

View File

@@ -9,6 +9,7 @@ import com.gxwebsoft.common.core.web.BatchParam;
import com.gxwebsoft.common.core.web.PageResult; import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.common.system.entity.User; import com.gxwebsoft.common.system.entity.User;
import com.gxwebsoft.common.system.mapper.UserMapper; import com.gxwebsoft.common.system.mapper.UserMapper;
import com.gxwebsoft.glt.dto.GltTransferOrderDto;
import com.gxwebsoft.glt.entity.GltTicketOrder; import com.gxwebsoft.glt.entity.GltTicketOrder;
import com.gxwebsoft.glt.param.GltTicketOrderDeliveredParam; import com.gxwebsoft.glt.param.GltTicketOrderDeliveredParam;
import com.gxwebsoft.glt.param.GltTicketOrderParam; import com.gxwebsoft.glt.param.GltTicketOrderParam;
@@ -23,6 +24,7 @@ import cn.hutool.core.util.StrUtil;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springdoc.api.annotations.ParameterObject;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@@ -56,7 +58,7 @@ public class GltTicketOrderController extends BaseController {
@Operation(summary = "分页查询送水订单") @Operation(summary = "分页查询送水订单")
@GetMapping("/page") @GetMapping("/page")
public ApiResult<PageResult<GltTicketOrder>> page(GltTicketOrderParam param) { public ApiResult<PageResult<GltTicketOrder>> page(@ParameterObject GltTicketOrderParam param) {
// 使用关联查询 // 使用关联查询
return success(gltTicketOrderService.pageRel(param)); return success(gltTicketOrderService.pageRel(param));
} }
@@ -260,6 +262,13 @@ public class GltTicketOrderController extends BaseController {
return success("接单成功"); return success("接单成功");
} }
@PreAuthorize("isAuthenticated()")
@Operation(summary = "配送员转单")
@PostMapping("/transferOrder")
public ApiResult<Boolean> transferOrder(@RequestBody GltTransferOrderDto orderDto) {
return success(gltTicketOrderService.transferOrder(orderDto));
}
@PreAuthorize("isAuthenticated()") @PreAuthorize("isAuthenticated()")
@Operation(summary = "配送员开始配送") @Operation(summary = "配送员开始配送")
@PostMapping("/{id}/start") @PostMapping("/{id}/start")

View File

@@ -0,0 +1,25 @@
package com.gxwebsoft.glt.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
/**
* 转单请求类
*
*/
@Data
@Schema(name = "ShopOrderMyVerifyDto", description = "转单请求类")
public class GltTransferOrderDto {
@Schema(description = "订单ID")
@NotEmpty(message = "订单ID不能为空")
private Integer id;
@Schema(description = "转单用户ID")
@NotEmpty(message = "转单用户ID不能为空")
private Integer userId;
}

View File

@@ -11,7 +11,7 @@
d.name as receiverName, d.phone as receiverPhone, d.name as receiverName, d.phone as receiverPhone,
d.province as receiverProvince, d.city as receiverCity, d.region as receiverRegion, d.province as receiverProvince, d.city as receiverCity, d.region as receiverRegion,
d.address as receiverAddress, d.full_address as receiverFullAddress, d.lat as receiverLat, d.lng as receiverLng, d.address as receiverAddress, d.full_address as receiverFullAddress, d.lat as receiverLat, d.lng as receiverLng,
COALESCE(o.order_no, f.order_no) as orderNo, o.order_status as orderStatus COALESCE(o.order_no, a.order_no) as orderNo, o.order_status as orderStatus
FROM glt_ticket_order a FROM glt_ticket_order a
LEFT JOIN shop_store b ON a.store_id = b.id LEFT JOIN shop_store b ON a.store_id = b.id
LEFT JOIN shop_store_warehouse w ON a.warehouse_id = w.id LEFT JOIN shop_store_warehouse w ON a.warehouse_id = w.id
@@ -88,7 +88,7 @@
AND a.create_time &lt;= #{param.createTimeEnd} AND a.create_time &lt;= #{param.createTimeEnd}
</if> </if>
<if test="param.orderNo != null"> <if test="param.orderNo != null">
AND (a.id = #{param.orderNo} OR COALESCE(o.order_no, f.order_no) = #{param.orderNo}) AND (a.id = #{param.orderNo} OR COALESCE(o.order_no, a.order_no) = #{param.orderNo})
</if> </if>
<if test="param.phone != null"> <if test="param.phone != null">
AND u.phone = #{param.phone} AND u.phone = #{param.phone}

View File

@@ -1,10 +1,7 @@
package com.gxwebsoft.glt.service; package com.gxwebsoft.glt.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.gxwebsoft.glt.entity.GltTicketTemplate; import com.gxwebsoft.glt.entity.*;
import com.gxwebsoft.glt.entity.GltUserTicket;
import com.gxwebsoft.glt.entity.GltUserTicketLog;
import com.gxwebsoft.glt.entity.GltUserTicketRelease;
import com.gxwebsoft.glt.task.DealerOrderSettlement10584Task; import com.gxwebsoft.glt.task.DealerOrderSettlement10584Task;
import com.gxwebsoft.shop.entity.ShopOrder; import com.gxwebsoft.shop.entity.ShopOrder;
import com.gxwebsoft.shop.entity.ShopOrderGoods; import com.gxwebsoft.shop.entity.ShopOrderGoods;
@@ -18,6 +15,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate; import org.springframework.transaction.support.TransactionTemplate;
import javax.annotation.Resource;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.LocalTime; import java.time.LocalTime;
@@ -37,6 +35,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
@RequiredArgsConstructor @RequiredArgsConstructor
public class GltTicketIssueService { public class GltTicketIssueService {
@Resource
private GltTicketOrderService gltTicketOrderService;
public static final int CHANGE_TYPE_ISSUE = 10; public static final int CHANGE_TYPE_ISSUE = 10;
private enum IssueOutcome { private enum IssueOutcome {
@@ -144,6 +145,9 @@ public class GltTicketIssueService {
//3.执行平台分红业务 TODO 待开发 //3.执行平台分红业务 TODO 待开发
//4.普通商品【非水票订单】如果是需要自配送的,则会同步生成派单信息
gltTicketOrderService.dispatchOrder(orderNo, tenantId);
} }
/** /**

View File

@@ -2,6 +2,7 @@ package com.gxwebsoft.glt.service;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import com.gxwebsoft.common.core.web.PageResult; import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.glt.dto.GltTransferOrderDto;
import com.gxwebsoft.glt.entity.GltTicketOrder; import com.gxwebsoft.glt.entity.GltTicketOrder;
import com.gxwebsoft.glt.param.GltTicketOrderParam; import com.gxwebsoft.glt.param.GltTicketOrderParam;
@@ -64,6 +65,13 @@ public interface GltTicketOrderService extends IService<GltTicketOrder> {
*/ */
void accept(Integer id, Integer riderId, Integer tenantId); void accept(Integer id, Integer riderId, Integer tenantId);
/**
* 配送员转单
* @param orderDto
* @return
*/
Boolean transferOrder(GltTransferOrderDto orderDto);
/** /**
* 指派/接单成功后,同步关联商城订单发货状态为“已发货”(deliveryStatus=20)。 * 指派/接单成功后,同步关联商城订单发货状态为“已发货”(deliveryStatus=20)。
* *
@@ -106,4 +114,10 @@ public interface GltTicketOrderService extends IService<GltTicketOrder> {
*/ */
int autoConfirmTimeout(Integer tenantId, LocalDateTime now, int timeoutHours, int batchSize); int autoConfirmTimeout(Integer tenantId, LocalDateTime now, int timeoutHours, int batchSize);
/**
* 派送订单调度
* @return
*/
Boolean dispatchOrder(String orderNo, Integer tenantId);
} }

View File

@@ -43,7 +43,7 @@ public class GltSubscribeMessageServiceImpl implements GltSubscribeMessageServic
* 模板名称:订单配送通知 * 模板名称:订单配送通知
* 关键词:订单编号、订单内容、配送地址、订单金额 * 关键词:订单编号、订单内容、配送地址、订单金额
*/ */
private static final String SUBSCRIBE_TEMPLATE_ID = "YOUR_TEMPLATE_ID"; // TODO: 替换为实际模板ID private static final String ORDER_DELIVERY_ID = "vSMSqGVy3aG1RuzQUZlk2y5sWiTFY_hewF5-R-uYwMk";
/** /**
* 发送新订单通知给配送员 * 发送新订单通知给配送员
@@ -196,8 +196,8 @@ public class GltSubscribeMessageServiceImpl implements GltSubscribeMessageServic
Map<String, Object> params = new HashMap<>(); Map<String, Object> params = new HashMap<>();
params.put("touser", openId); // 用户 openid params.put("touser", openId); // 用户 openid
params.put("template_id", SUBSCRIBE_TEMPLATE_ID); // 模板ID params.put("template_id", ORDER_DELIVERY_ID); // 模板ID
params.put("page", "pages/rider/orders/index"); // 点击后跳转的页面 // params.put("page", "pages/rider/orders/index"); // 点击后跳转的页面
params.put("data", data); params.put("data", data);
String response = HttpUtil.createPost(url) String response = HttpUtil.createPost(url)

View File

@@ -1,5 +1,6 @@
package com.gxwebsoft.glt.service.impl; package com.gxwebsoft.glt.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
@@ -7,11 +8,14 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.common.core.enums.ShopDealerCapitalUpdateEnum; import com.gxwebsoft.common.core.enums.ShopDealerCapitalUpdateEnum;
import com.gxwebsoft.common.core.enums.ShopDealerTypeEnum; import com.gxwebsoft.common.core.enums.ShopDealerTypeEnum;
import com.gxwebsoft.common.core.exception.BusinessException; import com.gxwebsoft.common.core.exception.BusinessException;
import com.gxwebsoft.common.core.exception.enums.GlobalErrorCodeConstants;
import com.gxwebsoft.common.core.utils.LoginUserUtil;
import com.gxwebsoft.common.core.web.PageParam; import com.gxwebsoft.common.core.web.PageParam;
import com.gxwebsoft.common.core.web.PageResult; import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.common.system.entity.User; import com.gxwebsoft.common.system.entity.User;
import com.gxwebsoft.common.system.mapper.UserMapper; import com.gxwebsoft.common.system.mapper.UserMapper;
import com.gxwebsoft.common.system.redis.OrderNoUtils; import com.gxwebsoft.common.system.redis.OrderNoUtils;
import com.gxwebsoft.glt.dto.GltTransferOrderDto;
import com.gxwebsoft.glt.entity.GltTicketOrder; import com.gxwebsoft.glt.entity.GltTicketOrder;
import com.gxwebsoft.glt.entity.GltUserTicket; import com.gxwebsoft.glt.entity.GltUserTicket;
import com.gxwebsoft.glt.entity.GltUserTicketLog; import com.gxwebsoft.glt.entity.GltUserTicketLog;
@@ -24,6 +28,7 @@ import com.gxwebsoft.glt.service.GltUserTicketService;
import com.gxwebsoft.shop.dto.ShopDealerUserReduceDto; import com.gxwebsoft.shop.dto.ShopDealerUserReduceDto;
import com.gxwebsoft.shop.entity.*; import com.gxwebsoft.shop.entity.*;
import com.gxwebsoft.shop.mapper.ShopGoodsMapper; import com.gxwebsoft.shop.mapper.ShopGoodsMapper;
import com.gxwebsoft.shop.mapper.ShopStoreRiderMapper;
import com.gxwebsoft.shop.mapper.ShopUserAddressMapper; import com.gxwebsoft.shop.mapper.ShopUserAddressMapper;
import com.gxwebsoft.shop.service.ShopDealerCapitalService; import com.gxwebsoft.shop.service.ShopDealerCapitalService;
import com.gxwebsoft.shop.service.ShopDealerUserService; import com.gxwebsoft.shop.service.ShopDealerUserService;
@@ -31,18 +36,20 @@ import com.gxwebsoft.shop.service.ShopOrderGoodsService;
import com.gxwebsoft.shop.service.ShopOrderService; import com.gxwebsoft.shop.service.ShopOrderService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate; import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.StringUtils;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@@ -97,10 +104,16 @@ public class GltTicketOrderServiceImpl extends ServiceImpl<GltTicketOrderMapper,
@Resource @Resource
private ShopGoodsMapper shopGoodsMapper; private ShopGoodsMapper shopGoodsMapper;
@Resource
private ShopStoreRiderMapper shopStoreRiderMapper;
// 轮询指针(高并发安全)
private final AtomicInteger index = new AtomicInteger(0);
@Override @Override
public PageResult<GltTicketOrder> pageRel(GltTicketOrderParam param) { public PageResult<GltTicketOrder> pageRel(GltTicketOrderParam param) {
PageParam<GltTicketOrder, GltTicketOrderParam> page = new PageParam<>(param); PageParam<GltTicketOrder, GltTicketOrderParam> page = new PageParam<>(param);
page.setDefaultOrder("sort_number asc, create_time desc"); page.setDefaultOrder("create_time desc");
List<GltTicketOrder> list = baseMapper.selectPageRel(page, param); List<GltTicketOrder> list = baseMapper.selectPageRel(page, param);
if(CollectionUtils.isNotEmpty(list)){ if(CollectionUtils.isNotEmpty(list)){
List<Integer> addressIdList = list.stream().map(GltTicketOrder::getAddressId).distinct().collect(Collectors.toList()); List<Integer> addressIdList = list.stream().map(GltTicketOrder::getAddressId).distinct().collect(Collectors.toList());
@@ -199,8 +212,13 @@ public class GltTicketOrderServiceImpl extends ServiceImpl<GltTicketOrderMapper,
gltTicketOrder.setCreateTime(now); gltTicketOrder.setCreateTime(now);
} }
// “立刻送水”下单场景不再需要前端选择配送时间;若未传则默认当前时间,便于排序与派单。 // “立刻送水”下单场景不再需要前端选择配送时间;若未传则默认当前时间,便于排序与派单。
if(gltTicketOrder.getSendEndTime() == null){
gltTicketOrder.setSendTime(now.format(SEND_TIME_FMT)); gltTicketOrder.setSendTime(now.format(SEND_TIME_FMT));
}
gltTicketOrder.setUpdateTime(now); gltTicketOrder.setUpdateTime(now);
//每个骑手平等获取派单
gltTicketOrder.setRiderId(getRiderUserId());
if (!this.save(gltTicketOrder)) { if (!this.save(gltTicketOrder)) {
throw new BusinessException("创建订单失败"); throw new BusinessException("创建订单失败");
} }
@@ -322,6 +340,27 @@ public class GltTicketOrderServiceImpl extends ServiceImpl<GltTicketOrderMapper,
throw new BusinessException("订单状态不允许接单"); throw new BusinessException("订单状态不允许接单");
} }
@Override
public Boolean transferOrder(GltTransferOrderDto orderDto) {
User loginUser = LoginUserUtil.getLoginUser();
if(loginUser == null){
throw new BusinessException(GlobalErrorCodeConstants.UNAUTHORIZED.getMsg());
}
GltTicketOrder gltTicketOrder = baseMapper.selectById(orderDto.getId());
if(gltTicketOrder != null){
if(!gltTicketOrder.getRiderId().equals(loginUser.getUserId())){
throw new BusinessException("该订单归属非本人,转单操作失败!");
}
gltTicketOrder.setRiderId(orderDto.getUserId());
gltTicketOrder.setUpdateTime(LocalDateTime.now());
return baseMapper.updateById(gltTicketOrder) > 0;
}else {
throw new BusinessException(GlobalErrorCodeConstants.NOT_FOUND.getMsg());
}
}
@Override @Override
public void markShopOrderShippedAfterRiderAssigned(Integer ticketOrderId, Integer tenantId, Integer riderId) { public void markShopOrderShippedAfterRiderAssigned(Integer ticketOrderId, Integer tenantId, Integer riderId) {
updateShopOrderDeliveryStatusAfterAccept(ticketOrderId, tenantId, riderId, LocalDateTime.now()); updateShopOrderDeliveryStatusAfterAccept(ticketOrderId, tenantId, riderId, LocalDateTime.now());
@@ -685,6 +724,49 @@ public class GltTicketOrderServiceImpl extends ServiceImpl<GltTicketOrderMapper,
return confirmed; return confirmed;
} }
@Override
public Boolean dispatchOrder(String orderNo, Integer tenantId) {
ShopOrder shopOrder = shopOrderService.getByOrderNo(orderNo, tenantId);
if(shopOrder != null){
LocalDateTime now = LocalDateTime.now();
//只有:1-及时自配送、3-预约自配送 方式会生成调度单
if(Arrays.asList(1, 3).contains(shopOrder.getOrderType())){
GltTicketOrder dispatchOrder = BeanUtil.toBean(shopOrder, GltTicketOrder.class);
String no = orderNoUtils.generate("S");
dispatchOrder.setNo(no);
dispatchOrder.setRiderId(getRiderUserId());
dispatchOrder.setSendTime(now.format(SEND_TIME_FMT));
Integer deliveryMethod = shopOrder.getDeliveryMethod();
if(deliveryMethod != null && deliveryMethod == 1){
dispatchOrder.setDeliveryMethod("stairs");
}else {
dispatchOrder.setDeliveryMethod("elevator");
}
dispatchOrder.setComments("系统自动派单");
dispatchOrder.setCreateTime(now);
dispatchOrder.setUpdateTime(now);
baseMapper.insert(dispatchOrder);
}
}
return Boolean.TRUE;
}
/**
* 每个骑手平等获取派单
* @return
*/
private Integer getRiderUserId(){
List<ShopStoreRider> shopStoreRiders = shopStoreRiderMapper.selectList(new LambdaQueryWrapper<ShopStoreRider>().select(ShopStoreRider::getUserId).in(ShopStoreRider::getWorkStatus, Arrays.asList(1, 2)));
if(CollectionUtils.isNotEmpty(shopStoreRiders)){
List<Integer> riderIdList = shopStoreRiders.stream().map(ShopStoreRider::getUserId).distinct().collect(Collectors.toList());
int i = index.getAndIncrement() % riderIdList.size();
return riderIdList.get(i);
}
return null;
}
/** /**
* 更新送水订单为已完成状态 * 更新送水订单为已完成状态
* @param ticketOrderId * @param ticketOrderId

View File

@@ -6,7 +6,6 @@ import com.gxwebsoft.shop.entity.ShopGoodsCategory;
import com.gxwebsoft.shop.param.ShopGoodsCategoryParam; import com.gxwebsoft.shop.param.ShopGoodsCategoryParam;
import com.gxwebsoft.common.core.web.ApiResult; import com.gxwebsoft.common.core.web.ApiResult;
import com.gxwebsoft.common.core.web.PageResult; import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.common.core.web.PageParam;
import com.gxwebsoft.common.core.web.BatchParam; import com.gxwebsoft.common.core.web.BatchParam;
import com.gxwebsoft.common.core.annotation.OperationLog; import com.gxwebsoft.common.core.annotation.OperationLog;
import com.gxwebsoft.common.system.entity.User; import com.gxwebsoft.common.system.entity.User;

View File

@@ -0,0 +1,96 @@
package com.gxwebsoft.shop.controller;
import com.gxwebsoft.common.core.annotation.OperationLog;
import com.gxwebsoft.common.core.web.ApiResult;
import com.gxwebsoft.common.core.web.BaseController;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.shop.entity.ShopVerifyUser;
import com.gxwebsoft.shop.param.ShopVerifyUserParam;
import com.gxwebsoft.shop.service.ShopVerifyUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
/**
* 订单核销人管理控制器
*
* @author xm
* @since 2026-05-25 17:13:01
*/
@Tag(name = "订单核销人管理管理")
@RestController
@RequestMapping("/api/shop/shop-verify-user")
public class ShopVerifyUserController extends BaseController {
@Resource
private ShopVerifyUserService shopVerifyUserService;
// @PreAuthorize("hasAuthority('shop:shopVerifyUser:list')")
@Operation(summary = "分页查询订单核销人管理")
@GetMapping("/page")
public ApiResult<PageResult<ShopVerifyUser>> page(ShopVerifyUserParam param) {
// 使用关联查询
return success(shopVerifyUserService.pageRel(param));
}
// @PreAuthorize("hasAuthority('shop:shopVerifyUser:list')")
@Operation(summary = "查询全部订单核销人管理")
@GetMapping()
public ApiResult<List<ShopVerifyUser>> list(ShopVerifyUserParam param) {
// 使用关联查询
return success(shopVerifyUserService.listRel(param));
}
// @PreAuthorize("hasAuthority('shop:shopVerifyUser:list')")
@Operation(summary = "根据id查询订单核销人管理")
@GetMapping("/{id}")
public ApiResult<ShopVerifyUser> get(@PathVariable("id") Integer id) {
// 使用关联查询
return success(shopVerifyUserService.getByIdRel(id));
}
// @PreAuthorize("hasAuthority('shop:shopVerifyUser:save')")
@OperationLog
@Operation(summary = "添加订单核销人管理")
@PostMapping()
public ApiResult<Boolean> save(@RequestBody ShopVerifyUser shopVerifyUser) {
return success(shopVerifyUserService.saveInfo(shopVerifyUser));
}
// @PreAuthorize("hasAuthority('shop:shopVerifyUser:update')")
@Operation(summary = "修改订单核销人管理")
@PutMapping()
public ApiResult<?> update(@RequestBody ShopVerifyUser shopVerifyUser) {
if (shopVerifyUserService.updateById(shopVerifyUser)) {
return success("修改成功");
}
return fail("修改失败");
}
@Operation(summary = "修改订单核销人开启状态")
@PutMapping("/updateStatus")
public ApiResult<Boolean> updateStatus(@RequestParam("id") Integer id) {
return success(shopVerifyUserService.updateStatus(id));
}
@Operation(summary = "修改订单核销人核销权限")
@PutMapping("/updateVerifyFlag")
public ApiResult<Boolean> updateVerifyFlag(@RequestParam("id") Integer id) {
return success(shopVerifyUserService.updateVerifyFlag(id));
}
// @PreAuthorize("hasAuthority('shop:shopVerifyUser:remove')")
@OperationLog
@Operation(summary = "删除订单核销人管理")
@DeleteMapping("/{id}")
public ApiResult<?> remove(@PathVariable("id") Integer id) {
if (shopVerifyUserService.removeById(id)) {
return success("删除成功");
}
return fail("删除失败");
}
}

View File

@@ -91,6 +91,12 @@ public class OrderCreateRequest {
@Schema(description = "发货店铺") @Schema(description = "发货店铺")
private String expressMerchantName; private String expressMerchantName;
@Schema(description = "配送方式 0-电梯 1-步梯")
private Integer deliveryMethod;
@Schema(description = "楼层")
private Integer deliveryFloor;
@Schema(description = "订单总额") @Schema(description = "订单总额")
@NotNull(message = "订单总额不能为空") @NotNull(message = "订单总额不能为空")
@DecimalMin(value = "0.01", message = "订单总额必须大于0") @DecimalMin(value = "0.01", message = "订单总额必须大于0")

View File

@@ -0,0 +1,27 @@
package com.gxwebsoft.shop.dto;
import com.gxwebsoft.common.core.web.BaseParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 查询个人核销记录
*
*/
@Data
@Schema(name = "ShopOrderMyVerifyDto", description = "查询个人核销记录")
public class ShopOrderMyVerifyDto extends BaseParam {
@Schema(description = "用户ID")
private Integer userId;
@Schema(description = "订单号")
private String orderNo;
@Schema(description = "开始时间【核销时间】", example = "2026-05-20")
private String dateStart;
@Schema(description = "结束时间【核销时间】", example = "2026-05-25")
private String dateEnd;
}

View File

@@ -9,6 +9,8 @@ import java.time.LocalDateTime;
import com.fasterxml.jackson.annotation.JsonAlias; import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serializable; import java.io.Serializable;
import java.util.List;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@@ -179,17 +181,21 @@ public class ShopGoods implements Serializable {
@Schema(description = "用户ID") @Schema(description = "用户ID")
private Integer userId; private Integer userId;
@Schema(description = "配送方式:1-自配送 2-自提 4-发快递 多属性用','隔开") @Schema(description = "配送方式:1-自配送 2-自提 4-发快递 5-水票 多属性用','隔开")
private String deliveryType; private String deliveryType;
@Schema(description = "配送方式:1-自配送 2-自提 4-发快递 5-水票 多属性用','隔开")
@TableField(exist = false)
private List<Integer> deliveryTypeList;
@Schema(description = "水票标识 0-否 1-是") @Schema(description = "水票标识 0-否 1-是")
private Integer waterTicketFlag; private Integer waterTicketFlag;
@Schema(description = "水票ID") @Schema(description = "水票ID")
private Integer waterTickerId; private Integer waterTickerId;
@Schema(description = "商品大类 1-水 2-茶叶 3-酒 4-香水") @Schema(description = "配送楼层步梯费(元)")
private Integer categoryType; private BigDecimal deliveryFee;
@Schema(description = "租户id") @Schema(description = "租户id")
private Integer tenantId; private Integer tenantId;

View File

@@ -2,15 +2,16 @@ package com.gxwebsoft.shop.entity;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import java.time.LocalDateTime;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.baomidou.mybatisplus.annotation.TableLogic; import com.baomidou.mybatisplus.annotation.TableLogic;
import java.io.Serializable; import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema; import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.time.LocalDateTime;
/** /**
* 商品分类 * 商品分类
* *
@@ -20,6 +21,7 @@ import lombok.EqualsAndHashCode;
@Data @Data
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
@Schema(name = "ShopGoodsCategory对象", description = "商品分类") @Schema(name = "ShopGoodsCategory对象", description = "商品分类")
@TableName("shop_goods_category")
public class ShopGoodsCategory implements Serializable { public class ShopGoodsCategory implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@@ -33,7 +33,7 @@ public class ShopOrder implements Serializable {
@TableId(value = "order_id", type = IdType.AUTO) @TableId(value = "order_id", type = IdType.AUTO)
private Integer orderId; private Integer orderId;
@Schema(description = "订单类型 1-及时自配送 2-自提 3-预约自配送 4-发快递") @Schema(description = "订单类型 1-及时自配送 2-自提 3-预约自配送 4-发快递 5-水票 6-(配送:自配送/快递)")
private Integer orderType; private Integer orderType;
@Schema(description = "订单编号") @Schema(description = "订单编号")
@@ -354,6 +354,15 @@ public class ShopOrder implements Serializable {
@Schema(description = "分红结算标识 0-未结算 1-已结算") @Schema(description = "分红结算标识 0-未结算 1-已结算")
private Integer dividendSettlementFlag; private Integer dividendSettlementFlag;
@Schema(description = "配送方式 0-电梯 1-步梯")
private Integer deliveryMethod;
@Schema(description = "楼层")
private Integer deliveryFloor;
@Schema(description = "配送费(步梯配送特有)")
private BigDecimal deliveryFee;
@Schema(description = "修改时间") @Schema(description = "修改时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime; private LocalDateTime updateTime;

View File

@@ -32,6 +32,9 @@ public class ShopSurchargeConfig implements Serializable {
@Schema(description = "名称") @Schema(description = "名称")
private String name; private String name;
@Schema(description = "商品ID")
private Integer goodsId;
@Schema(description = "价格(元)") @Schema(description = "价格(元)")
private BigDecimal price; private BigDecimal price;

View File

@@ -0,0 +1,58 @@
package com.gxwebsoft.shop.entity;
import com.baomidou.mybatisplus.annotation.*;
import java.time.LocalDateTime;
import java.io.Serializable;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 订单核销人管理
*
* @author xm
* @since 2026-05-25 17:13:00
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Schema(name = "ShopVerifyUser对象", description = "订单核销人管理")
@TableName("shop_verify_user")
public class ShopVerifyUser implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "主键ID")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@Schema(description = "用户ID")
private Integer userId;
@Schema(description = "用户名称")
@TableField(exist = false)
private String userName;
@Schema(description = "核销权限是否开启 0-未开启 1-已开启")
private Boolean verifyFlag;
@Schema(description = "是否开启 0-未开始 1-已开启")
private Boolean status;
@Schema(description = "创建人")
private Integer creator;
@Schema(description = "创建时间")
private LocalDateTime createTime;
@Schema(description = "更新人")
private Integer updater;
@Schema(description = "更新时间")
private LocalDateTime updateTime;
@Schema(description = "是否删除 0-未删 1-已删")
@TableLogic
private Integer deleted;
}

View File

@@ -0,0 +1,37 @@
package com.gxwebsoft.shop.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.gxwebsoft.shop.entity.ShopVerifyUser;
import com.gxwebsoft.shop.param.ShopVerifyUserParam;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 订单核销人管理Mapper
*
* @author xm
* @since 2026-05-25 17:13:00
*/
public interface ShopVerifyUserMapper extends BaseMapper<ShopVerifyUser> {
/**
* 分页查询
*
* @param page 分页对象
* @param param 查询参数
* @return List<ShopVerifyUser>
*/
List<ShopVerifyUser> selectPageRel(@Param("page") IPage<ShopVerifyUser> page,
@Param("param") ShopVerifyUserParam param);
/**
* 查询全部
*
* @param param 查询参数
* @return List<User>
*/
List<ShopVerifyUser> selectListRel(@Param("param") ShopVerifyUserParam param);
}

View File

@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.gxwebsoft.shop.mapper.ShopVerifyUserMapper">
<!-- 关联查询sql -->
<sql id="selectSql">
SELECT a.*
FROM shop_verify_user a
<where>
<if test="param.id != null">
AND a.id = #{param.id}
</if>
<if test="param.userId != null">
AND a.user_id = #{param.userId}
</if>
<if test="param.verifyFlag != null">
AND a.verify_flag = #{param.verifyFlag}
</if>
<if test="param.status != null">
AND a.status = #{param.status}
</if>
<if test="param.creator != null">
AND a.creator = #{param.creator}
</if>
<if test="param.createTimeStart != null">
AND a.create_time &gt;= #{param.createTimeStart}
</if>
<if test="param.createTimeEnd != null">
AND a.create_time &lt;= #{param.createTimeEnd}
</if>
<if test="param.updater != null">
AND a.updater = #{param.updater}
</if>
<if test="param.deleted != null">
AND a.deleted = #{param.deleted}
</if>
<if test="param.deleted == null">
AND a.deleted = 0
</if>
<if test="param.keywords != null">
AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%')
)
</if>
</where>
</sql>
<!-- 分页查询 -->
<select id="selectPageRel" resultType="com.gxwebsoft.shop.entity.ShopVerifyUser">
<include refid="selectSql"></include>
</select>
<!-- 查询全部 -->
<select id="selectListRel" resultType="com.gxwebsoft.shop.entity.ShopVerifyUser">
<include refid="selectSql"></include>
</select>
</mapper>

View File

@@ -0,0 +1,52 @@
package com.gxwebsoft.shop.param;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.gxwebsoft.common.core.annotation.QueryField;
import com.gxwebsoft.common.core.annotation.QueryType;
import com.gxwebsoft.common.core.web.BaseParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 订单核销人管理查询参数
*
* @author xm
* @since 2026-05-25 17:13:00
*/
@Data
@EqualsAndHashCode(callSuper = false)
@JsonInclude(JsonInclude.Include.NON_NULL)
@Schema(name = "ShopVerifyUserParam对象", description = "订单核销人管理查询参数")
public class ShopVerifyUserParam extends BaseParam {
private static final long serialVersionUID = 1L;
@Schema(description = "主键ID")
@QueryField(type = QueryType.EQ)
private Integer id;
@Schema(description = "用户ID")
@QueryField(type = QueryType.EQ)
private Integer userId;
@Schema(description = "核销权限是否开启 0-未开启 1-已开启")
@QueryField(type = QueryType.EQ)
private Integer verifyFlag;
@Schema(description = "是否开启 0-未开始 1-已开启")
@QueryField(type = QueryType.EQ)
private Integer status;
@Schema(description = "创建人")
@QueryField(type = QueryType.EQ)
private Integer creator;
@Schema(description = "更新人")
@QueryField(type = QueryType.EQ)
private Integer updater;
@Schema(description = "是否删除 0-未删 1-已删")
@QueryField(type = QueryType.EQ)
private Integer deleted;
}

View File

@@ -23,6 +23,7 @@ import java.math.RoundingMode;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -134,18 +135,6 @@ public class OrderBusinessService {
throw new BusinessException("用户未登录"); throw new BusinessException("用户未登录");
} }
// 检查是否为测试账号
boolean isTestAccount = orderConfig.isTestAccount(loginUser.getPhone());
if (isTestAccount) {
// 测试账号:直接使用测试金额,跳过金额验证
BigDecimal testAmount = orderConfig.getTestAccount().getTestPayAmount();
request.setTotalPrice(testAmount);
log.info("测试账号订单,用户:{},使用测试金额:{}", loginUser.getPhone(), testAmount);
return; // 测试账号跳过后续验证
}
// 非测试账号:正常验证流程
// 验证商品信息并计算总金额 // 验证商品信息并计算总金额
BigDecimal calculatedTotal = validateAndCalculateTotal(request); BigDecimal calculatedTotal = validateAndCalculateTotal(request);
@@ -157,7 +146,6 @@ public class OrderBusinessService {
if (request.getTotalPrice() != null && if (request.getTotalPrice() != null &&
request.getTotalPrice().subtract(calculatedTotal).abs().compareTo(new BigDecimal("0.01")) > 0) { request.getTotalPrice().subtract(calculatedTotal).abs().compareTo(new BigDecimal("0.01")) > 0) {
log.warn("订单金额计算不一致,前端传入:{},后台计算:{}", request.getTotalPrice(), calculatedTotal); log.warn("订单金额计算不一致,前端传入:{},后台计算:{}", request.getTotalPrice(), calculatedTotal);
// throw new BusinessException("订单金额计算错误,请刷新重试");
} }
// 使用后台计算的金额 // 使用后台计算的金额
@@ -328,23 +316,6 @@ public class OrderBusinessService {
shopOrder.setComments(orderConfig.getDefaultConfig().getDefaultComments()); shopOrder.setComments(orderConfig.getDefaultConfig().getDefaultComments());
} }
// 设置价格相关字段(解决数据库字段没有默认值的问题)
if (shopOrder.getPayPrice() == null) {
shopOrder.setPayPrice(shopOrder.getTotalPrice()); // 实际付款默认等于订单总额
}
if (shopOrder.getPrice() == null) {
shopOrder.setPrice(shopOrder.getTotalPrice()); // 用于统计的价格默认等于订单总额
}
if (shopOrder.getReducePrice() == null) {
shopOrder.setReducePrice(BigDecimal.ZERO); // 减少金额默认为0
}
if (shopOrder.getMoney() == null) {
shopOrder.setMoney(shopOrder.getTotalPrice()); // 用于积分赠送的价格默认等于订单总额
}
// 设置默认状态 // 设置默认状态
shopOrder.setPayStatus(false); // 未付款 shopOrder.setPayStatus(false); // 未付款
shopOrder.setOrderStatus(0); // 未使用 shopOrder.setOrderStatus(0); // 未使用
@@ -378,6 +349,16 @@ public class OrderBusinessService {
shopOrder.setWaterTicketFlag(0); shopOrder.setWaterTicketFlag(0);
} }
//自配送才计算步梯费用业务【选择步梯配送方式、配送楼层大于1楼、商品已设置配送费】
if(Arrays.asList(1, 3).contains(shopOrder.getOrderType()) && shopOrder.getDeliveryMethod() == 1 && shopOrder.getDeliveryFloor() > 1
&& shopGoods.getDeliveryFee().compareTo(BigDecimal.ZERO) > 0){
BigDecimal deliveryFee = BigDecimal.valueOf(shopOrder.getDeliveryFloor() - 1).multiply(shopGoods.getDeliveryFee()).multiply(BigDecimal.valueOf(goodsItem.getQuantity()));
if(deliveryFee.compareTo(BigDecimal.ZERO) > 0){
shopOrder.setDeliveryFee(deliveryFee);
shopOrder.setTotalPrice(shopOrder.getTotalPrice().add(deliveryFee));
}
}
//单一配送方式商品如用户没选择配送方式按商品默认配送属性设定订单类型 //单一配送方式商品如用户没选择配送方式按商品默认配送属性设定订单类型
String deliveryType = shopGoods.getDeliveryType(); String deliveryType = shopGoods.getDeliveryType();
if(orderType == null && StrUtil.isNotBlank(deliveryType) && !deliveryType.contains(",")){ if(orderType == null && StrUtil.isNotBlank(deliveryType) && !deliveryType.contains(",")){
@@ -396,14 +377,31 @@ public class OrderBusinessService {
break; break;
} }
default:{ default:{
orderType = 1; orderType = 5;
} }
} }
} }
} }
} }
shopOrder.setOrderType(orderType);
// 设置价格相关字段(解决数据库字段没有默认值的问题)
if (shopOrder.getPayPrice() == null) {
shopOrder.setPayPrice(shopOrder.getTotalPrice()); // 实际付款默认等于订单总额
}
if (shopOrder.getPrice() == null) {
shopOrder.setPrice(shopOrder.getTotalPrice()); // 用于统计的价格默认等于订单总额
}
if (shopOrder.getReducePrice() == null) {
shopOrder.setReducePrice(BigDecimal.ZERO); // 减少金额默认为0
}
if (shopOrder.getMoney() == null) {
shopOrder.setMoney(shopOrder.getTotalPrice()); // 用于积分赠送的价格默认等于订单总额
}
shopOrder.setOrderType(orderType);
return shopOrder; return shopOrder;
} }
@@ -667,8 +665,8 @@ public class OrderBusinessService {
throw new BusinessException("收货地址坐标异常,请重新选择收货地址"); throw new BusinessException("收货地址坐标异常,请重新选择收货地址");
} }
//订单类型:5-配送【系统自动识别电子围栏内转及时配送,电子围栏外发快递】 //订单类型:6-配送【系统自动识别电子围栏内转及时配送,电子围栏外发快递】
if(orderType != null && orderType == 5){ if(orderType != null && orderType == 6){
Boolean exit = shopStoreFenceService.validatePointInEnabled(shopOrder.getTenantId(), lng, lat); Boolean exit = shopStoreFenceService.validatePointInEnabled(shopOrder.getTenantId(), lng, lat);
if(exit){ if(exit){
shopOrder.setOrderType(1); shopOrder.setOrderType(1);

View File

@@ -0,0 +1,63 @@
package com.gxwebsoft.shop.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.shop.entity.ShopVerifyUser;
import com.gxwebsoft.shop.param.ShopVerifyUserParam;
import java.util.List;
/**
* 订单核销人管理Service
*
* @author xm
* @since 2026-05-25 17:13:00
*/
public interface ShopVerifyUserService extends IService<ShopVerifyUser> {
/**
* 分页关联查询
*
* @param param 查询参数
* @return PageResult<ShopVerifyUser>
*/
PageResult<ShopVerifyUser> pageRel(ShopVerifyUserParam param);
/**
* 关联查询全部
*
* @param param 查询参数
* @return List<ShopVerifyUser>
*/
List<ShopVerifyUser> listRel(ShopVerifyUserParam param);
/**
* 根据id查询
*
* @param id 主键ID
* @return ShopVerifyUser
*/
ShopVerifyUser getByIdRel(Integer id);
/**
* 修改订单核销人开启状态
* @param id 主键ID
* @return
*/
Boolean updateStatus(Integer id);
/**
* 修改订单核销人核销权限
* @param id 主键ID
* @return
*/
Boolean updateVerifyFlag(Integer id);
/**
* 保存数据
* @param shopVerifyUser
* @return
*/
Boolean saveInfo(ShopVerifyUser shopVerifyUser);
}

View File

@@ -125,10 +125,11 @@ public class ShopFlashSaleActivityServiceImpl extends ServiceImpl<ShopFlashSaleA
if(!newUser){ if(!newUser){
//查询当前用户是否有下过秒杀活动订单数据【判断下单数量是否超过限制】 //查询当前用户是否有下过秒杀活动订单数据【判断下单数量是否超过限制】
List<Integer> activityIdList = activityWrapper.list().stream().map(ShopFlashSaleActivity::getId).collect(Collectors.toList()); List<Integer> activityIdList = activityWrapper.list().stream().map(ShopFlashSaleActivity::getId).collect(Collectors.toList());
if(CollectionUtils.isNotEmpty(activityIdList)){
LambdaQueryWrapper<ShopOrder> shopOrderWrapper = new LambdaQueryWrapper<ShopOrder>().select(ShopOrder::getOrderId, ShopOrder::getActivityId, ShopOrder::getTotalNum) LambdaQueryWrapper<ShopOrder> shopOrderWrapper = new LambdaQueryWrapper<ShopOrder>().select(ShopOrder::getOrderId, ShopOrder::getActivityId, ShopOrder::getTotalNum)
.eq(ShopOrder::getUserId, loginUser.getUserId()).in(ShopOrder::getActivityId, activityIdList).in(ShopOrder::getOrderStatus, Arrays.asList(0, 1)); .eq(ShopOrder::getUserId, loginUser.getUserId()).in(ShopOrder::getActivityId, activityIdList).in(ShopOrder::getOrderStatus, Arrays.asList(0, 1));
activityMap = shopOrderMapper.selectList(shopOrderWrapper).stream().collect(Collectors.groupingBy(ShopOrder::getActivityId, Collectors.summingInt(ShopOrder::getTotalNum))); activityMap = shopOrderMapper.selectList(shopOrderWrapper).stream().collect(Collectors.groupingBy(ShopOrder::getActivityId, Collectors.summingInt(ShopOrder::getTotalNum)));
}
activityWrapper.eq(ShopFlashSaleActivity::getDisplayType, 0); activityWrapper.eq(ShopFlashSaleActivity::getDisplayType, 0);
} }
activityWrapper.orderByAsc(ShopFlashSaleActivity::getSortNumber); activityWrapper.orderByAsc(ShopFlashSaleActivity::getSortNumber);

View File

@@ -1,5 +1,6 @@
package com.gxwebsoft.shop.service.impl; package com.gxwebsoft.shop.service.impl;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.annotation.InterceptorIgnore; import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.shop.mapper.ShopGoodsMapper; import com.gxwebsoft.shop.mapper.ShopGoodsMapper;
@@ -11,7 +12,9 @@ import com.gxwebsoft.common.core.web.PageResult;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
/** /**
* 商品Service实现 * 商品Service实现
@@ -28,6 +31,13 @@ public class ShopGoodsServiceImpl extends ServiceImpl<ShopGoodsMapper, ShopGoods
PageParam<ShopGoods, ShopGoodsParam> page = new PageParam<>(param); PageParam<ShopGoods, ShopGoodsParam> page = new PageParam<>(param);
page.setDefaultOrder("sort_number asc, create_time desc"); page.setDefaultOrder("sort_number asc, create_time desc");
List<ShopGoods> list = baseMapper.selectPageRel(page, param); List<ShopGoods> list = baseMapper.selectPageRel(page, param);
list.forEach(shopGoods ->{
String deliveryType = shopGoods.getDeliveryType();
if(StrUtil.isNotBlank(deliveryType)){
List<Integer> deliveryTypeList = Arrays.stream(deliveryType.split(",")).map(Integer::parseInt).collect(Collectors.toList());
shopGoods.setDeliveryTypeList(deliveryTypeList);
}
});
return new PageResult<>(list, page.getTotal()); return new PageResult<>(list, page.getTotal());
} }
@@ -37,6 +47,13 @@ public class ShopGoodsServiceImpl extends ServiceImpl<ShopGoodsMapper, ShopGoods
// 排序 // 排序
PageParam<ShopGoods, ShopGoodsParam> page = new PageParam<>(); PageParam<ShopGoods, ShopGoodsParam> page = new PageParam<>();
page.setDefaultOrder("sort_number asc, create_time desc"); page.setDefaultOrder("sort_number asc, create_time desc");
list.forEach(shopGoods ->{
String deliveryType = shopGoods.getDeliveryType();
if(StrUtil.isNotBlank(deliveryType)){
List<Integer> deliveryTypeList = Arrays.stream(deliveryType.split(",")).map(Integer::parseInt).collect(Collectors.toList());
shopGoods.setDeliveryTypeList(deliveryTypeList);
}
});
return page.sortRecords(list); return page.sortRecords(list);
} }
@@ -44,7 +61,12 @@ public class ShopGoodsServiceImpl extends ServiceImpl<ShopGoodsMapper, ShopGoods
public ShopGoods getByIdRel(Integer goodsId) { public ShopGoods getByIdRel(Integer goodsId) {
ShopGoodsParam param = new ShopGoodsParam(); ShopGoodsParam param = new ShopGoodsParam();
param.setGoodsId(goodsId); param.setGoodsId(goodsId);
return param.getOne(baseMapper.selectListRel(param)); ShopGoods shopGoods = param.getOne(baseMapper.selectListRel(param));
if(shopGoods != null && StrUtil.isNotBlank(shopGoods.getDeliveryType())){
List<Integer> deliveryTypeList = Arrays.stream(shopGoods.getDeliveryType().split(",")).map(Integer::parseInt).collect(Collectors.toList());
shopGoods.setDeliveryTypeList(deliveryTypeList);
}
return shopGoods;
} }
@InterceptorIgnore(tenantLine = "true") @InterceptorIgnore(tenantLine = "true")

View File

@@ -28,10 +28,7 @@ import com.gxwebsoft.shop.dto.ShopDealerUserReduceDto;
import com.gxwebsoft.shop.dto.ShopOrderMyVerifyDto; import com.gxwebsoft.shop.dto.ShopOrderMyVerifyDto;
import com.gxwebsoft.shop.dto.VerifyShopOrderDto; import com.gxwebsoft.shop.dto.VerifyShopOrderDto;
import com.gxwebsoft.shop.entity.*; import com.gxwebsoft.shop.entity.*;
import com.gxwebsoft.shop.mapper.ShopFlashSaleActivityMapper; import com.gxwebsoft.shop.mapper.*;
import com.gxwebsoft.shop.mapper.ShopGoodsMapper;
import com.gxwebsoft.shop.mapper.ShopOrderMapper;
import com.gxwebsoft.shop.mapper.ShopUserAddressMapper;
import com.gxwebsoft.shop.param.ShopOrderParam; import com.gxwebsoft.shop.param.ShopOrderParam;
import com.gxwebsoft.shop.service.*; import com.gxwebsoft.shop.service.*;
import com.gxwebsoft.shop.vo.ShopOrderMyVerifyItemVO; import com.gxwebsoft.shop.vo.ShopOrderMyVerifyItemVO;
@@ -118,6 +115,8 @@ public class ShopOrderServiceImpl extends ServiceImpl<ShopOrderMapper, ShopOrder
private UserMapper userMapper; private UserMapper userMapper;
@Resource @Resource
private ShopFlashSaleActivityMapper shopFlashSaleActivityMapper; private ShopFlashSaleActivityMapper shopFlashSaleActivityMapper;
@Resource
private ShopVerifyUserMapper shopVerifyUserMapper;
private static final long USER_ORDER_STATS_CACHE_SECONDS = 60L; private static final long USER_ORDER_STATS_CACHE_SECONDS = 60L;
private static final long WECHAT_PREPAY_SNAPSHOT_TTL_MINUTES = 30L; private static final long WECHAT_PREPAY_SNAPSHOT_TTL_MINUTES = 30L;
@@ -495,8 +494,8 @@ public class ShopOrderServiceImpl extends ServiceImpl<ShopOrderMapper, ShopOrder
//2.判断是否有核销权限 //2.判断是否有核销权限
Integer verifyType = verifyDto.getVerifyType(); Integer verifyType = verifyDto.getVerifyType();
if(verifyType == 2){ if(verifyType == 2){
ShopDealerUser shopDealerUser = shopDealerUserService.getByUserIdRel(loginUser.getUserId()); ShopVerifyUser verifyUser = shopVerifyUserMapper.selectOne(new LambdaQueryWrapper<ShopVerifyUser>().eq(ShopVerifyUser::getUserId, loginUser.getUserId()));
if(!(shopDealerUser != null && shopDealerUser.getVerifyFlag() != null && shopDealerUser.getVerifyFlag())){ if(!(verifyUser != null && verifyUser.getVerifyFlag() && verifyUser.getStatus())){
throw new RuntimeException("暂无核销权限!"); throw new RuntimeException("暂无核销权限!");
} }
} }

View File

@@ -0,0 +1,151 @@
package com.gxwebsoft.shop.service.impl;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.common.core.exception.BusinessException;
import com.gxwebsoft.common.core.exception.enums.GlobalErrorCodeConstants;
import com.gxwebsoft.common.core.utils.LoginUserUtil;
import com.gxwebsoft.common.system.entity.User;
import com.gxwebsoft.common.system.mapper.UserMapper;
import com.gxwebsoft.shop.mapper.ShopVerifyUserMapper;
import com.gxwebsoft.shop.service.ShopVerifyUserService;
import com.gxwebsoft.shop.entity.ShopVerifyUser;
import com.gxwebsoft.shop.param.ShopVerifyUserParam;
import com.gxwebsoft.common.core.web.PageParam;
import com.gxwebsoft.common.core.web.PageResult;
import lombok.AllArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;
/**
* 订单核销人管理Service实现
*
* @author xm
* @since 2026-05-25 17:00:03
*/
@Service
@AllArgsConstructor
public class ShopVerifyUserServiceImpl extends ServiceImpl<ShopVerifyUserMapper, ShopVerifyUser> implements ShopVerifyUserService {
private UserMapper userMapper;
@Override
public PageResult<ShopVerifyUser> pageRel(ShopVerifyUserParam param) {
PageParam<ShopVerifyUser, ShopVerifyUserParam> page = new PageParam<>(param);
page.setDefaultOrder("create_time desc");
List<ShopVerifyUser> list = baseMapper.selectPageRel(page, param);
if(CollectionUtils.isNotEmpty(list)){
List<Integer> userIdList = list.stream().map(ShopVerifyUser::getUserId).distinct().collect(Collectors.toList());
if(CollectionUtils.isNotEmpty(userIdList)){
List<User> userList = userMapper.selectByUserIdList(userIdList);
for(ShopVerifyUser verifyUser : list){
User u = userList.stream().filter(user -> verifyUser.getUserId().equals(user.getUserId())).findFirst().orElse(null);
if(u != null){
verifyUser.setUserName(StrUtil.isNotEmpty(u.getRealName()) ? u.getRealName() : u.getNickname());
}
}
}
}
return new PageResult<>(list, page.getTotal());
}
@Override
public List<ShopVerifyUser> listRel(ShopVerifyUserParam param) {
List<ShopVerifyUser> list = baseMapper.selectListRel(param);
if(CollectionUtils.isNotEmpty(list)){
List<Integer> userIdList = list.stream().map(ShopVerifyUser::getUserId).distinct().collect(Collectors.toList());
if(CollectionUtils.isNotEmpty(userIdList)){
List<User> userList = userMapper.selectByUserIdList(userIdList);
for(ShopVerifyUser verifyUser : list){
User u = userList.stream().filter(user -> verifyUser.getUserId().equals(user.getUserId())).findFirst().orElse(null);
if(u != null){
verifyUser.setUserName(StrUtil.isNotEmpty(u.getRealName()) ? u.getRealName() : u.getNickname());
}
}
}
}
// 排序
PageParam<ShopVerifyUser, ShopVerifyUserParam> page = new PageParam<>();
page.setDefaultOrder("sort_number asc, create_time desc");
return page.sortRecords(list);
}
@Override
public ShopVerifyUser getByIdRel(Integer id) {
ShopVerifyUserParam param = new ShopVerifyUserParam();
param.setId(id);
ShopVerifyUser verifyUser = param.getOne(baseMapper.selectListRel(param));
if(verifyUser != null){
User user = userMapper.getById(verifyUser.getUserId());
if(user != null){
verifyUser.setUserName(StrUtil.isNotEmpty(user.getRealName()) ? user.getRealName() : user.getNickname());
}
}
return verifyUser;
}
@Override
public Boolean updateStatus(Integer id) {
ShopVerifyUser verifyUser = baseMapper.selectById(id);
if(verifyUser != null){
Boolean status = verifyUser.getStatus();
if(status){
verifyUser.setStatus(false);
}else {
verifyUser.setStatus(true);
}
verifyUser.setUpdateTime(LocalDateTime.now());
User loginUser = LoginUserUtil.getLoginUser();
verifyUser.setUpdater(loginUser != null ? loginUser.getUserId() : null);
return baseMapper.updateById(verifyUser) > 0;
}else {
throw new BusinessException(GlobalErrorCodeConstants.NOT_FOUND.getMsg());
}
}
@Override
public Boolean updateVerifyFlag(Integer id) {
ShopVerifyUser verifyUser = baseMapper.selectById(id);
if(verifyUser != null){
Boolean verifyFlag = verifyUser.getVerifyFlag();
if(verifyFlag){
verifyUser.setVerifyFlag(false);
}else {
verifyUser.setVerifyFlag(true);
}
verifyUser.setUpdateTime(LocalDateTime.now());
User loginUser = LoginUserUtil.getLoginUser();
verifyUser.setUpdater(loginUser != null ? loginUser.getUserId() : null);
return baseMapper.updateById(verifyUser) > 0;
}else {
throw new BusinessException(GlobalErrorCodeConstants.NOT_FOUND.getMsg());
}
}
@Override
public Boolean saveInfo(ShopVerifyUser shopVerifyUser) {
Integer userId = shopVerifyUser.getUserId();
if(userId == null){
throw new BusinessException("用户ID必传");
}
List<ShopVerifyUser> list = lambdaQuery().eq(ShopVerifyUser::getUserId, userId).list();
if(CollectionUtils.isNotEmpty(list)){
throw new BusinessException("该用户已存在核销人关系!");
}
User loginUser = LoginUserUtil.getLoginUser();
shopVerifyUser.setCreator(loginUser != null ? loginUser.getUserId() : null);
shopVerifyUser.setCreateTime(LocalDateTime.now());
return baseMapper.insert(shopVerifyUser) > 0;
}
}

View File

@@ -0,0 +1,70 @@
package com.gxwebsoft.shop.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.Min;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 查询个人核销记录
*
*/
@Data
@Schema(name = "ShopOrderMyVerifyDto", description = "查询个人核销记录")
public class ShopOrderMyVerifyItemVO {
@Schema(description = "订单号")
private Integer orderId;
@Schema(description = "订单类型 1-及时自配送 2-自提 3-预约自配送 4-发快递")
private Integer orderType;
@Schema(description = "订单编号")
private String orderNo;
@Schema(description = "订单总额")
private BigDecimal totalPrice;
@Schema(description = "实际付款")
private BigDecimal payPrice;
@Schema(description = "购买数量")
@Min(value = 1, message = "购买数量必须大于0")
private Integer totalNum;
@Schema(description = "商品名称")
private String goodsName;
@Schema(description = "活动名称")
private String activeName;
@Schema(description = "支付方式0余额支付1微信支付2支付宝支付3银联支付4现金支付5POS机支付6免费7积分支付")
private Integer payType;
@Schema(description = "0未付款1已付款")
private Boolean payStatus;
@Schema(description = "0未使用1已完成2已取消3取消中4退款申请中5退款被拒绝6退款成功7客户端申请退款")
private Integer orderStatus;
@Schema(description = "用户id")
private Integer userId;
@Schema(description = "核销时间")
private LocalDateTime verifyTime;
@Schema(description = "核销人")
private Integer verifyUser;
@Schema(description = "推广核销佣金")
private BigDecimal verifyMoney;
@Schema(description = "创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
}

View File

@@ -0,0 +1,52 @@
package com.gxwebsoft.shop.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
/**
* 查询个人核销记录
*
*/
@Data
@Schema(name = "ShopOrderMyVerifyDto", description = "查询个人核销记录")
public class ShopOrderMyVerifyVO {
@Schema(description = "总核销单量")
private Integer totalOrderNum = 0;
@Schema(description = "总核销商品数量")
private Integer totalGoodsNum = 0;
@Schema(description = "总核销订单金额")
private BigDecimal totalMoney = BigDecimal.ZERO;
@Schema(description = "当月核销单量")
private Integer monthOrderNum = 0;
@Schema(description = "当月核销商品数量")
private Integer monthGoodsNum = 0;
@Schema(description = "当月核销订单金额")
private BigDecimal monthMoney = BigDecimal.ZERO;
@Schema(description = "促销快核订单数")
private Integer liveOrderNum = 0;
@Schema(description = "促销快核商品数量")
private Integer liveGoodsNum = 0;
@Schema(description = "促销快核订单金额")
private BigDecimal liveMoney = BigDecimal.ZERO;
@Schema(description = "核验订单数据")
private List<ShopOrderMyVerifyItemVO> itemVOList = new ArrayList<>();
@Schema(description = "分页查询涉及总单量")
private Integer count = 0;
}

View File

@@ -14,8 +14,8 @@ spring:
# redis # redis
redis: redis:
database: 0 database: 0
host: 1Panel-redis-GmNr host: 8.134.55.105
port: 6379 port: 16379
password: redis_t74P8C password: redis_t74P8C
# 日志配置 # 日志配置

View File

@@ -15,8 +15,9 @@ spring:
redis: redis:
database: 0 database: 0
host: localhost host: 8.134.55.105
port: 6379 port: 16379
password: redis_t74P8C
# 日志配置 # 日志配置
logging: logging: