mirror of
https://codeup.aliyun.com/67762337eccfc218f6110e0e/per-boe/java-servers.git
synced 2025-12-07 01:46:47 +08:00
Compare commits
45 Commits
master-202
...
20251029-1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
55dac06e5f | ||
|
|
a72a042636 | ||
|
|
4110d0632f | ||
|
|
6fe6f7c6e5 | ||
|
|
249a8d81a6 | ||
|
|
7abb00772b | ||
|
|
04e11f2e71 | ||
|
|
2feb149e92 | ||
|
|
16fa9cb028 | ||
|
|
cac466ba73 | ||
|
|
30d2a0cde2 | ||
|
|
541e542d9b | ||
|
|
aa04e16209 | ||
|
|
57e22492e5 | ||
|
|
1917647a99 | ||
|
|
f5f7ab3bc5 | ||
|
|
413a2ebc33 | ||
|
|
22db916abf | ||
|
|
8ce284ea7e | ||
|
|
c485757061 | ||
|
|
9a00b41cde | ||
|
|
59beaa5b74 | ||
|
|
9b9e97a8d4 | ||
|
|
200ec38038 | ||
|
|
7613f30ca7 | ||
|
|
248e0799bd | ||
|
|
618b0b3f62 | ||
|
|
5836b147c4 | ||
|
|
fb1d11ebab | ||
|
|
add1d6abb2 | ||
|
|
eafe17b99a | ||
|
|
d1b6573c25 | ||
|
|
1039f80aec | ||
|
|
efc0605115 | ||
|
|
d938425151 | ||
|
|
00510562ca | ||
|
|
3e70e71e5a | ||
|
|
24011a4470 | ||
|
|
8948165296 | ||
|
|
076b1828ad | ||
|
|
95312696f6 | ||
|
|
1aca002b8f | ||
|
|
50bdc39ce8 | ||
|
|
4fff780970 | ||
|
|
47813ea565 |
@@ -45,10 +45,7 @@ import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
@@ -98,7 +95,8 @@ public class ThirdApi {
|
||||
private String syncOnLineScore;
|
||||
@Value("${coursesuilt.updateOnLineStatua}")
|
||||
private String updateOnLineStatua;
|
||||
|
||||
@Value("${coursesuilt.delOnLineById}")
|
||||
private String delOnLineById;
|
||||
|
||||
//获取例外人员的id
|
||||
public List<String> getUserId() {
|
||||
@@ -398,4 +396,28 @@ public class ThirdApi {
|
||||
public void syncExamStudyRecord(ExamStudyRecordParam param) {
|
||||
externalRemoteClient.syncExamStudyRecord(param);
|
||||
}
|
||||
|
||||
public void delOnLineById(CourseParam param, String token) {
|
||||
log.info("---------------同步在线课删除 ------- param " + param);
|
||||
String resp = Optional.ofNullable(
|
||||
HttpRequest.post(delOnLineById).body(JSONUtil.toJsonStr(param)).header("token", token).execute()
|
||||
.body()).orElseThrow(() -> new RuntimeException("token校验失败"));
|
||||
log.info("-------delOnLineById = " + resp);
|
||||
}
|
||||
|
||||
//获取字典信息
|
||||
public List<Dict> getDictItems(CommonSearchVo searcher) {
|
||||
try {
|
||||
List<Dict> dictList = dictRemoteClient.getList(searcher);
|
||||
if(!Objects.isNull(dictList) && dictList.size() > 0){
|
||||
// List<String> dicts = dictList.stream().map(Dict::getValue).collect(Collectors.toList());
|
||||
return dictList;
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("-------获取字典信息 = " + e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import com.xboe.api.ThirdApi;
|
||||
import com.xboe.module.course.dto.CourseParam;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -321,6 +322,7 @@ public class CourseAuditApi extends ApiBaseController{
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/hrbp-submit-audit")
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public JsonResponse<Boolean> hrbpAudit(String auditId,String courseId,String title,Boolean pass,String remark, HttpServletRequest request){
|
||||
if(StringUtils.isBlank(auditId)){
|
||||
return badRequest("参数错误");
|
||||
@@ -350,22 +352,19 @@ public class CourseAuditApi extends ApiBaseController{
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
CurrentUser cu=getCurrent();
|
||||
service.hrbpSubmitAudit(auditId, courseId,open, pass,cu.getAccountId(),cu.getName(), remark);
|
||||
CurrentUser cu=getCurrent();
|
||||
service.hrbpSubmitAudit(auditId, courseId,open, pass,cu.getAccountId(),cu.getName(), remark);
|
||||
|
||||
if (pass){
|
||||
//修改在线课开课状态=已开课
|
||||
String token = request.getHeader("Xboe-Access-Token");
|
||||
CourseParam param = new CourseParam();
|
||||
param.setId(courseId);
|
||||
thirdApi.updateOnLineStatua(param,token);
|
||||
}
|
||||
return success(true);
|
||||
} catch (Exception e) {
|
||||
log.error("HRBP审核提交处理错误",e);
|
||||
return error("审核处理失败",e.getMessage(),false);
|
||||
}
|
||||
if (pass){
|
||||
//修改在线课开课状态=已开课
|
||||
String token = request.getHeader("Xboe-Access-Token");
|
||||
CourseParam param = new CourseParam();
|
||||
param.setId(courseId);
|
||||
param.setOrgId(c.getOrgId());
|
||||
param.setOrgName(c.getOrgName());
|
||||
thirdApi.updateOrSaveCourse(param,token);
|
||||
}
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PostMapping("/last-audit-list")
|
||||
@@ -390,6 +389,7 @@ public class CourseAuditApi extends ApiBaseController{
|
||||
* @param dto
|
||||
* @return
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@PostMapping("/submit-publish")
|
||||
@AutoLog(module = "课程",action = "默认管理员提交发布",info = "")
|
||||
public JsonResponse<Boolean> submitAndPublish(@RequestBody CourseFullDto dto, HttpServletRequest request){
|
||||
@@ -423,23 +423,16 @@ public class CourseAuditApi extends ApiBaseController{
|
||||
dto.getCourse().setStatus(Course.STATUS_AUDIT_FINISH);//设置为审核通过状态
|
||||
dto.getCourse().setEnabled(true);//设置启用状态问题
|
||||
dto.getCourse().setPublished(false);//重新提交审核设置为未发布状态
|
||||
try {
|
||||
|
||||
courseService.submitAndPublish(dto,cuser.getAccountId(),cuser.getName());
|
||||
log.info("---------------在线课开始同步到讲师管理 ------- token = " + token);
|
||||
CourseParam param = new CourseParam();
|
||||
param.setId(dto.getCourse().getId());
|
||||
param.setOrgId(dto.getCourse().getOrgId());
|
||||
param.setOrgName(dto.getCourse().getOrgName());
|
||||
thirdApi.updateOrSaveCourse(param,token);
|
||||
log.info("---------------在线课同步到讲师管理完毕 -------");
|
||||
return success(true);
|
||||
} catch (Exception e) {
|
||||
log.error("默认管理员提交直接发布处理失败",e);
|
||||
e.printStackTrace();
|
||||
return error("发布课程失败",e.getMessage());
|
||||
}
|
||||
|
||||
courseService.submitAndPublish(dto,cuser.getAccountId(),cuser.getName());
|
||||
log.info("---------------在线课开始同步到讲师管理 ------- token = " + token);
|
||||
CourseParam param = new CourseParam();
|
||||
param.setId(dto.getCourse().getId());
|
||||
param.setOrgId(dto.getCourse().getOrgId());
|
||||
param.setOrgName(dto.getCourse().getOrgName());
|
||||
thirdApi.updateOrSaveCourse(param,token);
|
||||
log.info("---------------在线课同步到讲师管理完毕 -------");
|
||||
return success(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2,15 +2,19 @@
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.boe.feign.api.infrastructure.entity.CommonSearchVo;
|
||||
import com.boe.feign.api.infrastructure.entity.Dict;
|
||||
import com.xboe.api.ThirdApi;
|
||||
import com.xboe.module.course.dto.*;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
@@ -169,19 +173,48 @@ public class CourseManageApi extends ApiBaseController{
|
||||
List<CourseSection> sectionlist=sectionService.getByCourseId(id);
|
||||
List<CourseTeacher> teachers=courseService.findTeachersByCourseId(id);
|
||||
List<CourseCrowd> crowds=courseService.findCrowdByCourseId(id);
|
||||
|
||||
//
|
||||
|
||||
CommonSearchVo searcher = new CommonSearchVo();
|
||||
searcher.setPid(637L);
|
||||
searcher.setType(1);
|
||||
List<Dict> dictList = thirdApi.getDictItems(searcher);
|
||||
boolean isPermission = false;
|
||||
if(dictList != null && dictList.size() > 0){
|
||||
List<String> dicts = dictList.stream().map(Dict::getValue).collect(Collectors.toList());
|
||||
isPermission = dicts.contains(course.getOrgId());
|
||||
rs.put("dicts",dicts);
|
||||
}
|
||||
log.error("-------是否仅内网查看 = " + isPermission);
|
||||
rs.put("course",course);
|
||||
rs.put("contents",cclist);
|
||||
rs.put("sections",sectionlist);
|
||||
rs.put("teachers",teachers);
|
||||
rs.put("crowds",crowds);
|
||||
|
||||
rs.put("isPermission",isPermission);
|
||||
|
||||
|
||||
|
||||
return success(rs);
|
||||
|
||||
}
|
||||
|
||||
@GetMapping("/getDictIds")
|
||||
public JsonResponse<Map<String,Object>> getDictIds(Long pid,Integer type){
|
||||
CommonSearchVo searcher = new CommonSearchVo();
|
||||
if(pid==null || type ==null){
|
||||
return badRequest("参数错误");
|
||||
}
|
||||
Map<String,Object> rs=new HashMap<String,Object>();
|
||||
searcher.setPid(pid);
|
||||
searcher.setType(type);
|
||||
List<Dict> dictList = thirdApi.getDictItems(searcher);
|
||||
rs.put("dicts",null);
|
||||
if(dictList != null && dictList.size() > 0){
|
||||
List<String> dicts = dictList.stream().map(Dict::getValue).collect(Collectors.toList());
|
||||
rs.put("dicts",dicts);
|
||||
}
|
||||
return success(rs);
|
||||
}
|
||||
|
||||
/**
|
||||
* 管理员审核列表,教师的审核不在这里,此审核也应该移动CourseAuditApi中去
|
||||
* @param pager
|
||||
@@ -268,6 +301,7 @@ public class CourseManageApi extends ApiBaseController{
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/save")
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@AutoLog(module = "课程",action = "保存课程基本信息",info = "")
|
||||
public JsonResponse<CourseFullDto> saveCourseFull(@RequestBody CourseFullDto dto, HttpServletRequest request){
|
||||
if(dto.getCourse()==null){
|
||||
@@ -289,30 +323,25 @@ public class CourseManageApi extends ApiBaseController{
|
||||
}
|
||||
|
||||
//填充必要的信息
|
||||
try {
|
||||
if(StringUtils.isBlank(dto.getCourse().getId())) {
|
||||
//只有在第一次添加保存时才会这样
|
||||
fillCourseData(dto.getCourse());
|
||||
courseService.save(dto);
|
||||
}else {
|
||||
//修改后重置,重新提交审核,重新发布
|
||||
dto.getCourse().setPublished(false);
|
||||
dto.getCourse().setStatus(Course.STATUS_NONE);
|
||||
courseService.update(dto);
|
||||
}
|
||||
String token = request.getHeader("Xboe-Access-Token");
|
||||
log.info("---------------在线课开始同步到讲师管理 ------- token = " + token);
|
||||
CourseParam param = new CourseParam();
|
||||
param.setId(dto.getCourse().getId());
|
||||
param.setOrgId(dto.getCourse().getOrgId());
|
||||
param.setOrgName(dto.getCourse().getOrgName());
|
||||
thirdApi.updateOrSaveCourse(param,token);
|
||||
log.info("---------------在线课同步到讲师管理完毕 -------");
|
||||
return success(dto);
|
||||
} catch (Exception e) {
|
||||
log.error("整体保存课程信息错误",e);
|
||||
return error("保存失败",e.getMessage());
|
||||
}
|
||||
if(StringUtils.isBlank(dto.getCourse().getId())) {
|
||||
//只有在第一次添加保存时才会这样
|
||||
fillCourseData(dto.getCourse());
|
||||
courseService.save(dto);
|
||||
}else {
|
||||
//修改后重置,重新提交审核,重新发布
|
||||
dto.getCourse().setPublished(false);
|
||||
dto.getCourse().setStatus(Course.STATUS_NONE);
|
||||
courseService.update(dto);
|
||||
}
|
||||
String token = request.getHeader("Xboe-Access-Token");
|
||||
log.info("---------------在线课开始同步到讲师管理 ------- token = " + token);
|
||||
CourseParam param = new CourseParam();
|
||||
param.setId(dto.getCourse().getId());
|
||||
param.setOrgId(dto.getCourse().getOrgId());
|
||||
param.setOrgName(dto.getCourse().getOrgName());
|
||||
thirdApi.updateOrSaveCourse(param,token);
|
||||
log.info("---------------在线课同步到讲师管理完毕 -------");
|
||||
return success(dto);
|
||||
}
|
||||
|
||||
/***
|
||||
@@ -411,6 +440,7 @@ public class CourseManageApi extends ApiBaseController{
|
||||
|
||||
|
||||
@PostMapping("/submit")
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@AutoLog(module = "课程",action = "提交课程",info = "")
|
||||
public JsonResponse<CourseFullDto> submitCourseFull(@RequestBody CourseFullDto dto){
|
||||
if(dto.getCourse()==null){
|
||||
@@ -488,68 +518,63 @@ public class CourseManageApi extends ApiBaseController{
|
||||
//检查课程内容的完整性
|
||||
//填充必要的信息
|
||||
//fillCourseData(dto.getCourse());
|
||||
try {
|
||||
CourseHRBPAudit hrbpAudit = hrbpAuditService.hasAuditing(dto.getCourse().getId());
|
||||
if(hrbpAudit!=null) {
|
||||
return badRequest("此课程中已有审核,不能再提交审核,如修改请先撤回");
|
||||
}
|
||||
if(!isLocalDevelopment()) {
|
||||
if(StringUtils.isBlank(dto.getAuditUser().getAid())) {
|
||||
CourseHRBPAudit hrbpAudit = hrbpAuditService.hasAuditing(dto.getCourse().getId());
|
||||
if(hrbpAudit!=null) {
|
||||
return badRequest("此课程中已有审核,不能再提交审核,如修改请先撤回");
|
||||
}
|
||||
if(!isLocalDevelopment()) {
|
||||
if(StringUtils.isBlank(dto.getAuditUser().getAid())) {
|
||||
// if(StringUtils.isBlank(dto.getAuditUser().getKid())) {
|
||||
// return badRequest("HRBP审核信息人员错误");
|
||||
// }
|
||||
//转化用户id
|
||||
User u = userService.getByUserNo(dto.getAuditUser().getCode());
|
||||
if(u==null) { //本地没有,需要同步、
|
||||
//20230815 直接返回错误,这个时候传的用户,在新系统中没有,需要用户登录一下,或着用户中心推送
|
||||
return badRequest("无关联HRBP审核人员,请先同步用户");
|
||||
//Organization org = orgService.getBySysId(dto.getAuditUser().getOrgkid());
|
||||
//转化用户id
|
||||
User u = userService.getByUserNo(dto.getAuditUser().getCode());
|
||||
if(u==null) { //本地没有,需要同步、
|
||||
//20230815 直接返回错误,这个时候传的用户,在新系统中没有,需要用户登录一下,或着用户中心推送
|
||||
return badRequest("无关联HRBP审核人员,请先同步用户");
|
||||
//Organization org = orgService.getBySysId(dto.getAuditUser().getOrgkid());
|
||||
// UserVo fwUser = fwUserService.getById(dto.getAuditUser().getKid());
|
||||
// Account a =userService.syncAccountUser(fwUser);
|
||||
// dto.getAuditUser().setAid(a.getId());
|
||||
}else {
|
||||
dto.getAuditUser().setAid(u.getId());
|
||||
}
|
||||
}else {
|
||||
log.info("已获取过hrbp审核人id【"+dto.getAuditUser().getAid()+"】,不需要再转化");
|
||||
}
|
||||
|
||||
}else {
|
||||
//弄成固定值,用于测试
|
||||
dto.getAuditUser().setAid(getCurrent().getAccountId());
|
||||
}
|
||||
if(StringUtils.isBlank(dto.getAuditUser().getAid())) {
|
||||
return badRequest("查询组织HRBP审核人员失败");
|
||||
}
|
||||
|
||||
//设置为提交状态
|
||||
dto.getCourse().setStatus(Course.STATUS_SUBMIT);
|
||||
dto.getCourse().setEnabled(true);//设置启用状态问题
|
||||
dto.getCourse().setPublished(false);//重新提交审核设置为未发布状态
|
||||
courseService.submit(dto);
|
||||
//提交成功发邮件提醒
|
||||
try {
|
||||
String htmlEmail=createEmailHtml(dto.getAuditUser().getName(),dto.getCourse().getOrgId(),
|
||||
dto.getCourse().getOrgName(),
|
||||
dto.getCourse().getSysCreateBy(),dto.getCourse().getName());
|
||||
//邮件发送
|
||||
String email=dto.getAuditUser().getEmail();
|
||||
if(!isLocalDevelopment()) {
|
||||
//只是非开发模式下才可以发送
|
||||
service.sendMail(email,"《"+dto.getCourse().getName()+"》课程审核提醒", htmlEmail,"数字化学习平台");
|
||||
}else {
|
||||
//service.sendMail("daihaixing@bjxask.com","课程审核提醒", htmlEmail,"数字化学习平台");
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
log.error("邮件发送失败",ex);
|
||||
return error("课程已提交,但邮件发送失败",ex.getMessage());
|
||||
}
|
||||
return success(dto);
|
||||
} catch (Exception e) {
|
||||
log.error("提交保存课程信息错误",e);
|
||||
return error("提交课程处理失败",e.getMessage());
|
||||
}
|
||||
}else {
|
||||
dto.getAuditUser().setAid(u.getId());
|
||||
}
|
||||
}else {
|
||||
log.info("已获取过hrbp审核人id【"+dto.getAuditUser().getAid()+"】,不需要再转化");
|
||||
}
|
||||
|
||||
}else {
|
||||
//弄成固定值,用于测试
|
||||
dto.getAuditUser().setAid(getCurrent().getAccountId());
|
||||
}
|
||||
if(StringUtils.isBlank(dto.getAuditUser().getAid())) {
|
||||
return badRequest("查询组织HRBP审核人员失败");
|
||||
}
|
||||
|
||||
//设置为提交状态
|
||||
dto.getCourse().setStatus(Course.STATUS_SUBMIT);
|
||||
dto.getCourse().setEnabled(true);//设置启用状态问题
|
||||
dto.getCourse().setPublished(false);//重新提交审核设置为未发布状态
|
||||
courseService.submit(dto);
|
||||
//提交成功发邮件提醒
|
||||
try {
|
||||
String htmlEmail=createEmailHtml(dto.getAuditUser().getName(),dto.getCourse().getOrgId(),
|
||||
dto.getCourse().getOrgName(),
|
||||
dto.getCourse().getSysCreateBy(),dto.getCourse().getName());
|
||||
//邮件发送
|
||||
String email=dto.getAuditUser().getEmail();
|
||||
if(!isLocalDevelopment()) {
|
||||
//只是非开发模式下才可以发送
|
||||
service.sendMail(email,"《"+dto.getCourse().getName()+"》课程审核提醒", htmlEmail,"数字化学习平台");
|
||||
}else {
|
||||
//service.sendMail("daihaixing@bjxask.com","课程审核提醒", htmlEmail,"数字化学习平台");
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
log.error("邮件发送失败",ex);
|
||||
return error("课程已提交,但邮件发送失败",ex.getMessage());
|
||||
}
|
||||
return success(dto);
|
||||
}
|
||||
|
||||
private String createEmailHtml(String name,String orgId, String orgName,String createBy,String courseName) throws Exception {
|
||||
@@ -583,6 +608,7 @@ public class CourseManageApi extends ApiBaseController{
|
||||
}
|
||||
|
||||
@PostMapping("/sumbits")
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public JsonResponse<Boolean> sumbitId(HttpServletRequest request,CourseHRBPAudit audit,String ucode,String ukid,String email,String orgName){
|
||||
if(StringUtils.isBlank(audit.getCourseId())){
|
||||
return badRequest("参数错误");
|
||||
@@ -605,24 +631,23 @@ public class CourseManageApi extends ApiBaseController{
|
||||
return badRequest(error);
|
||||
}
|
||||
|
||||
try {
|
||||
CourseHRBPAudit hrbpAudit = hrbpAuditService.hasAuditing(audit.getCourseId());
|
||||
if(hrbpAudit!=null) {
|
||||
return badRequest("此课程中已有审核,不能再提交审核,如修改请先撤回");
|
||||
}
|
||||
|
||||
if(!isLocalDevelopment()) {
|
||||
if(StringUtils.isBlank(audit.getAid())) {
|
||||
|
||||
CourseHRBPAudit hrbpAudit = hrbpAuditService.hasAuditing(audit.getCourseId());
|
||||
if(hrbpAudit!=null) {
|
||||
return badRequest("此课程中已有审核,不能再提交审核,如修改请先撤回");
|
||||
}
|
||||
|
||||
if(!isLocalDevelopment()) {
|
||||
if(StringUtils.isBlank(audit.getAid())) {
|
||||
|
||||
// if(StringUtils.isBlank(ukid)){
|
||||
// return badRequest("未关联HRBP审核人员");
|
||||
// }
|
||||
//转化用户id
|
||||
User u = userService.getByUserNo(ucode);
|
||||
if(u==null) { //本地没有,需要同步
|
||||
return badRequest("无关联HRBP审核人员,请先同步用户");
|
||||
//Organization org = orgService.getBySysId(dto.getAuditUser().getOrgkid());
|
||||
//20230815 已经不再使用直接查老系统,采用接口同步的方式
|
||||
//转化用户id
|
||||
User u = userService.getByUserNo(ucode);
|
||||
if(u==null) { //本地没有,需要同步
|
||||
return badRequest("无关联HRBP审核人员,请先同步用户");
|
||||
//Organization org = orgService.getBySysId(dto.getAuditUser().getOrgkid());
|
||||
//20230815 已经不再使用直接查老系统,采用接口同步的方式
|
||||
// UserVo fwUser = fwUserService.getById(ukid);
|
||||
// Account a =userService.syncAccountUser(fwUser);
|
||||
// audit.setAid(a.getId());
|
||||
@@ -638,43 +663,39 @@ public class CourseManageApi extends ApiBaseController{
|
||||
// }catch(Exception exp) {
|
||||
// log.error("登录同步用户错误",exp);
|
||||
// }
|
||||
}else {
|
||||
audit.setAid(u.getId());
|
||||
}
|
||||
}else {
|
||||
log.info("已获取过hrbp审核人id【"+audit.getAid()+"】,不需要再转化");
|
||||
}
|
||||
|
||||
}else {
|
||||
//弄成固定值,用于测试
|
||||
audit.setAid(getCurrent().getAccountId());
|
||||
}
|
||||
|
||||
if(StringUtils.isBlank(audit.getAid())) {
|
||||
return badRequest("查询组织HRBP审核人员失败");
|
||||
}
|
||||
|
||||
courseService.submit(audit);
|
||||
|
||||
//提交成功发邮件提醒
|
||||
try {
|
||||
String htmlEmail=createEmailHtml(audit.getAuditUser(),course.getOrgId(), orgName,audit.getCourseUser(),audit.getCourseName());
|
||||
//邮件发送
|
||||
if(!isLocalDevelopment()) {
|
||||
//只是非高度环境上才会发送
|
||||
service.sendMail(email,"《"+course.getName()+"》课程审核提醒",htmlEmail,"数字化学习平台");
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
log.error("邮件发送失败",ex);
|
||||
return error("课程已提交,但邮件发送失败",ex.getMessage());
|
||||
}
|
||||
|
||||
return success(true);
|
||||
}catch(Exception e) {
|
||||
log.error("提交保存课程信息错误",e);
|
||||
return error("提交课程处理失败",e.getMessage());
|
||||
}
|
||||
}else {
|
||||
audit.setAid(u.getId());
|
||||
}
|
||||
}else {
|
||||
log.info("已获取过hrbp审核人id【"+audit.getAid()+"】,不需要再转化");
|
||||
}
|
||||
|
||||
}else {
|
||||
//弄成固定值,用于测试
|
||||
audit.setAid(getCurrent().getAccountId());
|
||||
}
|
||||
|
||||
if(StringUtils.isBlank(audit.getAid())) {
|
||||
return badRequest("查询组织HRBP审核人员失败");
|
||||
}
|
||||
|
||||
courseService.submit(audit);
|
||||
|
||||
//提交成功发邮件提醒
|
||||
try {
|
||||
String htmlEmail=createEmailHtml(audit.getAuditUser(),course.getOrgId(), orgName,audit.getCourseUser(),audit.getCourseName());
|
||||
//邮件发送
|
||||
if(!isLocalDevelopment()) {
|
||||
//只是非高度环境上才会发送
|
||||
service.sendMail(email,"《"+course.getName()+"》课程审核提醒",htmlEmail,"数字化学习平台");
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
log.error("邮件发送失败",ex);
|
||||
return error("课程已提交,但邮件发送失败",ex.getMessage());
|
||||
}
|
||||
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PostMapping("/revoke")
|
||||
@@ -886,7 +907,7 @@ public class CourseManageApi extends ApiBaseController{
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/delete")
|
||||
public JsonResponse<Boolean> delete(String id,Boolean erasable,String title,String remark){
|
||||
public JsonResponse<Boolean> delete(String id,Boolean erasable,String title,String remark, HttpServletRequest request){
|
||||
if(StringUtils.isBlank(id)){
|
||||
return badRequest("参数错误");
|
||||
}
|
||||
@@ -901,6 +922,11 @@ public class CourseManageApi extends ApiBaseController{
|
||||
try {
|
||||
CurrentUser cu=getCurrent();
|
||||
courseService.delete(id, erasable,cu.getAccountId(), cu.getName(), remark);
|
||||
|
||||
String token = request.getHeader("Xboe-Access-Token");
|
||||
CourseParam param = new CourseParam();
|
||||
param.setId(id);
|
||||
thirdApi.delOnLineById(param,token);
|
||||
return success(true);
|
||||
} catch (Exception e) {
|
||||
log.error("管理员删除课程错误",e);
|
||||
|
||||
@@ -33,7 +33,10 @@ public class Course extends BaseEntity {
|
||||
|
||||
/**所有的设备*/
|
||||
public static int DEVICE_ALL=3;
|
||||
|
||||
|
||||
/**仅内网*/
|
||||
public static int DEVICE_INTERNAL=4;
|
||||
|
||||
/**未提交,草稿*/
|
||||
public static final int STATUS_NONE=1;
|
||||
|
||||
|
||||
@@ -161,14 +161,14 @@ public interface ICourseService {
|
||||
* 课程信息的整体更新,用于对课程的编辑处理
|
||||
* @param full
|
||||
*/
|
||||
void update(CourseFullDto full)throws Exception;
|
||||
void update(CourseFullDto full);
|
||||
|
||||
/**
|
||||
* 提交课程,提交进入课程审核,独立的方法处理
|
||||
* @param full
|
||||
* @throws Exception
|
||||
*/
|
||||
void submit(CourseFullDto full)throws Exception;
|
||||
void submit(CourseFullDto full);
|
||||
|
||||
/**
|
||||
* 用于默认管理员,直接提交发布,不走审核流程
|
||||
@@ -177,14 +177,14 @@ public interface ICourseService {
|
||||
* @param aname 姓名
|
||||
* @throws Exception
|
||||
*/
|
||||
void submitAndPublish(CourseFullDto full,String aid,String aname)throws Exception;
|
||||
void submitAndPublish(CourseFullDto full,String aid,String aname);
|
||||
|
||||
/**
|
||||
* 提交一个课程
|
||||
* @param audit
|
||||
* @throws Exception
|
||||
*/
|
||||
void submit(CourseHRBPAudit audit) throws Exception;
|
||||
void submit(CourseHRBPAudit audit);
|
||||
|
||||
/**
|
||||
* update 传一个id直接改值
|
||||
@@ -342,4 +342,5 @@ public interface ICourseService {
|
||||
|
||||
|
||||
List<Course> findByIds(List<String> courseIds);
|
||||
void deletedStudyResourceBatchByCourseIdAndType(String courseId,Integer courseType);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.xboe.module.course.service.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
@@ -20,6 +21,11 @@ import com.xboe.core.orm.*;
|
||||
import com.xboe.school.study.dao.StudyCourseDao;
|
||||
import com.xboe.school.study.entity.StudyCourse;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.elasticsearch.client.RequestOptions;
|
||||
import org.elasticsearch.client.RestHighLevelClient;
|
||||
import org.elasticsearch.index.query.BoolQueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilders;
|
||||
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
|
||||
import org.hibernate.mapping.IdGenerator;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
@@ -116,6 +122,9 @@ public class CourseServiceImpl implements ICourseService {
|
||||
@Autowired(required = false)
|
||||
private IEventDataSender eventSender;
|
||||
|
||||
@Resource
|
||||
RestHighLevelClient restHighLevelClient;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@@ -174,6 +183,8 @@ public class CourseServiceImpl implements ICourseService {
|
||||
filters.add(FieldFilters.in("device", Course.DEVICE_MOBILE, Course.DEVICE_ALL));
|
||||
} else if (dto.getDevice() == Course.DEVICE_ALL) {
|
||||
filters.add(FieldFilters.eq("device", Course.DEVICE_ALL));
|
||||
}else if (dto.getDevice() == Course.DEVICE_INTERNAL) {
|
||||
filters.add(FieldFilters.eq("device", Course.DEVICE_INTERNAL));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -855,12 +866,14 @@ public class CourseServiceImpl implements ICourseService {
|
||||
log.error("未配置事件消息发送的实现");
|
||||
}
|
||||
}
|
||||
|
||||
// 删除ES数据
|
||||
deletedStudyResourceBatchByCourseIdAndType(id,c.getType());
|
||||
} else {
|
||||
//彻底删除,课件设置为无课程状态
|
||||
courseDao.setDeleted(id);
|
||||
}
|
||||
//记录删除日志信息
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -963,7 +976,7 @@ public class CourseServiceImpl implements ICourseService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(CourseFullDto full) throws Exception {
|
||||
public void update(CourseFullDto full) {
|
||||
|
||||
Course c = full.getCourse();//当前的课程信息
|
||||
Course nowCourse = courseDao.get(c.getId());//修改之前的课程信息
|
||||
@@ -1015,7 +1028,7 @@ public class CourseServiceImpl implements ICourseService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void submit(CourseFullDto full) throws Exception {
|
||||
public void submit(CourseFullDto full) {
|
||||
|
||||
Course c = full.getCourse();//当前的课程信息
|
||||
if (c.getVisible() == null) {
|
||||
@@ -1071,7 +1084,7 @@ public class CourseServiceImpl implements ICourseService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void submitAndPublish(CourseFullDto full, String aid, String aname) throws Exception {
|
||||
public void submitAndPublish(CourseFullDto full, String aid, String aname) {
|
||||
|
||||
Course c = full.getCourse();//当前的课程信息
|
||||
c.setPublished(true);
|
||||
@@ -1118,7 +1131,7 @@ public class CourseServiceImpl implements ICourseService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void submit(CourseHRBPAudit hrbpAudit) throws Exception {
|
||||
public void submit(CourseHRBPAudit hrbpAudit) {
|
||||
|
||||
courseDao.updateMultiFieldById(hrbpAudit.getCourseId(), UpdateBuilder.create("status", Course.STATUS_SUBMIT),
|
||||
UpdateBuilder.create("published", false), UpdateBuilder.create("publishTime", LocalDateTime.now()));
|
||||
@@ -1987,5 +2000,17 @@ public class CourseServiceImpl implements ICourseService {
|
||||
return courseDao.findListByHql("Select new Course(id,studys,score) from Course where id in(?1)", ids);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void deletedStudyResourceBatchByCourseIdAndType(String courseId, Integer courseType) {
|
||||
DeleteByQueryRequest request = new DeleteByQueryRequest("new_study_resource");
|
||||
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
|
||||
boolQueryBuilder.must(QueryBuilders.matchQuery("courseId", courseId));
|
||||
boolQueryBuilder.must(QueryBuilders.matchQuery("courseType", courseType));
|
||||
request.setQuery(boolQueryBuilder);
|
||||
try {
|
||||
restHighLevelClient.deleteByQuery(request, RequestOptions.DEFAULT);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.xboe.module.popup.entity;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.xboe.core.SysConstant;
|
||||
import com.xboe.core.orm.IdEntity;
|
||||
import lombok.Data;
|
||||
@@ -24,12 +25,14 @@ public class Popup extends IdEntity {
|
||||
* 开始时间
|
||||
* */
|
||||
@Column(name = "start_time")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime startTime;
|
||||
|
||||
/**
|
||||
* 结束时间
|
||||
* */
|
||||
@Column(name = "end_time")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime endTime;
|
||||
|
||||
|
||||
|
||||
@@ -10,11 +10,14 @@ import java.util.stream.Collectors;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import com.alibaba.nacos.shaded.com.google.common.util.concurrent.RateLimiter;
|
||||
import com.boe.feign.api.infrastructure.entity.CommonSearchVo;
|
||||
import com.boe.feign.api.infrastructure.entity.Dict;
|
||||
import com.xboe.api.ThirdApi;
|
||||
import com.xboe.constants.CacheName;
|
||||
import com.xboe.module.course.vo.TeacherVo;
|
||||
import com.xboe.module.usergroup.service.IUserGroupService;
|
||||
import com.xboe.school.study.dao.StudyCourseDao;
|
||||
import com.xboe.school.vo.StudyTimeVo;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -232,7 +235,30 @@ public class StudyCourseApi extends ApiBaseController{
|
||||
rs.put("contents",cclist);
|
||||
rs.put("sections",sectionlist);
|
||||
rs.put("teachers",teachers);
|
||||
|
||||
// 未选择仅内网时isPermission = false,不用区分内外网
|
||||
boolean isPermission = false;
|
||||
if(course.getDevice() ==4){
|
||||
CommonSearchVo searcher = new CommonSearchVo();
|
||||
searcher.setPid(637L);
|
||||
searcher.setType(1);
|
||||
List<Dict> dictList = thirdApi.getDictItems(searcher);
|
||||
if(dictList != null && dictList.size() > 0){
|
||||
List<String> dicts = dictList.stream().map(Dict::getValue).collect(Collectors.toList());
|
||||
// 选择仅内网 并且字典中配置了此课程资源归属,那么只能内网观看 返回 truw
|
||||
isPermission = dicts.contains(course.getOrgId());
|
||||
}
|
||||
}
|
||||
rs.put("isPermission",isPermission);
|
||||
|
||||
CommonSearchVo warn = new CommonSearchVo();
|
||||
warn.setCode("course_warn");
|
||||
warn.setType(1);
|
||||
List<Dict> warns = thirdApi.getDictItems(warn);
|
||||
if(warns != null && warns.size() > 0){
|
||||
rs.put("warn",warns.get(0).getValue());
|
||||
rs.put("warnTitle",warns.get(0).getName());
|
||||
}
|
||||
|
||||
//检查是否已报名
|
||||
StudyCourse sc=service.findByCourseIdAndAid(cid, aid);
|
||||
if(pass==true && sc==null) {
|
||||
@@ -275,19 +301,6 @@ public class StudyCourseApi extends ApiBaseController{
|
||||
continue;
|
||||
}
|
||||
|
||||
// 查询redis上面的key,并解析value获取到lastStudyTime
|
||||
String lastActive = redisTemplate.opsForValue().get("studyContentId:" + item.getId() + ":last_active");
|
||||
if (StringUtil.isNotBlank(lastActive)) {
|
||||
String[] parts = lastActive.split("&");
|
||||
if (parts.length == 2) {
|
||||
int lastStudyTimeRedis = Integer.parseInt(parts[0]);
|
||||
log.info("study-video-time-redis获取---lastStudyTimeRedis = " + lastStudyTimeRedis);
|
||||
if(lastStudyTimeRedis>0){
|
||||
item.setLastStudyTime(lastStudyTimeRedis);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BigDecimal lastStudyTime = new BigDecimal(item.getLastStudyTime());
|
||||
BigDecimal duration = new BigDecimal(content.getDuration());
|
||||
BigDecimal progress = lastStudyTime.divide(duration, 10, RoundingMode.HALF_UP);
|
||||
@@ -579,8 +592,8 @@ public class StudyCourseApi extends ApiBaseController{
|
||||
}
|
||||
try {
|
||||
studyService.finishVideoStudyItem(itemId, studyId,courseId,cnum,token);
|
||||
List<StudyCourse> allUserList = thirdApi.getStudyCourseList(studyId ,courseId, token);
|
||||
log.info("在线课学习记录"+allUserList);
|
||||
// List<StudyCourse> allUserList = thirdApi.getStudyCourseList(studyId ,courseId, token);
|
||||
// log.info("在线课学习记录"+allUserList);
|
||||
return success(true);
|
||||
}catch(Exception e) {
|
||||
log.error("记录内容学习完成错误",e);
|
||||
@@ -625,7 +638,7 @@ public class StudyCourseApi extends ApiBaseController{
|
||||
@Deprecated
|
||||
@RequestMapping(value="/appendtime",method = {RequestMethod.GET,RequestMethod.POST})
|
||||
public JsonResponse<String> appendTime(StudyTime studyTime, HttpServletRequest request){
|
||||
|
||||
|
||||
if(StringUtils.isBlank(studyTime.getStudyId())){
|
||||
return error("参数错误");
|
||||
}
|
||||
@@ -655,7 +668,91 @@ public class StudyCourseApi extends ApiBaseController{
|
||||
return error("记录学习时长错误",e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* appendtime 于 study-video-time 合并
|
||||
* */
|
||||
/*@RequestMapping(value="/updateStudyVideoTime1",method = {RequestMethod.GET,RequestMethod.POST})
|
||||
public JsonResponse<String> updateStudyVideoTime1(StudyTimeVo studyTime, HttpServletRequest request){
|
||||
|
||||
// 0 study-video-time , 1 appendtime
|
||||
if (studyTime.getType() == 0){
|
||||
if(StringUtils.isBlank(studyTime.getItemId())){
|
||||
return error("参数错误");
|
||||
}
|
||||
if(studyTime.getVideoTime()==null){
|
||||
return error("无时间点");
|
||||
}
|
||||
//检查是否已存在
|
||||
try {
|
||||
studyService.updateLastTime(studyTime.getItemId(),studyTime.getVideoTime(), getCurrent().getAccountId());
|
||||
if (studyTime.getContentId() != null && studyTime.getCourseId() != null && studyTime.getProgressVideo() != null){
|
||||
contentService.updateProcessVideo(studyTime.getContentId(), studyTime.getCourseId(), studyTime.getProgressVideo());
|
||||
}
|
||||
return success("true");
|
||||
}catch(Exception e) {
|
||||
log.error("updateStudyVideoTime type =0 记录最后学习时间错误",e);
|
||||
return error("updateStudyVideoTime type =0 记录最后学习时间失败 ",e.getMessage());
|
||||
}
|
||||
}else if(studyTime.getType() == 1){
|
||||
if(StringUtils.isBlank(studyTime.getStudyId())){
|
||||
return error("参数错误");
|
||||
}
|
||||
if(StringUtils.isBlank(studyTime.getCourseId())){
|
||||
return error("未指定课程");
|
||||
}
|
||||
if(StringUtils.isBlank(studyTime.getContentId())){
|
||||
return error("未指定资源内容");
|
||||
}
|
||||
|
||||
String token = request.getHeader("Xboe-Access-Token");
|
||||
if (StringUtils.isEmpty(token)) {
|
||||
token = request.getHeader("token");
|
||||
}
|
||||
try {
|
||||
studyService.updateStudyDuration(studyTime.getStudyId(),null,studyTime.getContentId(),studyTime.getVideoTime(),studyTime.getCourseId());
|
||||
List<StudyCourse> allUserList = thirdApi.getStudyCourseList(studyTime.getStudyId() ,studyTime.getCourseId(), token);
|
||||
log.info("updateStudyVideoTime type =1 在线课学习记录 = " + allUserList);
|
||||
return success(studyTime.getId());
|
||||
}catch(Exception e) {
|
||||
log.error("updateStudyVideoTime type =1 记录学习时长错误",e);
|
||||
return error("updateStudyVideoTime type =1 记录学习时长错误 ",e.getMessage());
|
||||
}
|
||||
}else{
|
||||
return error("type不能为空");
|
||||
}
|
||||
}*/
|
||||
|
||||
@RequestMapping(value="/updateStudyVideoTime",method = {RequestMethod.GET,RequestMethod.POST})
|
||||
public JsonResponse<String> updateStudyVideoTime(StudyTimeVo studyTime, HttpServletRequest request){
|
||||
try {
|
||||
if(StringUtils.isBlank(studyTime.getItemId())){
|
||||
return error("参数错误");
|
||||
}
|
||||
if(studyTime.getVideoTime()==null){
|
||||
return error("无时间点");
|
||||
}
|
||||
if(StringUtils.isBlank(studyTime.getStudyId())){
|
||||
return error("参数错误");
|
||||
}
|
||||
if(StringUtils.isBlank(studyTime.getCourseId())){
|
||||
return error("未指定课程");
|
||||
}
|
||||
if(StringUtils.isBlank(studyTime.getContentId())){
|
||||
return error("未指定资源内容");
|
||||
}
|
||||
studyService.updateStudyDuration(studyTime.getStudyId(),studyTime.getItemId(),studyTime.getContentId(),studyTime.getVideoTime(),studyTime.getCourseId());
|
||||
if (studyTime.getContentId() != null && studyTime.getCourseId() != null && studyTime.getProgressVideo() != null){
|
||||
contentService.updateProcessVideo(studyTime.getContentId(), studyTime.getCourseId(), studyTime.getProgressVideo());
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("updateStudyVideoTime",e);
|
||||
return error("学习时长记录失败",e.getMessage(),null);
|
||||
}
|
||||
return success("true");
|
||||
}
|
||||
|
||||
/**获取最后一次的学习内容*/
|
||||
@GetMapping("/last-study")
|
||||
public JsonResponse<Map<String,Object>> lastStudy(){
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.xboe.school.study.api;
|
||||
|
||||
import com.xboe.api.ThirdApi;
|
||||
import com.xboe.school.study.entity.StudyCourse;
|
||||
import com.xboe.school.study.service.IStudyService;
|
||||
import com.xxl.job.core.handler.annotation.XxlJob;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -10,10 +12,13 @@ import org.springframework.data.redis.core.ScanOptions;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
/**
|
||||
* @author by lyc
|
||||
@@ -26,13 +31,15 @@ public class StudyCourseTask {
|
||||
|
||||
private final IStudyService studyService;
|
||||
private final StringRedisTemplate redisTemplate;
|
||||
@Resource
|
||||
private ThirdApi thirdApi;
|
||||
|
||||
/**
|
||||
* 定时任务
|
||||
* 获取redis 中学习结束的数据更新入库
|
||||
* */
|
||||
@XxlJob("saveStudyCourseItemLastTime")
|
||||
public void saveStudyCourseItemLastTime() {
|
||||
@XxlJob("saveStudyCourseItemLastTime2")
|
||||
public void saveStudyCourseItemLastTime2() {
|
||||
// 1. 定义匹配模式(匹配所有目标key)
|
||||
final String KEY_PATTERN = "studyContentId:*:last_active";
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");
|
||||
@@ -59,7 +66,6 @@ public class StudyCourseTask {
|
||||
String[] parts = redisKey.split(":");
|
||||
if (parts.length < 2) continue;
|
||||
String studyContentId = parts[1];
|
||||
|
||||
// 7. 获取存储的时间点(示例逻辑)
|
||||
String redisValue = redisTemplate.opsForValue().get(redisKey);
|
||||
if (redisValue == null) continue;
|
||||
@@ -69,19 +75,15 @@ public class StudyCourseTask {
|
||||
if (partValues.length >= 2){
|
||||
timestamp = LocalDateTime.parse(partValues[1], formatter);
|
||||
}
|
||||
|
||||
// 8. 更新数据库(调用已有服务方法)
|
||||
studyService.updateStudyCourseItemLastTime(studyContentId, lastStudyTime, timestamp);
|
||||
|
||||
// 9. 删除Redis键(原子操作)
|
||||
redisTemplate.delete(redisKey);
|
||||
|
||||
log.info("处理成功 key: {}, lastStudyTime: {}", redisKey, lastStudyTime);
|
||||
} catch (Exception e) {
|
||||
log.error("处理失败 key: {}", redisKey, e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
cursor.close();
|
||||
} catch (Exception e) {
|
||||
@@ -102,5 +104,159 @@ public class StudyCourseTask {
|
||||
}
|
||||
|
||||
|
||||
@XxlJob("saveStudyCourseItemLastTime")
|
||||
public void saveStudyCourseItemLastTime() {
|
||||
// 1. 定义匹配模式(匹配所有目标key)
|
||||
final String KEY_PATTERN = "studyId:*:courseId:*:courseContentId:*:studyItemId:*";
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");
|
||||
// 2. 使用SCAN安全遍历(避免阻塞)
|
||||
ScanOptions options = ScanOptions.scanOptions()
|
||||
.match(KEY_PATTERN)
|
||||
.count(100) // 分页大小
|
||||
.build();
|
||||
|
||||
try (RedisConnection connection = Objects.requireNonNull(redisTemplate.getConnectionFactory()).getConnection()) {
|
||||
Cursor<byte[]> cursor = connection.scan(options);
|
||||
// 3. 遍历处理符合条件的key
|
||||
while (cursor.hasNext()) {
|
||||
String redisKey = new String(cursor.next());
|
||||
log.info("-定时任务 saveStudyCourseItemLastTime ---redisKey = " + redisKey);
|
||||
// 4. 获取剩余TTL(秒)
|
||||
Long ttl = redisTemplate.getExpire(redisKey, TimeUnit.SECONDS);
|
||||
|
||||
// 5. 过滤条件:剩余时间 >= 29天23小时30分钟(转换为秒)
|
||||
// 总需时间 = (30天 - 30分钟) = 29天23小时30分钟 = 2590200秒
|
||||
// 5分钟 300秒 || 2592000 - 300 = 2591700
|
||||
if (ttl <= 2590200) {
|
||||
try {
|
||||
// 6. 提取studyContentId
|
||||
String[] parts = redisKey.split(":");
|
||||
if (parts.length < 7) continue;
|
||||
String studyId = parts[1];
|
||||
String courseId = parts[3];
|
||||
String courseContentId = parts[5];
|
||||
String studyItemId = parts[7];
|
||||
// 7. 获取存储的时间点(示例逻辑)
|
||||
String redisValue = redisTemplate.opsForValue().get(redisKey);
|
||||
log.info("-定时任务 saveStudyCourseItemLastTime ---redisValue = " + redisValue);
|
||||
if (redisValue == null) continue;
|
||||
String[] partValues = redisValue.split("&");
|
||||
int studyVideoTtime = Integer.parseInt(partValues[0]);
|
||||
int appendtime = Integer.parseInt(partValues[1]);
|
||||
LocalDateTime timestamp = null;
|
||||
if (partValues.length >= 2){
|
||||
timestamp = LocalDateTime.parse(partValues[2], formatter);
|
||||
}
|
||||
// 8. 更新数据库(调用已有服务方法)
|
||||
studyService.newAppendStudyDuration(studyId,null,courseContentId,appendtime,timestamp);
|
||||
log.info("-定时任务 saveStudyCourseItemLastTime ---studyItemId = " + studyItemId);
|
||||
if (studyItemId != null && !studyItemId.equals("null")){
|
||||
log.info("-定时任务 saveStudyCourseItemLastTime --- boolean studyItemId = " + (studyItemId != null));
|
||||
// 8. 更新数据库(调用已有服务方法)
|
||||
studyService.updateStudyCourseItemLastTime(studyItemId, studyVideoTtime, timestamp);
|
||||
}
|
||||
List<StudyCourse> allUserList = thirdApi.getStudyCourseList(studyId , courseId, null);
|
||||
log.info("处理成功 allUserList: {}", allUserList);
|
||||
// 9. 删除Redis键(原子操作)
|
||||
redisTemplate.delete(redisKey);
|
||||
log.info("处理成功 key: {}, lastStudyTime: {}", redisKey, appendtime);
|
||||
} catch (Exception e) {
|
||||
log.error("处理失败 key: {}", redisKey, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
cursor.close();
|
||||
} catch (Exception e) {
|
||||
log.error("定时任务执行异常", e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@XxlJob("saveStudyCourseItemLastTime1")
|
||||
public void saveStudyCourseItemLastTime1() {
|
||||
// 定义需要处理的键模式集合
|
||||
processKeys("studyContentId:*:last_active", this::handleLastActiveKey);
|
||||
processKeys("studyId:*:courseId:*:courseContentId:*", this::handleDurationKey);
|
||||
}
|
||||
|
||||
private void processKeys(String keyPattern, BiConsumer<String, String> keyHandler) {
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");
|
||||
ScanOptions options = ScanOptions.scanOptions()
|
||||
.match(keyPattern)
|
||||
.count(100)
|
||||
.build();
|
||||
|
||||
try (RedisConnection connection = Objects.requireNonNull(redisTemplate.getConnectionFactory()).getConnection()) {
|
||||
Cursor<byte[]> cursor = connection.scan(options);
|
||||
while (cursor.hasNext()) {
|
||||
String redisKey = new String(cursor.next());
|
||||
Long ttl = redisTemplate.getExpire(redisKey, TimeUnit.SECONDS);
|
||||
|
||||
if (ttl != null && ttl <= 2590200) {
|
||||
try {
|
||||
String redisValue = redisTemplate.opsForValue().get(redisKey);
|
||||
if (redisValue != null) {
|
||||
// 调用对应的处理方法
|
||||
keyHandler.accept(redisKey, redisValue);
|
||||
}
|
||||
redisTemplate.delete(redisKey);
|
||||
log.info("Key processed: {}", redisKey);
|
||||
} catch (Exception e) {
|
||||
log.error("Process failed [{}]", redisKey, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
cursor.close();
|
||||
} catch (Exception e) {
|
||||
log.error("Key processing error: {}", keyPattern, e);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理 last_active 类型键
|
||||
private void handleLastActiveKey(String redisKey, String redisValue) {
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");
|
||||
String[] parts = redisKey.split(":");
|
||||
String studyContentId = parts[1];
|
||||
|
||||
String[] values = redisValue.split("&");
|
||||
int lastStudyTime = Integer.parseInt(values[0]);
|
||||
LocalDateTime timestamp = values.length >= 2 ?
|
||||
LocalDateTime.parse(values[1], formatter) : null;
|
||||
|
||||
studyService.updateStudyCourseItemLastTime(studyContentId, lastStudyTime, timestamp);
|
||||
}
|
||||
|
||||
// 处理 duration 类型键
|
||||
private void handleDurationKey(String redisKey, String redisValue) {
|
||||
String[] parts = redisKey.split(":");
|
||||
String studyId = parts[1];
|
||||
String courseId = parts[3];
|
||||
String courseContentId = parts[5];
|
||||
|
||||
String[] values = redisValue.split("&");
|
||||
int duration = Integer.parseInt(values[0]);
|
||||
LocalDateTime timestamp = values.length >= 2 ?
|
||||
LocalDateTime.parse(values[1], DateTimeFormatter.ISO_LOCAL_DATE_TIME) : null;
|
||||
|
||||
studyService.newAppendStudyDuration(studyId, null, courseContentId, duration, timestamp);
|
||||
|
||||
// 保留第三方调用
|
||||
List<StudyCourse> allUserList = thirdApi.getStudyCourseList(studyId, courseId, null);
|
||||
log.info("Study records synced: {}", allUserList.size());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -101,4 +101,8 @@ public interface IStudyService {
|
||||
List<StudyCourseItem> getList(String courseId, String contentId, String name, Integer status);
|
||||
|
||||
void updateStudyCourseItemLastTime(String studyContentId, int lastStudyTime, LocalDateTime timestamp);
|
||||
|
||||
void updateStudyDuration(String studyId,String studyItemId, String contentId, Integer videoTime,String courseId);
|
||||
|
||||
void newAppendStudyDuration(String studyId, String studyItemId, String courseContentId, int duration, LocalDateTime timestamp);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import com.xboe.module.course.entity.CourseExam;
|
||||
import com.xboe.school.study.dao.StudyCourseDao;
|
||||
import com.xboe.school.study.dao.StudyCourseItemDao;
|
||||
import com.xboe.school.study.dao.StudyExamDao;
|
||||
import com.xboe.school.study.entity.StudyCourse;
|
||||
import com.xboe.school.study.entity.StudyCourseItem;
|
||||
import com.xboe.school.study.entity.StudyExam;
|
||||
import com.xboe.school.study.service.IStudyExamService;
|
||||
@@ -170,15 +171,32 @@ public class StudyExamServiceImpl implements IStudyExamService{
|
||||
}
|
||||
builder.addGroupBy("studyId");
|
||||
List<StudyExam> list1 = dao.findList(builder.builder());
|
||||
log.info("------------QueryBuilder list1.size = " + list1.size() + ",0 = " + list1.get(0));
|
||||
|
||||
for(StudyExam item : list1){
|
||||
log.info("-----------------CourseId = " + item.getCourseId() + " , StudyId = " + item.getStudyId() + " , StudentId = " + item.getStudentId());
|
||||
int totalContent = courseContentDao.getCount(item.getCourseId());
|
||||
log.info("----------准备判断进度-------totalContent = " + totalContent);
|
||||
scDao.finishCheck1(item.getStudyId(),item.getCourseId(),totalContent);
|
||||
log.info("----------判断进度完毕----------------------");
|
||||
if(list1 != null && list1.size() > 0){
|
||||
log.info("----------StudyExam--QueryBuilder list1.size = " + list1.size() + ",0 = " + list1.get(0));
|
||||
for(StudyExam item : list1){
|
||||
log.info("--------------StudyExam---CourseId = " + item.getCourseId() + " , StudyId = " + item.getStudyId() + " , StudentId = " + item.getStudentId());
|
||||
int totalContent = courseContentDao.getCount(item.getCourseId());
|
||||
log.info("--------StudyExam--准备判断进度-------totalContent = " + totalContent);
|
||||
scDao.finishCheck1(item.getStudyId(),item.getCourseId(),totalContent);
|
||||
log.info("--------StudyExam--判断进度完毕----------------------");
|
||||
}
|
||||
}else{
|
||||
QueryBuilder builder1 = QueryBuilder.from(StudyCourse.class);
|
||||
if (StringUtils.isEmpty(courseId)){
|
||||
return;
|
||||
}
|
||||
builder1.addFilter(FieldFilters.eq("courseId", courseId));
|
||||
List<StudyCourse> list2 = scDao.findList(builder1.builder());
|
||||
log.info("------------StudyCourse list2.size = " + list2.size() + ",0 = " + list2.get(0));
|
||||
for(StudyCourse item : list2){
|
||||
log.info("-------------StudyCourse----CourseId = " + item.getCourseId() + " , StudyId = " + item.getId() + " , StudentId = " + item.getAid());
|
||||
int totalContent = courseContentDao.getCount(item.getCourseId());
|
||||
log.info("--------StudyCourse--准备判断进度-------totalContent = " + totalContent);
|
||||
scDao.finishCheck1(item.getId(),item.getCourseId(),totalContent);
|
||||
log.info("--------StudyCourse--判断进度完毕----------------------");
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception exception) {
|
||||
exception.printStackTrace();
|
||||
log.info("------异常----------------------:" +exception.getMessage());
|
||||
|
||||
@@ -116,34 +116,74 @@ public class StudyServiceImpl implements IStudyService{
|
||||
//增加内容的学习时长
|
||||
if(StringUtils.isNotBlank(studyItemId)) {
|
||||
//直接根据id更新
|
||||
// String hql="Update StudyCourseItem set studyDuration=studyDuration+"+duration+",status=(case when status<2 then 2 else status end) where id=?1";
|
||||
// scItemDao.update(hql,studyItemId);
|
||||
String sql="Update boe_study_course_item set study_duration=study_duration+"+duration+",status=(case when status<2 then 2 else status end) where id=?1";
|
||||
scItemDao.sqlUpdate(sql,studyItemId);
|
||||
//scItemDao.updateMultiFieldById(studyItemId, UpdateBuilder.create("studyDuration", "studyDuration+"+duration,FieldUpdateType.EXPRESSION));
|
||||
|
||||
|
||||
}else {
|
||||
//根据学习id和课程内容id更新
|
||||
// scItemDao.update(UpdateBuilder.from(StudyCourseItem.class)
|
||||
// .addUpdateField("studyDuration", "studyDuration+"+duration,FieldUpdateType.EXPRESSION)
|
||||
// .addFilter(FieldFilters.eq("studyId", studyId))
|
||||
// .addFilter(FieldFilters.eq("contentId", courseContentId))
|
||||
// .builder());
|
||||
//
|
||||
// String hql="Update StudyCourseItem set studyDuration=studyDuration+"+duration+",status=(case when status<2 then 2 else status end) where studyId=?1 and contentId=?2";
|
||||
// scItemDao.update(hql,studyId,courseContentId);
|
||||
String sql="Update boe_study_course_item set study_duration=study_duration+"+duration+",status=(case when status<2 then 2 else status end) where study_id=?1 and content_id=?2";
|
||||
scItemDao.sqlUpdate(sql,studyId,courseContentId);
|
||||
}
|
||||
|
||||
//追加课程的学习时长
|
||||
//scDao.updateMultiFieldById(studyId, UpdateBuilder.create("totalDuration", "totalDuration+"+duration,FieldUpdateType.EXPRESSION));
|
||||
|
||||
String sql="Update boe_study_course set total_duration=total_duration+"+duration+",status=(case when status<2 then 2 else status end),progress=(case when progress=0 then 1 else progress end),last_time = '"+LocalDateTime.now()+"' where id=?1";
|
||||
scDao.sqlUpdate(sql,studyId);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void newAppendStudyDuration(String studyId,String studyItemId,String courseContentId, int duration,LocalDateTime timestamp) {
|
||||
|
||||
//增加内容的学习时长
|
||||
if(StringUtils.isNotBlank(studyItemId)) {
|
||||
//直接根据id更新
|
||||
String sql="Update boe_study_course_item set study_duration=study_duration+"+duration+",status=(case when status<2 then 2 else status end) where id=?1";
|
||||
scItemDao.sqlUpdate(sql,studyItemId);
|
||||
|
||||
}else {
|
||||
String sql="Update boe_study_course_item set study_duration=study_duration+"+duration+",status=(case when status<2 then 2 else status end) where study_id=?1 and content_id=?2";
|
||||
scItemDao.sqlUpdate(sql,studyId,courseContentId);
|
||||
}
|
||||
|
||||
String sql="Update boe_study_course set total_duration=total_duration+"+duration+",status=(case when status<2 then 2 else status end),progress=(case when progress=0 then 1 else progress end),last_time = '"+timestamp+"' where id=?1";
|
||||
scDao.sqlUpdate(sql,studyId);
|
||||
}
|
||||
|
||||
// 更新 前端传输已学习时长
|
||||
@Override
|
||||
public void updateStudyDuration(String studyId,String studyItemId,String courseContentId, Integer videoTime,String courseId) {
|
||||
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");
|
||||
|
||||
String key = "studyId:" + studyId + ":courseId:" + courseId + ":courseContentId:" + courseContentId + ":studyItemId:" + studyItemId;
|
||||
String currentValue = redisTemplate.opsForValue().get(key);
|
||||
Integer lastDuration = 0;
|
||||
Integer oldVideoTime = 0;
|
||||
Integer sum = 10; // 原appendtime改为固定10秒调用一次接口
|
||||
if (currentValue != null) {
|
||||
String[] partValues = currentValue.split("&");
|
||||
oldVideoTime = Integer.parseInt(partValues[0]);
|
||||
lastDuration = Integer.parseInt(partValues[1]);
|
||||
sum += lastDuration;
|
||||
if(oldVideoTime > videoTime){
|
||||
videoTime = oldVideoTime;// 取最大值最终入库
|
||||
}
|
||||
};
|
||||
|
||||
String value = videoTime + "&" + sum + "&" + now.format(formatter); // study_video_time & appendtime & time
|
||||
log.info("-study-video-time-----value = " + value);
|
||||
|
||||
// 20250303 优化 多次更新改一次更新
|
||||
// 更新Redis中的最后活跃时间(带30秒过期)
|
||||
redisTemplate.opsForValue().set(
|
||||
key,
|
||||
value,
|
||||
Duration.ofSeconds(2592000)
|
||||
);
|
||||
log.info("- 合并 updateStudyDuration -redis保存---value = " + value);
|
||||
// Duration.ofDays(30) 也就是 2592000秒
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void appendStudyDuration(StudyTime st) {
|
||||
@@ -166,7 +206,21 @@ public class StudyServiceImpl implements IStudyService{
|
||||
|
||||
@Override
|
||||
public List<StudyCourseItem> findByStudyId(String studyId) {
|
||||
return scItemDao.findList(OrderCondition.desc("lastTime"),FieldFilters.eq("studyId", studyId));
|
||||
List<StudyCourseItem> list = scItemDao.findList(OrderCondition.desc("lastTime"),FieldFilters.eq("studyId", studyId));
|
||||
for (StudyCourseItem item : list){
|
||||
log.info("-- studyIndex -查询上次学习的是什么资源。mysql查询---------------- item = " + item);
|
||||
String redisKey = "studyId:" + studyId + ":courseId:" + item.getCourseId() + ":courseContentId:" + item.getContentId() + ":studyItemId:" + item.getId();
|
||||
log.info("-- studyIndex -查询上次学习的是什么资源。查询用户的学习情况---------------- redisKey = " + redisKey);
|
||||
String redisValue = redisTemplate.opsForValue().get(redisKey);
|
||||
log.info("-- studyIndex -查询上次学习的是什么资源。查询用户的学习情况---------------- redisValue = " + redisValue);
|
||||
if (redisValue != null) {
|
||||
String[] values = redisValue.split("&");
|
||||
int duration = Integer.parseInt(values[0]);
|
||||
item.setLastStudyTime(duration);
|
||||
log.info("-- studyIndex -----set 结果---------------- LastStudyTime = " + item.getLastStudyTime());
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -228,11 +282,12 @@ public class StudyServiceImpl implements IStudyService{
|
||||
return pageList;
|
||||
}
|
||||
}
|
||||
|
||||
String sql = "select a.id, a.course_id, a.course_name, a.aname, " +
|
||||
"IFNULL(b.finish_time, '0') as finish_time, IFNULL(b.progress, 0) as progress, IFNULL(b.status, 1) as status " +
|
||||
"IFNULL(b.finish_time, '0') as finish_time, IFNULL(b.progress, 0) as progress, IFNULL(b.status, 1) as status,b.score " +
|
||||
"from (select id, course_id, course_name, aname, 0, 1 from boe_study_course where course_id = '" + courseId + "' and aname like '%"+name+"%') a " +
|
||||
"left join " +
|
||||
"(select bsc.id, bsc.course_id, bsc.course_name, bsc.aname, item.finish_time, item.progress, item.status " +
|
||||
"(select bsc.id, bsc.course_id, bsc.course_name, bsc.aname, item.finish_time, item.progress, item.status,MAX(item.score) score " +
|
||||
"from boe_study_course bsc left join boe_study_course_item item on item.course_id = bsc.course_id and item.study_id = bsc.id " +
|
||||
"where bsc.course_id = '" + courseId + "' and item.content_id = '" + contentId + "' and item.aname like '%"+name+"%' group by bsc.id) b " +
|
||||
"on a.course_id = b.course_id and a.id = b.id " +
|
||||
@@ -261,6 +316,9 @@ public class StudyServiceImpl implements IStudyService{
|
||||
sc.setProgress(Integer.valueOf(objs[5].toString()));
|
||||
sc.setStatus(Integer.valueOf(objs[6].toString()));
|
||||
sc.setAname(objs[3].toString());
|
||||
if(objs[7] != null){
|
||||
sc.setScore(Float.valueOf(objs[7].toString()));
|
||||
}
|
||||
item.add(sc);
|
||||
}
|
||||
log.info("资源完成情况人员"+item);
|
||||
@@ -357,6 +415,7 @@ public class StudyServiceImpl implements IStudyService{
|
||||
log.info("-study-video-time-mysql保存---studyContentId = " + studyContentId);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Map<String,Object> getLast(String aid) {
|
||||
//按lastTime排序,第一条,只是课件内容
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.xboe.school.vo;
|
||||
|
||||
import com.xboe.school.study.entity.StudyTime;
|
||||
import lombok.Data;
|
||||
|
||||
/** appendtime 于 study-video-time 合并
|
||||
* appendtime 参数 StudyTime
|
||||
* study-video-time 参数 是 StudyTimeVo
|
||||
*/
|
||||
@Data
|
||||
public class StudyTimeVo extends StudyTime {
|
||||
|
||||
private String itemId;
|
||||
private Integer videoTime;
|
||||
// private String contentId; // 已继承
|
||||
// private String courseId; // 已继承
|
||||
private Float progressVideo;
|
||||
private Integer type; // 0 study-video-time , 1 appendtime
|
||||
}
|
||||
@@ -73,4 +73,5 @@ coursesuilt:
|
||||
updateOrSaveCourse: ${boe.domain}/manageApi/admin/teacherRecord/updateOrSaveCourse
|
||||
syncCourseStudent: ${boe.domain}/manageApi/admin/teacherRecord/syncCourseStudent
|
||||
syncOnLineScore: ${boe.domain}/manageApi/admin/teacherRecord/syncOnLineScore
|
||||
updateOnLineStatua: ${boe.domain}/manageApi/admin/teacherRecord/updateOnLineStatua
|
||||
updateOnLineStatua: ${boe.domain}/manageApi/admin/teacherRecord/updateOnLineStatua
|
||||
delOnLineById: ${boe.domain}/manageApi/admin/teacherRecord/delOnLineById
|
||||
Reference in New Issue
Block a user