ExamEvalList.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. <template>
  2. <el-container class="exam-container">
  3. <el-header height="auto" class="exam-header">
  4. <div class="filter-wrapper">
  5. <span class="filter-label">科目筛选:</span>
  6. <el-select
  7. v-model="queryInfo.subjectId"
  8. clearable
  9. placeholder="请选择科目"
  10. @change="subjectChange"
  11. size="medium"
  12. >
  13. <el-option
  14. v-for="item in allSubject"
  15. :key="item.label"
  16. :label="item.label"
  17. :value="item.value"
  18. />
  19. </el-select>
  20. </div>
  21. </el-header>
  22. <el-main class="exam-main">
  23. <el-card shadow="never" class="table-card">
  24. <el-table
  25. :data="dataList"
  26. stripe
  27. style="width: 100%"
  28. header-cell-class-name="table-header-cell"
  29. >
  30. <el-table-column
  31. fixed="left"
  32. label="序号"
  33. type="index"
  34. align="center"
  35. />
  36. <el-table-column
  37. prop="examName"
  38. label="测评名称"
  39. show-overflow-tooltip
  40. />
  41. <el-table-column
  42. label="测评码"
  43. align="center"
  44. >
  45. <template slot-scope="scope">
  46. <el-tag
  47. v-if="scope.row.needPasscode"
  48. size="small"
  49. type="danger"
  50. effect="light"
  51. >需要</el-tag>
  52. <el-tag
  53. v-else
  54. size="small"
  55. type="success"
  56. effect="light"
  57. >不需要</el-tag>
  58. </template>
  59. </el-table-column>
  60. <el-table-column
  61. prop="startTime"
  62. label="测评时间"
  63. align="center"
  64. />
  65. <el-table-column
  66. prop="duration"
  67. label="时长"
  68. align="center"
  69. />
  70. <el-table-column
  71. prop="totalScore"
  72. label="试卷总分"
  73. align="center"
  74. />
  75. <el-table-column
  76. prop="userScore"
  77. label="我的分数"
  78. align="center"
  79. />
  80. <el-table-column
  81. fixed="right"
  82. label="操作"
  83. align="center"
  84. >
  85. <template slot-scope="scope">
  86. <el-button
  87. v-if="scope.row.evalStatus === 1"
  88. size="mini"
  89. type="primary"
  90. icon="el-icon-edit"
  91. @click="prepareExam(scope.$index, scope.row)"
  92. >去测评</el-button>
  93. <el-button
  94. v-else-if="scope.row.evalStatus === 2"
  95. size="mini"
  96. type="danger"
  97. icon="el-icon-s-claim"
  98. @click="markPaper(scope.$index, scope.row)"
  99. >进行中</el-button>
  100. <el-button
  101. v-else-if="scope.row.evalStatus === 3"
  102. size="mini"
  103. type="warning"
  104. icon="el-icon-loading"
  105. disabled
  106. @click="waitMark(scope.$index, scope.row)"
  107. >阅卷中</el-button>
  108. <el-button
  109. v-else-if="scope.row.evalStatus === 4"
  110. size="mini"
  111. type="warning"
  112. icon="el-icon-loading"
  113. disabled
  114. @click="waitMark(scope.$index, scope.row)"
  115. >看结果</el-button>
  116. </template>
  117. </el-table-column>
  118. </el-table>
  119. <div class="pagination-container">
  120. <el-pagination
  121. background
  122. :small="screenWidth <= 768"
  123. layout="total, prev, pager, next"
  124. :page-size="pageSize"
  125. :current-page="currentPage"
  126. :total="totalSize"
  127. @current-change="handleCurrentChange"
  128. @prev-click="handleCurrentChange"
  129. @next-click="handleCurrentChange"
  130. />
  131. </div>
  132. </el-card>
  133. </el-main>
  134. <el-dialog
  135. title="进入测评确认"
  136. :visible.sync="startExamDialog"
  137. center
  138. width="480px"
  139. custom-class="exam-confirm-dialog"
  140. >
  141. <el-alert
  142. title="请诚信测评!"
  143. description="点击“开始测评”后将自动进入系统。测评过程中可能会对用户行为、用户视频进行截图采样,请知悉。"
  144. type="warning"
  145. :closable="false"
  146. show-icon
  147. />
  148. <div class="exam-info-spec">
  149. <div class="spec-item">
  150. <span class="label">测评名称:</span>
  151. <span class="value val-bold">{{ currentSelectedExam.examName }}</span>
  152. </div>
  153. <div class="spec-item">
  154. <span class="label">测评时长:</span>
  155. <span class="value">{{ currentSelectedExam.duration }} 分钟</span>
  156. </div>
  157. <div class="spec-item">
  158. <span class="label">试卷总分:</span>
  159. <span class="value">{{ currentSelectedExam.totalScore }} 分</span>
  160. </div>
  161. <div class="spec-item">
  162. <span class="label">开放类型:</span>
  163. <span class="value">
  164. <el-tag size="mini" :type="currentSelectedExam.needPasscode ? 'danger' : 'success'">
  165. {{ currentSelectedExam.needPasscode ? '密码开启' : '完全公开' }}
  166. </el-tag>
  167. </span>
  168. </div>
  169. </div>
  170. <span slot="footer" class="dialog-footer">
  171. <el-button @click="startExamDialog = false" size="medium">返 回</el-button>
  172. <el-button type="primary" @click="startExam(currentSelectedExam.examId)" size="medium">开始测评</el-button>
  173. </span>
  174. </el-dialog>
  175. </el-container>
  176. </template>
  177. <script>
  178. import { getSubjectKV, getExamList } from '@/api/exam'
  179. export default {
  180. name: 'ExamEvalList',
  181. data() {
  182. return {
  183. // 屏幕宽度, 为了控制分页条的大小
  184. screenWidth: document.body.clientWidth,
  185. currentPage: 1,
  186. pageSize: 20,
  187. totalSize: 0,
  188. dataList: [],
  189. // **********************************************************************
  190. queryInfo: {
  191. subjectId: null,
  192. pageNumber: 1,
  193. pageSize: 10
  194. },
  195. allSubject: [],
  196. // 开始测评的提示框
  197. startExamDialog: false,
  198. // 当前选中的测评的信息
  199. currentSelectedExam: {
  200. examId: 114511
  201. }
  202. }
  203. },
  204. created() {
  205. document.title = '我的试卷'
  206. this.getData(this.queryInfo)
  207. this.getSubjects()
  208. // this.getQuestionTypes()
  209. },
  210. methods: {
  211. handleCurrentChange(pageNumber) {
  212. this.currentPage = pageNumber
  213. this.queryInfo.pageNumber = this.currentPage
  214. this.queryInfo.pageSize = this.pageSize
  215. this.getData(this.queryInfo)
  216. // 回到顶部
  217. scrollTo(0, 0)
  218. },
  219. getData(queryInfo) {
  220. getExamList(queryInfo).then(resp => {
  221. if (resp.code === 0) {
  222. this.dataList = resp.data.list
  223. this.totalSize = resp.data.totalSize
  224. } else {
  225. this.$notify({
  226. title: '提示',
  227. message: resp.msg,
  228. type: 'warning',
  229. duration: 3000
  230. })
  231. }
  232. }).catch(error => {
  233. this.$notify({
  234. title: '提示',
  235. message: error.message,
  236. type: 'error',
  237. duration: 3000
  238. })
  239. })
  240. },
  241. getSubjects() {
  242. getSubjectKV().then((resp) => {
  243. if (resp.code === 0) {
  244. this.allSubject = resp.data
  245. }
  246. })
  247. },
  248. // 题库变化
  249. subjectChange(val) {
  250. this.queryInfo.subjectId = val
  251. this.queryInfo.pageNumber = this.currentPage
  252. this.queryInfo.pageSize = this.pageSize
  253. this.getData(this.queryInfo)
  254. },
  255. prepareExam(index, row) {
  256. if (!row.needPasscode) {
  257. this.startExamDialog = true
  258. this.currentSelectedExam = row
  259. return
  260. }
  261. this.$prompt('请提供测评码', 'Tips', {
  262. confirmButtonText: '确定',
  263. cancelButtonText: '取消'
  264. }).then(({ value }) => {
  265. if (value === 123) {
  266. this.$message.error('密码错误o(╥﹏╥)o')
  267. return
  268. }
  269. this.startExamDialog = true
  270. this.currentSelectedExam = row
  271. }).catch(() => {
  272. })
  273. },
  274. startExam(examId) {
  275. const routeUrl = this.$router.resolve({
  276. path: '/exams',
  277. query: {
  278. examId: examId
  279. }
  280. })
  281. window.open(routeUrl.href, '_blank')
  282. },
  283. waitMark(index, row) {
  284. this.$message.info('试卷待批改')
  285. },
  286. markPaper(index, row) {
  287. const paperId = row.examId
  288. const routeUrl = this.$router.resolve({
  289. path: '/exam/paper/detail',
  290. query: {
  291. paperId: paperId,
  292. viewType: 3,
  293. userId: 0
  294. }
  295. })
  296. window.open(routeUrl.href, '_blank')
  297. },
  298. viewResult(index, row) {
  299. const paperId = row.examId
  300. const routeUrl = this.$router.resolve({
  301. path: '/exam/paper/detail',
  302. query: {
  303. paperId: paperId,
  304. viewType: 4,
  305. userId: ''
  306. }
  307. })
  308. window.open(routeUrl.href, '_blank')
  309. }
  310. }
  311. }
  312. </script>
  313. <style scoped>
  314. /* 使用 scoped 避免样式污染,采用更具现代感的设计规范 */
  315. .exam-container {
  316. background-color: #f5f7fa;
  317. min-height: 100vh;
  318. padding: 16px;
  319. }
  320. .exam-header {
  321. background-color: #ffffff;
  322. border-radius: 8px;
  323. padding: 16px 24px;
  324. margin-bottom: 16px;
  325. box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
  326. display: flex;
  327. align-items: center;
  328. }
  329. .filter-wrapper {
  330. display: flex;
  331. align-items: center;
  332. }
  333. .filter-label {
  334. font-size: 14px;
  335. color: #606266;
  336. font-weight: 500;
  337. margin-right: 8px;
  338. }
  339. .exam-main {
  340. padding: 0 !important;
  341. }
  342. .table-card {
  343. border-radius: 8px;
  344. border: none;
  345. box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05) !important;
  346. }
  347. /* 表头美化 */
  348. ::v-deep .table-header-cell {
  349. background-color: #fafafa !important;
  350. color: #303133 !important;
  351. font-weight: 600;
  352. height: 48px;
  353. }
  354. .score-text {
  355. font-weight: 600;
  356. color: #303133;
  357. }
  358. .pagination-container {
  359. margin-top: 24px;
  360. display: flex;
  361. justify-content: flex-end;
  362. }
  363. /* 弹窗内容规格表美化 */
  364. .exam-info-spec {
  365. margin-top: 20px;
  366. background-color: #f8f9fa;
  367. border-radius: 6px;
  368. padding: 16px;
  369. border: 1px solid #e4e7ed;
  370. }
  371. .spec-item {
  372. display: flex;
  373. margin-bottom: 12px;
  374. font-size: 14px;
  375. line-height: 1.5;
  376. }
  377. .spec-item:last-child {
  378. margin-bottom: 0;
  379. }
  380. .spec-item .label {
  381. color: #909399;
  382. width: 80px;
  383. flex-shrink: 0;
  384. }
  385. .spec-item .value {
  386. color: #303133;
  387. }
  388. .spec-item .val-bold {
  389. font-weight: 600;
  390. color: #2c3e50;
  391. }
  392. /* 规整弹窗底部按钮间距 */
  393. .exam-confirm-dialog ::v-deep .el-dialog__footer {
  394. padding-top: 10px;
  395. padding-bottom: 24px;
  396. }
  397. </style>