Compare commits

...

11 Commits

64 changed files with 921 additions and 194 deletions

View File

@ -109,6 +109,10 @@
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
<build>

View File

@ -1,4 +1,4 @@
package com.seer.teach.common.config;
package com.seer.teach.admin.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;

View File

@ -58,5 +58,10 @@
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-redis-template</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -25,5 +25,9 @@
<artifactId>common-validation</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,36 @@
package com.seer.teach.common.enums.teacher;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum ReportTypeEnum {
DAILY(0, "今天"),
WEEKLY(1, "本周"),
MONTHLY(2, "本月");
private final Integer type;
private final String desc;
@JsonCreator
public static ReportTypeEnum fromType(Integer type) {
for (ReportTypeEnum e : values()) {
if (e.type.equals(type)) {
return e;
}
}
throw new IllegalArgumentException("非法报告类型type:" + type);
}
@JsonValue
public Integer getType() {
return type;
}
}

View File

@ -1,5 +1,7 @@
package com.seer.teach.common.utils;
import com.seer.teach.common.enums.teacher.ReportTypeEnum;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
@ -29,6 +31,7 @@ public class DateUtils {
/**
* 根据创建时间计算距离当前时间相差多少天
*
* @param createTime 创建时间LocalDateTime
* @return 相差的天数例如5
*/
@ -43,46 +46,54 @@ public class DateUtils {
/**
* Ai报告获取开始时间
* @param type 1-本周2-本天
* @return 开始时间
* 获取开始时间
*
* @param type 类型
* @return LocalDateTime对象
*/
public static LocalDateTime getStartTime(Integer type) {
if (type == 1) {
//
public static LocalDateTime getStartTime(ReportTypeEnum type) {
if (type.getType().equals(0)) {
//
return LocalDate.now().atStartOfDay();
} else if(type == 0){
} else if (type.getType().equals(1)) {
// 本周
return LocalDate.now().with(DayOfWeek.MONDAY).atStartOfDay();
} else if (type.getType().equals(2)) {
// 本月
return LocalDate.now().withDayOfMonth(1).atStartOfDay();
} else {
throw new IllegalArgumentException("type只能为0或1");
throw new IllegalArgumentException("type只能为0、1或2");
}
}
/**
* 将秒数转换为小时或者天
*
* @param seconds 秒数
* @param type 1-本周2-
* @param type 0-今天1-本周2-
* @return 时间字符串
*/
public static String formatSecondsToHourMinute(Integer seconds, Integer type) {
if (type == 1) {
// 本天转换为小时
int hours = seconds / 3600;
return hours + "小时";
} else if (type == 0){
// 本周转换为天
public static String formatSecondsToHourMinute(Integer seconds, ReportTypeEnum type) {
if (type.getType().equals(0)) {
// 今天转换为小时和分钟
return formatSecondsToHourAndMinute(seconds);
} else if (type.getType().equals(1) || type.getType().equals(2)) {
// 本周和本月转换为天
int days = seconds / 86400;
return days + "";
} else {
throw new IllegalArgumentException("type只能为0或1");
throw new IllegalArgumentException("type只能为0、1或2");
}
}
public static String formatSecondsToHourAndMinute(Integer seconds) {
int hours = seconds / 3600;
int minutes = (seconds % 3600) / 60;
return hours + "小时" + minutes + "";
if (hours > 0) {
return hours + "小时" + minutes + "分钟";
} else {
return minutes + "分钟";
}
}
}

View File

@ -287,7 +287,7 @@
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-redis</artifactId>
<artifactId>sa-token-redis-template</artifactId>
<version>${sa-token-version}</version>
</dependency>

View File

@ -46,7 +46,7 @@ public class LoadBalancerConfig {
String ip = Optional.ofNullable(exchange.getRequest().getRemoteAddress())
.map(addr -> addr.getAddress().getHostAddress())
.orElse("unknown");
log.info("请求来自客户端: {}", ip);
log.info("ipForwardFilter 请求来自客户端: {}", ip);
ServerHttpRequest mutatedRequest = exchange.getRequest().mutate()
.header("X-Forwarded-For", ip)
.build();

View File

@ -16,7 +16,7 @@ import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
@Slf4j
@Component
// @Component
public class CorsFilter implements WebFilter {
private static final String MAX_AGE = String.valueOf(1000 * 60 * 60 * 24);

View File

@ -19,7 +19,7 @@ import java.time.LocalDateTime;
*/
@Getter
@Setter
@TableName("mp_activities")
@TableName("mp_activity")
@Schema(name = "MpAgentActivityEntity对象", description = "活动表")
public class MpActivityEntity extends BaseEntity {
@ -47,6 +47,8 @@ public class MpActivityEntity extends BaseEntity {
@TableField("end_time")
private LocalDateTime endTime;
/**
* 活动状态0-禁用1-启用
*/

View File

@ -17,7 +17,7 @@ import lombok.Setter;
*/
@Getter
@Setter
@TableName("mp_agent_activity_participants")
@TableName("mp_agent_activity_participant")
@Schema(name = "MpAgentActivityParticipantEntity对象", description = "代理商活动参与记录表")
public class MpAgentActivityParticipantEntity extends BaseEntity {
@ -28,8 +28,26 @@ public class MpAgentActivityParticipantEntity extends BaseEntity {
private Integer activityId;
/**
* 代理商ID对应user表的ID
* 代理商ID
*/
@TableField("agent_id")
private Integer agentId;
/**
* 活动名称
*/
@TableField("activity_name")
private String activityName;
/**
* 代理商名称
*/
@TableField("agent_name")
private String agentName;
/**
* 活动二维码 url
*/
@TableField("qr_code_url")
private String qrCodeUrl;
}

View File

@ -17,7 +17,7 @@ import lombok.Setter;
*/
@Getter
@Setter
@TableName("mp_agent_employee_relations")
@TableName("mp_agent_employee_relation")
@Schema(name = "MpAgentEmployeeRelationEntity对象", description = "代理商员工关联表")
public class MpAgentEmployeeRelationEntity extends BaseEntity {
@ -33,6 +33,13 @@ public class MpAgentEmployeeRelationEntity extends BaseEntity {
@TableField("employee_user_id")
private Integer employeeUserId;
@TableField("agent_name")
private String agentName;
@TableField("employee_name")
private String employeeName;
/**
* 员工职位
*/

View File

@ -8,7 +8,7 @@ import lombok.Data;
* 代理商实体类
*/
@Data
@TableName("mp_agents")
@TableName("mp_agent")
public class MpAgentEntity extends BaseEntity {
/**

View File

@ -12,6 +12,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@ -30,9 +31,9 @@ public class AdminActivityController {
private final IAdminActivityService agentActivityService;
@Operation(summary = "活动列表")
@GetMapping("/page-list")
@PostMapping("/page-list")
@SaCheckPermission("mp:admin:agent:activity:list")
public ResultBean<PageListBean<AdminActivityResp>> pageList(MpActivityQueryReq query) {
public ResultBean<PageListBean<AdminActivityResp>> pageList(@RequestBody @Validated MpActivityQueryReq query) {
return ResultBean.success(agentActivityService.pageList(query));
}

View File

@ -10,6 +10,7 @@ import com.seer.teach.mp.admin.service.IAdminAgentActivityLogService;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@ -24,9 +25,9 @@ public class AdminAgentActivityLogController {
private final IAdminAgentActivityLogService adminAgentActivityLogService;
@Operation(summary = "代理商活动操作日志列表")
@GetMapping("/page-list")
@PostMapping("/page-list")
@SaCheckPermission("mp:admin:agent:activity:log:list")
public ResultBean<PageListBean<AdminAgentActivityLogResp>> pageList(AgentActivityLogQueryReq query) {
public ResultBean<PageListBean<AdminAgentActivityLogResp>> pageList(@RequestBody @Validated AgentActivityLogQueryReq query) {
return ResultBean.success(adminAgentActivityLogService.pageList(query));
}

View File

@ -5,20 +5,17 @@ import com.seer.teach.common.PageListBean;
import com.seer.teach.common.ResultBean;
import com.seer.teach.common.annotation.LogPrint;
import com.seer.teach.mp.admin.controller.req.AgentActivityParticipantQueryReq;
import com.seer.teach.mp.admin.controller.req.AgentActivityParticipantReq;
import com.seer.teach.mp.admin.controller.resp.AdminAgentActivityParticipantResp;
import com.seer.teach.mp.admin.service.IAdminAgentActivityParticipantService;
import com.seer.teach.mp.entity.MpAgentActivityParticipantEntity;
import com.seer.teach.mp.service.IMpActivityService;
import com.seer.teach.mp.service.IMpAgentService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.DeleteMapping;
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 org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@ -31,6 +28,10 @@ public class AdminAgentActivityParticipantController {
private final IAdminAgentActivityParticipantService adminAgentActivityParticipantService;
private final IMpAgentService mpAgentService;
private final IMpActivityService mpActivityService;
@Operation(summary = "代理商活动参与记录列表")
@GetMapping("/page-list")
@SaCheckPermission("mp:admin:agent:activity:participant:list")
@ -48,8 +49,8 @@ public class AdminAgentActivityParticipantController {
@Operation(summary = "新增")
@PostMapping
@SaCheckPermission("mp:admin:agent:activity:participant:save")
public ResultBean<Boolean> save(@RequestBody MpAgentActivityParticipantEntity participantEntity) {
return ResultBean.success(adminAgentActivityParticipantService.saveParticipant(participantEntity));
public ResultBean<Boolean> save(@RequestBody @Validated AgentActivityParticipantReq req) {
return ResultBean.success(adminAgentActivityParticipantService.saveParticipant(req));
}
@Operation(summary = "更新")
@ -63,10 +64,19 @@ public class AdminAgentActivityParticipantController {
@DeleteMapping
@SaCheckPermission("mp:admin:agent:activity:participant:delete")
public ResultBean<Boolean> delete(@RequestBody List<Integer> ids) {
boolean result = true;
for (Integer id : ids) {
result &= adminAgentActivityParticipantService.deleteParticipant(id);
return ResultBean.success(adminAgentActivityParticipantService.deleteById(ids));
}
return ResultBean.success(result);
@Operation(summary = "查询代理商名称")
@GetMapping("/agent-name")
public ResultBean<List<String>> getAgentName() {
return ResultBean.success(mpAgentService.getAgentName());
}
@Operation(summary = "查询活动名称")
@GetMapping("/activity-name")
public ResultBean<List<String>> getActivityName() {
return ResultBean.success(mpActivityService.getActivityName());
}
}

View File

@ -11,6 +11,7 @@ import com.seer.teach.mp.entity.MpAgentEntity;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@ -25,9 +26,9 @@ public class AdminAgentController {
private final AdminAgentService adminAgentService;
@Operation(summary = "代理商列表")
@GetMapping("/page-list")
@PostMapping("/page-list")
@SaCheckPermission("mp:admin:agent:list")
public ResultBean<PageListBean<AgentResp>> pageList(AgentQueryReq query) {
public ResultBean<PageListBean<AgentResp>> pageList(@RequestBody @Validated AgentQueryReq query) {
return ResultBean.success(adminAgentService.pageList(query));
}

View File

@ -6,19 +6,14 @@ import com.seer.teach.common.ResultBean;
import com.seer.teach.common.annotation.LogPrint;
import com.seer.teach.mp.admin.controller.req.AgentEmployeeRelationQueryReq;
import com.seer.teach.mp.admin.controller.req.AgentEmployeeRelationReq;
import com.seer.teach.mp.admin.controller.req.AgentEmployeeSaveReq;
import com.seer.teach.mp.admin.controller.resp.AgentEmployeeRelationResp;
import com.seer.teach.mp.admin.service.IAdminAgentEmployeeRelationService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.DeleteMapping;
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 org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@LogPrint
@RequiredArgsConstructor
@ -30,16 +25,23 @@ public class AdminAgentEmployeeRelationController {
private final IAdminAgentEmployeeRelationService agentEmployeeRelationService;
@Operation(summary = "代理商员工关联列表")
@GetMapping("/page-list")
@PostMapping("/page-list")
@SaCheckPermission("mp:admin:agent:employee:list")
public ResultBean<PageListBean<AgentEmployeeRelationResp>> pageList(AgentEmployeeRelationQueryReq query) {
public ResultBean<PageListBean<AgentEmployeeRelationResp>> pageList(@RequestBody @Validated AgentEmployeeRelationQueryReq query) {
return ResultBean.success(agentEmployeeRelationService.pageList(query));
}
@Operation(summary = "创建或更新代理商员工关联")
@Operation(summary = "代理商员工关联")
@PostMapping("/save")
@SaCheckPermission("mp:admin:agent:employee:save")
public ResultBean<Boolean> save(@Valid @RequestBody AgentEmployeeRelationReq request) {
public ResultBean<Boolean> save(@RequestBody @Validated AgentEmployeeSaveReq request) {
return ResultBean.success(agentEmployeeRelationService.save(request));
}
@Operation(summary = "更新代理商员工关联")
@PostMapping("/update")
@SaCheckPermission("mp:admin:agent:employee:update")
public ResultBean<Boolean> update(@RequestBody @Validated AgentEmployeeRelationReq request) {
return ResultBean.success(agentEmployeeRelationService.saveOrUpdateRelation(request));
}

View File

@ -22,12 +22,9 @@ public class AgentActivityParticipantQueryReq {
@Schema(description = "每页数量")
private Integer pageSize = 10;
@Schema(description = "活动ID")
private Integer activityId;
@Schema(description = "活动名称")
private String activityName;
@Schema(description = "代理商ID")
private Integer agentId;
@Schema(description = "家长ID")
private Integer parentId;
@Schema(description = "代理商名称")
private String agentName;
}

View File

@ -0,0 +1,18 @@
package com.seer.teach.mp.admin.controller.req;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
@Data
@Schema(name = "代理商活动参与请求对象")
public class AgentActivityParticipantReq {
@Schema(description = "代理商名称")
@NotBlank(message = "代理商名称不能为空")
private String agentName;
@Schema(description = "活动名称")
@NotBlank(message = "活动名称不能为空")
private String activityName;
}

View File

@ -8,11 +8,11 @@ import lombok.Data;
@Data
public class AgentEmployeeRelationQueryReq extends PageRequest {
@Schema(description = "代理商ID")
private Integer agentId;
@Schema(description = "代理商名称")
private String agentName;
@Schema(description = "员工用户ID")
private Integer employeeUserId;
@Schema(description = "员工名称")
private String employeeName;
@Schema(description = "员工状态0-禁用1-启用")
private Integer status;

View File

@ -0,0 +1,25 @@
package com.seer.teach.mp.admin.controller.req;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Data
@Schema(name = "AgentEmployeeSaveReq", description = "新增代理商员工请求参数")
public class AgentEmployeeSaveReq {
@Schema(description = "代理商名称")
@NotNull(message = "代理商名称不能为空")
private String agentName;
@Schema(description = "员工名称")
@NotNull(message = "员工名称不能为空")
private String employeeName;
@Schema(description = "员工职位")
private String position;
@Schema(description = "员工状态0-禁用1-启用")
private Integer status = 1;
}

View File

@ -25,6 +25,12 @@ public class AdminAgentActivityParticipantResp {
@Schema(description = "代理商ID")
private Integer agentId;
@Schema(description = "代理商名称")
private String agentName;
@Schema(description = "活动名称")
private String activityName;
@Schema(description = "创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;

View File

@ -14,9 +14,15 @@ public class AgentEmployeeRelationResp {
@Schema(description = "代理商ID")
private Integer agentId;
@Schema(description = "代理商名称")
private String agentName;
@Schema(description = "员工用户ID")
private Integer employeeUserId;
@Schema(description = "员工名称")
private String employeeName;
@Schema(description = "员工职位")
private String position;

View File

@ -1,5 +1,6 @@
package com.seer.teach.mp.admin.convert;
import com.seer.teach.mp.admin.controller.req.AgentActivityParticipantReq;
import com.seer.teach.mp.admin.controller.resp.AdminAgentActivityParticipantResp;
import com.seer.teach.mp.entity.MpAgentActivityParticipantEntity;
import org.mapstruct.Mapper;
@ -15,4 +16,7 @@ public interface AdminAgentActivityParticipantConvert {
AdminAgentActivityParticipantResp convertToResp(MpAgentActivityParticipantEntity entity);
List<AdminAgentActivityParticipantResp> convertToRespList(List<MpAgentActivityParticipantEntity> entity);
MpAgentActivityParticipantEntity convertToEntity(AgentActivityParticipantReq entity);
}

View File

@ -2,6 +2,7 @@ package com.seer.teach.mp.admin.convert;
import com.seer.teach.mp.admin.controller.req.AgentEmployeeRelationQueryReq;
import com.seer.teach.mp.admin.controller.req.AgentEmployeeRelationReq;
import com.seer.teach.mp.admin.controller.req.AgentEmployeeSaveReq;
import com.seer.teach.mp.admin.controller.resp.AgentEmployeeRelationResp;
import com.seer.teach.mp.entity.MpAgentEmployeeRelationEntity;
import org.mapstruct.Mapper;
@ -21,4 +22,6 @@ public interface AdminAgentEmployeeRelationConvert {
AgentEmployeeRelationResp convertToResp(MpAgentEmployeeRelationEntity entity);
List<AgentEmployeeRelationResp> convertToRespList(List<MpAgentEmployeeRelationEntity> mpAgentEmployeeRelationEntities);
MpAgentEmployeeRelationEntity convert(AgentEmployeeSaveReq request);
}

View File

@ -36,7 +36,10 @@ public class AdminAgentService {
MpAgentEntity query = AgentConvert.INSTANCE.convertOne(pageReq);
IPage<MpAgentEntity> resultPage = mpAgentService.page(pageParam, new LambdaQueryWrapper<>(MpAgentEntity.class)
.like(StringUtils.isNotBlank(query.getAgentName()), MpAgentEntity::getAgentName, query.getAgentName())
.eq(query.getStatus() != null, MpAgentEntity::getStatus, query.getStatus())
.like(StringUtils.isNotBlank(query.getContactName()), MpAgentEntity::getContactName, query.getContactName())
.like(StringUtils.isNotBlank(query.getAgentCode()), MpAgentEntity::getAgentCode, query.getAgentCode())
.like(StringUtils.isNotBlank(query.getAgentLevel()), MpAgentEntity::getAgentLevel, query.getAgentLevel())
.like(StringUtils.isNotBlank(query.getContactPhone()), MpAgentEntity::getContactPhone, query.getContactPhone()));
return PageConverterUtils.convertPageListBean(resultPage, AgentConvert.INSTANCE::convertRespList);
@ -84,13 +87,13 @@ public class AdminAgentService {
* @return 是否成功
*/
public Boolean deleteById(List<Integer> ids) {
if(ids == null || ids.isEmpty()){
if (ids == null || ids.isEmpty()) {
log.warn("删除代理商时ID列表为空");
return false;
}
boolean result = mpAgentService.removeByIds(ids);
log.info("删除代理商结果: {}", result);
if(result){
if (result) {
log.info("删除代理商成功ID列表: {}", ids);
}
return result;

View File

@ -2,9 +2,12 @@ package com.seer.teach.mp.admin.service;
import com.seer.teach.common.PageListBean;
import com.seer.teach.mp.admin.controller.req.AgentActivityParticipantQueryReq;
import com.seer.teach.mp.admin.controller.req.AgentActivityParticipantReq;
import com.seer.teach.mp.admin.controller.resp.AdminAgentActivityParticipantResp;
import com.seer.teach.mp.entity.MpAgentActivityParticipantEntity;
import java.util.List;
/**
* <p>
* 代理商活动参与记录表 管理端服务类
@ -29,7 +32,7 @@ public interface IAdminAgentActivityParticipantService {
* @param entity 参与记录实体
* @return 操作是否成功
*/
boolean saveParticipant(MpAgentActivityParticipantEntity entity);
boolean saveParticipant(AgentActivityParticipantReq entity);
/**
* 更新代理商活动参与记录管理端
@ -39,14 +42,6 @@ public interface IAdminAgentActivityParticipantService {
*/
boolean updateParticipant(MpAgentActivityParticipantEntity entity);
/**
* 根据ID删除代理商活动参与记录管理端
*
* @param id 参与记录ID
* @return 操作是否成功
*/
boolean deleteParticipant(Integer id);
/**
* 根据ID获取代理商活动参与记录详情管理端
*
@ -54,4 +49,12 @@ public interface IAdminAgentActivityParticipantService {
* @return 参与记录详情
*/
AdminAgentActivityParticipantResp getById(Integer id);
/**
* 根据ID删除代理商活动参与记录管理端
*
* @param ids 参与记录ID
* @return 操作是否成功
*/
Boolean deleteById(List<Integer> ids);
}

View File

@ -1,6 +1,7 @@
package com.seer.teach.mp.admin.service;
import com.seer.teach.common.PageListBean;
import com.seer.teach.mp.admin.controller.req.AgentEmployeeSaveReq;
import com.seer.teach.mp.admin.controller.resp.AgentEmployeeRelationResp;
import com.seer.teach.mp.admin.controller.req.AgentEmployeeRelationQueryReq;
import com.seer.teach.mp.admin.controller.req.AgentEmployeeRelationReq;
@ -56,4 +57,11 @@ public interface IAdminAgentEmployeeRelationService {
* @return 员工关联列表
*/
List<AgentEmployeeRelationResp> getEmployeeRelationsByAgentId(Integer agentId);
/**
* 新增代理商员工关联管理端
* @param request 新增代理商员工关联请求对象
* @return 新增是否成功
*/
boolean save(AgentEmployeeSaveReq request);
}

View File

@ -13,8 +13,6 @@ import com.seer.teach.mp.service.IMpAgentActivityLogService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* <p>
* 代理商活动操作日志表 管理端服务实现类
@ -32,31 +30,13 @@ public class AdminAgentActivityLogServiceImpl implements IAdminAgentActivityLogS
@Override
public PageListBean<AdminAgentActivityLogResp> pageList(AgentActivityLogQueryReq query) {
Page<MpAgentActivityLogEntity> page = new Page<>(query.getPageNum(), query.getPageSize());
LambdaQueryWrapper<MpAgentActivityLogEntity> wrapper = new LambdaQueryWrapper<>();
// 根据活动ID查询
if (query.getActivityId() != null) {
wrapper.eq(MpAgentActivityLogEntity::getActivityId, query.getActivityId());
}
// 根据操作人ID查询
if (query.getOperatorId() != null) {
wrapper.eq(MpAgentActivityLogEntity::getOperatorId, query.getOperatorId());
}
// 根据操作类型查询
if (query.getOperationType() != null && !query.getOperationType().isEmpty()) {
wrapper.eq(MpAgentActivityLogEntity::getOperationType, query.getOperationType());
}
// 根据创建时间范围查询
if (query.getStartTime() != null) {
wrapper.ge(MpAgentActivityLogEntity::getCreateTime, query.getStartTime());
}
if (query.getEndTime() != null) {
wrapper.le(MpAgentActivityLogEntity::getCreateTime, query.getEndTime());
}
wrapper.eq(query.getActivityId() != null, MpAgentActivityLogEntity::getActivityId, query.getActivityId())
.eq(query.getOperatorId() != null, MpAgentActivityLogEntity::getOperatorId, query.getOperatorId())
.eq(query.getOperationType() != null, MpAgentActivityLogEntity::getOperationType, query.getOperationType())
.ge(query.getStartTime() != null, MpAgentActivityLogEntity::getCreateTime, query.getStartTime())
.le(query.getEndTime() != null, MpAgentActivityLogEntity::getCreateTime, query.getEndTime())
.orderByDesc(MpAgentActivityLogEntity::getUpdateTime);
IPage<MpAgentActivityLogEntity> result = mpAgentActivityLogService.page(page, wrapper);

View File

@ -1,19 +1,25 @@
package com.seer.teach.mp.admin.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.seer.teach.common.PageListBean;
import com.seer.teach.common.utils.PageConverterUtils;
import com.seer.teach.mp.admin.controller.req.AgentActivityParticipantQueryReq;
import com.seer.teach.mp.admin.controller.req.AgentActivityParticipantReq;
import com.seer.teach.mp.admin.controller.resp.AdminAgentActivityParticipantResp;
import com.seer.teach.mp.admin.convert.AdminAgentActivityParticipantConvert;
import com.seer.teach.mp.admin.service.IAdminAgentActivityParticipantService;
import com.seer.teach.mp.entity.MpActivityEntity;
import com.seer.teach.mp.entity.MpAgentActivityParticipantEntity;
import com.seer.teach.mp.entity.MpAgentEntity;
import com.seer.teach.mp.service.IMpActivityService;
import com.seer.teach.mp.service.IMpAgentActivityParticipantService;
import com.seer.teach.mp.service.IMpAgentService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* <p>
* 代理商活动参与记录表 管理端服务实现类
@ -28,66 +34,78 @@ public class AdminAgentActivityParticipantServiceImpl implements IAdminAgentActi
private final IMpAgentActivityParticipantService mpAgentActivityParticipantService;
private final IMpAgentService mpAgentService;
private final IMpActivityService mpActivityService;
@Override
public PageListBean<AdminAgentActivityParticipantResp> pageList(AgentActivityParticipantQueryReq query) {
Page<MpAgentActivityParticipantEntity> page = new Page<>(query.getPageNum(), query.getPageSize());
LambdaQueryWrapper<MpAgentActivityParticipantEntity> wrapper = new LambdaQueryWrapper<>();
// 根据活动ID查询
if (query.getActivityId() != null) {
wrapper.eq(MpAgentActivityParticipantEntity::getActivityId, query.getActivityId());
if (query.getActivityName() != null) {
wrapper.like(MpAgentActivityParticipantEntity::getActivityName, query.getActivityName());
}
// 根据代理商ID查询
if (query.getAgentId() != null) {
wrapper.eq(MpAgentActivityParticipantEntity::getAgentId, query.getAgentId());
if (query.getAgentName() != null) {
wrapper.like(MpAgentActivityParticipantEntity::getAgentName, query.getAgentName());
}
IPage<MpAgentActivityParticipantEntity> result = mpAgentActivityParticipantService.page(page, wrapper);
Page<MpAgentActivityParticipantEntity> result = mpAgentActivityParticipantService.page(page, wrapper);
return PageConverterUtils.convertPageListBean(result, AdminAgentActivityParticipantConvert.INSTANCE::convertToRespList);
}
@Override
public boolean saveParticipant(MpAgentActivityParticipantEntity entity) {
public boolean saveParticipant(AgentActivityParticipantReq entity) {
// 检查是否已存在相同的活动代理商和家长记录
LambdaQueryWrapper<MpAgentActivityParticipantEntity> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(MpAgentActivityParticipantEntity::getActivityId, entity.getActivityId())
.eq(MpAgentActivityParticipantEntity::getAgentId, entity.getAgentId());
wrapper.eq(MpAgentActivityParticipantEntity::getActivityName, entity.getActivityName())
.eq(MpAgentActivityParticipantEntity::getAgentName, entity.getAgentName());
long count = mpAgentActivityParticipantService.count(wrapper);
if (count > 0) {
throw new RuntimeException("该代理商活动参与记录已存在");
}
return mpAgentActivityParticipantService.save(entity);
Integer agentId = mpAgentService.lambdaQuery().eq(MpAgentEntity::getAgentName, entity.getAgentName()).one().getId();
Integer activityId = mpActivityService.lambdaQuery().eq(MpActivityEntity::getActivityName, entity.getActivityName()).one().getId();
MpAgentActivityParticipantEntity result = AdminAgentActivityParticipantConvert.INSTANCE.convertToEntity(entity);
result.setActivityId(activityId);
result.setAgentId(agentId);
return mpAgentActivityParticipantService.save(result);
}
@Override
public boolean updateParticipant(MpAgentActivityParticipantEntity entity) {
// 检查是否存在相同的活动代理商和家长记录排除当前记录
LambdaQueryWrapper<MpAgentActivityParticipantEntity> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(MpAgentActivityParticipantEntity::getActivityId, entity.getActivityId())
.eq(MpAgentActivityParticipantEntity::getAgentId, entity.getAgentId())
wrapper.eq(MpAgentActivityParticipantEntity::getActivityName, entity.getActivityName())
.eq(MpAgentActivityParticipantEntity::getAgentName, entity.getAgentName())
.ne(MpAgentActivityParticipantEntity::getId, entity.getId());
long count = mpAgentActivityParticipantService.count(wrapper);
if (count > 0) {
throw new RuntimeException("该代理商活动参与记录已存在");
}
Integer agentId = mpAgentService.lambdaQuery().eq(MpAgentEntity::getAgentName, entity.getAgentName()).one().getId();
Integer activityId = mpActivityService.lambdaQuery().eq(MpActivityEntity::getActivityName, entity.getActivityName()).one().getId();
entity.setActivityId(activityId);
entity.setAgentId(agentId);
return mpAgentActivityParticipantService.updateById(entity);
}
@Override
public boolean deleteParticipant(Integer id) {
return mpAgentActivityParticipantService.removeById(id);
}
@Override
public AdminAgentActivityParticipantResp getById(Integer id) {
MpAgentActivityParticipantEntity entity = mpAgentActivityParticipantService.getById(id);
return AdminAgentActivityParticipantConvert.INSTANCE.convertToResp(entity);
}
@Override
public Boolean deleteById(List<Integer> ids) {
if (ids == null || ids.isEmpty()) {
return false;
}
return mpAgentActivityParticipantService.removeByIds(ids);
}
}

View File

@ -3,14 +3,19 @@ package com.seer.teach.mp.admin.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.seer.teach.common.PageListBean;
import com.seer.teach.common.enums.ResultCodeEnum;
import com.seer.teach.common.utils.AssertUtils;
import com.seer.teach.common.utils.PageConverterUtils;
import com.seer.teach.mp.admin.controller.req.AgentEmployeeSaveReq;
import com.seer.teach.mp.admin.service.IAdminAgentEmployeeRelationService;
import com.seer.teach.mp.admin.controller.req.AgentEmployeeRelationQueryReq;
import com.seer.teach.mp.admin.controller.req.AgentEmployeeRelationReq;
import com.seer.teach.mp.admin.controller.resp.AgentEmployeeRelationResp;
import com.seer.teach.mp.admin.convert.AdminAgentEmployeeRelationConvert;
import com.seer.teach.mp.entity.MpAgentEmployeeRelationEntity;
import com.seer.teach.mp.entity.MpAgentEntity;
import com.seer.teach.mp.service.IMpAgentEmployeeRelationService;
import com.seer.teach.mp.service.IMpAgentService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@ -31,12 +36,14 @@ public class AdminAgentEmployeeRelationServiceImpl implements IAdminAgentEmploye
private final IMpAgentEmployeeRelationService agentEmployeeRelationService;
private final IMpAgentService mpAgentService;
@Override
public PageListBean<AgentEmployeeRelationResp> pageList(AgentEmployeeRelationQueryReq query) {
Page<MpAgentEmployeeRelationEntity> pageParm = new Page<>(query.getPageNo(), query.getPageSize());
var pageResult = agentEmployeeRelationService.page(pageParm, new LambdaQueryWrapper<>(MpAgentEmployeeRelationEntity.class)
.eq(Objects.nonNull(query.getAgentId()), MpAgentEmployeeRelationEntity::getAgentId, query.getAgentId())
.eq(Objects.nonNull(query.getEmployeeUserId()), MpAgentEmployeeRelationEntity::getEmployeeUserId, query.getEmployeeUserId())
.like(Objects.nonNull(query.getAgentName()), MpAgentEmployeeRelationEntity::getAgentName, query.getAgentName())
.like(Objects.nonNull(query.getEmployeeName()), MpAgentEmployeeRelationEntity::getEmployeeName, query.getEmployeeName())
.eq(Objects.nonNull(query.getStatus()), MpAgentEmployeeRelationEntity::getStatus, query.getStatus()));
return PageConverterUtils.convertPageListBean(pageResult, AdminAgentEmployeeRelationConvert.INSTANCE::convertToRespList);
@ -66,4 +73,12 @@ public class AdminAgentEmployeeRelationServiceImpl implements IAdminAgentEmploye
.map(AdminAgentEmployeeRelationConvert.INSTANCE::convertToResp)
.toList();
}
@Override
public boolean save(AgentEmployeeSaveReq request) {
AssertUtils.isNull(request.getAgentName(), ResultCodeEnum.AGENT_EMPLOYEE_ALREADY_EXISTS);
MpAgentEmployeeRelationEntity relation = AdminAgentEmployeeRelationConvert.INSTANCE.convert(request);
Integer agentId = mpAgentService.lambdaQuery().eq(MpAgentEntity::getAgentName, request.getAgentName()).one().getId();
return true;
}
}

View File

@ -24,6 +24,7 @@ spring:
- optional:nacos:${spring.application.name}-${spring.profiles.active}.yaml
- optional:nacos:shared-database.yaml
- optional:nacos:shared-redis.yaml
- optional:nacos:shared-sa-token.yaml
cloud:
nacos:
discovery:

View File

@ -25,6 +25,8 @@ CREATE TABLE `mp_agent_employee_relation` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '关联ID',
`agent_id` int NOT NULL COMMENT '代理商ID对应user表的ID',
`employee_user_id` int NOT NULL COMMENT '员工用户ID对应user表的ID',
`agent_name` varchar(50) COMMENT '代理商名称',
`employee_name` varchar(50) COMMENT '员工名称',
`position` varchar(50) COMMENT '员工职位',
`status` tinyint NOT NULL DEFAULT '1' COMMENT '员工状态0-禁用1-启用',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
@ -61,8 +63,11 @@ CREATE TABLE `mp_activity` (
DROP TABLE IF EXISTS `mp_agent_activity_participant`;
CREATE TABLE `mp_agent_activity_participant` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '参与记录ID',
`activity_id` int NOT NULL COMMENT '活动ID',
`agent_id` int NOT NULL COMMENT '代理商ID',
`agent_id` int DEFAULT NULL COMMENT '代理商ID对应user表的ID',
`activity_id` int DEFAULT NULL COMMENT '活动ID',
`activity_name` varchar(100) NOT NULL COMMENT '活动名称',
`agent_name` varchar(100) NOT NULL COMMENT '代理商名称',
`qr_code_url` varchar(255) NOT NULL COMMENT '二维码url',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`create_by` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_german2_ci NULL DEFAULT NULL COMMENT '创建人',
`update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',

View File

@ -16,6 +16,7 @@ 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.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
@ -51,4 +52,12 @@ public class AppAgentActivityController {
public ResultBean<AppActivityResp> getDetail(@PathVariable Integer id) {
return ResultBean.success(agentActivityService.getById(id));
}
@Operation(summary = "活动二维码")
@GetMapping("/{agentId}/{activityId}/qrcode")
@SaCheckPermission("mp:app:agent:activity:qrcode")
public ResultBean<String> getQrCode(@PathVariable("agentId") Integer agentId, @PathVariable("activityId") Integer activityId, @RequestParam("appId") String appId) {
Integer userId = StpUtil.getLoginIdAsInt();
return ResultBean.success(agentActivityService.getQrCode(userId,agentId,activityId,appId));
}
}

View File

@ -1,5 +1,6 @@
package com.seer.teach.mp.app.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.stp.StpUtil;
import com.seer.teach.common.ResultBean;
import com.seer.teach.common.annotation.DecryptionAnnotation;
@ -37,6 +38,7 @@ public class AppAgentController {
@Operation(summary = "获取代理商详情")
@GetMapping("/detail")
@SaCheckPermission("mp:app:agent:detail")
public ResultBean<AppMpAgentResp> getAgent() {
Integer userId = StpUtil.getLoginIdAsInt();
return ResultBean.success(appAgentService.getAgentRespByUserId(userId));

View File

@ -1,5 +1,6 @@
package com.seer.teach.mp.app.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.seer.teach.common.ResultBean;
import com.seer.teach.common.annotation.DecryptionAnnotation;
import com.seer.teach.common.annotation.EncryptionAnnotation;
@ -38,6 +39,7 @@ public class AppMpQrCodeController {
*/
@Operation(summary = "生成微信服务号二维码")
@PostMapping("/official/generate")
@SaCheckPermission("mp:app:qrcode:generate")
public ResultBean<MpQrCodeResp> generateOfficialQrCode(@Valid @RequestBody MpGenerateQrCodeReq req) {
return ResultBean.success(appOfficialQrCodeService.generateQrCode(req));
}
@ -48,6 +50,7 @@ public class AppMpQrCodeController {
*/
@Operation(summary = "生成微信小程序二维码")
@PostMapping("/mini/generate")
@SaCheckPermission("mp:app:qrcode:mini-generate")
public ResultBean<String> generateQrCode(@Valid @RequestBody GetQrCodeReq reqParams) {
OssImageUploadResp resp = wechatMiniProgramService.createQrcode(reqParams);
return ResultBean.success(resp.getUrl());

View File

@ -0,0 +1,39 @@
package com.seer.teach.mp.app.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.seer.teach.common.ResultBean;
import com.seer.teach.common.annotation.DecryptionAnnotation;
import com.seer.teach.common.annotation.EncryptionAnnotation;
import com.seer.teach.common.annotation.LogPrint;
import com.seer.teach.mp.app.controller.req.JsapiSignatureReq;
import com.seer.teach.mp.app.controller.resp.JsapiSignatureResp;
import com.seer.teach.mp.app.service.IAppMpSignatureService;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor;
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 jakarta.validation.Valid;
@EncryptionAnnotation
@DecryptionAnnotation
@Tag(name = "APP - 微信JS-SDK签名")
@RestController
@RequestMapping("/app/signature")
@LogPrint
@RequiredArgsConstructor
public class AppMpSignatureController {
private final IAppMpSignatureService appMpSignatureService;
@Operation(summary = "生成JS-SDK签名")
@PostMapping("/jsapi")
@SaCheckPermission("mp:app:signature:jsapi")
public ResultBean<JsapiSignatureResp> generateJsapiSignature(@Valid @RequestBody JsapiSignatureReq req) {
JsapiSignatureResp resp = appMpSignatureService.generateJsapiSignature(req);
return ResultBean.success(resp);
}
}

View File

@ -0,0 +1,22 @@
package com.seer.teach.mp.app.controller.req;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.NotEmpty;
/**
* JS-SDK签名请求参数
*/
@Data
@Schema(description = "JS-SDK签名请求参数")
public class JsapiSignatureReq {
@NotEmpty(message = "URL不能为空")
@Schema(description = "当前网页的URL不包含#及其后面部分")
private String url;
@NotEmpty(message = "appId不能为空")
@Schema(description = "公众号的唯一标识")
private String appId;
}

View File

@ -0,0 +1,34 @@
package com.seer.teach.mp.app.controller.resp;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* JS-SDK签名响应参数
*/
@Data
@Schema(description = "JS-SDK签名响应参数")
public class JsapiSignatureResp {
@Schema(description = "生成签名的时间戳")
private Long timestamp;
@Schema(description = "生成签名的随机串")
private String nonceStr;
@Schema(description = "签名")
private String signature;
@Schema(description = "公众号的唯一标识")
private String appId;
public JsapiSignatureResp() {
}
public JsapiSignatureResp(Long timestamp, String nonceStr, String signature, String appId) {
this.timestamp = timestamp;
this.nonceStr = nonceStr;
this.signature = signature;
this.appId = appId;
}
}

View File

@ -30,4 +30,14 @@ public interface IAppActivityService {
* @return 活动详情
*/
AppActivityResp getById(Integer id);
/**
* 获取活动二维码
*
* @param userId 用户ID
* @param agentId 代理商ID
* @param activityId 活动ID
* @return 活动二维码
*/
String getQrCode(Integer userId,Integer agentId,Integer activityId,String appId);
}

View File

@ -0,0 +1,18 @@
package com.seer.teach.mp.app.service;
import com.seer.teach.mp.app.controller.resp.JsapiSignatureResp;
import com.seer.teach.mp.app.controller.req.JsapiSignatureReq;
/**
* 微信公众号JS-SDK签名服务接口
*/
public interface IAppMpSignatureService {
/**
* 生成JS-SDK签名
*
* @param req 签名请求参数
* @return JS-SDK签名响应参数
*/
JsapiSignatureResp generateJsapiSignature(JsapiSignatureReq req);
}

View File

@ -5,13 +5,22 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.seer.teach.common.PageListBean;
import com.seer.teach.common.enums.ResultCodeEnum;
import com.seer.teach.common.exception.CommonException;
import com.seer.teach.common.utils.AssertUtils;
import com.seer.teach.common.utils.PageConverterUtils;
import com.seer.teach.mp.app.controller.req.AppAgentActivityQueryReq;
import com.seer.teach.mp.app.controller.req.MpGenerateQrCodeReq;
import com.seer.teach.mp.app.controller.resp.AppActivityResp;
import com.seer.teach.mp.app.controller.resp.MpQrCodeResp;
import com.seer.teach.mp.app.convert.AppAgentActivityConvert;
import com.seer.teach.mp.app.service.AppOfficialQrCodeService;
import com.seer.teach.mp.app.service.IAppActivityService;
import com.seer.teach.mp.entity.MpActivityEntity;
import com.seer.teach.mp.entity.MpAgentActivityParticipantEntity;
import com.seer.teach.mp.service.IMpActivityService;
import com.seer.teach.mp.service.IMpAgentActivityParticipantService;
import com.seer.teach.mp.service.IMpAgentService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
@ -34,6 +43,10 @@ public class AppActivityServiceImpl implements IAppActivityService {
private final IMpActivityService activityService;
private final AppOfficialQrCodeService officialQrCodeService;
private final IMpAgentActivityParticipantService agentActivityParticipantService;
@Override
public PageListBean<AppActivityResp> pageList(AppAgentActivityQueryReq query, Integer agentId) {
log.info("查询参数:{}", query);
@ -53,4 +66,27 @@ public class AppActivityServiceImpl implements IAppActivityService {
MpActivityEntity entity = activityService.getById(id);
return AppAgentActivityConvert.INSTANCE.convertToResp(entity);
}
@Override
public String getQrCode(Integer userId,Integer agentId,Integer activityId,String appId) {
MpActivityEntity activity = activityService.getById(activityId);
AssertUtils.notNull(activity, ResultCodeEnum.INVALID_ACTIVITY);
if(activity.getStatus() != 1){
throw new CommonException(ResultCodeEnum.INVALID_ACTIVITY);
}
MpAgentActivityParticipantEntity relation = agentActivityParticipantService.getParticipantsByActivityAndAgent(activityId, agentId);
AssertUtils.notNull(relation, ResultCodeEnum.INVALID_ACTIVITY);
if(StringUtils.isNotBlank(relation.getQrCodeUrl())){
return relation.getQrCodeUrl();
}
MpGenerateQrCodeReq req = new MpGenerateQrCodeReq();
req.setSceneStr("agentId=" + agentId + "&activityId=" + activityId);
req.setAppId(appId);
req.setType(2);
MpQrCodeResp mpQrCodeResp = officialQrCodeService.generateQrCode(req);
relation.setQrCodeUrl(mpQrCodeResp.getQrCodeUrl());
agentActivityParticipantService.updateById(relation);
return mpQrCodeResp.getQrCodeUrl();
}
}

View File

@ -0,0 +1,37 @@
package com.seer.teach.mp.app.service.impl;
import com.seer.teach.mp.app.controller.req.JsapiSignatureReq;
import com.seer.teach.mp.app.controller.resp.JsapiSignatureResp;
import com.seer.teach.mp.app.service.IAppMpSignatureService;
import com.seer.teach.mp.factory.MpServiceFactory;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.WxJsapiSignature;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.stereotype.Service;
/**
* 微信公众号JS-SDK签名服务实现类
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class AppMpSignatureServiceImpl implements IAppMpSignatureService {
private final MpServiceFactory mpServiceFactory;
@Override
public JsapiSignatureResp generateJsapiSignature(JsapiSignatureReq req) {
try {
// 获取WxMpService实例
var mpService = mpServiceFactory.getRequiredMpService(req.getAppId());
WxJsapiSignature wxJsapiSignature = mpService.createJsapiSignature(req.getUrl());
return new JsapiSignatureResp(wxJsapiSignature.getTimestamp(), wxJsapiSignature.getNonceStr(), wxJsapiSignature.getSignature(), req.getAppId());
} catch (WxErrorException e) {
log.error("生成JS-SDK签名失败appId: {}, url: {}", req.getAppId(), req.getUrl(), e);
throw new RuntimeException("生成JS-SDK签名失败", e);
}
}
}

View File

@ -3,6 +3,8 @@ package com.seer.teach.mp.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.seer.teach.mp.entity.MpActivityEntity;
import java.util.List;
/**
* <p>
* 代理商活动表 服务类
@ -29,4 +31,10 @@ public interface IMpActivityService extends IService<MpActivityEntity> {
* @return 操作是否成功
*/
boolean deleteActivity(Integer id);
/**
* 获取代理商活动名称列表
* @return 代理商活动名称列表
*/
List<String> getActivityName();
}

View File

@ -31,4 +31,12 @@ public interface IMpAgentActivityParticipantService extends IService<MpAgentActi
* @return 参与记录列表
*/
List<MpAgentActivityParticipantEntity> getListByAgentId(Integer agentId);
/**
* 根据活动ID获取所有参与记录
*
* @param activityId 活动ID
* @return 参与记录列表
*/
List<MpAgentActivityParticipantEntity> getOneByActivityId(Integer activityId);
}

View File

@ -3,6 +3,8 @@ package com.seer.teach.mp.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.seer.teach.mp.entity.MpAgentEntity;
import java.util.List;
/**
* 代理商服务接口
*/
@ -31,4 +33,10 @@ public interface IMpAgentService extends IService<MpAgentEntity> {
* @return 是否成功
*/
Boolean updateAgent(MpAgentEntity agentEntity);
/**
* 获取代理商名称列表
* @return 代理商名称列表
*/
List<String> getAgentName();
}

View File

@ -16,6 +16,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List;
/**
* <p>
@ -104,6 +105,12 @@ public class MpActivityServiceImpl extends ServiceImpl<MpAgentActivityMapper, Mp
return result;
}
@Override
public List<String> getActivityName() {
return this.list().stream()
.map(MpActivityEntity::getActivityName).toList();
}
@Override
public boolean saveOrUpdate(MpActivityEntity entity) {
boolean result = super.saveOrUpdate(entity);

View File

@ -42,4 +42,9 @@ public class MpAgentActivityParticipantServiceImpl extends ServiceImpl<MpAgentAc
return super.list(new LambdaQueryWrapper<MpAgentActivityParticipantEntity>()
.eq(MpAgentActivityParticipantEntity::getAgentId, agentId));
}
@Override
public List<MpAgentActivityParticipantEntity> getOneByActivityId(Integer activityId) {
return super.list(new LambdaQueryWrapper<MpAgentActivityParticipantEntity>().eq(MpAgentActivityParticipantEntity::getActivityId, activityId));
}
}

View File

@ -6,6 +6,8 @@ import com.seer.teach.mp.mapper.MpAgentMapper;
import com.seer.teach.mp.service.IMpAgentService;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 代理商服务实现类
*/
@ -26,4 +28,10 @@ public class MpAgentServiceImpl extends ServiceImpl<MpAgentMapper, MpAgentEntity
public Boolean updateAgent(MpAgentEntity agentEntity) {
return this.updateById(agentEntity);
}
@Override
public List<String> getAgentName() {
List<MpAgentEntity> list = this.list();
return list.stream().map(MpAgentEntity::getAgentName).toList();
}
}

View File

@ -1,13 +1,13 @@
package com.seer.teach.teacher.common.req;
import com.seer.teach.common.enums.teacher.ReportTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import jakarta.validation.constraints.NotNull;
@Data
@AllArgsConstructor
@ -16,7 +16,7 @@ import jakarta.validation.constraints.NotNull;
@Schema(description = "Ai报告请求实体类")
public class AiReportReq {
@Schema(description = "报告类型(0-本周1-本天)")
@Schema(description ="报告类型(0-今天1-本周2-本月)")
@NotNull(message = "报告类型不能为空")
private Integer type;
private ReportTypeEnum type;
}

View File

@ -1,7 +1,6 @@
package com.seer.teach.teacher.common.resp;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
@ -32,6 +31,9 @@ public class AiReportResp {
@Schema(description = "作业正确率")
private String homeworkCorrectRate;
@Schema(description = "鼓励语句")
private String encourage;
@Schema(description = "科目正确率")
private List<SubjectCorrectRateResp> subjectCorrectRate;
}

View File

@ -0,0 +1,24 @@
package com.seer.teach.teacher.common.resp;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Schema(description = "举一反三类似题目返回实体类")
public class SimilarQuestionResp {
@Schema(description = "题目Id")
private Integer id;
@Schema(description = "做题富文本数据")
private String questionHtml;
@Schema(description = "题型(1单选选择题 2多选选择题 4判断题 6填空题)")
private Integer type;
}

View File

@ -7,8 +7,8 @@ import com.seer.teach.common.annotation.LogPrint;
import com.seer.teach.teacher.common.req.AiReportReq;
import com.seer.teach.teacher.common.resp.AiReportResp;
import com.seer.teach.teacher.service.ReportService;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;

View File

@ -5,19 +5,22 @@ import com.seer.teach.common.ResultBean;
import com.seer.teach.common.annotation.DecryptionAnnotation;
import com.seer.teach.common.annotation.EncryptionAnnotation;
import com.seer.teach.common.annotation.LogPrint;
import com.seer.teach.common.enums.AiScenarioCodeEnum;
import com.seer.teach.teacher.common.req.WrongQuestionBookReq;
import com.seer.teach.teacher.common.req.WrongQuestionPageListReq;
import com.seer.teach.teacher.common.resp.SimilarQuestionResp;
import com.seer.teach.teacher.common.resp.WrongQuestionPageListResp;
import com.seer.teach.teacher.common.resp.WrongQuestionResp;
import com.seer.teach.teacher.module.entity.IdEntity;
import com.seer.teach.teacher.service.WrongQuestionService;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
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 java.util.List;
@ -37,7 +40,7 @@ public class WrongQuestionController {
@LogPrint
@Operation(summary = "获取各科目的错题数量")
public ResultBean<WrongQuestionResp> getWrongQuestionBook(@RequestBody @Validated WrongQuestionBookReq params) {
WrongQuestionResp wrongQuestion = wrongQuestionService.getWrongQuestion(params);
WrongQuestionResp wrongQuestion = wrongQuestionService.getWrongQuestionCount(params);
return ResultBean.success(wrongQuestion);
}
@ -57,13 +60,12 @@ public class WrongQuestionController {
return ResultBean.success();
}
@PostMapping("/generateQuestionsByQuestionId")
@PostMapping("/getSimilarQuestions")
@LogPrint
@Operation(summary = "举一反三")
public ResultBean<List<String>> generateSimilarQuestions(@RequestBody @Validated IdEntity params) {
List<String> questions = wrongQuestionService.generateSimilarQuestions(params.getId(),
AiScenarioCodeEnum.LEARN_BY_ANALOGY_GENERATE_QUESTIONS, 3);
return ResultBean.success(questions);
@Operation(summary = "举一反三获取相似题目")
public ResultBean<List<SimilarQuestionResp>> getSimilarQuestions(@RequestBody @Validated IdEntity params) {
List<SimilarQuestionResp> result = wrongQuestionService.getSimilarQuestionsByQuestionId(params.getId());
return ResultBean.success(result);
}

View File

@ -21,6 +21,7 @@ spring:
import:
- optional:nacos:${spring.application.name}-${spring.profiles.active}.yaml
- optional:nacos:shared-database.yaml
- optional:nacos:shared-minio.yaml
- optional:nacos:shared-redis.yaml
- optional:nacos:shared-sa-token.yaml
- optional:nacos:shared-minio.yaml

View File

@ -12,5 +12,6 @@ public interface AiReportConvert {
AiReportConvert INSTANCE = Mappers.getMapper(AiReportConvert.class);
AiReportResp toAiReportResp(String studyTime, String readingTime, String practiceCount, String dailyStudyTime, String homeworkCorrectRate, List<SubjectCorrectRateResp> subjectCorrectRate);
AiReportResp toAiReportResp(String studyTime, String readingTime, String practiceCount, String encourage,
String dailyStudyTime, String homeworkCorrectRate, List<SubjectCorrectRateResp> subjectCorrectRate);
}

View File

@ -1,10 +1,14 @@
package com.seer.teach.teacher.convert;
import com.seer.teach.teacher.common.resp.SimilarQuestionResp;
import com.seer.teach.teacher.common.resp.WrongQuestionResp;
import com.seer.teach.teacher.module.entity.BankQuestionsEntity;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper
public interface WrongQuestionBookConvert {
@ -13,4 +17,8 @@ public interface WrongQuestionBookConvert {
@Mapping(source = "totalWrongCount",target = "count")
WrongQuestionResp toWrongQuestion(String totalWrongCount);
SimilarQuestionResp toSimilarQuestion(BankQuestionsEntity bankQuestionsEntity);
List<SimilarQuestionResp> toSimilarQuestionList(List<BankQuestionsEntity> bankQuestionsEntity);
}

View File

@ -4,6 +4,7 @@ import com.seer.teach.common.PageListBean;
import com.seer.teach.common.enums.AiScenarioCodeEnum;
import com.seer.teach.teacher.common.req.WrongQuestionBookReq;
import com.seer.teach.teacher.common.req.WrongQuestionPageListReq;
import com.seer.teach.teacher.common.resp.SimilarQuestionResp;
import com.seer.teach.teacher.common.resp.WrongQuestionPageListResp;
import com.seer.teach.teacher.common.resp.WrongQuestionResp;
import com.seer.teach.teacher.module.entity.IdEntity;
@ -24,7 +25,7 @@ public interface WrongQuestionService {
* @param params 请求参数
* @return 错题本
*/
WrongQuestionResp getWrongQuestion(WrongQuestionBookReq params);
WrongQuestionResp getWrongQuestionCount(WrongQuestionBookReq params);
/**
* 获取错题列表
@ -51,4 +52,11 @@ public interface WrongQuestionService {
* @return 举一反三
*/
List<String> generateSimilarQuestions(Integer id, AiScenarioCodeEnum scenarioCode, Integer count);
/**
* 举一反三获取相似题目
* @param id 题目Id
* @return 相似题目
*/
List<SimilarQuestionResp> getSimilarQuestionsByQuestionId(Integer id);
}

View File

@ -4,6 +4,7 @@ import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.seer.teach.common.entity.BaseEntity;
import com.seer.teach.common.enums.MakeQuestionTypeEnums;
import com.seer.teach.common.enums.teacher.ReportTypeEnum;
import com.seer.teach.common.utils.DateUtils;
import com.seer.teach.iot.api.UserDeviceServiceApi;
import com.seer.teach.teacher.common.dto.ReportQuestionDTO;
@ -18,18 +19,18 @@ import com.seer.teach.teacher.convert.QuestionConvert;
import com.seer.teach.teacher.convert.ReportConvert;
import com.seer.teach.teacher.module.entity.*;
import com.seer.teach.teacher.service.*;
import com.seer.teach.teacher.util.RateUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.*;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* <p>
@ -47,6 +48,20 @@ public class ReportServiceImpl implements ReportService {
private static final String PERCENT_SIGN = "%";
private static final String FIRST_STUDY = "你近期首次学习,期待你的持续进步!";
private static final String NOT_STUDY = "你%s还没有学习哦! 快去学习吧~";
private static final String VERY_GREAT = "很棒哦! %s你的作业正确率提升了%d%%,继续保持优秀表现~";
private static final String NOT_BAD = "不错哦! %s你的作业正确率提升了%d%%,请继续加油~";
private static final String COME_ON = "加油哦! %s你的作业正确率有提升再接再厉~";
private static final String CONTINUE_STUDYING = "继续努力哦! %s你的作业正确率还有提升空间~";
private static final String DON_LOSE_HEART = "别灰心哦!%s你的作业正确率有所下降坚持学习一定会进步的~";
private final EvaluationTasksService evaluationTasksService;
private final UserDeviceServiceApi userDeviceServiceApi;
@ -161,16 +176,144 @@ public class ReportServiceImpl implements ReportService {
.reduce(0, Integer::sum);
String readingTime = DateUtils.formatSecondsToHourAndMinute(readingSeconds);
// 鼓励语句
String encourage = generateEncouragement(params.getType(), homeworkCorrectRate, userId);
// 日均学习时间
long days = ChronoUnit.DAYS.between(startTime.toLocalDate(), endTime.toLocalDate()) + 1;
String dailyStudyTime = (studySeconds / 60 / days) + MINUTE;
// 返回最终AI报告结果
return AiReportConvert.INSTANCE.toAiReportResp(
studyTime, readingTime, practiceCount, dailyStudyTime, homeworkCorrectRate, subjectRates
);
return AiReportConvert.INSTANCE.toAiReportResp(studyTime, readingTime, practiceCount, encourage,
dailyStudyTime, homeworkCorrectRate, subjectRates);
}
/**
* 鼓励语句
*
* @param type 时间类型
* @param correctRate 当前正确率
* @return 鼓励语
*/
private String generateEncouragement(ReportTypeEnum type, String correctRate, Integer userId) {
// 时间段
String timePeriod = type.getDesc();
// 当前正确率
BigDecimal currentRate = RateUtils.percentStrToRate(correctRate);
// 如果正确率为0%说明没有做题返回鼓励语
if (currentRate.compareTo(BigDecimal.ZERO) == 0) {
return String.format(NOT_STUDY, timePeriod);
}
// 获取历史正确率进行对比
Optional<BigDecimal> historyRateOpt = getHistoricalCorrectRate(userId, type);
// 如果没有历史学习记录返回提示语
if (!historyRateOpt.isPresent()) {
return FIRST_STUDY;
}
// 获取提升百分比
BigDecimal historyRate = historyRateOpt.get();
BigDecimal improvementPercent = RateUtils.calculateImprovementPercent(currentRate, historyRate);
int improve = improvementPercent.intValue();
if (improve >= 20) {
return String.format(VERY_GREAT, timePeriod, improve);
} else if (improve >= 10) {
return String.format(NOT_BAD, timePeriod, improve);
} else if (improve >= 5) {
return String.format(COME_ON, timePeriod);
} else if (improve > -5) {
return String.format(CONTINUE_STUDYING, timePeriod);
} else {
return String.format(DON_LOSE_HEART, timePeriod);
}
}
/**
* 获取历史作业正确率
*
* @param userId 用户Id
* @param type 时间类型
* @return 历史作业正确率
*/
private Optional<BigDecimal> getHistoricalCorrectRate(Integer userId, ReportTypeEnum type) {
// 获取当前查询时间段的开始时间
LocalDateTime currentTimeStart = DateUtils.getStartTime(type);
// 查询当前时间段之前的学习记录按时间倒序排列
List<LessonsEntity> previousLessons = lessonsService.lambdaQuery()
.eq(LessonsEntity::getUserId, userId)
.lt(LessonsEntity::getCreateTime, currentTimeStart)
.orderByDesc(LessonsEntity::getCreateTime)
.list();
List<EvaluationTasksEntity> previousEvaluations = evaluationTasksService.lambdaQuery()
.eq(EvaluationTasksEntity::getUserId, userId)
.lt(EvaluationTasksEntity::getCreateTime, currentTimeStart)
.orderByDesc(EvaluationTasksEntity::getCreateTime)
.list();
// 合并并按时间倒序排序找出最近一次学习会话的时间范围
List<LocalDateTime> allCreateTimes = Stream.concat(
previousLessons.stream().map(LessonsEntity::getCreateTime),
previousEvaluations.stream().map(EvaluationTasksEntity::getCreateTime))
.sorted(Collections.reverseOrder()).collect(Collectors.toList());
if (allCreateTimes.isEmpty()) {
return Optional.empty();
}
// 获取最近一次学习的时间
LocalDateTime latestLearningTime = allCreateTimes.get(0);
// 根据报告类型确定历史时间段
LocalDateTime periodStart, periodEnd;
switch (type) {
case DAILY:
// 查找最近一次学习的那一天的所有学习记录
LocalDate learningDate = latestLearningTime.toLocalDate();
periodStart = learningDate.atStartOfDay();
periodEnd = learningDate.atTime(LocalTime.MAX);
break;
case WEEKLY:
// 查找最近一次学习的那周
LocalDate learningWeekStart = latestLearningTime.toLocalDate().with(DayOfWeek.MONDAY);
LocalDate learningWeekEnd = learningWeekStart.plusDays(6);
periodStart = learningWeekStart.atStartOfDay();
periodEnd = learningWeekEnd.atTime(LocalTime.MAX);
break;
case MONTHLY:
// 查找最近一次学习的那个月
YearMonth learningMonth = YearMonth.from(latestLearningTime);
periodStart = learningMonth.atDay(1).atStartOfDay();
periodEnd = learningMonth.atEndOfMonth().atTime(LocalTime.MAX);
break;
default:
return Optional.empty();
}
// 获取该历史时期的完整学习数据
List<LessonsEntity> lessons = lessonsService.lambdaQuery()
.eq(LessonsEntity::getUserId, userId)
.ge(LessonsEntity::getCreateTime, periodStart)
.le(LessonsEntity::getCreateTime, periodEnd)
.list();
List<EvaluationTasksEntity> evaluations = evaluationTasksService.lambdaQuery()
.eq(EvaluationTasksEntity::getUserId, userId)
.ge(EvaluationTasksEntity::getCreateTime, periodStart)
.le(EvaluationTasksEntity::getCreateTime, periodEnd)
.list();
int totalQ = getTotalQuestions(lessons) + getTotalQuestions(evaluations);
if (totalQ == 0) {
return Optional.empty();
}
BigDecimal totalCorrect = calculateTotalCorrect(lessons).add(calculateTotalCorrect(evaluations));
return Optional.of(totalCorrect.divide(BigDecimal.valueOf(totalQ), 2, RoundingMode.HALF_UP));
}
/**
* 获取指定用户的全部题目数据包括测评和计划中的题目
*
@ -535,6 +678,11 @@ public class ReportServiceImpl implements ReportService {
* @return 科目ID到名称的映射
*/
private Map<Integer, String> getSubjectsByIds(Set<Integer> ids) {
log.info("获取科目名称ID集合: {}", ids);
if (ids == null || ids.isEmpty()) {
log.info("ID集合为空返回空map");
return new HashMap<>();
}
Map<Integer, String> map = new HashMap<>();
for (SubjectsEntity s : subjectsService.listByIds(new ArrayList<>(ids))) {
map.put(s.getId(), s.getSubject());

View File

@ -7,11 +7,15 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.JsonNode;
import com.seer.teach.common.PageListBean;
import com.seer.teach.common.enums.*;
import com.seer.teach.common.enums.AiScenarioCodeEnum;
import com.seer.teach.common.enums.BankQuestionStatusEnum;
import com.seer.teach.common.enums.QuestionResultEnums;
import com.seer.teach.common.enums.ResultCodeEnum;
import com.seer.teach.common.utils.AssertUtils;
import com.seer.teach.common.utils.PageConverterUtils;
import com.seer.teach.teacher.common.req.WrongQuestionBookReq;
import com.seer.teach.teacher.common.req.WrongQuestionPageListReq;
import com.seer.teach.teacher.common.resp.SimilarQuestionResp;
import com.seer.teach.teacher.common.resp.WrongQuestionPageListResp;
import com.seer.teach.teacher.common.resp.WrongQuestionResp;
import com.seer.teach.teacher.convert.WrongQuestionBookConvert;
@ -63,7 +67,7 @@ public class WrongQuestionServiceImpl implements WrongQuestionService {
* @return 返回封装了总错题数的响应对象
*/
@Override
public WrongQuestionResp getWrongQuestion(WrongQuestionBookReq params) {
public WrongQuestionResp getWrongQuestionCount(WrongQuestionBookReq params) {
Integer userId = StpUtil.getLoginIdAsInt();
log.info("开始获取用户[{}]测评错题本数据", userId);
@ -243,6 +247,40 @@ public class WrongQuestionServiceImpl implements WrongQuestionService {
}).collect(Collectors.toList());
}
/**
* 举一反三获取相似题目
*
* @param id 题目Id
* @return 相似题目列表
*/
@Override
public List<SimilarQuestionResp> getSimilarQuestionsByQuestionId(Integer id) {
// 根据题目Id获取题目
BankQuestionsEntity questionBank = bankQuestionsService.getById(id);
AssertUtils.notNull(questionBank, ResultCodeEnum.QUESTION_NOT_EXIST);
// 获取知识点Id
Integer knowId = questionBank.getKnowId();
// 查询相同知识点的题目排除原题目
List<BankQuestionsEntity> questionsList = bankQuestionsService.lambdaQuery()
.eq(BankQuestionsEntity::getKnowId, knowId)
.ne(BankQuestionsEntity::getId, id)
.list();
List<SimilarQuestionResp> similarQuestionList = WrongQuestionBookConvert.INSTANCE.toSimilarQuestionList(questionsList);
// 过滤掉questionHtml为空的题目
List<SimilarQuestionResp> result = similarQuestionList.stream()
.filter(question -> question.getQuestionHtml() != null && !question.getQuestionHtml().isEmpty())
.collect(Collectors.toList());
// 将相似题目打乱顺序排序
Collections.shuffle(result);
// 返回10道知识点相同的题目
return result.stream()
.limit(10)
// 重新编号(序号1-10)
.peek((question) -> question.setId(result.indexOf(question) + 1))
.collect(Collectors.toList());
}
/**
* 异步批量插入生成的相似题目到题库
*

View File

@ -0,0 +1,47 @@
package com.seer.teach.teacher.util;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.math.RoundingMode;
@Slf4j
@Component
public class RateUtils {
/**
* 百分比字符串转正确率"62%" -> 0.62
*
* @param percent 百分比字符串
* @return 正确率
*/
public static BigDecimal percentStrToRate(String percent) {
if (percent == null || percent.trim().isEmpty() || "0%".equals(percent)) {
return BigDecimal.ZERO;
}
return new BigDecimal(percent.replace("%", ""))
.divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP);
}
/**
* 计算提升百分比
*
* @param current 当前正确率
* @param history 历史正确率
* @return 提升百分比
*/
public static BigDecimal calculateImprovementPercent(BigDecimal current, BigDecimal history) {
if (history.compareTo(BigDecimal.ZERO) <= 0) {
// 历史为 0认为是首次学习
return BigDecimal.valueOf(100);
}
BigDecimal improve = current.subtract(history)
.divide(history, 2, RoundingMode.HALF_UP)
.multiply(BigDecimal.valueOf(100))
.setScale(0, RoundingMode.HALF_UP);
// 限制范围 [-100, 100]
return improve.max(BigDecimal.valueOf(-100))
.min(BigDecimal.valueOf(100));
}
}

View File

@ -188,11 +188,10 @@ public class WrongQuestionUtils {
String processed = originalHtml
.replaceAll("<!--\\s*题目解析\\s*-->\\s*<p><b>解析:</b>", "<p>解析:")
.replaceAll("<p>\\s*<b>答案:</b>\\s*", "<p>【正确答案】 ");
String redX = "";
// String redX = "";
// 构建学生答案段
String studentSegment = "<p>【你的答案】 "
+ (safeStudentAnswer.isEmpty() ? "" : safeStudentAnswer)
+ redX
+ "</p>\n\n";
// 插入到正确答案之前
processed = processed.replaceFirst("<p>【正确答案】", studentSegment + "<p>【正确答案】");

View File

@ -21,6 +21,7 @@ spring:
- optional:nacos:${spring.application.name}-${spring.profiles.active}.yaml
- optional:nacos:shared-database.yaml
- optional:nacos:shared-redis.yaml
- optional:nacos:shared-sa-token.yaml
cloud:
nacos:
discovery: