PaperParams.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. <template>
  2. <el-dialog
  3. class="paper-params"
  4. :visible.sync="modalIsShow"
  5. top="10px"
  6. width="785px"
  7. :close-on-click-modal="false"
  8. :close-on-press-escape="false"
  9. append-to-body
  10. @open="dialogOpen"
  11. >
  12. <h1 class="params-dialog-title" slot="title">
  13. 请上传阅卷参数
  14. <span
  15. >卷面总分合计:<em class="param-sum-score">{{ pageSumScore }}分</em>
  16. </span>
  17. </h1>
  18. <div class="params-main">
  19. <div class="params-head">
  20. <el-button
  21. :type="!topicType ? 'primary' : 'default'"
  22. @click="selectType(0)"
  23. >客观题区</el-button
  24. >
  25. <el-button
  26. :type="topicType ? 'primary' : 'default'"
  27. @click="selectType(1)"
  28. >主观题区</el-button
  29. >
  30. </div>
  31. <div class="params-body">
  32. <div style="text-align:right;">
  33. <upload-button
  34. btn-icon="icon icon-share"
  35. btn-content="选择上传主观题标答文件(doc/docx)"
  36. btn-type="warning"
  37. :upload-url="uploadUrl"
  38. :format="['doc', 'docx']"
  39. @upload-error="uplaodError"
  40. @upload-success="uploadSuccess"
  41. style="margin: 0;"
  42. v-if="topicType"
  43. >
  44. </upload-button>
  45. </div>
  46. <div class="params-part" v-for="topic in curTopicList" :key="topic.id">
  47. <h2 class="params-title">{{ topic.topicName }}</h2>
  48. <p class="params-subtitle">
  49. <span>题型:{{ topic.name }}</span>
  50. <span v-if="topic.type !== 'COMPOSITION'">
  51. 通配小题分值:
  52. <el-input-number
  53. v-model="topic.commonQuestionScore"
  54. size="small"
  55. :min="0.1"
  56. :max="200"
  57. :step="0.1"
  58. step-strictly
  59. :controls="false"
  60. @change="commonQuestionScoreChange(topic)"
  61. ></el-input-number
  62. >分,</span
  63. >
  64. <span
  65. >本大题总分合计:<em class="param-sum-score"
  66. >{{ topic.sumScore }}分</em
  67. ></span
  68. >
  69. </p>
  70. <div class="params-table" v-if="topic.type !== 'COMPOSITION'">
  71. <table class="table table-striped">
  72. <tr>
  73. <th>题号</th>
  74. <th>分值</th>
  75. <th>题号</th>
  76. <th>分值</th>
  77. </tr>
  78. <tr v-for="(group, gindex) in topic.questions" :key="gindex">
  79. <template v-for="question in group">
  80. <td :key="`${question.questionNo}-1`">
  81. <span>{{ question.questionNo }}</span>
  82. </td>
  83. <td :key="`${question.questionNo}-2`">
  84. <el-input-number
  85. v-model="question.score"
  86. size="small"
  87. :min="0.1"
  88. :max="200"
  89. :step="0.1"
  90. step-strictly
  91. :controls="false"
  92. @change="questionScoreChange(topic)"
  93. v-if="question.questionNo"
  94. ></el-input-number>
  95. </td>
  96. </template>
  97. </tr>
  98. </table>
  99. </div>
  100. <div class="params-table" v-else>
  101. <el-input-number
  102. v-model="topic.sumScore"
  103. :min="0.1"
  104. :max="200"
  105. :step="0.1"
  106. step-strictly
  107. :controls="false"
  108. @change="getPageSumScore"
  109. ></el-input-number>
  110. </div>
  111. </div>
  112. </div>
  113. </div>
  114. <div slot="footer" style="text-align: right;">
  115. <el-button type="primary" @click="submit">确认</el-button>
  116. <el-button type="danger" @click="cancel" plain>取消</el-button>
  117. </div>
  118. </el-dialog>
  119. </template>
  120. <script>
  121. import { calcSum, isEmptyObject, objAssign } from "../plugins/utils";
  122. import UploadButton from "./UploadButton";
  123. export default {
  124. name: "paper-params",
  125. components: { UploadButton },
  126. props: {
  127. pages: {
  128. type: Array,
  129. default() {
  130. return [];
  131. }
  132. },
  133. paperParams: {
  134. type: Object,
  135. default() {
  136. return {};
  137. }
  138. }
  139. },
  140. data() {
  141. return {
  142. modalIsShow: false,
  143. topicType: 0,
  144. pageSumScore: 0,
  145. subjectiveAttachmentId: "",
  146. curTopicList: [],
  147. objectives: [],
  148. subjectives: [],
  149. cacheScores: {},
  150. initTopic: {
  151. id: "",
  152. topicNo: "",
  153. topicName: "",
  154. type: ""
  155. },
  156. // import
  157. uploadUrl: "/api/print/basic/sys/saveAttachment"
  158. };
  159. },
  160. methods: {
  161. selectType(topicType) {
  162. this.topicType = topicType;
  163. this.curTopicList = topicType ? this.subjectives : this.objectives;
  164. },
  165. listIncludeItem(list, item) {
  166. const index = list.findIndex(elem => elem.id === item.id);
  167. return index !== -1;
  168. },
  169. dialogOpen() {
  170. if (!isEmptyObject(this.paperParams)) {
  171. this.getCacheScore([
  172. ...this.paperParams.objectives,
  173. ...this.paperParams.subjectives
  174. ]);
  175. this.subjectiveAttachmentId = this.paperParams.subjectiveAttachmentId;
  176. }
  177. // 每次打开时,重新生成试题结构,以便避免题卡结构变化之后,当前页面的试题结构没有变的问题
  178. let objectiveList = [];
  179. let subjectiveList = [];
  180. let objectives = [];
  181. let subjectives = [];
  182. this.pages.forEach(page => {
  183. page.columns.forEach(column => {
  184. column.elements.forEach(element => {
  185. if (
  186. element.sign &&
  187. element.type !== "TOPIC_HEAD" &&
  188. element.type !== "CARD_HEAD"
  189. ) {
  190. if (element.sign === "objective") objectiveList.push(element);
  191. if (element.sign === "subjective") subjectiveList.push(element);
  192. }
  193. });
  194. });
  195. });
  196. // 客观题
  197. objectiveList.forEach(item => {
  198. const topic = item.parent || item;
  199. if (this.listIncludeItem(objectives, topic)) return;
  200. let data = {
  201. sumScore: 0,
  202. commonQuestionScore: 1,
  203. name: this.getObjectiveTopicName(topic),
  204. choiceList: this.getChoiceList(topic),
  205. questions: this.getQuestions(topic),
  206. ...objAssign(this.initTopic, topic)
  207. };
  208. data.sumScore = this.getTopicSumScore(data);
  209. objectives.push(data);
  210. });
  211. // 主观题
  212. subjectiveList.forEach(item => {
  213. const topic = item.parent || item;
  214. if (this.listIncludeItem(subjectives, topic)) return;
  215. let data = {
  216. sumScore: 0,
  217. commonQuestionScore: 1,
  218. name: this.getSubjectiveTopicName(topic),
  219. ...objAssign(this.initTopic, topic)
  220. };
  221. if (topic.type === "COMPOSITION") {
  222. data.sumScore = this.cacheScores[topic.topicNo] || 1;
  223. } else {
  224. data.questions = this.getQuestions(topic);
  225. data.sumScore = this.getTopicSumScore(data);
  226. }
  227. subjectives.push(data);
  228. });
  229. this.subjectives = subjectives;
  230. this.objectives = objectives;
  231. this.getPageSumScore();
  232. this.selectType(0);
  233. },
  234. getQuestions(topic) {
  235. let questions = [];
  236. let numPerColumn = Math.ceil(topic.questionsCount / 2);
  237. for (let j = topic.startNumber; j <= numPerColumn; j++) {
  238. let group = [];
  239. let question = {
  240. questionNo: j,
  241. score: this.cacheScores[`${topic.topicNo}-${j}`] || 1
  242. };
  243. if (topic.type === "FILL_QUESTION")
  244. question.answers = topic.isMultiply ? [] : "";
  245. group[0] = question;
  246. if (numPerColumn + j <= topic.questionsCount) {
  247. group[1] = {
  248. questionNo: numPerColumn + j,
  249. score:
  250. this.cacheScores[`${topic.topicNo}-${numPerColumn + j}`] || 1,
  251. answers:
  252. topic.type === "FILL_QUESTION" && topic.isMultiply ? [] : ""
  253. };
  254. } else {
  255. group[1] = { questionNo: "" };
  256. }
  257. questions.push(group);
  258. }
  259. return questions;
  260. },
  261. getObjectiveTopicName(data) {
  262. if (data.isMultiply) {
  263. return "选择题(多选)";
  264. } else if (data.isBoolean) {
  265. return "填空题";
  266. } else {
  267. return "选择题(单选)";
  268. }
  269. },
  270. getSubjectiveTopicName(data) {
  271. const names = {
  272. EXPLAIN: "解答题",
  273. COMPOSITION: "作文题",
  274. FILL_LINE: "填空题"
  275. };
  276. return names[data.type];
  277. },
  278. getChoiceList(data) {
  279. const options = data.isBoolean
  280. ? data.booleanType
  281. : "abcdefghijklmnopqrstuv";
  282. return options
  283. .toUpperCase()
  284. .slice(0, data.optionCount)
  285. .split("");
  286. },
  287. commonQuestionScoreChange(topic) {
  288. topic.questions.map(group => {
  289. group.map(question => {
  290. question.score = topic.commonQuestionScore;
  291. });
  292. });
  293. this.questionScoreChange(topic);
  294. },
  295. questionScoreChange(topic) {
  296. topic.sumScore = this.getTopicSumScore(topic);
  297. this.getPageSumScore();
  298. },
  299. getTopicSumScore(topic) {
  300. const scoreList = topic.questions.map(group => {
  301. return calcSum(group.map(question => question.score || 0));
  302. });
  303. return calcSum(scoreList);
  304. },
  305. getPageSumScore() {
  306. this.pageSumScore =
  307. calcSum(this.objectives.map(item => item.sumScore)) +
  308. calcSum(this.subjectives.map(item => item.sumScore));
  309. },
  310. getCacheScore(topics) {
  311. topics = topics || [...this.objectives, ...this.subjectives];
  312. let cacheScores = {};
  313. topics.map(topic => {
  314. if (topic.type === "COMPOSITION") {
  315. cacheScores[`${topic.topicNo}`] = topic.sumScore;
  316. } else {
  317. topic.questions.map(group => {
  318. group.map(question => {
  319. cacheScores[`${topic.topicNo}-${question.questionNo}`] =
  320. question.score;
  321. });
  322. });
  323. }
  324. });
  325. this.cacheScores = cacheScores;
  326. },
  327. // import
  328. uplaodError(errorData) {
  329. this.$notify.error({ title: "错误提示", message: errorData.message });
  330. },
  331. uploadSuccess(response) {
  332. this.$message.success("上传成功!");
  333. this.subjectiveAttachmentId = response.data.id;
  334. },
  335. // dialog
  336. cancel() {
  337. this.modalIsShow = false;
  338. },
  339. open() {
  340. this.modalIsShow = true;
  341. },
  342. submit() {
  343. this.$emit("confirm", {
  344. pageSumScore: this.pageSumScore,
  345. objectives: this.objectives,
  346. subjectives: this.subjectives,
  347. subjectiveAttachmentId: this.subjectiveAttachmentId
  348. });
  349. this.modalIsShow = false;
  350. }
  351. }
  352. };
  353. </script>