package com.xhkjedu.suser.service.gradeclass;

import com.xhkjedu.exception.MissingParametersException;
import com.xhkjedu.suser.mapper.gradeclass.ClassMapper;
import com.xhkjedu.suser.mapper.gradeclass.ClassStudentMapper;
import com.xhkjedu.suser.mapper.gradeclass.GroupStudentMapper;
import com.xhkjedu.suser.mapper.gradeclass.SchoolMapper;
import com.xhkjedu.suser.mapper.liveplay.CourseMapper;
import com.xhkjedu.suser.mapper.system.UserMapper;
import com.xhkjedu.suser.model.gradeclass.TClassStudent;
import com.xhkjedu.suser.model.gradeclass.TGroupStudent;
import com.xhkjedu.suser.model.gradeclass.TSchool;
import com.xhkjedu.suser.model.system.TUser;
import com.xhkjedu.suser.utils.PoiUtils;
import com.xhkjedu.suser.utils.UserUtil;
import com.xhkjedu.suser.vo.gradeclass.ClassStudentVo;
import com.xhkjedu.suser.vo.gradeclass.ClassVo;
import com.xhkjedu.suser.vo.gradeclass.ImportStudentVo;
import com.xhkjedu.utils.DatesUtil;
import com.xhkjedu.utils.N_Utils;
import com.xhkjedu.vo.ResultVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

/**
 * @author ywx
 * @classname TClassStudentService
 * @description
 * @date 2020/6/2 15:53
 **/
@Service
@Slf4j
public class ClassStudentService {
    @Resource
    private ClassStudentMapper classStudentMapper;
    @Resource
    private UserMapper userMapper;
    @Resource
    private ClassMapper classMapper;
    @Resource
    private SchoolMapper schoolMapper;
    @Resource
    private CourseMapper courseMapper;
    @Resource
    private GroupStudentMapper groupStudentMapper;
    @Autowired
    ApplicationContext applicationContext;

    //批量添加
    public void batchAdd(List<TClassStudent> students) throws Exception {
        try {
            TClassStudent s = students.get(0);
            Integer classid = s.getClassid();
            Integer schoolid = s.getSchoolid();
            Integer createid = s.getCreateid();
            ClassVo classVo = classMapper.getById(classid);
            Integer groupid = classVo.getGroupid();
            Integer year = classVo.getYear();
            List<Map> courses = courseMapper.listXzCourse(classid);
            Set<Integer> classids = new HashSet<>();
            Set<Integer> courseids = new HashSet<>();
            List<Future> futureList = new ArrayList<>();//来记录任务的完成情况，完成线程间的通信
            for (TClassStudent student : students) {
                Future<Boolean> future = saveOneXzStu(classid, schoolid, createid, classVo, groupid, year
                        , courses, student, classids, courseids);
                futureList.add(future);
            }

            UserUtil.isAllDone(futureList);//线程是否执行完
            updateClassGroupCourseNum(classids, courseids);//批量修改班级、班级分组、课程学生数量
        } catch (Exception e) {
            log.error("批量添加班级学生出错：" + e.getMessage());
            throw new MissingParametersException(e.getMessage());
        }
    }

    //单个行政班学生添加
    @Async("asyncPoolTaskExecutor")
    public Future<Boolean> saveOneXzStu(Integer classid, Integer schoolid, Integer createid, ClassVo classVo
            , Integer groupid, Integer year, List<Map> courses, TClassStudent student
            , Set<Integer> classids, Set<Integer> courseids) throws Exception {
        List<TClassStudent> addClassStudentList = new ArrayList<>();//新增的班级学生集合
        List<TGroupStudent> addGroupStudentList = new ArrayList<>();//新增的班级分组集合
        List<Integer> changeCourseidList = new ArrayList<>();//用户更新直播课中学生数量
        Integer studentid = student.getStudentid();
        //全体分组
        ImportStudentVo stu = getNumById(classid, studentid, year);
        if (classVo.getClasstype() == 1 && stu.getXznum() != 0) {
            throw new Exception("此学生已在行政班");
        }
        Integer num = stu.getClassnum();//班级学生数量
        if (num == 0) {//学生不在该班级
            setStudents(classid, schoolid, createid, groupid, addClassStudentList, addGroupStudentList, studentid);
            //把这个学生加到此行政班、提高班相关的所有直播班中
            if (classVo.getClasstype() == 1 || classVo.getClasstype() == 2) {
                handleAddClassCourse(addClassStudentList, addGroupStudentList, changeCourseidList, courses, studentid);
            }
        }
        if (N_Utils.isListNotEmpty(addClassStudentList)) {
            classStudentMapper.saveBatchClassStudent(addClassStudentList);//批量新增班级学生
            groupStudentMapper.saveBatchGroupStudent(addGroupStudentList);//批量新增班级分组学生

            //新增学生的班级id集合
            List<Integer> saveclassids = addClassStudentList.stream().map(TClassStudent::getClassid).collect(Collectors.toList());
            classids.addAll(saveclassids);
        }
        if (N_Utils.isListNotEmpty(changeCourseidList)) {
            courseids.addAll(changeCourseidList);
        }
        return new AsyncResult<>(true);
    }

    //班级学生批量添加-取消的删除
    public void batchAdd2(Integer classid, List<Integer> newStuIds) throws Exception {
        try {
            List<Map> courses = courseMapper.listXzCourse(classid);
            //全体分组
            ClassVo classVo = classMapper.getById(classid);
            Integer schoolid = classVo.getSchoolid();
            Integer createid = classVo.getCreateid();
            Integer groupid = classVo.getGroupid();
            Integer classtype = classVo.getClasstype();
            List<Integer> studentIds = classStudentMapper.listStudentIdByClassId(classid);//班级原有学生
            Map<String, List<Map>> courseMap = new HashMap();//班级直播课
            Set<Integer> classids = new HashSet<>();
            Set<Integer> courseids = new HashSet<>();
            List<Future> futureList = new ArrayList<>();//来记录任务的完成情况，完成线程间的通信
            for (Integer studentid : newStuIds) {//单个提高班学生添加
                Future<Boolean> future = saveOnTgStu(classid, studentIds, courses, classtype
                        , schoolid, createid, groupid
                        , studentid, classids, courseids);
                futureList.add(future);
            }

            for (Integer studentId : studentIds) {//单个提高班学生删除
                Future<Boolean> future = delOnTgStu(classid, newStuIds, courses, courseMap
                        , studentId, classids, courseids);
                futureList.add(future);
            }

            UserUtil.isAllDone(futureList);//线程是否执行完
            updateClassGroupCourseNum(classids, courseids);//批量修改班级、班级分组、课程学生数量
        } catch (Exception e) {
            log.error("班级学生批量添加-取消的删除出错：" + e.getMessage());
            throw new MissingParametersException(e.getMessage());
        }
    }

    //批量修改班级、班级分组、课程学生数量
    private void updateClassGroupCourseNum(Set<Integer> classids, Set<Integer> courseids) {
        if (classids.size() > 0) {
            String numclassids = classids.stream().map(String::valueOf).collect(Collectors.joining(","));
            classMapper.updateClassGroupNumByType(numclassids);//批量修改班级、班级分组数量
        }
        if (courseids.size() > 0) {
            String numcourseids = courseids.stream().map(String::valueOf).collect(Collectors.joining(","));
            courseMapper.updateStuNumBatch(numcourseids);//批量修改课程学生数量
        }
    }

    //单个提高班学生添加
    @Async("asyncPoolTaskExecutor")
    public Future<Boolean> saveOnTgStu(Integer classid, List<Integer> studentIds, List<Map> courses, Integer classtype
            , Integer schoolid, Integer createid, Integer groupid
            , Integer studentId, Set<Integer> classids, Set<Integer> courseids) {
        if (!N_Utils.numInList(studentId, studentIds)) {//新添加的学生
            if (courses == null) courses = new ArrayList<>();//null时执行hs1.removeAll(hs2)报错
            List<TClassStudent> addClassStudentList = new ArrayList<>();//新增的班级学生集合
            List<TGroupStudent> addGroupStudentList = new ArrayList<>();//新增的班级分组集合
            List<Integer> changeCourseidList = new ArrayList<>();//用户更新直播课中学生数量

            setStudents(classid, schoolid, createid, groupid, addClassStudentList, addGroupStudentList, studentId);
            //把这个学生加到此行政班、提高班相关的所有直播班中
            if (classtype == 1 || classtype == 2) {
                handleAddClassCourse(addClassStudentList, addGroupStudentList, changeCourseidList, courses, studentId);
            }

            if (N_Utils.isListNotEmpty(addClassStudentList)) {
                classStudentMapper.saveBatchClassStudent(addClassStudentList);//批量新增班级学生
                groupStudentMapper.saveBatchGroupStudent(addGroupStudentList);//批量新增班级分组学生

                //新增学生的班级id集合
                List<Integer> saveclassids = addClassStudentList.stream().map(TClassStudent::getClassid).collect(Collectors.toList());
                classids.addAll(saveclassids);
            }

            if (N_Utils.isListNotEmpty(changeCourseidList)) {
                courseids.addAll(changeCourseidList);
            }
        }
        return new AsyncResult<>(true);
    }

    //单个提高班学生删除
    @Async("asyncPoolTaskExecutor")
    public Future<Boolean> delOnTgStu(Integer classid, List<Integer> newStuIds
            , List<Map> courses, Map<String, List<Map>> courseMap
            , Integer studentId, Set<Integer> classids, Set<Integer> courseids) {
        if (!N_Utils.numInList(studentId, newStuIds)) {//删除的学生
            if (courses == null) courses = new ArrayList<>();//null时执行hs1.removeAll(hs2)报错
            List<Integer> delClassidList = new ArrayList<>();//需要删除的班级学生信息
            List<Integer> changeCourseidList = new ArrayList<>();//用户更新直播课中学生数量

            //把这个学生从此行政班、提高班关联的所有直播班移除
            String classIds = classStudentMapper.getClassIdsByCidAndSid(classid, studentId);//获取学生除某个班外的行政班和提高班ids
            List<Map> courses2;
            if (N_Utils.isNotEmpty(classIds)) {
                courses2 = courseMap.get(classIds);
                if (N_Utils.isListEmpty(courses2)) {
                    courses2 = courseMapper.listCourse(classIds);//某些班的直播课
                    courseMap.put(classIds, courses2);
                }
                if (courses2 == null) {//要排除班级的直播为空
                    courses2 = courses;
                } else {//要排除班级的直播不为空
                    HashSet hs1 = new HashSet(courses);
                    HashSet hs2 = new HashSet(courses2);
                    hs1.removeAll(hs2);//指定班级排除某些班级的直播
                    courses2 = new ArrayList<>();
                    courses2.addAll(hs1);
                }
            } else {
                courses2 = courses;//指定班级的直播课
            }
            handleDelClassCourse(delClassidList, changeCourseidList, courses2);//处理关联的直播课以及需要删除学生的直播班id

            classStudentMapper.deleteBatchStudent(delClassidList, studentId.toString());//批量移除班级学生
            classids.add(classid);

            if (N_Utils.isListNotEmpty(changeCourseidList)) {
                courseids.addAll(changeCourseidList);
            }
        }
        return new AsyncResult<>(true);
    }

    //添加
    @Transactional(rollbackFor = Exception.class)
    public Integer save(TClassStudent model) throws Exception {
        Integer delStuId = 0;//已删除学生id
        try {
            model.setCreatetime(N_Utils.getSecondTimestamp());
            Integer schoolid = model.getSchoolid();
            if (!N_Utils.isEmpty(model.getStudentno())) {
                String headpic = model.getHeadpic();
                TUser user = userMapper.getObjByLoginName(model.getStudentno());
                String examno = model.getExamno();
                if (user == null) {//学生信息在用户表不存在，添加学生信息
                    user = saveUser(model);//保存用户信息
                } else if (user.getUsertype() != 2) {
                    throw new Exception("禁止添加非学生账号");
                } else if (!schoolid.equals(user.getSchoolid())) {
                    throw new Exception("禁止添加非本校学生账号");
                } else if (N_Utils.isNotEmpty(headpic) || 1 != user.getUserstate()
                        || (N_Utils.isNotEmpty(examno) && !examno.equals(user.getExamno()))) {
                    TUser stu = new TUser();
                    if (N_Utils.isNotEmpty(examno)) {
                        TSchool school = schoolMapper.getSchoolInfoById(schoolid);
                        Integer limitenolen = school.getLimitenolen();
                        if (!N_Utils.isEmptyInteger(limitenolen) && !limitenolen.equals(examno.length())) {
                            throw new Exception("准考证号长度不符合要求");
                        }
                    }
                    if ("".equals(examno)) examno = null;
                    stu.setExamno(examno);
                    Integer userid = user.getUserid();
                    stu.setUserid(userid);
                    if (N_Utils.isNotEmpty(headpic)) {
                        TUser u = userMapper.getUserTypeAndHeadTime(userid, N_Utils.getSecondTimestamp());//获取用户类型和修改头像时间
                        if (u.getHeadtime() == 0) {
                            throw new Exception("6个月内只能修改一次");
                        } else {
                            stu.setHeadpic(headpic);
                            stu.setHeadtime(N_Utils.getSecondTimestamp());
                        }
                    }
                    if (1 != user.getUserstate()) {//已删除用户
                        delStuId = userid;
                    }
                    userMapper.updateByPrimaryKeySelective(stu);
                }

                model.setStudentid(user.getUserid());
            }

            //全体分组
            ClassVo classVo = classMapper.getById(model.getClassid());
            ImportStudentVo student = getNumById(model.getClassid(), model.getStudentid(), classVo.getYear());
            if (classVo.getClasstype() == 1 && student.getXznum() != 0) {
                throw new Exception("此学生已在行政班");
            }
            Integer num = student.getClassnum();//班级学生数量
            if (num == 0) {//学生不在该班级
                List<TClassStudent> addClassStudentList = new ArrayList<>();//新增的班级学生集合
                List<TGroupStudent> addGroupStudentList = new ArrayList<>();//新增的班级分组集合
                Integer studentid = model.getStudentid();
                //学生要加入新的班级信息处理
                moveClassHandleAddGroupStudent(addClassStudentList, addGroupStudentList, classVo, studentid);
                //一般分组
                if (!N_Utils.isEmptyInteger(model.getGroupid())) {
                    TGroupStudent groupStudent = new TGroupStudent();
                    groupStudent.setClassid(model.getClassid());
                    groupStudent.setGroupid(model.getGroupid());
                    groupStudent.setStudentid(model.getStudentid());
                    groupStudent.setCreateid(model.getCreateid());
                    groupStudent.setSchoolid(schoolid);
                    addGroupStudentList.add(groupStudent);
                }
                List<Integer> changeCourseidList = new ArrayList<>();//用户更新直播课中学生数量
                //把这个学生加到此行政班、提高班相关的所有直播班中
                List<Map> courses = courseMapper.listXzCourse(classVo.getClassid());
                handleAddClassCourse(addClassStudentList, addGroupStudentList, changeCourseidList, courses, studentid);
                classStudentMapper.saveBatchClassStudent(addClassStudentList);//批量新增班级学生
                groupStudentMapper.saveBatchGroupStudent(addGroupStudentList);//批量新增班级分组学生
                //新增学生的班级id集合
                List<Integer> saveclassids = addClassStudentList.stream().map(TClassStudent::getClassid).collect(Collectors.toList());

                String numclassids = saveclassids.stream().distinct().map(String::valueOf).collect(Collectors.joining(","));
                classMapper.updateClassGroupNumByType(numclassids);//批量修改班级、班级分组数量
                if (N_Utils.isListNotEmpty(changeCourseidList)) {
                    String numcourseids = changeCourseidList.stream().distinct().map(String::valueOf).collect(Collectors.joining(","));
                    courseMapper.updateStuNumBatch(numcourseids);//批量修改课程学生数量
                }

            }
        } catch (Exception e) {
            log.error("添加班级学生出错：" + e.getMessage());
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            throw new MissingParametersException(e.getMessage());
        }
        return delStuId;
    }

    /**
     * 保存用户信息
     *
     * @param [model]
     * @return com.xhkjedu.suser.model.system.TUser
     * @author ywx
     * @date 2022/5/20 10:22
     */
    private TUser saveUser(TClassStudent model) throws Exception {
        Integer schoolid = model.getSchoolid();
        TSchool school = schoolMapper.getSchoolInfoById(schoolid);
        Integer limitenolen = school.getLimitenolen();
        String examno = model.getExamno();
        if (N_Utils.isNotEmpty(examno) && !N_Utils.isEmptyInteger(limitenolen) && !limitenolen.equals(examno.length())) {
            throw new Exception("准考证号长度不符合要求");
        }
        TUser user = new TUser();
        user.setUsertype(2);
        user.setUsername(model.getStudentname());
        user.setLoginname(model.getStudentno());
        user.setLoginpwd(N_Utils.getMD5Pwd("123456"));
        user.setUsersex(model.getUsersex());
        user.setStudentno(model.getStudentno());
        if ("".equals(examno)) examno = null;
        user.setExamno(examno);
        user.setCreateid(model.getCreateid());
        user.setSchoolid(schoolid);
        user.setUsertime(model.getUsertime());
        user.setHeadpic(model.getHeadpic());
        user.setUserphone(model.getUserphone());
        Integer usernum = school.getUsernum();
        if (usernum != null) {
            Integer usernum2 = userMapper.getUserNumBySchoolId(schoolid);
            usernum2 = usernum2 + 1;//学校账号数量+本次添加的人
            if (usernum.compareTo(usernum2) == -1) {
                throw new Exception("账号数量已超限，请联系管理员");
            }
        }
        user.setUserstate(1);
        user.setCreatetime(N_Utils.getSecondTimestamp());
        Integer bindphoned = 0;
        String userphone = user.getUserphone();
        if (N_Utils.isNotEmpty(userphone)) {
            //获取手机号绑定的其他用户数量
            Integer num = userMapper.getNumByUserPhone(0, userphone);
            if (num != 0) {//手机号被其他账号绑定，不保存返回提示信息
                throw new Exception("手机号【" + userphone + "】已被绑定");
            } else {//手机号未被其他账号绑定，设置已绑定手机号
                bindphoned = 1;
            }
        }
        user.setBindphoned(bindphoned);
        if (DatesUtil.dateNan(user.getUsertime())) {//有效期异常值置空
            user.setUsertime(null);
        }
        user.setBindsecret(0);
        user.setUserlock(0);
        user.setErrornum(0);
        userMapper.insertUseGeneratedKeys(user);
        user.setUserid(user.getId());
        return user;
    }

    //删除
    @Transactional(rollbackFor = Exception.class)
    public void deleteById(Integer classid, Integer studentid) {
        try {
            //先获取需要删除的班级学生信息
            List<Integer> delClassidList = new ArrayList<>();
            delClassidList.add(classid);//班级的id

            List<Integer> changeCourseidList = new ArrayList<>();//用户更新直播课中学生数量
            //把这个学生从此行政班、提高班关联的所有直播班移除
            String classids = classStudentMapper.getClassIdsByCidAndSid(classid, studentid);//获取学生除某个班外的行政班和提高班ids
            List<Map> courses = courseMapper.listXzCourse(classid);//指定班级的直播课
            if (courses == null) courses = new ArrayList<>();//null时执行hs1.removeAll(hs2)报错
            if (N_Utils.isNotEmpty(classids)) {
                List<Map> courses2 = courseMapper.listCourse(classids);//某些班的直播课
                if (N_Utils.isListNotEmpty(courses2)) {//要排除班级的直播不为空
                    HashSet hs1 = new HashSet(courses);
                    HashSet hs2 = new HashSet(courses2);
                    hs1.removeAll(hs2);//指定班级排除某些班级的直播
                    courses = new ArrayList<>();
                    courses.addAll(hs1);
                }
            }
            handleDelClassCourse(delClassidList, changeCourseidList, courses);//处理关联的直播课以及需要删除学生的直播班id

            classStudentMapper.deleteBatchStudent(delClassidList, studentid.toString());//批量移除班级学生

            String numclassids = delClassidList.stream().distinct().map(String::valueOf).collect(Collectors.joining(","));
            classMapper.updateClassGroupNumByType(numclassids);//批量修改班级、班级分组数量
            if (N_Utils.isListNotEmpty(changeCourseidList)) {
                String numcourseids = changeCourseidList.stream().distinct().map(String::valueOf).collect(Collectors.joining(","));
                courseMapper.updateStuNumBatch(numcourseids);//批量修改课程学生数量
            }
        } catch (Exception e) {
            log.error("删除学生出错：" + e.getMessage());
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            throw new MissingParametersException(e.getMessage());
        }
    }

    //修改
    public ResultVo update(TClassStudent model) {
        TUser u = userMapper.getObjByLoginName(model.getStudentno());
        if (u != null && !model.getStudentid().equals(u.getUserid())) {
            return new ResultVo(1, "此账号已被【" + u.getUsername() + "】占用");
        }
        String examno = model.getExamno();
        if (N_Utils.isNotEmpty(examno)) {
            TSchool school = schoolMapper.getSchoolInfoByUserid(model.getStudentid());
            Integer limitenolen = school.getLimitenolen();
            if (!N_Utils.isEmptyInteger(limitenolen) && !limitenolen.equals(examno.length())) {
                return new ResultVo(1, "准考证号长度不符合要求");
            }
        }
        //修改学生信息
        TUser user = new TUser();
        user.setUserid(model.getStudentid());
        user.setUsersex(model.getUsersex());
        user.setUsername(model.getStudentname());
        user.setStudentno(model.getStudentno());
        if ("".equals(examno)) examno = null;
        user.setExamno(examno);
        user.setLoginname(model.getStudentno());
        user.setUserphone(model.getUserphone());
        user.setUsertime(model.getUsertime());
        user.setHeadpic(model.getHeadpic());
        user.setResethead(model.getResethead());
        Integer bindphoned = 0;
        String userphone = user.getUserphone();
        if (N_Utils.isEmpty(userphone) || userphone.contains("****")) {//手机号为空或带星号不修改手机号和是否绑定手机号
            bindphoned = null;
            user.setUserphone(null);
        } else if (N_Utils.isNotEmpty(userphone)) {
            //获取手机号绑定的其他用户数量
            Integer num = userMapper.getNumByUserPhone(user.getUserid(), userphone);
            if (num != 0) return new ResultVo(1, "此手机号已被绑定");
            bindphoned = 1;
        }
        user.setBindphoned(bindphoned);
        if (DatesUtil.dateNan(user.getUsertime())) {//有效期异常值置空
            user.setUsertime(null);
        }
        user.setCreatetime(N_Utils.getSecondTimestamp());
        userMapper.updateStudent(user);
        return new ResultVo(0, "修改成功");
    }

    //获取列表
    public List<ClassStudentVo> findAll(TClassStudent student) {
        setOrderField(student);
        return classStudentMapper.findAll(student);
    }

    //班级学生导入
    public ResultVo importUser(MultipartFile file, TClassStudent tClassStudent) {
        Integer schoolid = tClassStudent.getSchoolid();
        Integer createid = tClassStudent.getCreateid();
        N_Utils.validation(new Object[]{schoolid, "学校id", 1, createid, "创建人id", 1});

        try {
            //学校所有正常行政班
            Map<Integer, List<Map<String, Integer[]>>> gcg = listGradeClassGroup(schoolid, 1);

            Map<String, Object> map = PoiUtils.readExcelStudent(file, gcg);
            List<TUser> students = (List<TUser>) map.get("users");
            Integer lnum = students.stream().distinct().map(TUser::getLoginname).collect(Collectors.toList()).size();
            Integer stunum = students.size();
            if (stunum.compareTo(lnum) != 0) {
                return new ResultVo(1, "有重复的登录学号");
            }
            List<String> elist = students.stream().filter(u -> N_Utils.isNotEmpty(u.getExamno()))
                    .map(TUser::getExamno).collect(Collectors.toList());
            long examnum2 = elist.stream().distinct().count();
            Integer examnum = elist.size();
            if (examnum2 < examnum) {
                return new ResultVo(1, "有重复的准考证号");
            }
            TSchool school = schoolMapper.getSchoolInfoById(schoolid);
            Integer limitenolen = school.getLimitenolen();
            for (String examno : elist) {
                if (!N_Utils.isEmptyInteger(limitenolen) && !limitenolen.equals(examno.length())) {
                    throw new Exception("准考证号长度不符合要求");
                }
            }
            Integer usernum = school.getUsernum();
            if (usernum != null) {
                Integer usernum2 = userMapper.getUserNumBySchoolId(schoolid);
                usernum2 = usernum2 + stunum;//学校账号数量+本次添加的人
                if (usernum.compareTo(usernum2) == -1) {
                    return new ResultVo(1, "账号数量已超限，请联系管理员");
                }
            }
            map.remove("users");//导入成功的学生信息不返回给前端

            Set<Integer> classids = new HashSet<>();
            Set<Integer> courseids = new HashSet<>();

            Map<Integer, List<Map>> courseMap = new HashMap<>();//要添加班级直播
            Map<String, List<Map>> delCourseMap = new HashMap<>();//要删除班级直播
            List<TUser> teachersExisted = new ArrayList<>();//已存在教师列表
            List<TUser> studentsExisted = new ArrayList<>();//已存在学生列表
            List<TUser> usersExisted = new ArrayList<>();//已存在非本校账号列表
            List<TUser> userexamnoExisted = new ArrayList<>();//已存在准考证号
            List<TUser> delUsers = new ArrayList<>();//已删除学生列表
            List<String> loginnames = students.stream().map(s -> s.getLoginname()).collect(Collectors.toList());
            List<String> examnos = students.stream().filter(s -> N_Utils.isNotEmpty(s.getExamno())).map(s -> s.getExamno()).collect(Collectors.toList());
            Map<String, TUser> userMap = userMapper.listByLoginNames(loginnames).stream()
                    .collect(Collectors.toMap(u -> u.getLoginname(), u -> u));
            Map<String,TUser> userexamnoMap = null;
            if(N_Utils.isListNotEmpty(examnos)){
                userexamnoMap = userMapper.listByExamnos(examnos).stream().collect(Collectors.toMap(u -> u.getExamno(), u -> u));
            }
            List<Future> futureList = new ArrayList<>();//来记录任务的完成情况，完成线程间的通信
            for (TUser user : students) {
                Future<Boolean> future = importOneXzStu(schoolid, createid, students, courseMap, delCourseMap
                        , teachersExisted, studentsExisted, usersExisted, userexamnoExisted
                        , delUsers, userMap, userexamnoMap, user, classids, courseids);
                futureList.add(future);
            }

            UserUtil.isAllDone(futureList);//线程是否执行完
            updateClassGroupCourseNum(classids, courseids);//批量修改班级、班级分组、课程学生数量

            map.put("teachersExisted", teachersExisted);
            map.put("studentsExisted", studentsExisted);
            map.put("usersExisted", usersExisted);
            map.put("delUsers", delUsers);
            map.put("userexamnoExisted", userexamnoExisted);
            if (N_Utils.isListNotEmpty(teachersExisted) || N_Utils.isListNotEmpty(studentsExisted)
                    || N_Utils.isListNotEmpty(usersExisted) || N_Utils.isListNotEmpty(delUsers) || N_Utils.isListNotEmpty(userexamnoExisted)) {
                map.put("code", 1);
            } else {
                map.put("code", 0);
            }
            return new ResultVo(0, "导入成功", map);
        } catch (Exception e) {
            log.error("导入失败 : " + e.getMessage());
            return new ResultVo(1, "导入失败 : " + e.getMessage());
        }
    }

    //单个行政班学生导入
    @Async("asyncPoolTaskExecutor")
    public Future<Boolean> importOneXzStu(Integer schoolid, Integer createid, List<TUser> students
            , Map<Integer, List<Map>> courseMap, Map<String, List<Map>> delCourseMap
            , List<TUser> teachersExisted, List<TUser> studentsExisted
            , List<TUser> usersExisted, List<TUser> userexamnoExisted, List<TUser> delUsers
            , Map<String, TUser> userMap, Map<String, TUser> userexamnoMap, TUser user
            , Set<Integer> classids, Set<Integer> courseids) {
        List<TClassStudent> classStudents = new ArrayList<>();
        List<TGroupStudent> groupStudents = new ArrayList<>();
        List<TClassStudent> delStudentList = new ArrayList<>();//要删除的班级学生集合
        List<Integer> changeCourseidList = new ArrayList<>();//用户更新直播课中学生数量
        TUser u = userMap.get(user.getLoginname());
        TUser uexamno = null;
        if (N_Utils.isNotEmpty(user.getExamno()) && userexamnoMap != null) {
            uexamno = userexamnoMap.get(user.getExamno());
        }
        if (null == u && uexamno == null) {
            user.setSchoolid(schoolid);
            user.setCreateid(createid);
            user.setCreatetime(N_Utils.getSecondTimestamp());
            user.setUserstate(1);
            user.setUsertype(2);
            user.setBindphoned(0);
            user.setBindsecret(0);
            user.setUserlock(0);
            user.setErrornum(0);
            userMapper.insertUseGeneratedKeys(user);
            Integer studentid = user.getId();
            Integer classid = user.getClassid();
            setStudents(classid, schoolid, createid, user.getGroupid(), classStudents, groupStudents, studentid);//处理班级加入学生
            List<Map> courses = listCourseByClassId(courseMap, classid);
            handleAddClassCourse(classStudents, groupStudents, changeCourseidList, courses, studentid);//处理班级加入学生中关联的直播课加入学生
        } else if (null == u && uexamno != null) {
            user.setLoginpwd("");
            userexamnoExisted.add(user);
            return new AsyncResult<>(true);
        } else {
            if (schoolid != u.getSchoolid()) {
                usersExisted.add(u);
                return new AsyncResult<>(true);
            } else if (2 != u.getUsertype()) {
                teachersExisted.add(u);
                return new AsyncResult<>(true);
            } else {
                Integer studentid = u.getUserid();
                Integer oldclassid = classStudentMapper.getClassIdByStuId(studentid);//获取学生行政班id
                Integer classid = user.getClassid();
                if (1 != u.getUserstate()) {
                    delUsers.add(u);
                } else {
                    studentsExisted.add(u);
                }
                if (!classid.equals(oldclassid)) {
                    //要添加的班级
                    setStudents(classid, schoolid, createid, user.getGroupid(), classStudents, groupStudents, studentid);//处理班级加入学生
                    List<Map> courses = listCourseByClassId(courseMap, classid);
                    if (courses == null) courses = new ArrayList<>();//null时执行hs1.removeAll(hs2)报错
                    handleAddClassCourse(classStudents, groupStudents, changeCourseidList, courses, studentid);//处理班级加入学生中关联的直播课加入学生

                    if (oldclassid != null) {//要删除的班级
                        //把这个学生从此行政班、提高班关联的所有直播班移除
                        TClassStudent cs = new TClassStudent();
                        cs.setClassid(oldclassid);
                        cs.setStudentid(studentid);
                        delStudentList.add(cs);
                        String classIds = classStudentMapper.getClassIdsByCidAndSid(oldclassid, studentid);//获取学生除某个班外的行政班和提高班ids
                        List<Map> courses2;
                        if (N_Utils.isNotEmpty(classIds)) {
                            courses2 = delCourseMap.get(classIds);
                            if (N_Utils.isListEmpty(courses2)) {
                                courses2 = courseMapper.listCourse(classIds);//某些班的直播课
                                delCourseMap.put(classIds, courses2);
                            }
                            if (courses2 == null) {//要排除班级的直播为空
                                courses2 = courses;
                            } else {//要排除班级的直播不为空
                                HashSet hs1 = new HashSet(courses);
                                HashSet hs2 = new HashSet(courses2);
                                hs1.removeAll(hs2);//指定班级排除某些班级的直播
                                courses2 = new ArrayList<>();
                                courses2.addAll(hs1);
                            }
                        } else {
                            courses2 = listCourseByClassId(courseMap, oldclassid);//指定班级的直播课
                        }
                        handleDelClassCourse2(delStudentList, changeCourseidList, courses2, studentid);//处理关联的直播课以及需要删除学生的直播班id
                    }
                }
                String examno = user.getExamno();
                if (N_Utils.isNotEmpty(examno) && !examno.equals(u.getExamno())) {
                    user.setUserid(u.getUserid());
                    userMapper.updateUser(user);
                }
            }
        }

        List<Integer> classidlist = new ArrayList<>();
        if (N_Utils.isListNotEmpty(delStudentList)) {//要删除的班级学生集合
            List<Integer> delClassidList = delStudentList.stream().map(TClassStudent::getClassid).collect(Collectors.toList());
            classStudentMapper.deleteBatchStudent2(delStudentList);//批量删除班级、分组对应学生
            classidlist.addAll(delClassidList);
        }

        //保存学生关联信息
        if (!CollectionUtils.isEmpty(classStudents)) {
            classStudentMapper.saveBatchClassStudent(classStudents);
            groupStudentMapper.saveBatchGroupStudent(groupStudents);

            //获取所有导入学生的班级
            classidlist.addAll(students.stream().map(TUser::getClassid).collect(Collectors.toList()));
        }

        if (N_Utils.isListNotEmpty(classidlist)) {
            classids.addAll(classidlist);
        }

        if (N_Utils.isListNotEmpty(changeCourseidList)) {
            courseids.addAll(changeCourseidList);
        }
        return new AsyncResult<>(true);
    }

    //处理关联的直播课以及需要删除学生的直播班id
    private void handleDelClassCourse2(List<TClassStudent> delStudentList, List<Integer> changeCourseidList, List<Map> courses, Integer studentid) {
        if (courses != null && courses.size() > 0) {
            for (Map course : courses) {
                Integer courseid = (Integer) course.get("courseid");
                Integer classid = (Integer) course.get("classid");
                TClassStudent cs = new TClassStudent();
                cs.setClassid(classid);
                cs.setStudentid(studentid);
                delStudentList.add(cs);
                changeCourseidList.add(courseid);
            }
        }
    }

    private List<Map> listCourseByClassId(Map<Integer, List<Map>> courseMap, Integer classid) {
        List<Map> courses = courseMap.get(classid);
        if (N_Utils.isListEmpty(courses)) {
            courses = courseMapper.listXzCourse(classid);
        }
        return courses;
    }

    //获取全校年级、班级、分组
    private Map<Integer, List<Map<String, Integer[]>>> listGradeClassGroup(Integer schoolid, Integer classtype) {
        Map<Integer, List<Map<String, Integer[]>>> gclasses = new HashMap<>();//年级下班级集合

        List<Map> classes = classMapper.listClass(schoolid, classtype);
        Map<Integer, List<Map>> grades = classes.stream().collect(Collectors.groupingBy(c -> (Integer) c.get("gradeid")));
        for (Map.Entry<Integer, List<Map>> g : grades.entrySet()) {
            List<Map<String, Integer[]>> cmap = new ArrayList<>();
            List<Map> list = g.getValue();
            for (Map m : list) {
                Map<String, Integer[]> c = new HashMap();
                Integer[] classid_groupid = {(Integer) m.get("classid"), (Integer) m.get("groupid"), (Integer) m.get("year")};
                c.put(m.get("classname").toString(), classid_groupid);

                cmap.add(c);
            }
            gclasses.put(g.getKey(), cmap);
        }
        return gclasses;
    }

    //提高班学生导入
    public ResultVo importUser2(MultipartFile file, TClassStudent tClassStudent) {
        Integer schoolid = tClassStudent.getSchoolid();
        Integer createid = tClassStudent.getCreateid();
        N_Utils.validation(new Object[]{schoolid, "学校id", 1, createid, "创建人id", 1});
        try {
            //学校所有正常提高班
            Map<Integer, List<Map<String, Integer[]>>> gcg = listGradeClassGroup(schoolid, 2);
            Map<String, Object> map = PoiUtils.readExcelStudent(file, gcg);
            List<TUser> students = (List<TUser>) map.get("users");
            Integer lnum = students.stream().distinct().map(TUser::getLoginname).collect(Collectors.toList()).size();
            Integer stunum = students.size();
            if (stunum.compareTo(lnum) != 0) {
                return new ResultVo(1, "有重复的登录学号");
            }
            List<String> elist = students.stream().filter(u -> N_Utils.isNotEmpty(u.getExamno()))
                    .map(TUser::getExamno).collect(Collectors.toList());
            long examnum2 = elist.stream().distinct().count();
            Integer examnum = elist.size();
            if (examnum2 < examnum) {
                return new ResultVo(1, "有重复的准考证号");
            }
            TSchool school = schoolMapper.getSchoolInfoById(schoolid);
            Integer limitenolen = school.getLimitenolen();
            for (String examno : elist) {
                if (!N_Utils.isEmptyInteger(limitenolen) && !limitenolen.equals(examno.length())) {
                    throw new Exception("准考证号长度不符合要求");
                }
            }
            map.remove("users");//导入成功的学生信息不返回给前端


            Map<Integer, List<Map>> courseMap = new HashMap<>();
            // 以下学生信息不存在
            List<TUser> usersNotExisted = new ArrayList<>();
            List<TUser> delUsers = new ArrayList<>();//已删除学生列表
            Set<Integer> classids = new HashSet<>();
            Set<Integer> courseids = new HashSet<>();
            List<String> loginnames = students.stream().map(s -> s.getLoginname()).collect(Collectors.toList());
            Map<String, TUser> userMap = userMapper.listByLoginNames(loginnames).stream()
                    .collect(Collectors.toMap(u -> u.getLoginname(), u -> u));
            List<Future> futureList = new ArrayList<>();//来记录任务的完成情况，完成线程间的通信
            for (TUser user : students) {
                Future<Boolean> future = importOneTgStu(schoolid, createid, students, courseMap
                        , usersNotExisted, delUsers, user, userMap, classids, courseids);
                futureList.add(future);
            }

            UserUtil.isAllDone(futureList);//线程是否执行完
            updateClassGroupCourseNum(classids, courseids);//批量修改班级、班级分组、课程学生数量

            map.put("usersNotExisted", usersNotExisted);
            map.put("delUsers", delUsers);
            if (N_Utils.isListNotEmpty(usersNotExisted) || N_Utils.isListNotEmpty(delUsers)) {
                map.put("code", 1);
            } else {
                map.put("code", 0);
            }
            return new ResultVo(0, "导入成功", map);
        } catch (Exception e) {
            log.error("导入失败 : " + e.getMessage());
            return new ResultVo(1, "导入失败 : " + e.getMessage());
        }
    }

    //单个提高班学生导入
    @Async("asyncPoolTaskExecutor")
    public Future<Boolean> importOneTgStu(Integer schoolid, Integer createid, List<TUser> students
            , Map<Integer, List<Map>> courseMap, List<TUser> usersNotExisted, List<TUser> delUsers
            , TUser user, Map<String, TUser> userMap, Set<Integer> classids, Set<Integer> courseids) {
        TUser u = userMap.get(user.getLoginname());
        if (null == u) {
            user.setSchoolid(schoolid);
            user.setCreateid(createid);
            user.setCreatetime(N_Utils.getSecondTimestamp());
            user.setUserstate(1);
            user.setUsertype(2);
            usersNotExisted.add(user);
            return new AsyncResult<>(true);
        }
        List<TClassStudent> classStudents = new ArrayList<>();
        List<TGroupStudent> groupStudents = new ArrayList<>();
        List<Integer> changeCourseidList = new ArrayList<>();//用户更新直播课中学生数量
        Integer studentid = u.getUserid();
        Integer classid = user.getClassid();
        ImportStudentVo student = getNumById(classid, studentid, user.getYear());
        Integer classnum = student.getClassnum();//本班级学生数量
        if (2 != u.getUsertype() || schoolid != u.getSchoolid() || 0 == student.getXznum()) {
            usersNotExisted.add(u);
        } else {
            if (1 != u.getUserstate()) {
                delUsers.add(u);
            }
            if (0 == classnum) {
                setStudents(classid, schoolid, createid, user.getGroupid(), classStudents, groupStudents, studentid);//处理班级加入学生
                List<Map> courses = listCourseByClassId(courseMap, classid);
                handleAddClassCourse(classStudents, groupStudents, changeCourseidList, courses, studentid);//处理班级加入学生中关联的直播课加入学生
            }
            String examno = user.getExamno();
            if (N_Utils.isNotEmpty(examno) && !examno.equals(u.getExamno())) {
                user.setUserid(u.getUserid());
                userMapper.updateUser(user);//更新用户信息
            }
        }

        //保存学生关联信息
        if (!CollectionUtils.isEmpty(classStudents)) {
            classStudentMapper.saveBatchClassStudent(classStudents);
            groupStudentMapper.saveBatchGroupStudent(groupStudents);
            //获取所有导入学生的班级
            List<Integer> classidlist = students.stream().map(TUser::getClassid).collect(Collectors.toList());
            classids.addAll(classidlist);
        }

        if (N_Utils.isListNotEmpty(changeCourseidList)) {
            courseids.addAll(changeCourseidList);
        }
        return new AsyncResult<>(true);
    }

    private void setStudents(Integer classid, Integer schoolid, Integer createid, Integer groupid, List<TClassStudent> classStudents, List<TGroupStudent> groupStudents, Integer studentid) {
        TClassStudent cs = new TClassStudent();
        cs.setClassid(classid);
        cs.setStudentid(studentid);
        cs.setCreateid(createid);
        cs.setCreatetime(N_Utils.getSecondTimestamp());
        cs.setSchoolid(schoolid);
        classStudents.add(cs);

        TGroupStudent gs = new TGroupStudent();
        gs.setGroupid(groupid);
        gs.setClassid(classid);
        gs.setStudentid(studentid);
        gs.setCreateid(createid);
        gs.setCreatetime(N_Utils.getSecondTimestamp());
        gs.setSchoolid(schoolid);
        groupStudents.add(gs);
    }

    //班级学生数量
    private ImportStudentVo getNumById(Integer classid, Integer studentid, Integer year) {
        return classStudentMapper.getNumById(classid, studentid, year);
    }

    @Transactional(rollbackFor = Exception.class)
    public void moveClass2(Integer oldclassid, Integer classid, Integer studentid) throws Exception {
        try {
            //第一步 先获取需要删除的班级学生信息
            List<Integer> delClassidList = new ArrayList<>();
            delClassidList.add(oldclassid);//原来班级的id

            List<Integer> changeCourseidList = new ArrayList<>();//用户更新直播课中学生数量
            //把这个学生从此行政班、提高班关联的所有直播班移除
            String classids = classStudentMapper.getClassIdsByCidAndSid(oldclassid, studentid);//获取学生除某个班外的行政班和提高班ids
            List<Map> courses = courseMapper.listXzCourse(oldclassid);//指定班级的直播课
            if (courses == null) courses = new ArrayList<>();//null时执行hs1.removeAll(hs2)报错
            if (N_Utils.isNotEmpty(classids)) {
                List<Map> courses2 = courseMapper.listCourse(classids);//某些班的直播课
                if (N_Utils.isListNotEmpty(courses2)) {//要排除班级的直播不为空
                    HashSet hs1 = new HashSet(courses);
                    HashSet hs2 = new HashSet(courses2);
                    hs1.removeAll(hs2);//指定班级排除某些班级的直播
                    courses = new ArrayList<>();
                    courses.addAll(hs1);
                }
            }
            handleDelClassCourse(delClassidList, changeCourseidList, courses);//处理关联的直播课以及需要删除学生的直播班id

            //第二步获取新班级信息，并把学生加入新班级，以及新班级关联的直播课所属班级
            List<TClassStudent> addClassStudentList = new ArrayList<>();//新增的班级学生集合
            List<TGroupStudent> addGroupStudentList = new ArrayList<>();//新增的班级分组集合
            //学生新添加班级的信息
            ClassVo classVo = classMapper.getById(classid);//获取新班级信息
            //学生要加入新的班级信息处理
            moveClassHandleAddGroupStudent(addClassStudentList, addGroupStudentList, classVo, studentid);

            //第三步获取新班级关联直播课关联的班级，并把学生加入
            courses = courseMapper.listXzCourse(classid);
            handleAddClassCourse(addClassStudentList, addGroupStudentList, changeCourseidList, courses, studentid);

            //第四步批量处理原班级学生移除，新班级学生添加，班级分组数量，课程数量
            classStudentMapper.deleteBatchStudent(delClassidList, studentid.toString());//批量移除班级学生
            classStudentMapper.saveBatchClassStudent(addClassStudentList);//批量新增班级学生
            groupStudentMapper.saveBatchGroupStudent(addGroupStudentList);//批量新增班级分组学生

            //新增学生的班级id集合
            List<Integer> saveclassids = addClassStudentList.stream().map(TClassStudent::getClassid).collect(Collectors.toList());
            delClassidList.addAll(saveclassids);

            String numclassids = delClassidList.stream().map(String::valueOf).collect(Collectors.joining(","));
            classMapper.updateClassGroupNumByType(numclassids);//批量修改班级、班级分组数量
            if (N_Utils.isListNotEmpty(changeCourseidList)) {
                String numcourseids = changeCourseidList.stream().map(String::valueOf).collect(Collectors.joining(","));
                courseMapper.updateStuNumBatch(numcourseids);//批量修改课程学生数量
            }
        } catch (Exception e) {
            log.error("学生转班出错：" + e.getMessage());
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            throw new MissingParametersException(e.getMessage());
        }
    }

    //处理要移除学生的班级，以及班级关联的直播
    private void handleDelClassCourse(List<Integer> delClassidList, List<Integer> changeCourseidList, List<Map> courses) {
        if (courses != null && courses.size() > 0) {
            for (Map course : courses) {
                Integer courseid = (Integer) course.get("courseid");
                Integer classid = (Integer) course.get("classid");
                delClassidList.add(classid);
                changeCourseidList.add(courseid);
            }
        }
    }

    //处理班级加入学生中关联的直播课加入学生
    private void handleAddClassCourse(List<TClassStudent> addClassStudentList, List<TGroupStudent> addGroupStudentList, List<Integer> changeCourseidList, List<Map> courses, Integer studentid) {
        if (courses != null && courses.size() > 0) {
            for (int i = 0; i < courses.size(); i++) {
                Map course = courses.get(i);
                Integer courseid = (Integer) course.get("courseid");
                Integer liveClassid = (Integer) course.get("classid");
                Integer teacherid = (Integer) course.get("createid");
                Integer schoolid = (Integer) course.get("schoolid");
                Integer groupid = (Integer) course.get("groupid");
                Integer timestamp = N_Utils.getSecondTimestamp();

                TClassStudent cs = new TClassStudent();
                cs.setClassid(liveClassid);
                cs.setStudentid(studentid);
                cs.setCreateid(teacherid);
                cs.setSchoolid(schoolid);
                cs.setCreatetime(timestamp);
                addClassStudentList.add(cs);

                TGroupStudent gs = new TGroupStudent();
                gs.setClassid(liveClassid);
                gs.setGroupid(groupid);
                gs.setStudentid(studentid);
                gs.setCreateid(teacherid);
                gs.setSchoolid(schoolid);
                gs.setCreatetime(timestamp);
                addGroupStudentList.add(gs);
                changeCourseidList.add(courseid);
            }
        }
    }

    //处理要班级加入学生
    private void moveClassHandleAddGroupStudent(List<TClassStudent> addClassStudentList, List<TGroupStudent> addGroupStudentList, ClassVo classVo, Integer studentid) {
        Integer timestamp = N_Utils.getSecondTimestamp();
        //班级学生
        TClassStudent cs = new TClassStudent();
        cs.setClassid(classVo.getClassid());
        cs.setStudentid(studentid);
        Integer createid = classVo.getCreateid();
        cs.setCreateid(createid);
        cs.setCreatetime(timestamp);
        Integer schoolid = classVo.getSchoolid();
        cs.setSchoolid(schoolid);
        addClassStudentList.add(cs);

        //分组学生
        Integer groupid = classVo.getGroupid();
        TGroupStudent g = new TGroupStudent();
        g.setClassid(classVo.getClassid());
        g.setGroupid(groupid);
        g.setStudentid(studentid);
        g.setCreateid(createid);
        g.setCreatetime(timestamp);
        g.setSchoolid(schoolid);
        addGroupStudentList.add(g);
    }

    /**
     * 解除mac绑定
     *
     * @return void
     * @Param [studentid]
     * @Author ywx
     * @Date 2020/9/18 11:56
     **/
    public void removeBind(Integer studentid) {
        List<Integer> studentids = new ArrayList<>();
        studentids.add(studentid);
        userMapper.batchRemoveBind(studentids);//批量解绑
    }

    /**
     * 批量解绑
     *
     * @param [studentids]
     * @return void
     * @author ywx
     * @date 2022/5/20 13:48
     */
    public void batchRemoveBind(List<Integer> studentids) {
        userMapper.batchRemoveBind(studentids);//批量解绑
    }

    /**
     * 功能描述 获取学生所在班级
     *
     * @param *         @param year
     * @param studentid
     * @return java.util.List<com.xhkjedu.suser.vo.gradeclass.ClassVo>
     * @author WN
     * @date 2020/10/20
     */
    public List<ClassVo> listClassByStudentId(Integer studentid) {
        Integer year = schoolMapper.getYearByUserId(studentid);
        return classStudentMapper.listClassByStudentId(year, studentid);
    }

    public List<ClassStudentVo> listNoClassStu(TClassStudent student) {
        return classStudentMapper.listNoClassStu(student);
    }

    public void setOrderField(TClassStudent student) {
        String fieldname = student.getFieldname();
        if (N_Utils.isEmpty(fieldname) || fieldname.equals("createtime")) {
            fieldname = "cs.createtime";//按创建时间排序导入的学生分页显示会有重复
            if (N_Utils.isEmpty(student.getFieldorder())) {
                student.setFieldorder("desc");
            }
        } else if (fieldname.equals("studentname")) {
            fieldname = "convert(u.username using gbk)";
        } else if (fieldname.equals("studentno")) {
            fieldname = "u.studentno";
        }
        student.setFieldname(fieldname);
    }

    //获取学生所在年级列表
    public List<Integer> listGrade(Integer studentid) {
        Integer year = schoolMapper.getYearByUserId(studentid);
        return classStudentMapper.listGrade(studentid, year);
    }

    //获取全校学生列表
    public List<ClassStudentVo> listAllStudents(TClassStudent student) {
        return classStudentMapper.listAllStudents(student);
    }

    //设置年份
    public void setYear(TClassStudent student) {
        Integer year = schoolMapper.getYearById(student.getSchoolid());
        student.setYear(year);
    }

    //删除学生所有提高班和所在提高班直播课
    public ResultVo delTgStu(String loginname) {
        String[] userIds = loginname.split(",");
        for (String userid : userIds) {
            Integer studentid = N_Utils.str2Int(userid);
            List<Integer> classids = classStudentMapper.listTgClassid(studentid);//获取学生所有提高班
            for (Integer classid : classids) {
                deleteById(classid, studentid);
            }
        }
        return new ResultVo(0, "取消选课成功");
    }

    /**
     * 批量移除学生
     *
     * @param [students]
     * @return void
     * @author ywx
     * @date 2022/5/20 14:52
     */
    public void batchDelete(List<TClassStudent> students) {
        try {
            List<Integer> delids = students.stream().map(TClassStudent::getClassid).distinct().collect(Collectors.toList());

            List<Map> classMap = classStudentMapper.listClassIdsByCidAndSid(students);//获取学生除某个班外的行政班和提高班ids
            Map<Integer, String> studentClassMap = new HashMap<>();//学生除某个班外的行政班和提高班ids集合
            for (Map map : classMap) {
                studentClassMap.put((Integer) map.get("studentid"), map.get("classids").toString());
            }
            List<Map> courseAll = courseMapper.listXzCourse2(delids);//指定班级的直播课
            Map<Integer, List<Map>> delCourseMap = courseAll.stream().collect(Collectors.groupingBy(m -> (Integer) m.get("oldclassid")));
            Map<String, List<Map>> claCourseMap = new HashMap<>();
            Set<Integer> classids = new HashSet<>();
            Set<Integer> courseids = new HashSet<>();
            List<Future> futureList = new ArrayList<>();//来记录任务的完成情况，完成线程间的通信
            for (TClassStudent student : students) {
                Future<Boolean> future = delOneStu(studentClassMap, delCourseMap, claCourseMap
                        , student, classids, courseids);
                futureList.add(future);
            }

            UserUtil.isAllDone(futureList);//线程是否执行完
            updateClassGroupCourseNum(classids, courseids);//批量修改班级、班级分组、课程学生数量
        } catch (Exception e) {
            log.error("批量移除学生出错：" + e.getMessage());
            throw new MissingParametersException(e.getMessage());
        }
    }

    //单个学生移除
    @Async("asyncPoolTaskExecutor")
    public Future<Boolean> delOneStu(Map<Integer, String> studentClassMap
            , Map<Integer, List<Map>> delCourseMap, Map<String, List<Map>> claCourseMap
            , TClassStudent student, Set<Integer> classids, Set<Integer> courseids) {
        List<TClassStudent> delStudentList = new ArrayList<>();//要删除的班级学生集合
        delStudentList.add(student);
        List<Integer> changeCourseidList = new ArrayList<>();//用户更新直播课中学生数量
        Integer classid = student.getClassid();
        Integer studentid = student.getStudentid();
        //把这个学生从此行政班、提高班关联的所有直播班移除
        String classIds = studentClassMap.get(studentid);//获取学生除某个班外的行政班和提高班ids
        List<Map> courses = delCourseMap.get(classid);//指定班级的直播课
        if (courses == null) courses = new ArrayList<>();//null时执行hs1.removeAll(hs2)报错
        if (N_Utils.isNotEmpty(classIds)) {
            List<Map> courses2;//某些班的直播课
            if (claCourseMap.containsKey(classIds)) {
                courses2 = claCourseMap.get(classIds);//某些班的直播课
            } else {
                courses2 = courseMapper.listCourse(classIds);//某些班的直播课
                claCourseMap.put(classIds,courses2);
            }
            if (N_Utils.isListNotEmpty(courses2)) {//要排除班级的直播不为空
                HashSet hs1 = new HashSet(courses);
                HashSet hs2 = new HashSet(courses2);
                hs1.removeAll(hs2);//指定班级排除某些班级的直播
                courses = new ArrayList<>();
                courses.addAll(hs1);
            }
        }
        handleDelClassCourse2(delStudentList, changeCourseidList, courses, studentid);//处理关联的直播课以及需要删除学生的直播班id
        List<Integer> delClassidList = delStudentList.stream().map(TClassStudent::getClassid).distinct().collect(Collectors.toList());
        classStudentMapper.deleteBatchStudent2(delStudentList);//批量删除班级、分组对应学生
        classids.addAll(delClassidList);
        if (N_Utils.isListNotEmpty(changeCourseidList)) {
            courseids.addAll(changeCourseidList);
        }
        return new AsyncResult<>(true);
    }

    /**
     * 批量转班
     *
     * @param [students]
     * @return void
     * @author ywx
     * @date 2022/5/20 17:07
     */
    public void batchMoveClass(List<TClassStudent> students) {
        try {
            List<Integer> classIds = students.stream().map(TClassStudent::getClassid).distinct().collect(Collectors.toList());
            List<ClassVo> classes = classMapper.listByIds(classIds);//获取新班级信息
            List<Map> addCourseAll = courseMapper.listXzCourse2(classIds);//指定班级的直播课
            Map<Integer, List<Map>> addCourseMap = addCourseAll.stream().collect(Collectors.groupingBy(m -> (Integer) m.get("oldclassid")));

            List<TClassStudent> oldStudents = new ArrayList<>();//要转班的班级学生集合
            for (TClassStudent student : students) {
                TClassStudent oldStu = new TClassStudent();
                oldStu.setClassid(student.getOldclassid());
                oldStu.setStudentid(student.getStudentid());
                oldStudents.add(oldStu);
            }
            List<Map> classMap = classStudentMapper.listClassIdsByCidAndSid(oldStudents);//获取学生除某个班外的行政班和提高班ids
            Map<Integer, String> studentClassMap = new HashMap<>();//学生除某个班外的行政班和提高班ids集合
            for (Map map : classMap) {
                studentClassMap.put((Integer) map.get("studentid"), map.get("classids").toString());
            }
            List<Integer> delids = students.stream().map(TClassStudent::getOldclassid).distinct().collect(Collectors.toList());
            List<Map> courseAll = courseMapper.listXzCourse2(delids);//指定班级的直播课
            Map<Integer, List<Map>> courseMap = courseAll.stream().collect(Collectors.groupingBy(m -> (Integer) m.get("oldclassid")));
            Map<String, List<Map>> delCourseMap = new HashMap();//要删除班级直播课
            Set<Integer> classids = new HashSet<>();
            Set<Integer> courseids = new HashSet<>();
            List<Future> futureList = new ArrayList<>();//来记录任务的完成情况，完成线程间的通信
            for (TClassStudent student : students) {
                Future<Boolean> future = moveOneStu(classes, addCourseMap, studentClassMap, courseMap, delCourseMap
                        , student, classids, courseids);
                futureList.add(future);
            }

            UserUtil.isAllDone(futureList);//线程是否执行完
            updateClassGroupCourseNum(classids, courseids);//批量修改班级、班级分组、课程学生数量
        } catch (Exception e) {
            log.error("批量转班出错：" + e.getMessage());
            throw new MissingParametersException(e.getMessage());
        }
    }

    //单个学生转班
    @Async("asyncPoolTaskExecutor")
    public Future<Boolean> moveOneStu(List<ClassVo> classes, Map<Integer, List<Map>> addCourseMap
            , Map<Integer, String> studentClassMap, Map<Integer, List<Map>> courseMap
            , Map<String, List<Map>> delCourseMap, TClassStudent student
            , Set<Integer> classids, Set<Integer> courseids) {
        List<TClassStudent> delStudentList = new ArrayList<>();//要删除的班级学生集合
        List<TClassStudent> addClassStudentList = new ArrayList<>();//新增的班级学生集合
        List<TGroupStudent> addGroupStudentList = new ArrayList<>();//新增的班级分组集合
        List<Integer> changeCourseidList = new ArrayList<>();//用户更新直播课中学生数量

        TClassStudent oldStu = new TClassStudent();
        oldStu.setClassid(student.getOldclassid());
        oldStu.setStudentid(student.getStudentid());
        delStudentList.add(oldStu);//把旧班级学生添加到要删除班级学生集合

        Integer studentid = student.getStudentid();
        Integer classid = student.getClassid();
        //把这个学生从此行政班、提高班关联的所有直播班移除
        String classIds = studentClassMap.get(studentid);//获取学生除某个班外的行政班和提高班ids
        List<Map> courses = courseMap.get(student.getOldclassid());//指定班级的直播课
        if (courses == null) courses = new ArrayList<>();//null时执行hs1.removeAll(hs2)报错
        List<Map> courses2;
        if (N_Utils.isNotEmpty(classIds)) {
            if (delCourseMap.containsKey(classIds)) {
                courses2 = delCourseMap.get(classIds);
            } else {
                courses2 = courseMapper.listCourse(classIds);//某些班的直播课
                delCourseMap.put(classIds, courses2);
            }
            if (courses2 == null) {//要排除班级的直播为空
                courses2 = courses;
            } else {//要排除班级的直播不为空
                HashSet hs1 = new HashSet(courses);
                HashSet hs2 = new HashSet(courses2);
                hs1.removeAll(hs2);//指定班级排除某些班级的直播
                courses2 = new ArrayList<>();
                courses2.addAll(hs1);
            }
        } else {
            courses2 = courses;//指定班级的直播课
        }
        handleDelClassCourse2(delStudentList, changeCourseidList, courses2, studentid);//处理关联的直播课以及需要删除学生的直播班id

        //学生新添加班级的信息
        ClassVo classVo = classes.stream().filter(c -> c.getClassid().equals(classid)).findFirst().orElse(null);//获取新班级信息
        //学生要加入新的班级信息处理
        moveClassHandleAddGroupStudent(addClassStudentList, addGroupStudentList, classVo, studentid);

        //获取新班级关联直播课关联的班级，并把学生加入
        courses = addCourseMap.get(classid);
        handleAddClassCourse(addClassStudentList, addGroupStudentList, changeCourseidList, courses, studentid);

        List<Integer> delClassidList = delStudentList.stream().map(TClassStudent::getClassid).distinct().collect(Collectors.toList());
        classStudentMapper.deleteBatchStudent2(delStudentList);//批量删除班级、分组对应学生
        classStudentMapper.saveBatchClassStudent(addClassStudentList);//批量新增班级学生
        groupStudentMapper.saveBatchGroupStudent(addGroupStudentList);//批量新增班级分组学生

        //新增学生的班级id集合
        List<Integer> saveclassids = addClassStudentList.stream().map(TClassStudent::getClassid).distinct().collect(Collectors.toList());
        delClassidList.addAll(saveclassids);

        classids.addAll(delClassidList);
        if (N_Utils.isListNotEmpty(changeCourseidList)) {
            courseids.addAll(changeCourseidList);
        }
        return new AsyncResult<>(true);
    }
}
