This commit is contained in:
Lx 2025-04-30 13:25:39 +08:00
parent 80766669e0
commit 9d077f9205
10 changed files with 284 additions and 9 deletions

View File

@ -0,0 +1,131 @@
package cn.iocoder.yudao.module.base.controller.app;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage;
import cn.binarywang.wx.miniapp.config.WxMaConfig;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.jx.domain.DriveSchoolGuide;
import cn.iocoder.yudao.module.jx.service.DriveSchoolGuideService;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import cn.iocoder.yudao.util.SendSmsUtil;
import lombok.Data;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import cn.iocoder.yudao.module.base.vo.SubscriptionMessageDTO;
import javax.annotation.Resource;
import javax.annotation.security.PermitAll;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/wxPush/message")
public class MessageController {
@Autowired
@Qualifier("jxWxMaService")
private WxMaService jxWxMaService;
@Autowired
private DriveSchoolGuideService driveSchoolGuideService;
@Resource
private AdminUserApi userApi;
/**
* 发送一次性订阅消息
*/
@PostMapping("/sendOnce")
public ResponseEntity<Map<String, Object>> sendOnce(
@RequestBody SubscriptionMessageDTO messageDTO) {
Map<String, Object> response = new HashMap<>();
try {
// 构建消息
WxMaSubscribeMessage message = new WxMaSubscribeMessage();
message.setToUser(messageDTO.getOpenid());
message.setTemplateId(messageDTO.getTemplateId());
// 设置跳转页面
message.setPage(messageDTO.getPage());
// 添加模板内容
messageDTO.getData().forEach((key, value) -> {
message.addData(new WxMaSubscribeMessage.MsgData(key, value.getValue()));
});
// 发送订阅消息
jxWxMaService.getMsgService().sendSubscribeMsg(message);
// 发送短信
/*if(messageDTO.getPage() != null){
String page = messageDTO.getPage();
if (page.contains("tenantId=")) {
String tenantId = page.substring(page.indexOf("tenantId=") + 9);
this.sendSms(tenantId);
}
}*/
response.put("success", true);
response.put("message", "发送成功");
return ResponseEntity.ok(response);
} catch (WxErrorException e) {
// 微信接口错误处理
response.put("success", false);
response.put("errorCode", e.getError().getErrorCode());
response.put("message", "微信接口错误: " + e.getError().getErrorMsg());
return ResponseEntity.status(500).body(response);
} catch (Exception e) {
// 其他错误处理
response.put("success", false);
response.put("message", "系统错误: " + e.getMessage());
return ResponseEntity.status(500).body(response);
}
}
/**
* 向用户发送短信
* @return
*/
@GetMapping("/sendSms")
public void sendSms(String tenantId) {
// 通过tenantId获取需要发送的短信内容
List<DriveSchoolGuide> driveSchoolGuides = driveSchoolGuideService.listByTenantId(tenantId);
Long userId = SecurityFrameworkUtils.getLoginUserId();
AdminUserRespDTO user = userApi.getUser(userId);
String mobile = user.getUsername();
if(!driveSchoolGuides.isEmpty()){
String msgText = driveSchoolGuides.get(0).getMsgText();
// 发送短信
if(!msgText.isEmpty() && !mobile.isEmpty()){
SendSmsUtil.sendMsgCommon(new String[]{msgText}, mobile, "1400852709", "驾悦同行小程序", "2143603");
}
}
}
@GetMapping("/checkConfig")
@PermitAll
public String checkConfig() {
// 获取当前 WxMaService 的配置
WxMaConfig config = jxWxMaService.getWxMaConfig();
return String.format(
"当前使用的配置:\nAppID: %s\nSecret: %s\nToken: %s\nAESKey: %s",
config.getAppid(),
config.getSecret(),
config.getToken(),
config.getAesKey()
);
}
}

View File

@ -30,10 +30,10 @@ public interface DlDriveSchoolStudentService extends IService<DlDriveSchoolStude
/**
* 根据身份证查询学员是否已存在
*
* @param idCard 身份证号
* @param userId 用户id
* return boolean
*/
DlDriveSchoolStudent getStudentByIdCard(String idCard);
DlDriveSchoolStudent getStudentByIdCard(Long userId);
/**
* 获取学员详细信息
@ -152,6 +152,7 @@ public interface DlDriveSchoolStudentService extends IService<DlDriveSchoolStude
* @param tenantId 租户id
*/
Boolean updateStudentPassAndGradTime(Date passTime, Long userId, String courseId, Long tenantId);
Boolean updateStudentGradTime(Long userId, String courseId, Long tenantId);
/**
* 根据唯一码查询学员信息

View File

@ -9,9 +9,12 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.base.constant.SchoolBaseConstants;
import cn.iocoder.yudao.module.base.entity.DlDriveSchoolCoach;
import cn.iocoder.yudao.module.base.entity.DlDriveSchoolStudent;
import cn.iocoder.yudao.module.base.mapper.DlDriveSchoolStudentMapper;
import cn.iocoder.yudao.module.base.service.DlDriveSchoolCoachService;
import cn.iocoder.yudao.module.base.service.DlDriveSchoolStudentService;
import cn.iocoder.yudao.module.base.service.SchoolNotifyMessageSendService;
import cn.iocoder.yudao.module.base.vo.DlDriveSchoolStaffVO;
@ -21,6 +24,8 @@ import cn.iocoder.yudao.module.course.entity.Process;
import cn.iocoder.yudao.module.course.entity.SchoolCourseOrder;
import cn.iocoder.yudao.module.course.service.ProcessService;
import cn.iocoder.yudao.module.course.service.SchoolCourseOrderService;
import cn.iocoder.yudao.module.jx.domain.DriveSchoolCourseOrder;
import cn.iocoder.yudao.module.jx.utils.uuid.UUID;
import cn.iocoder.yudao.module.staff.service.UniqueCodeService;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
@ -38,10 +43,16 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.Comparator;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.time.LocalDate;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.config.CommonStr.USER_TYPE_CUS;
@ -56,6 +67,7 @@ public class DlDriveSchoolStudentServiceImpl extends ServiceImpl<DlDriveSchoolSt
@Resource
private DlDriveSchoolStudentMapper dlDriveSchoolStudentMapper;
@Resource
private ProcessService processService;
@ -71,11 +83,14 @@ public class DlDriveSchoolStudentServiceImpl extends ServiceImpl<DlDriveSchoolSt
@Resource
private AdminUserApi adminUserApi;
@Resource
private DlDriveSchoolCoachService dlDriveSchoolCoachService;
@Override
public String createDlDriveSchoolStudent(DlDriveSchoolStudentVO createReqVO) {
// 插入
DlDriveSchoolStudent dlDriveSchoolStudent = BeanUtils.toBean(createReqVO, DlDriveSchoolStudent.class);
DlDriveSchoolStudent studentByIdCard = this.getStudentByIdCard(dlDriveSchoolStudent.getIdCard());
DlDriveSchoolStudent studentByIdCard = this.getStudentByIdCard(dlDriveSchoolStudent.getUserId());
//查询当前学生的手机号是否存在users表中
AdminUserRespDTO userByMobile = adminUserApi.getUserByMobile(dlDriveSchoolStudent.getPhone());
@ -112,9 +127,9 @@ public class DlDriveSchoolStudentServiceImpl extends ServiceImpl<DlDriveSchoolSt
}
@Override
public DlDriveSchoolStudent getStudentByIdCard(String idCard) {
public DlDriveSchoolStudent getStudentByIdCard(Long userId) {
return lambdaQuery()
.eq(DlDriveSchoolStudent::getIdCard, idCard)
.eq(DlDriveSchoolStudent::getUserId, userId)
.orderByDesc(DlDriveSchoolStudent::getCreateTime)
.last("LIMIT 1")
.one();
@ -123,7 +138,7 @@ public class DlDriveSchoolStudentServiceImpl extends ServiceImpl<DlDriveSchoolSt
/**
* 生成学员编码 年份 + 五位递增数字
* @return
*/
*//*
private String generateDrivingStudentCode() {
String year = String.valueOf(LocalDate.now().getYear());
@ -143,6 +158,32 @@ public class DlDriveSchoolStudentServiceImpl extends ServiceImpl<DlDriveSchoolSt
}
return year + String.format("%05d", next);
}*/
/**
* 生成学员编码年份 + 月份 + 四位递增数字
*/
private String generateDrivingStudentCode() {
String yearMonth = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMM"));
Long tenantId = TenantContextHolder.getTenantId();
QueryWrapper<DlDriveSchoolStudent> wrapper = new QueryWrapper<>();
wrapper.select("driving_student_code")
.likeRight("driving_student_code", yearMonth)
.eq("tenant_id", tenantId)
.orderByDesc("driving_student_code")
.last("LIMIT 1");
DlDriveSchoolStudent maxStudent = dlDriveSchoolStudentMapper.selectOne(wrapper);
int next = 1;
if (maxStudent != null && StringUtils.isNotBlank(maxStudent.getDrivingStudentCode())) {
String code = maxStudent.getDrivingStudentCode();
String suffix = code.substring(6);
next = Integer.parseInt(suffix) + 1;
}
return yearMonth + String.format("%04d", next);
}
@ -382,6 +423,29 @@ public class DlDriveSchoolStudentServiceImpl extends ServiceImpl<DlDriveSchoolSt
return true;
}
/**
* 更新学员拿证时间
*
* @param userId 学员id
* @param courseId 课程id
* @param tenantId 租户id
*/
@TenantIgnore
@Override
@Transactional
public Boolean updateStudentGradTime(Long userId, String courseId, Long tenantId) {
if (ObjectUtils.isEmpty(userId) || ObjectUtils.isEmpty(tenantId)) {
return false;
}
// 更新学员拿证时间
schoolCourseOrderService.update(Wrappers.lambdaUpdate(SchoolCourseOrder.class)
.eq(SchoolCourseOrder::getUserId, userId)
.eq(SchoolCourseOrder::getCourseId, courseId)
.set(SchoolCourseOrder::getGradTime, new Date()));
return true;
}
/**
* 根据唯一码查询学员信息
*

View File

@ -0,0 +1,25 @@
package cn.iocoder.yudao.module.base.utils;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class WxMaConfiguration {
@Bean(name = "jxWxMaService")
public WxMaService jxWxMaService(
@Value("${wx.jx-miniapp.appid}") String appid,
@Value("${wx.jx-miniapp.secret}") String secret) {
WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
config.setAppid(appid);
config.setSecret(secret);
WxMaService service = new WxMaServiceImpl();
service.setWxMaConfig(config);
return service;
}
}

View File

@ -0,0 +1,19 @@
package cn.iocoder.yudao.module.base.vo;
import lombok.Data;
import java.util.Map;
@Data
public class SubscriptionMessageDTO {
private String openid;
private String templateId;
private String page;
private Map<String, TemplateData> data;
@Data
public static class TemplateData {
private String value;
}
}

View File

@ -400,6 +400,10 @@ public class ProcessServiceImpl extends ServiceImpl<ProcessMapper, Process> impl
}
/**
* 科目一科目四考试成绩录入
* @param process
*/
@Override
public void updateProcess(Process process) {
Long userId = SecurityFrameworkUtils.getLoginUserId();

View File

@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.exam.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.base.constant.SchoolBaseConstants;
import cn.iocoder.yudao.module.base.service.DlDriveSchoolStudentService;
import cn.iocoder.yudao.module.base.service.SchoolNotifyMessageSendService;
import cn.iocoder.yudao.module.course.entity.Process;
import cn.iocoder.yudao.module.course.mapper.ProcessMapper;
@ -56,6 +57,9 @@ public class ExamBatchItemServiceImpl extends ServiceImpl<ExamBatchItemMapper, E
@Resource
private AdminUserApi userApi;
@Resource
private DlDriveSchoolStudentService dlDriveSchoolStudentService;
/**
* 分页查询
*
@ -288,6 +292,10 @@ public class ExamBatchItemServiceImpl extends ServiceImpl<ExamBatchItemMapper, E
processService.updateById(nextProcess);
}
}
// 科目三通过之后更新学员毕业时间
if(process.getSubject() == 3){
dlDriveSchoolStudentService.updateStudentGradTime(process.getUserId(), process.getCourseId(), process.getTenantId());
}
}
} else {
//考试不通过

View File

@ -168,6 +168,12 @@
<artifactId>yudao-spring-boot-starter-protection</artifactId>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java-miniapp-spring-boot-starter</artifactId>
<version>4.6.0</version>
</dependency>
</dependencies>
<build>

View File

@ -184,6 +184,7 @@ logging:
cn.iocoder.yudao.module.property.mapper: debug #
cn.iocoder.yudao.module.tickets.mapper: debug #
cn.iocoder.yudao.module.project.mapper: debug #
com.github.binarywang: debug # 打印 WxJava 详细日志
debug: false
@ -210,6 +211,13 @@ wx:
type: RedisTemplate # 采用 RedisTemplate 操作 Redis会自动从 Spring 中获取
key-prefix: wa # Redis Key 的前缀
http-client-type: HttpClient # 采用 HttpClient 请求微信公众号平台
jx-miniapp: # 小程序配置(必填)
appid: wx684fc832e96cee65
secret: d1fecac806c5f3cd9aca9f3d5c3759c7
config-storage:
type: RedisTemplate # 采用 RedisTemplate 操作 Redis会自动从 Spring 中获取
key-prefix: jx
http-client-type: HttpClient # 采用 HttpClient 请求微信公众号平台
--- #################### 芋道相关配置 ####################
@ -256,3 +264,5 @@ justauth:
prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE::
timeout: 24h # 超时时长,目前只对 Redis 缓存生效,默认 3 分钟

View File

@ -203,6 +203,13 @@ wx:
type: RedisTemplate # 采用 RedisTemplate 操作 Redis会自动从 Spring 中获取
key-prefix: wa # Redis Key 的前缀
http-client-type: HttpClient # 采用 HttpClient 请求微信公众号平台
jx-miniapp: # 小程序配置(必填)
appid: wx684fc832e96cee65
secret: d1fecac806c5f3cd9aca9f3d5c3759c7
config-storage:
type: RedisTemplate # 采用 RedisTemplate 操作 Redis会自动从 Spring 中获取
key-prefix: jx
http-client-type: HttpClient # 采用 HttpClient 请求微信公众号平台
--- #################### 芋道相关配置 ####################