Przeglądaj źródła

Merge remote-tracking branch 'origin/master'

luoyb 1 rok temu
rodzic
commit
2cd96123c5
45 zmienionych plików z 1469 dodań i 52 usunięć
  1. 1 0
      ruoyi-api/ruoyi-api-hotel/src/main/java/org/dromara/hotel/api/domain/vo/RemoteOrderVo.java
  2. 1 1
      ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/Constants.java
  3. 12 0
      ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/HotelBusinessConstants.java
  4. 61 0
      ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/SmsUtils.java
  5. 6 4
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/basics/controller/PtAreaController.java
  6. 42 21
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/basics/controller/PtRoomController.java
  7. 48 0
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/basics/domain/bo/QueryRoomBo.java
  8. 4 1
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/basics/mapper/PtRoomMapper.java
  9. 1 1
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/basics/service/IPtAreaService.java
  10. 10 0
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/basics/service/IPtRoomService.java
  11. 10 4
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/basics/service/impl/PtAreaServiceImpl.java
  12. 45 1
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/basics/service/impl/PtRoomServiceImpl.java
  13. 22 3
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/business/lock/LockBusiness.java
  14. 5 0
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/controller/lock/LockController.java
  15. 2 1
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/mq/KafkaNormalConsumer.java
  16. 6 1
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/util/LockUtils.java
  17. 11 0
      ruoyi-modules/ruoyi-backstage/src/main/resources/mapper/basics/room/PtRoomMapper.xml
  18. 5 6
      ruoyi-modules/ruoyi-backstage/src/test/java/org/dromara/backstage/mq/KafkaProducerTest.java
  19. 106 0
      ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/controller/KfDoorOpenHisController.java
  20. 13 0
      ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/controller/KfGuestController.java
  21. 61 0
      ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/controller/KfOrderController.java
  22. 74 0
      ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/domain/KfDoorOpenHis.java
  23. 87 0
      ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/domain/bo/ChangeRoomBo.java
  24. 40 0
      ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/domain/bo/ChangeRoomStatusBo.java
  25. 68 0
      ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/domain/bo/KfDoorOpenHisBo.java
  26. 1 0
      ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/domain/bo/KfGuestBo.java
  27. 78 0
      ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/domain/vo/KfDoorOpenHisVo.java
  28. 5 0
      ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/domain/vo/KfGuestVo.java
  29. 1 0
      ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/domain/vo/KfTeamGuestVo.java
  30. 15 0
      ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/mapper/KfDoorOpenHisMapper.java
  31. 5 0
      ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/mapper/KfGuestMapper.java
  32. 8 0
      ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/mapper/KfOrderMapper.java
  33. 69 0
      ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/service/IKfDoorOpenHisService.java
  34. 8 0
      ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/service/IKfGuestService.java
  35. 24 1
      ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/service/IKfOrderService.java
  36. 150 0
      ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/service/impl/KfDoorOpenHisServiceImpl.java
  37. 13 0
      ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/service/impl/KfGuestServiceImpl.java
  38. 239 5
      ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/service/impl/KfOrderServiceImpl.java
  39. 17 0
      ruoyi-modules/ruoyi-hotel/src/main/resources/mapper/hotel/basics/KfGuestMapper.xml
  40. 9 1
      ruoyi-modules/ruoyi-hotel/src/main/resources/mapper/hotel/business/KfOrderMapper.xml
  41. 24 0
      ruoyi-modules/ruoyi-hotel/src/main/resources/mapper/hotel/report/KfDoorOpenHisMapper.xml
  42. 15 0
      ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/controller/SysSmsController.java
  43. 4 0
      ruoyi-modules/ruoyi-system/pom.xml
  44. 42 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysSmsController.java
  45. 1 1
      ruoyi-visual/ruoyi-nacos/pom.xml

+ 1 - 0
ruoyi-api/ruoyi-api-hotel/src/main/java/org/dromara/hotel/api/domain/vo/RemoteOrderVo.java

@@ -21,6 +21,7 @@ public class RemoteOrderVo implements Serializable {
     @Serial
     private static final long serialVersionUID = -4941828023451615520L;
 
+    private Long id;
     //region 客人基本信息
     /**
      * 客人ID

+ 1 - 1
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/Constants.java

@@ -65,7 +65,7 @@ public interface Constants {
     /**
      * 验证码有效期(分钟)
      */
-    Integer CAPTCHA_EXPIRATION = 2;
+    Integer CAPTCHA_EXPIRATION = 5;
 
     /**
      * 令牌

+ 12 - 0
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/HotelBusinessConstants.java

@@ -1,5 +1,9 @@
 package org.dromara.common.core.constant;
 
+import org.dromara.common.core.enums.HotelRoomStatusEnum;
+
+import java.util.Map;
+
 /**
  * @author Hz
  * @date 2024/11/15
@@ -31,4 +35,12 @@ public class HotelBusinessConstants {
     /** 是 */
     public static final String YES = "1";
 
+
+    /** 订单状态和房间状态对应关系*/
+    public static final Map<String, String> orderStatusRoomStatusMap = Map.of(
+        ORDER_STATUS_YD, HotelRoomStatusEnum.YD.code()
+        , ORDER_STATUS_SF, HotelRoomStatusEnum.SF.code()
+        , ORDER_STATUS_RZ, HotelRoomStatusEnum.YZ.code()
+        , ORDER_STATUS_TF, HotelRoomStatusEnum.ZF.code());
+
 }

+ 61 - 0
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/SmsUtils.java

@@ -0,0 +1,61 @@
+package org.dromara.common.core.utils;
+
+import cn.hutool.http.HttpRequest;
+import com.alibaba.fastjson.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+
+/**
+ * @author Hz
+ * @date 2024/11/27
+ * @description 短信平台工具类
+ */
+@Slf4j
+public class SmsUtils {
+
+    public static final String PHONE_CODE_PREFIX = "PhoneCode_";
+
+    @Value("sms.swdx.url")
+    private static String url = "http://172.16.137.85:9023";
+    @Value("sms.swdx.user")
+    private static String user = "jw";
+    @Value("sms.swdx.pwd")
+    private static String pwd = "jw@Swdx20220414";
+
+    public static Boolean send(String phones, String content) {
+        boolean flag = false;
+        String sendUrl = url + "/sms/api/v1/send";
+        String token = getToken();
+
+        if(StringUtils.isNotBlank(token)){
+            String body = "{\"mobile\":\"" + phones + "\",\"message\":\"" + content + "\"}";
+            String res = HttpRequest.post(sendUrl)
+                .header("token", token)
+                .body(body)
+                .execute().body();
+            JSONObject resJson = JSONObject.parseObject(res);
+            flag = resJson.getBoolean("success");
+        }
+        return flag;
+    }
+
+    /** 获取短信平台token*/
+    private static String getToken() {
+        String token = "";
+        try {
+            String loginUrl = url + "/sms/api/v1/login";
+            String res = HttpRequest.post(loginUrl)
+                .body("{\"name\":\"" + user + "\",\"pwd\":\"" + pwd + "\"}")
+                .execute().body();
+            JSONObject body = JSONObject.parseObject(res);
+            if(body.getBoolean("success")){
+                token = body.getString("data");
+            }
+        }catch (Exception e) {
+            log.error("获取token异常!", e);
+        }
+
+        return token;
+    }
+
+}

+ 6 - 4
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/basics/controller/PtAreaController.java

@@ -54,16 +54,18 @@ public class PtAreaController extends BaseController {
     }
 
     /**
-     * 查询非楼层的区域列表
+     * 查询有客房的区域列表
      * @param
      * @return
      */
-    @GetMapping("/listNoLC")
-    public R<List<PtAreaVo>> listNoLC() {
-        List<PtAreaVo> list = ptAreaService.queryListNoLC();
+    @GetMapping("/listHasKF")
+    public R<List<PtAreaVo>> listHasKF() {
+        List<PtAreaVo> list = ptAreaService.queryListHasKF();
         return R.ok(list);
     }
 
+
+
     /**
      * 查询楼层列表
      * @param bo

+ 42 - 21
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/basics/controller/PtRoomController.java

@@ -1,38 +1,41 @@
 package org.dromara.backstage.basics.controller;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-import lombok.RequiredArgsConstructor;
-import jakarta.servlet.http.HttpServletResponse;
-import jakarta.validation.constraints.*;
 import cn.dev33.satoken.annotation.SaCheckPermission;
-import org.dromara.common.message.kafka.aop.annotation.SyncDataToLocal;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.RequiredArgsConstructor;
 import org.dromara.backstage.basics.domain.bo.PtRoomBatchSetBo;
+import org.dromara.backstage.basics.domain.bo.PtRoomBo;
+import org.dromara.backstage.basics.domain.bo.QueryRoomBo;
 import org.dromara.backstage.basics.domain.vo.PtAreaVo;
 import org.dromara.backstage.basics.domain.vo.PtRoomTempImportVo;
+import org.dromara.backstage.basics.domain.vo.PtRoomVo;
 import org.dromara.backstage.basics.listener.PtRoomImportListener;
-import org.dromara.common.excel.core.ExcelResult;
-import org.dromara.system.api.RemoteDictService;
-import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.*;
-import org.springframework.validation.annotation.Validated;
-import org.dromara.common.idempotent.annotation.RepeatSubmit;
-import org.dromara.common.log.annotation.Log;
-import org.dromara.common.web.core.BaseController;
-import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.backstage.basics.service.IPtRoomService;
 import org.dromara.common.core.domain.R;
+import org.dromara.common.core.enums.FJLXEnum;
+import org.dromara.common.core.enums.HotelRoomStatusEnum;
 import org.dromara.common.core.validate.AddGroup;
 import org.dromara.common.core.validate.EditGroup;
-import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.excel.core.ExcelResult;
 import org.dromara.common.excel.utils.ExcelUtil;
-import org.dromara.backstage.basics.domain.vo.PtRoomVo;
-import org.dromara.backstage.basics.domain.bo.PtRoomBo;
-import org.dromara.backstage.basics.service.IPtRoomService;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.message.kafka.aop.annotation.SyncDataToLocal;
+import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.web.core.BaseController;
+import org.springframework.http.MediaType;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
 import static org.dromara.common.message.kafka.constant.MessageEventTypeConstants.*;
 
 /**
@@ -59,6 +62,14 @@ public class PtRoomController extends BaseController {
         return ptRoomService.queryPageList(bo, pageQuery);
     }
 
+//    @SaCheckPermission("room:ptRoom:getCountByStatus")
+    @GetMapping("/getPageListByAreaIds")
+    public TableDataInfo<PtRoomVo> getPageListByAreaIds(QueryRoomBo bo, PageQuery pageQuery) {
+        bo.setStatus(HotelRoomStatusEnum.OK.code());
+        bo.setRoomType(FJLXEnum.KF.code());
+        return ptRoomService.queryPageListByAreaIds(bo, pageQuery);
+    }
+
     @SaCheckPermission("room:ptRoom:list")
     @GetMapping("/queryRoom2AreaList")
     public R<Map<Long, List<PtAreaVo>>> queryRoom2AreaList(PtRoomBo bo) {
@@ -178,4 +189,14 @@ public class PtRoomController extends BaseController {
     public R<Map<String, Long>> getCountByStatus() {
         return R.ok(ptRoomService.getCountByStatus());
     }
+
+    /**
+     * 根据房间编号和楼层查询房间信息
+     */
+
+    @SaCheckPermission("room:ptRoom:list")
+    @GetMapping("/hotel/room")
+    public R<List<PtRoomVo>> queryHotelRoom(PtRoomBo bo) {
+        return R.ok(ptRoomService.queryHotelRoomList(bo.getAreaId()));
+    }
 }

+ 48 - 0
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/basics/domain/bo/QueryRoomBo.java

@@ -0,0 +1,48 @@
+package org.dromara.backstage.basics.domain.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.backstage.basics.domain.PtRoom;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.tenant.core.TenantEntity;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 查询房间定义业务对象
+ *
+ * @author bing
+ * @date 2024-08-09
+ */
+@Data
+public class QueryRoomBo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = -2066736243150515345L;
+
+
+    /**
+     * 房间编码
+     */
+    private String roomCode;
+
+    /**
+     * 楼层
+     */
+    private List<Long> floorIds;
+
+    private String status;
+
+    private String roomType;
+
+
+
+
+
+}

+ 4 - 1
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/basics/mapper/PtRoomMapper.java

@@ -1,9 +1,12 @@
 package org.dromara.backstage.basics.mapper;
 
+import org.apache.ibatis.annotations.Param;
 import org.dromara.backstage.basics.domain.PtRoom;
 import org.dromara.backstage.basics.domain.vo.PtRoomVo;
 import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
 
+import java.util.List;
+
 /**
  * 房间定义Mapper接口
  *
@@ -11,5 +14,5 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
  * @date 2024-08-09
  */
 public interface PtRoomMapper extends BaseMapperPlus<PtRoom, PtRoomVo> {
-
+    List<PtRoomVo> selectHotelRoomList(@Param("areaIds") List<Long> areaIds);
 }

+ 1 - 1
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/basics/service/IPtAreaService.java

@@ -35,7 +35,7 @@ public interface IPtAreaService {
      * @return 建筑物区域列表
      */
     List<PtAreaVo> queryList(PtAreaBo bo);
-    List<PtAreaVo> queryListNoLC();
+    List<PtAreaVo> queryListHasKF();
     List<PtAreaVo> queryByLDList(List<PtAreaBo> dataList);
 
     List<PtAreaVo> queryListLD(Long areaId);

+ 10 - 0
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/basics/service/IPtRoomService.java

@@ -1,6 +1,7 @@
 package org.dromara.backstage.basics.service;
 
 import org.dromara.backstage.basics.domain.bo.PtRoomBatchSetBo;
+import org.dromara.backstage.basics.domain.bo.QueryRoomBo;
 import org.dromara.backstage.basics.domain.vo.PtAreaVo;
 import org.dromara.backstage.basics.domain.vo.PtRoomVo;
 import org.dromara.backstage.basics.domain.bo.PtRoomBo;
@@ -36,6 +37,8 @@ public interface IPtRoomService {
      */
     TableDataInfo<PtRoomVo> queryPageList(PtRoomBo bo, PageQuery pageQuery);
 
+    TableDataInfo<PtRoomVo> queryPageListByAreaIds(QueryRoomBo bo, PageQuery pageQuery);
+
     List<PtRoomVo> queryRoomByAreaId(Long areaId);
 
     /**
@@ -105,4 +108,11 @@ public interface IPtRoomService {
      * @return 更新结果
      */
     Boolean updateGuestRoomStatus(String roomCode, String tenantId, String roomStatus);
+
+    /**
+     * 查询酒店下的所有客房
+     * @param hotelId 客房区域id
+     * @return 客房集合
+     */
+    List<PtRoomVo> queryHotelRoomList(Long hotelId);
 }

+ 10 - 4
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/basics/service/impl/PtAreaServiceImpl.java

@@ -80,7 +80,7 @@ public class PtAreaServiceImpl implements IPtAreaService {
     }
 
     @Override
-    public List<PtAreaVo> queryListNoLC() {
+    public List<PtAreaVo> queryListHasKF() {
 //        lqw.notIn(PtArea::getAreaType, BuildAreaTypeEnum.LC.code());
 
         List<PtAreaVo> ptAreaVos = baseMapper.selectVoList();
@@ -104,8 +104,11 @@ public class PtAreaServiceImpl implements IPtAreaService {
                 .filter(ptRoomVo -> HotelRoomStatusEnum.OK.code().equals(ptRoomVo.getStatus())).count());
         });
 
+        //去掉没有客房的楼层
+        lcs = lcs.stream().filter(ptAreaVo -> ptAreaVo.getAllCount() > 0).toList();
+
         // 楼栋
-        List<PtAreaVo> lds = rs.stream().filter(ptAreaVo -> ptAreaVo.getAreaType().equals(BuildAreaTypeEnum.LD.code())).toList();
+        List<PtAreaVo> lds = rs.stream().filter(ptAreaVo -> BuildAreaTypeEnum.LD.code().equals(ptAreaVo.getAreaType())).toList();
 
         setCount(lcs, lds);
 
@@ -117,13 +120,13 @@ public class PtAreaServiceImpl implements IPtAreaService {
         // 校区
         List<PtAreaVo> xqs = vos.stream().filter(ptAreaVo -> ptAreaVo.getAreaType().equals(BuildAreaTypeEnum.XQ.code())).toList();
         // 排除 没有 子节点的 校区
-        List<PtAreaVo> result = vos.stream().filter(ptAreaVo -> {
+        List<PtAreaVo> result = new ArrayList<>(vos.stream().filter(ptAreaVo -> {
             if (ptAreaVo.getAreaType().equals(BuildAreaTypeEnum.XQ.code())) {
                 return vos.stream().anyMatch(ptAreaVo1 -> ptAreaVo1.getParentId().equals(ptAreaVo.getAreaId()));
             } else {
                 return true;
             }
-        }).toList();
+        }).toList());
         // 统计校区
         List<PtAreaVo> capList = result.stream().filter(ptAreaVo -> BuildAreaTypeEnum.XQ.code().equals(ptAreaVo.getAreaType())).toList();
         setCount(result, capList);
@@ -132,6 +135,9 @@ public class PtAreaServiceImpl implements IPtAreaService {
         List<PtAreaVo> schoolList = result.stream().filter(ptAreaVo -> BuildAreaTypeEnum.XX.code().equals(ptAreaVo.getAreaType())).toList();
         setCount(result, schoolList);
 
+        //加上楼层
+        result.addAll(lcs);
+
         return result;
     }
 

+ 45 - 1
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/basics/service/impl/PtRoomServiceImpl.java

@@ -3,8 +3,11 @@ package org.dromara.backstage.basics.service.impl;
 import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.map.MapUtil;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import org.dromara.backstage.basics.domain.PtRoomType;
 import org.dromara.backstage.basics.domain.bo.PtRoomBatchSetBo;
+import org.dromara.backstage.basics.domain.bo.QueryRoomBo;
 import org.dromara.backstage.basics.domain.vo.PtAreaVo;
+import org.dromara.backstage.basics.mapper.PtRoomTypeMapper;
 import org.dromara.common.core.constant.CacheNames;
 import org.dromara.common.core.enums.FJLXEnum;
 import org.dromara.common.core.enums.HotelRoomStatusEnum;
@@ -43,6 +46,8 @@ public class PtRoomServiceImpl implements IPtRoomService {
 
     private final PtAreaServiceImpl areaService;
 
+    private final PtRoomTypeMapper roomTypeMapper;
+
 //    public static final String ROOM_KF = "10";
 
     /**
@@ -90,6 +95,29 @@ public class PtRoomServiceImpl implements IPtRoomService {
         return TableDataInfo.build(result);
     }
 
+    @Override
+    public TableDataInfo<PtRoomVo> queryPageListByAreaIds(QueryRoomBo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<PtRoom> lqw = new LambdaQueryWrapper<>();
+        lqw.eq(StringUtils.isNotBlank(bo.getRoomType()),PtRoom::getRoomType, bo.getRoomType());
+        lqw.eq(StringUtils.isNotBlank(bo.getStatus()),PtRoom::getStatus, bo.getStatus());
+        lqw.in(CollectionUtil.isNotEmpty(bo.getFloorIds()),PtRoom::getAreaId, bo.getFloorIds())
+            .and(StringUtils.isNotBlank(bo.getRoomCode()),
+                e -> e.eq(PtRoom::getRoomCode, bo.getRoomCode()).or().eq(PtRoom::getRoomName, bo.getRoomCode()));
+        lqw.orderByDesc(PtRoom::getCreateTime);
+        Page<PtRoomVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        List<PtRoomVo> records = result.getRecords();
+        if(CollectionUtil.isNotEmpty(records)){
+            List<PtRoomType> ptRoomTypes = roomTypeMapper.selectBatchIds(records.stream().map(PtRoomVo::getGuestRoomType).collect(Collectors.toList()));
+            Map<Long, PtRoomType> ptRoomTypeMap = ptRoomTypes.stream().collect(Collectors.toMap(PtRoomType::getRoomTypeId, e -> e));
+            records.forEach(x -> {
+                PtRoomType ptRoomType = ptRoomTypeMap.get(x.getGuestRoomType() == null ? "" : x.getGuestRoomType());
+                x.setGuestRoomTypeName(Optional.ofNullable(ptRoomType).map(PtRoomType::getRoomTypeName).orElse(""));
+            });
+        }
+
+        return TableDataInfo.build(result);
+    }
+
     /**
      * 根据areaId查询下面的所有房间
      */
@@ -103,7 +131,6 @@ public class PtRoomServiceImpl implements IPtRoomService {
             lqw.in(PtRoom::getAreaId, areaIds);
             rs = baseMapper.selectVoList(lqw);
         }
-
         return rs;
     }
 
@@ -363,4 +390,21 @@ public class PtRoomServiceImpl implements IPtRoomService {
 
         return baseMapper.update(null,luw)>0;
     }
+    /**
+     * 查询酒店下的所有客房
+     * @param hotelId 客房区域id
+     * @return 客房集合
+     */
+    @Override
+    public List<PtRoomVo> queryHotelRoomList(Long hotelId) {
+        List<PtRoomVo> rs = new ArrayList<>();
+        //先查询楼层,在查询楼层下面的房间
+        List<PtAreaVo> ptAreaVos = areaService.queryListLD(hotelId);
+        if(CollectionUtil.isNotEmpty(ptAreaVos)){
+            LambdaQueryWrapper<PtRoom> lqw = Wrappers.lambdaQuery();
+            List<Long> areaIds = ptAreaVos.stream().map(PtAreaVo::getAreaId).toList();;
+            rs = baseMapper.selectHotelRoomList(areaIds);
+        }
+        return rs;
+    }
 }

+ 22 - 3
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/business/lock/LockBusiness.java

@@ -7,6 +7,8 @@ import cn.hutool.json.JSONObject;
 import cn.hutool.json.JSONUtil;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.dromara.backstage.basics.domain.vo.PtRoomVo;
+import org.dromara.backstage.basics.service.IPtRoomService;
 import org.dromara.backstage.domain.bo.lock.RoomCardBo;
 import org.dromara.backstage.util.LockUtils;
 import org.dromara.common.core.constant.DefaultConstants;
@@ -31,21 +33,31 @@ import java.util.Map;
 @RequiredArgsConstructor
 public class LockBusiness {
     private final LockUtils lockUtils;
+    private final IPtRoomService roomService;
 
+    /**
+     * 获取门锁发卡数据
+     *
+     * @param bo 门锁发卡业务对象
+     * @return 发卡数据
+     */
     public R<String> getWriteCardData(RoomCardBo bo) {
         Integer cardType = bo.getCardType();
         String cardData = "";
         Map<String, Object> formMap;
         cardData = switch (cardType) {
             case 0 -> {
+                // 密码卡
                 formMap = setPwdCardParam(bo);
                 yield lockUtils.getPwdCardData(formMap);
             }
             case 1 -> {
+                // 客人卡
                 formMap = setGuestCardParam(bo);
                 yield lockUtils.getWriteCardData(formMap);
             }
             case 2 -> {
+                // 员工卡
                 formMap = setManageCardParam(bo);
                 yield lockUtils.getWriteCardData(formMap);
             }
@@ -58,6 +70,12 @@ public class LockBusiness {
         return R.fail();
     }
 
+    /**
+     * 远程开门
+     * @param lockId 门锁Id
+     * @return 开门结果
+     */
+
     public R<String> remoteOpenDoor(String lockId) {
         Map<String, Object> formMap = new HashMap<>();
         formMap.put("DEVICE_ID", lockId);
@@ -101,8 +119,9 @@ public class LockBusiness {
             List<String> areaIds = List.of(bo.getGroupIds().split(","));
 
             for (String areaId : areaIds) {
-                // TODO 2024-11-20 luoyibo 根据区域id查询出对应的门锁id,只需要一条
-                String lockId = "0000";
+                List<PtRoomVo> roomVos = roomService.queryHotelRoomList(Long.valueOf(areaId));
+                String lockId = roomVos.get(0).getLockId();
+                // String lockId = "0000";
                 Map<String, Object> mapGroup = new HashMap<>();
                 mapGroup.put("DEVICE_ID", lockId);
                 mapGroup.put("PAGENO", 1);
@@ -111,7 +130,7 @@ public class LockBusiness {
                 JSONObject obj = JSONUtil.parseObj(result);
                 String lockkeyid = obj.getJSONArray("AppkeyList").getJSONObject(0).getStr("KEY_ID");
                 // 通过keyid获取分组
-                mapGroup = new HashMap<String, Object>();
+                mapGroup = new HashMap<>();
                 mapGroup.put("LOCKKEYID", lockkeyid);
                 mapGroup.put("OPERATETYPE", "2");
                 result = lockUtils.sendPost(mapGroup, "operateLockGroup");

+ 5 - 0
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/controller/lock/LockController.java

@@ -59,6 +59,11 @@ public class LockController {
         return ReturnResult.success(lockBusiness.getWriteCardData(bo));
     }
 
+    /**
+     * 远程开门
+     * @param lockId 门锁Id
+     * @return 开门结果
+     */
     @GetMapping(value = "/remote/open")
     ReturnResult remoteOpen(@RequestParam("lockId") String lockId) {
         R<String> result = lockBusiness.remoteOpenDoor(lockId);

+ 2 - 1
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/mq/KafkaNormalConsumer.java

@@ -16,6 +16,7 @@ import org.dromara.common.core.domain.R;
 import org.dromara.common.core.enums.CreditTypeEnum;
 import org.springframework.kafka.annotation.KafkaListener;
 import org.dromara.common.message.kafka.domain.KafkaMessage;
+import org.springframework.stereotype.Component;
 
 import java.math.BigDecimal;
 import java.util.HashMap;
@@ -50,7 +51,7 @@ public class KafkaNormalConsumer {
 
                 //uploadtest();
             } catch (Exception e) {
-                log.info(e.getMessage());
+                log.error("消费记录处理失败:", e);
             }
         }
         log.info("【消费者】received the message key {},value:{}", key, value);

+ 6 - 1
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/util/LockUtils.java

@@ -100,7 +100,7 @@ public class LockUtils {
     }
 
     /**
-     * 请求发卡数据
+     * 请求发卡数据 员工卡和客人卡
      * @param mapForm 请求参数
      * @return 发卡数据
      */
@@ -113,6 +113,11 @@ public class LockUtils {
         }
     }
 
+    /**
+     * 请求发卡数据 密码卡
+     * @param mapForm 请求参数
+     * @return 发卡数据
+     */
     public String getPwdCardData(Map<String, Object> mapForm) {
         return sendPost(mapForm, "addLockKey");
     }

+ 11 - 0
ruoyi-modules/ruoyi-backstage/src/main/resources/mapper/basics/room/PtRoomMapper.xml

@@ -20,4 +20,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <result property="updateBy"    column="update_by"    />
             <result property="updateTime"    column="update_time"    />
     </resultMap>
+
+    <select id="selectHotelRoomList" resultType="org.dromara.backstage.basics.domain.vo.PtRoomVo">
+        SELECT tpr.*,tkrlr.lock_id,tkrlr.lock_password FROM t_pt_room tpr
+         INNER JOIN t_kf_room_lock_r tkrlr on tkrlr.room_id=tpr.room_id
+        <if test="areaIds != null and areaIds.size() > 0">
+            where tpr.area_id in
+            <foreach collection="areaIds" item="item" open="(" separator="," close=")">
+                #{item}
+            </foreach>
+        </if>
+    </select>
 </mapper>

+ 5 - 6
ruoyi-modules/ruoyi-backstage/src/test/java/org/dromara/backstage/mq/KafkaProducerTest.java

@@ -1,6 +1,5 @@
 package org.dromara.backstage.mq;
 
-import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 
@@ -10,9 +9,9 @@ public class KafkaProducerTest {
     @Autowired
     private KafkaNormalProducer kafkaProcedurer;
 
-    @Test
-    public void send()
-    {
-        kafkaProcedurer.send("ykt_local_listener", "test message2");
-    }
+    // @Test
+    // public void send()
+    // {
+    //     kafkaProcedurer.sendKafkaMessage("ykt_local_listener", "test message2");
+    // }
 }

+ 106 - 0
ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/controller/KfDoorOpenHisController.java

@@ -0,0 +1,106 @@
+package org.dromara.hotel.controller;
+
+import java.util.List;
+
+import lombok.RequiredArgsConstructor;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.*;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.validation.annotation.Validated;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.hotel.domain.vo.KfDoorOpenHisVo;
+import org.dromara.hotel.domain.bo.KfDoorOpenHisBo;
+import org.dromara.hotel.service.IKfDoorOpenHisService;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+
+/**
+ * 开门记录
+ * 前端访问路由地址为:/report/kfDoorOpenHis
+ *
+ * @author LionLi
+ * @date 2024-11-29
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/report/kfDoorOpenHis")
+public class KfDoorOpenHisController extends BaseController {
+
+    private final IKfDoorOpenHisService kfDoorOpenHisService;
+
+    /**
+     * 查询开门记录列表
+     */
+    @SaCheckPermission("report:kfDoorOpenHis:list")
+    @GetMapping("/list")
+    public TableDataInfo<KfDoorOpenHisVo> list(KfDoorOpenHisBo bo, PageQuery pageQuery) {
+        return kfDoorOpenHisService.queryPageList(bo, pageQuery);
+    }
+
+    /**
+     * 导出开门记录列表
+     */
+    @SaCheckPermission("report:kfDoorOpenHis:export")
+    @Log(title = "开门记录", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(KfDoorOpenHisBo bo, HttpServletResponse response) {
+        List<KfDoorOpenHisVo> list = kfDoorOpenHisService.queryList(bo);
+        ExcelUtil.exportExcel(list, "开门记录", KfDoorOpenHisVo.class, response);
+    }
+
+    /**
+     * 获取开门记录详细信息
+     *
+     * @param id 主键
+     */
+    @SaCheckPermission("report:kfDoorOpenHis:query")
+    @GetMapping("/{id}")
+    public R<KfDoorOpenHisVo> getInfo(@NotNull(message = "主键不能为空")
+                                     @PathVariable Long id) {
+        return R.ok(kfDoorOpenHisService.queryById(id));
+    }
+
+    /**
+     * 新增开门记录
+     */
+    @SaCheckPermission("report:kfDoorOpenHis:add")
+    @Log(title = "开门记录", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody KfDoorOpenHisBo bo) {
+        return toAjax(kfDoorOpenHisService.insertByBo(bo));
+    }
+
+    /**
+     * 修改开门记录
+     */
+    @SaCheckPermission("report:kfDoorOpenHis:edit")
+    @Log(title = "开门记录", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody KfDoorOpenHisBo bo) {
+        return toAjax(kfDoorOpenHisService.updateByBo(bo));
+    }
+
+    /**
+     * 删除开门记录
+     *
+     * @param ids 主键串
+     */
+    @SaCheckPermission("report:kfDoorOpenHis:remove")
+    @Log(title = "开门记录", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "主键不能为空")
+                          @PathVariable Long[] ids) {
+        return toAjax(kfDoorOpenHisService.deleteWithValidByIds(List.of(ids), true));
+    }
+}

+ 13 - 0
ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/controller/KfGuestController.java

@@ -46,6 +46,19 @@ public class KfGuestController extends BaseController {
         return kfGuestService.queryPageList(bo, pageQuery);
     }
 
+    /**
+     * 根据团客id 分页查询客人列表
+     * @param bo
+     * @param pageQuery
+     * @return
+     */
+    @GetMapping("/getGuestByTeam")
+    public TableDataInfo<KfGuestVo> getGuestByTeam(KfGuestBo bo, PageQuery pageQuery) {
+        return kfGuestService.queryCustomPageListByTeam(bo, pageQuery);
+    }
+
+
+
     /**
      * 导出客人管理列表
      */

+ 61 - 0
ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/controller/KfOrderController.java

@@ -2,10 +2,13 @@ package org.dromara.hotel.controller;
 
 import java.util.List;
 
+import cn.hutool.core.util.RandomUtil;
 import lombok.RequiredArgsConstructor;
 import jakarta.servlet.http.HttpServletResponse;
 import jakarta.validation.constraints.*;
 import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.dromara.hotel.domain.bo.ChangeRoomBo;
+import org.dromara.hotel.domain.bo.ChangeRoomStatusBo;
 import org.dromara.hotel.domain.bo.KfGuestBo;
 import org.dromara.hotel.domain.vo.KfTeamGuestVo;
 import org.springframework.web.bind.annotation.*;
@@ -132,6 +135,28 @@ public class KfOrderController extends BaseController {
         return toAjax(kfOrderService.updateByBo(bo));
     }
 
+    /**
+     * 团客身份证报到
+     */
+    @SaCheckPermission("business:guestOrder:edit")
+    @Log(title = "身份证报到", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping("teamGuestCheckIn")
+    public R<Void> teamGuestCheckIn(@RequestBody KfTeamGuestVo vo) {
+        return toAjax(kfOrderService.teamGuestCheckIn(vo));
+    }
+
+    /**
+     * 手机号报到
+     */
+    @SaCheckPermission("business:guestOrder:edit")
+    @Log(title = "手机号报到", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping("phoneCodeCheckIn")
+    public R<Void> phoneCodeCheckIn(@RequestBody KfTeamGuestVo vo) {
+        return kfOrderService.phoneCheckIn(vo.getPhone(), vo.getPhoneCode());
+    }
+
     /**
      * 退房|取消预定
      */
@@ -142,6 +167,18 @@ public class KfOrderController extends BaseController {
     public R<Void> distributeOrder(@Validated(EditGroup.class) @RequestBody KfOrderBo bo) {
         return toAjax(kfOrderService.distributeOrder(bo));
     }
+
+    /**
+     * distributeForRoomStatus 批量退房
+     */
+    @SaCheckPermission("business:guestOrder:edit")
+    @Log(title = "批量退房|取消预定", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PostMapping("distributeForRoomStatus")
+    public R<Void> distributeForRoomStatus(@Validated(EditGroup.class) @RequestBody List<KfOrderBo> bo) {
+        return toAjax(kfOrderService.distributeForRoomStatus(bo));
+    }
+
     /**
      * 删除散客入住
      *
@@ -154,4 +191,28 @@ public class KfOrderController extends BaseController {
                           @PathVariable Long[] ids) {
         return toAjax(kfOrderService.deleteWithValidByIds(List.of(ids), true));
     }
+
+    // 团客入住
+    @PostMapping("/checkInTeam")
+    @Log(title = "团客入住for房态", businessType = BusinessType.INSERT)
+    public R<Void> checkInTeam(@Validated(AddGroup.class) @RequestBody KfOrderBo bo) {
+        return toAjax(kfOrderService.checkInTeamFromRoomStatus(bo));
+    }
+
+    // 更换房间
+    @PostMapping("/changeRoom")
+    @Log(title = "更换房间for房态", businessType = BusinessType.INSERT)
+    public R<Void> changeRoom(@Validated(EditGroup.class) @RequestBody ChangeRoomBo bo) {
+        return toAjax(kfOrderService.changeRoom(bo));
+    }
+
+    /**
+     * 根据房间编号批量修改房间状态
+     */
+    @PostMapping("/changeRoomStatus")
+    @Log(title = "修改房间状态for房态", businessType = BusinessType.UPDATE)
+    public R<Void> changeRoomStatus(@Validated(EditGroup.class) @RequestBody ChangeRoomStatusBo bo) {
+        return toAjax(kfOrderService.updateRoomStatus(bo));
+    }
+
 }

+ 74 - 0
ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/domain/KfDoorOpenHis.java

@@ -0,0 +1,74 @@
+package org.dromara.hotel.domain;
+
+import org.dromara.common.tenant.core.TenantEntity;
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+import java.io.Serial;
+
+/**
+ * 开门记录对象 t_kf_door_open_his
+ *
+ * @author LionLi
+ * @date 2024-11-29
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("t_kf_door_open_his")
+public class KfDoorOpenHis extends TenantEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 房间编号
+     */
+    private String roomCode;
+
+    /**
+     * 房间名称
+     */
+    private String roomName;
+
+    /**
+     * 开门方式
+     */
+    private String openDoorMode;
+
+    /**
+     * 开门时间
+     */
+    private Date openTime;
+
+    /**
+     * 开门结果
+     */
+    private String openResult;
+
+    /**
+     * 物理卡号
+     */
+    private String factoryId;
+
+    /**
+     * 开门用户
+     */
+    private Long openDoorUser;
+
+    /**
+     * 删除标志
+     */
+    @TableLogic
+    private String delFlag;
+
+
+}

+ 87 - 0
ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/domain/bo/ChangeRoomBo.java

@@ -0,0 +1,87 @@
+package org.dromara.hotel.domain.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.hotel.domain.KfOrder;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 更换房间Bo
+ *
+ * @author bing
+ * @date 2024-11-13
+ */
+@Data
+public class ChangeRoomBo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 4524605401498591013L;
+    /**
+     * 主键
+     */
+    @NotNull(message = "新客房不能为空", groups = {EditGroup.class})
+    private String newRoomCode;
+
+    /**
+     * 客人ID
+     */
+//    @NotNull(message = "客人ID不能为空", groups = {AddGroup.class})
+//    private Long guestId;
+
+    /**
+     * 客人姓名
+     */
+//    private String guestName;
+
+    /**
+     * 客团名称
+     */
+//    private String teamName;
+
+    /**
+     * 房间编号
+     */
+//    @NotBlank(message = "房间编号不能为空", groups = {AddGroup.class, EditGroup.class})
+//    private String roomCode;
+
+    /**
+     * 房间名称
+     */
+//    private String roomName;
+
+    /**
+     * 入住时间
+     */
+    @NotNull(message = "入住时间不能为空", groups = {AddGroup.class, EditGroup.class})
+    private Date startTime;
+
+    /**
+     * 退住时间
+     */
+    @NotNull(message = "退住时间不能为空", groups = {AddGroup.class, EditGroup.class})
+    private Date endTime;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+    /**
+     * 原始订单信息
+     */
+//    @Valid
+    @NotNull(message = "原始订单信息不能为空", groups = {AddGroup.class, EditGroup.class})
+    private List<KfOrderBo> oldOrderList;
+
+}

+ 40 - 0
ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/domain/bo/ChangeRoomStatusBo.java

@@ -0,0 +1,40 @@
+package org.dromara.hotel.domain.bo;
+
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 更换房间Bo
+ *
+ * @author bing
+ * @date 2024-11-13
+ */
+@Data
+public class ChangeRoomStatusBo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 6236155533331811156L;
+    /**
+     * 主键
+     */
+    @NotNull(message = "客房编号不能为空", groups = {EditGroup.class})
+    private List<String> roomCodes;
+
+
+    /**
+     * 入住时间
+     */
+    @NotNull(message = "房间状态不能为空", groups = {EditGroup.class})
+    private String status;
+
+    private String remark;
+
+
+}

+ 68 - 0
ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/domain/bo/KfDoorOpenHisBo.java

@@ -0,0 +1,68 @@
+package org.dromara.hotel.domain.bo;
+
+import org.dromara.hotel.domain.KfDoorOpenHis;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+/**
+ * 开门记录业务对象 t_kf_door_open_his
+ *
+ * @author LionLi
+ * @date 2024-11-29
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = KfDoorOpenHis.class, reverseConvertGenerate = false)
+public class KfDoorOpenHisBo extends BaseEntity {
+
+    /**
+     * 主键
+     */
+    @NotNull(message = "主键不能为空", groups = { EditGroup.class })
+    private Long id;
+
+    /**
+     * 房间编号
+     */
+    @NotBlank(message = "房间编号不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String roomCode;
+
+    /**
+     * 房间名称
+     */
+    private String roomName;
+
+    /**
+     * 开门方式
+     */
+    private String openDoorMode;
+
+    /**
+     * 开门时间
+     */
+    private Date openTime;
+
+    /**
+     * 开门结果
+     */
+    private String openResult;
+
+    /**
+     * 物理卡号
+     */
+    private String factoryId;
+
+    /**
+     * 开门用户
+     */
+    private Long openDoorUser;
+
+
+}

+ 1 - 0
ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/domain/bo/KfGuestBo.java

@@ -61,4 +61,5 @@ public class KfGuestBo extends BaseEntity {
      * 数据来源
      */
     private String dataSource;
+
 }

+ 78 - 0
ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/domain/vo/KfDoorOpenHisVo.java

@@ -0,0 +1,78 @@
+package org.dromara.hotel.domain.vo;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import org.dromara.hotel.domain.KfDoorOpenHis;
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+
+/**
+ * 开门记录视图对象 t_kf_door_open_his
+ *
+ * @author LionLi
+ * @date 2024-11-29
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = KfDoorOpenHis.class)
+public class KfDoorOpenHisVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键
+     */
+    @ExcelProperty(value = "主键")
+    private Long id;
+
+    /**
+     * 房间编号
+     */
+    @ExcelProperty(value = "房间编号")
+    private String roomCode;
+
+    /**
+     * 房间名称
+     */
+    @ExcelProperty(value = "房间名称")
+    private String roomName;
+
+    /**
+     * 开门方式
+     */
+    @ExcelProperty(value = "开门方式", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "open_door_mode")
+    private String openDoorMode;
+
+    /**
+     * 开门时间
+     */
+    @ExcelProperty(value = "开门时间")
+    private Date openTime;
+
+    /**
+     * 开门结果
+     */
+    @ExcelProperty(value = "开门结果", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "sys_opration_result")
+    private String openResult;
+
+    /**
+     * 物理卡号
+     */
+    @ExcelProperty(value = "物理卡号")
+    private String factoryId;
+
+
+}

+ 5 - 0
ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/domain/vo/KfGuestVo.java

@@ -86,4 +86,9 @@ public class KfGuestVo implements Serializable {
      */
 //    @ExcelProperty(value = "数据来源", converter = ExcelDictConvert.class)
     private String dataSource;
+
+    /**
+     * 入住状态,
+     */
+    private String checkInStatus;
 }

+ 1 - 0
ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/domain/vo/KfTeamGuestVo.java

@@ -57,6 +57,7 @@ public class KfTeamGuestVo implements Serializable {
      */
     @ExcelProperty(value = "手机号")
     private String phone;
+    private String phoneCode;
 
     private String teamName;
     private Long teamId;

+ 15 - 0
ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/mapper/KfDoorOpenHisMapper.java

@@ -0,0 +1,15 @@
+package org.dromara.hotel.mapper;
+
+import org.dromara.hotel.domain.KfDoorOpenHis;
+import org.dromara.hotel.domain.vo.KfDoorOpenHisVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * 开门记录Mapper接口
+ *
+ * @author LionLi
+ * @date 2024-11-29
+ */
+public interface KfDoorOpenHisMapper extends BaseMapperPlus<KfDoorOpenHis, KfDoorOpenHisVo> {
+
+}

+ 5 - 0
ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/mapper/KfGuestMapper.java

@@ -1,6 +1,9 @@
 package org.dromara.hotel.mapper;
 
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.apache.ibatis.annotations.Param;
 import org.dromara.hotel.domain.KfGuest;
+import org.dromara.hotel.domain.bo.KfGuestBo;
 import org.dromara.hotel.domain.vo.KfGuestVo;
 import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
 
@@ -12,4 +15,6 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
  */
 public interface KfGuestMapper extends BaseMapperPlus<KfGuest, KfGuestVo> {
 
+    Page<KfGuestVo> customPageList(@Param("page") Page<KfGuest> page, @Param("bo") KfGuestBo bo);
+
 }

+ 8 - 0
ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/mapper/KfOrderMapper.java

@@ -33,6 +33,14 @@ public interface KfOrderMapper extends BaseMapperPlus<KfOrder, KfOrderVo> {
     /** 根据房间code修改房间状态*/
     int updateRoomStatus(@Param("roomCode") String roomCode, @Param("status") String status);
 
+    /**
+     * 批量更新房态
+     * @param roomCodes
+     * @param status
+     * @return
+     */
+    int updateRoomStatusBatch(@Param("roomCodes") List<String> roomCodes, @Param("status") String status);
+
     /// 根据姓名或手机号查询订单
     List<KfOrderVo> queryListByGuestNameOrPhone(@Param("nameOrPhone") String nameOrPhone,
                                                 @Param("orderStatusList") List<String> orderStatusList);

+ 69 - 0
ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/service/IKfDoorOpenHisService.java

@@ -0,0 +1,69 @@
+package org.dromara.hotel.service;
+
+import org.dromara.hotel.domain.KfDoorOpenHis;
+import org.dromara.hotel.domain.vo.KfDoorOpenHisVo;
+import org.dromara.hotel.domain.bo.KfDoorOpenHisBo;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 开门记录Service接口
+ *
+ * @author LionLi
+ * @date 2024-11-29
+ */
+public interface IKfDoorOpenHisService {
+
+    /**
+     * 查询开门记录
+     *
+     * @param id 主键
+     * @return 开门记录
+     */
+    KfDoorOpenHisVo queryById(Long id);
+
+    /**
+     * 分页查询开门记录列表
+     *
+     * @param bo        查询条件
+     * @param pageQuery 分页参数
+     * @return 开门记录分页列表
+     */
+    TableDataInfo<KfDoorOpenHisVo> queryPageList(KfDoorOpenHisBo bo, PageQuery pageQuery);
+
+    /**
+     * 查询符合条件的开门记录列表
+     *
+     * @param bo 查询条件
+     * @return 开门记录列表
+     */
+    List<KfDoorOpenHisVo> queryList(KfDoorOpenHisBo bo);
+
+    /**
+     * 新增开门记录
+     *
+     * @param bo 开门记录
+     * @return 是否新增成功
+     */
+    Boolean insertByBo(KfDoorOpenHisBo bo);
+
+    /**
+     * 修改开门记录
+     *
+     * @param bo 开门记录
+     * @return 是否修改成功
+     */
+    Boolean updateByBo(KfDoorOpenHisBo bo);
+
+    /**
+     * 校验并批量删除开门记录信息
+     *
+     * @param ids     待删除的主键集合
+     * @param isValid 是否进行有效性校验
+     * @return 是否删除成功
+     */
+    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+}

+ 8 - 0
ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/service/IKfGuestService.java

@@ -33,6 +33,14 @@ public interface IKfGuestService {
      */
     TableDataInfo<KfGuestVo> queryPageList(KfGuestBo bo, PageQuery pageQuery);
 
+    /**
+     * 自定义分页查询
+     * @param bo 查询条件
+     * @param pageQuery 分页参数
+     * @return 客人管理分页列表
+     */
+    TableDataInfo<KfGuestVo> queryCustomPageListByTeam(KfGuestBo bo, PageQuery pageQuery);
+
     /**
      * 查询符合条件的客人管理列表
      *

+ 24 - 1
ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/service/IKfOrderService.java

@@ -1,15 +1,17 @@
 package org.dromara.hotel.service;
 
+import org.checkerframework.checker.units.qual.C;
 import org.dromara.common.core.domain.R;
 import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.hotel.api.domain.bo.RemoteOrderBo;
 import org.dromara.hotel.api.domain.vo.RemoteOrderVo;
+import org.dromara.hotel.domain.bo.ChangeRoomBo;
+import org.dromara.hotel.domain.bo.ChangeRoomStatusBo;
 import org.dromara.hotel.domain.bo.KfGuestBo;
 import org.dromara.hotel.domain.bo.KfOrderBo;
 import org.dromara.hotel.domain.vo.KfOrderVo;
 import org.dromara.hotel.domain.vo.KfTeamGuestVo;
-import org.dromara.hotel.domain.vo.OrderAndGuestVo;
 
 import java.util.Collection;
 import java.util.List;
@@ -73,10 +75,19 @@ public interface IKfOrderService {
      */
     Boolean updateByBo(KfOrderBo bo);
 
+    Boolean teamGuestCheckIn(KfTeamGuestVo bo);
+
+    /** 手机号码报到*/
+    R<Void> phoneCheckIn(String phone, String phoneCode);
+
+    /** 修改订单信息和房间状态*/
+    Boolean updateOrderAndRoomStatus(KfOrderBo bo);
     /**
      * 退房
      */
     Boolean distributeOrder(KfOrderBo bo);
+
+    Boolean distributeForRoomStatus(List<KfOrderBo> bo);
     /**
      * 校验并批量删除散客入住信息
      *
@@ -93,6 +104,18 @@ public interface IKfOrderService {
      * @return 订单信息
      */
     RemoteOrderVo selectByBo(KfOrderBo bo);
+
+
+    boolean checkInTeamFromRoomStatus(KfOrderBo bo);
+
+    boolean changeRoom(ChangeRoomBo bo);
+
+    /**
+     * 更新房间状态 修改房态
+     * @param bo
+     * @return
+     */
+    boolean updateRoomStatus(ChangeRoomStatusBo bo);
     /**
      * 办理团客入住
       * @param remoteBo 入住业务对象

+ 150 - 0
ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/service/impl/KfDoorOpenHisServiceImpl.java

@@ -0,0 +1,150 @@
+package org.dromara.hotel.service.impl;
+
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.dromara.hotel.domain.bo.KfDoorOpenHisBo;
+import org.dromara.hotel.domain.vo.KfDoorOpenHisVo;
+import org.dromara.hotel.domain.KfDoorOpenHis;
+import org.dromara.hotel.mapper.KfDoorOpenHisMapper;
+import org.dromara.hotel.service.IKfDoorOpenHisService;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Collection;
+
+/**
+ * 开门记录Service业务层处理
+ *
+ * @author LionLi
+ * @date 2024-11-29
+ */
+@RequiredArgsConstructor
+@Service
+public class KfDoorOpenHisServiceImpl implements IKfDoorOpenHisService {
+
+    private final KfDoorOpenHisMapper baseMapper;
+
+    /**
+     * 查询开门记录
+     *
+     * @param id 主键
+     * @return 开门记录
+     */
+    @Override
+    public KfDoorOpenHisVo queryById(Long id){
+        return baseMapper.selectVoById(id);
+    }
+
+    /**
+     * 分页查询开门记录列表
+     *
+     * @param bo        查询条件
+     * @param pageQuery 分页参数
+     * @return 开门记录分页列表
+     */
+    @Override
+    public TableDataInfo<KfDoorOpenHisVo> queryPageList(KfDoorOpenHisBo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<KfDoorOpenHis> lqw = buildQueryWrapper(bo);
+        Page<KfDoorOpenHisVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(result);
+    }
+
+    /**
+     * 查询符合条件的开门记录列表
+     *
+     * @param bo 查询条件
+     * @return 开门记录列表
+     */
+    @Override
+    public List<KfDoorOpenHisVo> queryList(KfDoorOpenHisBo bo) {
+        LambdaQueryWrapper<KfDoorOpenHis> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<KfDoorOpenHis> buildQueryWrapper(KfDoorOpenHisBo bo) {
+        Map<String, Object> params = bo.getParams();
+        LambdaQueryWrapper<KfDoorOpenHis> lqw = Wrappers.lambdaQuery();
+        lqw.like(StringUtils.isNotBlank(bo.getRoomCode()), KfDoorOpenHis::getRoomCode, bo.getRoomCode());
+        lqw.eq(StringUtils.isNotBlank(bo.getOpenDoorMode()), KfDoorOpenHis::getOpenDoorMode, bo.getOpenDoorMode());
+        lqw.between(params.get("beginOpenTime") != null && params.get("endOpenTime") != null,
+            KfDoorOpenHis::getOpenTime ,params.get("beginOpenTime"), params.get("endOpenTime"));
+        lqw.eq(StringUtils.isNotBlank(bo.getOpenResult()), KfDoorOpenHis::getOpenResult, bo.getOpenResult());
+        lqw.orderByDesc(KfDoorOpenHis::getOpenTime);
+        return lqw;
+    }
+
+    private QueryWrapper<KfDoorOpenHis> buildQueryWrapper(KfDoorOpenHisBo bo,String tableAlias) {
+        QueryWrapper<KfDoorOpenHis> lqw = new QueryWrapper<>();
+        Map<String, Object> params = bo.getParams();
+        String columnPrefix = "";
+        if(StringUtils.isNotBlank(tableAlias)){
+            columnPrefix = tableAlias + ".";
+        }
+        lqw.like(StringUtils.isNotBlank(bo.getRoomCode()), columnPrefix+"room_code", bo.getRoomCode());
+        lqw.eq(StringUtils.isNotBlank(bo.getOpenDoorMode()), columnPrefix+"open_door_mode", bo.getOpenDoorMode());
+        lqw.between(params.get("beginOpenTime") != null && params.get("endOpenTime") != null,
+        columnPrefix+"open_time" ,params.get("beginOpenTime"), params.get("endOpenTime"));
+        lqw.eq(StringUtils.isNotBlank(bo.getOpenResult()), columnPrefix+"open_result", bo.getOpenResult());
+        return lqw;
+    }
+
+    /**
+     * 新增开门记录
+     *
+     * @param bo 开门记录
+     * @return 是否新增成功
+     */
+    @Override
+    public Boolean insertByBo(KfDoorOpenHisBo bo) {
+        KfDoorOpenHis add = MapstructUtils.convert(bo, KfDoorOpenHis.class);
+        validEntityBeforeSave(add);
+        boolean flag = baseMapper.insert(add) > 0;
+        if (flag) {
+            bo.setId(add.getId());
+        }
+        return flag;
+    }
+
+    /**
+     * 修改开门记录
+     *
+     * @param bo 开门记录
+     * @return 是否修改成功
+     */
+    @Override
+    public Boolean updateByBo(KfDoorOpenHisBo bo) {
+        KfDoorOpenHis update = MapstructUtils.convert(bo, KfDoorOpenHis.class);
+        validEntityBeforeSave(update);
+        return baseMapper.updateById(update) > 0;
+    }
+
+    /**
+     * 保存前的数据校验
+     */
+    private void validEntityBeforeSave(KfDoorOpenHis entity){
+        //TODO 做一些数据校验,如唯一约束
+    }
+
+    /**
+     * 校验并批量删除开门记录信息
+     *
+     * @param ids     待删除的主键集合
+     * @param isValid 是否进行有效性校验
+     * @return 是否删除成功
+     */
+    @Override
+    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
+        if(isValid){
+            //TODO 做一些业务上的校验,判断是否需要校验
+        }
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+}

+ 13 - 0
ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/service/impl/KfGuestServiceImpl.java

@@ -62,6 +62,19 @@ public class KfGuestServiceImpl implements IKfGuestService {
         return TableDataInfo.build(result);
     }
 
+    /**
+     * 自定义分页查询
+     *
+     * @param bo        查询条件
+     * @param pageQuery 分页参数
+     * @return 客人管理分页列表
+     */
+    @Override
+    public TableDataInfo<KfGuestVo> queryCustomPageListByTeam(KfGuestBo bo, PageQuery pageQuery) {
+        Page<KfGuestVo> kfGuestVoPage = baseMapper.customPageList(pageQuery.build(), bo);
+        return TableDataInfo.build(kfGuestVoPage);
+    }
+
     /**
      * 查询符合条件的客人管理列表
      *

+ 239 - 5
ruoyi-modules/ruoyi-hotel/src/main/java/org/dromara/hotel/service/impl/KfOrderServiceImpl.java

@@ -3,25 +3,30 @@ package org.dromara.hotel.service.impl;
 import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.collection.ListUtil;
 import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.RandomUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.*;
 import org.apache.dubbo.config.annotation.DubboReference;
 import org.dromara.backstage.api.RemotePtRoomService;
-import org.dromara.common.core.constant.DefaultConstants;
-import org.dromara.common.core.constant.HotelBusinessConstants;
 import org.dromara.common.core.domain.R;
 import org.dromara.common.core.enums.HotelRoomStatusEnum;
 import org.dromara.common.core.exception.ServiceException;
 import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.SmsUtils;
+import org.dromara.common.core.utils.SpringUtils;
 import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.redis.utils.RedisUtils;
 import org.dromara.hotel.api.domain.bo.RemoteOrderBo;
 import org.dromara.hotel.api.domain.vo.RemoteOrderVo;
 import org.dromara.hotel.domain.KfOrder;
+import org.dromara.hotel.domain.bo.ChangeRoomBo;
+import org.dromara.hotel.domain.bo.ChangeRoomStatusBo;
 import org.dromara.hotel.domain.bo.KfGuestBo;
 import org.dromara.hotel.domain.bo.KfOrderBo;
 import org.dromara.hotel.domain.vo.*;
@@ -33,7 +38,9 @@ import org.dromara.hotel.service.IKfTeamService;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.time.Duration;
 import java.util.*;
+import java.util.concurrent.LinkedBlockingQueue;
 
 /**
  * 散客入住Service业务层处理
@@ -49,7 +56,6 @@ public class KfOrderServiceImpl implements IKfOrderService {
 
     private final KfOrderMapper baseMapper;
     private final IKfTeamService teamService;
-    private final KfGuestMapper guestMapper;
     private final IKfGuestTeamRService guestTeamService;
 
     /**
@@ -125,7 +131,7 @@ public class KfOrderServiceImpl implements IKfOrderService {
         //2.查询团客入住信息
         KfOrder order = baseMapper.selectOne(Wrappers.<KfOrder>lambdaQuery()
             .eq(KfOrder::getGuestId, teamGuest.getId())
-            .eq(KfOrder::getGuestId, teamGuest.getId()));
+            .eq(KfOrder::getTeamId, teamGuest.getTeamId()));
         if(ObjectUtil.isNotEmpty(order)) {
             teamGuest.setRoomCode(order.getRoomCode());
             teamGuest.setRoomName(order.getRoomName());
@@ -229,6 +235,92 @@ public class KfOrderServiceImpl implements IKfOrderService {
         return baseMapper.updateById(update) > 0;
     }
 
+    /**
+     * 团客报到
+     */
+    @Override
+    public Boolean teamGuestCheckIn(KfTeamGuestVo bo) {
+        boolean flag = false;
+        //1.根据客人ID和客团ID修改客人客团关系表的报到状态,并发送kafka消息
+        flag = guestTeamService.setGuestCheckInStatus(bo.getId(), bo.getTeamId());
+        String roomCode = bo.getRoomCode();
+        //2.修改订单信息
+        if (bo.getOrderId() != null) {
+            // 参数里面有OrderId,设置订单状态为入住
+            KfOrderBo orderBo = new KfOrderBo();
+            orderBo.setId(bo.getOrderId());
+            orderBo.setOrderStatus(HotelBusinessConstants.ORDER_STATUS_RZ);
+            //3.删除锁房缓存,根据roomCode修改房间状态
+            updateOrderAndRoomStatus(orderBo);
+        } else {
+            // 参数里面没有OrderId,根据团客ID查询锁房订单信息,设置订单状态为入住
+            LambdaQueryWrapper<KfOrder> queryWrapper = new LambdaQueryWrapper<KfOrder>()
+                .eq(KfOrder::getTeamId, bo.getTeamId())
+                .eq(KfOrder::getOrderStatus, HotelBusinessConstants.ORDER_STATUS_SF)
+                .orderByAsc(KfOrder::getOrderIndex);
+
+            List<KfOrderVo> list = baseMapper.selectVoList(queryWrapper);
+            if(ObjectUtil.isNotEmpty(list)){
+                KfOrderVo orderVo = list.get(0);
+                KfOrderBo orderBo = new KfOrderBo();
+                orderBo.setId(orderVo.getId());
+                orderBo.setGuestId(bo.getId());
+                orderBo.setGuestName(bo.getName());
+                orderBo.setOrderStatus(HotelBusinessConstants.ORDER_STATUS_RZ);
+                //3.删除锁房缓存,根据roomCode修改房间状态
+                updateOrderAndRoomStatus(orderBo);
+            }
+        }
+        return flag;
+        }
+
+    @Override
+    public R<Void> phoneCheckIn(String phone, String phoneCode) {
+        //1.校验验证码
+        if(RedisUtils.isExistsObject(SmsUtils.PHONE_CODE_PREFIX + phone)){
+            if(RedisUtils.getCacheObject(SmsUtils.PHONE_CODE_PREFIX + phone).equals(phoneCode)){
+                //2.根据手机号查询团客信息
+                KfGuestBo guestBo = new KfGuestBo();
+                guestBo.setPhone(phone);
+                R<KfTeamGuestVo> teamGuestVoR = getTeamGuestCheckInfo(guestBo);
+                if("已报到".equals(teamGuestVoR.getData().getCheckInStatus())){
+                    return R.ok("该团客已报到");
+                }
+                //3.报到
+                if(teamGuestCheckIn(teamGuestVoR.getData())){
+                    return R.ok("报到成功");
+                }else {
+                    return R.fail("报到失败");
+                }
+            } else {
+                return R.fail("验证码错误");
+            }
+        }else {
+            return R.fail("验证码错误");
+        }
+    }
+
+    @Override
+    public Boolean updateOrderAndRoomStatus(KfOrderBo bo) {
+        if(ObjectUtil.isNotEmpty(bo)){
+            //更新订单
+            boolean flag = updateByBo(bo);
+            if(flag){
+                String roomStatus = HotelBusinessConstants.orderStatusRoomStatusMap.get(bo.getOrderStatus());
+                //更新房间状态
+                baseMapper.updateRoomStatus(bo.getRoomCode(), roomStatus);
+                //清除缓存
+                String key = CacheNames.CLASS_ROOM + "_" + bo.getTeamId();
+                if(RedisUtils.isExistsObject(key)){
+                    LinkedBlockingQueue<String> concurrentLinkedQueue = RedisUtils.getCacheObject(key);
+                    concurrentLinkedQueue.poll();
+                    RedisUtils.setCacheObject(key, concurrentLinkedQueue);
+                }
+            }
+        }
+        return null;
+    }
+
     @Override
     public Boolean distributeOrder(KfOrderBo bo) {
         boolean flag = false;
@@ -249,6 +341,60 @@ public class KfOrderServiceImpl implements IKfOrderService {
         return flag;
     }
 
+    /**
+     * 批量取消订单
+     * @param bo 预定和入住的订单
+     * @return
+     */
+    @Transactional
+    public Boolean distributeForRoomStatus(List<KfOrderBo> bo) {
+        boolean flag = false;
+        if(CollectionUtil.isEmpty(bo)){
+            return flag;
+        }
+        // 1. 修改订单状态 只有预定和入住的可以退房
+        List<String> orderStatusYd = List.of(HotelBusinessConstants.ORDER_STATUS_YD, HotelBusinessConstants.ORDER_STATUS_RZ);
+        List<KfOrderBo> kfOrderBos = bo.stream().filter(item -> orderStatusYd.contains(item.getOrderStatus())).toList();
+        if(CollectionUtil.isEmpty(kfOrderBos)){
+            return flag;
+        }
+        List<KfOrder> convert = new ArrayList<>();
+        kfOrderBos.forEach(item -> {
+            KfOrder kfOrder = new KfOrder();
+            kfOrder.setId(item.getId());
+            if(HotelBusinessConstants.ORDER_STATUS_YD.equals(item.getOrderStatus())){
+                kfOrder.setOrderStatus(HotelBusinessConstants.ORDER_STATUS_QX);
+            }else{
+                kfOrder.setOrderStatus(HotelBusinessConstants.ORDER_STATUS_TF);
+            }
+            convert.add(kfOrder);
+        });
+
+        if(CollectionUtil.isEmpty(convert)){
+            return flag;
+        }
+        boolean b = baseMapper.updateBatchById(convert);
+        if(!b){
+            return flag;
+        }
+        // 2. 修改房间状态 updateRoomStatusBatch
+        List<KfOrderBo> oks = kfOrderBos.stream().filter(item -> HotelBusinessConstants.ORDER_STATUS_YD.equals(item.getOrderStatus())).toList();
+        //ok房
+        List<String> okRoomCodes = oks.stream().map(KfOrderBo::getRoomCode).toList();
+        if(CollectionUtil.isNotEmpty(okRoomCodes)){
+            int i = baseMapper.updateRoomStatusBatch(okRoomCodes, HotelRoomStatusEnum.OK.code());
+        }
+
+        List<KfOrderBo> zfs = kfOrderBos.stream().filter(item -> HotelBusinessConstants.ORDER_STATUS_RZ.equals(item.getOrderStatus())).toList();
+        //脏房
+        List<String> zfRoomCodes = zfs.stream().map(KfOrderBo::getRoomCode).toList();
+        if(CollectionUtil.isNotEmpty(zfRoomCodes)){
+            int j = baseMapper.updateRoomStatusBatch(zfRoomCodes, HotelRoomStatusEnum.ZF.code());
+        }
+
+        return b;
+    }
+
     /**
      * 保存前的数据校验
      */
@@ -283,6 +429,89 @@ public class KfOrderServiceImpl implements IKfOrderService {
         return baseMapper.selectByBo(bo);
     }
 
+    @Override
+    @Transactional
+    public boolean checkInTeamFromRoomStatus(KfOrderBo bo) {
+        // 查询 客人信息 是否有存在的订单
+        LambdaQueryWrapper<KfOrder> queryWrapper = Wrappers.lambdaQuery();
+        List<String> orderStatusYd = List.of(HotelBusinessConstants.ORDER_STATUS_YD, HotelBusinessConstants.ORDER_STATUS_RZ);
+        queryWrapper.in(KfOrder::getOrderStatus, orderStatusYd);
+        queryWrapper.and(e -> e.eq(KfOrder::getRoomCode, bo.getRoomCode()).or().eq(KfOrder::getGuestId, bo.getGuestId()));
+        // 已入住、已预定 不能再入住
+        // 房间状态是否为ok房 其他房不能入住
+        if(baseMapper.selectCount(queryWrapper) > 0){
+            throw new ServiceException("不能办理入住,原因:1.已入住或已预定,2.房间不是OK房");
+        }
+
+        //办理入住
+        bo.setOrderStatus(HotelBusinessConstants.ORDER_STATUS_RZ); // 入住
+        bo.setOrderType(HotelBusinessConstants.ORDER_TYPE_TK); // 客团
+        RemoteOrderVo remoteOrderVo = checkInTeamByBoPrivate(bo);
+
+        return remoteOrderVo != null;
+    }
+
+    @Override
+    @Transactional
+    public boolean changeRoom(ChangeRoomBo bo) {
+        List<KfOrderBo> oldOrderList = bo.getOldOrderList();
+        if(CollectionUtil.isEmpty(oldOrderList)){
+            throw new ServiceException("无原始订单信息,无需办理换房");
+        }
+        //处理原始订单信息
+        //1.修改订单状态为退房
+        List<KfOrder> oldOrders = new ArrayList<>();
+        for (KfOrderBo kfOrderBo : oldOrderList) {
+            KfOrder kfOrder = new KfOrder();
+            kfOrder.setId(kfOrderBo.getId());
+            kfOrder.setOrderStatus(HotelBusinessConstants.ORDER_STATUS_TF);
+            oldOrders.add(kfOrder);
+        }
+        baseMapper.updateBatchById(oldOrders);
+        //2.修改房间状态为脏房
+        String oldRoomCode = oldOrderList.get(0).getRoomCode();
+        baseMapper.updateRoomStatus(oldRoomCode, HotelRoomStatusEnum.ZF.code());
+
+        //新增新订单
+        //1.根据原始订单进行新增订单
+        List<KfOrder> newOrders = new ArrayList<>();
+        oldOrderList.forEach(item -> {
+            KfOrder kfOrder = baseMapper.selectById(item.getId());
+            if(kfOrder != null){
+                KfOrder convert = MapstructUtils.convert(kfOrder, KfOrder.class);
+                assert convert != null;
+                convert.setId(null);
+                convert.setOrderStatus(HotelBusinessConstants.ORDER_STATUS_RZ);
+                convert.setStartTime(bo.getStartTime());
+                convert.setEndTime(bo.getEndTime());
+                convert.setRoomCode(bo.getNewRoomCode());
+                convert.setRoomName(bo.getNewRoomCode());
+                String defaultRemark = "由"+oldRoomCode+"换到"+bo.getNewRoomCode();
+                String remark = StringUtils.isNotBlank(item.getRemark()) ? item.getRemark() + ";" + defaultRemark : defaultRemark;
+                convert.setRemark(remark);
+                newOrders.add(convert);
+            }
+        });
+
+        baseMapper.insertBatch(newOrders);
+        //2.修改房间状态为入住
+        baseMapper.updateRoomStatus(bo.getNewRoomCode(), HotelRoomStatusEnum.YZ.code());
+
+
+        return true;
+    }
+
+    /**
+     * 更新房间状态 修改房态
+     *
+     * @param bo
+     * @return
+     */
+    @Override
+    public boolean updateRoomStatus(ChangeRoomStatusBo bo) {
+        return baseMapper.updateRoomStatusBatch(bo.getRoomCodes(), bo.getStatus()) > 0;
+    }
+
     /**
      * 办理团客入住
      *
@@ -290,9 +519,14 @@ public class KfOrderServiceImpl implements IKfOrderService {
      * @return 入住信息
      */
     @Override
+    @Transactional
     public RemoteOrderVo checkInTeamByBo(RemoteOrderBo remoteBo) {
-        List<String> orderStatusList = Arrays.asList("1", "2");
         KfOrderBo bo = MapstructUtils.convert(remoteBo, KfOrderBo.class);
+        return checkInTeamByBoPrivate(bo);
+    }
+
+    private RemoteOrderVo checkInTeamByBoPrivate(KfOrderBo bo) {
+        List<String> orderStatusList = Arrays.asList("1", "2");
         if (bo != null) {
             KfOrderVo vo = baseMapper.selectVoOne(
                 new LambdaQueryWrapper<KfOrder>()

+ 17 - 0
ruoyi-modules/ruoyi-hotel/src/main/resources/mapper/hotel/basics/KfGuestMapper.xml

@@ -19,4 +19,21 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <result property="updateTime"    column="update_time"    />
             <result property="dataSource" column="data_source" />
     </resultMap>
+
+    <select id="customPageList" resultType="org.dromara.hotel.domain.vo.KfGuestVo">
+        select g.*,
+       (CASE o.order_status WHEN '1' THEN '已预定' WHEN '3' THEN '已入住' else '未入住' END) AS checkInStatus
+        from t_kf_guest_team_r tgr
+            left join t_kf_guest g on tgr.guest_id = g.id
+            left join t_kf_order o on g.id = o.guest_id
+        <where>
+            tgr.del_flag = '0' and o.order_status not in ('1','3')
+            <if test="bo.teamId != null">
+                and tgr.team_id = #{bo.teamId}
+            </if>
+            <if test="bo.name != null">
+                and g.name like concat('%', #{bo.name}, '%')
+            </if>
+        </where>
+    </select>
 </mapper>

+ 9 - 1
ruoyi-modules/ruoyi-hotel/src/main/resources/mapper/hotel/business/KfOrderMapper.xml

@@ -133,6 +133,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         update t_pt_room set status = #{status} where room_code = #{roomCode}
     </update>
 
+    <update id="updateRoomStatusBatch" >
+        update t_pt_room set status = #{status} where room_code in (
+        <foreach collection="roomCodes" item="roomCode" separator=",">
+            #{roomCode}
+        </foreach>
+        )
+    </update>
+
     <select id = "queryListByGuestNameOrPhone" resultType="org.dromara.hotel.domain.vo.KfOrderVo">
         select o.*, g.name as guestName, g.phone,g.id_card as idCard, g.sex from t_kf_order o
         left join t_kf_guest g on o.guest_id = g.id
@@ -151,7 +159,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </select>
 
     <select id = "queryByRoomCodes" resultType="org.dromara.hotel.api.domain.vo.RemoteOrderVo">
-        select o.*, g.name as name, g.phone,g.id_card as idCard, g.sex from t_kf_order o
+        select o.*, g.name as name, g.phone,g.id_card as idCard, g.sex,o.start_time as checkinDate, o.end_time as checkoutDate,o.id from t_kf_order o
         left join t_kf_guest g on o.guest_id = g.id
         <where>
             g.del_flag = '0' and o.del_flag = '0'

+ 24 - 0
ruoyi-modules/ruoyi-hotel/src/main/resources/mapper/hotel/report/KfDoorOpenHisMapper.xml

@@ -0,0 +1,24 @@
+<?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="org.dromara.hotel.mapper.KfDoorOpenHisMapper">
+
+    <resultMap type="org.dromara.hotel.domain.KfDoorOpenHis" id="KfDoorOpenHisResult">
+            <result property="id"    column="id"    />
+            <result property="roomCode"    column="room_code"    />
+            <result property="roomName"    column="room_name"    />
+            <result property="openDoorMode"    column="open_door_mode"    />
+            <result property="openTime"    column="open_time"    />
+            <result property="openResult"    column="open_result"    />
+            <result property="factoryId"    column="factory_id"    />
+            <result property="openDoorUser"    column="open_door_user"    />
+            <result property="createBy"    column="create_by"    />
+            <result property="createTime"    column="create_time"    />
+            <result property="updateBy"    column="update_by"    />
+            <result property="updateTime"    column="update_time"    />
+            <result property="createDept"    column="create_dept"    />
+            <result property="tenantId"    column="tenant_id"    />
+            <result property="delFlag"    column="del_flag"    />
+    </resultMap>
+</mapper>

+ 15 - 0
ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/controller/SysSmsController.java

@@ -8,6 +8,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.dromara.common.core.constant.Constants;
 import org.dromara.common.core.constant.GlobalConstants;
 import org.dromara.common.core.domain.R;
+import org.dromara.common.core.utils.SmsUtils;
 import org.dromara.common.ratelimiter.annotation.RateLimiter;
 import org.dromara.common.redis.utils.RedisUtils;
 import org.dromara.common.web.core.BaseController;
@@ -58,4 +59,18 @@ public class SysSmsController extends BaseController {
         return R.ok();
     }
 
+    /** 调用省委党校短信平台发送短信验证码*/
+    @RateLimiter(key = "#phone", time = 60, count = 1)
+    @GetMapping("/sendPhoneCode")
+    public R<Object> sendPhoneCode(String phone)  {
+        String key = "PhoneCode_" + phone;
+        String code = RandomUtil.randomNumbers(4);
+        RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
+        String content = "您的验证码为:" + code + ",有效性为" + Constants.CAPTCHA_EXPIRATION + "分钟,请尽快填写。";
+        boolean flag = SmsUtils.send(phone, content);
+        if (!flag) {
+            return R.fail("验证码短信发送异常,请稍后重试!");
+        }
+        return R.ok();
+    }
 }

+ 4 - 0
ruoyi-modules/ruoyi-system/pom.xml

@@ -141,6 +141,10 @@
             <artifactId>ruoyi-common-message</artifactId>
             <version>${revision}</version>
         </dependency>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-ratelimiter</artifactId>
+        </dependency>
     </dependencies>
 
     <build>

+ 42 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysSmsController.java

@@ -0,0 +1,42 @@
+package org.dromara.system.controller.system;
+
+import cn.hutool.core.util.RandomUtil;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.Constants;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.utils.SmsUtils;
+import org.dromara.common.ratelimiter.annotation.RateLimiter;
+import org.dromara.common.redis.utils.RedisUtils;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.time.Duration;
+
+/**
+ * @author Hz
+ * @date 2024/11/27
+ * @description 短信发送
+ */
+
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/sms")
+public class SysSmsController {
+
+    /** 调用省委党校短信平台发送短信验证码*/
+    @RateLimiter(key = "#phone", time = 60, count = 1)
+    @GetMapping("/sendPhoneCode")
+    public R<Object> sendPhoneCode(String phone)  {
+        String key = SmsUtils.PHONE_CODE_PREFIX + phone;
+        String code = RandomUtil.randomNumbers(4);
+        RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
+        String content = "您的验证码为:" + code + ",有效性为" + Constants.CAPTCHA_EXPIRATION + "分钟,请尽快填写。";
+        boolean flag = SmsUtils.send(phone, content);
+        if (!flag) {
+            return R.fail("验证码短信发送异常,请稍后重试!");
+        }
+        return R.ok();
+    }
+}

+ 1 - 1
ruoyi-visual/ruoyi-nacos/pom.xml

@@ -318,7 +318,7 @@
             <artifactId>spring-boot-admin-client</artifactId>
             <version>${spring-boot-admin.version}</version>
         </dependency>
-        <dependency>
+      <dependency>
             <groupId>cn.com.kingbase</groupId>
             <artifactId>kingbase8</artifactId>
         </dependency>