'use strict'; const assert = require('assert'); const _ = require('lodash'); const { ObjectId } = require('mongoose').Types; const moment = require('moment'); const { CrudService } = require('naf-framework-mongoose/lib/service'); const { BusinessError, ErrorCode } = require('naf-core').Error; class CountService extends CrudService { constructor(ctx) { super(ctx, 'count'); this.smodel = this.ctx.model.Student; this.tmodel = this.ctx.model.Trainplan; this.lmodel = this.ctx.model.Leave; this.schmodel = this.ctx.model.School; this.setmodel = this.ctx.model.Setting; } // 查询 async countstudent() { // levelexit:退出人数 √ // levelqj:请假人数 √ // notrainstu:上传名单,但是未培训人数 student表中的数据不稳,后加的可能没有了.被人绑定更换也可能没有了.所以 这个数字用 student.total - user(type=4&&openid) 的结果 √ // schstu:上传名单人数 该年度计划下,的student.total √ // trainstu:已参加培训人数 user(type==4&&openid).total √ // planstu:年度计划人数(重算) 根据年度计划学校的分配计算 √ // schs:[{schname 学校名称,schnum 学校人数}] 学校上传人数 试用聚合做 √ // 取得当前年份计划信息 const setting = await this.setmodel.findOne(); if (!setting) { throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '没有找到默认设置'); } const { planid } = setting; if (!planid) { throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '没有找到默认年度计划'); } const trainPlan = await this.tmodel.findById(planid); if (!trainPlan) { throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '没有找到默认年度计划'); } let { termnum } = trainPlan; if (!_.isArray(termnum)) { throw new BusinessError(ErrorCode.DATA_INVALID, '默认年度计划的期数据格式不正确'); } // 转换下,因为之后用的期id不是ObjectId termnum = JSON.parse(JSON.stringify(termnum)); const termids = termnum.map(i => i._id); const data = {}; // 请假,退出 const levelqj = await this.ctx.model.Leave.count({ termid: { $in: termids }, type: '0', status: '1', }); const levelexit = await this.ctx.model.Leave.count({ termid: { $in: termids }, type: '1', status: '1', }); data.levelqj = levelqj || 0; data.levelexit = levelexit || 0; // 参加培训的学生 const trainstuRes = await this.ctx.model.Student.aggregate([{ $match: { planid } }, { $match: { openid: { $exists: true } } }, { $count: 'total' }]); const h = _.head(trainstuRes); if (h) { let { total: trainstu } = h; // 减去退出的学生 trainstu = trainstu - data.levelexit || 0; data.trainstu = trainstu; } else { data.trainstu = 0; } // 已上传的学生总数 const schstu = await this.ctx.model.Student.count({ planid }); data.schstu = schstu; // 未参加培训的学生 const notrainstu = schstu - data.trainstu; data.notrainstu = notrainstu; // 年度计划实际人数 这个还没用聚合,不是很优雅 const mid = await this.ctx.model.Schtime.find({ planid }); const planstu = mid.reduce((p, n) => p + n.arrange.reduce((np, nn) => np + (nn.number * 1 || 0), 0), 0); data.planstu = planstu; // 各个学校上传的人数 const schs = await this.ctx.model.Student.aggregate([ { $match: { planid } }, { $group: { _id: '$schid', sum: { $sum: 1 } } }, { $lookup: { from: 'school', localField: '_id', foreignField: 'code', as: 'school', }, }, { $unwind: '$school' }, { $project: { _id: 0, schname: '$school.name', schnum: '$sum' } }, ]); data.schs = schs; return data; } // 按学校id统计查询 async countschstu({ id }) { // levelexit:退出人数 √ // levelqj:请假人数 √ // notrainstu:上传名单,但是未培训人数 student表中的数据不稳,后加的可能没有了.被人绑定更换也可能没有了.所以 这个数字用 student.total - user(type=4&&openid) 的结果 √ // schstu:上传名单人数 该年度计划下,的student.total √ // trainstu:已参加培训人数 user(type==4&&openid).total √ // planstu:年度计划人数(重算) 根据年度计划学校的分配计算 √ // leaveNum:请假人数未处理 √ // uploadNum:计划上报未处理 √ // 取得当前年份计划信息 const setting = await this.setmodel.findOne(); if (!setting) { throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '没有找到默认设置'); } const { planid, termid } = setting; if (!planid) { throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '没有找到默认年度计划'); } const trainPlan = await this.tmodel.findById(planid); if (!trainPlan) { throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '没有找到默认年度计划'); } let { termnum } = trainPlan; if (!_.isArray(termnum)) { throw new BusinessError(ErrorCode.DATA_INVALID, '默认年度计划的期数据格式不正确'); } // 转换下,因为之后用的期id不是ObjectId termnum = JSON.parse(JSON.stringify(termnum)); const termids = termnum.map(i => i._id); const data = {}; // 请假,退出 const levelqj = await this.ctx.model.Leave.count({ termid: { $in: termids }, type: '0', status: '1', schid: id, }); const levelexit = await this.ctx.model.Leave.count({ termid: { $in: termids }, type: '1', status: '1', schid: id, }); data.levelqj = levelqj || 0; data.levelexit = levelexit || 0; // 参加培训的学生 const trainstuRes = await this.ctx.model.Student.aggregate([ { $addFields: { u_id: { $toString: '$_id' } } }, { $match: { planid, schid: id } }, { $lookup: { from: 'user', localField: 'u_id', foreignField: 'uid', as: 'user', }, }, { $match: { 'user.type': '4', 'user.openid': { $exists: true } } }, { $count: 'total' }, ]); const h = _.head(trainstuRes); if (h) { let { total: trainstu } = h; // 减去退出的学生 trainstu = trainstu - data.levelexit || 0; data.trainstu = trainstu; } else { data.trainstu = 0; } // 已上传的学生总数 const schstu = await this.ctx.model.Student.count({ planid, schid: id }); data.schstu = schstu; // 未参加培训的学生 const notrainstu = schstu - data.trainstu; data.notrainstu = notrainstu; // 年度计划实际人数 这个还没用聚合,不是很优雅 const mid = await this.ctx.model.Schtime.find({ planid, schid: id }); const planstu = mid.reduce((p, n) => p + n.arrange.reduce((np, nn) => np + (nn.number * 1 || 0), 0), 0); data.planstu = planstu; // 请假或退出人数未处理 const leaveNum = await this.ctx.model.Leave.count({ termid, schid: id, status: '0', }); data.leaveNum = leaveNum || 0; // 计划上报学校上传学生名单 const schtime = await this.ctx.model.Schtime.findOne({ planid, schid: id }).lean(); const uploadNum = 0; if (schtime && schtime.arrange) { for (const val of schtime.arrange) { const { termid, batchid } = val; const studentTotal = await this.ctx.model.Student.count({ termid, batchid, schid: id }); if (studentTotal === 0) uploadNum + 1; } } data.uploadNum = uploadNum; return data; } } module.exports = CountService;