InvigilationDetail.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. <template>
  2. <div class="invigilation-detail">
  3. <div class="part-box-head">
  4. <div class="part-box-head-left"><h1>监考明细管理</h1></div>
  5. </div>
  6. <div class="part-filter">
  7. <div class="part-filter-form">
  8. <el-form
  9. class="part-box-filter-form"
  10. ref="FilterForm"
  11. label-position="left"
  12. inline
  13. >
  14. <el-form-item>
  15. <el-select
  16. v-model="filter.examId"
  17. placeholder="请选择批次"
  18. @change="examChange"
  19. >
  20. <el-option
  21. v-for="item in examBatchs"
  22. :key="item.id"
  23. :value="item.id"
  24. :label="item.name"
  25. ></el-option>
  26. </el-select>
  27. </el-form-item>
  28. <el-form-item>
  29. <el-select
  30. v-model="filter.examActivityId"
  31. placeholder="请选择场次"
  32. clearable
  33. >
  34. <el-option
  35. v-for="item in examActivities"
  36. :key="item.id"
  37. :value="item.id"
  38. :label="item.code"
  39. ></el-option>
  40. </el-select>
  41. </el-form-item>
  42. <el-form-item>
  43. <el-select
  44. v-model="filter.roomCode"
  45. placeholder="请选择考场"
  46. clearable
  47. >
  48. <el-option
  49. v-for="item in examRooms"
  50. :key="item.id"
  51. :value="item.roomCode"
  52. :label="item.roomName"
  53. ></el-option>
  54. </el-select>
  55. </el-form-item>
  56. <el-form-item>
  57. <el-select
  58. v-model="filter.courseCode"
  59. placeholder="请选择科目"
  60. clearable
  61. >
  62. <el-option
  63. v-for="item in examCourses"
  64. :key="item.courseCode"
  65. :value="item.courseCode"
  66. :label="item.courseName"
  67. ></el-option>
  68. </el-select>
  69. </el-form-item>
  70. <el-form-item>
  71. <el-input
  72. v-model.trim="filter.name"
  73. placeholder="姓名"
  74. clearable
  75. ></el-input>
  76. </el-form-item>
  77. <el-form-item>
  78. <el-input
  79. v-model.trim="filter.identity"
  80. placeholder="证件号"
  81. clearable
  82. ></el-input>
  83. </el-form-item>
  84. <el-form-item>
  85. <el-select
  86. v-model="filter.finishType"
  87. placeholder="交卷方式"
  88. clearable
  89. >
  90. <el-option
  91. v-for="(val, key) in STUDENT_FINISH_EXAM_TYPE"
  92. :key="key"
  93. :value="key"
  94. :label="val"
  95. ></el-option>
  96. </el-select>
  97. </el-form-item>
  98. <el-form-item>
  99. <el-select v-model="filter.status" placeholder="筛选状态" clearable>
  100. <el-option
  101. v-for="(val, key) in STUDENT_ONLINE_STATUS"
  102. :key="key"
  103. :value="key"
  104. :label="val"
  105. ></el-option>
  106. </el-select>
  107. </el-form-item>
  108. <el-form-item>
  109. <el-select
  110. v-model="filter.breachStatus"
  111. placeholder="违纪状态"
  112. clearable
  113. >
  114. <el-option
  115. v-for="(val, key) in STUDENT_BEHAVIOR_STATUS"
  116. :key="key"
  117. :value="key * 1"
  118. :label="val"
  119. ></el-option>
  120. </el-select>
  121. </el-form-item>
  122. <el-form-item label="陌生人脸" v-if="showAdvancedFilter">
  123. <el-input-number
  124. style="width: 52px;"
  125. v-model.trim="filter.minMultipleFaceCount"
  126. placeholder="下限"
  127. :controls="false"
  128. ></el-input-number>
  129. <span class="line-split">-</span>
  130. <el-input-number
  131. style="width: 52px;"
  132. v-model.trim="filter.maxMultipleFaceCount"
  133. placeholder="上限"
  134. :controls="false"
  135. ></el-input-number>
  136. </el-form-item>
  137. <el-form-item label="异常处理" v-if="showAdvancedFilter">
  138. <el-input-number
  139. style="width: 52px;"
  140. v-model.trim="filter.minExceptionCount"
  141. placeholder="下限"
  142. :controls="false"
  143. ></el-input-number>
  144. <span class="line-split">-</span>
  145. <el-input-number
  146. style="width: 52px;"
  147. v-model.trim="filter.maxExceptionCount"
  148. placeholder="上限"
  149. :controls="false"
  150. ></el-input-number>
  151. </el-form-item>
  152. <el-form-item label="预警数" v-if="showAdvancedFilter">
  153. <el-input-number
  154. style="width: 52px;"
  155. v-model.trim="filter.minWarningCount"
  156. placeholder="下限"
  157. :controls="false"
  158. ></el-input-number>
  159. <span class="line-split">-</span>
  160. <el-input-number
  161. style="width: 52px;"
  162. v-model.trim="filter.maxWarningCount"
  163. placeholder="上限"
  164. :controls="false"
  165. ></el-input-number>
  166. </el-form-item>
  167. <el-form-item>
  168. <el-button type="primary" @click="toSearch">查询</el-button>
  169. <el-button type="primary" @click="changeFilter">{{
  170. showAdvancedFilter ? "隐藏高级查询" : "高级查询"
  171. }}</el-button>
  172. <el-button type="primary" :loading="isDownload" @click="toExport"
  173. >导出</el-button
  174. >
  175. </el-form-item>
  176. </el-form>
  177. </div>
  178. <div class="part-filter-info">
  179. <summary-line
  180. class="part-filter-info-main"
  181. data-type="complete"
  182. :exam-id="filter.examId"
  183. ></summary-line>
  184. </div>
  185. </div>
  186. <el-table ref="TableList" :data="dataList">
  187. <el-table-column prop="examName" label="批次"></el-table-column>
  188. <el-table-column prop="examActivityCode" label="场次"></el-table-column>
  189. <el-table-column prop="roomName" label="考场"> </el-table-column>
  190. <el-table-column prop="examId" label="考试ID"></el-table-column>
  191. <el-table-column prop="identity" label="证件号"></el-table-column>
  192. <el-table-column prop="name" label="姓名"></el-table-column>
  193. <el-table-column prop="mobileNumber" label="联系电话"></el-table-column>
  194. <el-table-column prop="courseCode" label="科目(代码)">
  195. </el-table-column>
  196. <el-table-column prop="status" label="状态"></el-table-column>
  197. <el-table-column prop="finishType" label="交卷方式">
  198. <template slot-scope="scope">
  199. <div>{{ STUDENT_FINISH_EXAM_TYPE[scope.row.finishType] }}</div>
  200. </template>
  201. </el-table-column>
  202. <el-table-column
  203. prop="multipleFaceCount"
  204. label="陌生人脸"
  205. ></el-table-column>
  206. <el-table-column prop="exceptionCount" label="异常处理"></el-table-column>
  207. <el-table-column prop="warningCount" label="预警数"></el-table-column>
  208. <el-table-column prop="breachStatus" label="违纪">
  209. <template slot-scope="scope">
  210. <span :class="{ 'color-danger': !scope.row.breachStatus }">
  211. {{ !scope.row.breachStatus ? "违纪" : "正常" }}
  212. </span>
  213. </template>
  214. </el-table-column>
  215. <el-table-column label="操作" width="100" fixed="right">
  216. <template slot-scope="scope">
  217. <el-button
  218. class="btn-table-icon"
  219. type="primary"
  220. icon="icon icon-view"
  221. @click="toDetail(scope.row)"
  222. >详情</el-button
  223. >
  224. </template>
  225. </el-table-column>
  226. </el-table>
  227. <div class="part-page">
  228. <el-pagination
  229. background
  230. layout="prev, pager, next,total,sizes,jumper"
  231. :current-page="current"
  232. :total="total"
  233. :page-size.sync="size"
  234. @size-change="toPage(1)"
  235. @current-change="toPage"
  236. >
  237. </el-pagination>
  238. </div>
  239. </div>
  240. </template>
  241. <script>
  242. import {
  243. examBatchList,
  244. examActivityRoomList,
  245. invigilationHistoryList,
  246. exportInvigilationHistory,
  247. } from "@/api/invigilation";
  248. import { downloadBlob } from "@/utils/utils";
  249. import {
  250. STUDENT_FINISH_EXAM_TYPE,
  251. STUDENT_ONLINE_STATUS,
  252. STUDENT_BEHAVIOR_STATUS,
  253. } from "@/constant/constants";
  254. import SummaryLine from "../common/SummaryLine";
  255. import { mapState, mapActions, mapMutations } from "vuex";
  256. export default {
  257. name: "InvigilationDetail",
  258. components: { SummaryLine },
  259. data() {
  260. return {
  261. filter: {
  262. examId: "",
  263. examActivityId: null,
  264. roomCode: null,
  265. courseCode: null,
  266. auditStatus: null,
  267. name: "",
  268. identity: "",
  269. maxMultipleFaceCount: undefined,
  270. minMultipleFaceCount: undefined,
  271. maxExceptionCount: undefined,
  272. minExceptionCount: undefined,
  273. maxWarningCount: undefined,
  274. minWarningCount: undefined,
  275. },
  276. STUDENT_FINISH_EXAM_TYPE,
  277. STUDENT_ONLINE_STATUS,
  278. STUDENT_BEHAVIOR_STATUS,
  279. showAdvancedFilter: false,
  280. current: 1,
  281. total: 0,
  282. size: 10,
  283. examBatchs: [],
  284. examActivities: [],
  285. examRooms: [],
  286. examCourses: [],
  287. dataList: [],
  288. isDownload: false,
  289. };
  290. },
  291. computed: {
  292. ...mapState("invigilation", ["selectedExamId"]),
  293. user() {
  294. return this.$store.state.user;
  295. },
  296. IS_INVIGILATE() {
  297. return this.user.roleCodes.includes("INVIGILATE");
  298. },
  299. },
  300. mounted() {
  301. this.initData();
  302. },
  303. methods: {
  304. ...mapActions("invigilation", ["updateDetailIds", "updateSelectedExamId"]),
  305. ...mapMutations("invigilation", ["setDetailIds", "setSelectedExamId"]),
  306. async initData() {
  307. await this.getExamBatchList();
  308. if (!this.examBatchs.length) return;
  309. this.updateSelectedExamId({
  310. exams: this.examBatchs,
  311. selectedExamId: this.selectedExamId,
  312. });
  313. this.filter.examId = this.selectedExamId;
  314. // this.filter.examId = this.examBatchs[0] && this.examBatchs[0].id;
  315. this.toSearch();
  316. this.getExamActivityRoomList();
  317. },
  318. async getList() {
  319. const datas = {
  320. ...this.filter,
  321. pageNumber: this.current,
  322. pageSize: this.size,
  323. };
  324. const res = await invigilationHistoryList(datas);
  325. this.dataList = res.data.data.records;
  326. this.total = res.data.data.total;
  327. },
  328. toPage(page) {
  329. this.current = page;
  330. this.getList();
  331. },
  332. async toSearch() {
  333. this.setSelectedExamId(this.filter.examId);
  334. this.current = 1;
  335. await this.getList();
  336. if (this.total > this.size) {
  337. this.updateDetailIds({
  338. filterData: this.filter,
  339. fetchFunc: invigilationHistoryList,
  340. });
  341. } else {
  342. const ids = this.dataList.map((item) => item.examRecordId);
  343. this.setDetailIds([...new Set(ids)]);
  344. }
  345. },
  346. async toExport() {
  347. this.isDownload = true;
  348. const res = await downloadBlob(() => {
  349. return exportInvigilationHistory(this.filter);
  350. }).catch(() => {});
  351. this.isDownload = false;
  352. if (res) {
  353. this.$message.success("导出成功!");
  354. } else {
  355. this.$message.error("导出失败,请重新尝试!");
  356. }
  357. },
  358. async getExamBatchList() {
  359. const userId = this.IS_INVIGILATE ? this.user.id : null;
  360. const res = await examBatchList(userId);
  361. this.examBatchs = res.data.data;
  362. },
  363. async getExamActivityRoomList() {
  364. if (!this.filter.examId) return;
  365. const res = await examActivityRoomList(this.filter.examId);
  366. this.examActivities = res.data.data.examActivitys;
  367. this.examRooms = res.data.data.examRooms;
  368. this.examCourses = res.data.data.examCourses;
  369. },
  370. examChange() {
  371. this.filter.examActivityId = null;
  372. this.filter.roomCode = null;
  373. this.filter.courseCode = null;
  374. this.getExamActivityRoomList();
  375. },
  376. changeFilter() {
  377. this.showAdvancedFilter = !this.showAdvancedFilter;
  378. if (!this.showAdvancedFilter) {
  379. this.filter.maxMultipleFaceCount = null;
  380. this.filter.minMultipleFaceCount = null;
  381. this.filter.maxExceptionCount = null;
  382. this.filter.minExceptionCount = null;
  383. this.filter.maxWarningCount = null;
  384. this.filter.minWarningCount = null;
  385. }
  386. },
  387. toDetail(row) {
  388. const router = this.IS_INVIGILATE
  389. ? "WarningDetail"
  390. : "InvigilationWarningDetail";
  391. this.$router.push({
  392. name: router,
  393. params: { recordId: row.examRecordId },
  394. });
  395. },
  396. },
  397. };
  398. </script>