teacher.js 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. 'use strict';
  2. const assert = require('assert');
  3. const _ = require('lodash');
  4. const moment = require('moment');
  5. const XLSX = require('xlsx');
  6. const { CrudService } = require('naf-framework-mongoose/lib/service');
  7. const { BusinessError, ErrorCode } = require('naf-core').Error;
  8. const stringRandom = require('string-random');
  9. const { ObjectId } = require('mongoose').Types;
  10. class TeacherService extends CrudService {
  11. constructor(ctx) {
  12. super(ctx, 'teacher');
  13. this.model = this.ctx.model.Teacher;
  14. this.umodel = this.ctx.model.User;
  15. const { baseUrl } = _.get(this.ctx.app.config, 'mission');
  16. if (baseUrl) this.missionBase = baseUrl;
  17. }
  18. async query({ name, ...info } = {}, { skip = 0, limit = 0 } = {}) {
  19. const query = { ...info };
  20. if (name) {
  21. query.name = { $regex: name };
  22. }
  23. let res = await this.model.find(query).skip(Number(skip)).limit(Number(limit));
  24. res = JSON.parse(JSON.stringify(res));
  25. for (const tea of res) {
  26. const r = await this.umodel.findOne({ uid: tea._id }, '+passwd');
  27. if (r) {
  28. const { passwd } = r;
  29. tea.secret = passwd.secret;
  30. tea.openid = _.get(r, 'openid');
  31. }
  32. }
  33. return res;
  34. }
  35. async count({ name, ...info } = {}) {
  36. const query = { ...info };
  37. if (name) {
  38. query.name = { $regex: name };
  39. }
  40. const res = await this.model.count(query);
  41. return res;
  42. }
  43. // 根据状态删除教师信息
  44. async deleteByStatus({ status }) {
  45. await this.model.deleteMany({ status });
  46. return 'deleted';
  47. }
  48. // 查询详情
  49. async fetchTeacher({ id }) {
  50. // 将文件拼到查询到的数据后
  51. return await this.model.findById(id, '+file');
  52. }
  53. async create(data) {
  54. const { name, phone: mobile } = data;
  55. const user = await this.umodel.findOne({ mobile });
  56. if (user) {
  57. throw new BusinessError(ErrorCode.DATA_EXIST, '电话已经存在');
  58. }
  59. // 创建教师信息
  60. const res = await this.model.create(data);
  61. // 再创建教师用户
  62. const passwd = stringRandom();
  63. const newdata = {
  64. name,
  65. mobile,
  66. type: '3',
  67. uid: ObjectId(res.id || res._id).toString(),
  68. passwd: { secret: passwd },
  69. };
  70. await this.umodel.create(newdata);
  71. // 返回教师信息
  72. return this.model.findById(res._id || res.id);
  73. }
  74. async delete({ id }) {
  75. await this.model.findByIdAndDelete(id);
  76. await this.umodel.deleteOne({ uid: id, type: '3' });
  77. return 'deleted';
  78. }
  79. // 批量查询教师
  80. async fetchteachers({ ids }) {
  81. return await this.model.find({ _id: { $in: ids } });
  82. }
  83. // 检查教师
  84. async checkarrange({ id, date }) {}
  85. async status(data) {
  86. const { teachersid, zlscore, msscore, status, remark } = data;
  87. for (const teacherid of teachersid) {
  88. const teacher = await this.model.findById(teacherid);
  89. console.log(status);
  90. teacher.status = status;
  91. if (zlscore) {
  92. teacher.zlscore = zlscore;
  93. }
  94. if (msscore) {
  95. teacher.msscore = msscore;
  96. }
  97. await teacher.save();
  98. let detail = '';
  99. if (status === '1') {
  100. const userInfo = await this.umodel.findOne({ uid: teacherid }, '+passwd');
  101. if (!userInfo) continue;
  102. const passwd = _.get(userInfo, 'passwd.secret');
  103. detail = '您的账号身份已确认,密码为:' + passwd + '请尽快登录账号上传课件资料附件';
  104. } else if (status === '4') {
  105. detail = '您已通过审核被正式录入教师库';
  106. }
  107. const date = await this.ctx.service.util.updatedate();
  108. const user = await this.umodel.findOne({ uid: teacher.id, type: '3' });
  109. if (user && user.openid) {
  110. await this.ctx.service.weixin.sendTemplateMsg(this.ctx.app.config.REVIEW_TEMPLATE_ID, user.openid, '您有一个新的通知', detail, date, remark);
  111. } else {
  112. await this.ctx.service.util.sendMail(teacher.email, '账号审核', detail, '');
  113. }
  114. }
  115. }
  116. // 教室分数上传
  117. async teaimport(data) {
  118. const { filepath } = data;
  119. assert(filepath, 'filepath不能为空');
  120. // 取得excle中数据
  121. const _filepath = this.ctx.app.config.baseUrl + filepath;
  122. const teadatas = await this.getImportXLSXData(_filepath);
  123. // 将得到的数据校验
  124. const datacheck = await this.datacheck(teadatas);
  125. if (datacheck.errorcode === '1') {
  126. return datacheck;
  127. }
  128. // 将数据存入数据库中
  129. for (const tea of teadatas) {
  130. const res = await this.model.findOne({
  131. idnumber: tea.idnumber,
  132. name: tea.name,
  133. });
  134. if (res) {
  135. res.beforescore = tea.xsscore;
  136. await res.save();
  137. }
  138. }
  139. return datacheck;
  140. }
  141. // 获取导入的XLSX文件中的数据
  142. async getImportXLSXData(filepath) {
  143. const file = await this.ctx.curl(filepath);
  144. const workbook = XLSX.read(file.data);
  145. // 读取内容
  146. let exceldata = [];
  147. const sheetNames = workbook.SheetNames; // 获取表名
  148. const sheet = workbook.Sheets[sheetNames[0]]; // 通过表名得到表对象
  149. // 遍历26个字母
  150. const theadRule = [];
  151. const range = XLSX.utils.decode_range(sheet['!ref']);
  152. const col_start = range.s.c;
  153. const col_end = range.e.c;
  154. for (let i = col_start; i <= col_end; i++) {
  155. const addr = XLSX.utils.encode_col(i) + XLSX.utils.encode_row(0);
  156. theadRule.push(sheet[addr].v);
  157. }
  158. const params = XLSX.utils.sheet_to_json(sheet); // 通过工具将表对象的数据读出来并转成json
  159. if (!params) return [];
  160. const length = params.length;
  161. const _datas = [];
  162. let data = {};
  163. for (let i = 0; i < length; i++) {
  164. data = params[i];
  165. _datas.push({
  166. idnumber: data[theadRule[1]],
  167. name: data[theadRule[2]],
  168. xsscore: data[theadRule[3]],
  169. });
  170. }
  171. exceldata = [ ...exceldata, ..._datas ];
  172. return exceldata;
  173. }
  174. // 获取导入的XLSX文件中的数据
  175. async datacheck(studatas) {
  176. let errorcode = '0';
  177. const errormsg = [];
  178. for (const data of studatas) {
  179. // 判断是否为空
  180. if (!data.idnumber) {
  181. errorcode = '1';
  182. data.msg = data.msg + '身份证号不允许为空,';
  183. }
  184. if (!data.name) {
  185. errorcode = '1';
  186. data.msg = data.msg + '姓名不允许为空,';
  187. }
  188. if (!data.xsscore) {
  189. errorcode = '1';
  190. data.msg = data.msg + '评分不允许为空,';
  191. }
  192. if (errorcode === '1') {
  193. errormsg.push(data);
  194. }
  195. }
  196. return { errorcode, errormsg };
  197. }
  198. // 建立任务
  199. async toExport(body) {
  200. const fn = `教师导出 ${moment().format('YYYY-MM-DD HH:SS:mm')}`;
  201. const data = {
  202. title: fn,
  203. params: {
  204. project: 'center',
  205. service: 'teacher',
  206. method: 'export',
  207. body,
  208. },
  209. };
  210. if (this.missionBase) {
  211. const url = `${this.missionBase}/api/mission`;
  212. const res = await this.ctx.curl(url, {
  213. method: 'post',
  214. headers: {
  215. 'content-type': 'application/json',
  216. },
  217. data,
  218. dataType: 'json',
  219. });
  220. if (res.status !== 200 || res.data.errcode !== 0) {
  221. throw new BusinessError(ErrorCode.SERVICE_FAULT, '创建任务失败');
  222. }
  223. } else {
  224. throw new BusinessError(ErrorCode.SERVICE_FAULT, '未找到任务项目设置');
  225. }
  226. }
  227. // 导出
  228. async export({ missionid, model }) {
  229. assert(missionid, '缺少任务信息,无法执行任务');
  230. try {
  231. const head = model.map(i => {
  232. const { zh, model } = i;
  233. const headObj = { header: zh };
  234. if (model) headObj.key = model;
  235. headObj.width = 20;
  236. return headObj;
  237. });
  238. const fn = '教师导出';
  239. const data = await this.query();
  240. console.log(data.length);
  241. if (data.length <= 0) {
  242. throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到教师信息');
  243. }
  244. this.ctx.service.util.updateProcess(missionid, '50');
  245. const res = await this.ctx.service.util.toExcel(data, head, fn);
  246. console.log(res);
  247. if (!res) {
  248. console.error(`${moment().format('YYYY-MM-DD HH:mm:ss')} ${fn} 导出失败`);
  249. throw new BusinessError(ErrorCode.SERVICE_FAULT, `${fn}导出失败`);
  250. }
  251. this.ctx.service.util.updateProcess(missionid, '100', '2', {
  252. uri: res,
  253. });
  254. } catch (error) {
  255. console.log('in function:error');
  256. this.ctx.service.util.updateProcess(missionid, undefined, '3');
  257. }
  258. }
  259. }
  260. module.exports = TeacherService;