AdminAnswerBookShow.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. <template>
  2. <div class="AdminAnswerBookShow"
  3. :style="localOptions.style">
  4. <q-card v-if="!answerBook.loading && answerBook.id">
  5. <q-card-section class="flex justify-between">
  6. <div>{{ answerBook.test_info.title }}</div>
  7. </q-card-section>
  8. <q-separator />
  9. <q-banner>
  10. <div class="row">
  11. <div class="col-md-6 col-12">
  12. وضعیت آزمون:
  13. {{ answerBook.status_info.label }}
  14. </div>
  15. <div v-if="answerBook.grader_info"
  16. class="col-md-6 col-12">
  17. مصحح:
  18. {{ answerBook.grader_info.firstname }}
  19. {{ answerBook.grader_info.lastname }}
  20. (کدملی: {{ answerBook.grader_info.national_code }})
  21. </div>
  22. </div>
  23. </q-banner>
  24. <q-separator />
  25. <q-banner>
  26. <div class="row">
  27. <div class="col-md-4 col-12">
  28. زمان شروع:
  29. {{ toShamsi(answerBook.attending_start_time) }}
  30. </div>
  31. <div class="col-md-4 col-12">
  32. {{ answerBook.owner_info.firstname }}
  33. {{ answerBook.owner_info.lastname }}
  34. (کدملی: {{ answerBook.owner_info.national_code }})
  35. </div>
  36. <div class="col-md-4 col-12">
  37. نمره نهایی
  38. <template v-if="answerBook.status === 'GRADING'">
  39. {{ totalScore }}
  40. </template>
  41. <template v-else>
  42. {{ answerBook.total_score }}
  43. </template>
  44. </div>
  45. </div>
  46. </q-banner>
  47. <q-list separator>
  48. <q-item v-for="(answerSheet, answerSheetIndex) in answerBook.answer_sheet_info.list"
  49. :key="answerSheetIndex"
  50. clickable>
  51. <div class="row full-width q-col-gutter-md">
  52. <div class="col-12"
  53. :class="{'col-md-10': $route.query.classroom_type !== 'EVENT'}">
  54. <div v-html="'<span>' + (answerSheetIndex + 1) + ' - </span>' + answerSheet.test_question_info.question_info.text" />
  55. <q-card class="q-mt-sm">
  56. <q-card-section v-if="Array.isArray(answerSheet.test_question_info.question_info.choices_info) && answerSheet.test_question_info.question_info.choices_info.length > 0">
  57. <div v-for="(choice, choiceIndex) in answerSheet.test_question_info.question_info.choices_info"
  58. :key="choiceIndex">
  59. <q-banner>
  60. <template v-slot:avatar>
  61. <q-icon :name="answerSheet.answer_choice_index === choiceIndex ? 'check_box' : 'check_box_outline_blank'"
  62. size="sm"
  63. color="primary" />
  64. </template>
  65. <div v-html="choice.text.replace(/\n/g, '<br>')" />
  66. </q-banner>
  67. <q-separator />
  68. </div>
  69. </q-card-section>
  70. <q-card-section v-else>
  71. <div>
  72. متن پاسخ:
  73. </div>
  74. <div>
  75. {{ answerSheet.answer_text }}
  76. </div>
  77. <div v-if="answerSheet.answer_attachment">
  78. <q-separator class="q-my-md" />
  79. <q-btn outline
  80. color="primary"
  81. icon="attachment"
  82. label="فایل پیوست"
  83. :href="answerSheet.answer_attachment"
  84. target="_blank" />
  85. </div>
  86. </q-card-section>
  87. </q-card>
  88. </div>
  89. <div v-if="$route.query.classroom_type !== 'EVENT'"
  90. class="col-md-2 col-12">
  91. <q-badge v-if="answerSheet.score !== null">
  92. {{ answerSheet.score }}
  93. از
  94. {{ answerSheet.test_question_info.question_info.mark }}
  95. نمره
  96. </q-badge>
  97. <q-badge v-else>
  98. {{ answerSheet.test_question_info.question_info.mark }}
  99. نمره
  100. </q-badge>
  101. <div class="q-mt-md input-grate-question">
  102. <q-input v-model="scores[answerSheetIndex].score"
  103. :loading="scores[answerSheetIndex].loading"
  104. dense>
  105. <template v-slot:append>
  106. <q-btn color="primary"
  107. label="ثبت نمره"
  108. outline
  109. :loading="scores[answerSheetIndex].loading"
  110. @click="submitScore(answerSheetIndex)" />
  111. </template>
  112. </q-input>
  113. </div>
  114. </div>
  115. </div>
  116. </q-item>
  117. </q-list>
  118. <q-separator class="q-my-lg" />
  119. <div class="q-pa-lg">
  120. <entity-show v-if="mounted"
  121. ref="entityShow"
  122. v-model:value="overallAnswerInput"
  123. :loaded-data="answerBook"
  124. :show-close-button="false"
  125. :show-edit-button="false"
  126. :show-expand-button="false"
  127. :show-save-button="false"
  128. :show-index-button="false"
  129. :show-reload-button="false"
  130. :default-layout="false" />
  131. </div>
  132. <template v-if="answerBook.objection_request">
  133. <div>
  134. متن اعتراض:
  135. </div>
  136. <div v-html="answerBook.objection_request" />
  137. </template>
  138. <template v-if="answerBook.objection_request && !answerBook.objection_result">
  139. <q-separator class="q-my-xl" />
  140. <q-card-section>
  141. <entity-edit v-if="mounted"
  142. ref="objectionEntityEdit"
  143. v-model:value="objectionInputs"
  144. title="پاسخ به اعتراض"
  145. :api="objectionApi"
  146. :loaded-data="{}"
  147. :show-close-button="false"
  148. :show-edit-button="false"
  149. :show-expand-button="false"
  150. :show-save-button="false"
  151. :show-reload-button="false">
  152. <template #after-form-builder>
  153. <div class="flex justify-end q-mt-md">
  154. <q-btn color="primary"
  155. label="ثبت اعتراض"
  156. @click="sendObjection" />
  157. </div>
  158. </template>
  159. </entity-edit>
  160. </q-card-section>
  161. </template>
  162. <template v-else-if="answerBook.objection_result">
  163. <div>
  164. نتیجه اعتراض:
  165. </div>
  166. <div v-html="answerBook.objection_result" />
  167. </template>
  168. </q-card>
  169. <div v-else>
  170. کمی صبر کنید...
  171. </div>
  172. </div>
  173. </template>
  174. <script>
  175. import Assist from 'src/assets/js/Assist.js'
  176. import { APIGateway } from 'src/api/APIGateway.js'
  177. import { EntityShow, EntityEdit } from 'quasar-crud'
  178. import { AnswerBook } from 'src/models/AnswerBook.js'
  179. import { mixinWidget, mixinAuth } from 'src/mixin/Mixins.js'
  180. export default {
  181. name: 'AdminAnswerBookShow',
  182. components: { EntityShow, EntityEdit },
  183. mixins: [mixinWidget, mixinAuth],
  184. data () {
  185. return {
  186. mounted: false,
  187. overallAnswerInput: [
  188. // { type: 'input', name: 'overall_answer_text', responseKey: 'overall_answer_text', label: 'متن پاسخ جامع', placeholder: ' ', inputType: 'textarea', col: 'col-12' },
  189. { type: 'file', name: 'overall_answer_attachment', responseKey: 'overall_answer_attachment', label: 'فایل پیوست جامع', placeholder: ' ', col: 'col-12' }
  190. ],
  191. questionInput: [
  192. { type: 'input', name: 'answer_text', responseKey: 'answer_text', label: 'متن پاسخ', placeholder: ' ', inputType: 'textarea', col: 'col-12' },
  193. { type: 'file', name: 'answer_attachment', responseKey: 'answer_attachment', label: 'فایل پیوست', placeholder: ' ', col: 'col-12' }
  194. ],
  195. questionInputs: [],
  196. scores: [],
  197. objectionInputs: [
  198. { type: 'input', name: 'objection_result', responseKey: 'objection_result', label: 'متن پاسخ', placeholder: ' ', inputType: 'textarea', col: 'col-12' }
  199. ],
  200. objectionApi: APIGateway.answerBook.APIAdresses.submitObjectionResult(this.$route.params.answer_book_id),
  201. answerBook: new AnswerBook()
  202. }
  203. },
  204. computed: {
  205. totalScore () {
  206. let totalScore = 0
  207. this.scores.forEach(item => {
  208. if (item.score) {
  209. totalScore += parseFloat(item.score)
  210. }
  211. })
  212. return totalScore
  213. }
  214. },
  215. mounted () {
  216. this.getAnswerBook()
  217. this.mounted = true
  218. },
  219. methods: {
  220. sendObjection () {
  221. this.answerBook.loading = true
  222. this.$refs.objectionEntityEdit.editEntity(false)
  223. .then(() => {
  224. this.getAnswerBook()
  225. })
  226. .catch(() => {
  227. this.getAnswerBook()
  228. })
  229. },
  230. toShamsi (miladi) {
  231. return Assist.miladiToShamsi(miladi)
  232. },
  233. loadAnswerBook (answerBook) {
  234. this.answerBook = new AnswerBook(answerBook)
  235. this.answerBook.answer_sheet_info.list.forEach((answerSheetItem) => {
  236. this.questionInputs.push(this.questionInput)
  237. this.scores.push({
  238. answerSheetId: answerSheetItem.id,
  239. score: answerSheetItem.score,
  240. loading: false
  241. })
  242. })
  243. },
  244. setGraderToMe () {
  245. this.answerBook.loading = true
  246. APIGateway.answerBook.setGraderToMe(this.$route.params.answer_book_id)
  247. .then((answerBook) => {
  248. this.loadAnswerBook(answerBook)
  249. this.answerBook.loading = false
  250. })
  251. .catch(() => {
  252. this.getAnswerBook()
  253. this.answerBook.loading = false
  254. })
  255. },
  256. submitScore (index) {
  257. this.scores[index].loading = true
  258. APIGateway.answerSheet.submitScore(this.scores[index].answerSheetId, this.scores[index].score)
  259. .then(() => {
  260. this.scores[index].loading = false
  261. this.getAnswerBook()
  262. })
  263. .catch(() => {
  264. this.scores[index].loading = false
  265. })
  266. },
  267. getAnswerBook () {
  268. this.answerBook.loading = true
  269. APIGateway.answerBook.get(this.$route.params.answer_book_id)
  270. .then((answerBook) => {
  271. this.loadAnswerBook(answerBook)
  272. this.answerBook.loading = false
  273. })
  274. .catch(() => {
  275. this.answerBook.loading = false
  276. })
  277. }
  278. }
  279. }
  280. </script>
  281. <style scoped lang="scss">
  282. .AdminAnswerBookShow {
  283. :deep(.q-banner) {
  284. background: #FCF9F4 0 0 no-repeat padding-box;
  285. padding: 20px;
  286. .q-banner__content {
  287. font-size: 16px;
  288. font-weight: normal;
  289. }
  290. }
  291. :deep(.q-list) {
  292. .q-item {
  293. .input-grate-question {
  294. .q-input {
  295. .q-field__inner .q-field__control {
  296. height: 40px;
  297. min-height: 40px;
  298. }
  299. }
  300. }
  301. .q-badge {
  302. background: #ACBCAE 0 0 no-repeat padding-box;
  303. border-radius: 18px;
  304. height: 32px;
  305. padding: 4px 16px;
  306. }
  307. }
  308. }
  309. }
  310. </style>