|
@@ -1,6 +1,5 @@
|
|
|
'use strict';
|
|
|
|
|
|
-
|
|
|
const assert = require('assert');
|
|
|
const _ = require('lodash');
|
|
|
const { ObjectId } = require('mongoose').Types;
|
|
@@ -33,7 +32,8 @@ class ClassService extends CrudService {
|
|
|
if (!newclass) {
|
|
|
throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '班级信息不存在');
|
|
|
}
|
|
|
- // 根据计划和期查询所有上报的学生 并按照学校排序
|
|
|
+ // 根据计划和期
|
|
|
+ // 查询所有上报的学生 并按照学校排序
|
|
|
const newstudent = await this.stumodel.find({ termid }).sort({ schid: 1 });
|
|
|
if (!newstudent) {
|
|
|
throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '学生信息不存在');
|
|
@@ -42,6 +42,7 @@ class ClassService extends CrudService {
|
|
|
const claGroup = _.groupBy(newclass, 'batchid');
|
|
|
const keys = Object.keys(claGroup);
|
|
|
const result = {}; // key:班级id;value:学生id数组
|
|
|
+ let cantSolveNotice = false;
|
|
|
// 循环批次
|
|
|
for (const bkey of keys) {
|
|
|
const classList = claGroup[bkey]; // 该批次下的班级列表
|
|
@@ -71,7 +72,6 @@ class ClassService extends CrudService {
|
|
|
// 存入最佳计算结果,但是需要验证,看看这批次的计算结果是否<=班级最少人数;多了可是要吐人的.吐人的写法代码更多
|
|
|
solve[`${skey}-boy`] = br;
|
|
|
solve[`${skey}-girl`] = gr;
|
|
|
-
|
|
|
}
|
|
|
// 验证最佳结果是否超出班级的最少人数,不是,则处理
|
|
|
// console.log('计算最优解');
|
|
@@ -99,15 +99,17 @@ class ClassService extends CrudService {
|
|
|
// console.log('补人前');
|
|
|
// 检查是否有学生剩余,如果有学生剩余,都需要继续进行人的处理,无论是补人还是加人.
|
|
|
let els = _.flatten(Object.values(studentGroup)).length;
|
|
|
+ // 无法解决,需要手动分配标识
|
|
|
+ let cantSolve = false;
|
|
|
// 没有剩余的学生,下面也没法处理,结束了(跳过while了)
|
|
|
- while (els > 0) {
|
|
|
+ while (els > 0 && !cantSolve) {
|
|
|
// 还有学生,那就需要继续处理,看看是补人还是加人
|
|
|
// 检查各个班级是否达到人数要求
|
|
|
const { ok, not } = this.checkClassStatus(result, classList);
|
|
|
// 如果not里有值,说明还有班级没满足人数要求->补人
|
|
|
// 如果not没有值,说明参培人员多了->分到每个班里
|
|
|
if (not.length > 0) {
|
|
|
- // 进行补人
|
|
|
+ // 进行补人
|
|
|
// not中的每个班进行补人,每个班补一个人(result[classid]加人),studentGroup[key]减人
|
|
|
// 如果没人了,break;
|
|
|
for (const c of not) {
|
|
@@ -115,6 +117,11 @@ class ClassService extends CrudService {
|
|
|
const { _id } = c;
|
|
|
const stuList = result[_id];
|
|
|
const claSolve = this.getClassSolve(stuList);
|
|
|
+ // 没有最优解=>没有班级有学生.人数甚至不满足把班级填满.需要手动安排
|
|
|
+ if (claSolve.length <= 0 && els > 0) {
|
|
|
+ cantSolve = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
// 根据solve结果,取对应的值,然后做加减
|
|
|
for (const s of claSolve) {
|
|
|
const { schid, gender } = s;
|
|
@@ -124,19 +131,24 @@ class ClassService extends CrudService {
|
|
|
result[_id].push(head);
|
|
|
midList = _.drop(midList);
|
|
|
studentGroup[`${schid}-${gender}`] = midList;
|
|
|
- break;// 一次,一班只补一个的重要关键词
|
|
|
+ break; // 一次,一班只补一个的重要关键词
|
|
|
}
|
|
|
}
|
|
|
} else {
|
|
|
- // 额外加人
|
|
|
- // 说明下这里为什么要ok:因为在上面的solve,强制以班级最少的人数为均分标准
|
|
|
- // 所以在班级人数不均等的情况下,出现某班均分完是正好的人数,剩下的班少人,但这时还得先把少人的班先补上才能均摊多的人
|
|
|
- // 为什么要说明,因为下面代码除了循环的 数组 外,都一样啊
|
|
|
+ // 额外加人
|
|
|
+ // 说明下这里为什么要ok:因为在上面的solve,强制以班级最少的人数为均分标准
|
|
|
+ // 所以在班级人数不均等的情况下,出现某班均分完是正好的人数,剩下的班少人,但这时还得先把少人的班先补上才能均摊多的人
|
|
|
+ // 为什么要说明,因为下面代码除了循环的 数组 外,都一样啊
|
|
|
for (const c of ok) {
|
|
|
- // 需要计算出这个班补人的最优解
|
|
|
+ // 需要计算出这个班补人的最优解
|
|
|
const { _id } = c;
|
|
|
const stuList = result[_id];
|
|
|
const claSolve = this.getClassSolve(stuList);
|
|
|
+ // 没有最优解=>没有班级有学生.人数甚至不满足把班级填满.需要手动安排
|
|
|
+ if (claSolve.length <= 0 && els > 0) {
|
|
|
+ cantSolve = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
// 根据solve结果,取对应的值,然后做加减
|
|
|
for (const s of claSolve) {
|
|
|
const { schid, gender } = s;
|
|
@@ -153,8 +165,7 @@ class ClassService extends CrudService {
|
|
|
// 重新计算人数,就是上面的els计算再执行一次
|
|
|
els = _.flatten(Object.values(studentGroup)).length;
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
+ if (cantSolve) cantSolveNotice = true;
|
|
|
}
|
|
|
// for (const key in result) {
|
|
|
// console.group(key);
|
|
@@ -175,6 +186,7 @@ class ClassService extends CrudService {
|
|
|
for (const cla of claList) {
|
|
|
await this.ctx.service.student.arrangeNumber({ classid: cla._id });
|
|
|
}
|
|
|
+ if (cantSolveNotice) throw new BusinessError(ErrorCode.SERVICE_FAULT, '剩余人数无法继续自动安排,请手动分配班级');
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -207,7 +219,8 @@ class ClassService extends CrudService {
|
|
|
for (const c of classList) {
|
|
|
const { _id, number } = c;
|
|
|
const nowNum = alreadyList[_id].length;
|
|
|
- if (nowNum < number) not.push(c); else ok.push(c);
|
|
|
+ if (nowNum < number) not.push(c);
|
|
|
+ else ok.push(c);
|
|
|
}
|
|
|
// 需要排序,需要按上限人数排列,把人少的放上面
|
|
|
ok = _.orderBy(ok, [ 'number' ], [ 'asc' ]);
|
|
@@ -258,7 +271,6 @@ class ClassService extends CrudService {
|
|
|
return solve;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
// 取得同样类型的学生
|
|
|
async getstutype(_students, type) {
|
|
|
const data = [];
|
|
@@ -273,6 +285,8 @@ class ClassService extends CrudService {
|
|
|
|
|
|
// 自动生成班级私有方法
|
|
|
async autoclass(planid, termid) {
|
|
|
+ // 将本期的学生都重新初始回无班级状态
|
|
|
+ await this.stumodel.updateMany({ termid }, { classid: undefined });
|
|
|
// 删除所有计划下的班级
|
|
|
await this.model.deleteMany({ planid, termid });
|
|
|
// 删除该期课表
|
|
@@ -382,7 +396,6 @@ class ClassService extends CrudService {
|
|
|
await this.ctx.service.student.arrangeNumber({ classid: classid_ });
|
|
|
// TODO 根据模板复制班级信息
|
|
|
await this.toSetClassSetting({ classid: classid_ });
|
|
|
-
|
|
|
}
|
|
|
|
|
|
async notice(data) {
|
|
@@ -485,7 +498,6 @@ class ClassService extends CrudService {
|
|
|
}
|
|
|
}
|
|
|
return data;
|
|
|
-
|
|
|
}
|
|
|
|
|
|
async fetch({ id }) {
|
|
@@ -536,7 +548,7 @@ class ClassService extends CrudService {
|
|
|
const b = batchnum.id(batchid);
|
|
|
if (!b) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到班级的批次信息');
|
|
|
const { batch, startdate, enddate } = b;
|
|
|
- if (batch)cla.batch = batch;
|
|
|
+ if (batch) cla.batch = batch;
|
|
|
if (startdate) cla.startdate = startdate;
|
|
|
if (enddate) cla.enddate = enddate;
|
|
|
// 礼仪教师
|
|
@@ -571,7 +583,6 @@ class ClassService extends CrudService {
|
|
|
return cla;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
async upclasses(data) {
|
|
|
for (const _data of data) {
|
|
|
await this.model.findByIdAndUpdate(_data.id, _data);
|