Browse Source

入住业务完成

wangzhengliang 3 years ago
parent
commit
9da293a601
28 changed files with 1035 additions and 66 deletions
  1. 97 0
      src/main/java/com/chuanghai/ihotel/component/DoorLockComponent.java
  2. 9 4
      src/main/java/com/chuanghai/ihotel/component/WaterElectricComponent.java
  3. 19 0
      src/main/java/com/chuanghai/ihotel/config/DoorLockConfig.java
  4. 15 3
      src/main/java/com/chuanghai/ihotel/controller/HotelOrderController.java
  5. 8 8
      src/main/java/com/chuanghai/ihotel/controller/RoomDoorLockController.java
  6. 25 0
      src/main/java/com/chuanghai/ihotel/controller/TestController.java
  7. 3 3
      src/main/java/com/chuanghai/ihotel/dao/RoomDoorLockDao.java
  8. 17 0
      src/main/java/com/chuanghai/ihotel/dao/RoomThirdSettingDao.java
  9. 28 0
      src/main/java/com/chuanghai/ihotel/dto/DoorLockAddPasswordDataDTO.java
  10. 24 0
      src/main/java/com/chuanghai/ihotel/dto/DoorLockAddPasswordRequestDTO.java
  11. 1 0
      src/main/java/com/chuanghai/ihotel/entity/HotelOrderBillEntity.java
  12. 16 9
      src/main/java/com/chuanghai/ihotel/entity/RoomDoorLockEntity.java
  13. 41 0
      src/main/java/com/chuanghai/ihotel/entity/RoomThirdSettingEntity.java
  14. 9 0
      src/main/java/com/chuanghai/ihotel/service/HotelOrderBillService.java
  15. 33 0
      src/main/java/com/chuanghai/ihotel/service/HotelOrderService.java
  16. 9 2
      src/main/java/com/chuanghai/ihotel/service/RoomDoorLockService.java
  17. 17 0
      src/main/java/com/chuanghai/ihotel/service/RoomThirdSettingService.java
  18. 64 1
      src/main/java/com/chuanghai/ihotel/service/impl/HotelOrderBillServiceImpl.java
  19. 134 0
      src/main/java/com/chuanghai/ihotel/service/impl/HotelOrderServiceImpl.java
  20. 99 0
      src/main/java/com/chuanghai/ihotel/service/impl/RoomDoorLockDataServiceImpl.java
  21. 0 29
      src/main/java/com/chuanghai/ihotel/service/impl/RoomDoorLockServiceImpl.java
  22. 24 0
      src/main/java/com/chuanghai/ihotel/service/impl/RoomThirdSettingServiceImpl.java
  23. 144 0
      src/main/java/com/chuanghai/ihotel/util/DoorLockAESUtil.java
  24. 40 0
      src/main/java/com/chuanghai/ihotel/util/DoorLockMD5Util.java
  25. 128 0
      src/main/java/com/chuanghai/ihotel/vo/UserOrderDetailVO.java
  26. 8 1
      src/main/resources/application.yml
  27. 19 0
      src/main/resources/mapper/ihotel/RoomDoorLockDataDao.xml
  28. 4 6
      src/main/resources/mapper/ihotel/RoomDoorLockDao.xml

+ 97 - 0
src/main/java/com/chuanghai/ihotel/component/DoorLockComponent.java

@@ -0,0 +1,97 @@
+package com.chuanghai.ihotel.component;
+
+import com.chuanghai.ihotel.common.exception.BizCodeEnume;
+import com.chuanghai.ihotel.common.exception.RRException;
+import com.chuanghai.ihotel.config.DoorLockConfig;
+import com.chuanghai.ihotel.dto.DoorLockAddPasswordRequestDTO;
+import com.chuanghai.ihotel.dto.DoorLockAddPasswordDataDTO;
+import com.chuanghai.ihotel.util.DoorLockAESUtil;
+import com.chuanghai.ihotel.util.DoorLockMD5Util;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * 门锁服务
+ */
+@Slf4j
+@Service
+public class DoorLockComponent {
+
+    private String sign;
+
+    @Autowired
+    private DoorLockConfig doorLockConfig;
+
+    /**
+     * 下发密码
+     * @param addPasswordDTO
+     * @return
+     * @throws JsonProcessingException
+     */
+    public DoorLockAddPasswordDataDTO addPassword(DoorLockAddPasswordRequestDTO addPasswordDTO) {
+        try {
+            String uri = "open/api/v2/lock/addPassword";
+            String url = doorLockConfig.getServiceHost() + uri;
+
+            addPasswordDTO.setCategoryId(doorLockConfig.getCategoryId());
+            ObjectMapper objectMapper = new ObjectMapper();
+            String encrypt = DoorLockAESUtil.encrypt(objectMapper.writeValueAsString(addPasswordDTO), doorLockConfig.getAppSecret());
+
+            RestTemplate restTemplate = new RestTemplate();
+            HttpHeaders headers = new HttpHeaders();
+            headers.add("Content-Type", "application/json");
+            headers.add("appId", doorLockConfig.getAppId());
+            headers.add("sign", getSign());
+            HttpEntity<String> formEntity = new HttpEntity<>(encrypt, headers);
+            ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, formEntity, String.class);
+            String body = responseEntity.getBody();
+
+            // {"result":1,"message":"successful operation",
+            // "data":{"id":"e4252cbabb884d5dba99d3a0fef24667","name":"test","usertype":4,
+            // "lockId":"bb725cba35484034b08f4d6e3f90b584","temporaryPassword":"B07CF12E3A1E2FC184D0DA2548FF0943",
+            // "starttime":1659420000000,"endtime":1659499200000,"enable":1,"taskId":null,"status":0,"password":"386327"}}
+            JsonNode jsonNode = objectMapper.readTree(body);
+            String result = jsonNode.get("result").asText();
+            if (!"1".equals(result)) {
+                throw new RRException(BizCodeEnume.THIRD_PARTY_SERVICE_CALL_FAILED, "请求结果状态不为1");
+            }
+
+            String dataJsonStr = jsonNode.get("data").toString();
+            DoorLockAddPasswordDataDTO dto = objectMapper.readValue(dataJsonStr, DoorLockAddPasswordDataDTO.class);
+            return dto;
+        } catch (Exception e) {
+            throw new RRException(BizCodeEnume.THIRD_PARTY_SERVICE_CALL_FAILED, "门锁服务-请求密码失败-" + e.getMessage());
+        }
+    }
+
+    private String getSign() {
+        if (StringUtils.hasText(sign)) {
+            return sign;
+        } else {
+            sign = DoorLockMD5Util.getMD5(doorLockConfig.getAppId() + doorLockConfig.getAppSecret());
+            return sign;
+        }
+    }
+
+    public static void main(String[] args) throws JsonProcessingException {
+        ObjectMapper objectMapper = new ObjectMapper();
+        String json = "{\"result\":1,\"message\":\"successful operation\",\"data\":{\"id\":\"b03ae22669374825a3a00e0f30a49d66\",\"name\":\"202207291607006501552928665994690562\",\"usertype\":4,\"lockId\":\"bb725cba35484034b08f4d6e3f90b584\",\"temporaryPassword\":\"0C0F326CAA87E4C6A942246ADE1F4161\",\"starttime\":1659420000000,\"endtime\":1659499200000,\"enable\":1,\"taskId\":null,\"status\":0,\"password\":\"270969\"}}";
+        JsonNode jsonNode = objectMapper.readTree(json);
+
+        System.out.println(jsonNode.get("result").asText());
+        JsonNode dataNode = jsonNode.get("data");
+        System.out.println(dataNode.toString());
+
+        DoorLockAddPasswordDataDTO dto = objectMapper.readValue(dataNode.toString(), DoorLockAddPasswordDataDTO.class);
+        System.out.println(dto);
+    }
+}

+ 9 - 4
src/main/java/com/chuanghai/ihotel/component/WaterElectricComponent.java

@@ -69,11 +69,14 @@ public class WaterElectricComponent {
      * @param pointId
      * @return
      */
-    public JsonNode queryPowerRealTimeData(String pointId) {
+    public String queryPowerRealTimeData(String pointId) {
         Map<String, String> map = new HashMap<>();
         map.put("pointId", pointId);
         try {
-            return queryData("queryPowerRealTimeData", map, queryToken());
+            JsonNode jsonNode = queryData("queryPowerRealTimeData", map, queryToken());
+            // {"bm": 1822.1, "dataTime": "", "frequency": "", "pointId": "", "status": 0}
+            log.info("读取电表数据【{}】", jsonNode.toString());
+            return jsonNode.get("bm").asText();
         } catch (Exception e) {
             throw new RRException(BizCodeEnume.THIRD_PARTY_SERVICE_CALL_FAILED, "请求水电接口-获取电表实时数据异常");
         }
@@ -84,12 +87,14 @@ public class WaterElectricComponent {
      * @param pointId
      * @return
      */
-    public JsonNode queryLastHistoryCumulantInfo(String pointId) {
+    public String queryLastHistoryCumulantInfo(String pointId) {
         Map<String, String> map = new HashMap<>();
         map.put("pointId", pointId);
         map.put("pointType", "2");
         try {
-            return queryData("queryLastHistoryCumulantInfo", map, queryToken());
+            JsonNode jsonNode = queryData("queryLastHistoryCumulantInfo", map, queryToken());
+            log.info("读取水表数据【{}】", jsonNode.toString());
+            return jsonNode.get("bm").asText();
         } catch (Exception e) {
             throw new RRException(BizCodeEnume.THIRD_PARTY_SERVICE_CALL_FAILED, "请求水电接口-获取电表实时数据异常");
         }

+ 19 - 0
src/main/java/com/chuanghai/ihotel/config/DoorLockConfig.java

@@ -0,0 +1,19 @@
+package com.chuanghai.ihotel.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 门锁配置
+ */
+@Data
+@Configuration
+@ConfigurationProperties(prefix = "door-lock")
+public class DoorLockConfig {
+
+    private String appId;
+    private String appSecret;
+    private String categoryId;
+    private String serviceHost;
+}

+ 15 - 3
src/main/java/com/chuanghai/ihotel/controller/HotelOrderController.java

@@ -147,7 +147,7 @@ public class HotelOrderController {
     }
 
     /**
-     * 用户订单详情
+     * 订单详情 【管理端】
      * @param userToken 用户token
      * @param orderId 订单id
      * @return
@@ -191,7 +191,7 @@ public class HotelOrderController {
     }
 
     /**
-     * 取消订单【用户端】
+     * 取消订单
      * @param userToken 用户token
      * @param orderId 订单id
      * @return
@@ -205,7 +205,19 @@ public class HotelOrderController {
         return CommonResult.ok();
     }
 
-    // 办理入住 -> 门锁、水电
+    /**
+     * 办理入住
+     * @param userToken 用户token
+     * @param orderId 订单id
+     * @return
+     */
+    @UserLoginCheck
+    @PutMapping("user/order/hold/{orderId}")
+    public CommonResult<String> userHoldOrder(@RequestHeader("user_token") String userToken,
+                                              @PathVariable("orderId") Long orderId) {
+        hotelOrderService.userHoldOrder(orderId);
+        return CommonResult.ok();
+    }
 
 
 

+ 8 - 8
src/main/java/com/chuanghai/ihotel/controller/RoomDoorLockController.java

@@ -12,8 +12,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RestController;
 
-import com.chuanghai.ihotel.entity.RoomDoorLockEntity;
-import com.chuanghai.ihotel.service.RoomDoorLockService;
+import com.chuanghai.ihotel.entity.RoomDoorLockDataEntity;
+import com.chuanghai.ihotel.service.RoomDoorLockDataService;
 import com.chuanghai.ihotel.common.utils.PageUtils;
 import com.chuanghai.ihotel.common.utils.CommonResult;
 import com.chuanghai.ihotel.common.utils.PageParam;
@@ -30,13 +30,13 @@ import com.chuanghai.ihotel.common.utils.PageParam;
 @RequestMapping("roomDoorLock")
 public class RoomDoorLockController {
     @Autowired
-    private RoomDoorLockService roomDoorLockService;
+    private RoomDoorLockDataService roomDoorLockService;
 
     /**
      * 列表
      */
     @GetMapping("/list")
-    public CommonResult<PageUtils<RoomDoorLockEntity>> list(PageParam pageParam){
+    public CommonResult<PageUtils<RoomDoorLockDataEntity>> list(PageParam pageParam){
         PageUtils page = roomDoorLockService.queryPage(pageParam);
 
         return CommonResult.ok().setResult(page);
@@ -47,8 +47,8 @@ public class RoomDoorLockController {
      * 信息
      */
     @GetMapping("/info/{id}")
-    public CommonResult<RoomDoorLockEntity> info(@PathVariable("id") Long id){
-		RoomDoorLockEntity roomDoorLock = roomDoorLockService.getById(id);
+    public CommonResult<RoomDoorLockDataEntity> info(@PathVariable("id") Long id){
+		RoomDoorLockDataEntity roomDoorLock = roomDoorLockService.getById(id);
 
         return CommonResult.ok().setResult(roomDoorLock);
     }
@@ -57,7 +57,7 @@ public class RoomDoorLockController {
      * 保存
      */
     @PostMapping("/save")
-    public CommonResult<String> save(@RequestBody RoomDoorLockEntity roomDoorLock){
+    public CommonResult<String> save(@RequestBody RoomDoorLockDataEntity roomDoorLock){
 		roomDoorLockService.save(roomDoorLock);
 
         return CommonResult.ok();
@@ -67,7 +67,7 @@ public class RoomDoorLockController {
      * 修改
      */
     @PutMapping("/update")
-    public CommonResult<String> update(@RequestBody RoomDoorLockEntity roomDoorLock){
+    public CommonResult<String> update(@RequestBody RoomDoorLockDataEntity roomDoorLock){
 		boolean flag = roomDoorLockService.updateById(roomDoorLock);
 
 		if (flag) {

+ 25 - 0
src/main/java/com/chuanghai/ihotel/controller/TestController.java

@@ -1,17 +1,25 @@
 package com.chuanghai.ihotel.controller;
 
+import com.chuanghai.ihotel.component.DoorLockComponent;
 import com.chuanghai.ihotel.component.WaterElectricComponent;
+import com.chuanghai.ihotel.dto.DoorLockAddPasswordRequestDTO;
+import com.fasterxml.jackson.core.JsonProcessingException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+
 @RestController
 @RequestMapping("test")
 public class TestController {
 
     @Autowired
     WaterElectricComponent waterElectricComponent;
+    @Autowired
+    DoorLockComponent doorLockComponent;
 
     @GetMapping("test1")
     public void test1() {
@@ -32,4 +40,21 @@ public class TestController {
     public void test4(String pointId, String operType) {
         System.out.println(waterElectricComponent.remoteDisconnect(pointId, operType));
     }
+
+    @GetMapping("test5")
+    public void test5() throws JsonProcessingException {
+        LocalDateTime startTime = LocalDateTime.of(2022, 8, 2, 14, 0);
+        LocalDateTime endTime = LocalDateTime.of(2022, 8, 3, 12, 0);
+
+        DoorLockAddPasswordRequestDTO dto = DoorLockAddPasswordRequestDTO
+                .builder()
+                .categoryId("d0c248256f8346d2a19afa296562b319")
+                .luid("80A036D93CFB")
+                .type("4")
+                .userName("test")
+                .startTime(startTime.toInstant(ZoneOffset.of("+8")).toEpochMilli())
+                .endTime(endTime.toInstant(ZoneOffset.of("+8")).toEpochMilli())
+                .build();
+        doorLockComponent.addPassword(dto);
+    }
 }

+ 3 - 3
src/main/java/com/chuanghai/ihotel/dao/RoomDoorLockDao.java

@@ -1,17 +1,17 @@
 package com.chuanghai.ihotel.dao;
 
-import com.chuanghai.ihotel.entity.RoomDoorLockEntity;
+import com.chuanghai.ihotel.entity.RoomDoorLockDataEntity;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import org.apache.ibatis.annotations.Mapper;
 
 /**
- * 门锁 
+ * 门锁数据
  * 
  * @author codingliang
  * @email codingliang@gmail.com
  * @date 2022-07-27 10:02:04
  */
 @Mapper
-public interface RoomDoorLockDao extends BaseMapper<RoomDoorLockEntity> {
+public interface RoomDoorLockDataDao extends BaseMapper<RoomDoorLockDataEntity> {
 	
 }

+ 17 - 0
src/main/java/com/chuanghai/ihotel/dao/RoomThirdSettingDao.java

@@ -0,0 +1,17 @@
+package com.chuanghai.ihotel.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.chuanghai.ihotel.entity.RoomThirdSettingEntity;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 房间第三方平台标识
+ * 
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2022-07-27 10:02:04
+ */
+@Mapper
+public interface RoomThirdSettingDao extends BaseMapper<RoomThirdSettingEntity> {
+	
+}

+ 28 - 0
src/main/java/com/chuanghai/ihotel/dto/DoorLockAddPasswordDataDTO.java

@@ -0,0 +1,28 @@
+package com.chuanghai.ihotel.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+/**
+ * @Author: codingliang
+ * @Description: 门锁新增密码返回dto
+ * @Date: 2022-08-02 15:59
+ * @Version: V1.0
+ **/
+@Data
+public class DoorLockAddPasswordDataDTO {
+    private String id;
+    private String name;
+    @JsonProperty("usertype")
+    private String userType;
+    private String lockId;
+    private String temporaryPassword;
+    @JsonProperty("starttime")
+    private Long startTime;
+    @JsonProperty("endtime")
+    private Long endTime;
+    private Integer enable;
+    private String taskId;
+    private Integer status;
+    private String password;
+}

+ 24 - 0
src/main/java/com/chuanghai/ihotel/dto/DoorLockAddPasswordRequestDTO.java

@@ -0,0 +1,24 @@
+package com.chuanghai.ihotel.dto;
+
+import lombok.Builder;
+import lombok.Data;
+
+/**
+ * 门锁下发密码dto
+ */
+@Data
+@Builder
+public class DoorLockAddPasswordRequestDTO {
+    private String categoryId;
+    private String luid;
+    private String type;
+    private String userName;
+    /**
+     * 有效时间 13位时间戳
+     */
+    private Long startTime;
+    /**
+     * 有效时间 13位时间戳
+     */
+    private Long endTime;
+}

+ 1 - 0
src/main/java/com/chuanghai/ihotel/entity/HotelOrderBillEntity.java

@@ -1,5 +1,6 @@
 package com.chuanghai.ihotel.entity;
 
+import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import lombok.Data;

+ 16 - 9
src/main/java/com/chuanghai/ihotel/entity/RoomDoorLockEntity.java

@@ -8,15 +8,15 @@ import java.io.Serializable;
 import java.time.LocalDateTime;
 
 /**
- * 门锁 
+ * 门锁数据
  * 
  * @author codingliang
  * @email codingliang@gmail.com
  * @date 2022-07-27 10:02:04
  */
 @Data
-@TableName("room_door_lock")
-public class RoomDoorLockEntity implements Serializable {
+@TableName("room_door_lock_data")
+public class RoomDoorLockDataEntity implements Serializable {
 	private static final long serialVersionUID = 8465903308715869966L;
 
 	/**
@@ -29,20 +29,27 @@ public class RoomDoorLockEntity implements Serializable {
 	 */
 	private Long roomId;
 	/**
-	 * id
+	 * 订单id
 	 */
-	private String lockId;
+	private Long orderId;
 	/**
-	 * 锁序列号
+	 * 锁id 用于删除锁
 	 */
-	private String lockNo;
+	private String lockId;
 	/**
 	 * 实时密码
 	 */
-	private String lockRealtimeNumber;
+	private String lockRealtimePassword;
+	/**
+	 * 有效时间-开始
+	 */
+	private LocalDateTime startTime;
+	/**
+	 * 有效时间-结束
+	 */
+	private LocalDateTime endTime;
 	/**
 	 * 更新时间
 	 */
 	private LocalDateTime updateTime;
-
 }

+ 41 - 0
src/main/java/com/chuanghai/ihotel/entity/RoomThirdSettingEntity.java

@@ -0,0 +1,41 @@
+package com.chuanghai.ihotel.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 房间第三方平台标识
+ *
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2022-07-27 10:02:04
+ */
+@Data
+@TableName("room_third_setting")
+public class RoomThirdSettingEntity implements Serializable {
+
+    private static final long serialVersionUID = 6141143627097396447L;
+
+    /**
+     * id
+     */
+    private Long id;
+    /**
+     * 房间id
+     */
+    private Long roomId;
+    /**
+     * 水表码
+     */
+    private String waterId;
+    /**
+     * 电表码
+     */
+    private String electricId;
+    /**
+     * 锁id
+     */
+    private String lockId;
+}

+ 9 - 0
src/main/java/com/chuanghai/ihotel/service/HotelOrderBillService.java

@@ -15,5 +15,14 @@ import com.chuanghai.ihotel.entity.HotelOrderBillEntity;
 public interface HotelOrderBillService extends IService<HotelOrderBillEntity> {
 
     PageUtils queryPage(PageParam pageParam);
+
+    HotelOrderBillEntity findByOrderId(Long orderId);
+
+    /**
+     * 生成结账单
+     * @param orderId 订单id
+     * @param roomId 房间id
+     */
+    void generateBill(Long orderId, Long roomId);
 }
 

+ 33 - 0
src/main/java/com/chuanghai/ihotel/service/HotelOrderService.java

@@ -10,6 +10,7 @@ import com.chuanghai.ihotel.dto.EventMessageDTO;
 import com.chuanghai.ihotel.entity.HotelOrderEntity;
 import com.chuanghai.ihotel.vo.ConfirmOrderVO;
 import com.chuanghai.ihotel.vo.OrderSubmitVO;
+import com.chuanghai.ihotel.vo.UserOrderDetailVO;
 
 import java.time.LocalDateTime;
 
@@ -75,5 +76,37 @@ public interface HotelOrderService extends IService<HotelOrderEntity> {
      * @param orderId 订单id
      */
     boolean cancelOrder(String userFlag, Long orderId);
+
+    /**
+     * 用户订单详情
+     * @param orderId
+     * @return
+     */
+    UserOrderDetailVO userOrderDetail(Long orderId);
+
+    /**
+     * 获取支付参数
+     * @param orderId
+     * @return
+     */
+    OrderSubmitVO getOrderPayParam(Long orderId);
+
+    /**
+     * 用户删除订单
+     * @param orderId
+     */
+    void userDeleteOrder(Long orderId);
+
+    /**
+     * 用户取消订单
+     * @param orderId
+     */
+    void userCancelOrder(Long orderId);
+
+    /**
+     * 用户办理入住
+     * @param orderId
+     */
+    void userHoldOrder(Long orderId);
 }
 

+ 9 - 2
src/main/java/com/chuanghai/ihotel/service/RoomDoorLockService.java

@@ -3,7 +3,8 @@ package com.chuanghai.ihotel.service;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.chuanghai.ihotel.common.utils.PageUtils;
 import com.chuanghai.ihotel.common.utils.PageParam;
-import com.chuanghai.ihotel.entity.RoomDoorLockEntity;
+import com.chuanghai.ihotel.entity.HotelOrderEntity;
+import com.chuanghai.ihotel.entity.RoomDoorLockDataEntity;
 
 /**
  * 门锁 
@@ -12,8 +13,14 @@ import com.chuanghai.ihotel.entity.RoomDoorLockEntity;
  * @email codingliang@gmail.com
  * @date 2022-07-27 10:02:04
  */
-public interface RoomDoorLockService extends IService<RoomDoorLockEntity> {
+public interface RoomDoorLockDataService extends IService<RoomDoorLockDataEntity> {
 
     PageUtils queryPage(PageParam pageParam);
+
+    /**
+     * 生成密码
+     * @param order
+     */
+    void generatePassword(HotelOrderEntity order);
 }
 

+ 17 - 0
src/main/java/com/chuanghai/ihotel/service/RoomThirdSettingService.java

@@ -0,0 +1,17 @@
+package com.chuanghai.ihotel.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.chuanghai.ihotel.entity.RoomThirdSettingEntity;
+
+/**
+ * 房间水电表
+ *
+ * @author codingliang
+ * @email codingliang@gmail.com
+ * @date 2022-07-27 10:02:04
+ */
+public interface RoomThirdSettingService extends IService<RoomThirdSettingEntity> {
+
+    RoomThirdSettingEntity findByRoomId(Long roomId);
+}
+

+ 64 - 1
src/main/java/com/chuanghai/ihotel/service/impl/HotelOrderBillServiceImpl.java

@@ -1,5 +1,13 @@
 package com.chuanghai.ihotel.service.impl;
 
+import com.chuanghai.ihotel.common.exception.BizCodeEnume;
+import com.chuanghai.ihotel.common.exception.RRException;
+import com.chuanghai.ihotel.component.WaterElectricComponent;
+import com.chuanghai.ihotel.entity.RoomThirdSettingEntity;
+import com.chuanghai.ihotel.entity.SystemSettingEntity;
+import com.chuanghai.ihotel.service.RoomThirdSettingService;
+import com.chuanghai.ihotel.service.SystemSettingService;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -11,19 +19,74 @@ import com.chuanghai.ihotel.common.utils.PageParam;
 import com.chuanghai.ihotel.dao.HotelOrderBillDao;
 import com.chuanghai.ihotel.entity.HotelOrderBillEntity;
 import com.chuanghai.ihotel.service.HotelOrderBillService;
+import org.springframework.util.StringUtils;
+
+import java.math.BigDecimal;
 
 
 @Service("hotelOrderBillService")
 public class HotelOrderBillServiceImpl extends ServiceImpl<HotelOrderBillDao, HotelOrderBillEntity> implements HotelOrderBillService {
 
+    @Autowired
+    private SystemSettingService systemSettingService;
+    @Autowired
+    private RoomThirdSettingService roomWaterElectricService;
+    @Autowired
+    private WaterElectricComponent waterElectricComponent;
+
     @Override
     public PageUtils queryPage(PageParam pageParam) {
         IPage<HotelOrderBillEntity> page = this.page(
                 new MyQuery<HotelOrderBillEntity>().getPage(pageParam),
-                new QueryWrapper<HotelOrderBillEntity>()
+                new QueryWrapper<>()
         );
 
         return new PageUtils(page);
     }
 
+    @Override
+    public HotelOrderBillEntity findByOrderId(Long orderId) {
+        QueryWrapper<HotelOrderBillEntity> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("hotel_order_id", orderId);
+        queryWrapper.last("limit 1");
+        return this.getOne(queryWrapper);
+    }
+
+    @Override
+    public void generateBill(Long orderId, Long roomId) {
+        // 系统设置
+        SystemSettingEntity systemSetting = systemSettingService.get();
+
+        // 水电抄表
+        RoomThirdSettingEntity waterElectricEntity = roomWaterElectricService.findByRoomId(roomId);
+        if (waterElectricEntity == null) {
+            throw new RRException(BizCodeEnume.PERMISSION_DENIED, "房间水电表数据读取失败");
+        }
+
+        String electricData = waterElectricComponent.queryPowerRealTimeData(waterElectricEntity.getElectricId());
+        if (!StringUtils.hasText(electricData)) {
+            throw new RRException(BizCodeEnume.UNKNOW_EXCEPTION, "读取电表数据异常");
+        }
+        String waterData = waterElectricComponent.queryLastHistoryCumulantInfo(waterElectricEntity.getWaterId());
+        if (!StringUtils.hasText(waterData)) {
+            throw new RRException(BizCodeEnume.UNKNOW_EXCEPTION, "读取电表数据异常");
+        }
+
+        // 生成结账单
+        HotelOrderBillEntity orderBill = new HotelOrderBillEntity();
+        orderBill.setHotelOrderId(orderId);
+        orderBill.setRoomId(roomId);
+        orderBill.setPriceOfElectric(systemSetting.getPriceOfElectric().toString());
+        orderBill.setPriceOfWater(systemSetting.getPriceOfWater().toString());
+        orderBill.setStartOfElectric(electricData);
+        orderBill.setStartOfWater(waterData);
+        orderBill.setTotalFree(new BigDecimal("0"));
+        orderBill.setDiscountFree(systemSetting.getFreeTotal());
+        orderBill.setShouldFree(new BigDecimal("0"));
+        orderBill.setRealFree(new BigDecimal("0"));
+        orderBill.setStatu("1"); // 1待处理 初始值、2已完成
+
+        this.save(orderBill);
+    }
+
 }

+ 134 - 0
src/main/java/com/chuanghai/ihotel/service/impl/HotelOrderServiceImpl.java

@@ -1,6 +1,7 @@
 package com.chuanghai.ihotel.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.IdWorker;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -20,6 +21,7 @@ import com.chuanghai.ihotel.controller.request.SubmitOrderRequest;
 import com.chuanghai.ihotel.dao.HotelOrderDao;
 import com.chuanghai.ihotel.dto.EventMessageDTO;
 import com.chuanghai.ihotel.dto.LockRoomDTO;
+import com.chuanghai.ihotel.entity.HotelOrderBillEntity;
 import com.chuanghai.ihotel.entity.HotelOrderEntity;
 import com.chuanghai.ihotel.entity.HotelUserEntity;
 import com.chuanghai.ihotel.entity.RoomEntity;
@@ -29,8 +31,10 @@ import com.chuanghai.ihotel.enums.EventMessageTypeEnum;
 import com.chuanghai.ihotel.enums.OrderBillStatuEnum;
 import com.chuanghai.ihotel.enums.OrderStatuEnum;
 import com.chuanghai.ihotel.enums.UserIdentityTypeEnum;
+import com.chuanghai.ihotel.service.HotelOrderBillService;
 import com.chuanghai.ihotel.service.HotelOrderService;
 import com.chuanghai.ihotel.service.HotelUserService;
+import com.chuanghai.ihotel.service.RoomDoorLockDataService;
 import com.chuanghai.ihotel.service.RoomRealtimeStatuService;
 import com.chuanghai.ihotel.service.RoomService;
 import com.chuanghai.ihotel.service.RoomTypeService;
@@ -39,6 +43,7 @@ import com.chuanghai.ihotel.util.CommonUtil;
 import com.chuanghai.ihotel.vo.ConfirmOrderVO;
 import com.chuanghai.ihotel.vo.LoginUserVO;
 import com.chuanghai.ihotel.vo.OrderSubmitVO;
+import com.chuanghai.ihotel.vo.UserOrderDetailVO;
 import com.chuanghai.ihotel.vo.UserOrderIndexVO;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.amqp.rabbit.core.RabbitTemplate;
@@ -71,6 +76,10 @@ public class HotelOrderServiceImpl extends ServiceImpl<HotelOrderDao, HotelOrder
     @Autowired
     private RoomService roomService;
     @Autowired
+    private HotelOrderBillService orderBillService;
+    @Autowired
+    private RoomDoorLockDataService doorLockService;
+    @Autowired
     private PayComponent payComponent;
     @Autowired
     private JXNXSPayConfig jxnxsPayConfig;
@@ -376,4 +385,129 @@ public class HotelOrderServiceImpl extends ServiceImpl<HotelOrderDao, HotelOrder
         roomRealtimeStatuService.releaseByBizId(orderEntity.getId());
         return true;
     }
+
+    @Override
+    public UserOrderDetailVO userOrderDetail(Long orderId) {
+        HotelOrderEntity orderEntity = userGetOrderById(orderId);
+
+        UserOrderDetailVO detailVO = new UserOrderDetailVO();
+        BeanUtils.copyProperties(orderEntity, detailVO);
+
+        RoomTypeEntity roomType = roomTypeService.myGetById(orderEntity.getRoomTypeId());
+        detailVO.setRoomTypeUsualPrice(roomType.getUsualPrice());
+        detailVO.setRoomTypeDiscountPrice(roomType.getDiscountPrice());
+
+        // 订单状态为已入住之后,查询水电等相关信息
+        if (Integer.valueOf(orderEntity.getOrderStatu()).intValue() >= Integer.valueOf(OrderStatuEnum.HOLD_ON.getCode()).intValue()) {
+            HotelOrderBillEntity orderBill = orderBillService.findByOrderId(orderId);
+            if (orderBill == null) {
+                throw new RRException(BizCodeEnume.UNKNOW_EXCEPTION, "用户订单详情-订单状态错误");
+            }
+            BeanUtils.copyProperties(orderBill, detailVO);
+        }
+
+        return detailVO;
+    }
+
+    @Override
+    public OrderSubmitVO getOrderPayParam(Long orderId) {
+        HotelOrderEntity orderEntity = userGetOrderById(orderId);
+        if (!OrderStatuEnum.WAIT_PAY.getCode().equalsIgnoreCase(orderEntity.getOrderStatu())) {
+            throw new RRException(BizCodeEnume.PARAMETER_ERROR, "当前订单状态为非待支付状态");
+        }
+
+        // 支付参数
+        String payUrl = String.format(jxnxsPayConfig.getPayUrl(), orderEntity.getOrderNo(), orderEntity.getPayAmount());
+        return OrderSubmitVO.builder().orderId(orderId).payUrl(payUrl).build();
+    }
+
+    @Override
+    public void userDeleteOrder(Long orderId) {
+        HotelOrderEntity order = userGetOrderById(orderId);
+
+        String orderStatu = order.getOrderStatu();
+
+        // 已取消、待支付、已完成订单才可以被删除
+        if (!(OrderStatuEnum.CANCEL.getCode().equalsIgnoreCase(orderStatu)
+                || OrderStatuEnum.WAIT_PAY.getCode().equalsIgnoreCase(orderStatu)
+                || OrderStatuEnum.FINISH_PAY.getCode().equalsIgnoreCase(orderStatu))) {
+            throw new RRException(BizCodeEnume.PERMISSION_DENIED, "当前订单不可删除");
+        }
+
+        UpdateWrapper<HotelOrderEntity> updateWrapper = new UpdateWrapper<>();
+        updateWrapper.eq("id", orderId);
+        updateWrapper.set("delete_flag", "0"); // 0表示删除
+        updateWrapper.last("limit 1");
+
+        this.update(null, updateWrapper);
+    }
+
+    @Override
+    public void userCancelOrder(Long orderId) {
+        HotelOrderEntity order = userGetOrderById(orderId);
+
+        // 已取消、待支付、已完成订单才可以被删除
+        if (!OrderStatuEnum.WAIT_PAY.getCode().equalsIgnoreCase(order.getOrderStatu())) {
+            throw new RRException(BizCodeEnume.PERMISSION_DENIED, "当前订单不可取消");
+        }
+        UpdateWrapper<HotelOrderEntity> updateWrapper = new UpdateWrapper<>();
+        updateWrapper.eq("id", orderId);
+        updateWrapper.set("order_statu", OrderStatuEnum.WAIT_PAY.getCode());
+        updateWrapper.last("limit 1");
+        this.update(null, updateWrapper);
+    }
+
+    @Transactional
+    @Override
+    public void userHoldOrder(Long orderId) {
+        HotelOrderEntity order = userGetOrderById(orderId);
+        // 支付完成状态的订单才可以办理入住
+        if (!OrderStatuEnum.FINISH_PAY.getCode().equalsIgnoreCase(order.getOrderStatu())) {
+            throw new RRException(BizCodeEnume.PERMISSION_DENIED, "订单状态异常");
+        }
+
+        // 订单有效时间校验
+        LocalDateTime now = LocalDateTime.now();
+        if (now.isAfter(order.getEnableEndTime())) {
+            throw new RRException(BizCodeEnume.PERMISSION_DENIED, "订单超过有效时间");
+        }
+
+        Long roomId = order.getRoomId();
+        // 水电抄表 => 生成结账单
+        orderBillService.generateBill(orderId, roomId);
+
+        // 门锁密码
+        doorLockService.generatePassword(order);
+
+        // 更新订单状态
+        UpdateWrapper<HotelOrderEntity> updateWrapper = new UpdateWrapper<>();
+        updateWrapper.eq("id", orderId);
+        updateWrapper.set("order_statu", OrderStatuEnum.HOLD_ON.getCode());
+        updateWrapper.last("limit 1");
+        this.update(null, updateWrapper);
+    }
+
+    /**
+     * 用户根据订单id获取订单
+     * @param orderId
+     * @return
+     */
+    private HotelOrderEntity userGetOrderById(Long orderId) {
+        HotelOrderEntity orderEntity = this.getById(orderId);
+        if ("0".equalsIgnoreCase(orderEntity.getDeleteFlag())) {
+            throw new RRException(BizCodeEnume.PARAMETER_ERROR, "订单不存在,订单已删除");
+        }
+
+        if (orderEntity == null) {
+            throw new RRException(BizCodeEnume.PARAMETER_ERROR, "订单不存在,无效的orderId");
+        }
+
+        LoginUserVO loginUserVO = LoginCheckAspect.threadLocal.get();
+        String userFlag = loginUserVO.getCardNumber();
+        if (!orderEntity.getUserFlag().equalsIgnoreCase(userFlag)) {
+            throw new RRException(BizCodeEnume.PERMISSION_DENIED, "非自己的订单");
+        }
+
+        return orderEntity;
+    }
 }

+ 99 - 0
src/main/java/com/chuanghai/ihotel/service/impl/RoomDoorLockDataServiceImpl.java

@@ -0,0 +1,99 @@
+package com.chuanghai.ihotel.service.impl;
+
+import com.chuanghai.ihotel.common.exception.BizCodeEnume;
+import com.chuanghai.ihotel.common.exception.RRException;
+import com.chuanghai.ihotel.component.DoorLockComponent;
+import com.chuanghai.ihotel.dto.DoorLockAddPasswordRequestDTO;
+import com.chuanghai.ihotel.dto.DoorLockAddPasswordDataDTO;
+import com.chuanghai.ihotel.entity.HotelOrderEntity;
+import com.chuanghai.ihotel.entity.RoomThirdSettingEntity;
+import com.chuanghai.ihotel.service.RoomThirdSettingService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.chuanghai.ihotel.common.utils.PageUtils;
+import com.chuanghai.ihotel.common.utils.MyQuery;
+import com.chuanghai.ihotel.common.utils.PageParam;
+
+import com.chuanghai.ihotel.dao.RoomDoorLockDataDao;
+import com.chuanghai.ihotel.entity.RoomDoorLockDataEntity;
+import com.chuanghai.ihotel.service.RoomDoorLockDataService;
+
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+
+
+@Service("roomDoorLockService")
+public class RoomDoorLockDataServiceImpl extends ServiceImpl<RoomDoorLockDataDao, RoomDoorLockDataEntity> implements RoomDoorLockDataService {
+
+    @Autowired
+    private DoorLockComponent doorLockComponent;
+    @Autowired
+    private RoomThirdSettingService roomThirdSettingService;
+
+    @Override
+    public PageUtils queryPage(PageParam pageParam) {
+        IPage<RoomDoorLockDataEntity> page = this.page(
+                new MyQuery<RoomDoorLockDataEntity>().getPage(pageParam),
+                new QueryWrapper<>()
+        );
+
+        return new PageUtils(page);
+    }
+
+    @Override
+    public void generatePassword(HotelOrderEntity order) {
+        Long roomId = order.getRoomId();
+        RoomThirdSettingEntity roomThirdSettingEntity = roomThirdSettingService.findByRoomId(roomId);
+        if (roomThirdSettingEntity == null) {
+            throw new RRException(BizCodeEnume.UNKNOW_EXCEPTION, "门锁不存在");
+        }
+
+        LocalDateTime startTime = order.getEnableStartTime();
+        LocalDateTime endTime = order.getEnableEndTime();
+        // 判断当前时间段门锁是否被占用
+        if (!safeCheck(roomId, startTime, endTime)) {
+            throw new RRException(BizCodeEnume.UNKNOW_EXCEPTION, "当前门锁被占用,请联系管理员");
+        }
+
+        // 请求密码
+        DoorLockAddPasswordRequestDTO dto = DoorLockAddPasswordRequestDTO
+                .builder()
+                .luid(roomThirdSettingEntity.getLockId())
+                .type("4")
+                .userName(order.getOrderNo())
+                .startTime(startTime.toInstant(ZoneOffset.of("+8")).toEpochMilli())
+                .endTime(endTime.toInstant(ZoneOffset.of("+8")).toEpochMilli())
+                .build();
+        DoorLockAddPasswordDataDTO dataDTO = doorLockComponent.addPassword(dto);
+
+        // 数据入库
+        RoomDoorLockDataEntity doorLockData = new RoomDoorLockDataEntity();
+        doorLockData.setRoomId(roomId);
+        doorLockData.setOrderId(order.getId());
+        doorLockData.setLockId(dataDTO.getLockId());
+        doorLockData.setLockRealtimePassword(dataDTO.getPassword());
+        doorLockData.setStartTime(startTime);
+        doorLockData.setEndTime(endTime);
+        doorLockData.setUpdateTime(LocalDateTime.now());
+
+        this.save(doorLockData);
+    }
+
+    /**
+     * 安全检查 - 检查当前时间段内房间门锁是否被占用
+     * @param roomId 房间id
+     * @param startTime 开始时间
+     * @param endTime 结束时间
+     * @return
+     */
+    private boolean safeCheck(Long roomId, LocalDateTime startTime, LocalDateTime endTime) {
+        QueryWrapper<RoomDoorLockDataEntity> wrapper = new QueryWrapper<>();
+        wrapper.eq("room_id", roomId);
+        wrapper.between("end_time", startTime, endTime);
+        wrapper.last("limit 1");
+        return this.getOne(wrapper) == null;
+    }
+}

+ 0 - 29
src/main/java/com/chuanghai/ihotel/service/impl/RoomDoorLockServiceImpl.java

@@ -1,29 +0,0 @@
-package com.chuanghai.ihotel.service.impl;
-
-import org.springframework.stereotype.Service;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.chuanghai.ihotel.common.utils.PageUtils;
-import com.chuanghai.ihotel.common.utils.MyQuery;
-import com.chuanghai.ihotel.common.utils.PageParam;
-
-import com.chuanghai.ihotel.dao.RoomDoorLockDao;
-import com.chuanghai.ihotel.entity.RoomDoorLockEntity;
-import com.chuanghai.ihotel.service.RoomDoorLockService;
-
-
-@Service("roomDoorLockService")
-public class RoomDoorLockServiceImpl extends ServiceImpl<RoomDoorLockDao, RoomDoorLockEntity> implements RoomDoorLockService {
-
-    @Override
-    public PageUtils queryPage(PageParam pageParam) {
-        IPage<RoomDoorLockEntity> page = this.page(
-                new MyQuery<RoomDoorLockEntity>().getPage(pageParam),
-                new QueryWrapper<RoomDoorLockEntity>()
-        );
-
-        return new PageUtils(page);
-    }
-
-}

+ 24 - 0
src/main/java/com/chuanghai/ihotel/service/impl/RoomThirdSettingServiceImpl.java

@@ -0,0 +1,24 @@
+package com.chuanghai.ihotel.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.chuanghai.ihotel.dao.RoomThirdSettingDao;
+import com.chuanghai.ihotel.entity.RoomThirdSettingEntity;
+import com.chuanghai.ihotel.service.RoomThirdSettingService;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+
+
+@Service("roomWaterElectricService")
+public class RoomThirdSettingServiceImpl extends ServiceImpl<RoomThirdSettingDao, RoomThirdSettingEntity> implements RoomThirdSettingService {
+
+
+    @Cacheable(value = {"roomThirdSetting"}, key = "#root.method.name + '-' + #roomId")
+    @Override
+    public RoomThirdSettingEntity findByRoomId(Long roomId) {
+        QueryWrapper<RoomThirdSettingEntity> wrapper = new QueryWrapper<>();
+        wrapper.eq("room_id", roomId);
+        wrapper.last("limit 1");
+        return this.getOne(wrapper);
+    }
+}

+ 144 - 0
src/main/java/com/chuanghai/ihotel/util/DoorLockAESUtil.java

@@ -0,0 +1,144 @@
+package com.chuanghai.ihotel.util;
+
+import org.springframework.util.Assert;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * 门锁AES工具
+ */
+public class DoorLockAESUtil {
+
+    /**
+     * @Author liujun
+     * @Description:
+     * @params:
+     * @param content 需要加密的内容
+     * @param password  加密密码
+     * @Date 上午 9:41 2017/12/26 0026
+     */
+    public static String encrypt(String content, String password) {
+        //数据为空,不需要进行加解密,否则会出现空指针异常
+        Assert.hasLength(content, "content不能为空");
+        Assert.hasLength(password, "密钥不能为空");
+        password = passwordPad(password);
+
+        return bytes2HexString(encryptAES(content.getBytes(), password.getBytes()));
+    }
+
+    /**
+     * @Author liujun
+     * @Description:
+     * @params:
+     * @param content 待解密内容
+     * @param password 解密密钥
+     * @Date 上午 9:40 2017/12/26 0026
+     */
+    public static String decrypt(String content, String password) {
+        Assert.hasLength(content, "content不能为空");
+        Assert.hasLength(password, "密钥不能为空");
+        password = passwordPad(password);
+
+        return new String(decryptAES(hexString2Bytes(content), password.getBytes()));
+    }
+
+    /**
+     * AES 加密
+     *
+     * @param data 明文
+     * @param key  16、24、32 字节秘钥
+     * @return 密文
+     */
+    public static byte[] encryptAES(final byte[] data,
+                                    final byte[] key) {
+        try {
+            SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
+            Cipher cipher = Cipher.getInstance("AES");// 创建密码器
+            byte[] byteContent = data;
+            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);// 初始化
+            byte[] result = cipher.doFinal(byteContent);
+            return result; // 加密
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    /**
+     * AES 解密
+     *
+     * @param data 密文
+     * @param key  16、24、32 字节秘钥
+     * @return 明文
+     */
+    public static byte[] decryptAES(final byte[] data,
+                                    final byte[] key) {
+        try {
+            SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
+            Cipher cipher = Cipher.getInstance("AES");// 创建密码器
+            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);// 初始化
+            byte[] result = cipher.doFinal(data);
+            return result; // 加密
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    private static String bytes2HexString(final byte[] bytes) {
+        if (bytes == null) return null;
+        int len = bytes.length;
+        if (len <= 0) return null;
+        char[] ret = new char[len << 1];
+        for (int i = 0, j = 0; i < len; i++) {
+            ret[j++] = hexDigits[bytes[i] >>> 4 & 0x0f];
+            ret[j++] = hexDigits[bytes[i] & 0x0f];
+        }
+        return new String(ret);
+    }
+
+    private static final char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+
+    public static byte[] hexString2Bytes(String hexString) {
+        if (isSpace(hexString)) return null;
+        int len = hexString.length();
+        if (len % 2 != 0) {
+            hexString = "0" + hexString;
+            len = len + 1;
+        }
+        char[] hexBytes = hexString.toUpperCase().toCharArray();
+        byte[] ret = new byte[len >> 1];
+        for (int i = 0; i < len; i += 2) {
+            ret[i >> 1] = (byte) (hex2Dec(hexBytes[i]) << 4 | hex2Dec(hexBytes[i + 1]));
+        }
+        return ret;
+    }
+
+    private static int hex2Dec(final char hexChar) {
+        if (hexChar >= '0' && hexChar <= '9') {
+            return hexChar - '0';
+        } else if (hexChar >= 'A' && hexChar <= 'F') {
+            return hexChar - 'A' + 10;
+        } else {
+            throw new IllegalArgumentException();
+        }
+    }
+
+    private static String passwordPad(String password) {
+        if (password.length() < 16) {
+            password = password + "0000000000000000".substring(0, 16 - password.length());
+        } else if (password.length() > 16) {
+            password = password.substring(0, 16);
+        }
+        return password;
+    }
+
+    private static boolean isSpace(final String s) {
+        if (s == null) return true;
+        for (int i = 0, len = s.length(); i < len; ++i) {
+            if (!Character.isWhitespace(s.charAt(i))) {
+                return false;
+            }
+        }
+        return true;
+    }
+}

+ 40 - 0
src/main/java/com/chuanghai/ihotel/util/DoorLockMD5Util.java

@@ -0,0 +1,40 @@
+package com.chuanghai.ihotel.util;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * 门锁md5工具
+ */
+public class DoorLockMD5Util {
+
+    /**
+     * MD5加密
+     *
+     * @param str  明文
+     * @return 密文
+     * @throws Exception
+     */
+    public static String getMD5(String str) {
+        char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+        try {
+            byte[] strTemp = str.getBytes();
+            // 使用MD5创建MessageDigest对象
+            MessageDigest mdTemp = MessageDigest.getInstance("MD5");
+            mdTemp.update(strTemp);
+            byte[] md = mdTemp.digest();
+            int j = md.length;
+            char ch[] = new char[j * 2];
+            int k = 0;
+            for (int i = 0; i < j; i++) {
+                byte b = md[i];
+                // 将每个数(int)b进行双字节加密s
+                ch[k++] = hexDigits[b >> 4 & 0xf];
+                ch[k++] = hexDigits[b & 0xf];
+            }
+            return new String(ch);
+        } catch (NoSuchAlgorithmException e) {
+            return null;
+        }
+    }
+}

+ 128 - 0
src/main/java/com/chuanghai/ihotel/vo/UserOrderDetailVO.java

@@ -0,0 +1,128 @@
+package com.chuanghai.ihotel.vo;
+
+import com.chuanghai.ihotel.util.BigDecimalSerializer;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * @Author: codingliang
+ * @Description: 用户订单详情
+ * @Date: 2022-08-01 9:20
+ * @Version: V1.0
+ **/
+@Data
+public class UserOrderDetailVO {
+    /**
+     * 订单id
+     */
+    private Long id;
+    /**
+     * 订单编号
+     */
+    private String orderNo;
+    /**
+     * 用户姓名
+     */
+    private String userName;
+    /**
+     * 用户手机号码
+     */
+    private String userPhone;
+    /**
+     * 下单时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime createTime;
+    /**
+     * 支付时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime payTime;
+    /**
+     * 最早入住时间 最早可入住时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime enableStartTime;
+    /**
+     * 最晚离店时间 最晚要离店时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime enableEndTime;
+    /**
+     * 房间id
+     */
+    private Long roomId;
+    /**
+     * 房间编号
+     */
+    private String roomNo;
+    /**
+     * 房型id
+     */
+    private Long roomTypeId;
+    /**
+     * 房型名称
+     */
+    private String roomTypeName;
+    /**
+     * 房型日常价格
+     */
+    private BigDecimal roomTypeUsualPrice;
+    /**
+     * 房型优惠价格
+     */
+    private BigDecimal roomTypeDiscountPrice;
+    /**
+     * 实际支付金额
+     */
+    @JsonSerialize(using = BigDecimalSerializer.class)
+    private BigDecimal payAmount;
+    /**
+     * 订单状态 0已取消、1待支付、2待入住、3已入住、4待结账、5已完成
+     */
+    private String orderStatu;
+    /**
+     * 业务状态 0待处理、1发起退款、2发起结账支付、3退款或结账支付完成,订单状态为4的时候,显示该状态
+     */
+    private String bizStatu;
+    /**
+     * 水起码 单位:吨
+     */
+    private String startOfWater;
+    /**
+     * 水止码 单位:吨
+     */
+    private String endOfWater;
+    /**
+     * 电起码 单位:度
+     */
+    private String startOfElectric;
+    /**
+     * 电止码 单位:度
+     */
+    private String endOfElectric;
+    /**
+     * (水电)总费用 单位:元
+     */
+    @JsonSerialize(using = BigDecimalSerializer.class)
+    private BigDecimal totalFree;
+    /**
+     * (水电)减免费用 单位:元
+     */
+    @JsonSerialize(using = BigDecimalSerializer.class)
+    private BigDecimal discountFree;
+    /**
+     * 应缴费用 总费用-减免费用 单位:元
+     */
+    @JsonSerialize(using = BigDecimalSerializer.class)
+    private BigDecimal shouldFree;
+    /**
+     * 补缴费用 应缴费用-预缴费用 【补缴费用大于0时需要调用补缴接口发起支付】
+     */
+    @JsonSerialize(using = BigDecimalSerializer.class)
+    private BigDecimal realFree;
+}

+ 8 - 1
src/main/resources/application.yml

@@ -51,7 +51,7 @@ mybatis-plus:
   mapper-locations: classpath:/mapper/ihotel/*.xml
   global-config:
     db-config:
-      id-type: auto
+      id-type: assign_id
 logging:
   level:
     com.chuanghai: debug
@@ -84,3 +84,10 @@ water-electric:
   sign-key: 8eLaEDi53iHnwOVY
   # 服务地址
   service-host: http://172.16.20.37:8181/ems-share-api/
+
+# 门锁服务配置
+door-lock:
+  app-id: 20071f145a674343b39900a6d2e9c748
+  app-secret: 4f444dfc501b44e1a8641a1c1c1ec618
+  category-id: d0c248256f8346d2a19afa296562b319
+  service-host: https://www.qspms.cn/

+ 19 - 0
src/main/resources/mapper/ihotel/RoomDoorLockDataDao.xml

@@ -0,0 +1,19 @@
+<?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="com.chuanghai.ihotel.dao.RoomDoorLockDataDao">
+
+	<!-- 可根据自己的需求,是否要使用 -->
+    <resultMap type="com.chuanghai.ihotel.entity.RoomDoorLockDataEntity" id="roomDoorLockDataMap">
+        <result property="id" column="id"/>
+        <result property="roomId" column="room_id"/>
+        <result property="orderId" column="order_id"/>
+        <result property="lockId" column="lock_id"/>
+        <result property="lockRealtimePassword" column="lock_realtime_number"/>
+        <result property="startTime" column="start_time"/>
+        <result property="endTime" column="end_time"/>
+        <result property="updateTime" column="update_time"/>
+    </resultMap>
+
+
+</mapper>

+ 4 - 6
src/main/resources/mapper/ihotel/RoomDoorLockDao.xml

@@ -1,17 +1,15 @@
 <?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="com.chuanghai.ihotel.dao.RoomDoorLockDao">
+<mapper namespace="com.chuanghai.ihotel.dao.RoomTypeDao">
 
 	<!-- 可根据自己的需求,是否要使用 -->
-    <resultMap type="com.chuanghai.ihotel.entity.RoomDoorLockEntity" id="roomDoorLockMap">
+    <resultMap type="com.chuanghai.ihotel.entity.RoomThirdSettingEntity" id="roomThirdSettingMap">
         <result property="id" column="id"/>
         <result property="roomId" column="room_id"/>
+        <result property="electricId" column="water_id"/>
+        <result property="waterId" column="electric_id"/>
         <result property="lockId" column="lock_id"/>
-        <result property="lockNo" column="lock_no"/>
-        <result property="lockRealtimeNumber" column="lock_realtime_number"/>
-        <result property="updateTime" column="update_time"/>
     </resultMap>
 
-
 </mapper>