From b9679b6f96bbe8b52ee1d699033d9021d5fe870f Mon Sep 17 00:00:00 2001 From: mitao <2763622819@qq.com> Date: 星期五, 10 一月 2025 18:35:06 +0800 Subject: [PATCH] 1.小鹅通直播课程接口对接 2.商户端直播课程接口 --- ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/dto/XiaoeLiveDto.java | 69 ++ ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/miniapp/AppCourseController.java | 57 + ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/mapper/live/XiaoeLiveRecordMapper.java | 17 ruoyi-modules/ruoyi-goods/src/main/resources/mapper/live/XiaoeLiveAppointmentMapper.xml | 5 ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/vo/XiaoeLiveTeacherVo.java | 23 ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/service/biz/XiaoeLiveService.java | 249 ++++++++ ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/vo/XiaoeCourseGroupVO.java | 20 ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/vo/XiaoeCourseChapterVO.java | 36 + ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/service/live/IXiaoeLiveAppointmentService.java | 22 ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/factory/RemoteGoodsFallbackFactory.java | 5 ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/concole/LiveController.java | 33 + ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/service/biz/XiaoeCourseService.java | 39 + ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/miniapp/AppLiveController.java | 54 + ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/domain/dto/MgtEditShopDto.java | 3 ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/constant/DelayTaskEnum.java | 1 ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/service/impl/live/XiaoeLiveAppointmentServiceImpl.java | 57 + ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/listener/RedisListener.java | 16 ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/domain/vo/MgtShopInfoVo.java | 3 ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/business/MerLiveController.java | 101 +++ ruoyi-modules/ruoyi-goods/src/main/resources/mapper/live/XiaoeLiveRecordMapper.xml | 5 ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/dto/XiaoeCourseQueryDto.java | 45 + ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/mapper/live/XiaoeLiveAppointmentMapper.java | 17 ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/vo/XiaoeLiveVo.java | 109 +++ ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/utils/WeChatSubscribeMessageSender.java | 76 ++ ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/service/RemoteGoodsService.java | 10 ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/poji/shop/Shop.java | 6 ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/service/impl/live/XiaoeLiveRecordServiceImpl.java | 61 + ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/pojo/live/XiaoeLiveRecord.java | 64 ++ ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/vo/XiaoeCourseVO.java | 45 + ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/pojo/live/XiaoeLiveAppointment.java | 63 ++ ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/business/MerCourseController.java | 57 + ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/dto/XiaoeLiveQueryDto.java | 35 + ruoyi-common/ruoyi-common-core/pom.xml | 5 ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/service/live/IXiaoeLiveRecordService.java | 33 + ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/utils/XiaoeUtils.java | 375 ++++++++++++ 35 files changed, 1,816 insertions(+), 0 deletions(-) diff --git a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/constant/DelayTaskEnum.java b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/constant/DelayTaskEnum.java index d22b973..f9781f6 100644 --- a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/constant/DelayTaskEnum.java +++ b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/constant/DelayTaskEnum.java @@ -14,6 +14,7 @@ COUPON_SEND_DELAY_TASK("优惠券延时任务","定时启动优惠券发送"), ACTIVITY_START_TASK("活动延时任务","定时开始任务"), ACTIVITY_END_TASK("活动延时任务","定时结束任务"), + LIVE_APPOINTMENT_TASK("直播预约任务","直播预约任务") ; String name; diff --git a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/poji/shop/Shop.java b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/poji/shop/Shop.java index 11230b8..ed91abb 100644 --- a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/poji/shop/Shop.java +++ b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/poji/shop/Shop.java @@ -292,6 +292,12 @@ @TableField("shop_code") private String shopCode; + /** + * 小鹅通讲师id + */ + @TableField("xiaoe_guest_id") + private String xiaoeUserId; + @Override protected Serializable pkVal() { diff --git a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/factory/RemoteGoodsFallbackFactory.java b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/factory/RemoteGoodsFallbackFactory.java index 8513675..a5e8c61 100644 --- a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/factory/RemoteGoodsFallbackFactory.java +++ b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/factory/RemoteGoodsFallbackFactory.java @@ -80,6 +80,11 @@ public R<List<String>> listGoodsNameByGoodsClass(Long classId) { return R.fail("获取分类商品列表失败:" + throwable.getMessage()); } + + @Override + public R<?> push(Long appointmentId) { + return R.fail("推送小程序订阅消息失败:" + throwable.getMessage()); + } }; } } diff --git a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/service/RemoteGoodsService.java b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/service/RemoteGoodsService.java index b82e6a5..0fca1fe 100644 --- a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/service/RemoteGoodsService.java +++ b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/service/RemoteGoodsService.java @@ -11,6 +11,8 @@ import com.ruoyi.system.api.domain.vo.MerGoodsPriceListVo; import com.ruoyi.system.api.factory.RemoteGoodsFallbackFactory; import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -78,4 +80,12 @@ */ @PostMapping("/goods/listGoodsNameByGoodsClass") public R<List<String>> listGoodsNameByGoodsClass(@RequestBody Long classId); + + /** + * 推送微信小程序订阅消息 + * @param appointmentId + * @return + */ + @GetMapping("/live/push/{appointmentId}") + R<?> push(@PathVariable("appointmentId") Long appointmentId); } diff --git a/ruoyi-common/ruoyi-common-core/pom.xml b/ruoyi-common/ruoyi-common-core/pom.xml index ed4df6a..ad70db5 100644 --- a/ruoyi-common/ruoyi-common-core/pom.xml +++ b/ruoyi-common/ruoyi-common-core/pom.xml @@ -118,6 +118,11 @@ <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> + <dependency> + <groupId>cn.hutool</groupId> + <artifactId>hutool-all</artifactId> + <version>5.8.22</version> + </dependency> </dependencies> diff --git a/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/business/MerCourseController.java b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/business/MerCourseController.java new file mode 100644 index 0000000..8302029 --- /dev/null +++ b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/business/MerCourseController.java @@ -0,0 +1,57 @@ +package com.ruoyi.goods.controller.business; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.ruoyi.common.core.domain.R; +import com.ruoyi.goods.domain.dto.XiaoeCourseQueryDto; +import com.ruoyi.goods.domain.vo.XiaoeCourseChapterVO; +import com.ruoyi.goods.domain.vo.XiaoeCourseVO; +import com.ruoyi.goods.service.biz.XiaoeCourseService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.Valid; +import java.util.List; + +/** + * @author mitao + * @date 2025/1/10 + */ +@Api(tags = {"商户端海恒课程相关接口"}) +@Validated +@RestController +@RequestMapping("/mer/course") +@RequiredArgsConstructor +public class MerCourseController { + private final XiaoeCourseService xiaoeCourseService; + + /** + * 课程列表 + * @param dto + * @return + */ + @ApiOperation("课程列表") + @PostMapping("/page") + public R<Page<XiaoeCourseVO>> page(@Valid @RequestBody XiaoeCourseQueryDto dto) { + return R.ok(xiaoeCourseService.getCoursePageList(dto)); + } + + /** + * 课程章节详情 + * @param id + * @return + */ + @ApiOperation("课程章节详情") + @GetMapping("/detail/{id}") + public R<List<XiaoeCourseChapterVO>> detail(@ApiParam(name = "id",value = "课程id",required = true)@PathVariable("id") String id) { + return R.ok(xiaoeCourseService.getCourseDetail(id)); + } +} diff --git a/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/business/MerLiveController.java b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/business/MerLiveController.java new file mode 100644 index 0000000..2efc448 --- /dev/null +++ b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/business/MerLiveController.java @@ -0,0 +1,101 @@ +package com.ruoyi.goods.controller.business; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.ruoyi.common.core.domain.R; +import com.ruoyi.goods.domain.dto.XiaoeLiveDto; +import com.ruoyi.goods.domain.dto.XiaoeLiveQueryDto; +import com.ruoyi.goods.domain.vo.XiaoeLiveVo; +import com.ruoyi.goods.service.biz.XiaoeLiveService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.Valid; +import java.util.List; + +/** + * @author mitao + * @date 2025/1/9 + */ +@Validated +@RestController +@RequiredArgsConstructor +@Api(tags = "商户端直播相关接口") +@RequestMapping("/mer/live") +public class MerLiveController { + private final XiaoeLiveService xiaoeLiveService; + + /** + * 直播首页分页列表 + * @param dto + * @return + */ + @ApiOperation("直播首页分页列表") + @PostMapping("/page") + public R<Page<XiaoeLiveVo>> page(@Valid @RequestBody XiaoeLiveQueryDto dto) { + return R.ok(xiaoeLiveService.getLivePage(dto)); + } + + /** + * 预约直播 + * @param id + * @return + */ + @ApiOperation("预约") + @GetMapping("/appointment/{id}") + public R<Boolean> appointment(@ApiParam(name = "id",value = "直播id", required = true) @PathVariable("id") String id) { + return R.ok(xiaoeLiveService.appointment(id)); + } + + /** + * 我的直播 + * @param dto + * @return + */ + @ApiOperation("我的直播") + @PostMapping("/mine") + public R<Page<XiaoeLiveVo>> minePage(@Valid @RequestBody XiaoeLiveQueryDto dto) { + return R.ok(xiaoeLiveService.getMineLivePage(dto)); + } + + /** + * 获取当前店铺讲师id列表/创建直播前校验讲师信息 + * @return + */ + @ApiOperation("获取当前店铺讲师id列表/创建直播前校验讲师信息") + @GetMapping("/xiaoe/ids") + public R<List<String>> getShopXiaoeUserIdList() { + return R.ok(xiaoeLiveService.getShopXiaoeUserIdList()); + } + /** + * 创建直播 + * @param dto + * @return + */ + @ApiOperation("创建直播") + @PostMapping("/create") + public R<?> create(@Valid @RequestBody XiaoeLiveDto dto) { + xiaoeLiveService.create(dto,2); + return R.ok(); + } + + /** + * 编辑直播 + * @param dto + * @return + */ + @ApiOperation("编辑直播") + @PutMapping + public R<Boolean> edit(@Valid @RequestBody XiaoeLiveDto dto) { + return R.ok(xiaoeLiveService.edit(dto)); + } +} diff --git a/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/concole/LiveController.java b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/concole/LiveController.java new file mode 100644 index 0000000..73cda39 --- /dev/null +++ b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/concole/LiveController.java @@ -0,0 +1,33 @@ +package com.ruoyi.goods.controller.concole; + +import com.ruoyi.common.core.domain.R; +import com.ruoyi.goods.service.live.IXiaoeLiveAppointmentService; +import com.ruoyi.goods.utils.XiaoeUtils; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author mitao + * @date 2025/1/10 + */ +@RestController +@RequestMapping("/live") +@RequiredArgsConstructor +public class LiveController { + private final XiaoeUtils xiaoeUtils; + private final IXiaoeLiveAppointmentService xiaoeLiveAppointmentService; + + /** + * 推送微信小程序订阅消息 + * @param appointmentId + * @return + */ + @GetMapping("/push/{appointmentId}") + public R<?> push(@PathVariable("appointmentId") Long appointmentId) { + xiaoeLiveAppointmentService.push(appointmentId); + return R.ok(); + } +} diff --git a/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/miniapp/AppCourseController.java b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/miniapp/AppCourseController.java new file mode 100644 index 0000000..aa86dd2 --- /dev/null +++ b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/miniapp/AppCourseController.java @@ -0,0 +1,57 @@ +package com.ruoyi.goods.controller.miniapp; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.ruoyi.common.core.domain.R; +import com.ruoyi.goods.domain.dto.XiaoeCourseQueryDto; +import com.ruoyi.goods.domain.vo.XiaoeCourseChapterVO; +import com.ruoyi.goods.domain.vo.XiaoeCourseVO; +import com.ruoyi.goods.service.biz.XiaoeCourseService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.Valid; +import java.util.List; + +/** + * @author mitao + * @date 2025/1/10 + */ +@Api(tags = {"小程序海恒课程相关接口"}) +@Validated +@RestController +@RequestMapping("/app/course") +@RequiredArgsConstructor +public class AppCourseController { + private final XiaoeCourseService xiaoeCourseService; + + /** + * 课程列表 + * @param dto + * @return + */ + @ApiOperation("课程列表") + @PostMapping("/page") + public R<Page<XiaoeCourseVO>> page(@Valid @RequestBody XiaoeCourseQueryDto dto) { + return R.ok(xiaoeCourseService.getCoursePageList(dto)); + } + + /** + * 课程章节详情 + * @param id + * @return + */ + @ApiOperation("课程章节详情") + @GetMapping("/detail/{id}") + public R<List<XiaoeCourseChapterVO>> detail(@ApiParam(name = "id",value = "课程id",required = true)@PathVariable("id") String id) { + return R.ok(xiaoeCourseService.getCourseDetail(id)); + } +} diff --git a/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/miniapp/AppLiveController.java b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/miniapp/AppLiveController.java new file mode 100644 index 0000000..5c006fb --- /dev/null +++ b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/miniapp/AppLiveController.java @@ -0,0 +1,54 @@ +package com.ruoyi.goods.controller.miniapp; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.ruoyi.common.core.domain.R; +import com.ruoyi.goods.domain.dto.XiaoeLiveQueryDto; +import com.ruoyi.goods.domain.vo.XiaoeLiveVo; +import com.ruoyi.goods.service.biz.XiaoeLiveService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.Valid; + +/** + * @author mitao + * @date 2025/1/10 + */ +@Validated +@RestController +@RequiredArgsConstructor +@Api(tags = "小程序直播相关接口") +@RequestMapping("/app/live") +public class AppLiveController { + private final XiaoeLiveService xiaoeLiveService; + /** + * 直播首页分页列表 + * @param dto + * @return + */ + @ApiOperation("直播首页分页列表") + @PostMapping("/page") + public R<Page<XiaoeLiveVo>> page(@Valid @RequestBody XiaoeLiveQueryDto dto) { + return R.ok(xiaoeLiveService.getLivePage(dto)); + } + + /** + * 预约直播 + * @param id + * @return + */ + @ApiOperation("预约") + @GetMapping("/appointment/{id}") + public R<Boolean> appointment(@ApiParam(name = "id",value = "直播id", required = true) @PathVariable("id") String id) { + return R.ok(xiaoeLiveService.appointment(id)); + } +} diff --git a/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/dto/XiaoeCourseQueryDto.java b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/dto/XiaoeCourseQueryDto.java new file mode 100644 index 0000000..8bae0c9 --- /dev/null +++ b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/dto/XiaoeCourseQueryDto.java @@ -0,0 +1,45 @@ +package com.ruoyi.goods.domain.dto; + +import com.alibaba.fastjson2.annotation.JSONField; +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * @author mitao + * @date 2025/1/9 + */ +@Data +@ApiModel("小鹅通课程列表查询参数") +public class XiaoeCourseQueryDto { + + @ApiModelProperty(value = "课程名字模糊搜索") + @JSONField(name = "search_content") + private String searchContent; + + @ApiModelProperty(value = "课程创建来源") + @JSONField(name = "created_source") + private Integer createdSource; + + @ApiModelProperty("课程分组id数组") + @JSONField(name = "tags") + private List<Integer> tags; + + @ApiModelProperty(value = "当前页") + @JSONField(name = "page_index") + private Integer pageNo; + + @ApiModelProperty("每页条数") + @JSONField(name = "page_size") + private Integer pageSize; + + @ApiModelProperty("排序类型 1:创建时间倒序 2:开始时间升序") + @NotNull(message = "排序类型不能为空") + @JsonIgnore + private Integer sortBy; + +} diff --git a/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/dto/XiaoeLiveDto.java b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/dto/XiaoeLiveDto.java new file mode 100644 index 0000000..c321af8 --- /dev/null +++ b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/dto/XiaoeLiveDto.java @@ -0,0 +1,69 @@ +package com.ruoyi.goods.domain.dto; + +import com.alibaba.fastjson2.annotation.JSONField; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.Max; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +@ApiModel(description = "资源信息") +@Data +public class XiaoeLiveDto { + + @ApiModelProperty(value = "直播id",notes = "添加不传,编辑必传") + @JSONField(name = "id") + private String id; + + @ApiModelProperty(value = "直播标题", required = true, notes = "字符长度必须小于45") + @NotBlank(message = "直播标题不能为空") + @JSONField(name = "title") + private String title; + + @ApiModelProperty(value = "直播简介", notes = "字符长度必须小于256,默认为空") + @NotBlank(message = "直播简介不能为空") + @Max(value = 256, message = "直播简介长度不能超过256") + @JSONField(name = "summary") + private String summary; + + @ApiModelProperty(value = "预设直播开始时间", required = true, notes = "距离当前时间不能超过五年", example = "2023-05-31 18:00:00") + @NotBlank(message = "预设直播开始时间不能为空") + @JSONField(name = "zb_start_at") + private String zbStartAt; + + @ApiModelProperty(value = "预设直播时长,单位:秒", required = true, notes = "距离预设直播开始时间不能超过十年") + @JSONField(name = "zb_stop_at") + private Integer zbStopAt; + + @ApiModelProperty(value = "直播类型", notes = "0-语音,1-录播直播,2-推流直播,默认为0-语音直播") + @NotNull(message = "直播类型不能为空") + @JSONField(name = "alive_type") + private Integer aliveType; + + @ApiModelProperty(value = "直播模式:0-横屏直播,1-竖屏直播(默认为0-横屏直播)", example = "0") + @NotNull(message = "直播模式不能为空") + @JSONField(name = "alive_mode") + private Integer aliveMode; + + @ApiModelProperty(value = "讲师用户id") + @NotBlank(message = "讲师用户id不能为空") + @JSONField(name = "user_id") + private String userId; + + @ApiModelProperty(value = "支付类型:1-免费,3-加密,仅当goods_info.sale_type=2时才可用", example = "1") + @NotNull(message = "支付类型不能为空") + @JSONField(name = "payment_type") + private Integer paymentType; + + @ApiModelProperty(value = "密码(paymentType为3时必填,否则该字段无效)") + @JSONField(name = "resource_password") + private String resourcePassword; + + @ApiModelProperty(value = "直播详情", notes = "仅允许纯文本,不得超过5000个字符,默认为空") + @NotBlank(message = "直播详情不能为空") + @Max(value = 5000, message = "直播详情长度不能超过5000") + @JSONField(name = "descrb") + private String descrb; +} diff --git a/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/dto/XiaoeLiveQueryDto.java b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/dto/XiaoeLiveQueryDto.java new file mode 100644 index 0000000..83974ca --- /dev/null +++ b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/dto/XiaoeLiveQueryDto.java @@ -0,0 +1,35 @@ +package com.ruoyi.goods.domain.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @author mitao + * @date 2025/1/8 + */ +@Data +@ApiModel("直播分页查询参数") +public class XiaoeLiveQueryDto { + + @ApiModelProperty(value = "直播名称关键字") + private String searchContent; + + @ApiModelProperty(value = "直播课程类型 -1 全部;0 店铺课程; 1 转播课程;默认-1") + private Integer createMode; + + @ApiModelProperty(value = "直播商品状态 -1 全部; 0 已上架; 1 已下架;2 待上架;默认-1") + private Integer state; + + @ApiModelProperty(value = "直播模式:-1 全部;10 横屏直播;11竖屏直播;12语音直播;13录播直播;默认-1") + private Integer searchAliveType; + + @ApiModelProperty(value = "直播状态:-1全部;0未开始;1直播中;2已结束;默认-1") + private Integer alivePlayState; + + @ApiModelProperty(value = "页码,表示第几页,从1开始;默认1") + private Integer page; + + @ApiModelProperty(value = "每页条数,最大50条;默认10") + private Integer pageSize; +} diff --git a/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/pojo/live/XiaoeLiveAppointment.java b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/pojo/live/XiaoeLiveAppointment.java new file mode 100644 index 0000000..540b53f --- /dev/null +++ b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/pojo/live/XiaoeLiveAppointment.java @@ -0,0 +1,63 @@ +package com.ruoyi.goods.domain.pojo.live; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.Date; + +/** + * <p> + * 直播预约记录 + * </p> + * + * @author mitao + * @since 2025-01-09 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("t_xiaoe_live_appointment") +public class XiaoeLiveAppointment implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 直播id + */ + private String liveId; + + /** + * 预约人id + */ + private Long userId; + /** + * 直播开始时间 + */ + private Date aliveStartAt; + + /** + * 直播标题 + */ + private String title; + + /** + * 预约时间 + */ + @TableField(fill = FieldFill.INSERT) + private Date createTime; + + +} diff --git a/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/pojo/live/XiaoeLiveRecord.java b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/pojo/live/XiaoeLiveRecord.java new file mode 100644 index 0000000..440c69a --- /dev/null +++ b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/pojo/live/XiaoeLiveRecord.java @@ -0,0 +1,64 @@ +package com.ruoyi.goods.domain.pojo.live; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.Date; + +/** + * <p> + * 小鹅通直播添加记录表 + * </p> + * + * @author mitao + * @since 2025-01-09 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("t_xiaoe_live_record") +public class XiaoeLiveRecord implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + /** + * 记录类型(1:平台 2:经销商) + */ + private Integer type; + + /** + * 直播id + */ + private String liveId; + + /** + * 店铺(仅记录类型为经销商时使用) + */ + private Long shopId; + + /** + * 店铺名称 + */ + private String shopName; + + /** + * 添加时间 + */ + @TableField(fill = FieldFill.INSERT) + private Date createTime; + + +} diff --git a/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/vo/XiaoeCourseChapterVO.java b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/vo/XiaoeCourseChapterVO.java new file mode 100644 index 0000000..b764d0b --- /dev/null +++ b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/vo/XiaoeCourseChapterVO.java @@ -0,0 +1,36 @@ +package com.ruoyi.goods.domain.vo; + +import com.alibaba.fastjson2.annotation.JSONField; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +/** + * @author mitao + * @date 2025/1/9 + */ +@Data +@ApiModel("课程目录小节视图对象") +public class XiaoeCourseChapterVO { + @ApiModelProperty(value = "章节id") + @JSONField(name = "chapter_id") + private String chapterId; + + @ApiModelProperty(value = "章节名称") + @JSONField(name = "chapter_title") + private String chapterTitle; + + @ApiModelProperty(value = "章节类型 0-无 1-章 2-节") + @JSONField(name = "chapter_type") + private Integer chapterType; + + @ApiModelProperty(value = "关联资源的种类(1:图文,2:音频,3:视频,4:直播,20:电子书,45:AI互动课,34练习,27考试,51文档,15作业,13表单,14测试互动)") + @JSONField(name = "resource_type") + private Integer resourceType; + + @ApiModelProperty(value = "子章节集合") + @JSONField(name = "children") + private List<XiaoeCourseChapterVO> children; +} diff --git a/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/vo/XiaoeCourseGroupVO.java b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/vo/XiaoeCourseGroupVO.java new file mode 100644 index 0000000..9817d41 --- /dev/null +++ b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/vo/XiaoeCourseGroupVO.java @@ -0,0 +1,20 @@ +package com.ruoyi.goods.domain.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @author mitao + * @date 2025/1/9 + */ +@Data +@ApiModel("商品分组视图对象") +public class XiaoeCourseGroupVO { + + @ApiModelProperty("商品分组id") + private String id; + + @ApiModelProperty("商品分组名称") + private String name; +} diff --git a/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/vo/XiaoeCourseVO.java b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/vo/XiaoeCourseVO.java new file mode 100644 index 0000000..fd6f8ba --- /dev/null +++ b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/vo/XiaoeCourseVO.java @@ -0,0 +1,45 @@ +package com.ruoyi.goods.domain.vo; + +import com.alibaba.fastjson2.annotation.JSONField; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.Date; + +/** + * @author mitao + * @date 2025/1/9 + */ +@Data +@ApiModel("小鹅通课程视图对象") +public class XiaoeCourseVO { + @ApiModelProperty("课程id") + @JSONField(name = "resource_id") + private String resourceId; + + @ApiModelProperty("课程名称") + @JSONField(name = "title") + private String title; + + @ApiModelProperty("课程封面") + @JSONField(name = "img_url") + private String imgUrl; + + @ApiModelProperty("用户数") + @JSONField(name = "user_count") + private Integer userCount; + + @ApiModelProperty("内容数") + @JSONField(name = "resource_cnt") + private Integer resourceCnt; + + @ApiModelProperty("开课时间") + @JSONField(name = "curriculum_time") + private Date curriculumTime; + + @ApiModelProperty("开课结束时间") + @JSONField(name = "curriculum_end_time") + private Date curriculumEndTime; + +} diff --git a/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/vo/XiaoeLiveTeacherVo.java b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/vo/XiaoeLiveTeacherVo.java new file mode 100644 index 0000000..bc81487 --- /dev/null +++ b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/vo/XiaoeLiveTeacherVo.java @@ -0,0 +1,23 @@ +package com.ruoyi.goods.domain.vo; + +import com.alibaba.fastjson2.annotation.JSONField; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@ApiModel(description = "讲师信息") +@Data +public class XiaoeLiveTeacherVo { + + @ApiModelProperty(value = "讲师ID") + @JSONField(name = "user_id") + private String userId; // 讲师ID + + @ApiModelProperty(value = "讲师昵称") + @JSONField(name = "user_name") + private String userName; // 讲师昵称 + + @ApiModelProperty(value = "讲师绑定手机号") + @JSONField(name = "phone") + private String phone; // 讲师绑定手机号 +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/vo/XiaoeLiveVo.java b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/vo/XiaoeLiveVo.java new file mode 100644 index 0000000..0eeebe2 --- /dev/null +++ b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/vo/XiaoeLiveVo.java @@ -0,0 +1,109 @@ +package com.ruoyi.goods.domain.vo; + +import com.alibaba.fastjson2.annotation.JSONField; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +/** + * @author mitao + * @date 2025/1/8 + */ +@Data +@ApiModel("小鹅通直播视图对象") +public class XiaoeLiveVo { + + @ApiModelProperty(value = "直播ID") + @JSONField(name = "id") + private String id; // 直播ID + + @ApiModelProperty(value = "直播手动结束时间") + @JSONField(name = "alive_manual_stop_at") + private String aliveManualStopAt; // 直播手动结束时间 + + @ApiModelProperty(value = "直播结束时间") + @JSONField(name = "alive_stop_at") + private String aliveStopAt; // 直播结束时间 + + @ApiModelProperty(value = "直播名称") + @JSONField(name = "title") + private String title; // 直播名称 + + @ApiModelProperty(value = "直播观看人次,每5分钟同步一次数据") + @JSONField(name = "view_count") + private Integer viewCount; // 直播观看人次 + + @ApiModelProperty(value = "直播类型:10 横屏直播;11竖屏直播;12语音直播;13录播直播") + @JSONField(name = "alive_type") + private Integer aliveType; // 直播类型 + + @ApiModelProperty(value = "订阅量") + @JSONField(name = "purchase_count") + private Integer purchaseCount; // 订阅量 + + @ApiModelProperty(value = "打赏金额(元)") + @JSONField(name = "reward_sum") + private String rewardSum; // 打赏金额(元) + + @ApiModelProperty(value = "直播商品状态:-1 全部; 0 已上架; 1 已下架;2 待上架") + @JSONField(name = "recycle_bin_state") + private Integer recycleBinState; // 直播商品状态 + + @ApiModelProperty(value = "直播开始时间") + @JSONField(name = "alive_start_at") + private String aliveStartAt; // 直播开始时间 + + @ApiModelProperty(value = "直播状态:-1全部;0未开始;1直播中;2已结束") + @JSONField(name = "alive_state") + private Integer aliveState; // 直播状态 + + @ApiModelProperty(value = "直播显隐状态:0-显示,1-隐藏") + @JSONField(name = "resource_state") + private Integer resourceState; // 直播显隐状态 + + @ApiModelProperty(value = "店铺直播详情页地址") + @JSONField(name = "page_url") + private String pageUrl; // 店铺直播详情页地址 + + @ApiModelProperty(value = "直播课程类型:-1 全部;0 店铺课程; 1 转播课程") + @JSONField(name = "create_mode") + private Integer createMode; // 直播课程类型 + + @ApiModelProperty(value = "封面地址") + @JSONField(name = "img_url") + private String imgUrl; // 封面地址 + + @ApiModelProperty(value = "直播宣传图地址") + @JSONField(name = "alive_img_url") + private String aliveImgUrl; // 直播宣传图地址 + + @ApiModelProperty(value = "讲师列表") + @JSONField(name = "guest_list") + private List<XiaoeLiveTeacherVo> guestList; + + @ApiModelProperty("评论数") + @JSONField(name = "comment_count") + private Integer commentCount; + + @ApiModelProperty("评论用户数") + @JSONField(name = "comment_user_count") + private Integer commentUserCount; + + @ApiModelProperty("打赏次数") + @JSONField(name = "reward_count") + private Integer rewardCount; + + @ApiModelProperty("打赏人数") + @JSONField(name = "reward_user_count") + private Integer rewardUserCount; + + @ApiModelProperty("直播简介") + @JSONField(name = "summary") + private String summary; + + @ApiModelProperty("预约状态 1:已预约 0:未预约") + private Integer appointmentState=0; + +} diff --git a/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/mapper/live/XiaoeLiveAppointmentMapper.java b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/mapper/live/XiaoeLiveAppointmentMapper.java new file mode 100644 index 0000000..bf98aec --- /dev/null +++ b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/mapper/live/XiaoeLiveAppointmentMapper.java @@ -0,0 +1,17 @@ +package com.ruoyi.goods.mapper.live; + + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.ruoyi.goods.domain.pojo.live.XiaoeLiveAppointment; + +/** + * <p> + * 直播预约记录 Mapper 接口 + * </p> + * + * @author mitao + * @since 2025-01-09 + */ +public interface XiaoeLiveAppointmentMapper extends BaseMapper<XiaoeLiveAppointment> { + +} diff --git a/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/mapper/live/XiaoeLiveRecordMapper.java b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/mapper/live/XiaoeLiveRecordMapper.java new file mode 100644 index 0000000..60fbd6d --- /dev/null +++ b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/mapper/live/XiaoeLiveRecordMapper.java @@ -0,0 +1,17 @@ +package com.ruoyi.goods.mapper.live; + + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.ruoyi.goods.domain.pojo.live.XiaoeLiveRecord; + +/** + * <p> + * 小鹅通直播添加记录表 Mapper 接口 + * </p> + * + * @author mitao + * @since 2025-01-09 + */ +public interface XiaoeLiveRecordMapper extends BaseMapper<XiaoeLiveRecord> { + +} diff --git a/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/service/biz/XiaoeCourseService.java b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/service/biz/XiaoeCourseService.java new file mode 100644 index 0000000..cf72f59 --- /dev/null +++ b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/service/biz/XiaoeCourseService.java @@ -0,0 +1,39 @@ +package com.ruoyi.goods.service.biz; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.ruoyi.goods.domain.dto.XiaoeCourseQueryDto; +import com.ruoyi.goods.domain.vo.XiaoeCourseChapterVO; +import com.ruoyi.goods.domain.vo.XiaoeCourseVO; +import com.ruoyi.goods.utils.XiaoeUtils; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * @author mitao + * @date 2025/1/10 + */ +@Service +@RequiredArgsConstructor +public class XiaoeCourseService { + private final XiaoeUtils xiaoeUtils; + + /** + * 课程列表 + * @param dto + * @return + */ + public Page<XiaoeCourseVO> getCoursePageList(XiaoeCourseQueryDto dto) { + return xiaoeUtils.getCoursePageList(dto); + } + + /** + * 获取课程章节详情 + * @param id + * @return + */ + public List<XiaoeCourseChapterVO> getCourseDetail(String id) { + return xiaoeUtils.getCourseChapterDetail(id); + } +} diff --git a/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/service/biz/XiaoeLiveService.java b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/service/biz/XiaoeLiveService.java new file mode 100644 index 0000000..9df3c7d --- /dev/null +++ b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/service/biz/XiaoeLiveService.java @@ -0,0 +1,249 @@ +package com.ruoyi.goods.service.biz; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.ruoyi.common.core.exception.ServiceException; +import com.ruoyi.common.core.utils.DateUtils; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.redis.service.RedisService; +import com.ruoyi.common.security.utils.SecurityUtils; +import com.ruoyi.goods.domain.dto.XiaoeLiveDto; +import com.ruoyi.goods.domain.dto.XiaoeLiveQueryDto; +import com.ruoyi.goods.domain.pojo.live.XiaoeLiveAppointment; +import com.ruoyi.goods.domain.pojo.live.XiaoeLiveRecord; +import com.ruoyi.goods.domain.vo.XiaoeLiveVo; +import com.ruoyi.goods.service.live.IXiaoeLiveAppointmentService; +import com.ruoyi.goods.service.live.IXiaoeLiveRecordService; +import com.ruoyi.goods.utils.XiaoeUtils; +import com.ruoyi.system.api.constant.DelayTaskEnum; +import com.ruoyi.system.api.domain.poji.config.DelayTask; +import com.ruoyi.system.api.domain.poji.shop.Shop; +import com.ruoyi.system.api.domain.poji.sys.SysUser; +import com.ruoyi.system.api.domain.vo.ShopRelUserVo; +import com.ruoyi.system.api.service.RemoteConfigService; +import com.ruoyi.system.api.service.RemoteShopService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.Date; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +/** + * @author mitao + * @date 2025/1/9 + */ +@Service +@RequiredArgsConstructor +public class XiaoeLiveService { + private final IXiaoeLiveRecordService xiaoeLiveRecordService; + private final XiaoeUtils xiaoeUtils; + private final IXiaoeLiveAppointmentService xiaoeLiveAppointmentService; + private final RedisService redisService; + private final RemoteConfigService remoteConfigService; + private final RemoteShopService remoteShopService; + + + /** + * 直播首页分页列表 + * @param dto + * @return + */ + public Page<XiaoeLiveVo> getLivePage(XiaoeLiveQueryDto dto) { + //当前登录用户id + Long userId = SecurityUtils.getUserId(); + Page<XiaoeLiveVo> livePageList = xiaoeUtils.getLivePageList(dto); + if (CollectionUtil.isEmpty(livePageList.getRecords())) { + return new Page<>(); + } + //已预约的记录 + List<XiaoeLiveAppointment> appointments = xiaoeLiveAppointmentService.lambdaQuery() + .gt(XiaoeLiveAppointment::getAliveStartAt, DateUtils.getNowDate()).eq(XiaoeLiveAppointment::getUserId, userId).list(); + //处理获取到的直播数据 + List<XiaoeLiveVo> filteredRecords = livePageList.getRecords().stream() + .filter(item -> !item.getAliveState().equals(2)) + .flatMap(item -> appointments.stream().map(appointment -> { + //直播状态为未开始 且 预约记录存在 设置状态为已预约 + if (item.getAliveState().equals(0) && appointment.getLiveId().equals(item.getId())) { + item.setAppointmentState(1); + } + return item; + })).sorted(Comparator.comparing(XiaoeLiveVo::getAliveState).reversed()) + .collect(Collectors.toList()); + livePageList.setRecords(filteredRecords); + return livePageList; + } + + /** + * 预约直播 + * @param id + * @return + */ + public Boolean appointment(String id) { + //当前登录用户 + SysUser sysUser = SecurityUtils.getSysUser(); + Long userId = sysUser.getUserId(); + //查询预约记录 + Integer count = xiaoeLiveAppointmentService.lambdaQuery().eq(XiaoeLiveAppointment::getLiveId, id).gt(XiaoeLiveAppointment::getAliveStartAt, DateUtils.getNowDate()).eq(XiaoeLiveAppointment::getUserId, userId).count(); + if (count > 0) { + throw new ServiceException("您已预约过该直播,请勿重复预约"); + } + XiaoeLiveVo liveDetail = xiaoeUtils.getLiveDetail(id); + if (Objects.isNull(liveDetail)) { + throw new ServiceException("直播不存在"); + } + XiaoeLiveAppointment xiaoeLiveAppointment = new XiaoeLiveAppointment(); + xiaoeLiveAppointment.setLiveId(id); + xiaoeLiveAppointment.setUserId(userId); + Date aliveStartAt = DateUtil.parse(liveDetail.getAliveStartAt(), DatePattern.NORM_DATETIME_PATTERN); + xiaoeLiveAppointment.setAliveStartAt(aliveStartAt); + xiaoeLiveAppointment.setCreateTime(DateUtils.getNowDate()); + xiaoeLiveAppointmentService.save(xiaoeLiveAppointment); + /// 若为C端用户向 redis 添加预约记录 + if (sysUser.getUserType().equals("03")) { + // 如果活动在1小时内生成自动开始任务的延时任务 + Date checkTime = DateUtils.addMinutes(new Date(), 61); + // 获取当前时间 + Date nowTime = new Date(); + + // 计算直播开始时间与当前时间的差值 + long startTimeDifference = aliveStartAt.getTime() - nowTime.getTime(); + startTimeDifference = Math.max(startTimeDifference, 3000L); // 确保差值至少为3秒 + + // 根据条件判断是否创建延时任务 + if (checkTime.compareTo(aliveStartAt) > 0 || nowTime.compareTo(aliveStartAt) > 0) { + // 获取延时任务 + DelayTask startDelayTask = remoteConfigService.getDelayTask(DelayTaskEnum.LIVE_APPOINTMENT_TASK.getCode() + "-" + xiaoeLiveAppointment.getId()).getData(); + // 创建或者更新延时任务 + if (startDelayTask == null || !startDelayTask.getEndTime().equals(aliveStartAt)) { + // 删除旧的延时任务及缓存 + if (startDelayTask != null) { + remoteConfigService.deleteDelayTask(DelayTaskEnum.LIVE_APPOINTMENT_TASK.getCode() + "-" + xiaoeLiveAppointment.getId()); + redisService.deleteObject(DelayTaskEnum.LIVE_APPOINTMENT_TASK.getCode() + "-" + xiaoeLiveAppointment.getId()); + } + // 设置新的延时任务 + redisService.setCacheObject(DelayTaskEnum.LIVE_APPOINTMENT_TASK.getCode() + "-" + xiaoeLiveAppointment.getId(), aliveStartAt, startTimeDifference, TimeUnit.MILLISECONDS); + startDelayTask = new DelayTask(); + startDelayTask.setDelFlag(0); + startDelayTask.setCreateTime(new Date()); + startDelayTask.setEndTime(aliveStartAt); + startDelayTask.setRedisKey(DelayTaskEnum.LIVE_APPOINTMENT_TASK.getCode() + "-" + xiaoeLiveAppointment.getId()); + + // 添加新的延时任务 + remoteConfigService.addDelayTask(startDelayTask); + } + } + } + return true; + } + + /** + * 我的直播 + * @param dto + * @return + */ + public Page<XiaoeLiveVo> getMineLivePage(XiaoeLiveQueryDto dto) { + Long userId = SecurityUtils.getUserId(); + Page<XiaoeLiveVo> page = new Page<>(); + ShopRelUserVo shopRelUserVo = remoteShopService.getShopByUserId(userId).getData(); + if (Objects.isNull(shopRelUserVo)) { + return page; + } + List<XiaoeLiveRecord> xiaoeLiveRecordList = xiaoeLiveRecordService.getListByShopId(shopRelUserVo.getShopId()); + if (CollectionUtil.isEmpty(xiaoeLiveRecordList)) { + return page; + } + Page<XiaoeLiveVo> livePageList = xiaoeUtils.getLivePageList(dto); + if (CollectionUtil.isEmpty(livePageList.getRecords())) { + return page; + } + //当前商家创建的直播 + Set<String> liveIdSet = xiaoeLiveRecordList.stream().map(XiaoeLiveRecord::getLiveId).collect(Collectors.toSet()); + //过滤数据 + List<XiaoeLiveVo> filteredRecords = livePageList.getRecords().stream().filter(item -> liveIdSet.contains(item.getId()) && !item.getAliveState().equals(2)).collect(Collectors.toList()); + livePageList.setRecords(filteredRecords); + return livePageList; + } + + /** + * 获取当前店铺讲师id列表 + * @return + */ + public List<String> getShopXiaoeUserIdList() { + Long userId = SecurityUtils.getUserId(); + //获取用户所属店铺 + ShopRelUserVo shopRelUserVo = remoteShopService.getShopByUserId(userId).getData(); + if (Objects.isNull(shopRelUserVo)) { + throw new ServiceException("当前用户未关联店铺,请先关联店铺"); + } + //查询店铺信息 + Shop shop = remoteShopService.getShop(shopRelUserVo.getShopId()).getData(); + if (Objects.isNull(shop)) { + throw new ServiceException("店铺不存在"); + } + if (StringUtils.isBlank(shop.getXiaoeUserId())) { + throw new ServiceException("创建失败,请联系平台添加讲师。"); + } + return Arrays.asList(shop.getXiaoeUserId().split(",")); + } + /** + * 创建直播 + * @param dto + * @param type 创建类型 1:平台 2:经销商 + * @return + */ + public void create(XiaoeLiveDto dto,Integer type) { + if (dto.getPaymentType().equals(3) && StringUtils.isBlank(dto.getResourcePassword())){ + throw new ServiceException("密码不能为空"); + } + if (type.equals(2)) { + //获取当前登录用户 + Long userId = SecurityUtils.getUserId(); + //获取用户所属店铺 + ShopRelUserVo shopRelUserVo = remoteShopService.getShopByUserId(userId).getData(); + if (Objects.isNull(shopRelUserVo)) { + throw new ServiceException("当前用户未关联店铺,请先关联店铺"); + } + //查询店铺信息 + Shop shop = remoteShopService.getShop(shopRelUserVo.getShopId()).getData(); + if (Objects.isNull(shop)) { + throw new ServiceException("店铺不存在"); + } + String liveId = xiaoeUtils.addLive(dto); + if (StringUtils.isBlank(liveId)) { + throw new ServiceException("创建直播失败,请联系平台管理员"); + } + Long shopId = shop.getShopId(); + String shopName = shop.getShopName(); + //添加直播创建记录 + xiaoeLiveRecordService.add(shopId, type, shopName, liveId); + } else { + String liveId = xiaoeUtils.addLive(dto); + if (StringUtils.isBlank(liveId)) { + throw new ServiceException("创建直播失败,请联系平台管理员"); + } + //添加直播创建记录 + xiaoeLiveRecordService.add(null, type, "鸿瑞堂", liveId); + } + } + + /** + * 编辑直播 + * @param dto + */ + public Boolean edit(XiaoeLiveDto dto) { + if (StringUtils.isBlank(dto.getId())) { + throw new ServiceException("直播id不能为空"); + } + return xiaoeUtils.editLive(dto); + } + + +} diff --git a/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/service/impl/live/XiaoeLiveAppointmentServiceImpl.java b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/service/impl/live/XiaoeLiveAppointmentServiceImpl.java new file mode 100644 index 0000000..69956e1 --- /dev/null +++ b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/service/impl/live/XiaoeLiveAppointmentServiceImpl.java @@ -0,0 +1,57 @@ +package com.ruoyi.goods.service.impl.live; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.ruoyi.goods.domain.pojo.live.XiaoeLiveAppointment; +import com.ruoyi.goods.domain.pojo.live.XiaoeLiveRecord; +import com.ruoyi.goods.mapper.live.XiaoeLiveAppointmentMapper; +import com.ruoyi.goods.service.live.IXiaoeLiveAppointmentService; +import com.ruoyi.goods.service.live.IXiaoeLiveRecordService; +import com.ruoyi.goods.utils.WeChatSubscribeMessageSender; +import com.ruoyi.system.api.domain.poji.member.Member; +import com.ruoyi.system.api.service.RemoteMemberService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.Objects; + +/** + * <p> + * 直播预约记录 服务实现类 + * </p> + * + * @author mitao + * @since 2025-01-09 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class XiaoeLiveAppointmentServiceImpl extends ServiceImpl<XiaoeLiveAppointmentMapper, XiaoeLiveAppointment> implements IXiaoeLiveAppointmentService { + private final RemoteMemberService remoteMemberService; + private final IXiaoeLiveRecordService xiaoeLiveRecordService; + + /** + * 推送微信小程序订阅消息 + * @param appointmentId + * @return + */ + @Override + public void push(Long appointmentId) { + log.info("开始推送预约id为:{}的订阅消息",appointmentId); + XiaoeLiveAppointment appointment = getById(appointmentId); + if (Objects.nonNull(appointment)) { + Member member = remoteMemberService.getMember(appointment.getUserId()).getData(); + if (Objects.isNull(member)){ + return; + } + XiaoeLiveRecord record = xiaoeLiveRecordService.getByLiveId(appointment.getLiveId()); + if (Objects.isNull(record)) { + return; + } + //推送微信小程序订阅消息 + WeChatSubscribeMessageSender.push(member.getMiniOpenid(), appointment.getTitle(), record.getShopName(), appointment.getAliveStartAt()); + } + log.info("预约id为:{}的订阅消息推送成功",appointmentId); + } + +} diff --git a/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/service/impl/live/XiaoeLiveRecordServiceImpl.java b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/service/impl/live/XiaoeLiveRecordServiceImpl.java new file mode 100644 index 0000000..8f4454d --- /dev/null +++ b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/service/impl/live/XiaoeLiveRecordServiceImpl.java @@ -0,0 +1,61 @@ +package com.ruoyi.goods.service.impl.live; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.ruoyi.common.core.utils.DateUtils; +import com.ruoyi.goods.domain.pojo.live.XiaoeLiveRecord; +import com.ruoyi.goods.mapper.live.XiaoeLiveRecordMapper; +import com.ruoyi.goods.service.live.IXiaoeLiveRecordService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * <p> + * 小鹅通直播添加记录表 服务实现类 + * </p> + * + * @author mitao + * @since 2025-01-09 + */ +@Service +public class XiaoeLiveRecordServiceImpl extends ServiceImpl<XiaoeLiveRecordMapper, XiaoeLiveRecord> implements IXiaoeLiveRecordService { + /** + * 根据直播id查询记录 + * + * @param liveId + * @return + */ + @Override + public XiaoeLiveRecord getByLiveId(String liveId) { + return lambdaQuery().eq(XiaoeLiveRecord::getLiveId, liveId).one(); + } + + /** + * 根据店铺id查询记录 + * + * @param shopId + * @return + */ + @Override + public List<XiaoeLiveRecord> getListByShopId(Long shopId) { + return lambdaQuery().eq(XiaoeLiveRecord::getType, 2).eq(XiaoeLiveRecord::getShopId, shopId).list(); + } + + /** + * 添加直播创建记录 + * @param shopId + * @param type + * @param shopName + * @param liveId + */ + @Override + public void add(Long shopId, Integer type, String shopName, String liveId) { + XiaoeLiveRecord xiaoeLiveRecord = new XiaoeLiveRecord(); + xiaoeLiveRecord.setShopId(shopId); + xiaoeLiveRecord.setType(type); + xiaoeLiveRecord.setShopName(shopName); + xiaoeLiveRecord.setLiveId(liveId); + xiaoeLiveRecord.setCreateTime(DateUtils.getNowDate()); + save(xiaoeLiveRecord); + } +} diff --git a/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/service/live/IXiaoeLiveAppointmentService.java b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/service/live/IXiaoeLiveAppointmentService.java new file mode 100644 index 0000000..52dd780 --- /dev/null +++ b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/service/live/IXiaoeLiveAppointmentService.java @@ -0,0 +1,22 @@ +package com.ruoyi.goods.service.live; + + +import com.baomidou.mybatisplus.extension.service.IService; +import com.ruoyi.goods.domain.pojo.live.XiaoeLiveAppointment; + +/** + * <p> + * 直播预约记录 服务类 + * </p> + * + * @author mitao + * @since 2025-01-09 + */ +public interface IXiaoeLiveAppointmentService extends IService<XiaoeLiveAppointment> { + /** + * 推送微信小程序订阅消息 + * @param appointmentId + * @return + */ + void push(Long appointmentId); +} diff --git a/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/service/live/IXiaoeLiveRecordService.java b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/service/live/IXiaoeLiveRecordService.java new file mode 100644 index 0000000..a1db5cf --- /dev/null +++ b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/service/live/IXiaoeLiveRecordService.java @@ -0,0 +1,33 @@ +package com.ruoyi.goods.service.live; + + +import com.baomidou.mybatisplus.extension.service.IService; +import com.ruoyi.goods.domain.pojo.live.XiaoeLiveRecord; + +import java.util.List; + +/** + * <p> + * 小鹅通直播添加记录表 服务类 + * </p> + * + * @author mitao + * @since 2025-01-09 + */ +public interface IXiaoeLiveRecordService extends IService<XiaoeLiveRecord> { + /** + * 根据直播id查询记录 + * @param liveId + * @return + */ + XiaoeLiveRecord getByLiveId(String liveId); + + /** + * 根据店铺id查询记录 + * @param shopId + * @return + */ + List<XiaoeLiveRecord> getListByShopId(Long shopId); + + void add(Long shopId, Integer type, String shopName, String liveId); +} diff --git a/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/utils/WeChatSubscribeMessageSender.java b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/utils/WeChatSubscribeMessageSender.java new file mode 100644 index 0000000..d1d858b --- /dev/null +++ b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/utils/WeChatSubscribeMessageSender.java @@ -0,0 +1,76 @@ +package com.ruoyi.goods.utils; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson2.JSONObject; +import lombok.extern.slf4j.Slf4j; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * @author mitao + * @date 2025/1/10 + */ +@Slf4j +public class WeChatSubscribeMessageSender { + private static final String ACCESS_TOKEN_HOST = "https://api.weixin.qq.com/cgi-bin/token"; + private static final String API_URL = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send"; + + private static final String WX_APPID = "wxb7f0ea286fc4e535"; + + private static final String WX_SECRET = "852a2512a6ab559cafc68bae5d4160ac"; + private static final String TEMPLATE_ID = "EFeu75n2GMmOg33PxL1HNoyftp16ukco5DUbBfNBytE"; + + /** + *发送消息 + * @param touser 接收者(用户)的 openid + * @param title 直播主题 + * @param shopName 直播间名称 + * @param aliveStartAt 直播时间 + */ + public static void push(String touser, String title, String shopName, Date aliveStartAt) { + + //1,获取access_token + String accessToken = getAccessTokenByWX(); + String url = API_URL + "?access_token=" + accessToken; + Map<String, Object> params = new HashMap<>(); + params.put("template_id", TEMPLATE_ID); + params.put("page", null); + params.put("touser", touser); + // 构建订阅消息内容的JSON对象 + JSONObject messageData = new JSONObject(); + messageData.put("thing1", createDataItem("直播主题", title)); + messageData.put("thing4", createDataItem("直播间名称", shopName)); + messageData.put("time5", createDataItem("直播时间", DateUtil.format(aliveStartAt, "MM-dd HH:mm:ss"))); + params.put("data", messageData.toJSONString()); + params.put("miniprogram_state", "trial"); + params.put("lang", "zh_CN"); + try { + String post = HttpUtil.post(url, JSONObject.toJSONString(params)); + log.info("发送消息返回结果:{}", post); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * 获取access_token + * @return + */ + public static String getAccessTokenByWX() { + String host = ACCESS_TOKEN_HOST + "?appid=" + WX_APPID + "&secret=" + WX_SECRET + "&grant_type=client_credential"; + log.info("host:{}", host); + return HttpUtil.get(host); + } + private static Map<String, Object> createDataItem(String name, String value) { + Map<String, Object> item = new HashMap<>(); + item.put("value", value); + return item; + } + + public static void main(String[] args) throws Exception { + push("oL-gp5Fn7BobtFZCsQ3ZTY7QGU84", "直播推送", "鸿瑞堂", new Date()); + } +} diff --git a/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/utils/XiaoeUtils.java b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/utils/XiaoeUtils.java new file mode 100644 index 0000000..d409416 --- /dev/null +++ b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/utils/XiaoeUtils.java @@ -0,0 +1,375 @@ +package com.ruoyi.goods.utils; + +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.redis.service.RedisService; +import com.ruoyi.goods.domain.dto.XiaoeCourseQueryDto; +import com.ruoyi.goods.domain.dto.XiaoeLiveDto; +import com.ruoyi.goods.domain.dto.XiaoeLiveQueryDto; +import com.ruoyi.goods.domain.vo.XiaoeCourseChapterVO; +import com.ruoyi.goods.domain.vo.XiaoeCourseGroupVO; +import com.ruoyi.goods.domain.vo.XiaoeCourseVO; +import com.ruoyi.goods.domain.vo.XiaoeLiveVo; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 小鹅通工具类 + * @author mitao + * @date 2025/1/8 + */ +@Slf4j +@Component +public class XiaoeUtils { + @Resource + private RedisService redisService; + private static final String BASE_URL = "https://api.xiaoe-tech.com/token"; + //店铺的业务id + private String app_id = "appwmuwNWD48082"; + //应用的唯一标识,通过 client_id 来鉴别应用的身份 + private String client_id = "xopYwOAqNI36444"; + //应用的凭证秘钥,即client_secret,用来保证应用来源的可靠性,防止被伪造 + private String secret_key = "qKFxbGR0OlKX85PVyfCvkRF1P6fLRBEu"; + //固定填写client_credential + private String grant_type = "client_credential"; + //获取直播列表 + private static final String LIVE_PAGE_LIST = "https://api.xiaoe-tech.com/xe.alive.list.get/2.0.0"; + //获取直播详情 + private static final String LIVE_DETAIL = "https://api.xiaoe-tech.com/xe.alive.detail.get/1.0.0"; + //创建直播 + private static final String LIVE_ADD = "https://api.xiaoe-tech.com/xe.alive.live.create/1.0.0"; + //编辑直播 + private static final String LIVE_EDIT = "https://api.xiaoe-tech.com/xe.alive.live.update/1.0.0"; + //删除直播 + private static final String LIVE_DELETE = "https://api.xiaoe-tech.com/xe.alive.live.delete/1.0.0"; + //课程列表 + private static final String COURSE_PAGE_LIST = "https://api.xiaoe-tech.com/xe.course.course.list/1.0.0"; + //课程小节 + private static final String COURSE_CHAPTER = "https://api.xiaoe-tech.com/xe.course.course.chapter.get/1.0.0"; + //获取店铺商品分组列表 + private static final String COURSE_GROUP_LIST = "https://api.xiaoe-tech.com/xe.resource_tags.list/1.0.0"; + + /** + * 获取小鹅通access_token + * @return + */ + private String getAccessToken() { + Boolean flag = redisService.hasKey("xiaoe:access_token"); + String accessToken = ""; + if (flag) { + accessToken = redisService.getCacheObject("xiaoe:access_token"); + } else { + String urlString = BASE_URL + + "?app_id=" + this.app_id + + "&client_id=" + this.client_id + + "&secret_key=" + this.secret_key + + "&grant_type=" + this.grant_type; + String result = null; + try { + URL reqURL = new URL(urlString); + HttpURLConnection httpURLConnection = (HttpURLConnection) reqURL.openConnection(); + InputStreamReader isr = new InputStreamReader(httpURLConnection.getInputStream()); + char[] chars = new char[1024]; + result = ""; + int len; + while ((len = isr.read(chars)) != -1) { + result += new String(chars, 0, len); + } + isr.close(); + } catch (MalformedURLException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + JSONObject jsonObject = JSONObject.parseObject(result); + Map data = (Map) jsonObject.get("data"); + accessToken = (String) data.get("access_token"); + } + return accessToken; + } + + /** + * 获取直播列表 + * @param dto + * @return + */ + public Page<XiaoeLiveVo> getLivePageList(XiaoeLiveQueryDto dto) { + Map<String,Object> postParams = new HashMap<>(); + postParams.put("search_content", dto.getSearchContent()); + postParams.put("create_mode", dto.getCreateMode()); + postParams.put("state", dto.getState()); + postParams.put("search_alive_type", dto.getSearchAliveType()); + postParams.put("alive_play_state", dto.getAlivePlayState()); + postParams.put("page", dto.getPage()); + postParams.put("page_size", dto.getPageSize()); + postParams.put("access_token", getAccessToken()); + String post = HttpUtil.post(LIVE_PAGE_LIST, JSONObject.toJSONString(postParams)); + Page<XiaoeLiveVo> xiaoeLiveVOPage = new Page<>(); + if (StringUtils.isNotBlank(post)) { + JSONObject jsonObject = JSONObject.parseObject(post); + if (jsonObject.get("code").equals(0)) { + JSONObject data = jsonObject.getJSONObject("data"); + JSONArray list = data.getJSONArray("list"); + List<XiaoeLiveVo> xiaoeLiveVos = JSONArray.parseArray(list.toJSONString(), XiaoeLiveVo.class); + xiaoeLiveVOPage.setRecords(xiaoeLiveVos); + xiaoeLiveVOPage.setCurrent(data.getLong("page")); + xiaoeLiveVOPage.setTotal(data.getLong("total")); + xiaoeLiveVOPage.setPages(data.getLong("page_count")); + } + } + return xiaoeLiveVOPage; + } + + /** + *获取直播详情 + * @param id 直播ID + * @return + */ + public XiaoeLiveVo getLiveDetail(String id) { + Map<String, Object> postParams = new HashMap<>(); + postParams.put("id", id); + postParams.put("access_token", getAccessToken()); + String post = HttpUtil.post(LIVE_DETAIL, JSONObject.toJSONString(postParams)); + XiaoeLiveVo xiaoeLiveVO = null; + if (StringUtils.isNotBlank(post)) { + JSONObject jsonObject = JSONObject.parseObject(post); + if (jsonObject.get("code").equals(0)) { + JSONObject data = jsonObject.getJSONObject("data"); + xiaoeLiveVO = JSONObject.parseObject(data.toJSONString(), XiaoeLiveVo.class); + } + } + return xiaoeLiveVO; + } + + /** + * 创建直播 + * @param dto + * @return + */ + public String addLive(XiaoeLiveDto dto) { + Map<String, Object> requestParams = new HashMap<>(); + Map<String, Object> resourceInfoMap = new HashMap<>(); + resourceInfoMap.put("title", dto.getTitle()); + resourceInfoMap.put("summary", dto.getSummary()); + resourceInfoMap.put("zb_start_at", dto.getZbStartAt()); + resourceInfoMap.put("zb_stop_at", dto.getZbStopAt()); + resourceInfoMap.put("alive_type", dto.getAliveType()); + resourceInfoMap.put("descrb", dto.getDescrb()); + requestParams.put("resource_info", resourceInfoMap); + // 配置信息 + Map<String, Object> moudleInfoMap = new HashMap<>(); + moudleInfoMap.put("alive_mode", dto.getAliveMode()); + requestParams.put("module_info", moudleInfoMap); + //讲师信息 + Map<String, Object> roleInfoMap = new HashMap<>(); + roleInfoMap.put("user_id", dto.getUserId()); + requestParams.put("role_info", roleInfoMap); + //商品信息 + Map<String, Object> goodsInfoMap = new HashMap<>(); + goodsInfoMap.put("sale_type", 2);//售卖类型:1-单独售卖、2-关联售卖 + goodsInfoMap.put("payment_type", dto.getPaymentType()); + if (dto.getPaymentType().equals(3)) { + goodsInfoMap.put("resource_password", dto.getResourcePassword()); + } + requestParams.put("goods_info", goodsInfoMap); + requestParams.put("access_token", getAccessToken()); + String post = HttpUtil.post(LIVE_ADD, JSONObject.toJSONString(requestParams)); + if (StringUtils.isNotBlank(post)) { + JSONObject jsonObject = JSONObject.parseObject(post); + log.info("创建直播返回结果:{}" ,post); + if (jsonObject.get("code").equals(0)) { + JSONObject data = jsonObject.getJSONObject("data"); + return data.getString("id"); + } + } + return null; + } + /** + * 创建直播 + * @param dto + * @return + */ + public Boolean editLive(XiaoeLiveDto dto) { + boolean flag = false; + Map<String, Object> requestParams = new HashMap<>(); + Map<String, Object> resourceInfoMap = new HashMap<>(); + resourceInfoMap.put("id", dto.getId()); + resourceInfoMap.put("title", dto.getTitle()); + resourceInfoMap.put("summary", dto.getSummary()); + resourceInfoMap.put("zb_start_at", dto.getZbStartAt()); + resourceInfoMap.put("zb_stop_at", dto.getZbStopAt()); + resourceInfoMap.put("alive_type", dto.getAliveType()); + resourceInfoMap.put("descrb", dto.getDescrb()); + requestParams.put("resource_info", resourceInfoMap); + // 配置信息 + Map<String, Object> moudleInfoMap = new HashMap<>(); + moudleInfoMap.put("alive_mode", dto.getAliveMode()); + requestParams.put("module_info", moudleInfoMap); + //讲师信息 + Map<String, Object> roleInfoMap = new HashMap<>(); + roleInfoMap.put("user_id", dto.getUserId()); + requestParams.put("role_info", roleInfoMap); + //商品信息 + Map<String, Object> goodsInfoMap = new HashMap<>(); + goodsInfoMap.put("sale_type", 2);//售卖类型:1-单独售卖、2-关联售卖 + goodsInfoMap.put("payment_type", dto.getPaymentType()); + if (dto.getPaymentType().equals(3)) { + goodsInfoMap.put("resource_password", dto.getResourcePassword()); + } + requestParams.put("goods_info", goodsInfoMap); + requestParams.put("access_token", getAccessToken()); + String post = HttpUtil.post(LIVE_EDIT, JSONObject.toJSONString(requestParams)); + if (StringUtils.isNotBlank(post)) { + JSONObject jsonObject = JSONObject.parseObject(post); + log.info("编辑直播返回结果:{}" ,post); + if (jsonObject.get("code").equals(0)) { + flag = true; + } + } + return flag; + } + + /** + * 删除直播 + * @param id + * @return + */ + public Boolean deleteLive(String id) { + boolean flag = false; + Map<String, Object> requestParams = new HashMap<>(); + requestParams.put("id", id); + requestParams.put("access_token", getAccessToken()); + String post = HttpUtil.post(LIVE_DELETE, JSONObject.toJSONString(requestParams)); + if (StringUtils.isNotBlank(post)) { + JSONObject jsonObject = JSONObject.parseObject(post); + log.info("删除直播返回结果:{}" ,post); + if (jsonObject.get("code").equals(0)) { + flag = true; + } + } + return flag; + } + + /** + * 获取商品分组列表 + * @return + */ + public List<XiaoeCourseGroupVO> getCourseGroupList(){ + Map<String, Object> requestParams = new HashMap<>(); + requestParams.put("page", 1); + requestParams.put("page_size", 50); + requestParams.put("access_token", getAccessToken()); + String post = HttpUtil.post(COURSE_GROUP_LIST, JSONObject.toJSONString(requestParams)); + List<XiaoeCourseGroupVO> xiaoeCourseGroupVOList = new ArrayList<>(); + if (StringUtils.isNotBlank(post)) { + JSONObject jsonObject = JSONObject.parseObject(post); + log.info("获取商品分组返回结果:{}" ,post); + if (jsonObject.get("code").equals(0)) { + JSONObject data = jsonObject.getJSONObject("data"); + JSONArray jsonArray = data.getJSONArray("list"); + xiaoeCourseGroupVOList = JSONArray.parseArray(jsonArray.toJSONString(), XiaoeCourseGroupVO.class); + } + } + return xiaoeCourseGroupVOList; + } + + /** + * 获取课程列表 + * @param dto + * @return + */ + public Page<XiaoeCourseVO> getCoursePageList(XiaoeCourseQueryDto dto) { + JSONObject requestParams = JSONObject.parseObject(JSONObject.toJSONString(dto)); + if (dto.getSortBy().equals(1)) { + requestParams.put("order_by", "modify");//根据创建时间排序 + requestParams.put("order_type", "降序"); + } + + requestParams.put("sale_status", 1); + requestParams.put("access_token", getAccessToken()); + String post = HttpUtil.post(COURSE_PAGE_LIST, requestParams.toJSONString()); + Page<XiaoeCourseVO> page = new Page<>(); + if (StringUtils.isNotBlank(post)) { + log.info("获取课程列表返回结果:{}" ,post); + JSONObject jsonObject = JSONObject.parseObject(post); + if (jsonObject.get("code").equals(0)) { + JSONObject data = jsonObject.getJSONObject("data"); + JSONArray jsonArray = data.getJSONArray("list"); + List<XiaoeCourseVO> xiaoeCourseVOList = JSONArray.parseArray(jsonArray.toJSONString(), XiaoeCourseVO.class); + if (dto.getSortBy().equals(2)){ + xiaoeCourseVOList.sort(Comparator.comparing(XiaoeCourseVO::getCurriculumTime)); + } + page.setRecords(xiaoeCourseVOList); + page.setTotal(data.getLong("total")); + } + } + return page; + } + + /** + * 查询课程目录小节 + * @param id + * @return + */ + public List<XiaoeCourseChapterVO> getCourseChapterDetail(String id) { + Map<String, Object> requestParams = new HashMap<>(); + requestParams.put("course_id", id); + requestParams.put("access_token", getAccessToken()); + String post = HttpUtil.post(COURSE_CHAPTER, JSONObject.toJSONString(requestParams)); + List<XiaoeCourseChapterVO> xiaoeCourseChapterVO = new ArrayList<>(); + if (StringUtils.isNotBlank(post)) { + log.info("查询课程目录小节返回结果:{}" ,post); + JSONObject jsonObject = JSONObject.parseObject(post); + if (jsonObject.get("code").equals(0)) { + String data = jsonObject.getString("data"); + xiaoeCourseChapterVO = JSONArray.parseArray(data, XiaoeCourseChapterVO.class); + } + } + return xiaoeCourseChapterVO; + } + public static void main(String[] args) { + String urlString = BASE_URL + + "?app_id=appwmuwNWD48082" + + "&client_id=xopYwOAqNI36444"+ + "&secret_key=qKFxbGR0OlKX85PVyfCvkRF1P6fLRBEu" + + "&grant_type=client_credential"; + String result = null; + try { + URL reqURL = new URL(urlString); + HttpURLConnection httpURLConnection = (HttpURLConnection) reqURL.openConnection(); + InputStreamReader isr = new InputStreamReader(httpURLConnection.getInputStream()); + char[] chars = new char[1024]; + result = ""; + int len; + while ((len = isr.read(chars)) != -1) { + result += new String(chars, 0, len); + } + isr.close(); + } catch (MalformedURLException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + JSONObject jsonObject = JSONObject.parseObject(result); + System.out.println(jsonObject); + Map data = (Map) jsonObject.get("data"); + String accessToken = (String) data.get("access_token"); + System.out.println(accessToken); + } + +} diff --git a/ruoyi-modules/ruoyi-goods/src/main/resources/mapper/live/XiaoeLiveAppointmentMapper.xml b/ruoyi-modules/ruoyi-goods/src/main/resources/mapper/live/XiaoeLiveAppointmentMapper.xml new file mode 100644 index 0000000..08ed38e --- /dev/null +++ b/ruoyi-modules/ruoyi-goods/src/main/resources/mapper/live/XiaoeLiveAppointmentMapper.xml @@ -0,0 +1,5 @@ +<?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.ruoyi.goods.mapper.live.XiaoeLiveAppointmentMapper"> + +</mapper> diff --git a/ruoyi-modules/ruoyi-goods/src/main/resources/mapper/live/XiaoeLiveRecordMapper.xml b/ruoyi-modules/ruoyi-goods/src/main/resources/mapper/live/XiaoeLiveRecordMapper.xml new file mode 100644 index 0000000..7e4d32f --- /dev/null +++ b/ruoyi-modules/ruoyi-goods/src/main/resources/mapper/live/XiaoeLiveRecordMapper.xml @@ -0,0 +1,5 @@ +<?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.ruoyi.goods.mapper.live.XiaoeLiveRecordMapper"> + +</mapper> diff --git a/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/domain/dto/MgtEditShopDto.java b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/domain/dto/MgtEditShopDto.java index 116f5a9..3920dfe 100644 --- a/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/domain/dto/MgtEditShopDto.java +++ b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/domain/dto/MgtEditShopDto.java @@ -139,4 +139,7 @@ @ApiModelProperty(value="商户banner 多个用,隔开") private String shopBanners; + + @ApiModelProperty(value="小鹅通讲师id 多个用,隔开") + private String xiaoeUserId; } diff --git a/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/domain/vo/MgtShopInfoVo.java b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/domain/vo/MgtShopInfoVo.java index ce732c8..8bf91bf 100644 --- a/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/domain/vo/MgtShopInfoVo.java +++ b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/domain/vo/MgtShopInfoVo.java @@ -149,6 +149,9 @@ @ApiModelProperty(value="证书list") private List<ShopCertificate> shopCertificateList; + @ApiModelProperty(value="小鹅通讲师id 多个用,隔开") + private String xiaoeUserId; + diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/listener/RedisListener.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/listener/RedisListener.java index b852a0e..572ce5c 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/listener/RedisListener.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/listener/RedisListener.java @@ -7,6 +7,7 @@ import com.ruoyi.system.api.service.RemoteActivityService; import com.ruoyi.system.api.service.RemoteConfigService; import com.ruoyi.system.api.service.RemoteCouponService; +import com.ruoyi.system.api.service.RemoteGoodsService; import com.ruoyi.system.api.service.RemoteOrderService; import lombok.extern.log4j.Log4j2; import org.springframework.data.redis.connection.Message; @@ -44,6 +45,9 @@ @Resource private RemoteOrderService remoteOrderService; + @Resource + private RemoteGoodsService remoteGoodsService; + public RedisListener(RedisMessageListenerContainer listenerContainer, RedisTemplate redisTemplate) { super(listenerContainer); @@ -73,6 +77,8 @@ }else if(DelayTaskEnum.ORDER_AUTOMATIC_CANCEL.getCode().equals(operation)){ //自动结束任务 autoCancelOrder(split[1]); + } else if (DelayTaskEnum.LIVE_APPOINTMENT_TASK.getCode().equals(operation)) { + push(Long.valueOf(split[1])); } //删除失效的key @@ -84,6 +90,16 @@ } } + /** + * 推送消息 + * @param appointmentId + */ + private void push(Long appointmentId) { + remoteGoodsService.push(appointmentId); + //删除定时任务 + remoteConfigService.deleteDelayTask(DelayTaskEnum.LIVE_APPOINTMENT_TASK.getCode()+"-"+appointmentId); + } + public <T> T getAndSet(final String key, T value){ T oldValue=null; try { -- Gitblit v1.7.1