InvigilationDetail.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  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-select
  79. v-model="filter.finishType"
  80. placeholder="交卷方式"
  81. clearable
  82. >
  83. <el-option
  84. v-for="(val, key) in STUDENT_FINISH_EXAM_TYPE"
  85. :key="key"
  86. :value="key"
  87. :label="val"
  88. ></el-option>
  89. </el-select>
  90. </el-form-item>
  91. <el-form-item>
  92. <el-select v-model="filter.status" placeholder="筛选状态" clearable>
  93. <el-option
  94. v-for="(val, key) in STUDENT_ONLINE_STATUS"
  95. :key="key"
  96. :value="key"
  97. :label="val"
  98. ></el-option>
  99. </el-select>
  100. </el-form-item>
  101. <el-form-item>
  102. <el-select
  103. v-model="filter.breachStatus"
  104. placeholder="违纪/缺考"
  105. clearable
  106. >
  107. <el-option
  108. v-for="(val, key) in STUDENT_BEHAVIOR_STATUS"
  109. :key="key"
  110. :value="key * 1"
  111. :label="val"
  112. ></el-option>
  113. </el-select>
  114. </el-form-item>
  115. <el-form-item label="陌生人脸" v-if="showAdvancedFilter">
  116. <el-input-number
  117. style="width: 52px;"
  118. v-model.trim="filter.minMultipleFaceCount"
  119. placeholder="下限"
  120. :controls="false"
  121. ></el-input-number>
  122. <span class="line-split">-</span>
  123. <el-input-number
  124. style="width: 52px;"
  125. v-model.trim="filter.maxMultipleFaceCount"
  126. placeholder="上限"
  127. :controls="false"
  128. ></el-input-number>
  129. </el-form-item>
  130. <el-form-item label="异常处理" v-if="showAdvancedFilter">
  131. <el-input-number
  132. style="width: 52px;"
  133. v-model.trim="filter.minExceptionCount"
  134. placeholder="下限"
  135. :controls="false"
  136. ></el-input-number>
  137. <span class="line-split">-</span>
  138. <el-input-number
  139. style="width: 52px;"
  140. v-model.trim="filter.maxExceptionCount"
  141. placeholder="上限"
  142. :controls="false"
  143. ></el-input-number>
  144. </el-form-item>
  145. <el-form-item label="预警数" v-if="showAdvancedFilter">
  146. <el-input-number
  147. style="width: 52px;"
  148. v-model.trim="filter.minWarningCount"
  149. placeholder="下限"
  150. :controls="false"
  151. ></el-input-number>
  152. <span class="line-split">-</span>
  153. <el-input-number
  154. style="width: 52px;"
  155. v-model.trim="filter.maxWarningCount"
  156. placeholder="上限"
  157. :controls="false"
  158. ></el-input-number>
  159. </el-form-item>
  160. <el-form-item>
  161. <el-button type="primary" @click="toSearch">查询</el-button>
  162. <el-button type="primary" @click="changeFilter">{{
  163. showAdvancedFilter ? "隐藏高级查询" : "高级查询"
  164. }}</el-button>
  165. </el-form-item>
  166. </el-form>
  167. </div>
  168. <div class="part-filter-info">
  169. <summary-line
  170. class="part-filter-info-main"
  171. data-type="complete"
  172. :exam-id="filter.examId"
  173. v-if="filter.examId"
  174. ></summary-line>
  175. </div>
  176. </div>
  177. <el-table ref="TableList" :data="dataList">
  178. <el-table-column prop="examName" label="批次"></el-table-column>
  179. <el-table-column prop="examActivityCode" label="场次"></el-table-column>
  180. <el-table-column prop="roomName" label="考场"> </el-table-column>
  181. <el-table-column prop="examId" label="考试ID"></el-table-column>
  182. <el-table-column prop="identity" label="证件号"></el-table-column>
  183. <el-table-column prop="name" label="姓名"></el-table-column>
  184. <el-table-column prop="mobileNumber" label="联系电话"></el-table-column>
  185. <el-table-column prop="courseCode" label="科目(代码)">
  186. </el-table-column>
  187. <el-table-column prop="status" label="状态"></el-table-column>
  188. <el-table-column prop="finishType" label="交卷方式">
  189. <template slot-scope="scope">
  190. <div>{{ STUDENT_FINISH_EXAM_TYPE[scope.row.finishType] }}</div>
  191. </template>
  192. </el-table-column>
  193. <el-table-column
  194. prop="multipleFaceCount"
  195. label="陌生人脸"
  196. ></el-table-column>
  197. <el-table-column prop="exceptionCount" label="异常处理"></el-table-column>
  198. <el-table-column prop="warningCount" label="预警数"></el-table-column>
  199. <el-table-column prop="breachStatus" label="违纪">
  200. <template slot-scope="scope">
  201. <span :class="{ 'color-danger': !scope.row.breachStatus }">
  202. {{ !scope.row.breachStatus ? "违纪" : "正常" }}
  203. </span>
  204. </template>
  205. </el-table-column>
  206. <el-table-column label="操作">
  207. <template slot-scope="scope">
  208. <el-button
  209. class="btn-table-icon"
  210. type="primary"
  211. icon="icon icon-view"
  212. @click="toDetail(scope.row)"
  213. >详情</el-button
  214. >
  215. </template>
  216. </el-table-column>
  217. </el-table>
  218. <div class="part-page">
  219. <el-pagination
  220. background
  221. layout="prev, pager, next,total,sizes,jumper"
  222. :current-page="current"
  223. :total="total"
  224. :page-size="size"
  225. @size-change="toPage(1)"
  226. @current-change="toPage"
  227. >
  228. </el-pagination>
  229. </div>
  230. </div>
  231. </template>
  232. <script>
  233. import {
  234. examBatchList,
  235. examActivityRoomList,
  236. invigilationHistoryList,
  237. } from "@/api/invigilation";
  238. import {
  239. STUDENT_FINISH_EXAM_TYPE,
  240. STUDENT_ONLINE_STATUS,
  241. STUDENT_BEHAVIOR_STATUS,
  242. } from "@/constant/constants";
  243. import SummaryLine from "../common/SummaryLine";
  244. import { mapActions, mapMutations } from "vuex";
  245. export default {
  246. name: "InvigilationDetail",
  247. components: { SummaryLine },
  248. data() {
  249. return {
  250. filter: {
  251. examId: "",
  252. examActivityId: null,
  253. roomCode: null,
  254. courseCode: null,
  255. auditStatus: null,
  256. name: "",
  257. maxMultipleFaceCount: undefined,
  258. minMultipleFaceCount: undefined,
  259. maxExceptionCount: undefined,
  260. minExceptionCount: undefined,
  261. maxWarningCount: undefined,
  262. minWarningCount: undefined,
  263. },
  264. STUDENT_FINISH_EXAM_TYPE,
  265. STUDENT_ONLINE_STATUS,
  266. STUDENT_BEHAVIOR_STATUS,
  267. showAdvancedFilter: false,
  268. current: 1,
  269. total: 0,
  270. size: 10,
  271. examBatchs: [],
  272. examActivities: [],
  273. examRooms: [],
  274. examCourses: [],
  275. dataList: [],
  276. };
  277. },
  278. computed: {
  279. user() {
  280. return this.$store.state.user;
  281. },
  282. IS_INVIGILATE() {
  283. return this.user.roleCodes.includes("INVIGILATE");
  284. },
  285. },
  286. mounted() {
  287. this.initData();
  288. },
  289. methods: {
  290. ...mapActions("invigilation", ["updateDetailIds"]),
  291. ...mapMutations("invigilation", ["setDetailIds"]),
  292. async initData() {
  293. await this.getExamBatchList();
  294. this.filter.examId = this.examBatchs[0] && this.examBatchs[0].id;
  295. this.toSearch();
  296. this.getExamActivityRoomList();
  297. },
  298. async getList() {
  299. const datas = {
  300. ...this.filter,
  301. pageNumber: this.current,
  302. pageSize: this.size,
  303. };
  304. const res = await invigilationHistoryList(datas);
  305. this.dataList = res.data.data.records;
  306. this.total = res.data.data.total;
  307. },
  308. toPage(page) {
  309. this.current = page;
  310. this.getList();
  311. },
  312. async toSearch() {
  313. this.current = 1;
  314. await this.getList();
  315. if (this.total > this.size) {
  316. this.updateDetailIds({
  317. filterData: this.filter,
  318. fetchFunc: invigilationHistoryList,
  319. });
  320. } else {
  321. const ids = this.dataList.map((item) => item.examRecordId);
  322. this.setDetailIds([...new Set(ids)]);
  323. }
  324. },
  325. async getExamBatchList() {
  326. const userId = this.IS_INVIGILATE ? this.user.id : null;
  327. const res = await examBatchList(userId);
  328. this.examBatchs = res.data.data;
  329. },
  330. async getExamActivityRoomList() {
  331. if (!this.filter.examId) return;
  332. const res = await examActivityRoomList(this.filter.examId);
  333. this.examActivities = res.data.data.examActivitys;
  334. this.examRooms = res.data.data.examRooms;
  335. this.examCourses = res.data.data.examCourses;
  336. },
  337. examChange() {
  338. this.filter.examActivityId = null;
  339. this.filter.roomCode = null;
  340. this.filter.courseCode = null;
  341. this.getExamActivityRoomList();
  342. },
  343. changeFilter() {
  344. this.showAdvancedFilter = !this.showAdvancedFilter;
  345. if (!this.showAdvancedFilter) {
  346. this.filter.maxMultipleFaceCount = null;
  347. this.filter.minMultipleFaceCount = null;
  348. this.filter.maxExceptionCount = null;
  349. this.filter.minExceptionCount = null;
  350. this.filter.maxWarningCount = null;
  351. this.filter.minWarningCount = null;
  352. }
  353. },
  354. toDetail(row) {
  355. const router = this.IS_INVIGILATE
  356. ? "WarningDetail"
  357. : "InvigilationWarningDetail";
  358. this.$router.push({
  359. name: router,
  360. params: { recordId: row.examRecordId },
  361. });
  362. },
  363. },
  364. beforeRouteLeave(to, from, next) {
  365. if (
  366. to.name !== "WarningDetail" &&
  367. to.name !== "InvigilationWarningDetail"
  368. ) {
  369. this.$destroy();
  370. }
  371. next();
  372. },
  373. };
  374. </script>