This commit is contained in:
xyc 2025-05-07 16:07:32 +08:00
parent e5f0684799
commit be3af2bd64
14 changed files with 288 additions and 19 deletions

View File

@ -0,0 +1,14 @@
package cn.iocoder.yudao.module.config.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ReminderMessage {
private Long taskId; // 任务id
private Long userId; // 用户id
private String message; // 消息
}

View File

@ -0,0 +1,43 @@
package cn.iocoder.yudao.module.config.service;
import cn.iocoder.yudao.module.config.entity.ReminderMessage;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.util.Set;
/**
* Redis 延迟队列服务
*/
@Service
public class RedisDelayedQueueService {
private static final String REDIS_KEY = "appointment:reminder:queue";
@Autowired
private StringRedisTemplate redisTemplate;
private final ObjectMapper objectMapper = new ObjectMapper();
public void addToQueue(ReminderMessage message, long triggerTimeMillis) {
try {
String json = objectMapper.writeValueAsString(message);
redisTemplate.opsForZSet().add(REDIS_KEY, json, triggerTimeMillis);
} catch (JsonProcessingException e) {
throw new RuntimeException("Failed to add reminder to Redis", e);
}
}
public Set<String> fetchDueMessages(long currentTimeMillis) {
return redisTemplate.opsForZSet()
.rangeByScore(REDIS_KEY, 0, currentTimeMillis);
}
public void removeMessage(String json) {
redisTemplate.opsForZSet().remove(REDIS_KEY, json);
}
}

View File

@ -0,0 +1,22 @@
package cn.iocoder.yudao.module.config.service;
import cn.iocoder.yudao.module.appBase.controller.admin.InspectionSocket;
import cn.iocoder.yudao.module.config.entity.ReminderMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class ReminderHandler {
@Autowired
private InspectionSocket inspectionSocket;
public void handleReminder(ReminderMessage message) {
// 调用websocket发送消息
inspectionSocket.sendMessage(message.getMessage(), String.valueOf(message.getUserId()));
}
}

View File

@ -0,0 +1,45 @@
package cn.iocoder.yudao.module.config.task;
import cn.iocoder.yudao.module.config.entity.ReminderMessage;
import cn.iocoder.yudao.module.config.service.ReminderHandler;
import cn.iocoder.yudao.module.config.service.RedisDelayedQueueService;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.Set;
@Slf4j
@Component
public class AppointmentReminderTask {
@Autowired
private RedisDelayedQueueService queueService;
@Autowired
private ReminderHandler reminderHandler;
@Scheduled(fixedRate = 60_000)
public void checkReminderQueue() {
long now = System.currentTimeMillis();
Set<String> dueMessages = queueService.fetchDueMessages(now);
for (String json : dueMessages) {
try {
ReminderMessage message = new ObjectMapper().readValue(json, ReminderMessage.class);
// 执行提醒
reminderHandler.handleReminder(message);
log.info("处理提醒成功:{}", message);
// 移除已处理任务
queueService.removeMessage(json);
} catch (Exception e) {
log.error("解析或处理提醒失败", e);
}
}
}
}

View File

@ -62,4 +62,9 @@ public class InspectionConstants {
* 接车完成类型 - 接车订单表
*/
public static final Integer INSPECTION_MEET_CAR_ORDER_IS_MEET_CAR_COMPLETE_TYPE_MEET_CAR_ORDER = 1;
/**
* 检测websocket消息内容-客户即将到店
*/
public static final String INSPECTION_WEBSOCKET_MESSAGE_CONTENT_CUSTOMER_ARRIVE = "客户即将到店";
}

View File

@ -65,6 +65,8 @@ public class InspectionInfo extends TenantBaseDO
//是否重审
private String isRetrial;
private String remark;
/** 检测次数 */
private Integer infoCount;
/** 0进行中1已结束 */
@Excel(name = "0进行中1已结束")

View File

@ -85,6 +85,11 @@ public class InspectionWorkNode extends TenantBaseDO {
*/
private String status;
/**
* 检测次数
*/
private Integer nodeCount;
/**
* 1-退办理 2-选择重审 3-项目完成

View File

@ -1576,6 +1576,7 @@ public class AppInspectionPartnerServiceImpl extends ServiceImpl<AppInspectionPa
res.setGoodsPrice(order.getGoodsPrice());
res.setGoodsName(sku.getSkuName());
res.setIsOnline(order.getIsOnline());
res.setInfoCount(info.getInfoCount());
res.setIsRetrial(info.getIsRetrial());
res.setIsPass(info.getIsPass());
res.setRemark(info.getRemark());

View File

@ -1,5 +1,9 @@
package cn.iocoder.yudao.module.inspection.service.impl;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;
@ -8,6 +12,8 @@ import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.appBase.controller.admin.InspectionSocket;
import cn.iocoder.yudao.module.config.entity.ReminderMessage;
import cn.iocoder.yudao.module.config.service.RedisDelayedQueueService;
import cn.iocoder.yudao.module.shop.entity.ShopConfig;
import cn.iocoder.yudao.module.shop.service.IShopConfigService;
import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
@ -37,6 +43,7 @@ import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import static cn.iocoder.yudao.module.constant.InspectionConstants.INSPECTION_WEBSOCKET_MESSAGE_CONTENT_CUSTOMER_ARRIVE;
import static cn.iocoder.yudao.util.DistanceUtil.getDistanceMeter;
/**
@ -67,6 +74,8 @@ public class InspectionAppointmentServiceImpl extends ServiceImpl<InspectionAppo
private IShopConfigService configService;
@Autowired
private IInspectionPickCarService pickCarService;
@Autowired
private RedisDelayedQueueService redisDelayedQueueService;
/**
* 查询请填写功能名称
*
@ -172,9 +181,9 @@ public class InspectionAppointmentServiceImpl extends ServiceImpl<InspectionAppo
// new String[]{Optional.ofNullable(appointment.getCarNo()).orElse(""),
// appointment.getAppointmentDay(),partners.getPartnerName(),partners.getAddress(),sysUser.getNickname()+" "+sysUser.getMobile()
//// },ownUser.getMobile(),"1400852709","机动车管家小程序","2112754");
//// }
SendSmsUtil.sendMsgCommon(null
,ownUser.getMobile(),"1400852709","蓝安汽车销售有限公司","2386324");
////// }
// SendSmsUtil.sendMsgCommon(null
// ,ownUser.getMobile(),"1400852709","蓝安汽车销售有限公司","2386324");
}
}else {
if (StringUtils.isNotEmpty(appointment.getOtherPhone())){
@ -212,10 +221,35 @@ public class InspectionAppointmentServiceImpl extends ServiceImpl<InspectionAppo
List<UserDTO> userListByCodes = roleService.getUserListByCodes(codes);
for (UserDTO userListByCode : userListByCodes) {
inspectionSocket.sendMessage("客户预约", userListByCode.getId().toString());
ReminderMessage message = new ReminderMessage(appointment.getId(), userListByCode.getId(), INSPECTION_WEBSOCKET_MESSAGE_CONTENT_CUSTOMER_ARRIVE);
long triggerTimeMillis = getArrivalTime(appointment.getAppointmentDay(), appointment.getAppointmentPeriod()).minusMinutes(10).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
redisDelayedQueueService.addToQueue(message, triggerTimeMillis);
}
return appointment.getId();
}
/**
* appointmentDay appointmentPeriod 转为 LocalDateTime
* @return LocalDateTime 类型的到店时间
*/
public static LocalDateTime getArrivalTime(String appointmentDay, String appointmentPeriod) {
LocalDate date = LocalDate.parse(appointmentDay); // 例如 2025-05-08
LocalTime time;
if ("0".equals(appointmentPeriod)) {
time = LocalTime.of(9, 0); // 上午 9:00
} else if ("1".equals(appointmentPeriod)) {
time = LocalTime.of(14, 0); // 下午 2:00
} else {
throw new IllegalArgumentException("appointmentPeriod 非法: " + appointmentPeriod);
}
return LocalDateTime.of(date, time);
}
@Override
public Long editAppointment(InspectionAppointment appointment) {

View File

@ -209,7 +209,7 @@ public class InspectionInfoServiceImpl extends ServiceImpl<InspectionInfoMapper,
// 查询订单
orderInfo = orderInfoService.getById(appointment1.getOrderId());
}else {
} else {
orderInfo.setPartnerId(partners.getPartnerId());
orderInfo.setGoodsId(Long.parseLong(goods.getId().toString()));
orderInfo.setGoodsTitle(goods.getTitle());
@ -243,6 +243,34 @@ public class InspectionInfoServiceImpl extends ServiceImpl<InspectionInfoMapper,
orderInfoService.update(Wrappers.<OrderInfo>lambdaUpdate()
.eq(OrderInfo::getId, orderInfo.getId())
.set(OrderInfo::getValidationTime, new Date()));
} else {
orderInfo.setPartnerId(partners.getPartnerId());
orderInfo.setGoodsId(Long.parseLong(goods.getId().toString()));
orderInfo.setGoodsTitle(goods.getTitle());
orderInfo.setGoodsType("jc");
orderInfo.setGoodNum(1);
orderInfo.setSkuId(Long.parseLong(sku.getId().toString()));
orderInfo.setSkuName(sku.getSkuName());
orderInfo.setGoodsPrice(goods.getPrice());
orderInfo.setStartTime(new Date());
orderInfo.setOrderTime(new Date());
orderInfo.setOrderType("jc");
orderInfo.setUserId(user.getId());
orderInfo.setRealName(user.getNickname());
orderInfo.setIsOnline("0");
orderInfo.setPhonenumber(user.getMobile());
orderInfo.setPartnerName(partner.getPartnerName());
orderInfo.setOrderNo("线下订单-" + System.currentTimeMillis());
//赊账的情况
orderInfo.setOrderStatus("0");
orderInfoService.save(orderInfo);
//修改预约信息表的orderId
InspectionAppointment appointment = new InspectionAppointment();
appointment.setOrderId(orderInfo.getId());
inspectionAppointmentService.update(Wrappers.<InspectionAppointment>lambdaUpdate()
.eq(InspectionAppointment::getId, inspectionInfo.getAppointmentId())
.set(InspectionAppointment::getOrderId, orderInfo.getId()));
}
inspectionInfo.setInspectionOrderId(orderInfo.getId());
inspectionInfo.setPartnerId(partners.getPartnerId());

View File

@ -6,6 +6,8 @@ import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.security.config.SecurityProperties;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.appBase.controller.admin.InspectionSocket;
import cn.iocoder.yudao.module.config.entity.ReminderMessage;
import cn.iocoder.yudao.module.config.service.RedisDelayedQueueService;
import cn.iocoder.yudao.module.inspection.entity.*;
import cn.iocoder.yudao.module.inspection.mapper.AppInspectionGoodsMapper;
import cn.iocoder.yudao.module.inspection.mapper.InspectionMeetCarOrderMapper;
@ -18,8 +20,12 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.time.ZoneId;
import java.util.Date;
import static cn.iocoder.yudao.module.constant.InspectionConstants.INSPECTION_WEBSOCKET_MESSAGE_CONTENT_CUSTOMER_ARRIVE;
import static cn.iocoder.yudao.module.inspection.service.impl.InspectionAppointmentServiceImpl.getArrivalTime;
/**
* @Description: 接车订单
* @Author: 86187
@ -42,6 +48,8 @@ public class InspectionMeetCarOrderServiceImpl extends ServiceImpl<InspectionMee
private final IShopInspectionGoodsService goodsService;
private final RedisDelayedQueueService redisDelayedQueueService;
/**
* 添加接车订单
*
@ -88,13 +96,20 @@ public class InspectionMeetCarOrderServiceImpl extends ServiceImpl<InspectionMee
.set(InspectionMeetCarOrder::getLongitude, pickCar.getLongitude())
.set(InspectionMeetCarOrder::getAppointmentDay, pickCar.getAppointmentDay())
.set(InspectionMeetCarOrder::getAppointmentTime, pickCar.getAppointmentTime()));
inspectionSocket.sendMessage("接工单", order.getMeetManId().toString());
} else {
update(Wrappers.<InspectionMeetCarOrder>lambdaUpdate()
.eq(InspectionMeetCarOrder::getId, order.getId())
.set(InspectionMeetCarOrder::getAppointmentDay, appointment.getAppointmentDay()));
// 设置消息提醒
ReminderMessage message = new ReminderMessage(appointment.getId(), order.getMeetManId(), INSPECTION_WEBSOCKET_MESSAGE_CONTENT_CUSTOMER_ARRIVE);
long triggerTimeMillis = getArrivalTime(appointment.getAppointmentDay(), appointment.getAppointmentPeriod()).minusMinutes(10).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
redisDelayedQueueService.addToQueue(message, triggerTimeMillis);
}
}
inspectionSocket.sendMessage("接工单", order.getMeetManId().toString());
}
if (StrUtil.isNotEmpty(order.getContent()) || StrUtil.isNotEmpty(order.getImages())) {

View File

@ -196,6 +196,11 @@ public class InspectionWorkNodeServiceImpl extends ServiceImpl<InspectionWorkNod
}
//根据流程id获取流程
InspectionWorkNode workNode = this.getById(inspectionWorkNode.getId());
if (ObjectUtil.isNotEmpty(workNode.getNodeCount())) {
inspectionWorkNode.setNodeCount(workNode.getNodeCount() + 1);
} else {
inspectionWorkNode.setNodeCount(1);
}
//根据工单id查询工单
InspectionInfo inspectionInfo = inspectionInfoService.selectInspectionInfoById(workNode.getInspectionInfoId());
@ -216,6 +221,12 @@ public class InspectionWorkNodeServiceImpl extends ServiceImpl<InspectionWorkNod
// 更新或插入步骤信息
DlInspectionProject project = inspectionProjectService.getOne(new LambdaQueryWrapper<DlInspectionProject>()
.eq(DlInspectionProject::getId, workNode.getProjectId()));
// 判断检测项目是否包含制证
if (ObjectUtil.isNotEmpty(project)) {
if (project.getProjectName().contains("制证")) {
flag = false;
}
}
List<InspectionStepInfo> stepInfos = inspectionStepService.list(new LambdaQueryWrapper<InspectionStepInfo>()
.and(i -> i.eq(InspectionStepInfo::getInspectionInfoId, workNode.getInspectionInfoId())
.eq(InspectionStepInfo::getWorkNodeId, workNode.getId())
@ -361,6 +372,12 @@ public class InspectionWorkNodeServiceImpl extends ServiceImpl<InspectionWorkNod
InspectionInfo info = inspectionInfoService.getById(workNodes.getInspectionInfoId());
info.setIsRetrial("1");
info.setIsPass("0");
// 设置检测次数加一
if (ObjectUtil.isNotEmpty(info.getInfoCount())) {
info.setInfoCount(info.getInfoCount() + 1);
} else {
info.setInfoCount(2);
}
//更新工单表
inspectionInfoService.updateById(info);
@ -384,13 +401,13 @@ public class InspectionWorkNodeServiceImpl extends ServiceImpl<InspectionWorkNod
// 添加步骤信息表
InspectionStepInfo stepInfo = new InspectionStepInfo();
stepInfo.setInspectionInfoId(Integer.parseInt(workNodes.getInspectionInfoId().toString()));
stepInfo.setTitle("");
stepInfo.setTitle("");
stepInfo.setCreateTime(DateUtil.date());
stepInfo.setCreator(Integer.parseInt(loginUser.getId().toString()));
if (ObjectUtil.isNotEmpty(workNodes.getRemark())) {
stepInfo.setContent(workNodes.getRemark());
} else {
stepInfo.setContent("审了" + projectNames + "项目");
stepInfo.setContent("");
}
if (ObjectUtil.isNotEmpty(workNodes.getDealImages())) {
stepInfo.setImages(workNodes.getDealImages());
@ -563,20 +580,20 @@ public class InspectionWorkNodeServiceImpl extends ServiceImpl<InspectionWorkNod
*/
public void retrial(InspectionWorkNode inspectionWorkNode) {
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
//通过流程节点id查询流程
InspectionWorkNode workNode = this.getById(inspectionWorkNode.getId());
//通过工单id获取工单
InspectionInfo info = inspectionInfoService.getById(inspectionWorkNode.getInspectionInfoId());
info.setIsRetrial("1");
info.setIsPass("0");
info.setStatus("2");
// info.setStatus("2");
// info.setNowOrderNum(workNode.getOrderNum());
// 通过流程id获取项目
List<String> workNodeIds = inspectionWorkNode.getWorkNodes().stream().map(InspectionWorkNode::getId).collect(Collectors.toList());
// 将所有项目重新走一遍
// 复检的项目重走一遍
this.update(new UpdateWrapper<InspectionWorkNode>()
.set("status", "0")
.set("status", "3")
.set("type", null)
.eq("inspection_info_id", inspectionWorkNode.getInspectionInfoId()));
.in("id", workNodeIds));
//跟新工单表
inspectionInfoService.updateById(info);
@ -590,20 +607,52 @@ public class InspectionWorkNodeServiceImpl extends ServiceImpl<InspectionWorkNod
// }
// sendSocketMessage(ids);
// 查询项目id
List<InspectionWorkNode> inspectionWorkNodes = baseMapper.selectBatchIds(workNodeIds);
List<String> projectIds = inspectionWorkNodes.stream().map(InspectionWorkNode::getProjectId).collect(Collectors.toList());
List<DlInspectionProject> projectList = inspectionProjectService.list(Wrappers.<DlInspectionProject>lambdaQuery()
.in(DlInspectionProject::getId, projectIds));
// 将项目名称以逗号隔开
String projectNames = projectList.stream().map(DlInspectionProject::getProjectName).collect(Collectors.joining(""));
// /*将当前步骤修改完已完成*/
// if (ObjectUtil.isNotNull(workNodes.getId())) {
// workNodes.setStatus("2");
// baseMapper.updateById(workNodes);
// }
// 添加步骤信息表
InspectionStepInfo stepInfo = new InspectionStepInfo();
stepInfo.setInspectionInfoId(Integer.parseInt(inspectionWorkNode.getInspectionInfoId().toString()));
stepInfo.setWorkNodeId(inspectionWorkNode.getId());
stepInfo.setTitle("重检");
stepInfo.setTitle("复检");
stepInfo.setCreateTime(DateUtil.date());
stepInfo.setCreator(Integer.parseInt(loginUser.getId().toString()));
if (ObjectUtil.isNotEmpty(inspectionWorkNode.getRemark())) {
stepInfo.setContent(inspectionWorkNode.getRemark());
} else {
stepInfo.setContent("复检了" + projectNames + "项目");
}
if (ObjectUtil.isNotEmpty(inspectionWorkNode.getDealImages())) {
stepInfo.setImages(inspectionWorkNode.getDealImages());
}
stepInfo.setCreateTime(DateUtil.date());
stepInfo.setCreator(Integer.parseInt(loginUser.getId().toString()));
inspectionStepService.save(stepInfo);
// 添加步骤信息表
// InspectionStepInfo stepInfo = new InspectionStepInfo();
// stepInfo.setInspectionInfoId(Integer.parseInt(inspectionWorkNode.getInspectionInfoId().toString()));
// stepInfo.setWorkNodeId(inspectionWorkNode.getId());
// stepInfo.setTitle("复检");
// if (ObjectUtil.isNotEmpty(inspectionWorkNode.getRemark())) {
// stepInfo.setContent(inspectionWorkNode.getRemark());
// }
// if (ObjectUtil.isNotEmpty(inspectionWorkNode.getDealImages())) {
// stepInfo.setImages(inspectionWorkNode.getDealImages());
// }
// stepInfo.setCreateTime(DateUtil.date());
// stepInfo.setCreator(Integer.parseInt(loginUser.getId().toString()));
// inspectionStepService.save(stepInfo);
}
public void sendSocketMessage(List<Long> userIds) {

View File

@ -34,6 +34,7 @@ public class InspectionInfoVo {
private String remark;
private String buyUserName;
private String buyUserPhone;
private Integer infoCount;
@TableField(exist = false)
private String buyName;

View File

@ -475,10 +475,15 @@ FROM
SELECT
count(1) allNum,
IFNULL(SUM(ii.status='0'),0) jxzNum,
IFNULL(SUM(ii.status='1'),0) ywcNum
IFNULL(SUM(ii.status='1'),0) ywcNum,
IFNULL(SUM(oi.sku_name LIKE '%年审%'),0) nsNum,
IFNULL(SUM(oi.sku_name LIKE '%上户%'),0) shNum,
IFNULL(SUM(oi.sku_name LIKE '%非定检%'),0) fdjNum,
IFNULL(SUM(oi.sku_name LIKE '%双燃料%'),0) srlNum
FROM
inspection_info ii
WHERE ii.partner_id =#{partnerId} and ii.deleted = 0
LEFT JOIN order_info oi on oi.id = ii.inspection_order_id
WHERE ii.partner_id =#{partnerId} and ii.deleted = 0 and oi.deleted = 0
and ii.create_time BETWEEN #{startTime} and #{endTime}
</select>
<select id="newStaticsTable2" resultType="java.util.Map">