MarkParamClass.vue 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. <template>
  2. <div class="mark-param-class">
  3. <div class="part-box part-box-pad box-justify">
  4. <el-form inline>
  5. <el-form-item label="是否开启分班阅卷:">
  6. <el-radio-group v-model="classMarkIsOpen" @change="markClassChange">
  7. <el-radio-button :label="true">开启</el-radio-button>
  8. <el-radio-button :label="false">关闭</el-radio-button>
  9. </el-radio-group>
  10. </el-form-item>
  11. <el-form-item v-if="classMarkIsOpen">
  12. <el-breadcrumb class="el-space" separator="|">
  13. <el-breadcrumb-item
  14. >班级数:{{ stat.classCount }}个</el-breadcrumb-item
  15. >
  16. <el-breadcrumb-item
  17. >未分配评卷员班级数:<span class="color-danger">{{
  18. stat.unsignClassCount
  19. }}</span
  20. >个</el-breadcrumb-item
  21. >
  22. <el-breadcrumb-item
  23. >设置完成进度:<span class="color-primary"
  24. >{{ stat.completeRate }}%</span
  25. ></el-breadcrumb-item
  26. >
  27. </el-breadcrumb>
  28. </el-form-item>
  29. </el-form>
  30. <div>
  31. <el-button type="primary" @click="toPrev(1)">上一步</el-button>
  32. <el-button type="primary" @click="toNext(1)">下一步</el-button>
  33. </div>
  34. </div>
  35. <div v-if="classMarkIsOpen" class="part-box part-box-pad">
  36. <el-table :data="dataList" border>
  37. <el-table-column type="index" width="50"> </el-table-column>
  38. <el-table-column label="评卷员" width="300">
  39. <template slot-scope="scope">
  40. <el-tag size="medium">
  41. {{ scope.row.marker.name }}({{ scope.row.marker.loginName }})
  42. </el-tag>
  43. </template>
  44. </el-table-column>
  45. <el-table-column prop="markerClassList" label="评卷班级">
  46. <template slot-scope="scope">
  47. {{ scope.row.markerClassList.join() }}
  48. </template>
  49. </el-table-column>
  50. <el-table-column class-name="action-column" label="操作" width="120">
  51. <template slot-scope="scope">
  52. <el-button
  53. class="btn-primary"
  54. type="text"
  55. @click="toSelectClass(scope.row)"
  56. >选择班级</el-button
  57. >
  58. </template>
  59. </el-table-column>
  60. </el-table>
  61. <div class="tips-info tips-error mt-2">
  62. <template v-if="subjectiveTaskList.length <= 1">
  63. <p v-if="unsignData.length">
  64. 未分配班级:{{ unsignData.map((item) => item.className).join() }}
  65. </p>
  66. </template>
  67. <template v-else>
  68. <p
  69. v-for="item in unsignData"
  70. :key="item.className"
  71. style="white-space: pre-wrap"
  72. >
  73. {{ item.content }}
  74. </p>
  75. </template>
  76. </div>
  77. </div>
  78. <div v-else class="part-box part-box-pad">
  79. <p class="tips-info">1.分班阅卷即评卷老师评指定班级的卷子;</p>
  80. <p class="tips-info">
  81. 2.如果需要进行分班阅卷,请在点击开启,不需要可以直接点击下一步,进行主观题评卷设置;
  82. </p>
  83. </div>
  84. <!-- SelectClassByCourse -->
  85. <select-class-by-course
  86. ref="SelectClassByCourse"
  87. :selected-ids="selectedClassIds"
  88. :class-list="classList"
  89. required
  90. @confirm="classSelected"
  91. ></select-class-by-course>
  92. </div>
  93. </template>
  94. <script>
  95. import { markClassList, markClassSave, markClassStatusUpdate } from "../../api";
  96. import { mapState, mapMutations } from "vuex";
  97. import SelectClassByCourse from "./SelectClassByCourse.vue";
  98. import { toPrecision } from "@/plugins/utils";
  99. import { MD5 } from "@/plugins/md5";
  100. export default {
  101. name: "mark-param-class",
  102. components: { SelectClassByCourse },
  103. data() {
  104. return {
  105. dataList: [],
  106. cacheDataMd5: "",
  107. curRow: {},
  108. classList: [],
  109. selectedClassIds: [],
  110. loading: false,
  111. unsignData: [],
  112. classMarkIsOpen: false,
  113. };
  114. },
  115. computed: {
  116. ...mapState("markParam", [
  117. "basicInfo",
  118. "subjectiveTaskList",
  119. "openClassMark",
  120. ]),
  121. stat() {
  122. return {
  123. classCount: this.classList.length,
  124. unsignClassCount: this.unsignData.length,
  125. completeRate: toPrecision(
  126. (100 * this.unsignData.length) / this.classList.length,
  127. 2
  128. ),
  129. };
  130. },
  131. },
  132. mounted() {
  133. this.initData();
  134. },
  135. methods: {
  136. ...mapMutations("markParam", ["setOpenClassMark"]),
  137. async initData() {
  138. this.classMarkIsOpen = this.openClassMark;
  139. if (!this.classMarkIsOpen) return;
  140. const params = {
  141. examId: this.basicInfo.examId,
  142. paperNumber: this.basicInfo.paperNumber,
  143. };
  144. const res = await markClassList(params);
  145. this.dataList = res.markerClass || [];
  146. this.classList = res.classNames || [];
  147. this.updateUnsignData();
  148. this.cacheDataMd5 = this.getSubmitDataMd5();
  149. },
  150. resetData() {
  151. this.dataList = [];
  152. this.classList = [];
  153. this.selectedClassIds = [];
  154. this.unsignData = [];
  155. this.cacheDataMd5 = "";
  156. },
  157. getSubmitDataMd5() {
  158. this.cacheDataMd5 = MD5(JSON.stringify(this.dataList));
  159. },
  160. async markClassChange() {
  161. const name = this.classMarkIsOpen ? "开启" : "关闭";
  162. const confirm = await this.$confirm(`确定要${name}分班阅卷吗?`, "提示", {
  163. type: "warning",
  164. }).catch(() => {});
  165. if (confirm !== "confirm") {
  166. this.classMarkIsOpen = !this.classMarkIsOpen;
  167. return;
  168. }
  169. const res = await markClassStatusUpdate({
  170. examId: this.basicInfo.examId,
  171. paperNumber: this.basicInfo.paperNumber,
  172. classMark: this.classMarkIsOpen,
  173. }).catch(() => {
  174. this.classMarkIsOpen = !this.classMarkIsOpen;
  175. });
  176. if (!res) return;
  177. this.setOpenClassMark(this.classMarkIsOpen);
  178. if (this.classMarkIsOpen) {
  179. this.initData();
  180. } else {
  181. this.resetData();
  182. }
  183. },
  184. toSelectClass(row) {
  185. this.curRow = row;
  186. this.selectedClassIds = row.markerClassList;
  187. this.$refs.SelectClassByCourse.open();
  188. },
  189. classSelected(markerClassList) {
  190. this.curRow.markerClassList = markerClassList;
  191. this.updateUnsignData();
  192. },
  193. updateUnsignData() {
  194. this.unsignData = this.classList
  195. .map((className) => {
  196. const markIds = this.dataList
  197. .filter((row) => row.markerClassList.includes(className))
  198. .map((row) => row.marker.userId);
  199. const unsignGroups = this.subjectiveTaskList
  200. .filter(
  201. (group) =>
  202. !group.markers.some((marker) => markIds.includes(marker.userId))
  203. )
  204. .map((group) => {
  205. return {
  206. id: group.id,
  207. question: `${group.mainNumber}-${group.subNumber}`,
  208. };
  209. });
  210. const nrow = {
  211. className,
  212. unsignGroups,
  213. content: "",
  214. };
  215. if (unsignGroups.length) {
  216. const groupCont = unsignGroups
  217. .map((group) => group.question)
  218. .join(" ");
  219. nrow.content = `${className}班级,${groupCont},未分配评卷员`;
  220. }
  221. return nrow;
  222. })
  223. .filter((item) => item.unsignGroups.length);
  224. },
  225. async submit() {
  226. if (this.unsignData.length) {
  227. this.$message.error("存在未分配班级,请完成分配!");
  228. return;
  229. }
  230. if (this.loading) return;
  231. const unvalid = this.dataList.some(
  232. (item) => !item.markerClassList.length
  233. );
  234. if (unvalid) {
  235. this.$message.error("有评卷员未设置班级");
  236. return;
  237. }
  238. const res = await markClassSave({
  239. examId: this.basicInfo.examId,
  240. paperNumber: this.basicInfo.paperNumber,
  241. questionMarkerClass: this.dataList,
  242. }).catch(() => {});
  243. if (!res) return;
  244. this.$message.success("保存成功!");
  245. this.cacheDataMd5 = this.getSubmitDataMd5();
  246. return true;
  247. },
  248. async toPrev(step = 1) {
  249. if (
  250. !this.classMarkIsOpen ||
  251. this.cacheDataMd5 === this.getSubmitDataMd5()
  252. ) {
  253. this.$emit("prev", step);
  254. return;
  255. }
  256. const confirm = await this.$confirm(
  257. `存在未保存的数据,是否保存后返回上一步?`,
  258. "提示",
  259. {
  260. type: "warning",
  261. }
  262. ).catch(() => {});
  263. if (confirm !== "confirm") {
  264. this.$emit("prev", step);
  265. return;
  266. }
  267. const res = await this.submit();
  268. if (!res) return;
  269. this.$emit("prev", step);
  270. },
  271. async toNext(step = 1) {
  272. if (
  273. !this.classMarkIsOpen ||
  274. this.cacheDataMd5 === this.getSubmitDataMd5()
  275. ) {
  276. this.$emit("next", step);
  277. return;
  278. }
  279. const res = await this.submit();
  280. if (!res) return;
  281. this.$emit("next", step);
  282. },
  283. },
  284. };
  285. </script>