import {ref, watch, computed, nextTick} from 'vue' import {createEventHook, injectLocal, provideLocal} from "@vueuse/core"; import {useProvidePaperService} from "@/components/mx-paper/usePaperInjection"; import {numberToChinese} from "@/utils"; import {useProvideQuestionOptionFormatter} from "@/components/mx-question-content/useQuestionOptionInjection"; import {useProvideMathJaxSwitch} from "@/components/mx-question-content/useMathJaxSwitchInjection"; import {toast} from "@/uni_modules/uv-ui-tools/libs/function"; import {empty, func} from "@/uni_modules/uv-ui-tools/libs/function/test"; import mxConst from "@/common/mxConst"; import {fnPlaceholder} from "@/utils/uni-helper"; const key = Symbol('STEP_PAPER_SERVICE') export const useProvideStepPaper = (name, answerFormatter = (v) => v) => { const title = ref(name) const welcomeShow = ref(true) const resultShow = ref(false) const step = ref(0) const steps = ref([]) const stepQuestionContainer = ref(new Map()) const answerData = ref(new Map()) const beginEvent = createEventHook() const stepStartEvent = createEventHook() const finishEvent = createEventHook() const currentStep = computed(() => steps.value[step.value] || {}) const currentStepQuestions = computed(() => stepQuestionContainer.value.get(currentStep.value.id)) const paperData = computed(() => ({ name: name, allowAnswer: true, allowScore: false, questions: currentStepQuestions.value })) const overridePaperService = { commitQuestion: async (commits) => { // step paper只涉及本地提交 // 没有更改doChunk,业务上还是可以依靠它来驱动 commits.forEach(item => { answerData.value.set(item.questionId, item.answer) }) }, commitPaper: async () => { // step paper表示往前走一步 // 此进是强制走步,此时将触发finish step.value += 1 } } // 只重写了step需要影响的部分 const paperService = useProvidePaperService(paperData, overridePaperService) const optionFormatter = (options) => options.map(o => ({code: o.id, option: o.label})) const optionClass = (q) => mxConst.question.isRadio(q.typeId) ? 'pt-10' : '' useProvideQuestionOptionFormatter(optionFormatter, optionClass) useProvideMathJaxSwitch(true) // 明确此类测评没有包含任何公式转换 const hasNextStep = computed(() => step.value < steps.value.length - 1) const hasPrevStep = computed(() => step.value > 0) const tryGoNextStep = () => { if (!hasNextStep.value) return toast('已经是最后一部分了') step.value += 1 paperService.index.value = 0 } const tryGoPrevStep = () => { if (!hasPrevStep.value) return toast('已经是第一题了') step.value -= 1 nextTick().then(() => { // 需要等待题加载完毕,再重置题的位置 paperService.index.value = paperService.questions.value.length - 1 }) } watch([welcomeShow, resultShow], async () => { if (!welcomeShow.value && !resultShow.value) { await beginEvent.trigger() } }) watch(currentStep, async (step) => { if (!empty(step)) { await stepStartEvent.trigger(step.id) } }) watch(() => step.value >= steps.value.length, async (complete) => { if (complete) { // 转成API要求的标准格式 const details = [] for (const [key, value] of answerData.value) { details.push({ questionId: key, answer: answerFormatter(value) }) } await finishEvent.trigger({details}) resultShow.value = true } }) const options = { ...paperService, title, welcomeShow, resultShow, step, steps, currentStep, stepQuestionContainer, hasPrevStep, hasNextStep, tryGoPrevStep, tryGoNextStep, paperData, answerData, onBegin: beginEvent.on, onStepStart: stepStartEvent.on, onFinish: finishEvent.on } provideLocal(key, options) return options } export const useInjectStepPaper = () => { return injectLocal(key) } export const stepFormatter = (steps) => { steps.forEach((s, i) => s.name = numberToChinese(i + 1)) return steps } export const questionsFormatter = (questions, typeId, options = null) => { questions.forEach((q, i) => { const op = func(options) ? options(q) : options q.questionId = q.questionId || q.id q.typeId = typeId q.seq = i + 1 q.options = op || q.options }) return questions }