diff --git a/cash-api/account-server/src/main/java/com/czg/controller/admin/CallTableController.java b/cash-api/account-server/src/main/java/com/czg/controller/admin/CallTableController.java new file mode 100644 index 00000000..d7656985 --- /dev/null +++ b/cash-api/account-server/src/main/java/com/czg/controller/admin/CallTableController.java @@ -0,0 +1,176 @@ +package com.czg.controller.admin; + +import com.czg.account.dto.calltable.*; +import com.czg.account.entity.CallConfig; +import com.czg.account.entity.CallQueue; +import com.czg.account.entity.CallTable; +import com.czg.account.service.CallTableService; +import com.czg.annotation.SaAdminCheckPermission; +import com.czg.resp.CzgResult; +import com.czg.sa.StpKit; +import com.mybatisflex.core.paginate.Page; +import com.mybatisflex.core.query.QueryWrapper; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +/** + * 叫号管理 + * + * @author Administrator + */ +@RestController +@RequestMapping("/admin/callTable") +@Slf4j +public class CallTableController { + @Resource + private CallTableService callTableService; + + /** + * 叫号桌型获取 + * + * @param callTableId 叫号桌型id + * @param state 0禁用 1使用 + * @return 分页数据 + */ + @SaAdminCheckPermission(value = "callTable:list", name = "叫号桌型获取") + @GetMapping + public CzgResult get(Long callTableId, Integer state) { + return CzgResult.success(callTableService.get(StpKit.USER.getShopId(), callTableId, state)); + } + + /** + * 叫号桌型新增 + * + * @param addCallTableDTO 新增数据 + * @return 是否成功 + */ + @SaAdminCheckPermission(value = "callTable:add", name = "叫号桌型添加") + @PostMapping + public CzgResult add(@Validated @RequestBody CallTableDTO addCallTableDTO) { + return CzgResult.success(callTableService.add(StpKit.USER.getShopId(), addCallTableDTO)); + } + + /** + * 叫号桌型修改 + * + * @return 是否成功 + */ + @SaAdminCheckPermission(value = "callTable:edit", name = "叫号桌型修改") + @PutMapping + public CzgResult update(@Validated @RequestBody UpdateCallTableDTO callTableDTO) { + return CzgResult.success(callTableService.update(StpKit.USER.getShopId(), callTableDTO)); + } + + /** + * 叫号桌型删除 + * + * @return 是否成功 + */ + @SaAdminCheckPermission(value = "callTable:del", name = "叫号桌型删除") + @DeleteMapping + public CzgResult delete(@Validated @RequestBody BaseCallTableDTO baseCallTableDTO) { + return CzgResult.success(callTableService.remove(new QueryWrapper().eq(CallTable::getShopId, StpKit.USER.getShopId()).eq(CallTable::getId, baseCallTableDTO.getCallTableId()))); + } + + /** + * 获取叫号号码 + */ + @SaAdminCheckPermission(value = "callTable:takeNumber", name = "获取叫号号码") + @PostMapping("takeNumber") + public CzgResult takeNumber(@Validated @RequestBody TakeNumberDTO takeNumberDTO) { + return CzgResult.success(callTableService.takeNumber(StpKit.USER.getShopId(), takeNumberDTO)); + } + + + /** + * 获取叫号页面二维码 + * + * @param callTableId 叫号桌型id + * @return base64编码 + */ + @SaAdminCheckPermission(value = "callTable:takeNumberCode", name = "获取叫号页面二维码") + @GetMapping("takeNumberCode") + public CzgResult takeNumberCode(@RequestParam Integer callTableId) { + return CzgResult.success(callTableService.takeNumberCode(StpKit.USER.getShopId(), callTableId)); + } + + + /** + * 执行叫号 + * + * @return 0失败 1成功 -1用户未订阅 + */ + @SaAdminCheckPermission(value = "callTable:call", name = "执行叫号") + @PostMapping("call") + public CzgResult call(@Validated @RequestBody CallQueueDTO callQueueDTO) { + try { + return CzgResult.success(callTableService.call(StpKit.USER.getShopId(), callQueueDTO)); + } catch (Exception e) { + log.error("异常", e); + return CzgResult.success(1); + } + } + + + /** + * 修改叫号队列状态 + * + * @return 是否成功 + */ + @SaAdminCheckPermission(value = "callTable:updateState", name = "修改叫号队列状态") + @PutMapping("updateState") + public CzgResult confirm(@Validated @RequestBody UpdateCallQueueDTO updateCallQueueDTO) { + return CzgResult.success(callTableService.updateInfo(StpKit.USER.getShopId(), updateCallQueueDTO)); + } + + + /** + * 获取叫号队列 + * + * @param callTableId 桌型id + * @param state 状态 -1已取消 0排队中 1叫号中 2已入座 3 已过号 + * @return 分页数据 + */ + @SaAdminCheckPermission(value = "callTable:queue:list", name = "获取叫号队列") + @GetMapping("queue") + public CzgResult> getQueue(Long callTableId, Integer state) { + return CzgResult.success(callTableService.getQueue(StpKit.USER.getShopId(), callTableId, state)); + } + + + /** + * 获取叫号记录列表 + * + * @param callTableId 桌型id + * @return 数据 + */ + @SaAdminCheckPermission(value = "callTable:callRecord:list", name = "获取叫号记录列表") + @GetMapping("callRecord") + public CzgResult> getCallRecord(Integer callTableId) { + return CzgResult.success(callTableService.getCallRecord(StpKit.USER.getShopId(), callTableId)); + } + + /** + * 获取叫号配置 + * + * @return 配置信息 + */ + @SaAdminCheckPermission(value = "callTable:config:list", name = "获取叫号配置") + @GetMapping("config") + public CzgResult getConfig() { + return CzgResult.success(callTableService.getConfig(StpKit.USER.getShopId())); + } + + /** + * 修改叫号配置 + * + * @return 是否成功 + */ + @SaAdminCheckPermission(value = "callTable:config:edit", name = "修改叫号配置") + @PutMapping("config") + public CzgResult updateConfig(@RequestBody UpdateConfigDTO configDTO) { + return CzgResult.success(callTableService.updateConfig(StpKit.USER.getShopId(), configDTO)); + } +} diff --git a/cash-common/cash-common-redis/src/main/java/com/czg/config/RedisCst.java b/cash-common/cash-common-redis/src/main/java/com/czg/config/RedisCst.java index dccc99c0..8e12f201 100644 --- a/cash-common/cash-common-redis/src/main/java/com/czg/config/RedisCst.java +++ b/cash-common/cash-common-redis/src/main/java/com/czg/config/RedisCst.java @@ -6,6 +6,8 @@ package com.czg.config; * @author Administrator */ public interface RedisCst { + String LOCK_KEY = "LOCK:"; + String LOGIN_CODE = "login:code:"; String SYS_LOG_KEY = "sys:log:"; @@ -14,4 +16,21 @@ public interface RedisCst { String SMS_CODE = "sms:code:"; // 店铺会员动态支付码 String SHOP_USER_DYNAMIC_CODE = "shop:user:dynamic:code:"; + + // 排队取号全局号码 + String TABLE_CALL_NUMBER = "TABLE_CALL_NUMBER:"; + + static String getLockKey(String sign, Object... args) { + StringBuilder key = new StringBuilder(LOCK_KEY + ":" + sign + ":"); + for (Object arg : args) { + if (arg != null) { + key.append(":").append(arg); + } + } + return key.toString(); + } + + static String getTableCallNumKey(Long shopId, Long callTableId) { + return TABLE_CALL_NUMBER + shopId + ":" + callTableId; + } } diff --git a/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/BaseCallTableDTO.java b/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/BaseCallTableDTO.java new file mode 100644 index 00000000..1955ab07 --- /dev/null +++ b/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/BaseCallTableDTO.java @@ -0,0 +1,17 @@ +package com.czg.account.dto.calltable; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + + +/** + * @author Administrator + */ +@Data +public class BaseCallTableDTO { + /** + * 叫号桌型id + */ + @NotNull(message = "台桌id不为空") + private Integer callTableId; +} diff --git a/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/CallQueueDTO.java b/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/CallQueueDTO.java new file mode 100644 index 00000000..52bea16d --- /dev/null +++ b/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/CallQueueDTO.java @@ -0,0 +1,17 @@ +package com.czg.account.dto.calltable; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + + +/** + * @author Administrator + */ +@Data +public class CallQueueDTO{ + /** + * 叫号队列id + */ + @NotNull + private Integer callQueueId; +} diff --git a/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/CallQueueListDTO.java b/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/CallQueueListDTO.java new file mode 100644 index 00000000..58a70396 --- /dev/null +++ b/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/CallQueueListDTO.java @@ -0,0 +1,17 @@ +package com.czg.account.dto.calltable; + +import com.czg.account.entity.CallQueue; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * @author Administrator + */ +@EqualsAndHashCode(callSuper = true) +@Data +public class CallQueueListDTO extends CallQueue { + /** + * 等待人数 + */ + private Long waitingCount; +} diff --git a/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/CallRecordVO.java b/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/CallRecordVO.java new file mode 100644 index 00000000..10afc379 --- /dev/null +++ b/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/CallRecordVO.java @@ -0,0 +1,22 @@ +package com.czg.account.dto.calltable; + +import com.czg.account.entity.CallQueue; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * @author Administrator + */ +@EqualsAndHashCode(callSuper = true) +@Data +public class CallRecordVO extends CallQueue { + /** + * 备注 + */ + private String note; + + /** + * 已过秒数 + */ + private Long sinceAt; +} diff --git a/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/CallTableDTO.java b/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/CallTableDTO.java new file mode 100644 index 00000000..d9478ea0 --- /dev/null +++ b/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/CallTableDTO.java @@ -0,0 +1,55 @@ +package com.czg.account.dto.calltable; + +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + + +/** + * @author Administrator + */ +@Data +public class CallTableDTO { + /** + * 台桌名称 + */ + @NotEmpty(message = "台桌名称不为空") + private String name; + /** + * 备注 + */ + private String note; + /** + * 等待时间 + */ + @NotNull(message = "等待时间不为空") + @Min(1) + private Integer waitTime; + /** + * 前缀 + */ + @NotBlank(message = "前缀不为空") + private String prefix; + /** + * 起始号码 + */ + @NotNull(message = "起始号码不为空") + @Min(1) + private Integer start; + /** + * 临近几桌提醒 + */ + @NotNull(message = "最近号码不为空") + @Min(1) + private Integer nearNum; + /** + * 是否顺延 + */ + private Integer isPostpone; + /** + * 顺延数量 + */ + private Integer postponeNum; +} diff --git a/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/CallTableInfoDTO.java b/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/CallTableInfoDTO.java new file mode 100644 index 00000000..53673eca --- /dev/null +++ b/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/CallTableInfoDTO.java @@ -0,0 +1,17 @@ +package com.czg.account.dto.calltable; + +import com.czg.account.entity.CallTable; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * @author Administrator + */ +@EqualsAndHashCode(callSuper = true) +@Data +public class CallTableInfoDTO extends CallTable { + /** + * 已经排号人数 + */ + private long totalCount; +} diff --git a/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/CallTableNumDTO.java b/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/CallTableNumDTO.java new file mode 100644 index 00000000..3f66d6ef --- /dev/null +++ b/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/CallTableNumDTO.java @@ -0,0 +1,24 @@ +package com.czg.account.dto.calltable; + +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * @author Administrator + */ +@Data +@Accessors(chain = true) +public class CallTableNumDTO { + /** + * 桌型名称 + */ + private String tableName; + /** + * 桌型备注 + */ + private String tableNote; + /** + * 号码 + */ + private String callNum; +} diff --git a/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/CallTablePage.java b/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/CallTablePage.java new file mode 100644 index 00000000..601c6594 --- /dev/null +++ b/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/CallTablePage.java @@ -0,0 +1,18 @@ +package com.czg.account.dto.calltable; + +import com.czg.account.entity.CallTable; +import com.mybatisflex.core.paginate.Page; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * @author Administrator + */ +@EqualsAndHashCode(callSuper = true) +@Data +public class CallTablePage extends Page { + /** + * 总数 + */ + private long totalCount; +} diff --git a/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/TakeNumberDTO.java b/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/TakeNumberDTO.java new file mode 100644 index 00000000..ef7fbd7d --- /dev/null +++ b/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/TakeNumberDTO.java @@ -0,0 +1,33 @@ +package com.czg.account.dto.calltable; + +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.Pattern; +import lombok.Data; +import lombok.EqualsAndHashCode; + + +/** + * @author Administrator + */ +@EqualsAndHashCode(callSuper = true) +@Data +public class TakeNumberDTO extends BaseCallTableDTO{ + /** + * 对应小程序用户id + */ + private Integer userId; + /** + * 手机号 + */ + @NotEmpty + @Pattern(regexp = "^1\\d{10}$|^(0\\d{2,3}-?|\\(0\\d{2,3}\\))?[1-9]\\d{4,7}(-\\d{1,8})?$",message = "手机号码格式错误") + private String phone; + /** + * 备注 + */ + private String note; + /** + * 姓名 + */ + private String name; +} diff --git a/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/UpdateCallQueueDTO.java b/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/UpdateCallQueueDTO.java new file mode 100644 index 00000000..12075cd6 --- /dev/null +++ b/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/UpdateCallQueueDTO.java @@ -0,0 +1,21 @@ +package com.czg.account.dto.calltable; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.Getter; + + +/** + * @author Administrator + */ +@EqualsAndHashCode(callSuper = true) +@Data +@Getter +public class UpdateCallQueueDTO extends CallQueueDTO{ + /** + * 状态 -1已取消 0排队中 1叫号中 2已入座 3 已过号 + */ + @NotNull + private Integer state; +} diff --git a/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/UpdateCallTableDTO.java b/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/UpdateCallTableDTO.java new file mode 100644 index 00000000..d9617b53 --- /dev/null +++ b/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/UpdateCallTableDTO.java @@ -0,0 +1,45 @@ +package com.czg.account.dto.calltable; + +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + + +/** + * @author Administrator + */ +@Data +public class UpdateCallTableDTO{ + /** + * 桌型id + */ + @NotNull(message = "台桌id不为空") + private Integer callTableId; + /** + * 桌型名称 + */ + private String name; + /** + * 桌型备注 + */ + private String note; + /** + * 每桌等待时间 + */ + @Min(1) + private Integer waitTime; + /** + * 前缀 + */ + private String prefix; + /** + * 叫号起始号码 + */ + @Min(1) + private Integer start; + /** + * 临近几桌提醒 + */ + @Min(1) + private Integer nearNum; +} diff --git a/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/UpdateConfigDTO.java b/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/UpdateConfigDTO.java new file mode 100644 index 00000000..43d027e8 --- /dev/null +++ b/cash-common/cash-common-service/src/main/java/com/czg/account/dto/calltable/UpdateConfigDTO.java @@ -0,0 +1,22 @@ +package com.czg.account.dto.calltable; + +import lombok.Data; + +/** + * @author Administrator + */ +@Data +public class UpdateConfigDTO { + /** + * 是否线上取号 + */ + private Integer isOnline; + /** + * 背景图片 + */ + private String bgCover; + /** + * 临近几桌提醒 + */ + private Integer nearNum; +} diff --git a/cash-common/cash-common-service/src/main/java/com/czg/account/entity/CallConfig.java b/cash-common/cash-common-service/src/main/java/com/czg/account/entity/CallConfig.java new file mode 100644 index 00000000..9b2b3e36 --- /dev/null +++ b/cash-common/cash-common-service/src/main/java/com/czg/account/entity/CallConfig.java @@ -0,0 +1,82 @@ +package com.czg.account.entity; + +import com.mybatisflex.annotation.Column; +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import com.mybatisflex.annotation.Table; +import java.io.Serializable; +import java.time.LocalDateTime; + +import java.io.Serial; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 叫号配置表 实体类。 + * + * @author zs + * @since 2025-02-21 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Table("tb_call_config") +public class CallConfig implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id(keyType = KeyType.Auto) + private Long id; + + /** + * 小程序页面地址 + */ + private String pageAddress; + + /** + * 线上取号 1是 0否 + */ + private Integer isOnline; + + /** + * 背景图片 + */ + private String bgCover; + + /** + * 成功提示 + */ + private String successMsg; + + /** + * 临近提示 + */ + private String nearMsg; + + /** + * 过号提示 + */ + private String callingMsg; + + /** + * 店铺id + */ + private Long shopId; + + /** + * 临近几桌提醒 + */ + private Integer nearNum; + + @Column(onInsertValue = "now()") + private LocalDateTime createTime; + + @Column(onInsertValue = "now()", onUpdateValue = "now()") + private LocalDateTime updateTime; + +} diff --git a/cash-common/cash-common-service/src/main/java/com/czg/account/entity/CallQueue.java b/cash-common/cash-common-service/src/main/java/com/czg/account/entity/CallQueue.java new file mode 100644 index 00000000..5349322d --- /dev/null +++ b/cash-common/cash-common-service/src/main/java/com/czg/account/entity/CallQueue.java @@ -0,0 +1,126 @@ +package com.czg.account.entity; + +import com.mybatisflex.annotation.Column; +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import com.mybatisflex.annotation.Table; +import java.io.Serializable; +import java.time.LocalDateTime; + +import java.io.Serial; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 叫号排号队列表 实体类。 + * + * @author zs + * @since 2025-02-21 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Table("tb_call_queue") +public class CallQueue implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id(keyType = KeyType.Auto) + private Long id; + + private Long userId; + + private String openId; + + /** + * 叫号台桌类型id + */ + private Long callTableId; + + /** + * 手机号 + */ + private String phone; + + /** + * 姓名 + */ + private String name; + + /** + * 店铺名称 + */ + private String shopName; + + /** + * 店铺id + */ + private Long shopId; + + /** + * -1已取消 0排队中 1叫号中 2已入座 3 已过号 + */ + private Integer state; + + /** + * 订阅提醒 0未订阅 1已订阅 + */ + private Integer subState; + + /** + * 备注 + */ + private String note; + + /** + * 叫号号码 + */ + private String callNum; + + /** + * 创建年月日 + */ + private String createDay; + + /** + * 是否已经顺延 0 未顺延 1已顺延一次 2顺延一次仍然过号 + */ + private Integer isPostpone; + + /** + * 排号时间 + */ + @Column(onInsertValue = "now()") + private LocalDateTime createTime; + + /** + * 叫号时间 + */ + private LocalDateTime callTime; + + /** + * 叫号次数 + */ + private Integer callCount; + + /** + * 过号时间 + */ + private LocalDateTime passTime; + + /** + * 取消时间 + */ + private LocalDateTime cancelTime; + + /** + * 确认时间 + */ + private LocalDateTime confirmTime; + +} diff --git a/cash-common/cash-common-service/src/main/java/com/czg/account/entity/CallTable.java b/cash-common/cash-common-service/src/main/java/com/czg/account/entity/CallTable.java new file mode 100644 index 00000000..2c9a4fb0 --- /dev/null +++ b/cash-common/cash-common-service/src/main/java/com/czg/account/entity/CallTable.java @@ -0,0 +1,97 @@ +package com.czg.account.entity; + +import com.mybatisflex.annotation.Column; +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import com.mybatisflex.annotation.Table; +import java.io.Serializable; +import java.time.LocalDateTime; + +import java.io.Serial; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 叫号桌型表 实体类。 + * + * @author zs + * @since 2025-02-21 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Table("tb_call_table") +public class CallTable implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id(keyType = KeyType.Auto) + private Long id; + + /** + * 店铺id + */ + private Long shopId; + + /** + * 名称 + */ + private String name; + + /** + * 描述 + */ + private String note; + + /** + * 等待时间分钟 + */ + private Integer waitTime; + + /** + * 前缀 + */ + private String prefix; + + /** + * 起始号码 + */ + private Integer start; + + /** + * 临近几桌提醒 + */ + private Integer nearNum; + + /** + * 0禁用 1使用 + */ + private Integer state; + + /** + * 二维码地址 + */ + private String qrcode; + + /** + * 顺延号码数量 + */ + private Integer postponeNum; + + /** + * 顺延号码数量 + */ + private Integer isPostpone; + + @Column(onInsertValue = "now()") + private LocalDateTime createTime; + + @Column(onInsertValue = "now()", onUpdateValue = "now()") + private LocalDateTime updateTime; + +} diff --git a/cash-common/cash-common-service/src/main/java/com/czg/account/service/CallConfigService.java b/cash-common/cash-common-service/src/main/java/com/czg/account/service/CallConfigService.java new file mode 100644 index 00000000..3c2f552d --- /dev/null +++ b/cash-common/cash-common-service/src/main/java/com/czg/account/service/CallConfigService.java @@ -0,0 +1,14 @@ +package com.czg.account.service; + +import com.mybatisflex.core.service.IService; +import com.czg.account.entity.CallConfig; + +/** + * 叫号配置表 服务层。 + * + * @author zs + * @since 2025-02-21 + */ +public interface CallConfigService extends IService { + +} diff --git a/cash-common/cash-common-service/src/main/java/com/czg/account/service/CallQueueService.java b/cash-common/cash-common-service/src/main/java/com/czg/account/service/CallQueueService.java new file mode 100644 index 00000000..b8acdf87 --- /dev/null +++ b/cash-common/cash-common-service/src/main/java/com/czg/account/service/CallQueueService.java @@ -0,0 +1,14 @@ +package com.czg.account.service; + +import com.mybatisflex.core.service.IService; +import com.czg.account.entity.CallQueue; + +/** + * 叫号排号队列表 服务层。 + * + * @author zs + * @since 2025-02-21 + */ +public interface CallQueueService extends IService { + +} diff --git a/cash-common/cash-common-service/src/main/java/com/czg/account/service/CallTableService.java b/cash-common/cash-common-service/src/main/java/com/czg/account/service/CallTableService.java new file mode 100644 index 00000000..c077d493 --- /dev/null +++ b/cash-common/cash-common-service/src/main/java/com/czg/account/service/CallTableService.java @@ -0,0 +1,39 @@ +package com.czg.account.service; + +import com.czg.account.dto.calltable.*; +import com.czg.account.entity.CallConfig; +import com.czg.account.entity.CallQueue; +import com.mybatisflex.core.paginate.Page; +import com.mybatisflex.core.service.IService; +import com.czg.account.entity.CallTable; + +/** + * 叫号桌型表 服务层。 + * + * @author zs + * @since 2025-02-21 + */ +public interface CallTableService extends IService { + + CallTablePage get(Long shopId, Long callTableId, Integer state); + + boolean add(Long shopId, CallTableDTO addCallTableDTO); + + boolean update(Long shopId, UpdateCallTableDTO callTableDTO); + + CallTableNumDTO takeNumber(Long shopId, TakeNumberDTO takeNumberDTO); + + String takeNumberCode(Long shopId, Integer callTableId); + + Integer call(Long shopId, CallQueueDTO callQueueDTO); + + boolean updateInfo(Long shopId, UpdateCallQueueDTO updateCallQueueDTO); + + Page getQueue(Long shopId, Long callTableId, Integer state); + + Page getCallRecord(Long shopId, Integer callTableId); + + CallConfig getConfig(Long shopId); + + boolean updateConfig(Long shopId, UpdateConfigDTO configDTO); +} diff --git a/cash-service/account-service/src/main/java/com/czg/service/account/mapper/CallConfigMapper.java b/cash-service/account-service/src/main/java/com/czg/service/account/mapper/CallConfigMapper.java new file mode 100644 index 00000000..2fc7108d --- /dev/null +++ b/cash-service/account-service/src/main/java/com/czg/service/account/mapper/CallConfigMapper.java @@ -0,0 +1,14 @@ +package com.czg.service.account.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.czg.account.entity.CallConfig; + +/** + * 叫号配置表 映射层。 + * + * @author zs + * @since 2025-02-21 + */ +public interface CallConfigMapper extends BaseMapper { + +} diff --git a/cash-service/account-service/src/main/java/com/czg/service/account/mapper/CallQueueMapper.java b/cash-service/account-service/src/main/java/com/czg/service/account/mapper/CallQueueMapper.java new file mode 100644 index 00000000..d407403f --- /dev/null +++ b/cash-service/account-service/src/main/java/com/czg/service/account/mapper/CallQueueMapper.java @@ -0,0 +1,19 @@ +package com.czg.service.account.mapper; + +import com.czg.account.dto.calltable.CallRecordVO; +import com.mybatisflex.core.BaseMapper; +import com.czg.account.entity.CallQueue; +import com.mybatisflex.core.paginate.Page; + +/** + * 叫号排号队列表 映射层。 + * + * @author zs + * @since 2025-02-21 + */ +public interface CallQueueMapper extends BaseMapper { + + Page selectCallRecord(); + long selectCallRecord_COUNT(); + +} diff --git a/cash-service/account-service/src/main/java/com/czg/service/account/mapper/CallTableMapper.java b/cash-service/account-service/src/main/java/com/czg/service/account/mapper/CallTableMapper.java new file mode 100644 index 00000000..536d7d56 --- /dev/null +++ b/cash-service/account-service/src/main/java/com/czg/service/account/mapper/CallTableMapper.java @@ -0,0 +1,14 @@ +package com.czg.service.account.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.czg.account.entity.CallTable; + +/** + * 叫号桌型表 映射层。 + * + * @author zs + * @since 2025-02-21 + */ +public interface CallTableMapper extends BaseMapper { + +} diff --git a/cash-service/account-service/src/main/java/com/czg/service/account/service/impl/CallConfigServiceImpl.java b/cash-service/account-service/src/main/java/com/czg/service/account/service/impl/CallConfigServiceImpl.java new file mode 100644 index 00000000..b384ea92 --- /dev/null +++ b/cash-service/account-service/src/main/java/com/czg/service/account/service/impl/CallConfigServiceImpl.java @@ -0,0 +1,18 @@ +package com.czg.service.account.service.impl; + +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.czg.account.entity.CallConfig; +import com.czg.account.service.CallConfigService; +import com.czg.service.account.mapper.CallConfigMapper; +import org.springframework.stereotype.Service; + +/** + * 叫号配置表 服务层实现。 + * + * @author zs + * @since 2025-02-21 + */ +@Service +public class CallConfigServiceImpl extends ServiceImpl implements CallConfigService{ + +} diff --git a/cash-service/account-service/src/main/java/com/czg/service/account/service/impl/CallQueueServiceImpl.java b/cash-service/account-service/src/main/java/com/czg/service/account/service/impl/CallQueueServiceImpl.java new file mode 100644 index 00000000..92484550 --- /dev/null +++ b/cash-service/account-service/src/main/java/com/czg/service/account/service/impl/CallQueueServiceImpl.java @@ -0,0 +1,18 @@ +package com.czg.service.account.service.impl; + +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.czg.account.entity.CallQueue; +import com.czg.account.service.CallQueueService; +import com.czg.service.account.mapper.CallQueueMapper; +import org.springframework.stereotype.Service; + +/** + * 叫号排号队列表 服务层实现。 + * + * @author zs + * @since 2025-02-21 + */ +@Service +public class CallQueueServiceImpl extends ServiceImpl implements CallQueueService{ + +} diff --git a/cash-service/account-service/src/main/java/com/czg/service/account/service/impl/CallTableServiceImpl.java b/cash-service/account-service/src/main/java/com/czg/service/account/service/impl/CallTableServiceImpl.java new file mode 100644 index 00000000..7ecebfdf --- /dev/null +++ b/cash-service/account-service/src/main/java/com/czg/service/account/service/impl/CallTableServiceImpl.java @@ -0,0 +1,537 @@ +package com.czg.service.account.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.qrcode.QrCodeUtil; +import cn.hutool.extra.qrcode.QrConfig; +import com.czg.account.dto.calltable.*; +import com.czg.account.entity.*; +import com.czg.account.service.*; +import com.czg.config.RedisCst; +import com.czg.exception.ApiNotPrintException; +import com.czg.resp.CzgResult; +import com.czg.service.account.mapper.CallQueueMapper; +import com.czg.service.account.util.FunUtil; +import com.czg.system.dto.SysParamsDTO; +import com.czg.system.service.SysParamsService; +import com.czg.utils.JoinQueryWrapper; +import com.czg.utils.PageUtil; +import com.mybatisflex.core.paginate.Page; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.czg.service.account.mapper.CallTableMapper; +import jakarta.annotation.Resource; +import org.apache.dubbo.config.annotation.DubboReference; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Service; + +import java.io.ByteArrayOutputStream; +import java.util.*; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; + +/** + * 叫号桌型表 服务层实现。 + * + * @author zs + * @since 2025-02-21 + */ +@Service +public class CallTableServiceImpl extends ServiceImpl implements CallTableService { +// @DubboReference + private SysParamsService sysParamsService; + + @Resource + private CallQueueService callQueueService; + @Resource + private ShopUserService shopUserService; + @Resource + private StringRedisTemplate stringRedisTemplate; + @Resource + private ShopInfoService shopInfoService; + @Resource + private CallConfigService callConfigService; + @Resource + private CallQueueMapper callQueueMapper; + + @Override + public CallTablePage get(Long shopId, Long callTableId, Integer state) { + QueryWrapper query = new QueryWrapper() + .eq(CallTable::getShopId, shopId) + .eq(CallTable::getState, 1); + + if (callTableId != null) { + query.eq(CallTable::getId, callTableId); + } + + if (state != null) { + query.eq(CallTable::getState, state); + } + Page pageInfo = page(PageUtil.buildPage(), query); + List info = new ArrayList<>(); + long totalCount = 0L; + for (CallTable item : pageInfo.getRecords()) { + long count = callQueueService.queryChain() + .eq(CallQueue::getCallTableId, item.getId()) + .eq(CallQueue::getShopId, shopId) + .eq(CallQueue::getCreateDay, DateUtil.today()) + .in(CallQueue::getState, 0, 1).count(); + + totalCount += count; + + CallTableInfoDTO callTableInfoDTO = BeanUtil.copyProperties(item, CallTableInfoDTO.class); + callTableInfoDTO.setTotalCount(count); + info.add(callTableInfoDTO); + } + + CallTablePage callTablePage = BeanUtil.copyProperties(pageInfo, CallTablePage.class); + callTablePage.setRecords(info); + callTablePage.setTotalCount(totalCount); + return callTablePage; + } + + @Override + public boolean add(Long shopId, CallTableDTO addCallTableDTO) { + long count = queryChain() + .eq(CallTable::getShopId, shopId) + .and(q -> { + q.eq(CallTable::getName, addCallTableDTO.getName()).or(q1 -> { + q1.eq(CallTable::getPrefix, addCallTableDTO.getPrefix()); + }); + }).count(); + if (count > 0) { + throw new ApiNotPrintException("名称或前缀已存在"); + } + + CallTable callTable = BeanUtil.copyProperties(addCallTableDTO, CallTable.class); + callTable.setShopId(shopId); + return save(callTable); + } + + @Override + public boolean update(Long shopId, UpdateCallTableDTO callTableDTO) { + CallTable callTable = queryChain() + .eq(CallTable::getShopId, shopId) + .eq(CallTable::getId, callTableDTO.getCallTableId()).one(); + if (StrUtil.isNotBlank(callTableDTO.getName())) { + long count = queryChain() + .eq(CallTable::getShopId, shopId) + .ne(CallTable::getId, callTableDTO.getCallTableId()) + .eq(CallTable::getName, callTableDTO.getName()).count(); + if (count > 0) { + throw new ApiNotPrintException("名称已存在"); + } + } + + if (StrUtil.isNotBlank(callTableDTO.getPrefix())) { + long count = queryChain() + .eq(CallTable::getShopId, shopId) + .ne(CallTable::getId, callTableDTO.getCallTableId()) + .eq(CallTable::getPrefix, callTableDTO.getPrefix()).count(); + if (count > 0) { + throw new ApiNotPrintException("前缀已存在"); + } + } + + if (callTable == null) { + throw new ApiNotPrintException("桌型不存在"); + } + + + CallTable newInfo = BeanUtil.copyProperties(callTableDTO, CallTable.class); + newInfo.setId(callTable.getId()); + + return updateById(newInfo); + } + + @Override + public CallTableNumDTO takeNumber(Long shopId, TakeNumberDTO takeNumberDTO) { + ShopInfo shopInfo = shopInfoService.getById(shopId); + + CallTable callTable = queryChain() + .eq(CallTable::getShopId, shopId) + .eq(CallTable::getId, takeNumberDTO.getCallTableId()).one(); + if (callTable == null) { + throw new ApiNotPrintException("桌型不存在"); + } + + // 拿取系统内部用户信息 + CallQueue callQueue; + if (takeNumberDTO.getUserId() != null) { + ShopUser shopUser = shopUserService.queryChain() + .eq(ShopUser::getStatus, 1) + .eq(ShopUser::getShopId, shopId) + .eq(ShopUser::getId, takeNumberDTO.getUserId()).one(); + if (shopUser == null) { + throw new ApiNotPrintException("用户不存在"); + } + + callQueue = callQueueService.queryChain() + .eq(CallQueue::getUserId, shopUser.getId()) + .eq(CallQueue::getShopId, shopId) + .in(CallQueue::getState, 0, 1) + .eq(CallQueue::getCreateDay, DateUtil.today()) + .ne(CallQueue::getIsPostpone, 2) + .eq(CallQueue::getCallTableId, takeNumberDTO.getCallTableId()).one(); + if (callQueue != null) { + throw new ApiNotPrintException("当前用户已取号"); + } + + callQueue = BeanUtil.copyProperties(takeNumberDTO, CallQueue.class); + callQueue.setPhone(StrUtil.isBlank(takeNumberDTO.getPhone()) ? shopUser.getPhone() : takeNumberDTO.getPhone()); +// callQueue.setOpenId(shopUser.getMiniOpenId()); + } else { +// if (StrUtil.isBlank(takeNumberDTO.getPhone()) || StrUtil.isBlank(takeNumberDTO.getOpenId())) { +// throw new ApiNotPrintException("手机号或openId不能为空"); +// } + + callQueue = callQueueService.queryChain() + .eq(CallQueue::getPhone, takeNumberDTO.getPhone()) + .eq(CallQueue::getShopId, shopId) + .eq(CallQueue::getCreateDay, DateUtil.today()) + .in(CallQueue::getState, 0, 1) + .ne(CallQueue::getIsPostpone, 2) + .eq(CallQueue::getCallTableId, takeNumberDTO.getCallTableId()).one(); + if (callQueue != null) { + throw new ApiNotPrintException("当前用户已取号"); + } + + callQueue = BeanUtil.copyProperties(takeNumberDTO, CallQueue.class); + callQueue.setPhone(takeNumberDTO.getPhone()); +// callQueue.setOpenId(takeNumberDTO.getOpenId()); + callQueue.setSubState(0); + } + + callQueue.setCreateDay(DateUtil.today()); + callQueue.setCallNum(getCallNumber(shopId, callTable)); + callQueue.setShopId(shopId); + callQueue.setShopName(shopInfo.getShopName()); + + callQueueService.save(callQueue); + + // todo 打印排号票信息 +// rabbitMsgUtils.printCallNumTicket(callQueue.getId(), callQueue.getShopId()); + + return new CallTableNumDTO().setTableName(callTable.getName()).setTableNote(callTable.getNote()) + .setCallNum(callQueue.getCallNum()); + } + + private String getCallNumber(Long shopId, CallTable callTable) { + return FunUtil.runFunAndCheckKey(() -> { + String callNumKey = RedisCst.getTableCallNumKey(shopId, callTable.getId()); + String value = stringRedisTemplate.opsForValue().get(callNumKey); + AtomicReference newVal = new AtomicReference<>(""); + // 初始化 + if (StrUtil.isBlank(value)) { + Boolean setFlag = FunUtil.runFunAndRetry(() -> stringRedisTemplate.opsForValue().setIfAbsent(callNumKey, callTable.getStart().toString()), flag -> !flag, + _ -> newVal.set(stringRedisTemplate.opsForValue().get(callNumKey))); + + if (setFlag) { + return callTable.getPrefix() + callTable.getStart(); + } else if (StrUtil.isNotBlank(newVal.get())) { + value = String.valueOf((Integer.parseInt(newVal.get()) + 1)); + stringRedisTemplate.opsForValue().set(callNumKey, value); + return callTable.getPrefix() + value; + } else { + throw new ApiNotPrintException("生成排队号码失败"); + } + + } else { + value = String.valueOf((Integer.parseInt(value) + 1)); + stringRedisTemplate.opsForValue().set(callNumKey, value); + return callTable.getPrefix() + value; + } + }, stringRedisTemplate, RedisCst.getLockKey("UPDATE_TABLE", shopId, callTable.getId())); + + } + + @Override + public String takeNumberCode(Long shopId, Integer callTableId) { + // 创建二维码配置对象,设置宽度和高度为400 + QrConfig config = new QrConfig(400, 400); + + // 使用字节数组输出流来存储二维码图片 + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + + // 生成二维码图片,输出到字节数组输出流 + CzgResult paramsByCode = sysParamsService.getParamsByCode("call_page_url"); + if (paramsByCode.getData() == null) { + throw new ApiNotPrintException("页面路径未配置"); + } + QrCodeUtil.generate(StrUtil.format(paramsByCode.getData().getParamValue(), shopId, ""), config, "png", outputStream); + + // 将图片转换为 Base64 字符串 + String base64 = Base64.getEncoder().encodeToString(outputStream.toByteArray()); + + // 返回Base64格式的图片字符串 + return "data:image/png;base64," + base64; + } + + @Override + public Integer call(Long shopId, CallQueueDTO callQueueDTO) { + CallQueue callQueue = callQueueService.queryChain() + .notIn(CallQueue::getState, -1, 2) + .eq(CallQueue::getCreateDay, DateUtil.today()) + .eq(CallQueue::getId, callQueueDTO.getCallQueueId()) + .eq(CallQueue::getShopId, shopId) + .one(); + + if (callQueue == null) { + throw new ApiNotPrintException("叫号用户不存在"); + } + + callQueue.setState(1); + callQueue.setCallCount(callQueue.getCallCount() + 1); + callQueueService.updateById(callQueue); + + if (callQueue.getSubState().equals(0)) { + return -1; + } + + // 发送模板消息通知用户 + + ShopInfo shopInfo = shopInfoService.getById(shopId); + if (shopInfo == null) { + throw new ApiNotPrintException("店铺信息不存在"); + } + + List current = callQueueService.queryChain() + .eq(CallQueue::getCallTableId, callQueue.getCallTableId()) + .eq(CallQueue::getCreateDay, DateUtil.today()) + .and(r -> { + r.eq(CallQueue::getState, 1) + .or(r1 -> { + r1.eq(CallQueue::getState, 0); + }); + }) + .orderBy(CallQueue::getCreateTime, true) + .page(new Page<>(1, 1)).getRecords(); + + + if (StrUtil.isBlank(callQueue.getOpenId())) { + return -1; + } + +// wxMiniUtils.sendCurrentOrNearCallMsg(shopInfo.getShopName(), getStrByState(Integer.valueOf(callQueue.getState())), +// callQueue.getCallNum(), current.isEmpty() ? "" : current.get(0).getCallNum(), "排号信息", callQueue.getOpenId(), false); + + CallConfig config = getConfig(shopId); + // 临近用户提醒 + List nearList = callQueueService.queryChain() + .eq(CallQueue::getCallTableId, callQueue.getCallTableId()) + .eq(CallQueue::getCreateDay, DateUtil.today()) + .gt(CallQueue::getId, current.getFirst().getId()) + .page(new Page<>(config.getNearNum(), 1)).getRecords(); + if (!nearList.isEmpty()) { + CallQueue nearQueue = nearList.getFirst(); +// wxMiniUtils.sendCurrentOrNearCallMsg(shopInfo.getShopName(), getStrByState(Integer.valueOf(nearQueue.getState())), +// nearQueue.getCallNum(), current.isEmpty() ? "" : current.get(0).getCallNum(), "排号信息", nearQueue.getOpenId(), true); + } + return 1; + } + + @Override + public boolean updateInfo(Long shopId, UpdateCallQueueDTO updateCallQueueDTO) { + CallQueue callQueue = callQueueService.queryChain() + .eq(CallQueue::getShopId, shopId) + .eq(CallQueue::getCreateDay, DateUtil.today()) + .eq(CallQueue::getId, updateCallQueueDTO.getCallQueueId()).one(); + if (callQueue == null) { + throw new ApiNotPrintException("叫号用户不存在"); + } + + switch (updateCallQueueDTO.getState()) { + case -1: + callQueue.setCancelTime(DateUtil.date().toLocalDateTime()); + break; + case 0: + callQueue.setState(0); + break; + case 1: + if (callQueue.getSubState().equals(0)) { + throw new ApiNotPrintException("当前用户未订阅微信提醒"); + } + callQueue.setState(1); + callQueue.setCallCount(callQueue.getCallCount() + 1); + callQueue.setCallTime(DateUtil.date().toLocalDateTime()); + break; + case 2: + callQueue.setConfirmTime(DateUtil.date().toLocalDateTime()); + break; + case 3: + callQueue.setPassTime(DateUtil.date().toLocalDateTime()); + // 已经顺延 + callQueue.setIsPostpone(callQueue.getIsPostpone() == null ? 1 : callQueue.getIsPostpone() == 0 ? 1 : 2); + ShopInfo shopInfo = shopInfoService.getById(callQueue.getShopId()); + if (shopInfo == null) { + throw new ApiNotPrintException("店铺信息不存在"); + } + + if (StrUtil.isBlank(callQueue.getOpenId()) && callQueue.getSubState() != 1) { + break; + } + + CallTable callTable = getById(callQueue.getCallTableId()); + Integer isPostpone = callTable.getIsPostpone(); + Integer postponeNum = callTable.getPostponeNum(); + + // 判断是否需要顺延, 暂时注释 + if (false && callQueue.getIsPostpone() == 0 && isPostpone != null && isPostpone == 1 && postponeNum != null && postponeNum > 0) { + // 查询当前桌以及顺延桌数 + List current = callQueueService.queryChain() + .eq(CallQueue::getCallTableId, callQueue.getCallTableId()) + .eq(CallQueue::getCreateDay, DateUtil.today()) + .eq(CallQueue::getShopId, callTable.getShopId()) + .ge(CallQueue::getId, callQueue.getId()) + .orderBy(CallQueue::getCreateTime, true) + .page(new Page<>(1, postponeNum + 1)) // 获取当前桌和顺延的桌数 + .getRecords(); + + // 确保有足够的桌可以顺延 + if (current.size() > 1) { + // 获取当前桌以及顺延桌 + CallQueue currentTable = BeanUtil.copyProperties(current.getFirst(), CallQueue.class); + // 顺延替换信息,将每一张顺延桌向前移动 + for (int i = 0; i < current.size() - 1; i++) { + exchangeCallQueueInfo(current.get(i), current.get(i + 1)); // 当前桌替换为顺延桌 + } + + exchangeCallQueueInfo(current.getLast(), currentTable); + callQueue = current.getLast(); + + // 更新数据库中的桌号信息 + callQueueService.updateBatch(current); + } + } + + List current = callQueueService.queryChain() + .eq(CallQueue::getCallTableId, callQueue.getCallTableId()) + .eq(CallQueue::getCreateDay, DateUtil.today()) + .and(r -> { + r.eq(CallQueue::getState, 1) + .or(q -> { + q.eq(CallQueue::getState, 0); + }); + }) + .orderBy(CallQueue::getCreateTime, true) + .page(new Page<>(1, 1)).getRecords(); +// wxMiniUtils.sendPassCallMsg(shopInfo.getShopName(), getStrByState(Integer.valueOf(updateCallQueueDTO.getState())), +// callQueue.getCallNum(), current.isEmpty() ? "" : current.get(0).getCallNum(), "即将过号", callQueue.getOpenId()); + break; + default: + throw new ApiNotPrintException("错误类型"); + + } + + callQueue.setState(updateCallQueueDTO.getState()); + + return callQueueService.updateById(callQueue); + } + + private void exchangeCallQueueInfo(CallQueue setCallQueue, CallQueue copyCallQueue) { + setCallQueue.setOpenId(copyCallQueue.getOpenId()); + setCallQueue.setState(copyCallQueue.getState()); + setCallQueue.setSubState(copyCallQueue.getSubState()); + setCallQueue.setCreateTime(copyCallQueue.getCreateTime()); + setCallQueue.setName(copyCallQueue.getName()); + setCallQueue.setNote(copyCallQueue.getNote()); + setCallQueue.setCallNum(copyCallQueue.getCallNum()); + setCallQueue.setCallTime(copyCallQueue.getCallTime()); + setCallQueue.setCallCount(copyCallQueue.getCallCount()); + setCallQueue.setPassTime(copyCallQueue.getPassTime()); + setCallQueue.setCancelTime(copyCallQueue.getCancelTime()); + setCallQueue.setUserId(copyCallQueue.getUserId()); + setCallQueue.setConfirmTime(copyCallQueue.getConfirmTime()); + } + + @Override + public Page getQueue(Long shopId, Long callTableId, Integer state) { + List tableIds; + if (callTableId != null) { + tableIds = Collections.singletonList(callTableId); + } else { + List list = queryChain().eq(CallTable::getShopId, shopId).eq(CallTable::getState, 1).list(); + if (list.isEmpty()) { + return new Page<>(); + } + tableIds = list.stream() + .map(CallTable::getId) + .collect(Collectors.toList()); + } + + QueryWrapper query = callQueueService.queryChain() + .eq(CallQueue::getShopId, shopId) + .eq(CallQueue::getCreateDay, DateUtil.today()) + .in(CallQueue::getCallTableId, tableIds); + if (state != null) { + query.eq(CallQueue::getState, state); + } else { + query.in(CallQueue::getState, 0, 1); + } + + Page pageInfo = callQueueService.page(PageUtil.buildPage(), query + .orderBy(CallQueue::getCreateTime, true) + .orderBy(CallQueue::getState, false)); + + List list1 = pageInfo.getRecords(); + + // 创建返回的结果集 + List resultList = new ArrayList<>(); + + // 遍历每一个叫号中的记录,计算前面状态为"0" (排队中) 的人数 + for (CallQueue calling : list1) { + // 计算前面等待的人数 (状态为"0"且在叫号记录创建时间之前的) + long waitingCount = 0; + if (calling.getState() == 0) { + waitingCount = list1.stream() + .filter(item -> item.getState() == 0 || item.getState() == 1) // 过滤出状态为"排队中"的 + .filter(item -> item.getCreateTime().isBefore(calling.getCreateTime())) // 时间在当前叫号之前 + .count(); + } + + // 创建一个Map来保存叫号中的记录及其前面排队的人数 + CallQueueListDTO callQueueListDTO = BeanUtil.copyProperties(calling, CallQueueListDTO.class); + callQueueListDTO.setWaitingCount(waitingCount); + // 将该map加入结果集 + resultList.add(callQueueListDTO); + } + + pageInfo.setRecords(resultList); + // 返回结果列表 + return pageInfo; + } + + @Override + public Page getCallRecord(Long shopId, Integer callTableId) { + QueryWrapper queryWrapper = new JoinQueryWrapper().eq(CallQueue::getShopId, shopId).in(CallQueue::getState, 3, 2, 1).orderBy(CallQueue::getCreateTime, false); + if (callTableId != null) { + queryWrapper.eq(CallQueue::getCallTableId, callTableId); + } + return callQueueMapper.xmlPaginate("selectCallRecord", PageUtil.buildPage(), queryWrapper); + } + + @Override + public CallConfig getConfig(Long shopId) { + CallConfig config = callConfigService.queryChain().eq(CallConfig::getShopId, shopId).one(); + if (config == null) { + config = new CallConfig(); + config.setShopId(shopId); + callConfigService.save(config); + config = callConfigService.queryChain().eq(CallConfig::getShopId, shopId).one(); + } + + return config; + } + + @Override + public boolean updateConfig(Long shopId, UpdateConfigDTO configDTO) { + CallConfig config = callConfigService.queryChain().eq(CallConfig::getShopId, shopId).one(); + if (config == null) { + throw new ApiNotPrintException("未查询到配置信息"); + } + CallConfig tbCallConfig = BeanUtil.copyProperties(configDTO, CallConfig.class); + tbCallConfig.setId(config.getId()); + return callConfigService.updateById(tbCallConfig); + } +} diff --git a/cash-service/account-service/src/main/java/com/czg/service/account/service/impl/ShopUserServiceImpl.java b/cash-service/account-service/src/main/java/com/czg/service/account/service/impl/ShopUserServiceImpl.java index 9f127f56..42d2325c 100644 --- a/cash-service/account-service/src/main/java/com/czg/service/account/service/impl/ShopUserServiceImpl.java +++ b/cash-service/account-service/src/main/java/com/czg/service/account/service/impl/ShopUserServiceImpl.java @@ -65,7 +65,7 @@ public class ShopUserServiceImpl extends ServiceImpl i }); }); -// queryWrapper.and(JoinQueryWrapper.column(UserInfo::getNickName).like(key).or(JoinQueryWrapper.column(UserInfo::getPhone).like(key))); + queryWrapper.and(column(UserInfo::getNickName).like(key).or(column(UserInfo::getPhone).like(key))); } if (isVip != null) { diff --git a/cash-service/account-service/src/main/java/com/czg/service/account/util/FunUtil.java b/cash-service/account-service/src/main/java/com/czg/service/account/util/FunUtil.java new file mode 100644 index 00000000..80a8670b --- /dev/null +++ b/cash-service/account-service/src/main/java/com/czg/service/account/util/FunUtil.java @@ -0,0 +1,64 @@ +package com.czg.service.account.util; + +import com.czg.exception.ApiNotPrintException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.core.StringRedisTemplate; + +import java.util.UUID; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; + +/** + * @author Administrator + */ +@Slf4j +public class FunUtil { + public static int retryCount = 5; + + public static T runFunAndCheckKey(Supplier supplier, StringRedisTemplate redisTemplate, String lockKey) { + try{ + // 设置分布式锁 + boolean lock = Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 30, TimeUnit.MILLISECONDS)); + int count = 0; + while (!lock) { + if (count++ > 100) { + throw new ApiNotPrintException("系统繁忙, 稍后再试"); + } + Thread.sleep(20); + lock = Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 30, TimeUnit.MILLISECONDS)); + } + return supplier.get(); + } catch (RuntimeException e){ + log.info("执行出错:{}", e.getMessage()); + throw e; + } catch (InterruptedException e) { + throw new RuntimeException(e); + } finally{ + redisTemplate.delete(lockKey); + } + } + + public static R runFunAndRetry( + Supplier function, + Function check, Consumer errFun) { + log.info("工具类开始执行函数"); + R result = function.get(); + boolean flag = check.apply(result); + + log.info("执行结果: {}", result); + + while (flag && retryCount-- > 0) { + log.info("执行函数失败, 剩余尝试次数{}", retryCount); + result = function.get(); + log.info("执行结果: {}", result); + flag = check.apply(result); + } + + if (flag) { + errFun.accept(result); + } + return result; + } +} diff --git a/cash-service/account-service/src/main/resources/mapper/CallConfigMapper.xml b/cash-service/account-service/src/main/resources/mapper/CallConfigMapper.xml new file mode 100644 index 00000000..23f88a9d --- /dev/null +++ b/cash-service/account-service/src/main/resources/mapper/CallConfigMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/cash-service/account-service/src/main/resources/mapper/CallQueueMapper.xml b/cash-service/account-service/src/main/resources/mapper/CallQueueMapper.xml new file mode 100644 index 00000000..e0caf88e --- /dev/null +++ b/cash-service/account-service/src/main/resources/mapper/CallQueueMapper.xml @@ -0,0 +1,20 @@ + + + + + + + diff --git a/cash-service/account-service/src/main/resources/mapper/CallTableMapper.xml b/cash-service/account-service/src/main/resources/mapper/CallTableMapper.xml new file mode 100644 index 00000000..1d14872a --- /dev/null +++ b/cash-service/account-service/src/main/resources/mapper/CallTableMapper.xml @@ -0,0 +1,7 @@ + + + + +