添加了课程模块的功能:

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 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.constant.UserConstant;
import com.greenorange.promotion.model.dto.CommonBatchRequest; import com.greenorange.promotion.model.dto.CommonBatchRequest;
import com.greenorange.promotion.model.dto.CommonRequest; 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.CourseAddRequest;
import com.greenorange.promotion.model.dto.course.CourseQrcodeAddRequest;
import com.greenorange.promotion.model.dto.course.CourseQueryRequest; import com.greenorange.promotion.model.dto.course.CourseQueryRequest;
import com.greenorange.promotion.model.dto.course.CourseUpdateRequest; import com.greenorange.promotion.model.dto.course.CourseUpdateRequest;
import com.greenorange.promotion.model.entity.Course; import com.greenorange.promotion.model.entity.Course;
import com.greenorange.promotion.model.entity.CourseChapter; 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.course.CourseVO;
import com.greenorange.promotion.model.vo.courseChapter.CourseChapterVO;
import com.greenorange.promotion.service.common.CommonService; import com.greenorange.promotion.service.common.CommonService;
import com.greenorange.promotion.service.course.CourseChapterService; import com.greenorange.promotion.service.course.CourseChapterService;
import com.greenorange.promotion.service.course.CourseService; 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.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
@ -52,6 +58,64 @@ public class CourseController {
@Resource @Resource
private CourseChapterService courseChapterService; 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端管理员添加课程 * web端管理员添加课程
* @param courseAddRequest 课程添加请求体 * @param courseAddRequest 课程添加请求体

View File

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

View File

@ -29,12 +29,12 @@ public class CourseChapter implements Serializable {
/** /**
* 章节时长(格式可自定义,如"00:10:00" * 章节时长(格式可自定义,如"00:10:00"
*/ */
private String duration; private Long duration;
/** /**
* 试看权限 * 试看权限
*/ */
private Object permissions; private String permissions;
/** /**
* 视频文件 view 值 * 视频文件 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; package com.greenorange.promotion.service.wechat;
import com.greenorange.promotion.config.WxAccessToken; import com.greenorange.promotion.config.WxAccessToken;
import com.greenorange.promotion.model.dto.course.CourseQrcodeAddRequest;
import java.io.IOException; 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.google.gson.Gson;
import com.greenorange.promotion.common.ErrorCode; import com.greenorange.promotion.common.ErrorCode;
import com.greenorange.promotion.config.WxAccessToken; import com.greenorange.promotion.config.WxAccessToken;
import com.greenorange.promotion.constant.SystemConstant;
import com.greenorange.promotion.exception.BusinessException; 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.model.entity.FileInfo;
import com.greenorange.promotion.service.file.FileInfoService; import com.greenorange.promotion.service.file.FileInfoService;
import com.greenorange.promotion.service.wechat.WechatGetQrcodeService; import com.greenorange.promotion.service.wechat.WechatGetQrcodeService;
@ -197,14 +199,14 @@ public class WechatGetQrcodeServiceImpl implements WechatGetQrcodeService {
*/ */
@Override @Override
@Transactional(rollbackFor = Exception.class) @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); String accessToken = (String) redisTemplate.opsForValue().get(ACCESS_TOKEN_KEY);
if (accessToken == null) { if (accessToken == null) {
accessToken = this.getAccessToken().getAccess_token(); accessToken = this.getAccessToken().getAccess_token();
} }
Map<String, Object> param = new HashMap<>(); Map<String, Object> param = new HashMap<>();
param.put("page", "pages/loginModule/register/register"); param.put("page", "pages/loginModule/register/register");
param.put("scene", "invitationCode=" + inviteCode); param.put("scene", "invitationCode=" + courseQrcodeAddRequest.getInvitationCode());
param.put("width", 430); param.put("width", 430);
param.put("check_path", false); param.put("check_path", false);
param.put("env_version", "develop"); param.put("env_version", "develop");
@ -216,9 +218,9 @@ public class WechatGetQrcodeServiceImpl implements WechatGetQrcodeService {
.execute() .execute()
.bodyBytes(); .bodyBytes();
String courseTitle = "【早鸟42折】掌握CAD技能实战技能实战技能实战技能实战工作训练营"; String courseTitle = courseQrcodeAddRequest.getName();
String originalPrice = "2680元"; String originalPrice = String.valueOf(courseQrcodeAddRequest.getOriginPrice());
String discountPrice = "1680"; String discountPrice = String.valueOf(courseQrcodeAddRequest.getDiscountPrice());
String discountText = "元券后价"; String discountText = "元券后价";
String FontType = "Microsoft YaHei UI"; String FontType = "Microsoft YaHei UI";
int FontStyle = Font.PLAIN; int FontStyle = Font.PLAIN;
@ -228,7 +230,7 @@ public class WechatGetQrcodeServiceImpl implements WechatGetQrcodeService {
ImageCombiner combiner = new ImageCombiner(blankUrl, 341, 391, ZoomMode.WidthHeight, OutputFormat.PNG); 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)); BufferedImage courseImage = ImageIO.read(new URL(courseUrl));
// Graphics2D graphics = courseImage.createGraphics(); // Graphics2D graphics = courseImage.createGraphics();
@ -314,18 +316,6 @@ public class WechatGetQrcodeServiceImpl implements WechatGetQrcodeService {
return biz + "-" + view; 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);
}