question.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. 'use strict';
  2. const { CrudService } = require('naf-framework-mongoose-free/lib/service');
  3. const { BusinessError, ErrorCode } = require('naf-core').Error;
  4. const _ = require('lodash');
  5. const assert = require('assert');
  6. // 题目
  7. class QuestionService extends CrudService {
  8. constructor(ctx) {
  9. super(ctx, 'question');
  10. this.model = this.ctx.model.Question;
  11. this.excelService = this.ctx.service.excel;
  12. this.typeModel = this.ctx.model.QuestionType;
  13. }
  14. async import({ url }) {
  15. const data = await this.excelService.importExcel(url);
  16. const head = _.head(data);
  17. let meta = this.getMeta();
  18. // 将meta整理下,把对应的列加上,key为index
  19. meta = meta.map(i => {
  20. if (!i.children) {
  21. const rIndex = head.findIndex(f => f === i.label);
  22. if (rIndex >= 0) i.index = rIndex;
  23. } else {
  24. for (const c of i.children) {
  25. const rcIndex = head.findIndex(f => f === c.label);
  26. if (rcIndex >= 0) c.index = rcIndex;
  27. }
  28. }
  29. return i;
  30. });
  31. // 表头干掉,处理数据不需要它
  32. data.shift();
  33. const midData = [];
  34. for (const row of data) {
  35. // row:每行数据
  36. const questData = {};
  37. for (const m of meta) {
  38. // 检查有没有index;如果是直接m.index,需要排除 值=0的情况(不明白的话,let x = 0,然后if(x)走下就知道了)
  39. // 所以换了个写法,只检查有没有该key
  40. const keys = Object.keys(m);
  41. if (!keys.includes('index') && !keys.includes('children')) continue;
  42. const { key, index, type, format } = m;
  43. if (!m.children) {
  44. const val = row[index];
  45. if (format && _.isFunction(format)) questData[key] = format(val);
  46. else questData[key] = val;
  47. } else {
  48. // 根据meta创建类型
  49. questData[key] = type === 'Array' ? [] : {};
  50. // 添加数据的方法
  51. const addToObject = type === 'Array' ? data => questData[key].push(data) : data => (questData[key] = { ...questData[key], ...data });
  52. const midObject = {};
  53. for (const c of m.children) {
  54. const { key: ckey, index: cIndex, format } = c;
  55. const val = row[cIndex];
  56. if (format && _.isFunction(format)) midObject[ckey] = format(val);
  57. else midObject[ckey] = val;
  58. }
  59. addToObject(midObject);
  60. }
  61. }
  62. midData.push(questData);
  63. }
  64. // 处理题
  65. let list = this.dealImportData(midData);
  66. // 将type换成系统中有的题型的id
  67. list = await this.changeType(list);
  68. const res = await this.model.insertMany(list);
  69. return res;
  70. }
  71. /**
  72. * 处理type换成系统中有的题型的id
  73. * @param {Array} array 数据数组,除type外所有数据已经处理完
  74. */
  75. async changeType(array) {
  76. const typeList = await this.typeModel.find();
  77. for (const i of array) {
  78. // 此处需要检验.该题型的答案是单选/多选
  79. const r = typeList.find(f => i.type === f.title);
  80. if (r)i.type = r._id;
  81. }
  82. return array;
  83. }
  84. /**
  85. * 将数据整理成数据库格式
  86. * @param {Array} array 数据数组,title和type为题目分界,只是选项的话,没有
  87. */
  88. dealImportData(array) {
  89. const list = [];
  90. let operaData = {};
  91. for (const i of array) {
  92. if (_.get(i, 'title') && _.get(i, 'type')) {
  93. if (_.get(operaData, 'title') && _.get(operaData, 'type')) {
  94. // 之前的题合并完了.该下一题了
  95. list.push(_.cloneDeep(operaData));
  96. // 新题
  97. operaData = i;
  98. } else {
  99. // 新题合并
  100. operaData = i;
  101. }
  102. } else {
  103. // 合并选项
  104. if (_.isArray(operaData.selects) && _.isArray(i.selects)) {
  105. operaData.selects = [ ...operaData.selects, ...i.selects ];
  106. }
  107. }
  108. }
  109. // 循环结束后,最后一个题扔保留在operaData中,放进list里
  110. if (operaData.title) {
  111. list.push(operaData);
  112. }
  113. return list;
  114. }
  115. getMeta() {
  116. return [
  117. { label: '题目', key: 'title' },
  118. { label: '题型', key: 'type', remark: '需要用字符串找到question_type的title一致的数据,将id拿来' },
  119. {
  120. key: 'selects',
  121. type: 'Array',
  122. children: [
  123. { label: '答案内容', key: 'title' },
  124. {
  125. label: '是否正确',
  126. key: 'isRight',
  127. format: i => {
  128. if (i === '是') return true;
  129. },
  130. },
  131. ],
  132. },
  133. ];
  134. }
  135. }
  136. module.exports = QuestionService;