排队管理-新增排队码
This commit is contained in:
parent
9ba5172bb2
commit
f6eb0c40d0
@ -1,6 +1,7 @@
|
|||||||
package com.yzt.admin.controller;
|
package com.yzt.admin.controller;
|
||||||
|
|
||||||
import com.yzt.common.page.CommonPage;
|
import com.yzt.common.page.CommonPage;
|
||||||
|
import com.yzt.common.request.AdminGenerateQueueCodeRequest;
|
||||||
import com.yzt.common.request.PageParamRequest;
|
import com.yzt.common.request.PageParamRequest;
|
||||||
import com.yzt.common.request.StoreCombinationRequest;
|
import com.yzt.common.request.StoreCombinationRequest;
|
||||||
import com.yzt.common.request.StoreCombinationSearchRequest;
|
import com.yzt.common.request.StoreCombinationSearchRequest;
|
||||||
@ -166,7 +167,14 @@ public class StoreCombinationController {
|
|||||||
storePinkService.adminCancelQueueAndRecalculate(pinkId);
|
storePinkService.adminCancelQueueAndRecalculate(pinkId);
|
||||||
return CommonResult.success();
|
return CommonResult.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 后台管理员新增排队码
|
||||||
|
*/
|
||||||
|
@ApiOperation(value = "后台管理员新增排队码")
|
||||||
|
@RequestMapping(value = "/admin/generate/queue", method = RequestMethod.POST)
|
||||||
|
public CommonResult<Object> adminGenerateQueueCodes(@RequestBody @Validated AdminGenerateQueueCodeRequest request) {
|
||||||
|
storePinkService.adminGenerateQueueCodes(request.getUid(), request.getProductId(), request.getCount(), request.getRemark());
|
||||||
|
return CommonResult.success("排队码生成成功");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,7 @@ import java.util.Date;
|
|||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = false)
|
@EqualsAndHashCode(callSuper = false)
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
@TableName("fw_schedule_job")
|
@TableName("zp_schedule_job")
|
||||||
@ApiModel(value="ScheduleJob对象", description="定时任务")
|
@ApiModel(value="ScheduleJob对象", description="定时任务")
|
||||||
public class ScheduleJob implements Serializable {
|
public class ScheduleJob implements Serializable {
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,7 @@ import java.util.Date;
|
|||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = false)
|
@EqualsAndHashCode(callSuper = false)
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
@TableName("fw_schedule_job_log")
|
@TableName("zp_schedule_job_log")
|
||||||
@ApiModel(value="ScheduleJobLog对象", description="定时任务日志")
|
@ApiModel(value="ScheduleJobLog对象", description="定时任务日志")
|
||||||
public class ScheduleJobLog implements Serializable {
|
public class ScheduleJobLog implements Serializable {
|
||||||
|
|
||||||
|
|||||||
@ -95,4 +95,10 @@ public class StorePink implements Serializable {
|
|||||||
@ApiModelProperty(value = "排队码编号(年月日时分秒+六位随机数)")
|
@ApiModelProperty(value = "排队码编号(年月日时分秒+六位随机数)")
|
||||||
private String queueCode;
|
private String queueCode;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "操作的管理员ID")
|
||||||
|
private Integer adminId;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "备注")
|
||||||
|
private String remark;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,32 @@
|
|||||||
|
package com.yzt.common.request;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.Min;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 后台管理员新增排队码请求参数
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ApiModel(value = "AdminGenerateQueueCodeRequest", description = "后台管理员新增排队码请求参数")
|
||||||
|
public class AdminGenerateQueueCodeRequest {
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "用户uid", required = true)
|
||||||
|
@NotNull(message = "用户uid不能为空")
|
||||||
|
private Integer uid;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "商品product_id", required = true)
|
||||||
|
@NotNull(message = "商品product_id不能为空")
|
||||||
|
private Integer productId;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "生成码数量", required = true)
|
||||||
|
@NotNull(message = "生成码数量不能为空")
|
||||||
|
@Min(value = 1, message = "生成码数量至少为1")
|
||||||
|
private Integer count;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "备注")
|
||||||
|
private String remark;
|
||||||
|
}
|
||||||
@ -109,4 +109,13 @@ public interface StorePinkService extends IService<StorePink> {
|
|||||||
* @param pinkId 拼团(排队)记录ID
|
* @param pinkId 拼团(排队)记录ID
|
||||||
*/
|
*/
|
||||||
void adminCancelQueueAndRecalculate(Integer pinkId);
|
void adminCancelQueueAndRecalculate(Integer pinkId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 后台管理员新增排队码
|
||||||
|
* @param uid 用户ID
|
||||||
|
* @param productId 商品ID
|
||||||
|
* @param count 生成码数量
|
||||||
|
* @param remark 备注
|
||||||
|
*/
|
||||||
|
void adminGenerateQueueCodes(Integer uid, Integer productId, Integer count, String remark);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import com.yzt.common.exception.YztException;
|
|||||||
import com.yzt.common.model.combination.StoreCombination;
|
import com.yzt.common.model.combination.StoreCombination;
|
||||||
import com.yzt.common.model.combination.StorePink;
|
import com.yzt.common.model.combination.StorePink;
|
||||||
import com.yzt.common.model.order.StoreOrder;
|
import com.yzt.common.model.order.StoreOrder;
|
||||||
|
import com.yzt.common.model.product.StoreProductAttr;
|
||||||
import com.yzt.common.model.system.SystemNotification;
|
import com.yzt.common.model.system.SystemNotification;
|
||||||
import com.yzt.common.model.user.User;
|
import com.yzt.common.model.user.User;
|
||||||
import com.yzt.common.model.user.UserBrokerageRecord;
|
import com.yzt.common.model.user.UserBrokerageRecord;
|
||||||
@ -88,6 +89,9 @@ public class StorePinkServiceImpl extends ServiceImpl<StorePinkMapper, StorePink
|
|||||||
@Autowired
|
@Autowired
|
||||||
private TenantService tenantService;
|
private TenantService tenantService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private StoreProductAttrService storeProductAttrService;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 列表
|
* 列表
|
||||||
@ -618,5 +622,186 @@ public class StorePinkServiceImpl extends ServiceImpl<StorePinkMapper, StorePink
|
|||||||
logger.warn("===== StorePinkService.saveBatch COMPLETED: {} records =====", entityList.size());
|
logger.warn("===== StorePinkService.saveBatch COMPLETED: {} records =====", entityList.size());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 后台管理员新增排队码
|
||||||
|
* @param uid 用户ID
|
||||||
|
* @param productId 商品ID
|
||||||
|
* @param count 生成码数量
|
||||||
|
* @param remark 备注
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void adminGenerateQueueCodes(Integer uid, Integer productId, Integer count, String remark) {
|
||||||
|
if (uid == null || productId == null || count == null || count <= 0) {
|
||||||
|
throw new YztException("参数错误");
|
||||||
|
}
|
||||||
|
|
||||||
|
User user = userService.getById(uid);
|
||||||
|
if (user == null) {
|
||||||
|
throw new YztException("用户不存在");
|
||||||
|
}
|
||||||
|
LambdaQueryWrapper<StoreProductAttr> attrWrapper = new LambdaQueryWrapper<>();
|
||||||
|
attrWrapper.eq(StoreProductAttr::getProductId, productId);
|
||||||
|
attrWrapper.eq(StoreProductAttr::getIsDel, false);
|
||||||
|
List<StoreProductAttr> attrList = storeProductAttrService.list(attrWrapper);
|
||||||
|
|
||||||
|
if (CollUtil.isEmpty(attrList)) {
|
||||||
|
throw new YztException("商品属性不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取第一个属性的attrValues
|
||||||
|
String attrValues = attrList.get(0).getAttrValues();
|
||||||
|
if (StrUtil.isBlank(attrValues)) {
|
||||||
|
throw new YztException("商品属性值为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
//判断队列类型
|
||||||
|
Integer queueType;
|
||||||
|
String redisKey;
|
||||||
|
if ("1".equals(attrValues)) {
|
||||||
|
queueType = 1;
|
||||||
|
redisKey = "queue:counter:member";
|
||||||
|
} else if ("2".equals(attrValues)) {
|
||||||
|
queueType = 2;
|
||||||
|
redisKey = "queue:counter:hall";
|
||||||
|
} else {
|
||||||
|
throw new YztException("商品属性值异常:" + attrValues + ",仅支持1(黔行)或2(茅香)");
|
||||||
|
}
|
||||||
|
|
||||||
|
List<StorePink> queueList = new ArrayList<>();
|
||||||
|
long currentTimeSeconds = System.currentTimeMillis() / 1000;
|
||||||
|
String orderId = String.valueOf(currentTimeSeconds);
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
// 使用Redis递增获取排队号
|
||||||
|
long currentQueueNo = redisUtil.incr(redisKey, 1);
|
||||||
|
|
||||||
|
StorePink queueItem = new StorePink();
|
||||||
|
|
||||||
|
// 用户信息
|
||||||
|
queueItem.setUid(user.getUid());
|
||||||
|
queueItem.setNickname(user.getNickname());
|
||||||
|
queueItem.setAvatar(user.getAvatar());
|
||||||
|
|
||||||
|
queueItem.setOrderId(orderId);
|
||||||
|
queueItem.setOrderIdKey(0);
|
||||||
|
|
||||||
|
queueItem.setPid(productId);
|
||||||
|
queueItem.setCid(productId);
|
||||||
|
queueItem.setTotalNum(count);
|
||||||
|
queueItem.setPrice(BigDecimal.ZERO);
|
||||||
|
queueItem.setTotalPrice(BigDecimal.ZERO);
|
||||||
|
|
||||||
|
queueItem.setPeople(1);
|
||||||
|
queueItem.setKId(0);
|
||||||
|
queueItem.setStatus(1);
|
||||||
|
queueItem.setAddTime(currentTimeSeconds);
|
||||||
|
queueItem.setStopTime(0L);
|
||||||
|
|
||||||
|
queueItem.setIsTpl(false);
|
||||||
|
queueItem.setIsRefund(false);
|
||||||
|
queueItem.setIs_virtual(false);
|
||||||
|
|
||||||
|
queueItem.setQueueType(queueType);
|
||||||
|
queueItem.setQueueNo((int) currentQueueNo);
|
||||||
|
queueItem.setQueueProgress(BigDecimal.ZERO); // 初始为0,后续重算
|
||||||
|
|
||||||
|
// 生成排队码编号:年月日时分秒+六位随机数
|
||||||
|
String queueCode = generateQueueCode(currentTimeSeconds);
|
||||||
|
queueItem.setQueueCode(queueCode);
|
||||||
|
|
||||||
|
// 设置备注
|
||||||
|
queueItem.setRemark(remark);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Integer adminId = com.yzt.common.utils.SecurityUtil.getCurrentUserId();
|
||||||
|
queueItem.setAdminId(adminId);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 如果获取不到管理员ID,不影响主流程,只记录日志
|
||||||
|
logger.warn("无法获取当前管理员ID: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
queueList.add(queueItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!queueList.isEmpty()) {
|
||||||
|
this.saveBatch(queueList);
|
||||||
|
logger.info("管理员生成排队码成功: uid={}, productId={}, count={}, queueType={}, remark={}",
|
||||||
|
uid, productId, count, queueType, remark);
|
||||||
|
}
|
||||||
|
|
||||||
|
//重新计算队列进度(查询该队列中所有is_refund=0且status=1的记录)
|
||||||
|
LambdaQueryWrapper<StorePink> waitingWrapper = new LambdaQueryWrapper<>();
|
||||||
|
waitingWrapper.eq(StorePink::getQueueType, queueType)
|
||||||
|
.eq(StorePink::getStatus, 1)
|
||||||
|
.eq(StorePink::getIsRefund, false)
|
||||||
|
.orderByAsc(StorePink::getQueueNo);
|
||||||
|
List<StorePink> waitingList = this.list(waitingWrapper);
|
||||||
|
|
||||||
|
if (CollUtil.isEmpty(waitingList)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用Redis中的计数器值作为Y(队列当前排到的位置)
|
||||||
|
long redisVal = redisUtil.get(redisKey) == null ? 0 : Long.parseLong(redisUtil.get(redisKey).toString());
|
||||||
|
int currentY = (int) redisVal;
|
||||||
|
if (currentY <= 0) {
|
||||||
|
currentY = waitingList.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重新计算进度:公式 (Y-X) / (5X)
|
||||||
|
List<StorePink> updates = new ArrayList<>();
|
||||||
|
for (StorePink xUser : waitingList) {
|
||||||
|
Integer xNo = xUser.getQueueNo();
|
||||||
|
if (xNo == null || xNo <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int x = xNo;
|
||||||
|
if (x >= currentY) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigDecimal numerator = new BigDecimal(currentY - x); // 分子 = Y - X
|
||||||
|
BigDecimal denominator = new BigDecimal(5 * x); // 分母 = 5X
|
||||||
|
if (denominator.compareTo(BigDecimal.ZERO) <= 0) {
|
||||||
|
// 分母异常时跳过,避免除零错误
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否免单成功
|
||||||
|
if (numerator.compareTo(denominator) >= 0) {
|
||||||
|
// (Y-X) >= (5X),即 progress >= 1
|
||||||
|
xUser.setQueueProgress(BigDecimal.ONE);
|
||||||
|
xUser.setStatus(2);
|
||||||
|
} else {
|
||||||
|
// 计算进度值,保留6位小数
|
||||||
|
BigDecimal progress = numerator.divide(denominator, 6, BigDecimal.ROUND_DOWN);
|
||||||
|
xUser.setQueueProgress(progress);
|
||||||
|
}
|
||||||
|
updates.add(xUser);
|
||||||
|
}
|
||||||
|
if (CollUtil.isNotEmpty(updates)) {
|
||||||
|
this.updateBatchById(updates);
|
||||||
|
logger.info("重新计算队列进度完成: queueType={}, 更新记录数={}", queueType, updates.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成排队码编号:年月日时分秒+六位随机数
|
||||||
|
* @param addTime Unix时间戳(秒)
|
||||||
|
* @return 排队码编号
|
||||||
|
*/
|
||||||
|
private String generateQueueCode(Long addTime) {
|
||||||
|
// 将Unix时间戳转换为日期时间格式
|
||||||
|
cn.hutool.core.date.DateTime dateTime = cn.hutool.core.date.DateUtil.date(addTime * 1000);
|
||||||
|
String timeStr = cn.hutool.core.date.DateUtil.format(dateTime, "yyMMddHHmmss");
|
||||||
|
|
||||||
|
// 生成六位随机数
|
||||||
|
int randomNum = (int)(Math.random() * 1000000);
|
||||||
|
String randomStr = String.format("%06d", randomNum);
|
||||||
|
|
||||||
|
return timeStr + randomStr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user