'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([ { $addFields: { u_id: { $toString: '$_id' } } }, { $match: { planid } }, { $lookup: { from: 'user', localField: 'u_id', foreignField: 'uid', as: 'user', }, }, { $match: { 'user.type': '4', 'user.openid': { $exists: true } } }, { $count: 'total' }, ]); const h = _.head(trainstuRes); const { total: trainstu } = h; data.trainstu = trainstu; // 已上传的学生总数 const schstu = await this.ctx.model.Student.count({ planid }); data.schstu = schstu; // 未参加培训的学生 const notrainstu = schstu - 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 }) { console.log(id); // 取得当前年份计划信息 console.log(moment().format('YYYY')); const plan = await this.tmodel.findOne({ year: moment().format('YYYY') }); if (!plan) { throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '当前全年计划不存在'); } // 根据计划取得当前年份下计划学校培训学生人数 const school = await this.schmodel.findOne({ code: id }); if (!school) { throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '学校信息不存在'); } const data = {}; data.planstu = school.number; // 根据学校id取得学校上报的学生数 const schstus = await this.smodel.find({ planid: plan.id, schid: id }); data.schstu = schstus.length; // 取得已培训的学生数 const trainstu = schstus.filter(item => item.openid); data.trainstu = trainstu.length; // 取得内未培训的学生数 const notrainstu = schstus.filter(item => !item.openid); data.notrainstu = notrainstu.length; // 取得学生请假数和退出数 const levelstus = []; // 循环取得所有请假和退出的学生信息 for (const elm of trainstu) { const level = await this.lmodel.findOne({ studentid: elm.id, status: '1' }); if (level) { levelstus.push(level); } } // 筛选出请假数和退出数 const levelqj = levelstus.filter(item => item.type === '0'); const levelexit = levelstus.filter(item => item.type === '1'); data.levelqj = levelqj.length; data.levelexit = levelexit.length; return data; } } module.exports = CountService;