import {computed, ref} from 'vue' import {createEventHook, injectLocal, provideLocal} from "@vueuse/core"; import {empty} from "@/uni_modules/uv-ui-tools/libs/function/test"; import { commitExamineePaper, commitExamineeQuestion, scoreExamineeQuestion, scoreFinish } from "@/api/webApi/studentEvaluating"; import mxConst from "@/common/mxConst"; import _ from "lodash"; import {toast} from "@/uni_modules/uv-ui-tools/libs/function"; const key = Symbol('PAPER_SERVICE') // 尽量保持只需要依靠paper/paper.questions中计算的相关API在paperService中 // 与userData计算相关的API集中的questionService中 export const useProvidePaperService = function (paperDataRef, overrideService = {}) { const paper = paperDataRef // 因为注入服务时paper可能还没有返回,为了方便注入时的有明确的属性名参考,这里将可能有用的属性抄了一遍。 const props = { paperName: computed(() => paper.value?.name), allowAnswer: computed(() => paper.value?.allowAnswer), allowScore: computed(() => paper.value?.allowScore), questions: computed(() => paper.value?.questions || []), examineeId: computed(() => paper.value?.examineeId), examineeType: computed(() => paper.value?.examineeType), scoringType: computed(() => paper.value?.scoringType), remaining: computed(() => paper.value?.remaining), // for fast query by questionId questionsMap: computed(() => _.keyBy(props.questions.value, 'questionId')) } // 事件定义 const events = { questionChange: createEventHook(), // display question change(index change) answerChange: createEventHook(), // user answered question answerComplete: createEventHook(), // all questions are answered scoreChange: createEventHook(), // user scored question scoreComplete: createEventHook(), // all questions are scored continueNext: createEventHook() // continue next paper } // data & service define const index = ref(0) const loading = ref(false) const current = computed(() => props.questions.value[index.value] || {}) const hasNext = computed(() => index.value < props.questions.value.length - 1) const hasPrev = computed(() => index.value > 0) // methods const methods = { reset: () => { paper.value = {} index.value = 0 loading.value = false }, isObjective: (q) => mxConst.question.isObjective(q.typeId), isCheckbox: (q) => mxConst.question.isCheckbox(q.typeId), isRadio: (q) => mxConst.question.isRadio(q.typeId), isAnswerCorrect: (q) => q.answers?.length && q.answer == q.answers[0].toString(), tryGoNext: () => { if (!hasNext.value) return toast('已经是最后一题了') index.value += 1 }, tryGoPrev: () => { if (!hasPrev.value) return toast('已经是第一题了') index.value -= 1 }, goToQuestion: (q) => { const idx = props.questions.value.indexOf(q) if (idx > -1) index.value = idx }, commitQuestion: async (commits) => { if (empty(commits)) return if (loading.value) return try { loading.value = true const examineeId = props.examineeId.value const examineeType = props.examineeType.value const commit = {examineeId, examineeType, questions: commits} await commitExamineeQuestion(commit) await events.answerChange.trigger(commits) } finally { loading.value = false } }, commitPaper: async () => { if (loading.value) return try { // uni.showLoading() // 不需要,交卷时有自定义弹窗 loading.value = true const examineeId = props.examineeId.value const examineeType = props.examineeType.value const commit = {examineeId, examineeType} await commitExamineePaper(commit) await events.answerComplete.trigger() } finally { loading.value = false // uni.hideLoading() } }, scoreQuestion: async (commits) => { if (empty(commits)) return if (loading.value) return try { loading.value = true const examineeId = props.examineeId.value const examineeType = props.examineeType.value const commit = {examineeId, examineeType, questions: commits} await scoreExamineeQuestion(commit) await events.scoreChange.trigger(commits) } finally { loading.value = false } }, scorePaper: async () => { if (loading.value) return try { uni.showLoading() loading.value = true const examineeId = props.examineeId.value const examineeType = props.examineeType.value const commit = {examineeId, examineeType} await scoreFinish(commit) await events.scoreComplete.trigger() } finally { loading.value = false uni.hideLoading() } }, triggerContinueNext: async () => { await events.continueNext.trigger() } } // api that should combine `props` & `methods` const extend = { isAllObjective: computed(() => { return props.questions.value.every(q => methods.isObjective(q)) }), answerCompletedTips: computed(() => { const type = props.scoringType.value + '' const source = { "1": `客观题已自动计分,主观题需要手动计分`, "2": `此卷为老师阅卷,需要学生交卷后老师进行阅卷计分`, "3": `此卷为系统阅卷,提交后系统自动计分` } return source[type] || source['1'] }) } const options = { loading, paper, ...props, onAnswerChange: events.answerChange.on, onAnswerComplete: events.answerComplete.on, onScoreChange: events.scoreChange.on, onScoreComplete: events.scoreComplete.on, onContinueNext: events.continueNext.on, index, current, hasNext, hasPrev, ...methods, ...extend, ...overrideService } provideLocal(key, options) return options } export const useInjectPaperService = function () { return injectLocal(key) }