usePaperQuestionCondition.js 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. import {useInjectPaperExactCondition} from "@/views/dz/papers/hooks/usePaperExactCondition.js";
  2. import {useInjectPaperFullCondition} from "@/views/dz/papers/hooks/usePaperFullCondition.js";
  3. import {useInjectPaperKnowledgeCondition} from "@/views/dz/papers/hooks/usePaperKnowledgeCondition.js";
  4. import {useInjectGlobalLoading} from "@/views/hooks/useGlobalLoading.js";
  5. import {getPaperQuestions, getPaperQuestionTypes} from "@/api/dz/papers.js";
  6. import {injectLocal, provideLocal} from "@vueuse/core";
  7. import {ElMessage} from "element-plus";
  8. const key = Symbol('PaperQuestionCondition')
  9. export const useProvidePaperQuestionCondition = function (exactMode, handMode) {
  10. const keyword = ref('')
  11. const questionId = ref('')
  12. const qtpye = ref('') // 历史遗留拼写错误
  13. const qTypes = ref([])
  14. const pageNum = ref(1)
  15. const pageSize = ref(10)
  16. const total = ref(0)
  17. const questionList = ref([])
  18. const {conditionArgs, conditionData} = exactMode ? useInjectPaperExactCondition() : useInjectPaperFullCondition()
  19. const {knowledgeId, knowledgeIds, knowledgeNode, knowledgeCheckNodes} = useInjectPaperKnowledgeCondition()
  20. const loading = useInjectGlobalLoading()
  21. // question cart
  22. const cart = ref([])
  23. const currentSubject = computed(() => {
  24. // 如果组卷条件里没有科目,试题篮就不设当前科目,即可以随意加题
  25. if (!conditionArgs.value.subjectId) return null
  26. if (!cart.value.length) return null
  27. // 否则,试题篮里不能跨科目加题
  28. const demoId = cart.value[0].subjectId
  29. return conditionData.value.subjectList.find(s => s.subjectId == demoId)
  30. })
  31. const subjectStat = computed(() => {
  32. const results = []
  33. cart.value.forEach(q => {
  34. const match = results.find(i => i.subjectId == q.subjectId)
  35. if (!match) {
  36. const subject = conditionData.value.subjectList.find(s => s.subjectId == q.subjectId)
  37. results.push({subjectId: q.subjectId, subjectName: subject?.subjectName || ('未知'+q.subjectId), count: 1})
  38. } else {
  39. match.count += 1
  40. }
  41. })
  42. return results
  43. })
  44. const groupedQuestions = computed(() => {
  45. const results = {}
  46. cart.value.forEach(q => {
  47. if (!results[q.qtpye]) {
  48. results[q.qtpye] = []
  49. }
  50. results[q.qtpye].push(q)
  51. })
  52. return Object.keys(results).map(k => ({qtpye: k, questions: results[k]}))
  53. })
  54. const hasQuestion = (q) => {
  55. return cart.value.some(c => c.id == q.id)
  56. }
  57. const removeQuestion = (q) => {
  58. const idx = cart.value.findIndex(c => c.id == q.id)
  59. if (idx > -1) cart.value.splice(idx, 1)
  60. }
  61. const addQuestion = (q) => {
  62. // 2025.10.25 取消科目限制,让用户随意添加
  63. // if (currentSubject.value && currentSubject.value.subjectId != q.subjectId) {
  64. // return ElMessage.error(`当前科目【${currentSubject.value.subjectName}】冲突`)
  65. // }
  66. cart.value.push(q)
  67. }
  68. const removeQuestionGroup = (qtpye) => {
  69. const ls = groupedQuestions.value.find(g => g.qtpye == qtpye)?.questions
  70. ls?.forEach(q => removeQuestion(q))
  71. }
  72. const clearCart = () => cart.value = []
  73. // hooks - 监听知识点变化,重新获取题型数据
  74. // 监听单个知识点节点和多选知识点节点的变化
  75. watch([() => conditionArgs.value.subjectId, knowledgeNode, knowledgeCheckNodes], async ([subjectId, knowledgeNodeVal, knowledgeCheckNodesVal]) => {
  76. // 获取知识点ID:优先使用单个知识点,否则使用多选知识点
  77. const currentKnowledgeId = knowledgeNodeVal?.id
  78. const currentKnowledgeIds = knowledgeCheckNodesVal?.map(k => k.id) || []
  79. // 如果没有知识点,直接返回
  80. if (!currentKnowledgeId && currentKnowledgeIds.length === 0) return
  81. // 定向模式下,如果subjectId为空,使用默认值11L(与后端逻辑一致)
  82. // 全量模式下,必须有subjectId才能继续
  83. let finalSubjectId = subjectId
  84. if (!finalSubjectId) {
  85. if (exactMode) {
  86. // 定向模式下,后端会自动设置subjectId为11L
  87. finalSubjectId = 11
  88. } else {
  89. // 全量模式下,必须有subjectId
  90. if (conditionData.value.subjectList?.length) return
  91. }
  92. }
  93. // 构建查询参数
  94. const knowledgeIdsToUse = currentKnowledgeId ? [currentKnowledgeId] : currentKnowledgeIds
  95. const query = {subjectId: finalSubjectId, knowledgeIds: knowledgeIdsToUse}
  96. try {
  97. const res = await getPaperQuestionTypes(query)
  98. const newQTypes = res.data || []
  99. // 保留已有的题型设置(特别是 count 和 score 值),只更新题型列表
  100. // 如果已有题型设置,则合并新旧题型,保留已有的 count 和 score
  101. if (qTypes.value.length > 0) {
  102. const existingTypesMap = new Map()
  103. qTypes.value.forEach(qt => {
  104. existingTypesMap.set(qt.dictValue, {
  105. count: qt.count || 0,
  106. score: qt.score !== undefined ? qt.score : 0
  107. })
  108. })
  109. // 合并新题型和已有设置
  110. qTypes.value = newQTypes.map(newQt => {
  111. const existing = existingTypesMap.get(newQt.dictValue)
  112. return {
  113. ...newQt,
  114. count: existing ? existing.count : (newQt.count || 0),
  115. score: existing ? existing.score : (newQt.score !== undefined ? newQt.score : 0)
  116. }
  117. })
  118. } else {
  119. // 如果没有已有设置,直接使用新的题型列表,初始化 score 为 0
  120. qTypes.value = newQTypes.map(qt => ({
  121. ...qt,
  122. score: qt.score !== undefined ? qt.score : 0
  123. }))
  124. }
  125. // 清空选中的题型
  126. qtpye.value = ''
  127. } catch (error) {
  128. console.error('获取题型列表失败:', error)
  129. // 出错时不清空已有设置
  130. }
  131. }, { deep: true, immediate: false })
  132. const questionQuery = computed(() => ({
  133. pageNum: pageNum.value,
  134. pageSize: pageSize.value,
  135. title: keyword.value,
  136. id: questionId.value,
  137. qtpye: qtpye.value,
  138. knowledgeId: knowledgeId.value,
  139. knowledges: knowledgeIds.value.toString()
  140. }))
  141. const getQuestionList = async function () {
  142. if (!handMode) return // 智能组卷时不需要查询
  143. loading.value = true
  144. try {
  145. const res = await getPaperQuestions(questionQuery.value)
  146. total.value = res.total
  147. questionList.value = res.rows
  148. } finally {
  149. loading.value = false
  150. }
  151. }
  152. watch([keyword, questionId, qtpye, knowledgeId, () => knowledgeIds.value.toString()], async ([title, id, qtpye, knowledgeId, knowledges]) => {
  153. pageNum.value = 1
  154. questionList.value = []
  155. total.value = 0
  156. if (!knowledgeId && !knowledges) return // 有知识点即可以查询题库
  157. await getQuestionList()
  158. })
  159. const payload = {
  160. keyword, questionId, qtpye, qTypes, pageNum, pageSize, total, questionList, getQuestionList,
  161. cart, currentSubject, groupedQuestions, subjectStat,
  162. hasQuestion, addQuestion, removeQuestion, removeQuestionGroup, clearCart
  163. }
  164. provideLocal(key, payload)
  165. return payload
  166. }
  167. export const useInjectPaperQuestionCondition = function () {
  168. return injectLocal(key)
  169. }