usePaperInjection.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. import {computed, ref} from 'vue'
  2. import {createEventHook, injectLocal, provideLocal} from "@vueuse/core";
  3. import {empty} from "@/uni_modules/uv-ui-tools/libs/function/test";
  4. import {
  5. commitExamineePaper,
  6. commitExamineeQuestion,
  7. scoreExamineeQuestion,
  8. scoreFinish
  9. } from "@/api/webApi/studentEvaluating";
  10. import mxConst from "@/common/mxConst";
  11. import _ from "lodash";
  12. import {toast} from "@/uni_modules/uv-ui-tools/libs/function";
  13. const key = Symbol('PAPER_SERVICE')
  14. // 尽量保持只需要依靠paper/paper.questions中计算的相关API在paperService中
  15. // 与userData计算相关的API集中的questionService中
  16. export const useProvidePaperService = function (paperDataRef, overrideService = {}) {
  17. const paper = paperDataRef
  18. // 因为注入服务时paper可能还没有返回,为了方便注入时的有明确的属性名参考,这里将可能有用的属性抄了一遍。
  19. const props = {
  20. paperName: computed(() => paper.value?.name),
  21. allowAnswer: computed(() => paper.value?.allowAnswer),
  22. allowScore: computed(() => paper.value?.allowScore),
  23. questions: computed(() => paper.value?.questions || []),
  24. examineeId: computed(() => paper.value?.examineeId),
  25. examineeType: computed(() => paper.value?.examineeType),
  26. scoringType: computed(() => paper.value?.scoringType),
  27. remaining: computed(() => paper.value?.remaining),
  28. // for fast query by questionId
  29. questionsMap: computed(() => _.keyBy(props.questions.value, 'questionId'))
  30. }
  31. // 事件定义
  32. const events = {
  33. questionChange: createEventHook(), // display question change(index change)
  34. answerChange: createEventHook(), // user answered question
  35. answerComplete: createEventHook(), // all questions are answered
  36. scoreChange: createEventHook(), // user scored question
  37. scoreComplete: createEventHook(), // all questions are scored
  38. continueNext: createEventHook() // continue next paper
  39. }
  40. // data & service define
  41. const index = ref(0)
  42. const loading = ref(false)
  43. const current = computed(() => props.questions.value[index.value] || {})
  44. const hasNext = computed(() => index.value < props.questions.value.length - 1)
  45. const hasPrev = computed(() => index.value > 0)
  46. // methods
  47. const methods = {
  48. reset: () => {
  49. paper.value = {}
  50. index.value = 0
  51. loading.value = false
  52. },
  53. isObjective: (q) => mxConst.question.isObjective(q.typeId),
  54. isCheckbox: (q) => mxConst.question.isCheckbox(q.typeId),
  55. isRadio: (q) => mxConst.question.isRadio(q.typeId),
  56. isAnswerCorrect: (q) => q.answers?.length && q.answer == q.answers[0].toString(),
  57. tryGoNext: () => {
  58. if (!hasNext.value) return toast('已经是最后一题了')
  59. index.value += 1
  60. },
  61. tryGoPrev: () => {
  62. if (!hasPrev.value) return toast('已经是第一题了')
  63. index.value -= 1
  64. },
  65. goToQuestion: (q) => {
  66. const idx = props.questions.value.indexOf(q)
  67. if (idx > -1) index.value = idx
  68. },
  69. commitQuestion: async (commits) => {
  70. if (empty(commits)) return
  71. if (loading.value) return
  72. try {
  73. loading.value = true
  74. const examineeId = props.examineeId.value
  75. const examineeType = props.examineeType.value
  76. const commit = {examineeId, examineeType, questions: commits}
  77. await commitExamineeQuestion(commit)
  78. await events.answerChange.trigger(commits)
  79. } finally {
  80. loading.value = false
  81. }
  82. },
  83. commitPaper: async () => {
  84. if (loading.value) return
  85. try {
  86. // uni.showLoading() // 不需要,交卷时有自定义弹窗
  87. loading.value = true
  88. const examineeId = props.examineeId.value
  89. const examineeType = props.examineeType.value
  90. const commit = {examineeId, examineeType}
  91. await commitExamineePaper(commit)
  92. await events.answerComplete.trigger()
  93. } finally {
  94. loading.value = false
  95. // uni.hideLoading()
  96. }
  97. },
  98. scoreQuestion: async (commits) => {
  99. if (empty(commits)) return
  100. if (loading.value) return
  101. try {
  102. loading.value = true
  103. const examineeId = props.examineeId.value
  104. const examineeType = props.examineeType.value
  105. const commit = {examineeId, examineeType, questions: commits}
  106. await scoreExamineeQuestion(commit)
  107. await events.scoreChange.trigger(commits)
  108. } finally {
  109. loading.value = false
  110. }
  111. },
  112. scorePaper: async () => {
  113. if (loading.value) return
  114. try {
  115. uni.showLoading()
  116. loading.value = true
  117. const examineeId = props.examineeId.value
  118. const examineeType = props.examineeType.value
  119. const commit = {examineeId, examineeType}
  120. await scoreFinish(commit)
  121. await events.scoreComplete.trigger()
  122. } finally {
  123. loading.value = false
  124. uni.hideLoading()
  125. }
  126. },
  127. triggerContinueNext: async () => {
  128. await events.continueNext.trigger()
  129. }
  130. }
  131. // api that should combine `props` & `methods`
  132. const extend = {
  133. isAllObjective: computed(() => {
  134. return props.questions.value.every(q => methods.isObjective(q))
  135. }),
  136. answerCompletedTips: computed(() => {
  137. const type = props.scoringType.value + ''
  138. const source = {
  139. "1": `客观题已自动计分,主观题需要手动计分`,
  140. "2": `此卷为老师阅卷,需要学生交卷后老师进行阅卷计分`,
  141. "3": `此卷为系统阅卷,提交后系统自动计分`
  142. }
  143. return source[type] || source['1']
  144. })
  145. }
  146. const options = {
  147. loading,
  148. paper,
  149. ...props,
  150. onAnswerChange: events.answerChange.on,
  151. onAnswerComplete: events.answerComplete.on,
  152. onScoreChange: events.scoreChange.on,
  153. onScoreComplete: events.scoreComplete.on,
  154. onContinueNext: events.continueNext.on,
  155. index,
  156. current,
  157. hasNext,
  158. hasPrev,
  159. ...methods,
  160. ...extend,
  161. ...overrideService
  162. }
  163. provideLocal(key, options)
  164. return options
  165. }
  166. export const useInjectPaperService = function () {
  167. return injectLocal(key)
  168. }