|
@@ -1,18 +1,22 @@
|
|
|
package com.qmrb.system.service.impl;
|
|
|
|
|
|
-import java.util.ArrayList;
|
|
|
-import java.util.Collections;
|
|
|
-import java.util.List;
|
|
|
-import java.util.Set;
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
+import java.util.*;
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
+import cn.hutool.core.date.DateField;
|
|
|
+import cn.hutool.core.date.DateUtil;
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
+import com.qmrb.system.common.result.Result;
|
|
|
import com.qmrb.system.pojo.entity.Contract;
|
|
|
+import com.qmrb.system.pojo.entity.ContractPlaceNumberRel;
|
|
|
+import com.qmrb.system.service.IContractPlaceNumberRelHisService;
|
|
|
+import com.qmrb.system.utils.DateUtils;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
-import com.qmrb.system.common.enums.StatusEnum;
|
|
|
-import com.qmrb.system.pojo.vo.Option;
|
|
|
import com.qmrb.system.converter.VirtualParkingSlotConverter;
|
|
|
import com.qmrb.system.pojo.entity.VirtualParkingSlot;
|
|
|
import com.qmrb.system.pojo.form.VirtualParkingSlotForm;
|
|
@@ -42,6 +46,9 @@ public class VirtualParkingSlotServiceImpl extends ServiceImpl<VirtualParkingSlo
|
|
|
|
|
|
@Autowired
|
|
|
private VirtualParkingSlotConverter converter;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IContractPlaceNumberRelHisService contractPlaceNumberRelHisService;
|
|
|
|
|
|
/**分页查询
|
|
|
* */
|
|
@@ -86,6 +93,7 @@ public class VirtualParkingSlotServiceImpl extends ServiceImpl<VirtualParkingSlo
|
|
|
*/
|
|
|
@Override
|
|
|
public void createFormsByContract(Contract contract) {
|
|
|
+ VirtualParkingSlot lastOne = this.getOne(new LambdaQueryWrapper<VirtualParkingSlot>().orderByDesc(VirtualParkingSlot::getId).last("limit 1"));
|
|
|
// 1 判断该包租协议是否已创建虚拟车位
|
|
|
List<VirtualParkingSlot> list = this.list(new LambdaQueryWrapper<VirtualParkingSlot>().eq(VirtualParkingSlot::getContractId, contract.getId())
|
|
|
.ne(VirtualParkingSlot::getStatus,"2").orderByAsc(VirtualParkingSlot::getId));
|
|
@@ -125,7 +133,8 @@ public class VirtualParkingSlotServiceImpl extends ServiceImpl<VirtualParkingSlo
|
|
|
}).collect(Collectors.toList());
|
|
|
|
|
|
// 增加虚拟车位
|
|
|
- Integer index = allVirtuals.size() + 1;;
|
|
|
+ // Integer index = allVirtuals.size() + 1;;
|
|
|
+ Long index = lastOne.getId() + 1;
|
|
|
List<VirtualParkingSlot> newVirtuals = new ArrayList<>();
|
|
|
for(int i = contract.getMaxParkingLotNum(); i > allVirtuals.size();i--){
|
|
|
VirtualParkingSlot virtualParkingSlot = new VirtualParkingSlot();
|
|
@@ -142,7 +151,8 @@ public class VirtualParkingSlotServiceImpl extends ServiceImpl<VirtualParkingSlo
|
|
|
}else{
|
|
|
// 首次创建包租协议,初始化虚拟车位
|
|
|
list = new ArrayList<>();
|
|
|
- Integer index = 1;
|
|
|
+ // Integer index = 1;
|
|
|
+ Long index = lastOne != null ? lastOne.getId() + 1 : 1L;
|
|
|
for(int i = contract.getMaxParkingLotNum(); i > 0;i--){
|
|
|
VirtualParkingSlot virtualParkingSlot = new VirtualParkingSlot();
|
|
|
virtualParkingSlot.setContractId(contract.getId());
|
|
@@ -177,5 +187,133 @@ public class VirtualParkingSlotServiceImpl extends ServiceImpl<VirtualParkingSlo
|
|
|
VirtualParkingSlotForm form = converter.entity2Form(entity);
|
|
|
return form;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据包租协议虚拟车位登记记录分配虚拟车位
|
|
|
+ * @param contractPlaceNumberRel
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public VirtualParkingSlotForm assignParkingSpot(ContractPlaceNumberRel contractPlaceNumberRel) {
|
|
|
+ VirtualParkingSlot virtualParkingSlot = null;
|
|
|
+ // 判断该车牌是否已占用车位
|
|
|
+ List<VirtualParkingSlot> occupyVirtualParkingSlots = this.list(new LambdaQueryWrapper<VirtualParkingSlot>()
|
|
|
+ .eq(VirtualParkingSlot::getStatus, "1")//已占用
|
|
|
+ .eq(VirtualParkingSlot::getContractId, contractPlaceNumberRel.getContractId())
|
|
|
+ .eq(VirtualParkingSlot::getCurrentPlateNumber, contractPlaceNumberRel.getPlateNumber())
|
|
|
+ .orderByAsc(VirtualParkingSlot::getContractId));
|
|
|
+ if(CollectionUtil.isNotEmpty(occupyVirtualParkingSlots)){
|
|
|
+ virtualParkingSlot = occupyVirtualParkingSlots.get(0);
|
|
|
+ virtualParkingSlot.setLastOccupiedTime(contractPlaceNumberRel.getStartTime());
|
|
|
+ this.updateById(virtualParkingSlot);
|
|
|
+ }else{
|
|
|
+ // 判断该包租协议下是否有空闲虚拟车位
|
|
|
+ List<VirtualParkingSlot> freeVirtualParkingSlots = this.list(new LambdaQueryWrapper<VirtualParkingSlot>()
|
|
|
+ .eq(VirtualParkingSlot::getStatus, "0")//空闲
|
|
|
+ .eq(VirtualParkingSlot::getContractId, contractPlaceNumberRel.getContractId())
|
|
|
+ .orderByAsc(VirtualParkingSlot::getContractId));
|
|
|
+ Assert.isTrue(CollectionUtil.isNotEmpty(freeVirtualParkingSlots),"无可用车位");
|
|
|
+ virtualParkingSlot = freeVirtualParkingSlots.get(0);
|
|
|
+ virtualParkingSlot.setStatus("1");//占用
|
|
|
+ virtualParkingSlot.setSlotType(StrUtil.equals("1",contractPlaceNumberRel.getCarType())? "small" : "large");
|
|
|
+ virtualParkingSlot.setCurrentPlateNumber(contractPlaceNumberRel.getPlateNumber());
|
|
|
+ virtualParkingSlot.setLastOccupiedTime(contractPlaceNumberRel.getStartTime());
|
|
|
+ virtualParkingSlot.setLastReleasedTime(contractPlaceNumberRel.getEndTime());
|
|
|
+ this.updateById(virtualParkingSlot);
|
|
|
+ }
|
|
|
+
|
|
|
+ return converter.entity2Form(virtualParkingSlot);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Result<VirtualParkingSlotForm> validParingSlot(String slotNumber, String plateNumber, Date currentDate) {
|
|
|
+ VirtualParkingSlot virtualParkingSlot = this.getOne(new LambdaQueryWrapper<VirtualParkingSlot>().eq(VirtualParkingSlot::getVirtualSlotNumber, slotNumber));
|
|
|
+ if(virtualParkingSlot == null){
|
|
|
+ return Result.failed("虚拟车位不存在!");
|
|
|
+ }
|
|
|
+ Date lastOccupiedTime = null;//开始时间
|
|
|
+ Date lastReleasedTime = virtualParkingSlot.getLastReleasedTime();//结束时间
|
|
|
+ if(StrUtil.equals(plateNumber,virtualParkingSlot.getCurrentPlateNumber()) && lastReleasedTime != null ){
|
|
|
+ // 获取n-2天零时零分零秒
|
|
|
+ Date beforeYesterday = DateUtils.getStartOfDay(DateUtil.offset(currentDate, DateField.DAY_OF_MONTH, -2));
|
|
|
+
|
|
|
+ if(lastReleasedTime.after(beforeYesterday)){
|
|
|
+ lastOccupiedTime = virtualParkingSlot.getLastReleasedTime();//2025-04-17 14:00:00
|
|
|
+ }else{
|
|
|
+ lastOccupiedTime = currentDate;
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ lastOccupiedTime = currentDate;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 结束时间固定为次日(N+1)14:00
|
|
|
+ Date endTime = DateUtil.parse(DateUtil.format(DateUtil.offset(currentDate, DateField.DAY_OF_MONTH, 1), "yyyy-MM-dd") + " 14:00:00");
|
|
|
+ lastReleasedTime = endTime;
|
|
|
+ log.info("开始时间:{}→结束时间:{} ===>{}",lastOccupiedTime,lastReleasedTime, JSON.toJSON(virtualParkingSlot));
|
|
|
+ // 登记时间段(开始时间→结束时间)不得与该虚拟车位有效的历史记录重叠
|
|
|
+ if(virtualParkingSlot.getLastOccupiedTime() != null && virtualParkingSlot.getLastReleasedTime() != null){
|
|
|
+
|
|
|
+ log.info("222222:{}→结束时间:{}",virtualParkingSlot.getLastOccupiedTime(),virtualParkingSlot.getLastReleasedTime());
|
|
|
+ if(this.isOverlap(virtualParkingSlot.getLastOccupiedTime(),virtualParkingSlot.getLastReleasedTime(),lastOccupiedTime,lastReleasedTime)){
|
|
|
+ return Result.failed("车位启用时间或到期时间有误!");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ String hour = DateUtil.format(lastReleasedTime, "HH");
|
|
|
+ log.info("hour:{}",hour);
|
|
|
+ if(!StrUtil.equals(hour,"14")){
|
|
|
+ return Result.failed("到期时间必须为次日14时!");
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ virtualParkingSlot.setLastOccupiedTime(lastOccupiedTime);
|
|
|
+ virtualParkingSlot.setLastReleasedTime(lastReleasedTime);
|
|
|
+ virtualParkingSlot.setCurrentPlateNumber(plateNumber);
|
|
|
+ return Result.success(converter.entity2Form(virtualParkingSlot));
|
|
|
+ }
|
|
|
+
|
|
|
+ public static boolean isOverlap(Date start1, Date end1, Date start2, Date end2) {
|
|
|
+ // 1. 校验参数非空
|
|
|
+ if (start1 == null || end1 == null || start2 == null || end2 == null) {
|
|
|
+ throw new IllegalArgumentException("时间参数不能为null");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 校验时间段有效性(开始时间 <= 结束时间)
|
|
|
+ if (start1.after(end1) || start2.after(end2)) {
|
|
|
+ throw new IllegalArgumentException("开始时间不能晚于结束时间");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 核心逻辑:判断是否有重叠(左闭右开区间)
|
|
|
+ return start1.before(end2) && start2.before(end1);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void releaseVirtualParking(){
|
|
|
+ log.info("定时释放虚拟车位:开始:" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
|
|
+ List<VirtualParkingSlot> list = this.list(new LambdaQueryWrapper<VirtualParkingSlot>().eq(VirtualParkingSlot::getStatus, "1"));
|
|
|
+ if(CollectionUtil.isEmpty(list)){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Date now = new Date();
|
|
|
+ List<VirtualParkingSlot> releasedList = new ArrayList<>();
|
|
|
+ for (VirtualParkingSlot virtualParkingSlot : list) {
|
|
|
+ if(now.after(virtualParkingSlot.getLastReleasedTime())){
|
|
|
+ releasedList.add(virtualParkingSlot);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(CollectionUtil.isEmpty(releasedList)){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ log.info("定时释放虚拟车位数:" + releasedList.size() + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
|
|
+ releasedList = releasedList.stream().map(iter->{
|
|
|
+ iter.setLastReleasedTime(null);
|
|
|
+ iter.setLastOccupiedTime(null);
|
|
|
+ iter.setCurrentPlateNumber(null);
|
|
|
+ iter.setSlotType("small");
|
|
|
+ iter.setStatus("0");
|
|
|
+ return iter;
|
|
|
+ }).collect(Collectors.toList());
|
|
|
+ this.updateBatchById(releasedList);
|
|
|
+ log.info("定时释放虚拟车位:结束:" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
|
|
+ }
|
|
|
+
|
|
|
}
|