|
|
@@ -1,86 +1,171 @@
|
|
|
<template>
|
|
|
- <div class="AdminTestShow"
|
|
|
+ <div class="TestShow"
|
|
|
:style="localOptions.style">
|
|
|
- <div class="flex justify-end">
|
|
|
- <q-btn flat
|
|
|
- color="grey"
|
|
|
- @click="$router.go(-1)">
|
|
|
- بازگشت
|
|
|
- >
|
|
|
- </q-btn>
|
|
|
+ <q-card v-if="!answerBook.loading && answerBook.id">
|
|
|
+ <q-card-section class="flex justify-between">
|
|
|
+ <div>{{ answerBook.test_info.title }}</div>
|
|
|
+ </q-card-section>
|
|
|
+ <q-separator />
|
|
|
+ <q-banner>
|
|
|
+ <div class="row">
|
|
|
+ <div class="col-md-4 col-12">
|
|
|
+ {{ toShamsi(answerBook.attending_start_time) }}
|
|
|
+ </div>
|
|
|
+ <div class="col-md-4 col-12">
|
|
|
+ {{ answerBook.test_info.test_set_info.test_set_questions.length }}
|
|
|
+ سوال
|
|
|
+ </div>
|
|
|
+ <div class="col-md-4 col-12">
|
|
|
+ {{ answerBook.duration }}
|
|
|
+ دقیقه
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </q-banner>
|
|
|
+ <q-list separator>
|
|
|
+ <q-item v-for="(question, questionIndex) in answerBook.test_info.test_set_info.test_set_questions"
|
|
|
+ :key="questionIndex"
|
|
|
+ clickable>
|
|
|
+ <q-item-section v-html="question.question_info.text" />
|
|
|
+ <q-item-section side>
|
|
|
+ <q-badge>
|
|
|
+ {{ question.mark }}
|
|
|
+ نمره
|
|
|
+ </q-badge>
|
|
|
+ </q-item-section>
|
|
|
+ </q-item>
|
|
|
+ </q-list>
|
|
|
+ </q-card>
|
|
|
+ <div v-else>
|
|
|
+ کمی صبر کنید...
|
|
|
</div>
|
|
|
- <entity-edit v-if="mounted"
|
|
|
- ref="entityEdit"
|
|
|
- v-model:value="inputs"
|
|
|
- title="مشخصات آزمون"
|
|
|
- :api="api"
|
|
|
- :entity-id-key="entityIdKey"
|
|
|
- :entity-param-key="entityParamKey"
|
|
|
- :show-close-button="false"
|
|
|
- :show-edit-button="false"
|
|
|
- :show-expand-button="false"
|
|
|
- :show-save-button="false"
|
|
|
- :show-reload-button="false"
|
|
|
- :redirect-after-edit="false" />
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
-import { shallowRef } from 'vue'
|
|
|
-import { EntityEdit } from 'quasar-crud'
|
|
|
+import Assist from 'src/assets/js/Assist.js'
|
|
|
import { mixinWidget } from 'src/mixin/Mixins.js'
|
|
|
import { APIGateway } from 'src/api/APIGateway.js'
|
|
|
-import { FormBuilderAssist } from 'quasar-form-builder'
|
|
|
-import BtnControl from 'src/components/Control/btn.vue'
|
|
|
-import UsersOfTestSelector from 'src/components/FormBuilderCustumComponents/UsersOfTestSelector/UsersOfTestSelector.vue'
|
|
|
-
|
|
|
-const BtnControlComp = shallowRef(BtnControl)
|
|
|
-const UsersOfTestSelectorComp = shallowRef(UsersOfTestSelector)
|
|
|
+import { AnswerBook } from 'src/models/AnswerBook.js'
|
|
|
|
|
|
export default {
|
|
|
- name: 'AdminTestShow',
|
|
|
- components: { EntityEdit },
|
|
|
+ name: 'TestShow',
|
|
|
mixins: [mixinWidget],
|
|
|
data () {
|
|
|
return {
|
|
|
mounted: false,
|
|
|
- entityLoading: false,
|
|
|
- api: APIGateway.test.APIAdresses.byId(this.$route.params.id),
|
|
|
- entityIdKey: 'id',
|
|
|
- entityParamKey: 'id',
|
|
|
- inputs: [
|
|
|
- { type: 'input', name: 'title', responseKey: 'title', label: 'عنوان', placeholder: ' ', col: 'col-12' },
|
|
|
- { type: 'inputEditor', name: 'detail', responseKey: 'detail', label: 'توضیحات آزمون', col: 'col-12' },
|
|
|
- { type: 'dateTime', name: 'start_time', responseKey: 'start_time', label: 'زمان شروع آزمون', placeholder: ' ', col: 'col-md-6 col-12' },
|
|
|
- { type: 'dateTime', name: 'end_time', responseKey: 'end_time', label: 'زمان پایان آزمون', placeholder: ' ', col: 'col-md-6 col-12' },
|
|
|
- { type: 'input', name: 'duration_deadline', responseKey: 'duration_deadline', label: 'مدت زمان پاسخ دهی (دقیقه)', placeholder: ' ', col: 'col-md-6 col-12' },
|
|
|
- { type: 'dateTime', name: 'announcement_time', responseKey: 'announcement_time', label: 'زمان اعلام نتایج', placeholder: ' ', col: 'col-md-6 col-12' },
|
|
|
- { type: 'dateTime', name: 'objection_start_time', responseKey: 'objection_start_time', label: 'زمان شروع اعتراض', placeholder: ' ', col: 'col-md-6 col-12' },
|
|
|
- { type: 'dateTime', name: 'objection_end_time', responseKey: 'objection_end_time', label: 'زمان پایان اعتراض', placeholder: ' ', col: 'col-md-6 col-12' },
|
|
|
- { type: 'hidden', name: 'test_set', responseKey: 'test_set', value: this.$route.params.test_set_id },
|
|
|
- { type: 'hidden', name: 'classroom', responseKey: 'classroom', value: this.$route.params.classroom_id },
|
|
|
- { type: UsersOfTestSelectorComp, name: 'examinees', responseKey: 'examinees', classroomId: this.$route.params.classroom_id, col: 'col-12' },
|
|
|
- { type: BtnControlComp, name: 'btn', responseKey: 'btn', label: 'تعیین جزییات', placeholder: ' ', atClick: () => {}, col: 'col-12 flex justify-end' }
|
|
|
- ]
|
|
|
+ participateType: null,
|
|
|
+ participateTypeDialog: false,
|
|
|
+ answerBook: new AnswerBook(),
|
|
|
+ remainingTime: 0,
|
|
|
+ timerInterval: null
|
|
|
}
|
|
|
},
|
|
|
- mounted() {
|
|
|
- this.setActionBtn()
|
|
|
+ computed: {
|
|
|
+ formattedRemainingTime () {
|
|
|
+ const hours = Math.floor(this.remainingTime / 3600)
|
|
|
+ const minutes = Math.floor((this.remainingTime % 3600) / 60)
|
|
|
+ const seconds = this.remainingTime % 60
|
|
|
+
|
|
|
+ // Add zero padding for hours, minutes, and seconds
|
|
|
+ const formattedHours = hours.toString().padStart(2, '0')
|
|
|
+ const formattedMinutes = minutes.toString().padStart(2, '0')
|
|
|
+ const formattedSeconds = seconds.toString().padStart(2, '0')
|
|
|
+
|
|
|
+ return formattedHours + ':' + formattedMinutes + ':' + formattedSeconds
|
|
|
+ }
|
|
|
+ },
|
|
|
+ mounted () {
|
|
|
+ // this.getAnswerBook()
|
|
|
+ this.getTestQuestions()
|
|
|
this.mounted = true
|
|
|
},
|
|
|
methods: {
|
|
|
- setActionBtn () {
|
|
|
- FormBuilderAssist.setAttributeByName(this.inputs, 'btn', 'atClick', this.edit)
|
|
|
+ onAllQuestionsSending () {
|
|
|
+ this.answerBook.loading = true
|
|
|
+ },
|
|
|
+ onAllQuestionsSentSuccess () {
|
|
|
+ this.answerBook.loading = false
|
|
|
+ this.backToClassList()
|
|
|
+ },
|
|
|
+ onAllQuestionsSentFailed () {
|
|
|
+ this.answerBook.loading = false
|
|
|
+ },
|
|
|
+ onSingleQuestionsSending () {
|
|
|
+ this.answerBook.loading = true
|
|
|
+ },
|
|
|
+ onSingleQuestionsSentSuccess () {
|
|
|
+ this.answerBook.loading = false
|
|
|
+ this.backToClassList()
|
|
|
+ },
|
|
|
+ onSingleQuestionsSentFailed () {
|
|
|
+ this.answerBook.loading = false
|
|
|
+ },
|
|
|
+ toShamsi (miladi) {
|
|
|
+ return Assist.miladiToShamsi(miladi)
|
|
|
+ },
|
|
|
+
|
|
|
+ startTest () {
|
|
|
+ this.$router.push({ name: this.participateType, params: { question_id: 1 } })
|
|
|
},
|
|
|
- edit() {
|
|
|
- this.entityLoading = true
|
|
|
- this.$refs.entityEdit.editEntity()
|
|
|
- .then(() => {
|
|
|
- this.$refs.entityEdit.getData()
|
|
|
- this.entityLoading = false
|
|
|
+ getRemainingTimeInSeconds (serverTimeStr, attendingStartTimeStr, durationInMinutes) {
|
|
|
+ // Convert the strings to Date objects
|
|
|
+ const serverTime = new Date(serverTimeStr)
|
|
|
+ const attendingStartTime = new Date(attendingStartTimeStr)
|
|
|
+
|
|
|
+ // Calculate the difference in milliseconds
|
|
|
+ const timeDiffInMilliseconds = serverTime - attendingStartTime
|
|
|
+
|
|
|
+ // Convert the difference to seconds
|
|
|
+ const timeDiffInSeconds = timeDiffInMilliseconds / 1000
|
|
|
+
|
|
|
+ // Calculate the remaining time in seconds considering the duration
|
|
|
+ return (durationInMinutes * 60) - timeDiffInSeconds
|
|
|
+ },
|
|
|
+ startTimer () {
|
|
|
+ this.timerInterval = setInterval(() => {
|
|
|
+ if (this.remainingTime <= 0) {
|
|
|
+ this.stopTimer()
|
|
|
+ } else {
|
|
|
+ this.remainingTime--
|
|
|
+ }
|
|
|
+ }, 1000)
|
|
|
+ },
|
|
|
+ stopTimer () {
|
|
|
+ if (!this.timerInterval) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ clearInterval(this.timerInterval)
|
|
|
+ },
|
|
|
+ backToClassList () {
|
|
|
+ // this.$router.push({ name: 'UserPanel.Profile.AllClassrooms' })
|
|
|
+ },
|
|
|
+ getAnswerBook () {
|
|
|
+ this.answerBook.loading = true
|
|
|
+ APIGateway.answerBook.get(this.$route.params.answer_book_id)
|
|
|
+ .then((answerBook) => {
|
|
|
+ this.answerBook = new AnswerBook(answerBook)
|
|
|
+ this.answerBook.loading = false
|
|
|
+ })
|
|
|
+ .catch(() => {
|
|
|
+ this.answerBook.loading = false
|
|
|
+ this.backToClassList()
|
|
|
+ })
|
|
|
+ },
|
|
|
+ getTestQuestions () {
|
|
|
+ this.answerBook.loading = true
|
|
|
+ APIGateway.answerBook.getTestQuestions(this.$route.params.answer_book_id)
|
|
|
+ .then((answerBook) => {
|
|
|
+ this.answerBook = new AnswerBook(answerBook)
|
|
|
+ this.answerBook.loading = false
|
|
|
+ this.answerBook.server_time = '2023-12-15T23:57:46.909211'
|
|
|
+ this.answerBook.attending_start_time = '2023-12-15T23:27:46.909211'
|
|
|
+ this.remainingTime = this.getRemainingTimeInSeconds(this.answerBook.server_time, this.answerBook.attending_start_time, this.answerBook.duration)
|
|
|
+ this.startTimer()
|
|
|
})
|
|
|
.catch(() => {
|
|
|
- this.entityLoading = false
|
|
|
+ this.answerBook.loading = false
|
|
|
+ this.backToClassList()
|
|
|
})
|
|
|
}
|
|
|
}
|
|
|
@@ -88,23 +173,14 @@ export default {
|
|
|
</script>
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
-.AdminTestShow {
|
|
|
- .title {
|
|
|
- font-style: normal;
|
|
|
- font-weight: 700;
|
|
|
- font-size: 24px;
|
|
|
- line-height: 140%;
|
|
|
- color: #424242;
|
|
|
- margin-bottom: 27px;
|
|
|
- position: relative;
|
|
|
- .back-action {
|
|
|
- position: absolute;
|
|
|
- right: 0;
|
|
|
- top: 0;
|
|
|
+.TestShow {
|
|
|
+ :deep(.q-banner) {
|
|
|
+ background: #FCF9F4 0 0 no-repeat padding-box;
|
|
|
+ padding: 20px;
|
|
|
+ .q-banner__content {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: normal;
|
|
|
}
|
|
|
}
|
|
|
- :deep(.form) {
|
|
|
- padding: 24px;
|
|
|
- }
|
|
|
}
|
|
|
</style>
|