添加了课程模块的功能:

1.小程序端用户根据类别查看课程列表
2.小程序端用户根据id查询课程详情
3.小程序端用户生成推广码
This commit is contained in:
2025-06-24 10:42:28 +08:00
parent 7ca23bc987
commit 95d30cc5f6
10 changed files with 295 additions and 26 deletions

View File

@ -7,4 +7,10 @@ public interface SystemConstant {
*/
String VERIFICATION_CODE = "verificationCode";
/**
* 文件公共前缀
*/
String FILE_COMMON_PREFIX = "http://27.30.77.229:9091/file/download/";
}

View File

@ -12,15 +12,21 @@ import com.greenorange.promotion.common.ResultUtils;
import com.greenorange.promotion.constant.UserConstant;
import com.greenorange.promotion.model.dto.CommonBatchRequest;
import com.greenorange.promotion.model.dto.CommonRequest;
import com.greenorange.promotion.model.dto.CommonStringRequest;
import com.greenorange.promotion.model.dto.course.CourseAddRequest;
import com.greenorange.promotion.model.dto.course.CourseQrcodeAddRequest;
import com.greenorange.promotion.model.dto.course.CourseQueryRequest;
import com.greenorange.promotion.model.dto.course.CourseUpdateRequest;
import com.greenorange.promotion.model.entity.Course;
import com.greenorange.promotion.model.entity.CourseChapter;
import com.greenorange.promotion.model.vo.course.CourseCardVO;
import com.greenorange.promotion.model.vo.course.CourseDetailVO;
import com.greenorange.promotion.model.vo.course.CourseVO;
import com.greenorange.promotion.model.vo.courseChapter.CourseChapterVO;
import com.greenorange.promotion.service.common.CommonService;
import com.greenorange.promotion.service.course.CourseChapterService;
import com.greenorange.promotion.service.course.CourseService;
import com.greenorange.promotion.service.wechat.WechatGetQrcodeService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
@ -52,6 +58,64 @@ public class CourseController {
@Resource
private CourseChapterService courseChapterService;
@Resource
private WechatGetQrcodeService wechatGetQrcodeService;
/**
* 小程序端用户根据类别查看课程列表
* @param commonStringRequest 课程类别
* @return 课程信息列表
*/
@PostMapping("query/type")
@Operation(summary = "小程序端用户根据类别查看课程列表", description = "参数课程添加请求体权限管理员方法名miniQueryCourseByType")
@RequiresPermission(mustRole = UserConstant.DEFAULT_ROLE)
@SysLog(title = "课程管理", content = "小程序端用户根据类别查看课程列表")
public BaseResponse<List<CourseCardVO>> miniQueryCourseByType(@Valid @RequestBody CommonStringRequest commonStringRequest) {
String courseType = commonStringRequest.getTemplateString();
LambdaQueryWrapper<Course> lambdaQueryWrapper = commonService.buildQueryWrapperByField(Course::getType, courseType, courseService);
List<Course> courseList = courseService.list(lambdaQueryWrapper);
List<CourseCardVO> courseCardVOS = commonService.convertList(courseList, CourseCardVO.class);
return ResultUtils.success(courseCardVOS);
}
/**
* 小程序端用户根据id查询课程详情
* @param commonRequest 课程id
* @return 课程信息列表
*/
@PostMapping("query/id")
@Operation(summary = "小程序端用户根据id查询课程详情", description = "参数课程id权限管理员方法名miniQueryCourseById")
@SysLog(title = "课程管理", content = "小程序端用户根据id查询课程详情")
public BaseResponse<CourseDetailVO> miniQueryCourseById(@Valid @RequestBody CommonRequest commonRequest) {
Long id = commonRequest.getId();
Course course = courseService.getById(id);
CourseDetailVO courseDetailVO = commonService.copyProperties(course, CourseDetailVO.class);
LambdaQueryWrapper<CourseChapter> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(CourseChapter::getCourseId, id);
List<CourseChapter> courseChapterList = courseChapterService.list(lambdaQueryWrapper);
List<CourseChapterVO> courseChapterVOS = commonService.convertList(courseChapterList, CourseChapterVO.class);
courseDetailVO.setCourseChapters(courseChapterVOS);
return ResultUtils.success(courseDetailVO);
}
/**
* 小程序端用户生成推广码
* @param courseQrcodeAddRequest 课程id
* @return 课程信息列表
*/
@PostMapping("generate/qrcode")
@Operation(summary = "小程序端用户生成推广码", description = "参数课程id权限管理员方法名miniGenerateQrcode")
@RequiresPermission(mustRole = UserConstant.DEFAULT_ROLE)
@SysLog(title = "课程管理", content = "小程序端用户生成推广码")
public BaseResponse<String> miniGenerateQrcode(@Valid @RequestBody CourseQrcodeAddRequest courseQrcodeAddRequest) throws Exception {
String videoView = wechatGetQrcodeService.getWxCourseQrCode(courseQrcodeAddRequest);
return ResultUtils.success(videoView);
}
/**
* web端管理员添加课程
* @param courseAddRequest 课程添加请求体

View File

@ -12,6 +12,7 @@ import com.greenorange.promotion.common.ResultUtils;
import com.greenorange.promotion.config.WxAccessToken;
import com.greenorange.promotion.constant.UserConstant;
import com.greenorange.promotion.model.dto.CommonStringRequest;
import com.greenorange.promotion.model.dto.course.CourseQrcodeAddRequest;
import com.greenorange.promotion.service.wechat.WechatGetQrcodeService;
import com.greenorange.promotion.utils.QRCodeUtil;
import io.swagger.v3.oas.annotations.Hidden;
@ -72,7 +73,7 @@ public class WechatGetQrcodeController {
* @return
* @throws IOException
*/
// @Hidden
@Hidden
@PostMapping("/get/qrcode")
@Operation(summary = "微信小程序获取二维码", description = "参数:无, 权限:所有人, 方法名getQrcode")
// @RequiresPermission(mustRole = UserConstant.DEFAULT_ROLE)
@ -88,13 +89,12 @@ public class WechatGetQrcodeController {
* @return
* @throws IOException
*/
// @Hidden
@Hidden
@PostMapping("/get/course/qrcode")
@Operation(summary = "微信小程序获取课程码", description = "参数:无, 权限:所有人, 方法名getCourseQrcode")
// @RequiresPermission(mustRole = UserConstant.DEFAULT_ROLE)
public BaseResponse<String> getCourseQrcode(@Valid @RequestBody CommonStringRequest commonStringRequest) throws Exception {
String inviteCode = commonStringRequest.getTemplateString();
String view = wechatGetQrcodeService.getWxCourseQrCode(inviteCode);
public BaseResponse<String> getCourseQrcode(@Valid @RequestBody CourseQrcodeAddRequest courseQrcodeAddRequest) throws Exception {
String view = wechatGetQrcodeService.getWxCourseQrCode(courseQrcodeAddRequest);
return ResultUtils.success(view);
}

View File

@ -0,0 +1,78 @@
package com.greenorange.promotion.model.dto.course;
import com.greenorange.promotion.annotation.EnumValue;
import com.greenorange.promotion.model.enums.CourseTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
/**
* 课程推广码生成请求体
*/
@Data
@Schema(description = "课程推广码生成请求体", requiredProperties = {
"id",
"name",
"type",
"image",
"originPrice",
"discountPrice",
"invitationCode"
})
public class CourseQrcodeAddRequest implements Serializable {
/**
* 课程ID
*/
@Min(value = 1L, message = "课程ID ID不能小于1")
@Schema(description = "课程ID", example = "1")
private Long id;
/**
* 课程名称
*/
@NotBlank(message = "课程名称不能为空")
@Schema(description = "课程名称", example = "数据分析工程师训练营")
private String name;
/**
* 课程类别[考公考研,自媒体,财经]
*/
@NotBlank(message = "课程类别不能为空")
@EnumValue(enumClass = CourseTypeEnum.class)
@Schema(description = "课程类别[考公考研,自媒体,财经]", example = "自媒体")
private String type;
/**
* 课程图片URL
*/
@NotBlank(message = "课程图片URL不能为空")
@Schema(description = "课程图片URL", example = "324IEHJDE")
private String image;
/**
* 课程原价
*/
@DecimalMin(value = "0.0", message = "课程原价不能小于0")
@Schema(description = "课程原价", example = "3499")
private BigDecimal originPrice;
/**
* 折扣价格
*/
@DecimalMin(value = "0.0", message = "折扣价格不能小于0")
@Schema(description = "折扣价格", example = "2499")
private BigDecimal discountPrice;
/**
* 邀请码
*/
@Schema(description = "邀请码", example = "666999")
@NotBlank(message = "邀请码不能为空")
private String invitationCode;
}

View File

@ -42,6 +42,7 @@ public class UserInfoRegisterRequest implements Serializable {
* 邀请码
*/
@Schema(description = "邀请码", example = "666999")
@NotBlank(message = "邀请码不能为空")
private String invitationCode;
/**

View File

@ -29,12 +29,12 @@ public class CourseChapter implements Serializable {
/**
* 章节时长(格式可自定义,如"00:10:00"
*/
private String duration;
private Long duration;
/**
* 试看权限
*/
private Object permissions;
private String permissions;
/**
* 视频文件 view 值

View File

@ -0,0 +1,54 @@
package com.greenorange.promotion.model.vo.course;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
@Data
@Schema(description = "课程卡片 视图对象")
public class CourseCardVO implements Serializable {
/**
* 课程ID
*/
@Schema(description = "课程ID", example = "1")
private Long id;
/**
* 课程名称
*/
@Schema(description = "课程名称", example = "数据分析工程师训练营")
private String name;
/**
* 课程类别[考公考研,自媒体,财经]
*/
@Schema(description = "课程类别[考公考研,自媒体,财经]", example = "自媒体")
private String type;
/**
* 课程图片URL
*/
@Schema(description = "课程图片URL", example = "324IEHJDE")
private String image;
/**
* 折扣价格
*/
@Schema(description = "折扣价格", example = "2499")
private BigDecimal discountPrice;
/**
* 已下单人数
*/
@Schema(description = "已下单人数", example = "100")
private Integer orderCount;
@Serial
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,75 @@
package com.greenorange.promotion.model.vo.course;
import com.greenorange.promotion.model.vo.courseChapter.CourseChapterVO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;
@Data
@Schema(description = "课程详情 视图对象")
public class CourseDetailVO implements Serializable {
/**
* 课程ID
*/
@Schema(description = "课程ID", example = "1")
private Long id;
/**
* 课程名称
*/
@Schema(description = "课程名称", example = "数据分析工程师训练营")
private String name;
/**
* 课程类别[考公考研,自媒体,财经]
*/
@Schema(description = "课程类别[考公考研,自媒体,财经]", example = "自媒体")
private String type;
/**
* 课程概述(富文本)
*/
@Schema(description = "课程概述(富文本)", example = "富文本")
private String detail;
/**
* 推广码说明(富文本)
*/
@Schema(description = "推广码说明(富文本)", example = "富文本")
private String promoCodeDesc;
/**
* 课程图片URL
*/
@Schema(description = "课程图片URL", example = "324IEHJDE")
private String image;
/**
* 课程原价
*/
@Schema(description = "课程原价", example = "3499")
private BigDecimal originPrice;
/**
* 折扣价格
*/
@Schema(description = "折扣价格", example = "2499")
private BigDecimal discountPrice;
/**
* 课程章节
*/
@Schema(description = "课程章节")
private List<CourseChapterVO> courseChapters;
@Serial
private static final long serialVersionUID = 1L;
}

View File

@ -1,6 +1,7 @@
package com.greenorange.promotion.service.wechat;
import com.greenorange.promotion.config.WxAccessToken;
import com.greenorange.promotion.model.dto.course.CourseQrcodeAddRequest;
import java.io.IOException;
@ -27,5 +28,5 @@ public interface WechatGetQrcodeService {
/**
* 微信小程序获取课程码
*/
String getWxCourseQrCode(String inviteCode) throws Exception;
String getWxCourseQrCode(CourseQrcodeAddRequest courseQrcodeAddRequest) throws Exception;
}

View File

@ -12,7 +12,9 @@ import com.freewayso.image.combiner.enums.ZoomMode;
import com.google.gson.Gson;
import com.greenorange.promotion.common.ErrorCode;
import com.greenorange.promotion.config.WxAccessToken;
import com.greenorange.promotion.constant.SystemConstant;
import com.greenorange.promotion.exception.BusinessException;
import com.greenorange.promotion.model.dto.course.CourseQrcodeAddRequest;
import com.greenorange.promotion.model.entity.FileInfo;
import com.greenorange.promotion.service.file.FileInfoService;
import com.greenorange.promotion.service.wechat.WechatGetQrcodeService;
@ -197,14 +199,14 @@ public class WechatGetQrcodeServiceImpl implements WechatGetQrcodeService {
*/
@Override
@Transactional(rollbackFor = Exception.class)
public String getWxCourseQrCode(String inviteCode) throws Exception {
public String getWxCourseQrCode(CourseQrcodeAddRequest courseQrcodeAddRequest) throws Exception {
String accessToken = (String) redisTemplate.opsForValue().get(ACCESS_TOKEN_KEY);
if (accessToken == null) {
accessToken = this.getAccessToken().getAccess_token();
}
Map<String, Object> param = new HashMap<>();
param.put("page", "pages/loginModule/register/register");
param.put("scene", "invitationCode=" + inviteCode);
param.put("scene", "invitationCode=" + courseQrcodeAddRequest.getInvitationCode());
param.put("width", 430);
param.put("check_path", false);
param.put("env_version", "develop");
@ -216,9 +218,9 @@ public class WechatGetQrcodeServiceImpl implements WechatGetQrcodeService {
.execute()
.bodyBytes();
String courseTitle = "【早鸟42折】掌握CAD技能实战技能实战技能实战技能实战工作训练营";
String originalPrice = "2680元";
String discountPrice = "1680";
String courseTitle = courseQrcodeAddRequest.getName();
String originalPrice = String.valueOf(courseQrcodeAddRequest.getOriginPrice());
String discountPrice = String.valueOf(courseQrcodeAddRequest.getDiscountPrice());
String discountText = "元券后价";
String FontType = "Microsoft YaHei UI";
int FontStyle = Font.PLAIN;
@ -228,7 +230,7 @@ public class WechatGetQrcodeServiceImpl implements WechatGetQrcodeService {
ImageCombiner combiner = new ImageCombiner(blankUrl, 341, 391, ZoomMode.WidthHeight, OutputFormat.PNG);
// 加载课程图片
String courseUrl = "https://img.picui.cn/free/2025/06/22/6856ef5908d4b.jpg";
String courseUrl = SystemConstant.FILE_COMMON_PREFIX + courseQrcodeAddRequest.getImage();
BufferedImage courseImage = ImageIO.read(new URL(courseUrl));
// Graphics2D graphics = courseImage.createGraphics();
@ -314,18 +316,6 @@ public class WechatGetQrcodeServiceImpl implements WechatGetQrcodeService {
return biz + "-" + view;
}
public static void main(String[] args) {
// 获取本地图形环境
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
// 列出所有可用字体家族名
String[] families = ge.getAvailableFontFamilyNames();
// 打印全部字体(可选)
System.out.println("=== Available Font Families ===");
Arrays.stream(families).forEach(System.out::println);
}