Sfoglia il codice sorgente

paper build all cc

abpcoder 3 settimane fa
parent
commit
d2e5e14e9c
33 ha cambiato i file con 280 aggiunte e 1018 eliminazioni
  1. 36 36
      back-ui/src/api/dz/papers.js
  2. 1 1
      back-ui/src/utils/consts.js
  3. 0 24
      back-ui/src/views/dz/papers/components-bak/paper-by-hand.vue
  4. 0 23
      back-ui/src/views/dz/papers/components-bak/paper-by-intelligent.vue
  5. 0 54
      back-ui/src/views/dz/papers/components-bak/paper-exact-conditions.vue
  6. 0 24
      back-ui/src/views/dz/papers/components-bak/paper-full-conditions.vue
  7. 0 24
      back-ui/src/views/dz/papers/components-bak/paper-hand-exact.vue
  8. 0 24
      back-ui/src/views/dz/papers/components-bak/paper-hand-full.vue
  9. 0 24
      back-ui/src/views/dz/papers/components-bak/paper-intelligent-exact.vue
  10. 0 24
      back-ui/src/views/dz/papers/components-bak/paper-intelligent-full.vue
  11. 0 45
      back-ui/src/views/dz/papers/components-bak/paper-knowledge-tree.vue
  12. 0 26
      back-ui/src/views/dz/papers/components-bak/paper-publish.vue
  13. 0 112
      back-ui/src/views/dz/papers/components-bak/paper-question-hand.vue
  14. 0 71
      back-ui/src/views/dz/papers/components-bak/paper-question-intelligent.vue
  15. 0 101
      back-ui/src/views/dz/papers/components/conditions/usePaperExactCondition.js
  16. 0 59
      back-ui/src/views/dz/papers/components/conditions/usePaperFullCondition.js
  17. 0 111
      back-ui/src/views/dz/papers/components/conditions/usePaperQuestionCondition.js
  18. 0 41
      back-ui/src/views/dz/papers/components/conditions/usePaperStorage.js
  19. 3 3
      back-ui/src/views/dz/papers/components/paper-exact-hand.vue
  20. 2 4
      back-ui/src/views/dz/papers/components/paper-exact-intelligent.vue
  21. 94 1
      back-ui/src/views/dz/papers/components/paper-full-hand.vue
  22. 3 7
      back-ui/src/views/dz/papers/components/paper-full-intelligent.vue
  23. 1 3
      back-ui/src/views/dz/papers/components/plugs/class-statistic-table.vue
  24. 1 1
      back-ui/src/views/dz/papers/components/plugs/knowledge-tree.vue
  25. 3 3
      back-ui/src/views/dz/papers/components/plugs/question-hand.vue
  26. 2 2
      back-ui/src/views/dz/papers/components/plugs/question-intelligent.vue
  27. 0 0
      back-ui/src/views/dz/papers/hooks/usePaperBatchCondition.js
  28. 0 0
      back-ui/src/views/dz/papers/hooks/usePaperClassStatisticCondition.js
  29. 75 101
      back-ui/src/views/dz/papers/hooks/usePaperExactCondition.js
  30. 42 50
      back-ui/src/views/dz/papers/hooks/usePaperFullCondition.js
  31. 0 0
      back-ui/src/views/dz/papers/hooks/usePaperKnowledgeCondition.js
  32. 14 16
      back-ui/src/views/dz/papers/hooks/usePaperQuestionCondition.js
  33. 3 3
      back-ui/src/views/dz/papers/index.vue

+ 36 - 36
back-ui/src/api/dz/papers.js

@@ -46,15 +46,15 @@ export function getPaperExamTypes(query) {
 
 /// 院校
 export function getPaperUniversities(query) {
-    // TODO: remove test code
-    return Promise.resolve({
-        code: 200,
-        data: [
-            {id: 1, name: '湖南民政职业技术学院'},
-            {id: 2, name: '湖南铁道职业技术学院'},
-            {id: 3, name: '湖南大众传媒'},
-        ]
-    })
+    // // TODO: remove test code
+    // return Promise.resolve({
+    //     code: 200,
+    //     data: [
+    //         {id: 1, name: '湖南民政职业技术学院'},
+    //         {id: 2, name: '湖南铁道职业技术学院'},
+    //         {id: 3, name: '湖南大众传媒'},
+    //     ]
+    // })
     // query: {batchId}
     return request({
         url: '/learn/teaching/universities',
@@ -65,15 +65,15 @@ export function getPaperUniversities(query) {
 
 /// 专业组
 export function getPaperMajors(query) {
-    // TODO: remove test code
-    return Promise.resolve({
-        code: 200,
-        data: [
-            {id: 1, majorGroup: '默认组', majorName: '电子信息'},
-            {id: 2, majorGroup: '专业组一', majorName: '商务英文'},
-            {id: 3, majorGroup: '专业组一', majorName: '商务管理'},
-        ]
-    })
+    // // TODO: remove test code
+    // return Promise.resolve({
+    //     code: 200,
+    //     data: [
+    //         {id: 1, majorGroup: '默认组', majorName: '电子信息'},
+    //         {id: 2, majorGroup: '专业组一', majorName: '商务英文'},
+    //         {id: 3, majorGroup: '专业组一', majorName: '商务管理'},
+    //     ]
+    // })
     // query: {location, examType, batchId, universityId}
     return request({
         url: '/learn/teaching/majors',
@@ -84,14 +84,14 @@ export function getPaperMajors(query) {
 
 /// 试卷批次
 export function getPaperBatches() {
-    // TODO: remove test code
-    return Promise.resolve({
-        code: 200,
-        data: [
-            {name: '第二批', batchId: 2},
-            {name: '第一批', batchId: 1}
-        ]
-    })
+    // // TODO: remove test code
+    // return Promise.resolve({
+    //     code: 200,
+    //     data: [
+    //         {name: '第二批', batchId: 2},
+    //         {name: '第一批', batchId: 1}
+    //     ]
+    // })
 
     return request({
         url: '/learn/test/list',
@@ -190,16 +190,16 @@ export function getPaperDetail(query) {
 }
 
 export function getPaperClassStatistic(query) {
-    // TODO: remove test code
-    return Promise.resolve({
-        code: 200,
-        data: [
-            {classId: 0, className: '2501班', total: 50, unexact: 10, exact: 40, unsend: 10, send: 20, unfinish: 5, finish: 15},
-            {classId: 0, className: '2502班', total: 50, unexact: 10, exact: 40, unsend: 10, send: 20, unfinish: 5, finish: 15},
-            {classId: 0, className: '2503班', total: 50, unexact: 10, exact: 40, unsend: 10, send: 20, unfinish: 5, finish: 15},
-            {classId: 0, className: '2504班', total: 50, unexact: 10, exact: 40, unsend: 10, send: 20, unfinish: 5, finish: 15}
-        ]
-    })
+    // // TODO: remove test code
+    // return Promise.resolve({
+    //     code: 200,
+    //     data: [
+    //         {classId: 1, className: '2501班', total: 50, unexact: 10, exact: 40, unsend: 10, send: 20, unfinish: 5, finish: 15},
+    //         {classId: 2, className: '2502班', total: 50, unexact: 10, exact: 40, unsend: 10, send: 20, unfinish: 5, finish: 15},
+    //         {classId: 3, className: '2503班', total: 50, unexact: 10, exact: 40, unsend: 10, send: 20, unfinish: 5, finish: 15},
+    //         {classId: 4, className: '2504班', total: 50, unexact: 10, exact: 40, unsend: 10, send: 20, unfinish: 5, finish: 15}
+    //     ]
+    // })
     // 2025.10.16 新增班级统计,用于组卷生成
     const queryDemo = {
         buildType: '', // 试卷构建类型,定义枚举?

+ 1 - 1
back-ui/src/utils/consts.js

@@ -4,7 +4,7 @@ export default {
             ExactIntelligent: 'ExactIntelligent',
             FullIntelligent: 'FullIntelligent',
             ExactHand: 'ExactHand',
-            FullHand: 'ExactHand'
+            FullHand: 'FullHand'
         }
     }
 }

+ 0 - 24
back-ui/src/views/dz/papers/components-bak/paper-by-hand.vue

@@ -1,24 +0,0 @@
-<template>
-    <el-tabs type="border-card" @tab-change="handleTabChange">
-        <el-tab-pane label="全量组卷">
-            <paper-hand-full />
-        </el-tab-pane>
-        <el-tab-pane label="定向组卷">
-            <paper-hand-exact v-if="exactVisited" />
-        </el-tab-pane>
-    </el-tabs>
-</template>
-
-<script setup name="PaperByHand">
-import PaperHandFull from "@/views/dz/papers/components/paper-hand-full.vue";
-import PaperHandExact from "@/views/dz/papers/components/paper-hand-exact.vue";
-
-// 延迟加载,减少初次加载项
-const exactVisited = ref(false)
-const handleTabChange = () => exactVisited.value = true
-
-</script>
-
-<style scoped>
-
-</style>

+ 0 - 23
back-ui/src/views/dz/papers/components-bak/paper-by-intelligent.vue

@@ -1,23 +0,0 @@
-<template>
-    <el-tabs type="border-card" @tab-change="handleTabChange">
-        <el-tab-pane label="全量组卷">
-            <paper-intelligent-full />
-        </el-tab-pane>
-        <el-tab-pane label="定向组卷">
-            <paper-intelligent-exact v-if="exactVisited" />
-        </el-tab-pane>
-    </el-tabs>
-</template>
-
-<script setup name="PaperByIntelligent">
-import PaperIntelligentFull from "@/views/dz/papers/components/paper-intelligent-full.vue";
-import PaperIntelligentExact from "@/views/dz/papers/components/paper-intelligent-exact.vue";
-
-// 延迟加载,减少初次加载项
-const exactVisited = ref(false)
-const handleTabChange = () => exactVisited.value = true
-</script>
-
-<style scoped>
-
-</style>

+ 0 - 54
back-ui/src/views/dz/papers/components-bak/paper-exact-conditions.vue

@@ -1,54 +0,0 @@
-<template>
-    <div class="flex flex-row items-center gap-2">
-        <span :class="labelClass">省份:</span>
-        <el-select v-model="location" style="width: 280px">
-            <el-option v-for="p in provinces" :label="p.dictLabel" :value="p.dictValue"/>
-        </el-select>
-    </div>
-    <div class="flex flex-row items-center gap-2 mt-5">
-        <span :class="labelClass">考生类型:</span>
-        <el-select v-model="examType" style="width: 280px">
-            <el-option v-for="t in examTypes" :label="t.dictLabel" :value="t.dictValue"/>
-        </el-select>
-    </div>
-    <div class="flex flex-row items-center gap-2 mt-5">
-        <span :class="labelClass">批次:</span>
-        <el-select v-model="batchId" style="width: 280px">
-            <el-option v-for="b in batchList" :label="b.name" :value="b.batchId"/>
-        </el-select>
-    </div>
-    <div class="flex flex-row items-center gap-2 mt-5">
-        <span :class="labelClass">院校:</span>
-        <el-select v-model="universityId" style="width: 280px">
-            <el-option v-for="u in universities" :label="u.name" :value="u.id"/>
-        </el-select>
-    </div>
-    <div class="flex flex-row items-center gap-2 mt-5">
-        <span :class="labelClass">专业组:</span>
-        <el-radio-group v-model="majorPlanId">
-            <el-radio-button v-for="m in majors" :label="m.majorGroup" :value="m.id"/>
-        </el-radio-group>
-    </div>
-    <div class="flex flex-row items-center gap-2 mt-5">
-        <span :class="labelClass">科目:</span>
-        <el-radio-group v-model="subjectId">
-            <el-radio-button v-for="s in subjects" :label="s.subjectName" :value="s.subjectId"/>
-        </el-radio-group>
-    </div>
-</template>
-
-<script setup name="PaperExactConditions">
-import {useInjectPaperExactCondition} from "@/views/dz/papers/hooks/usePaperExactCondition.js";
-
-const labelClass = 'break-keep text-sm font-bold w-[80px]'
-const {location, provinces,
-    examType, examTypes,
-    batchId, batchList,
-    universityId, universities,
-    majorPlanId, majors,
-    subjectId, subjects} = useInjectPaperExactCondition()
-</script>
-
-<style scoped>
-
-</style>

+ 0 - 24
back-ui/src/views/dz/papers/components-bak/paper-full-conditions.vue

@@ -1,24 +0,0 @@
-<template>
-    <div class="flex flex-row items-center gap-2">
-        <span class="break-keep text-sm font-bold">科目:</span>
-        <el-radio-group v-model="subjectId">
-            <el-radio-button v-for="s in subjects" :label="s.subjectName" :value="s.subjectId"/>
-        </el-radio-group>
-    </div>
-    <div class="flex flex-row items-center gap-2 mt-5">
-        <span class="break-keep text-sm font-bold">批次:</span>
-        <el-select v-model="batchId" style="width: 280px">
-            <el-option v-for="b in batchList" :label="b.name" :value="b.batchId"/>
-        </el-select>
-    </div>
-</template>
-
-<script setup name="PaperFullConditions">
-import {useInjectPaperFullCondition} from "@/views/dz/papers/hooks/usePaperFullCondition.js";
-
-const {subjectId, subjects, batchId, batchList} = useInjectPaperFullCondition()
-</script>
-
-<style scoped>
-
-</style>

+ 0 - 24
back-ui/src/views/dz/papers/components-bak/paper-hand-exact.vue

@@ -1,24 +0,0 @@
-<template>
-    <paper-exact-conditions/>
-    <el-container class="mt-5">
-        <el-aside width="350px">
-            <paper-knowledge-tree exact-mode/>
-        </el-aside>
-        <el-main>
-            <paper-question-hand exact-mode/>
-        </el-main>
-    </el-container>
-</template>
-
-<script setup name="PaperHandExact">
-import PaperExactConditions from "@/views/dz/papers/components/paper-exact-conditions.vue";
-import PaperKnowledgeTree from "@/views/dz/papers/components/paper-knowledge-tree.vue";
-import PaperQuestionHand from "@/views/dz/papers/components/paper-question-hand.vue";
-import {useProvidePaperExactCondition} from "@/views/dz/papers/hooks/usePaperExactCondition.js";
-
-useProvidePaperExactCondition()
-</script>
-
-<style scoped>
-
-</style>

+ 0 - 24
back-ui/src/views/dz/papers/components-bak/paper-hand-full.vue

@@ -1,24 +0,0 @@
-<template>
-    <paper-full-conditions/>
-    <el-container class="mt-5">
-        <el-aside width="350px">
-            <paper-knowledge-tree/>
-        </el-aside>
-        <el-main>
-            <paper-question-hand/>
-        </el-main>
-    </el-container>
-</template>
-
-<script setup name="PaperHandFull">
-import PaperFullConditions from "@/views/dz/papers/components/paper-full-conditions.vue";
-import {useProvidePaperFullCondition} from "@/views/dz/papers/hooks/usePaperFullCondition.js";
-import PaperKnowledgeTree from "@/views/dz/papers/components/paper-knowledge-tree.vue";
-import PaperQuestionHand from "@/views/dz/papers/components/paper-question-hand.vue";
-
-useProvidePaperFullCondition()
-</script>
-
-<style scoped>
-
-</style>

+ 0 - 24
back-ui/src/views/dz/papers/components-bak/paper-intelligent-exact.vue

@@ -1,24 +0,0 @@
-<template>
-    <paper-exact-conditions/>
-    <el-container class="mt-5">
-        <el-aside width="350px">
-            <paper-knowledge-tree allow-multiple exact-mode/>
-        </el-aside>
-        <el-main>
-            <paper-question-intelligent exact-mode/>
-        </el-main>
-    </el-container>
-</template>
-
-<script setup name="PaperIntelligentExact">
-import PaperExactConditions from "@/views/dz/papers/components/paper-exact-conditions.vue";
-import PaperKnowledgeTree from "@/views/dz/papers/components/paper-knowledge-tree.vue";
-import PaperQuestionIntelligent from "@/views/dz/papers/components/paper-question-intelligent.vue";
-import {useProvidePaperExactCondition} from "@/views/dz/papers/hooks/usePaperExactCondition.js";
-
-useProvidePaperExactCondition()
-</script>
-
-<style scoped>
-
-</style>

+ 0 - 24
back-ui/src/views/dz/papers/components-bak/paper-intelligent-full.vue

@@ -1,24 +0,0 @@
-<template>
-    <paper-full-conditions/>
-    <el-container class="mt-5">
-        <el-aside width="350px">
-            <paper-knowledge-tree allow-multiple/>
-        </el-aside>
-        <el-main>
-            <paper-question-intelligent/>
-        </el-main>
-    </el-container>
-</template>
-
-<script setup name="PaperIntelligentFull">
-import PaperFullConditions from "@/views/dz/papers/components/paper-full-conditions.vue";
-import PaperKnowledgeTree from "@/views/dz/papers/components/paper-knowledge-tree.vue";
-import PaperQuestionIntelligent from "@/views/dz/papers/components/paper-question-intelligent.vue";
-import {useProvidePaperFullCondition} from "@/views/dz/papers/hooks/usePaperFullCondition.js";
-
-useProvidePaperFullCondition()
-</script>
-
-<style scoped>
-
-</style>

+ 0 - 45
back-ui/src/views/dz/papers/components-bak/paper-knowledge-tree.vue

@@ -1,45 +0,0 @@
-<template>
-    <el-input v-model="keyword" placeholder="请输入知识点名称" clearable prefix-icon="Search"
-              style="margin-bottom: 20px"/>
-    <el-tree ref="treeRef" v-if="knowledges.length" :data="knowledges" :props="{ label: 'name', children: 'children' }"
-             :expand-on-click-node="false" :filter-node-method="filterNode" node-key="id" highlight-current
-             default-expand-all :show-checkbox="allowMultiple" @node-click="handleNodeClick" @check="handleNodeCheck"/>
-</template>
-
-<script setup name="PaperKnowledgeTree">
-import {useInjectPaperFullCondition} from "@/views/dz/papers/hooks/usePaperFullCondition.js";
-import {useInjectPaperExactCondition} from "@/views/dz/papers/hooks/usePaperExactCondition.js";
-
-const props = defineProps({
-    allowMultiple: Boolean,
-    exactMode: Boolean
-})
-
-const treeRef = ref(null)
-const keyword = ref('')
-const {knowledges, knowledgeNode, knowledgeCheckNodes, onKnowledgeRemove} = props.exactMode
-    ? useInjectPaperExactCondition()
-    : useInjectPaperFullCondition()
-
-const filterNode = function (value, data) {
-    if (!value) return true
-    return data.name.indexOf(value) !== -1
-}
-
-const handleNodeClick = function (data) {
-    knowledgeNode.value = data
-}
-
-const handleNodeCheck = function (data, {checkedNodes}) {
-    // 多选时,只保留叶子节点
-    knowledgeCheckNodes.value = checkedNodes.filter(k => !!!k.children?.length)
-}
-
-onKnowledgeRemove((k) => {
-    treeRef.value.setChecked(k, false, false)
-})
-</script>
-
-<style scoped>
-
-</style>

+ 0 - 26
back-ui/src/views/dz/papers/components-bak/paper-publish.vue

@@ -1,26 +0,0 @@
-<template>
-    <div class="">
-
-    </div>
-</template>
-
-<script setup name="PaperPublish">
-
-import {getPaperClasses} from "@/api/dz/papers.js";
-
-const props = defineProps({
-    paper: Object
-})
-
-const classList = ref([])
-const studentContainer = ref({})
-
-watch(() => paper.id, async (paperId) => {
-    const res = await getPaperClasses()
-    classList.value = res.data
-})
-</script>
-
-<style scoped>
-
-</style>

+ 0 - 112
back-ui/src/views/dz/papers/components-bak/paper-question-hand.vue

@@ -1,112 +0,0 @@
-<template>
-    <div class="text-main mb-3">
-        当前查询知识点(从左侧选择):<el-text size="large" type="primary" class="font-bold">{{ knowledgeNode?.name }}</el-text>
-    </div>
-    <div class="flex flex-row items-center gap-3">
-        <el-input v-model="keywordLocal" clearable prefix-icon="search" placeholder="输入题目关键字-回车触发搜索"
-                  style="width: 250px" @keydown.enter="confirmKeyword" @clear="confirmKeyword"/>
-        <el-select v-model="qtpye" clearable style="width: 220px">
-            <el-option v-for="t in qTypes" :value="t.dictValue" :label="t.dictLabel"></el-option>
-        </el-select>
-        <el-popover width="250">
-            <span v-if="currentSubject" class="text-sm font-bold">科目:{{ currentSubject.subjectName }}</span>
-            <div v-for="g in groupedQuestions" class="flex flex-col">
-                <el-divider style="margin: 10px 0"/>
-                <span>{{ g.qtpye }}:{{ g.questions.length }}道</span>
-                <el-link type="danger" plain icon="delete" class="self-end" @click="removeQuestionGroup(g.qtpye)">清除
-                </el-link>
-            </div>
-            <el-divider style="margin: 10px 0"/>
-            <div class="flex items-center justify-between">
-                <el-link type="danger" plain icon="delete" @click="clearCart">全部清除</el-link>
-                <el-button type="primary" @click="buildPaper">生成试卷</el-button>
-            </div>
-            <template #reference>
-                <el-button type="primary" size="large" icon="shopping-cart" class="ml-auto">
-                    试题篮({{ cart.length }})
-                </el-button>
-            </template>
-        </el-popover>
-    </div>
-    <el-divider/>
-    <el-empty v-if="total==0"/>
-    <template v-else v-for="q in questionList">
-        <question-content :question="q" @parse="showParseQuestion=q,showParse=true">
-            <el-button v-if="!hasQuestion(q)" type="primary" icon="plus" class="ml-auto" @click="addQuestion(q)">
-                加入试题篮
-            </el-button>
-            <el-button v-else type="danger" plain icon="delete" class="ml-auto" @click="removeQuestion(q)">移出试题篮
-            </el-button>
-        </question-content>
-        <el-divider/>
-    </template>
-    <pagination v-show="total>0" :total="total" v-model:page="pageNum" v-model:limit="pageSize"
-                @pagination="getQuestionList"/>
-
-    <el-dialog v-model="showParse" append-to-body show-close @close="showParse=false">
-        <template #title>ID:{{ showParseQuestion.id }} 试题解析</template>
-        <div v-if="showParseQuestion.answer0" v-html="`【正确答案】` + showParseQuestion.answer0"/>
-        <div v-if="showParseQuestion.parse" v-html="`【解析】` + showParseQuestion.parse" class="mt-5"></div>
-        <div v-if="showParseQuestion.parse0" v-html="`【解析】` + showParseQuestion.parse0" class="mt-5"></div>
-        <template #footer>
-            <el-button type="primary" @click="showParse=false">确 定</el-button>
-        </template>
-    </el-dialog>
-</template>
-
-<script setup name="PaperQuestionHand">
-import router from '@/router'
-import {ElMessage} from "element-plus";
-import {useProvidePaperQuestionCondition} from "@/views/dz/papers/hooks/usePaperQuestionCondition.js";
-import {useInjectPaperExactCondition} from "@/views/dz/papers/hooks/usePaperExactCondition.js";
-import {useInjectPaperFullCondition} from "@/views/dz/papers/hooks/usePaperFullCondition.js";
-import {usePaperStorage} from "@/views/dz/papers/hooks/usePaperStorage.js";
-import QuestionContent from "@/views/components/question-content.vue";
-
-const props = defineProps({
-    allowMultiple: Boolean,
-    exactMode: Boolean
-})
-
-const showParse = ref(false)
-const showParseQuestion = ref(null)
-
-const {knowledgeNode, paperArgs} = props.exactMode ? useInjectPaperExactCondition() : useInjectPaperFullCondition()
-const {
-    keyword,
-    qtpye,
-    qTypes,
-    pageNum,
-    pageSize,
-    total,
-    questionList,
-    getQuestionList,
-    cart,
-    groupedQuestions,
-    currentSubject,
-    hasQuestion,
-    addQuestion,
-    removeQuestion,
-    removeQuestionGroup,
-    clearCart
-} = useProvidePaperQuestionCondition(props.exactMode, props.allowMultiple)
-
-const keywordLocal = ref('')
-const confirmKeyword = (val) => keyword.value = keywordLocal.value
-
-const buildPaper = function () {
-    // validation
-    const {batchId} = paperArgs.value
-    if (!batchId) return ElMessage.error('请选择批次')
-    if (!knowledgeNode.value) return ElMessage.error('请选择知识点')
-    if (!cart.value.length) return ElMessage.error('请将试题加入试题篮')
-
-    const paper = {...paperArgs.value, questions: cart.value}
-    usePaperStorage(paper)
-    router.push({name: 'PaperDetail'})
-}
-</script>
-
-<style scoped>
-
-</style>

+ 0 - 71
back-ui/src/views/dz/papers/components-bak/paper-question-intelligent.vue

@@ -1,71 +0,0 @@
-<template>
-    <div class="text-main mb-3 flex items-center">
-        <div :class="seqClass">1</div>选择知识点(从左侧勾选)
-    </div>
-    <div class="flex flex-row flex-wrap gap-3">
-        <el-tag v-for="k in knowledgeCheckNodes" type="primary" round closable @close="removeKnowledge(k)">{{k.name}}</el-tag>
-    </div>
-    <div class="text-main mt-10 mb-3 flex items-center">
-        <div :class="seqClass">2</div>试题设置
-    </div>
-    <div class="flex flex-row flex-warp gap-10">
-        <div v-for="t in qTypes" class="flex items-center gap-3">
-            <el-text class="font-bold break-keep">{{t.dictLabel}}</el-text>
-            <el-input-number v-model="t.count" :min="0"/>
-        </div>
-    </div>
-    <div class="mt-10 text-right">
-        <el-button type="primary" size="large" @click="buildPaper">生成试卷</el-button>
-    </div>
-</template>
-
-<script setup name="PaperQuestionIntelligent">
-
-import {useInjectPaperExactCondition} from "@/views/dz/papers/hooks/usePaperExactCondition.js";
-import {useInjectPaperFullCondition} from "@/views/dz/papers/hooks/usePaperFullCondition.js";
-import {useProvidePaperQuestionCondition} from "@/views/dz/papers/hooks/usePaperQuestionCondition.js";
-import {useInjectLoading} from "@/views/hooks/useGlobalLoading.js";
-import {ElMessage} from "element-plus";
-import {buildPaperAuto} from "@/api/dz/papers.js";
-import {sleep} from "@/utils/index.js";
-import router from "@/router/index.js";
-
-const props = defineProps({
-    allowMultiple: Boolean,
-    exactMode: Boolean
-})
-
-const seqClass = 'inline-block rounded-full bg-blue-100 w-5 h-5 text-center mr-2'
-const {knowledgeCheckNodes, removeKnowledge, paperArgs} = props.exactMode ? useInjectPaperExactCondition() : useInjectPaperFullCondition()
-const {qTypes} = useProvidePaperQuestionCondition(props.exactMode, props.allowMultiple, true)
-const {loading} = useInjectLoading()
-
-const buildPaper = async function () {
-    // validation
-    const {batchId} = paperArgs.value
-    if (!batchId) return ElMessage.error('请选择批次')
-    if (!knowledgeCheckNodes.value.length) return ElMessage.error('请选择知识点')
-    if (!qTypes.value.length || qTypes.value.every(t => !t.count)) return ElMessage.error('请填写题量')
-
-    // build
-    const commit = {
-        ...paperArgs.value,
-        paperDef: {
-            knowIds: knowledgeCheckNodes.value.map(k => k.id),
-            types: qTypes.value.map(t => ({
-                type: t.dictValue,
-                title: t.dictLabel,
-                count: t.count
-            }))
-        }
-    }
-    await buildPaperAuto(commit)
-    ElMessage.success('生成成功,即将打开组卷记录')
-    await sleep(2000)
-    await router.push('/paper/list')
-}
-</script>
-
-<style scoped>
-
-</style>

+ 0 - 101
back-ui/src/views/dz/papers/components/conditions/usePaperExactCondition.js

@@ -1,101 +0,0 @@
-import {useProvidePaperBatchCondition} from "@/views/dz/papers/components/conditions/usePaperBatchCondition.js";
-import {getPaperMajors, getPaperUniversities} from "@/api/dz/papers.js";
-import {createEventHook, injectLocal, provideLocal} from "@vueuse/core";
-
-const key = Symbol('PaperExactCondition')
-export const useProvidePaperExactCondition = function (type) {
-    const {buildType, batchId, batchList} = useProvidePaperBatchCondition(type)
-
-    const universityId = ref('')
-    const universities = ref([])
-
-    const _allMajors = ref([])
-
-    const majorGroup = ref('')
-    const majorGroups = computed(() => {
-        const results = []
-        _allMajors.value.forEach(m => {
-            if (results.includes(m.majorGroup)) return
-            results.push(m.majorGroup)
-        })
-        return results
-    })
-
-    const majorPlanId = ref('')
-    const majors = computed(() => {
-        if (!majorGroup.value) return
-        return _allMajors.value.filter(m => m.majorGroup == majorGroup.value)
-    })
-
-    const conditionArgs = computed(() => ({
-        buildType: toValue(buildType),
-        universityId: toValue(universityId),
-        majorGroup: toValue(majorGroup),
-        majorPlanId: toValue(majorPlanId)
-    }))
-    const conditionData = computed(() => ({
-        universities: toValue(universities),
-        majorGroups: toValue(majorGroups),
-        majors: toValue(majors)
-    }))
-    const exactEvent = createEventHook()
-    const triggerExactEvent = async function (args) {
-         await exactEvent.trigger(args)
-    }
-
-    watch(batchId, async (batchId) => {
-        universityId.value = ''
-        universities.value = []
-
-        if (!batchId) return
-        const res = await getPaperUniversities({buildType, batchId})
-        universities.value = res.data
-    })
-
-    watch([batchId, universityId], async ([batchId, universityId]) => {
-        majorGroup.value = ''
-
-        if (!batchId || !universityId) return
-        const res = await getPaperMajors({buildType, batchId, universityId})
-        _allMajors.value = res.data
-
-        // 没有数据时,说明已经满足了条件
-        if (!majorGroups.value.length) await triggerExactEvent({buildType, batchId, universityId})
-        else if (majorGroups.value.length == 1) majorGroup.value = majorGroups.value[0]
-    })
-
-    watch([batchId, universityId, majorGroup], async ([batchId, universityId, majorGroup]) => {
-        majorPlanId.value = ''
-
-        if (!batchId || !universityId || !majorGroup) return
-        if (!majors.value.length) await triggerExactEvent({buildType, batchId, universityId, majorGroup})
-        else if (majors.value.length == 1) majorPlanId.value = majors.value[0].id
-    })
-
-    watch(majorPlanId, async (majorPlanId) => {
-        if (!majorPlanId) return
-
-        // 最细的情况,选中了专业
-        const args = {
-            buildType,
-            batchId: toValue(batchId),
-            universityId: toValue(universityId),
-            majorGroup: toValue(majorGroup),
-            majorPlanId
-        }
-        await triggerExactEvent(args)
-    })
-
-    const payload = {buildType, batchId, batchList,
-        universityId, universities,
-        majorGroup, majorGroups,
-        majorPlanId, majors,
-        conditionArgs, conditionData,
-        onConditionReady: exactEvent.on}
-    provideLocal(key, payload)
-    return payload
-}
-
-export const useInjectPaperExactCondition = function () {
-    return injectLocal(key)
-}

+ 0 - 59
back-ui/src/views/dz/papers/components/conditions/usePaperFullCondition.js

@@ -1,59 +0,0 @@
-import {createEventHook, injectLocal, provideLocal} from "@vueuse/core";
-import {useProvidePaperBatchCondition} from "@/views/dz/papers/components/conditions/usePaperBatchCondition.js";
-import {getPaperExamTypes, getPaperSubjects} from "@/api/dz/papers.js";
-
-const key = Symbol('PaperFullCondition')
-export const useProvidePaperFullCondition = function (type) {
-    const {buildType, batchId, batchList} = useProvidePaperBatchCondition(type)
-
-    const examType = ref('')
-    const examTypes = ref([])
-
-    const subjectId = ref('')
-    const subjectList = ref([])
-
-    const conditionArgs = computed(() => ({
-        buildType: toValue(buildType),
-        examType: toValue(examType),
-        subjectId: toValue(subjectId)
-    }))
-    const conditionData = computed(() => ({
-        examTypes: toValue(examTypes),
-        subjectList: toValue(subjectList)
-    }))
-    const readyEvent = createEventHook()
-
-    watch(batchId, async (batchId) => {
-        examType.value = ''
-        examTypes.value = []
-
-        const res = await getPaperExamTypes({buildType, batchId})
-        examTypes.value = res.data
-    })
-    watch([batchId, examType], async ([batchId, examType]) => {
-        subjectId.value = ''
-        subjectList.value = []
-
-        if(!batchId || !examType) return
-        const res = await getPaperSubjects({buildType, batchId, examType})
-        subjectList.value = res.data
-    })
-    watch([batchId, examType, subjectId], async ([batchId, examType, subjectId]) => {
-        if (!subjectId) return
-        const payload = {buildType, batchId, examType, subjectId}
-        await readyEvent.trigger(payload)
-    })
-
-    const payload = {buildType, batchId, batchList,
-        examType, examTypes,
-        subjectId, subjectList,
-        conditionArgs, conditionData,
-        onConditionReady: readyEvent.on}
-    provideLocal(key, payload)
-    return payload
-
-}
-
-export const useInjectPaperFullCondition = function (){
-    return injectLocal(key)
-}

+ 0 - 111
back-ui/src/views/dz/papers/components/conditions/usePaperQuestionCondition.js

@@ -1,111 +0,0 @@
-import {useInjectPaperExactCondition} from "@/views/dz/papers/components/conditions/usePaperExactCondition.js";
-import {useInjectPaperFullCondition} from "@/views/dz/papers/components/conditions/usePaperFullCondition.js";
-import {useInjectPaperKnowledgeCondition} from "@/views/dz/papers/components/conditions/usePaperKnowledgeCondition.js";
-import {useInjectGlobalLoading} from "@/views/hooks/useGlobalLoading.js";
-import {ElMessage} from "element-plus";
-import {getPaperQuestions, getPaperQuestionTypes} from "@/api/dz/papers.js";
-import {injectLocal, provideLocal} from "@vueuse/core";
-
-const key = Symbol('PaperQuestionCondition')
-
-export const useProvidePaperQuestionCondition = function (exactMode, handMode) {
-    const keyword = ref('')
-    const qtpye = ref('') // 历史遗留拼写错误
-    const qTypes = ref([])
-
-    const pageNum = ref(1)
-    const pageSize = ref(10)
-    const total = ref(0)
-    const questionList = ref([])
-
-    const {conditionArgs, conditionData, onConditionReady} = exactMode ? useInjectPaperExactCondition() : useInjectPaperFullCondition()
-    const {knowledgeId, knowledgeIds} = useInjectPaperKnowledgeCondition()
-    const loading = useInjectGlobalLoading()
-
-    // question cart
-    const cart = ref([])
-    const currentSubject = computed(() => {
-        if (!conditionArgs.value.subjectId) return null
-        return conditionData.value.subjectList.find(s => s.subjectId == conditionArgs.value.subjectId)
-    })
-    const groupedQuestions = computed(() => {
-        const results = {}
-        cart.value.forEach(q => {
-            if (!results[q.qtpye]) {
-                results[q.qtpye] = []
-            }
-            results[q.qtpye].push(q)
-        })
-        return Object.keys(results).map(k => ({qtpye: k, questions: results[k]}))
-    })
-    const hasQuestion = (q) => {
-        return cart.value.some(c => c.id == q.id)
-    }
-    const removeQuestion = (q) => {
-        const idx = cart.value.findIndex(c => c.id == q.id)
-        if (idx > -1) cart.value.splice(idx, 1)
-    }
-    const addQuestion = (q) => {
-        if (currentSubject.value && currentSubject.value.subjectId != q.subjectId) {
-            return ElMessage.error(`当前科目【${currentSubject.value.subjectName}】冲突`)
-        }
-        cart.value.push(q)
-    }
-    const removeQuestionGroup = (qtpye) => {
-        const ls = groupedQuestions.value.find(g => g.qtpye == qtpye)?.questions
-        ls?.forEach(q => removeQuestion(q))
-    }
-    const clearCart = () => cart.value = []
-
-    // hooks
-    watch([() => conditionArgs.value.subjectId, knowledgeId, () => knowledgeIds.value.toString()], async ([subjectId, knowledgeId, knowledgeIds]) => {
-        // clean
-        qtpye.value = ''
-        qTypes.value = []
-
-        if (!subjectId && conditionData.value.subjectList?.length) return
-        if (!knowledgeId && !knowledgeIds) return
-        const query = {subjectId, knowledgeIds: knowledgeId || knowledgeIds}
-        const res = await getPaperQuestionTypes(query)
-        qTypes.value = res.data
-    })
-
-    const questionQuery = computed(() => ({
-        pageNum: pageNum.value,
-        pageSize: pageSize.value,
-        title: keyword.value,
-        qtpye: qtpye.value,
-        // knowledgeId: knowledgeId.value,
-        // knowledges: knowledgeIds.value.toString()
-    }))
-    const getQuestionList = async function () {
-        if (!handMode) return // 智能组卷时不需要查询
-        loading.value = true
-        try {
-            const res = await getPaperQuestions(questionQuery.value)
-            total.value = res.total
-            questionList.value = res.rows
-        } finally {
-            loading.value = false
-        }
-    }
-    watch([keyword, qtpye, knowledgeId, () => knowledgeIds.value.toString()], async ([title, qtpye, knowledgeId, knowledges]) => {
-        pageNum.value = 1
-        questionList.value = []
-        total.value = 0
-
-        if (!knowledgeId && !knowledges) return // 有知识点即可以查询题库
-        await getQuestionList(pageNum.value, pageSize.value)
-    })
-
-    const payload = {
-        keyword, qtpye, qTypes, pageNum, pageSize, total, questionList, getQuestionList,
-        cart, currentSubject, groupedQuestions,
-        hasQuestion, addQuestion, removeQuestion, removeQuestionGroup, clearCart
-    }
-    provideLocal(key, payload)
-    return payload
-}
-export const useInjectPaperQuestionCondition = function () {
-    return injectLocal(key)
-}

+ 0 - 41
back-ui/src/views/dz/papers/components/conditions/usePaperStorage.js

@@ -1,41 +0,0 @@
-import {useStorage} from "@vueuse/core";
-
-const key = 'PaperStorage'
-export const usePaperStorage = function (body) {
-    const bodyStr = JSON.stringify(body)
-    const paper = useStorage(key, bodyStr)
-    paper.value = bodyStr
-    return {paper}
-}
-
-export const usePaperResolver = function () {
-    const paper = useStorage(key, null)
-    const paperLocal = ref(JSON.parse(paper.value))
-    const groupedQuestions = ref([])
-    const resolvePaper = (function () {
-        const results = {}
-        paperLocal.value.questions.forEach(q => {
-            if (!results[q.qtpye]) results[q.qtpye] = []
-            results[q.qtpye].push(q)
-        })
-        groupedQuestions.value = Object.keys(results).map(g => ({
-            title: g,
-            list: results[g],
-            num: results[g].length,
-            score: results[g].reduce((acc, current) => acc + current.score, 0)
-        }))
-    })()
-
-    const toCommitPaper = function () {
-        const questions = []
-        groupedQuestions.value.forEach(g => questions.push(...g.list))
-        return {
-            ...paperLocal.value,
-            questions
-        }
-    }
-
-    return {
-        paperLocal, groupedQuestions, resolvePaper, toCommitPaper
-    }
-}

+ 3 - 3
back-ui/src/views/dz/papers/components/paper-exact-hand.vue

@@ -42,9 +42,9 @@
 <script setup name="PaperExactHand">
 
 import consts from "@/utils/consts.js";
-import {useProvidePaperExactCondition} from "@/views/dz/papers/components/conditions/usePaperExactCondition.js";
-import {useProvidePaperClassStatisticCondition} from "@/views/dz/papers/components/conditions/usePaperClassStatisticCondition.js";
-import {useProvidePaperKnowledgeCondition} from "@/views/dz/papers/components/conditions/usePaperKnowledgeCondition.js";
+import {useProvidePaperExactCondition} from "@/views/dz/papers/hooks/usePaperExactCondition.js";
+import {useProvidePaperClassStatisticCondition} from "@/views/dz/papers/hooks/usePaperClassStatisticCondition.js";
+import {useProvidePaperKnowledgeCondition} from "@/views/dz/papers/hooks/usePaperKnowledgeCondition.js";
 import ClassStatisticTable from "@/views/dz/papers/components/plugs/class-statistic-table.vue";
 import KnowledgeTree from "@/views/dz/papers/components/plugs/knowledge-tree.vue";
 import QuestionHand from "@/views/dz/papers/components/plugs/question-hand.vue";

+ 2 - 4
back-ui/src/views/dz/papers/components/paper-exact-intelligent.vue

@@ -21,10 +21,8 @@
 
 <script setup name="PaperExactIntelligent">
 import consts from "@/utils/consts.js";
-import {useProvidePaperBatchCondition} from "@/views/dz/papers/components/conditions/usePaperBatchCondition.js";
-import {
-    useProvidePaperClassStatisticCondition
-} from "@/views/dz/papers/components/conditions/usePaperClassStatisticCondition.js";
+import {useProvidePaperBatchCondition} from "@/views/dz/papers/hooks/usePaperBatchCondition.js";
+import {useProvidePaperClassStatisticCondition} from "@/views/dz/papers/hooks/usePaperClassStatisticCondition.js";
 import ClassStatisticTable from "@/views/dz/papers/components/plugs/class-statistic-table.vue";
 import {ElMessage} from "element-plus";
 import {buildPaperExactIntelligent} from "@/api/dz/papers.js";

+ 94 - 1
back-ui/src/views/dz/papers/components/paper-full-hand.vue

@@ -1,8 +1,101 @@
 <template>
-    全量手动组卷
+    <el-row :gutter="20">
+        <el-col :span="8">
+            <el-form label-width="68px">
+                <el-form-item label="批次">
+                    <el-select v-model="batchId" clearable style="width: 227px">
+                        <el-option v-for="b in batchList" :label="b.name" :value="b.batchId"/>
+                    </el-select>
+                </el-form-item>
+                <el-form-item label="考生类型">
+                    <el-select v-model="examType" clearable style="width: 227px">
+                        <el-option v-for="e in examTypes" :label="e.dictLabel" :value="e.dictValue"/>
+                    </el-select>
+                </el-form-item>
+                <el-form-item label="科目">
+                    <el-select v-model="subjectId" clearable style="width: 227px">
+                        <el-option v-for="s in subjectList" :label="s.subjectName" :value="s.subjectId"/>
+                    </el-select>
+                </el-form-item>
+            </el-form>
+        </el-col>
+        <el-col :span="16">
+            <class-statistic-table/>
+        </el-col>
+    </el-row>
+    <el-divider/>
+    <el-row :gutter="20">
+        <el-col :span="6">
+            <knowledge-tree/>
+        </el-col>
+        <el-col :span="18">
+            <question-hand @submit="handleSubmit"/>
+        </el-col>
+    </el-row>
 </template>
 
 <script setup name="PaperFullHand">
+import {ElMessage} from "element-plus";
+import router from "@/router/index.js";
+import consts from "@/utils/consts.js";
+import {useProvidePaperClassStatisticCondition} from "@/views/dz/papers/hooks/usePaperClassStatisticCondition.js";
+import {useProvidePaperKnowledgeCondition} from "@/views/dz/papers/hooks/usePaperKnowledgeCondition.js";
+import {useProvidePaperFullCondition} from "@/views/dz/papers/hooks/usePaperFullCondition.js";
+import {usePaperStorage} from "@/views/dz/papers/hooks/usePaperStorage.js";
+import ClassStatisticTable from "@/views/dz/papers/components/plugs/class-statistic-table.vue";
+import KnowledgeTree from "@/views/dz/papers/components/plugs/knowledge-tree.vue";
+import QuestionHand from "@/views/dz/papers/components/plugs/question-hand.vue";
+
+const type = consts.enums.buildType.FullHand
+const {
+    batchId,
+    batchList,
+    examType,
+    examTypes,
+    subjectId,
+    subjectList,
+    onConditionReady
+} = useProvidePaperFullCondition(type)
+const {selectedClasses, classList, loadClassStatistic} = useProvidePaperClassStatisticCondition()
+const {knowledgeNode, knowledgeCheckNodes, loadKnowledge} = useProvidePaperKnowledgeCondition()
+
+const handleSubmit = async (questions) => {
+    // validation
+    if (!batchId.value) return ElMessage.error('请选择批次')
+    if (!examType.value) return ElMessage.error('请选择考生类型')
+    if (!subjectId.value) return ElMessage.error('请选择科目')
+    const classIds = selectedClasses.value.map(c => c.classId)
+    if (!classIds.length) return ElMessage.error('请选择班级')
+    if (!questions.length) return ElMessage.error('请将试题加入试题篮')
+
+    const paper = {
+        buildType: type,
+        batchId: toValue(batchId),
+        examType: toValue(examType),
+        subjectId: toValue(subjectId),
+        classIds,
+        questions
+    }
+    usePaperStorage(paper)
+    await router.push({name: 'PaperDetail'})
+}
+
+let statArg = null
+const _loadClassStatistic = async () => {
+    selectedClasses.value = []
+    classList.value = []
+
+    await loadClassStatistic(statArg)
+}
+
+onConditionReady(async (payload) => {
+    statArg = payload
+    knowledgeNode.value = null
+    knowledgeCheckNodes.value = []
+
+    await loadKnowledge(payload)
+    await _loadClassStatistic()
+})
 </script>
 
 <style scoped>

+ 3 - 7
back-ui/src/views/dz/papers/components/paper-full-intelligent.vue

@@ -37,18 +37,14 @@
 <script setup name="PaperFullIntelligent">
 
 import consts from "@/utils/consts.js";
-import {useProvidePaperFullCondition} from "@/views/dz/papers/components/conditions/usePaperFullCondition.js";
+import {useProvidePaperFullCondition} from "@/views/dz/papers/hooks/usePaperFullCondition.js";
 import ClassStatisticTable from "@/views/dz/papers/components/plugs/class-statistic-table.vue";
-import {
-    useProvidePaperClassStatisticCondition
-} from "@/views/dz/papers/components/conditions/usePaperClassStatisticCondition.js";
+import {useProvidePaperClassStatisticCondition} from "@/views/dz/papers/hooks/usePaperClassStatisticCondition.js";
 import KnowledgeTree from "@/views/dz/papers/components/plugs/knowledge-tree.vue";
-import {useProvidePaperKnowledgeCondition} from "@/views/dz/papers/components/conditions/usePaperKnowledgeCondition.js";
+import {useProvidePaperKnowledgeCondition} from "@/views/dz/papers/hooks/usePaperKnowledgeCondition.js";
 import QuestionIntelligent from "@/views/dz/papers/components/plugs/question-intelligent.vue";
 import {ElMessage} from "element-plus";
 import {buildPaperFullIntelligent} from "@/api/dz/papers.js";
-import {sleep} from "@/utils/index.js";
-import router from "@/router/index.js";
 
 const type = consts.enums.buildType.FullIntelligent
 const {

+ 1 - 3
back-ui/src/views/dz/papers/components/plugs/class-statistic-table.vue

@@ -4,9 +4,7 @@
 </template>
 
 <script setup name="ClassStatisticTable">
-import {
-    useInjectPaperClassStatisticCondition
-} from "@/views/dz/papers/components/conditions/usePaperClassStatisticCondition.js";
+import {useInjectPaperClassStatisticCondition} from "@/views/dz/papers/hooks/usePaperClassStatisticCondition.js";
 import Table from '@/components/Table/index.vue';
 
 const props = defineProps({

+ 1 - 1
back-ui/src/views/dz/papers/components/plugs/knowledge-tree.vue

@@ -6,7 +6,7 @@
 </template>
 
 <script setup name="KnowledgeTree">
-import {useInjectPaperKnowledgeCondition} from "@/views/dz/papers/components/conditions/usePaperKnowledgeCondition.js";
+import {useInjectPaperKnowledgeCondition} from "@/views/dz/papers/hooks/usePaperKnowledgeCondition.js";
 
 const props = defineProps({
     allowMultiple: Boolean

+ 3 - 3
back-ui/src/views/dz/papers/components/plugs/question-hand.vue

@@ -56,9 +56,9 @@
 
 <script setup name="QuestionHand">
 import {ElMessage} from "element-plus";
-import {useProvidePaperQuestionCondition} from "@/views/dz/papers/components/conditions/usePaperQuestionCondition.js";
-import {useInjectPaperBatchCondition} from "@/views/dz/papers/components/conditions/usePaperBatchCondition.js";
-import {useInjectPaperKnowledgeCondition} from "@/views/dz/papers/components/conditions/usePaperKnowledgeCondition.js";
+import {useProvidePaperQuestionCondition} from "@/views/dz/papers/hooks/usePaperQuestionCondition.js";
+import {useInjectPaperBatchCondition} from "@/views/dz/papers/hooks/usePaperBatchCondition.js";
+import {useInjectPaperKnowledgeCondition} from "@/views/dz/papers/hooks/usePaperKnowledgeCondition.js";
 import QuestionContent from "@/views/components/question-content.vue";
 
 const props = defineProps({

+ 2 - 2
back-ui/src/views/dz/papers/components/plugs/question-intelligent.vue

@@ -22,8 +22,8 @@
 
 <script setup name="QuestionIntelligent">
 
-import {useProvidePaperQuestionCondition} from "@/views/dz/papers/components/conditions/usePaperQuestionCondition.js";
-import {useInjectPaperKnowledgeCondition} from "@/views/dz/papers/components/conditions/usePaperKnowledgeCondition.js";
+import {useProvidePaperQuestionCondition} from "@/views/dz/papers/hooks/usePaperQuestionCondition.js";
+import {useInjectPaperKnowledgeCondition} from "@/views/dz/papers/hooks/usePaperKnowledgeCondition.js";
 
 const props = defineProps({
     exactMode: Boolean

+ 0 - 0
back-ui/src/views/dz/papers/components/conditions/usePaperBatchCondition.js → back-ui/src/views/dz/papers/hooks/usePaperBatchCondition.js


+ 0 - 0
back-ui/src/views/dz/papers/components/conditions/usePaperClassStatisticCondition.js → back-ui/src/views/dz/papers/hooks/usePaperClassStatisticCondition.js


+ 75 - 101
back-ui/src/views/dz/papers/hooks/usePaperExactCondition.js

@@ -1,124 +1,98 @@
+import {useProvidePaperBatchCondition} from "@/views/dz/papers/hooks/usePaperBatchCondition.js";
+import {getPaperMajors, getPaperUniversities} from "@/api/dz/papers.js";
 import {createEventHook, injectLocal, provideLocal} from "@vueuse/core";
-import {
-    getPaperBatches,
-    getPaperExamTypes,
-    getPaperKnowledges,
-    getPaperMajors,
-    getPaperProvinces,
-    getPaperSubjects,
-    getPaperUniversities
-} from "@/api/dz/papers.js";
 
 const key = Symbol('PaperExactCondition')
+export const useProvidePaperExactCondition = function (type) {
+    const {buildType, batchId, batchList} = useProvidePaperBatchCondition(type)
 
-export const useProvidePaperExactCondition = function () {
-    const batchId = ref('')
-    const batchList = ref([])
-
-    const location = ref('')
-    const provinces = ref([])
-    const examType = ref('')
-    const examTypes = ref([])
     const universityId = ref('')
     const universities = ref([])
+
+    const _allMajors = ref([])
+
+    const majorGroup = ref('')
+    const majorGroups = computed(() => {
+        const results = []
+        _allMajors.value.forEach(m => {
+            if (results.includes(m.majorGroup)) return
+            results.push(m.majorGroup)
+        })
+        return results
+    })
+
     const majorPlanId = ref('')
-    const majors = ref([])
-
-    const subjects = ref([])
-    const subjectId = ref('')
-    const knowledges = ref([])
-    const knowledgeNode = ref(null) // 单选节点
-    const knowledgeCheckNodes = ref([]) // 多选的节点
-    const knowledgeIds = computed(() => knowledgeCheckNodes.value.map(k => k.id))
-    const knowledgeId = computed(() => knowledgeNode.value?.id || '') // 单选
-    const knowledgeRemoveEvent = createEventHook()
-    const removeKnowledge = async (k) => {
-        const nodes = knowledgeCheckNodes.value
-        const idx = nodes.indexOf(k)
-        if (idx > -1) {
-            nodes.splice(idx, 1)
-            await knowledgeRemoveEvent.trigger(k)
-        }
-    }
+    const majors = computed(() => {
+        if (!majorGroup.value) return
+        return _allMajors.value.filter(m => m.majorGroup == majorGroup.value)
+    })
 
-    const paperArgs = computed(() => ({
-        batchId: toValue(batchId),
-        batchName: batchList.value.find(b => b.batchId == batchId.value)?.name,
-        subjectId: toValue(subjectId),
-        subjectName: subjects.value.find(s => s.subjectId == subjectId.value)?.subjectName,
-        examTypes: [toValue(examType)],
-        location: toValue(location),
-        universityIds: [toValue(universityId)],
-        planIds: [toValue(majorPlanId)]
+    const conditionArgs = computed(() => ({
+        buildType: toValue(buildType),
+        universityId: toValue(universityId),
+        majorGroup: toValue(majorGroup),
+        majorPlanId: toValue(majorPlanId)
+    }))
+    const conditionData = computed(() => ({
+        universities: toValue(universities),
+        majorGroups: toValue(majorGroups),
+        majors: toValue(majors)
     }))
-    const payload = {
-        location, provinces, examType, examTypes, universityId, universities,
-        batchId, batchList, majorPlanId, majors, subjects, subjectId,
-        knowledges, knowledgeNode, knowledgeId, knowledgeCheckNodes, knowledgeIds,
-        removeKnowledge, onKnowledgeRemove: knowledgeRemoveEvent.on,
-        paperArgs
+    const exactEvent = createEventHook()
+    const triggerExactEvent = async function (args) {
+         await exactEvent.trigger(args)
     }
-    provideLocal(key, payload)
 
-    // hooks
-    onMounted(async () => {
-        const res = await getPaperProvinces()
-        provinces.value = res.data
-    })
-    onMounted(async () => {
-        const res = await getPaperBatches()
-        batchList.value = res.data
-    })
-    watch(location, async (location) => {
-        // clean
-        examType.value = ''
-        examTypes.value = []
-
-        if (!location) return
-        const resT = await getPaperExamTypes({location})
-        examTypes.value = resT.data
-    })
-    watch([location, batchId], async ([location, batchId]) => {
-        // clean
+    watch(batchId, async (batchId) => {
         universityId.value = ''
         universities.value = []
 
-        if (!location || !batchId) return
-        const resU = await getPaperUniversities({location, batchId})
-        universities.value = resU.data
+        if (!batchId) return
+        const res = await getPaperUniversities({buildType, batchId})
+        universities.value = res.data
     })
-    watch([location, examType, batchId, universityId], async ([location, examType, batchId, universityId]) => {
-        // clean
-        majorPlanId.value = ''
-        majors.value = []
 
-        if (!location || !examType || !batchId || !universityId) return
-        const res = await getPaperMajors({location, examType, batchId, universityId})
-        majors.value = res.data
-        if (res.data.length) majorPlanId.value = res.data[0].id
+    watch([batchId, universityId], async ([batchId, universityId]) => {
+        majorGroup.value = ''
+
+        if (!batchId || !universityId) return
+        const res = await getPaperMajors({buildType, batchId, universityId})
+        _allMajors.value = res.data
+
+        // 没有数据时,说明已经满足了条件
+        if (!majorGroups.value.length) await triggerExactEvent({buildType, batchId, universityId})
+        else if (majorGroups.value.length == 1) majorGroup.value = majorGroups.value[0]
     })
-    watch(universityId, async (universityId) => {
-        // clean
-        subjects.value = []
-        subjectId.value = ''
-
-        if (!universityId) return
-        const res = await getPaperSubjects({universityId})
-        subjects.value = res.data
-        if (res.data.length) subjectId.value = res.data[0].subjectId
+
+    watch([batchId, universityId, majorGroup], async ([batchId, universityId, majorGroup]) => {
+        majorPlanId.value = ''
+
+        if (!batchId || !universityId || !majorGroup) return
+        if (!majors.value.length) await triggerExactEvent({buildType, batchId, universityId, majorGroup})
+        else if (majors.value.length == 1) majorPlanId.value = majors.value[0].id
     })
-    watch([majorPlanId, subjectId], async ([majorPlanId, subjectId]) => {
-        // clean
-        knowledges.value = []
-        knowledgeNode.value = null // 单选的情况
-        knowledgeCheckNodes.value = [] // 多选的情况
-
-        if (!subjectId || !majorPlanId) return
-        // 获取知识点数据
-        const res = await getPaperKnowledges({subjectId, majorPlanId})
-        knowledges.value = res.data
+
+    watch(majorPlanId, async (majorPlanId) => {
+        if (!majorPlanId) return
+
+        // 最细的情况,选中了专业
+        const args = {
+            buildType,
+            batchId: toValue(batchId),
+            universityId: toValue(universityId),
+            majorGroup: toValue(majorGroup),
+            majorPlanId
+        }
+        await triggerExactEvent(args)
     })
 
+    const payload = {buildType, batchId, batchList,
+        universityId, universities,
+        majorGroup, majorGroups,
+        majorPlanId, majors,
+        conditionArgs, conditionData,
+        onConditionReady: exactEvent.on}
+    provideLocal(key, payload)
     return payload
 }
 

+ 42 - 50
back-ui/src/views/dz/papers/hooks/usePaperFullCondition.js

@@ -1,67 +1,59 @@
 import {createEventHook, injectLocal, provideLocal} from "@vueuse/core";
-import {getPaperBatches, getPaperKnowledges, getPaperSubjects} from "@/api/dz/papers.js";
-import {watch} from "vue";
+import {useProvidePaperBatchCondition} from "@/views/dz/papers/hooks/usePaperBatchCondition.js";
+import {getPaperExamTypes, getPaperSubjects} from "@/api/dz/papers.js";
 
 const key = Symbol('PaperFullCondition')
+export const useProvidePaperFullCondition = function (type) {
+    const {buildType, batchId, batchList} = useProvidePaperBatchCondition(type)
 
-export const useProvidePaperFullCondition = function () {
-    const batchId = ref('')
-    const batchList = ref([])
+    const examType = ref('')
+    const examTypes = ref([])
 
-    const subjects = ref([])
     const subjectId = ref('')
-    const knowledges = ref([])
-    const knowledgeNode = ref(null) // 单选节点
-    const knowledgeCheckNodes = ref([]) // 多选的节点
-    const knowledgeIds = computed(() => knowledgeCheckNodes.value.map(k => k.id))
-    const knowledgeId = computed(() => knowledgeNode.value?.id || '')
-    const knowledgeRemoveEvent = createEventHook()
-    const removeKnowledge = async (k) => {
-        const nodes = knowledgeCheckNodes.value
-        const idx = nodes.indexOf(k)
-        if (idx > -1) {
-            nodes.splice(idx, 1)
-            await knowledgeRemoveEvent.trigger(k)
-        }
-    }
+    const subjectList = ref([])
 
-    const paperArgs = computed(() => ({
-        batchId: toValue(batchId),
-        batchName: batchList.value.find(b => b.batchId == batchId.value)?.name,
-        subjectId: toValue(subjectId),
-        subjectName: subjects.value.find(s => s.subjectId == subjectId.value)?.subjectName
+    const conditionArgs = computed(() => ({
+        buildType: toValue(buildType),
+        examType: toValue(examType),
+        subjectId: toValue(subjectId)
     }))
-    const payload = {
-        batchId, batchList, subjectId, subjects,
-        knowledges, knowledgeId, knowledgeNode, knowledgeCheckNodes, knowledgeIds,
-        removeKnowledge, onKnowledgeRemove: knowledgeRemoveEvent.on,
-        paperArgs
-    }
-    provideLocal(key, payload)
+    const conditionData = computed(() => ({
+        examTypes: toValue(examTypes),
+        subjectList: toValue(subjectList)
+    }))
+    const readyEvent = createEventHook()
 
-    onMounted(async () => {
-        const res = await getPaperSubjects()
-        subjects.value = res.data
-        // 给一个默认值
-        if (res.data.length) subjectId.value = res.data[0].subjectId
-    })
-    onMounted(async () => {
-        const res = await getPaperBatches()
-        batchList.value = res.data
+    watch(batchId, async (batchId) => {
+        examType.value = ''
+        examTypes.value = []
+
+        const res = await getPaperExamTypes({buildType, batchId})
+        examTypes.value = res.data
     })
-    watch(subjectId, async (subjectId) => {
-        // 先清空以前的知识点
-        knowledges.value = []
-        knowledgeNode.value = null // 单选的情况
-        knowledgeCheckNodes.value = [] // 多选的情况
+    watch([batchId, examType], async ([batchId, examType]) => {
+        subjectId.value = ''
+        subjectList.value = []
 
-        // 获取知识点数据
-        const res = await getPaperKnowledges({subjectId})
-        knowledges.value = res.data
+        if(!batchId || !examType) return
+        const res = await getPaperSubjects({buildType, batchId, examType})
+        subjectList.value = res.data
     })
+    watch([batchId, examType, subjectId], async ([batchId, examType, subjectId]) => {
+        if (!subjectId) return
+        const payload = {buildType, batchId, examType, subjectId}
+        await readyEvent.trigger(payload)
+    })
+
+    const payload = {buildType, batchId, batchList,
+        examType, examTypes,
+        subjectId, subjectList,
+        conditionArgs, conditionData,
+        onConditionReady: readyEvent.on}
+    provideLocal(key, payload)
     return payload
+
 }
 
-export const useInjectPaperFullCondition = function () {
+export const useInjectPaperFullCondition = function (){
     return injectLocal(key)
 }

+ 0 - 0
back-ui/src/views/dz/papers/components/conditions/usePaperKnowledgeCondition.js → back-ui/src/views/dz/papers/hooks/usePaperKnowledgeCondition.js


+ 14 - 16
back-ui/src/views/dz/papers/hooks/usePaperQuestionCondition.js

@@ -1,16 +1,14 @@
 import {useInjectPaperExactCondition} from "@/views/dz/papers/hooks/usePaperExactCondition.js";
 import {useInjectPaperFullCondition} from "@/views/dz/papers/hooks/usePaperFullCondition.js";
-import {injectLocal, provideLocal} from "@vueuse/core";
-import {useInjectLoading} from "@/views/hooks/useGlobalLoading.js";
+import {useInjectPaperKnowledgeCondition} from "@/views/dz/papers/hooks/usePaperKnowledgeCondition.js";
+import {useInjectGlobalLoading} from "@/views/hooks/useGlobalLoading.js";
 import {getPaperQuestions, getPaperQuestionTypes} from "@/api/dz/papers.js";
+import {injectLocal, provideLocal} from "@vueuse/core";
 import {ElMessage} from "element-plus";
 
 const key = Symbol('PaperQuestionCondition')
 
-export const useProvidePaperQuestionCondition = function (exactMode, allowMultiple, disableQuestionQuery = false) {
-    // exactMode: exact condition & full condition
-    // allowMultiple: multiple knowledge selection
-
+export const useProvidePaperQuestionCondition = function (exactMode, handMode) {
     const keyword = ref('')
     const qtpye = ref('') // 历史遗留拼写错误
     const qTypes = ref([])
@@ -20,16 +18,17 @@ export const useProvidePaperQuestionCondition = function (exactMode, allowMultip
     const total = ref(0)
     const questionList = ref([])
 
-    const {
-        subjectId, subjects, knowledgeId, knowledgeIds
-    } = exactMode ? useInjectPaperExactCondition() : useInjectPaperFullCondition()
-    const loading = useInjectLoading()
+    const {conditionArgs, conditionData} = exactMode ? useInjectPaperExactCondition() : useInjectPaperFullCondition()
+    const {knowledgeId, knowledgeIds} = useInjectPaperKnowledgeCondition()
+    const loading = useInjectGlobalLoading()
 
     // question cart
     const cart = ref([])
     const currentSubject = computed(() => {
-        const demoId = cart.value[0]?.subjectId
-        return subjects.value.find(s => s.subjectId == demoId)
+        if (!conditionArgs.value.subjectId) return null
+        if (!cart.value.length) return null
+        const demoId = cart.value[0].subjectId
+        return conditionData.value.subjectList.find(s => s.subjectId == demoId)
     })
     const groupedQuestions = computed(() => {
         const results = {}
@@ -61,12 +60,12 @@ export const useProvidePaperQuestionCondition = function (exactMode, allowMultip
     const clearCart = () => cart.value = []
 
     // hooks
-    watch([subjectId, knowledgeId, () => knowledgeIds.value.toString()], async ([subjectId, knowledgeId, knowledgeIds]) => {
+    watch([() => conditionArgs.value.subjectId, knowledgeId, () => knowledgeIds.value.toString()], async ([subjectId, knowledgeId, knowledgeIds]) => {
         // clean
         qtpye.value = ''
         qTypes.value = []
 
-        if (!subjectId) return
+        if (!subjectId && conditionData.value.subjectList?.length) return
         if (!knowledgeId && !knowledgeIds) return
         const query = {subjectId, knowledgeIds: knowledgeId || knowledgeIds}
         const res = await getPaperQuestionTypes(query)
@@ -82,7 +81,7 @@ export const useProvidePaperQuestionCondition = function (exactMode, allowMultip
         knowledges: knowledgeIds.value.toString()
     }))
     const getQuestionList = async function () {
-        if (disableQuestionQuery) return // 智能组卷时不需要查询
+        if (!handMode) return // 智能组卷时不需要查询
         loading.value = true
         try {
             const res = await getPaperQuestions(questionQuery.value)
@@ -109,7 +108,6 @@ export const useProvidePaperQuestionCondition = function (exactMode, allowMultip
     provideLocal(key, payload)
     return payload
 }
-
 export const useInjectPaperQuestionCondition = function () {
     return injectLocal(key)
 }

+ 3 - 3
back-ui/src/views/dz/papers/index.vue

@@ -21,7 +21,7 @@ const tabs = ref([{
     name: 'ExactIntelligent',
     label: '定向智能',
     page: markRaw(PaperExactIntelligent) ,
-    visited: false
+    visited: true
 }, {
     name: 'FullIntelligent',
     label: '全量智能',
@@ -31,14 +31,14 @@ const tabs = ref([{
     name: 'ExactHand',
     label: '定向手动',
     page: markRaw(PaperExactHand),
-    visited: true
+    visited: false
 }, {
     name: 'FullHand',
     label: '全量手动',
     page: markRaw(PaperFullHand),
     visited: false
 }])
-const currentTab = ref('ExactHand')
+const currentTab = ref('ExactIntelligent')
 
 watch(currentTab, tabName => {
     // 通过visited=true 延迟渲染