examTask.vue 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. <!-- 考试任务 -->
  2. <template>
  3. <view class="examTask-component">
  4. <view class="card">
  5. <view class="card-header">
  6. <view class="header-left">
  7. <view class="card-title">考试任务</view>
  8. <view class="header-subtitle">待完成的学习考试任务</view>
  9. </view>
  10. <text class="header-link" @click="goToPage('1')">更多 ›</text>
  11. </view>
  12. <view class="card-body">
  13. <view class="for-max-box" @click="goToPage('2',item)"
  14. v-for="(item,index) in onlineExamList" :key="index">
  15. <view class="left-box">
  16. <view>{{item.examName}}</view>
  17. <view>待完成</view>
  18. </view>
  19. <view class="right-box">›</view>
  20. </view>
  21. <view v-if="!onlineExamList[0]" class="empty-tip">暂无考试任务</view>
  22. </view>
  23. </view>
  24. <!-- 考试承诺书弹窗 -->
  25. <uni-popup ref="preExamDialog" type="center" :mask-click="false">
  26. <view class="pre-exam-dialog">
  27. <view class="dialog-header">
  28. <text class="dialog-title">考试承诺书</text>
  29. </view>
  30. <view class="dialog-body">
  31. <scroll-view scroll-y class="content-scroll">
  32. <richTextPdf ref="richTextPdf" :content="richTextHtml" />
  33. </scroll-view>
  34. </view>
  35. <view class="dialog-footer">
  36. <view v-if="preButtonType" class="btn btn-border" @click="downloadCommitment">下载</view>
  37. <view class="btn btn-primary" @click="confirmCommitment">确认</view>
  38. </view>
  39. </view>
  40. </uni-popup>
  41. </view>
  42. </template>
  43. <script>
  44. import {
  45. examUserExamStudyTaskList,
  46. examUserExamStart,
  47. examUserExamCommitmentConfirm,
  48. } from '@/pages_safetyEducationExamination/api/index.js'
  49. import richTextPdf from '@/pages_safetyEducationExamination/component/richTextPdf.vue'
  50. export default {
  51. components: {
  52. richTextPdf
  53. },
  54. data() {
  55. return {
  56. onlineExamList: [],
  57. // 承诺书相关
  58. preExamDialogType: false,
  59. preButtonType: false,
  60. richTextHtml: '',
  61. preData: null,
  62. }
  63. },
  64. created() {
  65. },
  66. mounted() {
  67. this.examUserExamStudyTaskList();
  68. },
  69. methods: {
  70. goToPage(type,item){
  71. if(type == 1){
  72. //考试列表
  73. uni.navigateTo({
  74. url: '/pages_safetyEducationExamination/views/exam/index',
  75. });
  76. }else if(type == 2){
  77. //开始考试相关业务
  78. if(item.conditionType == 1){
  79. if(item.examStudy&&item.courseId){
  80. //学习课程
  81. let obj = {
  82. courseId: item.courseId,
  83. examId: item.examId,
  84. }
  85. //等待后续逻辑
  86. }else{
  87. //学时要求
  88. if(item.knowledgePointIds){
  89. //学时知识点
  90. uni.navigateTo({
  91. url: `/pages_safetyEducationExamination/views/studyHourTask/index?knowledgePointId=${item.knowledgePointIds}`,
  92. });
  93. }else{
  94. //无知识点要求
  95. uni.navigateTo({
  96. url: '/pages_safetyEducationExamination/views/study/index',
  97. });
  98. }
  99. }
  100. }else if(item.conditionType == 2){
  101. //学习课程
  102. let obj = {
  103. courseId: item.courseId,
  104. examId: item.examId,
  105. }
  106. //等待后续逻辑
  107. }else if(item.conditionType == 3){
  108. //模拟考试
  109. if(item.mockExamId){
  110. let obj = {
  111. examId: item.examId,
  112. attemptId: item.mockExamId,
  113. }
  114. //等待后续逻辑
  115. }else{
  116. this.examUserExamStart({examId:item.examId,examScene:2});
  117. }
  118. }else if(item.conditionType == 4){
  119. //开始考试
  120. }
  121. }
  122. },
  123. //模拟考试获取试卷
  124. async examUserExamStart(obj) {
  125. try {
  126. const { data } = await examUserExamStart(obj);
  127. if (data.code === 200) {
  128. let obj = {
  129. examId: item.examId,
  130. attemptId: response.data.attemptId,
  131. }
  132. //等待后续逻辑
  133. }
  134. } catch (e) { console.error('模拟考试获取试卷失败', e); }
  135. },
  136. //开始考试判断是否有承诺书
  137. setRichExamData(item){
  138. if(item.commitmentEnabled == 1 && !item.commitmentConfirmed){
  139. //富文本弹窗考试承诺书
  140. this.preButtonType = item.commitmentPrintEnabled == 1;
  141. this.richTextHtml = item.commitmentContent;
  142. this.preData = item;
  143. this.$refs.preExamDialog.open();
  144. }else{
  145. if(item.attemptId){
  146. //上次考试未完成继续考试
  147. let obj = {
  148. attemptId: item.attemptId,
  149. type: '1',
  150. examKind:item.examKind,
  151. }
  152. //等待后续逻辑
  153. }else{
  154. //开始新考试
  155. this.startNewExam(item);
  156. }
  157. }
  158. },
  159. // 下载承诺书
  160. downloadCommitment() {
  161. uni.showToast({
  162. title: '正在下载,请耐心等候',
  163. icon: 'none'
  164. });
  165. this.$refs.richTextPdf.downloadPDF();
  166. },
  167. // 确认承诺书
  168. async confirmCommitment() {
  169. if (this.preData.attemptId) {
  170. await this.confirmAndStart(this.preData.attemptId);
  171. } else {
  172. try {
  173. const { data } = await examUserExamStart({
  174. examId: this.preData.examId,
  175. examScene: 1
  176. });
  177. if (data.code === 200 && data.data.attemptId) {
  178. await this.confirmAndStart(data.data.attemptId);
  179. } else {
  180. uni.showToast({
  181. title: data.message || '开始考试失败',
  182. icon: 'none'
  183. });
  184. }
  185. } catch (e) {
  186. console.error('开始考试失败', e);
  187. uni.showToast({
  188. title: '开始考试失败',
  189. icon: 'none'
  190. });
  191. }
  192. }
  193. },
  194. // 确认承诺并开始考试
  195. async confirmAndStart(attemptId) {
  196. try {
  197. const { data } = await examUserExamCommitmentConfirm({ attemptId });
  198. if (data.code === 200) {
  199. this.$refs.preExamDialog.close();
  200. // 跳转到考试页面
  201. let obj = {
  202. examId: this.preData.examId,
  203. attemptId: attemptId,
  204. type: '1',
  205. examKind: this.preData.examKind,
  206. };
  207. // 等待后续逻辑:跳转到答题页面
  208. uni.showToast({
  209. title: '已确认承诺书',
  210. icon: 'success'
  211. });
  212. }
  213. } catch (e) {
  214. console.error('确认承诺书失败', e);
  215. uni.showToast({
  216. title: '确认失败',
  217. icon: 'none'
  218. });
  219. }
  220. },
  221. //开始考试
  222. async examUserExamStart(item) {
  223. try {
  224. let obj = {examId:item.examId,examScene:1};
  225. const { data } = await examUserExamStart(obj);
  226. if (data.code === 200) {
  227. let obj = {
  228. examId: item.examId,
  229. attemptId: data.data.attemptId,
  230. type: '1',
  231. examKind:item.examKind,
  232. }
  233. //等待后续逻辑
  234. }
  235. } catch (e) { console.error('开始考试失败', e); }
  236. },
  237. // 开始新考试
  238. async startNewExam(item) {
  239. await this.examUserExamStart(item);
  240. },
  241. //获取任务列表
  242. async examUserExamStudyTaskList() {
  243. try {
  244. let obj = { page: 1, pageSize: 1, examStatus: 2, isSpecialExam: false };
  245. const { data } = await examUserExamStudyTaskList(obj);
  246. if (data.code === 200) {
  247. this.$set(this,'onlineExamList',data.data.records);
  248. }
  249. } catch (e) { console.error('获取考试任务失败', e); }
  250. },
  251. },
  252. }
  253. </script>
  254. <style lang="stylus" scoped>
  255. .examTask-component {
  256. margin: 0 32rpx 32rpx;
  257. .card {
  258. background: #fff;
  259. border-radius: 24rpx;
  260. overflow: hidden;
  261. margin-bottom: 24rpx;
  262. box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.03);
  263. border: 1px solid #dde3ed;
  264. }
  265. .card-header {
  266. padding: 20rpx 28rpx;
  267. display: flex;
  268. justify-content: space-between;
  269. align-items: center;
  270. .card-title {
  271. font-size: 28rpx;
  272. color: #333;
  273. }
  274. .header-subtitle{
  275. margin-top:10rpx;
  276. font-size:22rpx;
  277. color:#8896a7;
  278. }
  279. .header-link {
  280. padding:10rpx 20rpx;
  281. font-size: 24rpx;
  282. color: #1857d4;
  283. }
  284. }
  285. .card-body {
  286. padding: 0 28rpx 24rpx;
  287. .for-max-box:nth-child(1){
  288. margin-top:0;
  289. }
  290. .for-max-box{
  291. margin-top:20rpx;
  292. display: flex;
  293. background-color:#f4f6fa;
  294. padding: 20rpx 24rpx;
  295. border-radius: 16rpx;
  296. .left-box{
  297. flex:1;
  298. view:nth-child(1){
  299. font-size:26rpx;
  300. margin-bottom:4rpx;
  301. }
  302. view:nth-child(2){
  303. font-size:22rpx;
  304. color:#8896a7;
  305. }
  306. }
  307. .right-box{
  308. line-height:60rpx;
  309. font-size:40rpx;
  310. color:#8896a7;
  311. }
  312. }
  313. .empty-tip{
  314. text-align: center;
  315. line-height:40rpx;
  316. color:#8896a7;
  317. font-size:24rpx;
  318. }
  319. }
  320. }
  321. // 承诺书弹窗样式
  322. .pre-exam-dialog {
  323. width: 600rpx;
  324. max-height: 80vh;
  325. background: #fff;
  326. border-radius: 20rpx;
  327. overflow: hidden;
  328. }
  329. .dialog-header {
  330. padding: 32rpx;
  331. border-bottom: 1rpx solid #eee;
  332. .dialog-title {
  333. font-size: 32rpx;
  334. font-weight: 600;
  335. color: #333;
  336. }
  337. }
  338. .dialog-body {
  339. height: 800rpx;
  340. overflow: hidden;
  341. .content-scroll {
  342. height: 100%;
  343. }
  344. }
  345. .dialog-footer {
  346. display: flex;
  347. gap: 20rpx;
  348. padding: 24rpx 32rpx;
  349. border-top: 1rpx solid #eee;
  350. .btn {
  351. flex: 1;
  352. height: 72rpx;
  353. line-height: 72rpx;
  354. text-align: center;
  355. font-size: 28rpx;
  356. border-radius: 12rpx;
  357. }
  358. .btn-border {
  359. background: #fff;
  360. color: #1857d4;
  361. border: 1rpx solid #1857d4;
  362. }
  363. .btn-primary {
  364. background: #1857d4;
  365. color: #fff;
  366. }
  367. }
  368. </style>