TestParticipation.vue 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. <template>
  2. <div class="TestParticipation"
  3. :style="localOptions.style">
  4. <completion-page v-if="isCompletionPage"
  5. :answer-book="answerBook" />
  6. <q-card v-else-if="!answerBook.loading && answerBook.id">
  7. <q-card-section class="flex justify-between">
  8. <div>{{ answerBook.test_info.title }}</div>
  9. <div>
  10. زمان باقیمانده تا پایان آزمون
  11. {{ formattedRemainingTime }}
  12. </div>
  13. </q-card-section>
  14. <q-separator />
  15. <q-banner>
  16. <div class="row">
  17. <div class="col-md-4 col-12">
  18. {{ toShamsi(answerBook.attending_start_time) }}
  19. </div>
  20. <div class="col-md-4 col-12">
  21. {{ answerBook.test_info.test_set_info.test_set_questions.length }}
  22. سوال
  23. </div>
  24. <div class="col-md-4 col-12">
  25. {{ answerBook.duration }}
  26. دقیقه
  27. </div>
  28. </div>
  29. </q-banner>
  30. <template v-if="mounted">
  31. <all-questions v-if="$route.name === 'UserPanel.Test.AnswerBook.Participate.AllQuestions'"
  32. :answer-book="answerBook"
  33. @sentsuccess="onAllQuestionsSentSuccess"
  34. @sending="onAllQuestionsSending"
  35. @sentfailed="onAllQuestionsSentFailed" />
  36. <single-question v-else-if="$route.name === 'UserPanel.Test.AnswerBook.Participate.SingleQuestion'"
  37. :answer-book="answerBook"
  38. :question-number="parseInt($route.params.question_number)"
  39. @sending="onSingleQuestionsSending"
  40. @sentSuccess="onSingleQuestionsSentSuccess"
  41. @sentFailed="onSingleQuestionsSentFailed" />
  42. </template>
  43. </q-card>
  44. <div v-else>
  45. کمی صبر کنید...
  46. </div>
  47. <q-dialog v-model="participateTypeDialog">
  48. <q-card>
  49. <q-card-actions>
  50. نحوه پاسخ به آزمون
  51. </q-card-actions>
  52. <q-separator />
  53. <q-card-actions>
  54. <div>
  55. اندیشه جوی عزیز لطفا نحوه پاسخ به سوالات آزمون را مشخص کنید
  56. </div>
  57. <div>
  58. <q-radio v-model="participateType"
  59. val="UserPanel.Test.AnswerBook.Participate.AllQuestions"
  60. label="مایلم پاسخ سوالات را به صورت یک فایل جامع بارگزاری کنم" />
  61. <q-radio v-model="participateType"
  62. val="UserPanel.Test.AnswerBook.Participate.SingleQuestion"
  63. label="مایلم پاسخ سوالات را به صورت جداگانه ذیل همان سوال وارد کنم" />
  64. </div>
  65. </q-card-actions>
  66. <q-card-actions>
  67. <q-btn v-close-popup
  68. outline
  69. label="انصراف از آزمون"
  70. color="red" />
  71. <q-btn :disable="!participateType"
  72. label="تایید و شروع آزمون"
  73. color="primary"
  74. @click="startTest" />
  75. </q-card-actions>
  76. </q-card>
  77. </q-dialog>
  78. </div>
  79. </template>
  80. <script>
  81. import Assist from 'src/assets/js/Assist.js'
  82. import { mixinWidget } from 'src/mixin/Mixins.js'
  83. import { APIGateway } from 'src/api/APIGateway.js'
  84. import { AnswerBook } from 'src/models/AnswerBook.js'
  85. import AllQuestions from './components/AllQuestions.vue'
  86. import SingleQuestion from './components/SingleQuestion.vue'
  87. import CompletionPage from './components/CompletionPage.vue'
  88. export default {
  89. name: 'TestParticipation',
  90. components: { AllQuestions, SingleQuestion, CompletionPage },
  91. mixins: [mixinWidget],
  92. data () {
  93. return {
  94. mounted: false,
  95. participateType: null,
  96. participateTypeDialog: false,
  97. storeAnswerBook: null,
  98. answerBook: new AnswerBook(),
  99. remainingTime: 0,
  100. timerInterval: null
  101. }
  102. },
  103. computed: {
  104. isCompletionPage () {
  105. return this.$route.name === 'UserPanel.Test.AnswerBook.Participate.SingleQuestion' && this.$route.params.question_number === 'complete'
  106. },
  107. formattedRemainingTime () {
  108. const hours = Math.max(Math.floor(this.remainingTime / 3600), 0)
  109. const minutes = Math.max(Math.floor((this.remainingTime % 3600) / 60), 0)
  110. const seconds = Math.max(this.remainingTime % 60, 0)
  111. // Add zero padding for hours, minutes, and seconds
  112. const formattedHours = hours.toString().padStart(2, '0')
  113. const formattedMinutes = minutes.toString().padStart(2, '0')
  114. const formattedSeconds = seconds.toString().padStart(2, '0')
  115. return formattedHours + ':' + formattedMinutes + ':' + formattedSeconds
  116. }
  117. },
  118. mounted () {
  119. // this.getAnswerBook()
  120. this.getTestQuestions()
  121. this.mounted = true
  122. },
  123. methods: {
  124. loadAnswerBookFromStore () {
  125. this.storeAnswerBook = this.$store.getters['Test/answerBook']
  126. },
  127. onAllQuestionsSending () {
  128. this.answerBook.loading = true
  129. },
  130. onAllQuestionsSentSuccess () {
  131. this.answerBook.loading = false
  132. },
  133. onAllQuestionsSentFailed () {
  134. this.answerBook.loading = false
  135. },
  136. onSingleQuestionsSending () {
  137. this.answerBook.loading = true
  138. },
  139. onSingleQuestionsSentSuccess () {
  140. this.answerBook.loading = false
  141. this.backToClassList()
  142. },
  143. onSingleQuestionsSentFailed () {
  144. this.answerBook.loading = false
  145. },
  146. toShamsi (miladi) {
  147. return Assist.miladiToShamsi(miladi)
  148. },
  149. startTest () {
  150. this.$router.push({ name: this.participateType, params: { question_number: 1 } })
  151. },
  152. getRemainingTimeInSeconds (serverTimeStr, attendingStartTimeStr, durationInMinutes) {
  153. // Convert the strings to Date objects
  154. const serverTime = new Date(serverTimeStr)
  155. const attendingStartTime = new Date(attendingStartTimeStr)
  156. // Calculate the difference in milliseconds
  157. const timeDiffInMilliseconds = serverTime - attendingStartTime
  158. // Convert the difference to seconds
  159. const timeDiffInSeconds = timeDiffInMilliseconds / 1000
  160. // Calculate the remaining time in seconds considering the duration
  161. return Math.floor((durationInMinutes * 60) - timeDiffInSeconds)
  162. },
  163. startTimer () {
  164. this.timerInterval = setInterval(() => {
  165. if (this.remainingTime <= 0) {
  166. this.stopTimer()
  167. } else {
  168. this.remainingTime--
  169. this.answerBook.remainingTime = this.remainingTime
  170. this.$store.commit('Test/updateAnswerBook', this.answerBook)
  171. }
  172. }, 1000)
  173. },
  174. stopTimer () {
  175. if (!this.timerInterval) {
  176. return
  177. }
  178. clearInterval(this.timerInterval)
  179. },
  180. backToClassList () {
  181. this.$router.push({ name: 'UserPanel.Profile.AllClassrooms' })
  182. },
  183. getAnswerBook () {
  184. this.answerBook.loading = true
  185. APIGateway.answerBook.get(this.$route.params.answer_book_id)
  186. .then((answerBook) => {
  187. this.answerBook = new AnswerBook(answerBook)
  188. if (this.answerBook.test_info.test_set_questions_length === 0) {
  189. this.$q.notify({
  190. type: 'negative',
  191. message: 'لیست سوالات آزمون خالی است.'
  192. })
  193. this.backToClassList()
  194. }
  195. this.answerBook.loading = false
  196. })
  197. .catch(() => {
  198. this.answerBook.loading = false
  199. this.backToClassList()
  200. })
  201. },
  202. initPageFromAnswerBook (answerBook) {
  203. this.answerBook = new AnswerBook(answerBook)
  204. this.answerBook.loading = false
  205. if (this.answerBook.remainingTime === null) {
  206. this.answerBook.remainingTime = this.getRemainingTimeInSeconds(this.answerBook.server_time, this.answerBook.attending_start_time, this.answerBook.test_info.duration_deadline)
  207. }
  208. this.remainingTime = this.answerBook.remainingTime
  209. this.$store.commit('Test/updateAnswerBook', this.answerBook)
  210. this.startTimer()
  211. },
  212. getTestQuestions () {
  213. this.loadAnswerBookFromStore()
  214. if (this.storeAnswerBook && this.storeAnswerBook.id) {
  215. this.initPageFromAnswerBook(this.storeAnswerBook, false)
  216. return
  217. }
  218. this.answerBook.loading = true
  219. APIGateway.answerBook.getTestQuestions(this.$route.params.answer_book_id)
  220. .then((answerBook) => {
  221. this.initPageFromAnswerBook(answerBook)
  222. })
  223. .catch(() => {
  224. this.answerBook.loading = false
  225. this.backToClassList()
  226. })
  227. }
  228. }
  229. }
  230. </script>
  231. <style scoped lang="scss">
  232. .TestParticipation {
  233. :deep(.q-banner) {
  234. background: #FCF9F4 0 0 no-repeat padding-box;
  235. padding: 20px;
  236. .q-banner__content {
  237. font-size: 16px;
  238. font-weight: normal;
  239. }
  240. }
  241. }
  242. </style>