diff --git a/cash-api/market-server/src/main/java/com/czg/controller/admin/PpPackageController.java b/cash-api/market-server/src/main/java/com/czg/controller/admin/PpPackageController.java new file mode 100644 index 000000000..423311d84 --- /dev/null +++ b/cash-api/market-server/src/main/java/com/czg/controller/admin/PpPackageController.java @@ -0,0 +1,99 @@ +package com.czg.controller.admin; + +import com.alibaba.fastjson2.JSONObject; +import com.czg.annotation.SaAdminCheckPermission; +import com.czg.market.service.PpPackageService; +import com.czg.market.vo.PpPackagePageReqVo; +import com.czg.market.vo.PpPackageVO; +import com.czg.resp.CzgResult; +import com.czg.utils.AssertUtil; +import com.mybatisflex.core.paginate.Page; +import jakarta.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +/** + * 管理端/套餐推广 + * + * @author yjjie + * @date 2025/12/18 11:18 + */ +@RestController +@RequestMapping("/admin/package") +public class PpPackageController { + + @Resource + private PpPackageService ppPackageService; + + /** + * 添加套餐 + */ + @PostMapping + @SaAdminCheckPermission(parentName = "套餐推广", value = "points:package:add", name = "添加套餐") + public CzgResult addPackage(@RequestBody @Validated PpPackageVO packageVO) { + ppPackageService.insertPackage(packageVO); + return CzgResult.success(); + } + + /** + * 修改套餐 + */ + @PutMapping + @SaAdminCheckPermission(parentName = "套餐推广", value = "points:package:update", name = "修改套餐") + public CzgResult updatePackage(@RequestBody @Validated PpPackageVO packageVO) { + ppPackageService.updatePackage(packageVO); + return CzgResult.success(); + } + + /** + * 删除套餐 + * 如果返回值大于0则删除失败,存在进行中的订单,请继续调用确认删除套餐接口 + */ + @DeleteMapping("/{id}") + @SaAdminCheckPermission(parentName = "套餐推广", value = "points:package:delete", name = "删除套餐") + public CzgResult deletePackage(@PathVariable Long id) { + return CzgResult.success(ppPackageService.deletePackage(id)); + } + + /** + * 确认删除套餐 + */ + @DeleteMapping("/sure/{id}") + @SaAdminCheckPermission(parentName = "套餐推广", value = "points:package:sureDelete", name = "确认删除套餐") + public CzgResult sureDeletePackage(@PathVariable Long id) { + ppPackageService.sureDeletePackage(id); + return CzgResult.success(); + } + + /** + * 获取套餐列表 + */ + @GetMapping + public CzgResult> getPackageList(PpPackagePageReqVo reqVo) { + return CzgResult.success(ppPackageService.getPackagePage(reqVo, true)); + } + + /** + * 获取套餐推广开关 + * 0: 关闭 1: 开启 + */ + @GetMapping("/switch") + @SaAdminCheckPermission(parentName = "套餐推广", value = "points:package:getSwitch", name = "获取套餐推广开关") + public CzgResult getPackagePromotionSwitch() { + return CzgResult.success(ppPackageService.getPackagePromotionSwitch()); + } + + /** + * 修改套餐推广开关 + * 0: 关闭 1: 开启 + * 参数 key = "status" + */ + @PutMapping("/switch") + @SaAdminCheckPermission(parentName = "套餐推广", value = "points:package:updateSwitch", name = "修改套餐推广开关") + public CzgResult updatePackagePromotionSwitch(@RequestBody JSONObject param) { + AssertUtil.isNull(param, "参数错误"); + Integer status = param.getInteger("status"); + AssertUtil.isNull(status, "参数错误"); + return CzgResult.success(ppPackageService.updatePackagePromotionSwitch(status)); + } +} diff --git a/cash-common/cash-common-service/src/main/java/com/czg/account/entity/ShopConfig.java b/cash-common/cash-common-service/src/main/java/com/czg/account/entity/ShopConfig.java index 4774614d0..2921c827d 100644 --- a/cash-common/cash-common-service/src/main/java/com/czg/account/entity/ShopConfig.java +++ b/cash-common/cash-common-service/src/main/java/com/czg/account/entity/ShopConfig.java @@ -123,6 +123,10 @@ public class ShopConfig implements Serializable { * 拼团开关 1-是 0-否 */ private Integer isGroupBuy; + /** + * 套餐推广 开关 + */ + private Integer isPackagePromotion; private String dingAppKey; diff --git a/cash-common/cash-common-service/src/main/java/com/czg/constants/PpPackageConstants.java b/cash-common/cash-common-service/src/main/java/com/czg/constants/PpPackageConstants.java new file mode 100644 index 000000000..349b24971 --- /dev/null +++ b/cash-common/cash-common-service/src/main/java/com/czg/constants/PpPackageConstants.java @@ -0,0 +1,49 @@ +package com.czg.constants; + +/** + * @author yjjie + * @date 2025/12/18 11:37 + */ +public interface PpPackageConstants { + + /** + * 订单状态 + * ing进行中, wait_verify 待核销,finish 已核销,refunding 退款中,refund 已退款,cancel 已取消,timeout 超时 + */ + class OrderStatus { + /** + * 进行中 + */ + public static final String PROCESSING = "ing"; + + /** + * 待核销 + */ + public static final String WAIT_VERIFY = "wait_verify"; + + /** + * 已核销 + */ + public static final String FINISH = "finish"; + + /** + * 退款中 + */ + public static final String REFUNDING = "refunding"; + + /** + * 已退款 + */ + public static final String REFUND = "refund"; + + /** + * 已取消 + */ + public static final String CANCEL = "cancel"; + + /** + * 超时 + */ + public static final String TIMEOUT = "timeout"; + } +} diff --git a/cash-common/cash-common-service/src/main/java/com/czg/constants/SystemConstants.java b/cash-common/cash-common-service/src/main/java/com/czg/constants/SystemConstants.java new file mode 100644 index 000000000..b06dff91a --- /dev/null +++ b/cash-common/cash-common-service/src/main/java/com/czg/constants/SystemConstants.java @@ -0,0 +1,46 @@ +package com.czg.constants; + +/** + * 系统常量 + * @author yjjie + * @date 2025/12/18 13:45 + */ +public interface SystemConstants { + + /** + * 状态 1 0 + * 是否 1 0 + */ + class OneZero { + /** + * 是否:是 + * 状态:允许,开启 + */ + public static final Integer ONE = 1; + /** + * 是否:否 + * 状态:进制,关闭 + */ + public static final Integer ZERO = 0; + } + + /** + * 分店类型 + */ + class SubShopType { + /** + * 全部 + */ + public static final String ALL = "all"; + + /** + * 仅本店 + */ + public static final String ONLY = "only"; + + /** + * 自定义 + */ + public static final String CUSTOM = "custom"; + } +} diff --git a/cash-common/cash-common-service/src/main/java/com/czg/market/dto/PpHelpRecordDTO.java b/cash-common/cash-common-service/src/main/java/com/czg/market/dto/PpHelpRecordDTO.java new file mode 100644 index 000000000..822902745 --- /dev/null +++ b/cash-common/cash-common-service/src/main/java/com/czg/market/dto/PpHelpRecordDTO.java @@ -0,0 +1,51 @@ + +package com.czg.market.dto; + +import java.io.Serializable; +import lombok.experimental.Accessors; +import java.io.Serial; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 套餐推广助力记录 实体类。 + * + * @author gyj + * @since 2025-12-18 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Accessors(chain = true) +public class PpHelpRecordDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 自增主键 + */ + private Long id; + + /** + * 订单 Id + */ + private Long orderId; + + /** + * 用户 Id + */ + private Long userId; + + /** + * 用户头像 + */ + private String userName; + + /** + * 用户头像 + */ + private String userAvator; + +} diff --git a/cash-common/cash-common-service/src/main/java/com/czg/market/dto/PpPackageOrderDTO.java b/cash-common/cash-common-service/src/main/java/com/czg/market/dto/PpPackageOrderDTO.java new file mode 100644 index 000000000..73d3ad9b8 --- /dev/null +++ b/cash-common/cash-common-service/src/main/java/com/czg/market/dto/PpPackageOrderDTO.java @@ -0,0 +1,114 @@ + +package com.czg.market.dto; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import com.alibaba.fastjson2.annotation.JSONField; +import lombok.experimental.Accessors; +import java.io.Serial; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 套餐推广订单 实体类。 + * + * @author gyj + * @since 2025-12-18 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Accessors(chain = true) +public class PpPackageOrderDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 自增主键 + */ + private Long id; + + /** + * 店铺 Id + */ + private Long shopId; + + /** + * 订单编号 + */ + private String orderNo; + + /** + * 套餐 Id + */ + private Long packageId; + + /** + * 用户 Id + */ + private Long userId; + + /** + * 分享人数 + */ + private Integer shareNum; + + /** + * 最终支付金额 + */ + private BigDecimal finalPrice; + + /** + * 订单状态:ing进行中, wait_verify 待核销,finish 已核销,refunding 退款中,refund 已退款,cancel 已取消,timeout 超时 + */ + private String status; + + /** + * 支付时间 + */ + @JSONField(format = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime payTime; + + /** + * 支付订单 Id + */ + private Long payOrderId; + + /** + * 核销码 + */ + private String verifyCode; + + /** + * 核销时间 + */ + @JSONField(format = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime verifyTime; + + /** + * 取消时间 + */ + @JSONField(format = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime cancelTime; + + /** + * 取消原因 + */ + private String cancelReason; + + /** + * 创建时间 + */ + @JSONField(format = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + /** + * 更新时间 + */ + @JSONField(format = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/cash-common/cash-common-service/src/main/java/com/czg/market/entity/PpHelpRecord.java b/cash-common/cash-common-service/src/main/java/com/czg/market/entity/PpHelpRecord.java new file mode 100644 index 000000000..6c0fd3c51 --- /dev/null +++ b/cash-common/cash-common-service/src/main/java/com/czg/market/entity/PpHelpRecord.java @@ -0,0 +1,57 @@ +package com.czg.market.entity; + +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import com.mybatisflex.annotation.Table; +import java.io.Serializable; + +import java.io.Serial; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 套餐推广助力记录 实体类。 + * + * @author gyj + * @since 2025-12-18 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Table("pp_help_record") +public class PpHelpRecord implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 自增主键 + */ + @Id(keyType = KeyType.Auto) + private Long id; + + /** + * 订单 Id + */ + private Long orderId; + + /** + * 用户 Id + */ + private Long userId; + + /** + * 用户头像 + */ + private String userName; + + /** + * 用户头像 + */ + private String userAvator; + +} diff --git a/cash-common/cash-common-service/src/main/java/com/czg/market/entity/PpPackage.java b/cash-common/cash-common-service/src/main/java/com/czg/market/entity/PpPackage.java new file mode 100644 index 000000000..238c14558 --- /dev/null +++ b/cash-common/cash-common-service/src/main/java/com/czg/market/entity/PpPackage.java @@ -0,0 +1,138 @@ +package com.czg.market.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.math.BigDecimal; +import java.time.LocalDateTime; + +import java.io.Serial; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 套餐推广套餐 实体类。 + * + * @author gyj + * @since 2025-12-18 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Table("pp_package") +public class PpPackage implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 自增主键 + */ + @Id(keyType = KeyType.Auto) + private Long id; + + /** + * 店铺ID + */ + private Long shopId; + + /** + * only-仅本店 all全部 /custom 指定 + * {@link com.czg.constants.SystemConstants.SubShopType} + */ + private String useShopType; + + /** + * 可用门店(指定门店时存储门店ID,逗号分隔) + */ + private String useShops; + + /** + * 套餐名称 + */ + private String packageName; + + /** + * 套餐描述 + */ + private String description; + + /** + * 套餐图片 + */ + private String images; + + /** + * 套餐原价 + */ + private BigDecimal originPrice; + + /** + * 销售价格 + */ + private BigDecimal price; + + /** + * 套餐内容 json + */ + private String packageContent; + + /** + * 可用时段:08:00~21:30 + */ + private String useTimes; + + /** + * 可用周期: [周一,周二] + */ + private String useWeeks; + + /** + * 其他使用描述 + */ + private String otherDesc; + + /** + * 阶梯优惠 + */ + private String tieredDiscount; + + /** + * 分享期限(小时) + */ + private Integer expireHours; + + /** + * 上线状态 + */ + private Integer onlineStatus; + + /** + * 商品详情图片 + */ + private String detailImages; + + /** + * 创建时间 + */ + @Column(onInsertValue = "now()") + private LocalDateTime createTime; + + /** + * 更新时间 + */ + @Column(onInsertValue = "now()", onUpdateValue = "now()") + private LocalDateTime updateTime; + + /** + * 0否1是 + */ + private Integer isDel; + +} diff --git a/cash-common/cash-common-service/src/main/java/com/czg/market/entity/PpPackageOrder.java b/cash-common/cash-common-service/src/main/java/com/czg/market/entity/PpPackageOrder.java new file mode 100644 index 000000000..ff1c05918 --- /dev/null +++ b/cash-common/cash-common-service/src/main/java/com/czg/market/entity/PpPackageOrder.java @@ -0,0 +1,120 @@ +package com.czg.market.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.math.BigDecimal; +import java.time.LocalDateTime; + +import java.io.Serial; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +/** + * 套餐推广订单 实体类。 + * + * @author gyj + * @since 2025-12-18 + */ +@Data +@Builder +@Accessors(chain = true) +@NoArgsConstructor +@AllArgsConstructor +@Table("pp_package_order") +public class PpPackageOrder implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 自增主键 + */ + @Id(keyType = KeyType.Auto) + private Long id; + + /** + * 店铺 Id + */ + private Long shopId; + + /** + * 订单编号 + */ + private String orderNo; + + /** + * 套餐 Id + */ + private Long packageId; + + /** + * 用户 Id + */ + private Long userId; + + /** + * 分享人数 + */ + private Integer shareNum; + + /** + * 最终支付金额 + */ + private BigDecimal finalPrice; + + /** + * 订单状态:ing进行中, wait_verify 待核销,finish 已核销,refunding 退款中,refund 已退款,cancel 已取消,timeout 超时 + * {@link com.czg.constants.PpPackageConstants.OrderStatus} + */ + private String status; + + /** + * 支付时间 + */ + private LocalDateTime payTime; + + /** + * 支付订单 Id + */ + private Long payOrderId; + + /** + * 核销码 + */ + private String verifyCode; + + /** + * 核销时间 + */ + private LocalDateTime verifyTime; + + /** + * 取消时间 + */ + private LocalDateTime cancelTime; + + /** + * 取消原因 + */ + private String cancelReason; + + /** + * 创建时间 + */ + @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/market/service/PpHelpRecordService.java b/cash-common/cash-common-service/src/main/java/com/czg/market/service/PpHelpRecordService.java new file mode 100644 index 000000000..0e66d43cc --- /dev/null +++ b/cash-common/cash-common-service/src/main/java/com/czg/market/service/PpHelpRecordService.java @@ -0,0 +1,14 @@ +package com.czg.market.service; + +import com.mybatisflex.core.service.IService; +import com.czg.market.entity.PpHelpRecord; + +/** + * 套餐推广助力记录 服务层。 + * + * @author gyj + * @since 2025-12-18 + */ +public interface PpHelpRecordService extends IService { + +} diff --git a/cash-common/cash-common-service/src/main/java/com/czg/market/service/PpPackageOrderService.java b/cash-common/cash-common-service/src/main/java/com/czg/market/service/PpPackageOrderService.java new file mode 100644 index 000000000..f87510df8 --- /dev/null +++ b/cash-common/cash-common-service/src/main/java/com/czg/market/service/PpPackageOrderService.java @@ -0,0 +1,28 @@ +package com.czg.market.service; + +import com.mybatisflex.core.service.IService; +import com.czg.market.entity.PpPackageOrder; + +/** + * 套餐推广订单 服务层。 + * + * @author gyj + * @since 2025-12-18 + */ +public interface PpPackageOrderService extends IService { + + /** + * 创建推广订单 + */ + Long createPackageOrder(Long packageId); + + /** + * 获取进行中的套餐推广订单数量 + */ + long getProgressingPackageOrderCount(Long packageId); + + /** + * 将所有正在进行的推广订单设置为取消 + */ + void cancelProgressingPackageOrder(Long shopId, Long packageId); +} diff --git a/cash-common/cash-common-service/src/main/java/com/czg/market/service/PpPackageService.java b/cash-common/cash-common-service/src/main/java/com/czg/market/service/PpPackageService.java new file mode 100644 index 000000000..047486c02 --- /dev/null +++ b/cash-common/cash-common-service/src/main/java/com/czg/market/service/PpPackageService.java @@ -0,0 +1,51 @@ +package com.czg.market.service; + +import com.czg.market.vo.PpPackagePageReqVo; +import com.czg.market.vo.PpPackageVO; +import com.mybatisflex.core.paginate.Page; +import com.mybatisflex.core.service.IService; +import com.czg.market.entity.PpPackage; + +/** + * 套餐推广套餐 服务层。 + * + * @author gyj + * @since 2025-12-18 + */ +public interface PpPackageService extends IService { + + /** + * 获取套餐推广开关 + */ + Integer getPackagePromotionSwitch(); + + /** + * 更新套餐开关 + */ + boolean updatePackagePromotionSwitch(Integer status); + + /** + * 插入套餐 + */ + void insertPackage(PpPackageVO packageVO); + + /** + * 更新套餐 + */ + void updatePackage(PpPackageVO packageVO); + + /** + * 删除套餐 + */ + long deletePackage(Long id); + + /** + * 确认删除套餐 + */ + void sureDeletePackage(Long id); + + /** + * 获取套餐分页 + */ + Page getPackagePage(PpPackagePageReqVo reqVo, boolean isAdmin); +} diff --git a/cash-common/cash-common-service/src/main/java/com/czg/market/vo/PpPackagePageReqVo.java b/cash-common/cash-common-service/src/main/java/com/czg/market/vo/PpPackagePageReqVo.java new file mode 100644 index 000000000..7f64ce3d6 --- /dev/null +++ b/cash-common/cash-common-service/src/main/java/com/czg/market/vo/PpPackagePageReqVo.java @@ -0,0 +1,23 @@ +package com.czg.market.vo; + +import com.czg.BaseQueryParam; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * @author yjjie + * @date 2025/12/18 11:25 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class PpPackagePageReqVo extends BaseQueryParam { + /** + * 上架状态 + */ + private Integer onlineStatus; + + /** + * 套餐名称 + */ + private String packageName; +} diff --git a/cash-common/cash-common-service/src/main/java/com/czg/market/vo/PpPackageVO.java b/cash-common/cash-common-service/src/main/java/com/czg/market/vo/PpPackageVO.java new file mode 100644 index 000000000..d71db84ec --- /dev/null +++ b/cash-common/cash-common-service/src/main/java/com/czg/market/vo/PpPackageVO.java @@ -0,0 +1,176 @@ +package com.czg.market.vo; + +import com.alibaba.fastjson2.annotation.JSONField; +import com.czg.validator.group.InsertGroup; +import com.czg.validator.group.UpdateGroup; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +/** + * @author yjjie + * @date 2025/12/18 10:22 + */ +@Data +public class PpPackageVO { + + @Data + public static class TieredDiscount { + /** + * 人数 + */ + private Integer peopleNum; + + /** + * 价格 + */ + private BigDecimal price; + } + + @Data + public static class PackageContent { + /** + * 名称 + */ + private String name; + + /** + * 选择数量 + */ + private Integer num; + + /** + * 商品内容 + */ + private List packageProducts; + } + + + @Data + public static class PackageProduct { + /** + * 名称 + */ + private String name; + + /** + * 价格 + */ + private BigDecimal price; + + /** + * 数量 + */ + private Integer num; + } + + + /** + * 自增主键 + */ + @NotNull(message = "id不能为空", groups = {UpdateGroup.class}) + private Long id; + + /** + * 店铺ID + */ + private Long shopId; + + /** + * 可用门店:only-仅本店 all全部 /custom 指定 + * {@link com.czg.constants.SystemConstants.SubShopType} + */ + @NotBlank(message = "可用门店不能为空", groups = {UpdateGroup.class, InsertGroup.class}) + private String useShopType; + + /** + * 可用门店(指定门店时存储门店ID,逗号分隔) + */ + private String useShops; + + /** + * 套餐名称 + */ + @NotBlank(message = "套餐名称不能为空", groups = {UpdateGroup.class, InsertGroup.class}) + private String packageName; + + /** + * 套餐描述 + */ + private String description; + + /** + * 套餐图片 + */ + @NotNull(message = "套餐图片不能为空", groups = {UpdateGroup.class, InsertGroup.class}) + private List images; + + /** + * 套餐原价 + */ + @NotNull(message = "套餐原价不能为空", groups = {UpdateGroup.class, InsertGroup.class}) + private BigDecimal originPrice; + + /** + * 销售价格 + */ + @NotNull(message = "销售价格不能为空", groups = {UpdateGroup.class, InsertGroup.class}) + private BigDecimal price; + + /** + * 套餐内容 json + */ + @NotNull(message = "套餐内容不能为空", groups = {UpdateGroup.class, InsertGroup.class}) + private List packageContent; + + /** + * 可用时段:08:00~21:30 + */ + private String useTimes; + + /** + * 可用周期: [周一,周二] + */ + private List useWeeks; + + /** + * 其他使用描述 + */ + private String otherDesc; + + /** + * 阶梯优惠 + */ + private List tieredDiscount; + + /** + * 分享期限(小时) + */ + private Integer expireHours; + + /** + * 上线状态 + */ + private Integer onlineStatus = 1; + + /** + * 商品详情图片 + */ + private String detailImages; + + /** + * 创建时间 + */ + @JSONField(format = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + /** + * 更新时间 + */ + @JSONField(format = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; +} diff --git a/cash-common/cash-common-tools/src/main/java/com/czg/enums/OrderNoPrefixEnum.java b/cash-common/cash-common-tools/src/main/java/com/czg/enums/OrderNoPrefixEnum.java index edf3a82b8..e174ab3a8 100644 --- a/cash-common/cash-common-tools/src/main/java/com/czg/enums/OrderNoPrefixEnum.java +++ b/cash-common/cash-common-tools/src/main/java/com/czg/enums/OrderNoPrefixEnum.java @@ -21,6 +21,7 @@ public enum OrderNoPrefixEnum { GB("GB", "拼团-团单号"), GBO("GBO", "拼团-订单号"), REG("REG", "拼团-退单"), + PPO("PPO", "套餐推广订单号"), ; private final String value; diff --git a/cash-service/market-service/src/main/java/com/czg/service/market/mapper/PpHelpRecordMapper.java b/cash-service/market-service/src/main/java/com/czg/service/market/mapper/PpHelpRecordMapper.java new file mode 100644 index 000000000..fa7d97873 --- /dev/null +++ b/cash-service/market-service/src/main/java/com/czg/service/market/mapper/PpHelpRecordMapper.java @@ -0,0 +1,14 @@ +package com.czg.service.market.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.czg.market.entity.PpHelpRecord; + +/** + * 套餐推广助力记录 映射层。 + * + * @author gyj + * @since 2025-12-18 + */ +public interface PpHelpRecordMapper extends BaseMapper { + +} diff --git a/cash-service/market-service/src/main/java/com/czg/service/market/mapper/PpPackageMapper.java b/cash-service/market-service/src/main/java/com/czg/service/market/mapper/PpPackageMapper.java new file mode 100644 index 000000000..8262cb317 --- /dev/null +++ b/cash-service/market-service/src/main/java/com/czg/service/market/mapper/PpPackageMapper.java @@ -0,0 +1,14 @@ +package com.czg.service.market.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.czg.market.entity.PpPackage; + +/** + * 套餐推广套餐 映射层。 + * + * @author gyj + * @since 2025-12-18 + */ +public interface PpPackageMapper extends BaseMapper { + +} diff --git a/cash-service/market-service/src/main/java/com/czg/service/market/mapper/PpPackageOrderMapper.java b/cash-service/market-service/src/main/java/com/czg/service/market/mapper/PpPackageOrderMapper.java new file mode 100644 index 000000000..394dcf289 --- /dev/null +++ b/cash-service/market-service/src/main/java/com/czg/service/market/mapper/PpPackageOrderMapper.java @@ -0,0 +1,14 @@ +package com.czg.service.market.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.czg.market.entity.PpPackageOrder; + +/** + * 套餐推广订单 映射层。 + * + * @author gyj + * @since 2025-12-18 + */ +public interface PpPackageOrderMapper extends BaseMapper { + +} diff --git a/cash-service/market-service/src/main/java/com/czg/service/market/service/impl/PpHelpRecordServiceImpl.java b/cash-service/market-service/src/main/java/com/czg/service/market/service/impl/PpHelpRecordServiceImpl.java new file mode 100644 index 000000000..3190da1e5 --- /dev/null +++ b/cash-service/market-service/src/main/java/com/czg/service/market/service/impl/PpHelpRecordServiceImpl.java @@ -0,0 +1,18 @@ +package com.czg.service.market.service.impl; + +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.czg.market.entity.PpHelpRecord; +import com.czg.market.service.PpHelpRecordService; +import com.czg.service.market.mapper.PpHelpRecordMapper; +import org.springframework.stereotype.Service; + +/** + * 套餐推广助力记录 服务层实现。 + * + * @author gyj + * @since 2025-12-18 + */ +@Service +public class PpHelpRecordServiceImpl extends ServiceImpl implements PpHelpRecordService{ + +} diff --git a/cash-service/market-service/src/main/java/com/czg/service/market/service/impl/PpPackageOrderServiceImpl.java b/cash-service/market-service/src/main/java/com/czg/service/market/service/impl/PpPackageOrderServiceImpl.java new file mode 100644 index 000000000..edec1cc5b --- /dev/null +++ b/cash-service/market-service/src/main/java/com/czg/service/market/service/impl/PpPackageOrderServiceImpl.java @@ -0,0 +1,78 @@ +package com.czg.service.market.service.impl; + +import com.czg.constants.PpPackageConstants; +import com.czg.constants.SystemConstants; +import com.czg.enums.OrderNoPrefixEnum; +import com.czg.exception.CzgException; +import com.czg.market.entity.PpPackage; +import com.czg.market.entity.PpPackageOrder; +import com.czg.market.service.PpPackageOrderService; +import com.czg.sa.StpKit; +import com.czg.service.market.mapper.PpPackageMapper; +import com.czg.service.market.mapper.PpPackageOrderMapper; +import com.czg.utils.CzgRandomUtils; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.core.update.UpdateChain; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; + +/** + * 套餐推广订单 服务层实现。 + * + * @author gyj + * @since 2025-12-18 + */ +@Service +public class PpPackageOrderServiceImpl extends ServiceImpl implements PpPackageOrderService { + + @Resource + private PpPackageMapper ppPackageMapper; + + @Override + public Long createPackageOrder(Long packageId) { + PpPackage aPackage = ppPackageMapper.selectOneByQuery(QueryWrapper.create().eq(PpPackage::getId, packageId) + .eq(PpPackage::getIsDel, SystemConstants.OneZero.ZERO)); + if (aPackage == null) { + throw new CzgException("套餐不存在"); + } + + if (!aPackage.getOnlineStatus().equals(SystemConstants.OneZero.ONE)) { + throw new CzgException("套餐已下架"); + } + + PpPackageOrder order = new PpPackageOrder() + .setShopId(aPackage.getShopId()) + .setPackageId(packageId) + .setUserId(StpKit.USER.getLoginIdAsLong()) + .setShareNum(0) + .setOrderNo(CzgRandomUtils.randomNumber(OrderNoPrefixEnum.PPO, 12, false)) + .setStatus(PpPackageConstants.OrderStatus.PROCESSING); + save(order); + + return order.getId(); + } + + @Override + public long getProgressingPackageOrderCount(Long packageId) { + QueryWrapper wrapper = QueryWrapper.create().eq(PpPackageOrder::getPackageId, packageId) + .eq(PpPackageOrder::getStatus, PpPackageConstants.OrderStatus.PROCESSING); + return count(wrapper); + } + + @Override + public void cancelProgressingPackageOrder(Long shopId, Long packageId) { + UpdateChain update = UpdateChain.of(PpPackageOrder.class) + .set(PpPackageOrder::getStatus, PpPackageConstants.OrderStatus.CANCEL) + .set(PpPackageOrder::getCancelTime, LocalDateTime.now()) + .set(PpPackageOrder::getCancelReason, "商家下架套餐"); + if (packageId != null && packageId > 0L) { + update.eq(PpPackageOrder::getPackageId, packageId); + } + update.eq(PpPackageOrder::getShopId, shopId) + .eq(PpPackageOrder::getStatus, PpPackageConstants.OrderStatus.PROCESSING) + .update(); + } +} diff --git a/cash-service/market-service/src/main/java/com/czg/service/market/service/impl/PpPackageServiceImpl.java b/cash-service/market-service/src/main/java/com/czg/service/market/service/impl/PpPackageServiceImpl.java new file mode 100644 index 000000000..69534ec71 --- /dev/null +++ b/cash-service/market-service/src/main/java/com/czg/service/market/service/impl/PpPackageServiceImpl.java @@ -0,0 +1,201 @@ +package com.czg.service.market.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; +import com.czg.account.entity.ShopConfig; +import com.czg.account.service.ShopConfigService; +import com.czg.account.service.ShopInfoService; +import com.czg.constants.SystemConstants; +import com.czg.exception.CzgException; +import com.czg.market.entity.PpPackage; +import com.czg.market.service.PpPackageOrderService; +import com.czg.market.service.PpPackageService; +import com.czg.market.vo.PpPackagePageReqVo; +import com.czg.market.vo.PpPackageVO; +import com.czg.sa.StpKit; +import com.czg.service.market.mapper.PpPackageMapper; +import com.czg.utils.AssertUtil; +import com.mybatisflex.core.paginate.Page; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.core.update.UpdateChain; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.apache.dubbo.config.annotation.DubboReference; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; + +/** + * 套餐推广套餐 服务层实现。 + * + * @author gyj + * @since 2025-12-18 + */ +@Service +public class PpPackageServiceImpl extends ServiceImpl implements PpPackageService { + + @Resource + private PpPackageOrderService ppPackageOrderService; + + @DubboReference + private ShopInfoService shopInfoService; + + @DubboReference + private ShopConfigService shopConfigService; + + @Override + public Integer getPackagePromotionSwitch() { + return shopConfigService.getById(StpKit.USER.getShopId()).getIsPackagePromotion(); + } + + @Override + @Transactional + public boolean updatePackagePromotionSwitch(Integer status) { + Long shopId = StpKit.USER.getShopId(); + ShopConfig shopConfig = new ShopConfig(); + shopConfig.setIsPackagePromotion(status); + boolean update = shopConfigService.update(shopConfig, query().eq(ShopConfig::getId, shopId)); + if (update && status == 0) { + // 下架所有进行中的套餐订单 + UpdateChain.of(PpPackage.class) + .set(PpPackage::getOnlineStatus, SystemConstants.OneZero.ZERO) + .eq(PpPackage::getShopId, shopId) + .update(); + + ppPackageOrderService.cancelProgressingPackageOrder(StpKit.USER.getShopId(), 0L); + } + return update; + } + + @Override + public void insertPackage(PpPackageVO packageVO) { + if (SystemConstants.SubShopType.CUSTOM.equals(packageVO.getUseShopType())) { + AssertUtil.isBlank(packageVO.getUseShops(), "请配置可用门店"); + } + + Long shopId = StpKit.USER.getShopId(); + // 查询名称是否存在 + PpPackage ppPackage = getOne(QueryWrapper.create().eq(PpPackage::getPackageName, packageVO.getPackageName()) + .eq(PpPackage::getShopId, shopId).eq(PpPackage::getIsDel, SystemConstants.OneZero.ZERO)); + if (ppPackage != null) { + throw new CzgException("名称已存在"); + } + + ppPackage = BeanUtil.copyProperties(packageVO, PpPackage.class); + ppPackage.setShopId(shopId); + ppPackage.setPackageContent(JSONObject.toJSONString(packageVO.getPackageContent())); + ppPackage.setUseWeeks(JSONObject.toJSONString(packageVO.getUseWeeks())); + ppPackage.setTieredDiscount(JSONObject.toJSONString(packageVO.getTieredDiscount())); + + save(ppPackage); + } + + @Override + public void updatePackage(PpPackageVO packageVO) { + if (SystemConstants.SubShopType.CUSTOM.equals(packageVO.getUseShopType())) { + AssertUtil.isBlank(packageVO.getUseShops(), "请配置可用门店"); + } + + Long shopId = StpKit.USER.getShopId(); + + PpPackage ppPackage = getPackageById(packageVO.getId()); + + if (!ppPackage.getShopId().equals(shopId)) { + throw new CzgException("无权限"); + } + + ppPackage = BeanUtil.copyProperties(packageVO, PpPackage.class); + ppPackage.setPackageContent(JSONObject.toJSONString(packageVO.getPackageContent())); + ppPackage.setUseWeeks(JSONObject.toJSONString(packageVO.getUseWeeks())); + ppPackage.setTieredDiscount(JSONObject.toJSONString(packageVO.getTieredDiscount())); + updateById(ppPackage); + } + + @Override + @Transactional + public long deletePackage(Long id) { + Long shopId = StpKit.USER.getShopId(); + + PpPackage ppPackage = getPackageById(id); + + if (!ppPackage.getShopId().equals(shopId)) { + throw new RuntimeException("无权限"); + } + + long orderCount = ppPackageOrderService.getProgressingPackageOrderCount(id); + if (orderCount > 0) { + return orderCount; + } + + ppPackage.setIsDel(1); + updateById(ppPackage); + return 0L; + } + + @Override + @Transactional + public void sureDeletePackage(Long id) { + PpPackage ppPackage = getPackageById(id); + ppPackage.setIsDel(1); + updateById(ppPackage); + + ppPackageOrderService.cancelProgressingPackageOrder(StpKit.USER.getShopId(), id); + } + + @Override + public Page getPackagePage(PpPackagePageReqVo reqVo, boolean isAdmin) { + Long shopId = StpKit.USER.getShopId(); + + // 如果没有开启操作,直接返回空数据 + ShopConfig shopConfig = shopConfigService.getById(shopId); + if (SystemConstants.OneZero.ZERO.equals(shopConfig.getIsPackagePromotion())) { + return new Page<>(); + } + + Long mainShopId = shopInfoService.getMainIdByShopId(shopId); + + QueryWrapper queryWrapper = new QueryWrapper(); + queryWrapper.eq(PpPackage::getIsDel, SystemConstants.OneZero.ZERO) + .eq(PpPackage::getOnlineStatus, reqVo.getOnlineStatus()) + .like(PpPackage::getPackageName, reqVo.getPackageName()) + .orderBy(PpPackage::getCreateTime).desc(); + + queryWrapper.and(q -> { + q.eq(PpPackage::getShopId, shopId).or(q1 -> { + q1.eq(PpPackage::getUseShopType, SystemConstants.SubShopType.ALL).eq(PpPackage::getShopId, mainShopId); + }).or(q2 -> { + q2.eq(PpPackage::getUseShopType, SystemConstants.SubShopType.CUSTOM).and("FIND_IN_SET( " + shopId + ", use_shops ) > 0"); + }); + }); + + Page page = page(Page.of(reqVo.getPage(), reqVo.getSize()), queryWrapper); + + List voList = new ArrayList<>(); + page.getRecords().forEach(item -> { + PpPackageVO packageVO = BeanUtil.copyProperties(item, PpPackageVO.class); + + packageVO.setUseWeeks(JSONArray.parseArray(item.getUseWeeks(), String.class)); + packageVO.setPackageContent(JSONArray.parseArray(item.getPackageContent(), PpPackageVO.PackageContent.class)); + packageVO.setTieredDiscount(JSONArray.parseArray(item.getTieredDiscount(), PpPackageVO.TieredDiscount.class)); + + voList.add(packageVO); + }); + + Page voPage = new Page<>(); + BeanUtil.copyProperties(page, voPage, "records"); + voPage.setRecords(voList); + return voPage; + } + + private PpPackage getPackageById(Long id) { + PpPackage ppPackage = getOne(QueryWrapper.create().eq(PpPackage::getId, id) + .eq(PpPackage::getIsDel, SystemConstants.OneZero.ZERO)); + if (ppPackage == null) { + throw new RuntimeException("套餐不存在"); + } + return ppPackage; + } +} diff --git a/cash-service/market-service/src/main/resources/mapper/PpHelpRecordMapper.xml b/cash-service/market-service/src/main/resources/mapper/PpHelpRecordMapper.xml new file mode 100644 index 000000000..85d907392 --- /dev/null +++ b/cash-service/market-service/src/main/resources/mapper/PpHelpRecordMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/cash-service/market-service/src/main/resources/mapper/PpPackageMapper.xml b/cash-service/market-service/src/main/resources/mapper/PpPackageMapper.xml new file mode 100644 index 000000000..6cc705ebf --- /dev/null +++ b/cash-service/market-service/src/main/resources/mapper/PpPackageMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/cash-service/market-service/src/main/resources/mapper/PpPackageOrderMapper.xml b/cash-service/market-service/src/main/resources/mapper/PpPackageOrderMapper.xml new file mode 100644 index 000000000..693fb3ab4 --- /dev/null +++ b/cash-service/market-service/src/main/resources/mapper/PpPackageOrderMapper.xml @@ -0,0 +1,7 @@ + + + + +