Merge remote-tracking branch 'origin/master'

This commit is contained in:
赵旭 2024-08-26 23:45:11 +08:00
commit 18b08959a9
17 changed files with 528 additions and 50 deletions

View File

@ -75,4 +75,12 @@ public class UserConstants
*/
public static final int PASSWORD_MIN_LENGTH = 5;
public static final int PASSWORD_MAX_LENGTH = 20;
/** 救援业务管理员 */
public static final String RESCUE_MANAGE = "jiuyuan";
/** 救援司机 */
public static final String RESCUE_DRIVER = "jysj";
/** 救援定时任务时间 */
public static final Integer RESCUE_TIME = 3 * 60;
}

View File

@ -1,34 +1,38 @@
package cn.iocoder.yudao.module.rescue.controller.admin;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.constant.UserConstants;
import cn.iocoder.yudao.module.rescue.core.controller.BaseController;
import cn.iocoder.yudao.module.rescue.core.page.TableDataInfo;
import cn.iocoder.yudao.module.rescue.domain.DriverInfo;
import cn.iocoder.yudao.module.rescue.domain.RescueInfo;
import cn.iocoder.yudao.module.rescue.domain.RescueInfoDetail;
import cn.iocoder.yudao.module.rescue.domain.RescueOrderInfo;
import cn.iocoder.yudao.module.rescue.domain.*;
import cn.iocoder.yudao.module.rescue.dto.DriverInfoDto;
import cn.iocoder.yudao.module.rescue.dto.SysDictData;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.module.staff.entity.CompanyStaff;
import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO;
import cn.iocoder.yudao.module.rescue.service.IRescueDictStaffService;
import cn.iocoder.yudao.module.rescue.service.IRescueInfoDetailService;
import cn.iocoder.yudao.module.rescue.service.IRescueInfoService;
import cn.iocoder.yudao.module.rescue.service.IRescueOrderInfoService;
import cn.iocoder.yudao.module.rescue.utils.ExcelUtil;
import cn.iocoder.yudao.module.rescue.utils.StringUtils;
import cn.iocoder.yudao.module.rescue.vo.MoneyManagement;
import cn.iocoder.yudao.module.staff.entity.CompanyStaff;
import cn.iocoder.yudao.module.staff.service.CompanyStaffService;
import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO;
import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
import cn.iocoder.yudao.module.system.api.permission.RoleApi;
import cn.iocoder.yudao.module.system.api.permission.dto.RoleReqDTO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.context.annotation.Lazy;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@ -53,6 +57,22 @@ public class RescueInfoSystem extends BaseController {
@Resource
private IRescueInfoDetailService rescueInfoDetailService;
@Resource
private IRescueDictStaffService rescueDictStaffService;
@Resource
@Lazy
private AdminUserApi adminUserApi;
@Resource
private CompanyStaffService staffService;
@Resource
private RoleApi roleApi;
@Resource
private PermissionApi permissionApi;
/**
* 新增道路救援发起
*/
@ -310,6 +330,10 @@ public class RescueInfoSystem extends BaseController {
@PostMapping("/delRescueRoad")
public CommonResult delRescueRoad(Long dictId) {
dictDataApi.deleteDictDataByIds(new Long[]{dictId});
RescueDictStaff flag = rescueDictStaffService.getOne(new LambdaQueryWrapper<RescueDictStaff>().eq(RescueDictStaff::getDictId, dictId));
if (ObjectUtil.isNotEmpty(flag)){
rescueDictStaffService.remove(new LambdaQueryWrapper<RescueDictStaff>().eq(RescueDictStaff::getDictId, dictId));
}
return CommonResult.ok();
}
@ -349,4 +373,65 @@ public class RescueInfoSystem extends BaseController {
String title = "施救总金额:" + jsonObject.getString("allMoney") + "元 出车次数:" + jsonObject.getString("allNum") + "次 提成总金额:" + jsonObject.getString("tcAll") + " 元 燃油费小计:" + jsonObject.getString("refuelMoney") + "";
util.exportExcel(response, list, "救援财务报表", title);
}
/**
* 查询救援路段的司机和管理人员信息
* @author 小李
* @date 9:17 2024/8/26
* @param ids 路段IDs 一个或多个
**/
@GetMapping("/getDictStaff/{ids}")
public CommonResult getDictStaff(@PathVariable("ids") Long[] ids){
List<Long> dictIds = Arrays.asList(ids);
List<RescueDictStaff> rescueDictStaffs = dictIds.stream().map(item -> {
RescueDictStaff rescueDictStaff = rescueDictStaffService.getOne(new LambdaQueryWrapper<RescueDictStaff>().eq(RescueDictStaff::getDictId, item));
if (ObjectUtil.isNotEmpty(rescueDictStaff)) {
// 拿路段管理员的名字
AdminUserRespDTO user = adminUserApi.getUser(rescueDictStaff.getManageId());
rescueDictStaff.setManageName(user.getNickname());
// 拿路段司机的名字
List<Long> driverIds = Arrays.asList(rescueDictStaff.getDriverIds().split(",")).stream().map(Long::parseLong).collect(Collectors.toList());
List<AdminUserRespDTO> drivers = adminUserApi.getUserList(driverIds);
StringJoiner tempStr = new StringJoiner("|");
for (AdminUserRespDTO driver : drivers) {
tempStr.add(driver.getNickname());
}
rescueDictStaff.setDriverNames(tempStr.toString());
}
return rescueDictStaff;
}).collect(Collectors.toList());
return success(rescueDictStaffs);
}
/**
* 获得所有救援业务管理员
* @author 小李
* @date 10:10 2024/8/26
**/
@GetMapping("/getManages")
public CommonResult getManages(){
RoleReqDTO roleInfo = roleApi.getRoleInfo(UserConstants.RESCUE_MANAGE);
List<Long> userIds = permissionApi.getUserIdByRoleId(roleInfo.getId());
List<CompanyStaff> staffs = staffService.list(new LambdaQueryWrapper<CompanyStaff>().in(CompanyStaff::getUserId, userIds));
return success(staffs);
}
/**
* 获得所有司机
* @author 小李
* @date 10:10 2024/8/26
**/
@GetMapping("/getDrivers")
public CommonResult getDrivers(){
RoleReqDTO roleInfo = roleApi.getRoleInfo(UserConstants.RESCUE_DRIVER);
List<Long> userIds = permissionApi.getUserIdByRoleId(roleInfo.getId());
List<CompanyStaff> staffs = staffService.list(new LambdaQueryWrapper<CompanyStaff>().in(CompanyStaff::getUserId, userIds));
return success(staffs);
}
@PostMapping("/bindDictStaff")
public CommonResult bindDictStaff(@RequestBody RescueDictStaff rescueDictStaff){
rescueDictStaffService.saveOrUpdate(rescueDictStaff);
return CommonResult.ok();
}
}

View File

@ -0,0 +1,41 @@
package cn.iocoder.yudao.module.rescue.domain;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 路段和人员绑定表
* @author 小李
* @date 9:12 2024/8/26
**/
@Data
@TableName("rescue_dict_staff")
@EqualsAndHashCode(callSuper = true)
public class RescueDictStaff extends TenantBaseDO {
/** 主键标识 */
@TableId(type = IdType.ASSIGN_ID)
private String id;
/** 字典数据ID */
private Long dictId;
/** 管理人员ID */
private Long manageId;
/** 管理人员名字 */
@TableField(exist = false)
private String manageName;
/** 司机们的ID 逗号分隔 */
private String driverIds;
/** 司机们的名字 */
@TableField(exist = false)
private String driverNames;
}

View File

@ -184,4 +184,7 @@ public class RescueInfo extends TenantBaseDO
@TableField(exist = false)
private String rescueStartMonth;
@TableField(exist = false)
private Long[] roadIds;
}

View File

@ -0,0 +1,18 @@
package cn.iocoder.yudao.module.rescue.dto;
import lombok.Data;
/**
* 用于创建定时任务
* @author 小李
* @date 18:41 2024/8/26
**/
@Data
public class TaskDto {
// 谁发起的订单
private Long manageId;
// 发起的订单
private Long rescueInfoId;
}

View File

@ -0,0 +1,9 @@
package cn.iocoder.yudao.module.rescue.mapper;
import cn.iocoder.yudao.module.rescue.domain.RescueDictStaff;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface RescueDictStaffMapper extends BaseMapper<RescueDictStaff> {
}

View File

@ -0,0 +1,12 @@
package cn.iocoder.yudao.module.rescue.service;
import cn.iocoder.yudao.module.rescue.domain.RescueDictStaff;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* 路段和人员绑定表 接口
* @author 小李
* @date 9:13 2024/8/26
**/
public interface IRescueDictStaffService extends IService<RescueDictStaff> {
}

View File

@ -127,33 +127,46 @@ public class DriverInfoServiceImpl extends ServiceImpl<DriverInfoMapper, DriverI
**/
@Override
public void syncData(){
List<DriverInfo> driverInfos = baseMapper.selectList(new QueryWrapper<>());
List<CompanyStaff> companyStaffs = new ArrayList<>();
driverInfos.stream().forEach(item -> {
AdminUserRespDTO user = adminUserApi.getUser(item.getUserId());
if (ObjectUtil.isNotEmpty(user)){
long count = staffService.count(new LambdaQueryWrapper<CompanyStaff>().eq(CompanyStaff::getUserId, user.getId()));
if (count == 0){
CompanyStaff staff = new CompanyStaff();
staff.setUserId(user.getId());
staff.setDeptId(user.getDeptId());
DeptRespDTO dept = deptApi.getDept(user.getDeptId());
staff.setCorpId(dept.getCorpId());
String uniqueCode = uniqueCodeService.createUniqueCode();
if (!ObjectUtil.isNotEmpty(uniqueCode)) {
throw exception(CommonErrorCodeConstants.UNIQUE_CODE_CREATE_REPEAT);
}
staff.setUniqueCode(uniqueCode);
staff.setName(user.getNickname());
staff.setTel(item.getPhonenumber());
staff.setSex(String.valueOf(user.getSex()));
companyStaffs.add(staff);
}
}
});
if (ObjectUtil.isNotEmpty(companyStaffs)){
staffService.saveBatch(companyStaffs);
// List<DriverInfo> driverInfos = baseMapper.selectList(new QueryWrapper<>());
// List<CompanyStaff> companyStaffs = new ArrayList<>();
// driverInfos.stream().forEach(item -> {
// AdminUserRespDTO user = adminUserApi.getUser(item.getUserId());
// if (ObjectUtil.isNotEmpty(user)){
// long count = staffService.count(new LambdaQueryWrapper<CompanyStaff>().eq(CompanyStaff::getUserId, user.getId()));
// if (count == 0){
// CompanyStaff staff = new CompanyStaff();
// staff.setUserId(user.getId());
// staff.setDeptId(user.getDeptId());
// DeptRespDTO dept = deptApi.getDept(user.getDeptId());
// staff.setCorpId(dept.getCorpId());
// String uniqueCode = uniqueCodeService.createUniqueCode();
// if (!ObjectUtil.isNotEmpty(uniqueCode)) {
// throw exception(CommonErrorCodeConstants.UNIQUE_CODE_CREATE_REPEAT);
// }
// staff.setUniqueCode(uniqueCode);
//
// staff.setName(user.getNickname());
// staff.setTel(item.getPhonenumber());
// staff.setSex(String.valueOf(user.getSex()));
// companyStaffs.add(staff);
// }
// }
// });
// if (ObjectUtil.isNotEmpty(companyStaffs)){
// staffService.saveBatch(companyStaffs);
// }
AdminUserRespDTO user = adminUserApi.getUser(708L);
CompanyStaff staff = new CompanyStaff();
staff.setUserId(user.getId());
staff.setDeptId(100L);
staff.setWorkNo("la0000");
staff.setName(user.getNickname());
staff.setTel(user.getMobile());
staff.setSex(String.valueOf(user.getSex()));
String uniqueCode = uniqueCodeService.createUniqueCode();
if (ObjectUtil.isNotEmpty(uniqueCode)){
staff.setUniqueCode(uniqueCode);
}
};
staffService.save(staff);
}
}

View File

@ -0,0 +1,16 @@
package cn.iocoder.yudao.module.rescue.service.impl;
import cn.iocoder.yudao.module.rescue.domain.RescueDictStaff;
import cn.iocoder.yudao.module.rescue.mapper.RescueDictStaffMapper;
import cn.iocoder.yudao.module.rescue.service.IRescueDictStaffService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
* 路段和人员绑定表 接口实现类
* @author 小李
* @date 9:13 2024/8/26
**/
@Service
public class RescueDictStaffServiceImpl extends ServiceImpl<RescueDictStaffMapper, RescueDictStaff> implements IRescueDictStaffService {
}

View File

@ -4,7 +4,9 @@ import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.CoordinateUtil;
import cn.hutool.http.HttpUtil;
import cn.iocoder.yudao.module.rescue.domain.*;
import cn.iocoder.yudao.module.rescue.dto.TaskDto;
import cn.iocoder.yudao.module.rescue.mapper.RescueDriverInfoMapper;
import cn.iocoder.yudao.module.rescue.utils.RedissonDelayQueue;
import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
@ -31,7 +33,8 @@ import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import static cn.hutool.core.util.CoordinateUtil.wgs84ToGcj02;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0;
/**
@ -68,6 +71,8 @@ public class RescueDriverInfoServiceImpl extends ServiceImpl<RescueDriverInfoMap
private WechatPayRequest wechatPayRequest;
@Autowired
private WechatPayConfig wechatPayConfig;
@Resource
private RedissonDelayQueue redissonDelayQueue;
public static String Redis_Driver_Key = "Rescue:Driver:";
public static String Redis_Driver_Position_Key = "DriverPosition:";
@ -294,7 +299,7 @@ public class RescueDriverInfoServiceImpl extends ServiceImpl<RescueDriverInfoMap
lock.lock();
try {
if (!ObjectUtils.isEmpty(rescueInfo.getDriverId())) {
throw new Exception("订单已被抢走");
throw exception0(500, "订单已被抢走");
}
DriverInfo driverInfo = driverInfoService.getById(rescueDriverInfo.getDriverId());
@ -312,7 +317,7 @@ public class RescueDriverInfoServiceImpl extends ServiceImpl<RescueDriverInfoMap
rescueInfo.setDriverPhoneNum(driverInfo.getPhonenumber());
rescueInfo.setDriverCarNum(carInfo.getRescueCarNum());
} else {
throw new Exception("请联系管理员维护车辆信息开始接单");
throw exception0(500,"请联系管理员维护车辆信息开始接单");
}
//状态修改为救援中
rescueInfo.setRescueStatus("3");
@ -361,6 +366,9 @@ public class RescueDriverInfoServiceImpl extends ServiceImpl<RescueDriverInfoMap
map.put("rescueIds", rescueInfo.getId());
redisCache.setCacheMap(redisKey, map);
}
// 删除定时任务
redissonDelayQueue.removeAllTasks(rescueInfo.getId());
} catch (Exception e) {
log.error(e.getMessage());
throw new Exception("出现异常");

View File

@ -2,17 +2,21 @@ package cn.iocoder.yudao.module.rescue.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
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.framework.tenant.core.db.TenantBaseDO;
import cn.iocoder.yudao.module.appBase.domain.SysAnnouncement;
import cn.iocoder.yudao.module.appBase.service.ISysAnnouncementService;
import cn.iocoder.yudao.module.constant.UserConstants;
import cn.iocoder.yudao.module.rescue.domain.*;
import cn.iocoder.yudao.module.rescue.dto.DriverInfo2Dto;
import cn.iocoder.yudao.module.rescue.dto.DriverInfoDto;
import cn.iocoder.yudao.module.rescue.dto.TaskDto;
import cn.iocoder.yudao.module.rescue.mapper.RescueInfoMapper;
import cn.iocoder.yudao.module.rescue.service.*;
import cn.iocoder.yudao.module.rescue.utils.RedisUtil;
import cn.iocoder.yudao.module.rescue.utils.RedissonDelayQueue;
import cn.iocoder.yudao.module.rescue.utils.StringUtils;
import cn.iocoder.yudao.module.rescue.vo.MoneyManagement;
import cn.iocoder.yudao.module.staff.service.CompanyStaffService;
@ -25,6 +29,7 @@ import cn.iocoder.yudao.module.system.api.permission.dto.RoleReqDTO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import cn.iocoder.yudao.module.system.api.user.dto.UserDTO;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@ -92,6 +97,10 @@ public class RescueInfoServiceImpl extends ServiceImpl<RescueInfoMapper, RescueI
private CompanyStaffService staffService;
@Resource
private RoleApi roleApi;
@Resource
private RedissonDelayQueue redissonDelayQueue;
@Resource
private IRescueDictStaffService rescueDictStaffService;
/**
@ -353,6 +362,8 @@ public class RescueInfoServiceImpl extends ServiceImpl<RescueInfoMapper, RescueI
sysAnnouncement.setContent("有新的救援订单请立即处理");
announcementService.insertSysAnnouncements(sysAnnouncement);
// 删除延时消息
redissonDelayQueue.removeAllTasks(rescueId);
}
@ -365,7 +376,7 @@ public class RescueInfoServiceImpl extends ServiceImpl<RescueInfoMapper, RescueI
@Override
public void insertRescueInfo(RescueInfo rescueInfo) {
// 获取当前的用户
LoginUser loginUser = getLoginUser();
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
rescueInfo.setUserId(loginUser.getId());
rescueInfo.setRescueTime(new Date());
@ -380,12 +391,29 @@ public class RescueInfoServiceImpl extends ServiceImpl<RescueInfoMapper, RescueI
rescueInfo.setRescueTime(new Date());
baseMapper.insert(rescueInfo);
detailService.save(new RescueInfoDetail(rescueInfo.getId(), "0", "救援发起", "救援发起"));
// TODO: 2023/12/24 暂时取消自动指派司机
// Thread thread = new Thread(() -> {
// //自动派单
// this.appointDriverByBusiness(deptId,rescueInfo.getId());
// });
// thread.start();
// 自动通知对应路段司机
List<RescueDictStaff> list = rescueDictStaffService.list(new LambdaQueryWrapper<RescueDictStaff>().in(RescueDictStaff::getDictId, rescueInfo.getRoadIds()));
if (CollectionUtil.isNotEmpty(list)){
Set<Long> driverIds = list.stream()
.map(RescueDictStaff::getDriverIds)
.flatMap(item -> Arrays.stream(item.split(",")))
.map(Long::parseLong)
.collect(Collectors.toSet());
driverIds.forEach(item -> {
SysAnnouncement sysAnnouncement = new SysAnnouncement();
sysAnnouncement.setType("救援信息");
sysAnnouncement.setToUserIds(Collections.singletonList(item));
sysAnnouncement.setTitle("有新的救援订单请立即处理");
sysAnnouncement.setContent("有新的救援订单请立即处理");
announcementService.insertSysAnnouncements(sysAnnouncement);
});
}
// 新增延迟消息用于三分钟后没人接单通知
TaskDto taskDto = new TaskDto();
taskDto.setManageId(loginUser.getId());
taskDto.setRescueInfoId(rescueInfo.getId());
redissonDelayQueue.offerTask(JSON.toJSONString(taskDto), UserConstants.RESCUE_TIME);
}
}
@ -401,6 +429,10 @@ public class RescueInfoServiceImpl extends ServiceImpl<RescueInfoMapper, RescueI
if (rescueInfo.getRescueStatus().compareTo("9") > 0) {
rescueInfo.setRescueStatus(null);
}
// 取消订单时删除定时任务
if (rescueInfo.getRescueStatus().equals("0")){
redissonDelayQueue.removeAllTasks(rescueInfo.getId());
}
return baseMapper.updateById(rescueInfo);
}

View File

@ -0,0 +1,186 @@
package cn.iocoder.yudao.module.rescue.utils;
import cn.iocoder.yudao.module.appBase.domain.SysAnnouncement;
import cn.iocoder.yudao.module.appBase.service.ISysAnnouncementService;
import cn.iocoder.yudao.module.constant.UserConstants;
import cn.iocoder.yudao.module.rescue.dto.TaskDto;
import com.alibaba.fastjson.JSON;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBlockingQueue;
import org.redisson.api.RDelayedQueue;
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* Redisson 延迟队列组件用于处理带有延迟时间的任务
*
* @author 小李
* @date 16:37 2024/8/26
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class RedissonDelayQueue {
@Resource
private RedissonClient redissonClient;
// 注入 Redisson 提供的延迟队列接口
private RDelayedQueue<String> delayedQueue;
// 注入 Redisson 提供的阻塞队列接口
private RBlockingQueue<String> blockingQueue;
// 任务索引用于快速查找任务
private RMap<Long, String> taskIndex;
@Resource
private ISysAnnouncementService announcementService;
/**
* 初始化方法 Spring 容器加载后自动执行
* 创建一个固定大小的线程池来消费阻塞队列中的任务
*/
@PostConstruct
public void init() {
blockingQueue = redissonClient.getBlockingQueue("RESCUE_QUEUE");
delayedQueue = redissonClient.getDelayedQueue(blockingQueue);
taskIndex = redissonClient.getMap("RESCUE_INDEX");
// 创建一个单线程的线程池
ExecutorService executorService = Executors.newFixedThreadPool(1);
// 提交一个无限循环的任务到线程池用于持续消费队列中的任务
executorService.submit(() -> {
while (true) {
try {
// 从阻塞队列中获取一个任务如果队列为空则此方法会一直阻塞直到有任务可用
String task = blockingQueue.take();
// 记录接收到的任务信息
log.info("定时任务:{}", task);
// 通知发起者
TaskDto taskDto = JSON.parseObject(task, TaskDto.class);
SysAnnouncement sysAnnouncement = new SysAnnouncement();
sysAnnouncement.setType("救援超时信息");
sysAnnouncement.setToUserIds(Collections.singletonList(taskDto.getManageId()));
sysAnnouncement.setTitle("有救援订单超时请立即处理");
sysAnnouncement.setContent("有救援订单超时请立即处理");
announcementService.insertSysAnnouncements(sysAnnouncement);
// TODO 还要通知总调度
// 在新创建定时任务
offerTask(task, UserConstants.RESCUE_TIME);
} catch (Exception e) {
// 记录并打印异常信息
log.error("发生错误", e);
}
}
});
}
/**
* 向延迟队列中添加一个任务并设置延迟时间
*
* @param task 要添加的任务
* @param seconds 任务的延迟时间单位为秒
*/
public void offerTask(String task, long seconds) {
// 记录添加任务的日志信息
log.info("添加定时任务:{},过期时间为:{}s", task, seconds);
// 从任务中提取 rescueInfoId
TaskDto taskDto = JSON.parseObject(task, TaskDto.class);
Long rescueInfoId = taskDto.getRescueInfoId();
// 存储任务索引
taskIndex.put(rescueInfoId, task);
// 向延迟队列添加任务并设置延迟时间
delayedQueue.offer(task, seconds, TimeUnit.SECONDS);
}
/**
* 从延迟队列中移除指定的任务
*
* @param rescueInfoId 要移除的任务
* @return 移除是否成功
*/
private boolean removeDelayedTask(Long rescueInfoId) {
try {
// 从任务索引中查找任务
String task = taskIndex.get(rescueInfoId);
// 如果找到了任务则尝试从延迟队列中移除任务
if (task != null) {
boolean removed = delayedQueue.remove(task);
if (removed) {
// 从任务索引中移除任务
taskIndex.remove(rescueInfoId);
}
return removed;
}
} catch (Exception e) {
log.error("延迟队列删除失败", e);
}
return false;
}
/**
* 从阻塞队列中移除指定的任务
*
* @param rescueInfoId 要移除的任务
* @return 移除是否成功
*/
private boolean removeBlockingTask(Long rescueInfoId) {
try {
// 从任务索引中查找任务
String task = taskIndex.get(rescueInfoId);
// 如果找到了任务则尝试从阻塞队列中移除任务
if (task != null) {
boolean removed = blockingQueue.remove(task);
if (removed) {
// 从任务索引中移除任务
taskIndex.remove(rescueInfoId);
}
return removed;
}
} catch (Exception e) {
log.error("阻塞队列删除失败", e);
}
return false;
}
/**
* 尝试同时从延迟队列和阻塞队列中移除指定的任务
* 如果任务在任何一个队列中存在则尝试移除
*
* @param rescueInfoId 要移除的任务
* @return 是否至少在一个队列中移除成功
*/
public boolean removeAllTasks(Long rescueInfoId) {
// 尝试从延迟队列中移除任务
boolean removedFromDelayed = removeDelayedTask(rescueInfoId);
// 尝试从阻塞队列中移除任务
boolean removedFromBlocking = removeBlockingTask(rescueInfoId);
// 如果任何一个队列中移除成功则返回 true
return removedFromDelayed || removedFromBlocking;
}
}

View File

@ -0,0 +1,6 @@
<?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="cn.iocoder.yudao.module.rescue.mapper.RescueDictStaffMapper">
</mapper>

View File

@ -72,4 +72,12 @@ public interface PermissionApi {
* @param userId 用户ID
**/
List<Long> getRoleIdsByUserId(Long userId);
/**
* 根据权限ID拿拥有该权限的所有人
* @author 小李
* @date 10:25 2024/8/26
* @param roleId 权限ID
**/
List<Long> getUserIdByRoleId(Long roleId);
}

View File

@ -77,4 +77,15 @@ public class PermissionApiImpl implements PermissionApi {
return roleIds.stream().collect(Collectors.toList());
}
/**
* 根据权限ID拿拥有该权限的所有人
* @author 小李
* @date 10:25 2024/8/26
* @param roleId 权限ID
**/
@Override
public List<Long> getUserIdByRoleId(Long roleId){
return permissionService.getUserIdByRoleId(roleId);
}
}

View File

@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.system.service.permission;
import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import static java.util.Collections.singleton;
@ -161,4 +162,12 @@ public interface PermissionService {
*/
DeptDataPermissionRespDTO getDeptDataPermission(Long userId);
/**
* 根据权限ID拿拥有该权限的所有人
* @author 小李
* @date 10:25 2024/8/26
* @param roleId 权限ID
**/
List<Long> getUserIdByRoleId(Long roleId);
}

View File

@ -7,6 +7,7 @@ import cn.hutool.extra.spring.SpringUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
@ -33,6 +34,7 @@ import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.*;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
@ -359,4 +361,15 @@ public class PermissionServiceImpl implements PermissionService {
return SpringUtil.getBean(getClass());
}
/**
* 根据权限ID拿拥有该权限的所有人
* @author 小李
* @date 10:25 2024/8/26
* @param roleId 权限ID
**/
public List<Long> getUserIdByRoleId(Long roleId){
List<UserRoleDO> userRoleDOS = userRoleMapper.selectList(new LambdaQueryWrapperX<UserRoleDO>().eq(UserRoleDO::getRoleId, roleId));
List<Long> userIds = userRoleDOS.stream().map(item -> item.getUserId()).collect(Collectors.toList());
return userIds;
}
}