Parcourir la source

paper records - ui cc

abpcoder il y a 2 semaines
Parent
commit
6b6015758d

+ 467 - 8
back-ui/src/api/dz/papers.js

@@ -187,6 +187,394 @@ export function buildPaperFullHand(data) {
 
 export function getBuiltPaper(params) {
     // 与上面的4个build接口参数一样,只不过走1个接口,返回试卷详情
+    // // TODO: remove test code
+    // return Promise.resolve({
+    //     code: 200,
+    //     data: {
+    //         paperId: 1,
+    //         paperName: '试卷名称',
+    //         questions: [
+    //             {
+    //                 "createBy": null,
+    //                 "createTime": "2025-09-15 03:12:52",
+    //                 "updateBy": null,
+    //                 "updateTime": null,
+    //                 "remark": null,
+    //                 "id": 1,
+    //                 "title": "获取信息最常用、最快捷、最方便、最可靠的方法就是从因特网上检索信息",
+    //                 "optionA": "对",
+    //                 "optionB": "错",
+    //                 "optionC": null,
+    //                 "optionD": null,
+    //                 "optionE": null,
+    //                 "optionF": null,
+    //                 "optionG": null,
+    //                 "answer1": "B",
+    //                 "answer2": "B",
+    //                 "qtpye": "判断题",
+    //                 "subjectId": 10,
+    //                 "paperId": null,
+    //                 "knowledgeId": 2533,
+    //                 "diff": 0,
+    //                 "similarity": 0,
+    //                 "parse": "",
+    //                 "knowId": null,
+    //                 "gradeId": -1,
+    //                 "knowledges": null,
+    //                 "area": null,
+    //                 "year": 2025,
+    //                 "paperTpye": null,
+    //                 "source": "聚恒普高",
+    //                 "fromSite": "",
+    //                 "isSub": null,
+    //                 "isNormal": null,
+    //                 "isKonw": null,
+    //                 "tiid": "10026648",
+    //                 "md5": null,
+    //                 "isunique": null,
+    //                 "md52": null,
+    //                 "score": 0,
+    //                 "options": null,
+    //                 "number": null,
+    //                 "paperTypeTitle": null,
+    //                 "options0": null,
+    //                 "title0": "",
+    //                 "title1": null,
+    //                 "parse0": null,
+    //                 "answer0": null,
+    //                 "isUpdate": 0,
+    //                 "isSubType": "0",
+    //                 "typeId": null,
+    //                 "userId": null,
+    //                 "collect": false
+    //             },
+    //             {
+    //                 "createBy": null,
+    //                 "createTime": "2025-09-14 21:06:24",
+    //                 "updateBy": null,
+    //                 "updateTime": null,
+    //                 "remark": null,
+    //                 "id": 2,
+    //                 "title": "( ) 抗损性强、可折叠、可局部穿孔、可局部切割。",
+    //                 "optionA": "二维条码",
+    //                 "optionB": "磁卡",
+    //                 "optionC": "IC卡",
+    //                 "optionD": "光卡",
+    //                 "optionE": null,
+    //                 "optionF": null,
+    //                 "optionG": null,
+    //                 "answer1": "A",
+    //                 "answer2": "A",
+    //                 "qtpye": "单选题",
+    //                 "subjectId": 12,
+    //                 "paperId": null,
+    //                 "knowledgeId": 2278,
+    //                 "diff": 0,
+    //                 "similarity": 0,
+    //                 "parse": "本题主要考查信息编码。磁卡、IC卡、光卡均不可折叠,抗损性差。二维条码抗损性强、可折叠、可局部穿孔、可局部切割,故本题选A选项。",
+    //                 "knowId": null,
+    //                 "gradeId": -1,
+    //                 "knowledges": null,
+    //                 "area": null,
+    //                 "year": 2025,
+    //                 "paperTpye": null,
+    //                 "source": "聚恒普高",
+    //                 "fromSite": "",
+    //                 "isSub": null,
+    //                 "isNormal": null,
+    //                 "isKonw": null,
+    //                 "tiid": "10036700",
+    //                 "md5": null,
+    //                 "isunique": null,
+    //                 "md52": null,
+    //                 "score": 1,
+    //                 "options": null,
+    //                 "number": null,
+    //                 "paperTypeTitle": null,
+    //                 "options0": null,
+    //                 "title0": "",
+    //                 "title1": null,
+    //                 "parse0": null,
+    //                 "answer0": null,
+    //                 "isUpdate": 0,
+    //                 "isSubType": "0",
+    //                 "typeId": null,
+    //                 "userId": null,
+    //                 "collect": false
+    //             },
+    //             {
+    //                 "createBy": null,
+    //                 "createTime": "2025-09-14 21:27:53",
+    //                 "updateBy": null,
+    //                 "updateTime": null,
+    //                 "remark": null,
+    //                 "id": 3,
+    //                 "title": "字号中阿拉伯字号越大,表示字符越____;中文字号越小,表示字符越____。",
+    //                 "optionA": "大、小",
+    //                 "optionB": "小、大",
+    //                 "optionC": "不变",
+    //                 "optionD": "大、大",
+    //                 "optionE": null,
+    //                 "optionF": null,
+    //                 "optionG": null,
+    //                 "answer1": "D",
+    //                 "answer2": "D",
+    //                 "qtpye": "单选题",
+    //                 "subjectId": 12,
+    //                 "paperId": null,
+    //                 "knowledgeId": 2297,
+    //                 "diff": 0,
+    //                 "similarity": 0,
+    //                 "parse": "字号中阿拉伯字号越大,表示字符越大中文字号越小,表示字符越大。",
+    //                 "knowId": null,
+    //                 "gradeId": -1,
+    //                 "knowledges": null,
+    //                 "area": null,
+    //                 "year": 2025,
+    //                 "paperTpye": null,
+    //                 "source": "聚恒普高",
+    //                 "fromSite": "",
+    //                 "isSub": null,
+    //                 "isNormal": null,
+    //                 "isKonw": null,
+    //                 "tiid": "10048401",
+    //                 "md5": null,
+    //                 "isunique": null,
+    //                 "md52": null,
+    //                 "score": 1,
+    //                 "options": null,
+    //                 "number": null,
+    //                 "paperTypeTitle": null,
+    //                 "options0": null,
+    //                 "title0": "",
+    //                 "title1": null,
+    //                 "parse0": null,
+    //                 "answer0": null,
+    //                 "isUpdate": 0,
+    //                 "isSubType": "0",
+    //                 "typeId": null,
+    //                 "userId": null,
+    //                 "collect": false
+    //             },
+    //             {
+    //                 "createBy": null,
+    //                 "createTime": "2025-09-14 21:18:58",
+    //                 "updateBy": null,
+    //                 "updateTime": null,
+    //                 "remark": null,
+    //                 "id": 4,
+    //                 "title": "打开Excel后会自动创建一个名为Book1的文件,该文件扩展名为()",
+    //                 "optionA": "PPT",
+    //                 "optionB": "DBF",
+    //                 "optionC": "XLS",
+    //                 "optionD": "DOC",
+    //                 "optionE": null,
+    //                 "optionF": null,
+    //                 "optionG": null,
+    //                 "answer1": "C",
+    //                 "answer2": "C",
+    //                 "qtpye": "单选题",
+    //                 "subjectId": 12,
+    //                 "paperId": null,
+    //                 "knowledgeId": 2282,
+    //                 "diff": 0,
+    //                 "similarity": 0,
+    //                 "parse": "Excel电子表格文件的扩展名是xls。",
+    //                 "knowId": null,
+    //                 "gradeId": -1,
+    //                 "knowledges": null,
+    //                 "area": null,
+    //                 "year": 2025,
+    //                 "paperTpye": null,
+    //                 "source": "聚恒普高",
+    //                 "fromSite": "",
+    //                 "isSub": null,
+    //                 "isNormal": null,
+    //                 "isKonw": null,
+    //                 "tiid": "10053344",
+    //                 "md5": null,
+    //                 "isunique": null,
+    //                 "md52": null,
+    //                 "score": 1,
+    //                 "options": null,
+    //                 "number": null,
+    //                 "paperTypeTitle": null,
+    //                 "options0": null,
+    //                 "title0": "",
+    //                 "title1": null,
+    //                 "parse0": null,
+    //                 "answer0": null,
+    //                 "isUpdate": 0,
+    //                 "isSubType": "0",
+    //                 "typeId": null,
+    //                 "userId": null,
+    //                 "collect": false
+    //             },
+    //             {
+    //                 "createBy": null,
+    //                 "createTime": "2025-09-15 04:38:31",
+    //                 "updateBy": null,
+    //                 "updateTime": null,
+    //                 "remark": null,
+    //                 "id": 5,
+    //                 "title": "力使物体产生转动的效果与矩心的位置()。\n ",
+    //                 "optionA": "有关",
+    //                 "optionB": "无关",
+    //                 "optionC": "有时有关",
+    //                 "optionD": "说不清",
+    //                 "optionE": null,
+    //                 "optionF": null,
+    //                 "optionG": null,
+    //                 "answer1": "A",
+    //                 "answer2": "A",
+    //                 "qtpye": "单选题",
+    //                 "subjectId": 22,
+    //                 "paperId": null,
+    //                 "knowledgeId": 2487,
+    //                 "diff": 0,
+    //                 "similarity": 0,
+    //                 "parse": "",
+    //                 "knowId": null,
+    //                 "gradeId": -1,
+    //                 "knowledges": null,
+    //                 "area": null,
+    //                 "year": 2025,
+    //                 "paperTpye": null,
+    //                 "source": "聚恒普高",
+    //                 "fromSite": "",
+    //                 "isSub": null,
+    //                 "isNormal": null,
+    //                 "isKonw": null,
+    //                 "tiid": "10072901",
+    //                 "md5": null,
+    //                 "isunique": null,
+    //                 "md52": null,
+    //                 "score": 1,
+    //                 "options": null,
+    //                 "number": null,
+    //                 "paperTypeTitle": null,
+    //                 "options0": null,
+    //                 "title0": "",
+    //                 "title1": null,
+    //                 "parse0": null,
+    //                 "answer0": null,
+    //                 "isUpdate": 0,
+    //                 "isSubType": "0",
+    //                 "typeId": null,
+    //                 "userId": null,
+    //                 "collect": false
+    //             },
+    //             {
+    //                 "createBy": null,
+    //                 "createTime": "2025-09-15 02:11:16",
+    //                 "updateBy": null,
+    //                 "updateTime": null,
+    //                 "remark": null,
+    //                 "id": 6,
+    //                 "title": "小明使用Excel统计自己一年来的收入情况,在单元格B3到B14中,依次存放了从一月到十二月的收入情况,想在单元格B15中求出一年的平均月收入,应选用公式()",
+    //                 "optionA": "AVERAGE(B3:B14)",
+    //                 "optionB": "SUM(B3:B14)",
+    //                 "optionC": "AVERAGE(B1:B14)",
+    //                 "optionD": "AVERAGE(B3:B15)",
+    //                 "optionE": null,
+    //                 "optionF": null,
+    //                 "optionG": null,
+    //                 "answer1": "A",
+    //                 "answer2": "A",
+    //                 "qtpye": "单选题",
+    //                 "subjectId": 12,
+    //                 "paperId": null,
+    //                 "knowledgeId": 2264,
+    //                 "diff": 0,
+    //                 "similarity": 0,
+    //                 "parse": "想在单元格B15中求出一年的平均月收入,可使用求平均值函数AVERAGE(),求值区域是B3:B14,故应选用公式AVERAGE(B3:B14)。",
+    //                 "knowId": null,
+    //                 "gradeId": -1,
+    //                 "knowledges": null,
+    //                 "area": null,
+    //                 "year": 2025,
+    //                 "paperTpye": null,
+    //                 "source": "聚恒普高",
+    //                 "fromSite": "",
+    //                 "isSub": null,
+    //                 "isNormal": null,
+    //                 "isKonw": null,
+    //                 "tiid": "10075149",
+    //                 "md5": null,
+    //                 "isunique": null,
+    //                 "md52": null,
+    //                 "score": 0,
+    //                 "options": null,
+    //                 "number": null,
+    //                 "paperTypeTitle": null,
+    //                 "options0": null,
+    //                 "title0": "",
+    //                 "title1": null,
+    //                 "parse0": null,
+    //                 "answer0": null,
+    //                 "isUpdate": 0,
+    //                 "isSubType": "0",
+    //                 "typeId": null,
+    //                 "userId": null,
+    //                 "collect": false
+    //             },
+    //             {
+    //                 "createBy": null,
+    //                 "createTime": "2025-09-14 21:06:24",
+    //                 "updateBy": null,
+    //                 "updateTime": null,
+    //                 "remark": null,
+    //                 "id": 7,
+    //                 "title": "当前,在计算机应用方面已进入以()为特征的时代。",
+    //                 "optionA": "并行处理技术",
+    //                 "optionB": "分布式系统",
+    //                 "optionC": "微型计算机",
+    //                 "optionD": "计算机网络",
+    //                 "optionE": null,
+    //                 "optionF": null,
+    //                 "optionG": null,
+    //                 "answer1": "D",
+    //                 "answer2": "D",
+    //                 "qtpye": "单选题",
+    //                 "subjectId": 12,
+    //                 "paperId": null,
+    //                 "knowledgeId": 2278,
+    //                 "diff": 0,
+    //                 "similarity": 0,
+    //                 "parse": "当前,在计算机应用方面已进入以计算机网络为特征的时代。",
+    //                 "knowId": null,
+    //                 "gradeId": -1,
+    //                 "knowledges": null,
+    //                 "area": null,
+    //                 "year": 2025,
+    //                 "paperTpye": null,
+    //                 "source": "聚恒普高",
+    //                 "fromSite": "",
+    //                 "isSub": null,
+    //                 "isNormal": null,
+    //                 "isKonw": null,
+    //                 "tiid": "10117673",
+    //                 "md5": null,
+    //                 "isunique": null,
+    //                 "md52": null,
+    //                 "score": 1,
+    //                 "options": null,
+    //                 "number": null,
+    //                 "paperTypeTitle": null,
+    //                 "options0": null,
+    //                 "title0": "",
+    //                 "title1": null,
+    //                 "parse0": null,
+    //                 "answer0": null,
+    //                 "isUpdate": 0,
+    //                 "isSubType": "0",
+    //                 "typeId": null,
+    //                 "userId": null,
+    //                 "collect": false
+    //             }
+    //         ]
+    //     }
+    // })
     return request({
         url: '/learn/teaching/build/getBuiltPaper',
         method: 'get',
@@ -196,14 +584,27 @@ export function getBuiltPaper(params) {
 
 export function getPaperClassRecords(params) {
     // {id: 1, buildType: '定向智能', classId: 1, className: '2501班', batchName: '第一批', total: 50, unexact: 10, exact: 40, unsend: 10, send: 20, unfinish: 5, finish: 15}
-    // TODO: remove test code
-    return Promise.resolve({
-        code: 200,
-        total: 1,
-        rows: [
-            {id: 1, buildType: '定向智能', classId: 1, className: '2501班', batchName: '第一批', total: 50, unexact: 10, exact: 40, unsend: 10, send: 20, unfinish: 5, finish: 15}
-        ]
-    })
+    // // TODO: remove test code
+    // return Promise.resolve({
+    //     code: 200,
+    //     total: 1,
+    //     rows: [
+    //         {
+    //             buildType: 'ExactIntelligent',
+    //             classId: 1,
+    //             className: '2501班',
+    //             batchId: 1,
+    //             batchName: '第一批',
+    //             total: 50,
+    //             unexact: 10,
+    //             exact: 40,
+    //             unsend: 10,
+    //             send: 20,
+    //             unfinish: 5,
+    //             finish: 15
+    //         }
+    //     ]
+    // })
     return request({
         url: '/learn/teaching/getPaperClassRecords',
         method: 'get',
@@ -212,6 +613,43 @@ export function getPaperClassRecords(params) {
 }
 
 export function getPaperStudentRecords(params) {
+    // // TODO: remove test code
+    // return Promise.resolve({
+    //     code: 200,
+    //     data: [{
+    //         studentId: 1,
+    //         studentName: '张三',
+    //         classId: 1,
+    //         className: '2501班',
+    //         mobile: '13933445566',
+    //         batchId: 1,
+    //         batchName: '第一批',
+    //         paperId: 1,
+    //         paperName: '试卷一',
+    //         subjectId: 1,
+    //         subjectName: '科目说明',
+    //         state: '组卷已完成',
+    //         total: 100,
+    //         score: 99,
+    //         rate: null,
+    //     }, {
+    //         studentId: 1,
+    //         studentName: '张三',
+    //         classId: 1,
+    //         className: '2501班',
+    //         mobile: '13933445566',
+    //         batchId: 1,
+    //         batchName: '第一批',
+    //         paperId: 1,
+    //         paperName: '试卷一',
+    //         subjectId: 1,
+    //         subjectName: '科目说明',
+    //         state: '组卷已完成',
+    //         total: 100,
+    //         score: 99,
+    //         rate: 99,
+    //     }]
+    // })
     return request({
         url: '/learn/teaching/getPaperStudentRecords',
         method: 'get',
@@ -220,9 +658,30 @@ export function getPaperStudentRecords(params) {
 }
 
 export function getPaperStudentDetail(params) {
+    // // TODO: remove test code
+    // return Promise.resolve({
+    //     code: 200,
+    //     data: [
+    //         {
+    //             knowledgeId: 1,
+    //             knowledgeName: '知识点1',
+    //             num: 5,
+    //             correct: 4,
+    //             rate: 80
+    //         }
+    //     ]
+    // })
     return request({
         url: '/learn/teaching/getPaperStudentDetail',
         method: 'get',
         params
     })
+}
+
+export function sendUnfinishAlarm(data) {
+    return request({
+        url: '/learn/teaching/postUnfinishAlarm',
+        method: 'post',
+        data
+    })
 }

+ 10 - 0
back-ui/src/utils/index.js

@@ -392,4 +392,14 @@ export function sleep(delay) {
   return new Promise((resolve) => {
     setTimeout(() => resolve(), delay)
   })
+}
+
+export function listToMap(list, keySelector, valueSelector = item => item) {
+  const result = {}
+  list.forEach(i => {
+    const key = keySelector(i)
+    const val = valueSelector(i)
+    result[key] = val
+  })
+  return result
 }

+ 51 - 0
back-ui/src/utils/paper-helper.js

@@ -0,0 +1,51 @@
+
+const chnNumChar = ["零", "一", "二", "三", "四", "五", "六", "七", "八", "九"];
+const chnUnitSection = ["", "万", "亿", "万亿", "亿亿"];
+const chnUnitChar = ["", "十", "百", "千"];
+
+export const sectionToChinese = function (section) {
+    let strIns = "", chnStr = "";
+    let unitPos = 0;
+    let zero = true;
+    while (section > 0) {
+        const v = section % 10;
+        if (v === 0) {
+            if (!zero) {
+                zero = true;
+                chnStr = chnNumChar[v] + chnStr;
+            }
+        } else {
+            zero = false;
+            strIns = chnNumChar[v];
+            strIns += chnUnitChar[unitPos];
+            chnStr = strIns + chnStr;
+        }
+        unitPos++;
+        section = Math.floor(section / 10);
+    }
+    return chnStr;
+}
+export const numberToChinese = function (num) {
+    let unitPos = 0;
+    let strIns = "", chnStr = "";
+    let needZero = false;
+
+    if (num === 0) {
+        return chnNumChar[0];
+    }
+
+    while (num > 0) {
+        const section = num % 10000;
+        if (needZero) {
+            chnStr = chnNumChar[0] + chnStr;
+        }
+        strIns = sectionToChinese(section);
+        strIns += section !== 0 ? chnUnitSection[unitPos] : chnUnitSection[0];
+        chnStr = strIns + chnStr;
+        needZero = section < 1000 && section > 0;
+        num = Math.floor(num / 10000);
+        unitPos++;
+    }
+
+    return chnStr;
+}

+ 5 - 4
back-ui/src/views/dz/papers/components/list-exact-hand.vue

@@ -37,7 +37,7 @@
     </el-form>
     <Table :data="list" :columns="columns" :actions="actions" @get-list="getList" @action="handleAction" />
     <el-drawer v-model="drawer" title="班级详情" size="1000px">
-        <class-detail v-if="drawer" :state="queryParams.state" exact-mode />
+        <class-detail v-if="drawer" :data="drawerObj" exact-mode />
     </el-drawer>
 </template>
 
@@ -49,7 +49,7 @@ import Table from "@/components/Table/index.vue";
 import ClassDetail from "@/views/dz/papers/components/plugs/class-detail.vue";
 
 const columns = [
-    {label: '组卷类型', prop: 'buildType'},
+    {label: '组卷类型', prop: 'buildTypeName'},
     {label: '班级', prop: 'className'},
     {label: '批次', prop: 'batchName'},
     {label: '班级人数', prop: 'total'},
@@ -60,6 +60,7 @@ const actions = [
 ]
 
 const drawer = ref(false)
+const drawerObj = ref(null)
 const type = consts.enums.buildType.ExactHand
 const {
     batchList,
@@ -76,8 +77,8 @@ const {
 } = useProvidePaperExactCondition(type)
 const classId = ref('')
 const queryParams = computed(() => ({
-    ...conditionArgs.value,
-    classId
+    ...toValue(conditionArgs),
+    classId: toValue(classId)
 }))
 const {rules, handleQuery, resetQuery, list, total, getList, classList} = useProvidePaperList(queryParams)
 

+ 5 - 3
back-ui/src/views/dz/papers/components/list-exact-intelligent.vue

@@ -17,7 +17,7 @@
     </el-form>
     <Table :data="list" :columns="columns" :actions="actions" @get-list="getList" @action="handleAction" />
     <el-drawer v-model="drawer" title="班级详情" size="1000px">
-        <class-detail v-if="drawer" :state="queryParams.state" exact-mode />
+        <class-detail v-if="drawer" :data="drawerObj" exact-mode />
     </el-drawer>
 </template>
 
@@ -30,7 +30,7 @@ import Table from "@/components/Table/index.vue"
 import ClassDetail from "@/views/dz/papers/components/plugs/class-detail.vue";
 
 const columns = [
-    {label: '组卷类型', prop: 'buildType'},
+    {label: '组卷类型', prop: 'buildTypeName'},
     {label: '班级', prop: 'className'},
     {label: '批次', prop: 'batchName'},
     {label: '班级人数', prop: 'total'},
@@ -41,16 +41,18 @@ const actions = [
 ]
 
 const drawer = ref(false)
+const drawerObj = ref(null)
 const type = consts.enums.buildType.ExactIntelligent
 const {batchList, batchId} = useProvidePaperBatchCondition(type)
 const classId = ref('')
-const queryParams = computed(() => ({batchId: toValue(batchId), classId: toValue(classId)}))
+const queryParams = computed(() => ({buildType: type, batchId: toValue(batchId), classId: toValue(classId)}))
 const {rules, handleQuery, resetQuery, list, total, getList, classList} = useProvidePaperList(queryParams)
 
 const handleAction = function (action, row) {
     switch (action.key) {
         case "detail":
             drawer.value = true
+            drawerObj.value = row
             break;
         default:
             throw new Error(`Action key '${action.key}' not support.`)

+ 5 - 4
back-ui/src/views/dz/papers/components/list-full-hand.vue

@@ -29,7 +29,7 @@
     </el-form>
     <Table :data="list" :columns="columns" :actions="actions" @get-list="getList" @action="handleAction"/>
     <el-drawer v-model="drawer" title="班级详情" size="1000px">
-        <class-detail v-if="drawer" :state="queryParams.state" exact-mode/>
+        <class-detail v-if="drawer" :data="drawerObj" exact-mode/>
     </el-drawer>
 </template>
 
@@ -41,7 +41,7 @@ import Table from "@/components/Table/index.vue";
 import ClassDetail from "@/views/dz/papers/components/plugs/class-detail.vue";
 
 const columns = [
-    {label: '组卷类型', prop: 'buildType'},
+    {label: '组卷类型', prop: 'buildTypeName'},
     {label: '班级', prop: 'className'},
     {label: '批次', prop: 'batchName'},
     {label: '班级人数', prop: 'total'},
@@ -52,6 +52,7 @@ const actions = [
 ]
 
 const drawer = ref(false)
+const drawerObj = ref(null)
 const type = consts.enums.buildType.FullHand
 const {
     batchList,
@@ -64,8 +65,8 @@ const {
 } = useProvidePaperFullCondition(type)
 const classId = ref('')
 const queryParams = computed(() => ({
-    ...conditionArgs.value,
-    classId
+    ...toValue(conditionArgs),
+    classId: toValue(classId)
 }))
 const {rules, handleQuery, resetQuery, list, total, getList, classList} = useProvidePaperList(queryParams)
 

+ 5 - 4
back-ui/src/views/dz/papers/components/list-full-intelligent.vue

@@ -29,7 +29,7 @@
     </el-form>
     <Table :data="list" :columns="columns" :actions="actions" @get-list="getList" @action="handleAction"/>
     <el-drawer v-model="drawer" title="班级详情" size="1000px">
-        <class-detail v-if="drawer" :state="queryParams.state" exact-mode/>
+        <class-detail v-if="drawer" :data="drawerObj" exact-mode/>
     </el-drawer>
 </template>
 
@@ -41,7 +41,7 @@ import Table from '@/components/Table/index.vue';
 import ClassDetail from "@/views/dz/papers/components/plugs/class-detail.vue";
 
 const columns = [
-    {label: '组卷类型', prop: 'buildType'},
+    {label: '组卷类型', prop: 'buildTypeName'},
     {label: '班级', prop: 'className'},
     {label: '批次', prop: 'batchName'},
     {label: '班级人数', prop: 'total'},
@@ -52,6 +52,7 @@ const actions = [
 ]
 
 const drawer = ref(false)
+const drawerObj = ref(null)
 const type = consts.enums.buildType.FullIntelligent
 const {
     batchList,
@@ -64,8 +65,8 @@ const {
 } = useProvidePaperFullCondition(type)
 const classId = ref('')
 const queryParams = computed(() => ({
-    ...conditionArgs.value,
-    classId
+    ...toValue(conditionArgs),
+    classId: toValue(classId)
 }))
 const {rules, handleQuery, resetQuery, list, total, getList, classList} = useProvidePaperList(queryParams)
 

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

@@ -34,7 +34,7 @@
         </el-col>
     </el-row>
     <el-divider/>
-    <el-row :gutter="20">
+    <el-row v-if="!hasBuiltPaper" :gutter="20">
         <el-col :span="6">
             <knowledge-tree/>
         </el-col>
@@ -42,6 +42,7 @@
             <question-hand exact-mode @submit="handleSubmit"/>
         </el-col>
     </el-row>
+    <built-paper ref="built" @send="handleSubmit" />
 </template>
 
 <script setup name="PaperExactHand">
@@ -56,6 +57,7 @@ import QuestionHand from "@/views/dz/papers/components/plugs/question-hand.vue";
 import {usePaperStorage} from "@/views/dz/papers/hooks/usePaperStorage.js";
 import {ElMessage} from "element-plus";
 import router from "@/router/index.js";
+import BuiltPaper from "@/views/dz/papers/components/plugs/built-paper.vue";
 
 const type = consts.enums.buildType.ExactHand
 const {
@@ -64,10 +66,12 @@ const {
     universityId, universities,
     majorGroup, majorGroups,
     majors, majorPlanId,
-    onConditionReady
+    conditionArgs, onConditionReady
 } = useProvidePaperExactCondition(type)
 const {selectedClasses, classList, loadClassStatistic} = useProvidePaperClassStatisticCondition()
 const {knowledgeNode, knowledgeCheckNodes, loadKnowledge} = useProvidePaperKnowledgeCondition()
+const built = ref(null)
+const hasBuiltPaper = computed(() => built.value?.hasPaper)
 
 const handleSubmit = async (questions) => {
     // validation
@@ -108,7 +112,10 @@ onConditionReady(async (payload) => {
 
     await loadKnowledge(payload)
     await _loadClassStatistic()
+    await built.value.loadBuiltPaper(payload)
 })
+
+watch(conditionArgs, () => built.value.reset())
 </script>
 
 <style scoped>

+ 8 - 1
back-ui/src/views/dz/papers/components/paper-exact-intelligent.vue

@@ -14,9 +14,10 @@
         </el-col>
     </el-row>
     <el-divider/>
-    <div class="text-center">
+    <div v-if="!hasBuiltPaper" class="text-center">
         <el-button type="primary" size="large" @click="handleSubmit">生成试卷</el-button>
     </div>
+    <built-paper ref="built" @send="handleSubmit" />
 </template>
 
 <script setup name="PaperExactIntelligent">
@@ -27,11 +28,14 @@ import ClassStatisticTable from "@/views/dz/papers/components/plugs/class-statis
 import {ElMessage} from "element-plus";
 import {buildPaperExactIntelligent} from "@/api/dz/papers.js";
 import {useInjectGlobalLoading} from "@/views/hooks/useGlobalLoading.js";
+import BuiltPaper from "@/views/dz/papers/components/plugs/built-paper.vue";
 
 const type = consts.enums.buildType.ExactIntelligent
 const {batchId, batchList, onBatchReady} = useProvidePaperBatchCondition(type)
 const {selectedClasses, classList, loadClassStatistic} = useProvidePaperClassStatisticCondition()
 const {loading} = useInjectGlobalLoading()
+const built = ref(null)
+const hasBuiltPaper = computed(() => built.value?.hasPaper)
 
 const handleSubmit = async function () {
     if (!batchId.value) return ElMessage.error('请选择批次')
@@ -59,7 +63,10 @@ const _loadClassStatistic = async () => {
 onBatchReady(async (payload) => {
     statArgs = payload
     await _loadClassStatistic()
+    await built.value.loadBuiltPaper(payload)
 })
+
+watch(batchId, () => built.value.reset())
 </script>
 
 <style scoped>

+ 9 - 2
back-ui/src/views/dz/papers/components/paper-full-hand.vue

@@ -26,7 +26,7 @@
         </el-col>
     </el-row>
     <el-divider/>
-    <el-row :gutter="20">
+    <el-row v-if="!hasBuiltPaper" :gutter="20">
         <el-col :span="6">
             <knowledge-tree/>
         </el-col>
@@ -34,6 +34,7 @@
             <question-hand @submit="handleSubmit"/>
         </el-col>
     </el-row>
+    <built-paper ref="built" @send="handleSubmit" />
 </template>
 
 <script setup name="PaperFullHand">
@@ -47,6 +48,7 @@ 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";
+import BuiltPaper from "@/views/dz/papers/components/plugs/built-paper.vue";
 
 const type = consts.enums.buildType.FullHand
 const {
@@ -55,12 +57,14 @@ const {
     examType,
     examTypes,
     subjectId,
-    subjectList,
     groupedSubjects,
+    conditionArgs,
     onConditionReady
 } = useProvidePaperFullCondition(type)
 const {selectedClasses, classList, loadClassStatistic} = useProvidePaperClassStatisticCondition()
 const {knowledgeNode, knowledgeCheckNodes, loadKnowledge} = useProvidePaperKnowledgeCondition()
+const built = ref(null)
+const hasBuiltPaper = computed(() => built.value?.hasPaper)
 
 const handleSubmit = async (questions) => {
     // validation
@@ -98,7 +102,10 @@ onConditionReady(async (payload) => {
 
     await loadKnowledge(payload)
     await _loadClassStatistic()
+    await built.value.loadBuiltPaper(payload)
 })
+
+watch(conditionArgs, () => built.value.reset())
 </script>
 
 <style scoped>

+ 9 - 2
back-ui/src/views/dz/papers/components/paper-full-intelligent.vue

@@ -26,7 +26,7 @@
         </el-col>
     </el-row>
     <el-divider />
-    <el-row :gutter="20">
+    <el-row v-if="!hasBuiltPaper" :gutter="20">
         <el-col :span="6">
             <knowledge-tree allow-multiple/>
         </el-col>
@@ -34,6 +34,7 @@
             <question-intelligent @submit="handleSubmit" />
         </el-col>
     </el-row>
+    <built-paper ref="built" @send="handleSubmit" />
 </template>
 
 <script setup name="PaperFullIntelligent">
@@ -47,6 +48,7 @@ import {useProvidePaperKnowledgeCondition} from "@/views/dz/papers/hooks/usePape
 import QuestionIntelligent from "@/views/dz/papers/components/plugs/question-intelligent.vue";
 import {ElMessage} from "element-plus";
 import {buildPaperFullIntelligent} from "@/api/dz/papers.js";
+import BuiltPaper from "@/views/dz/papers/components/plugs/built-paper.vue";
 
 const type = consts.enums.buildType.FullIntelligent
 const {
@@ -55,12 +57,14 @@ const {
     examType,
     examTypes,
     subjectId,
-    subjectList,
     groupedSubjects,
+    conditionArgs,
     onConditionReady
 } = useProvidePaperFullCondition(type)
 const {selectedClasses, classList, loadClassStatistic} = useProvidePaperClassStatisticCondition()
 const {knowledgeNode, knowledgeCheckNodes, loadKnowledge} = useProvidePaperKnowledgeCondition()
+const built = ref(null)
+const hasBuiltPaper = computed(() => built.value?.hasPaper)
 
 const handleSubmit = async (qTypes) => {
     // validation
@@ -103,7 +107,10 @@ onConditionReady(async (payload) => {
 
     await loadKnowledge(payload)
     await _loadClassStatistic()
+    await built.value.loadBuiltPaper(payload)
 })
+
+watch(conditionArgs, () => built.value.reset())
 </script>
 
 <style scoped>

+ 86 - 0
back-ui/src/views/dz/papers/components/plugs/built-paper.vue

@@ -0,0 +1,86 @@
+<template>
+    <div v-if="hasPaper">
+        <div class="flex justify-center items-center gap-5">
+            <el-button type="primary" size="large" @click="handleSend">发送试卷</el-button>
+            <el-button type="warning" size="large" plain @click="handleSendNew">重新生成</el-button>
+            <el-button type="danger" size="large" plain @click="handleSendForce">全部重新生成</el-button>
+        </div>
+        <el-collapse class="mt-5">
+            <el-collapse-item title="1">
+                <template #title>
+                    <div slot="title" class="flex justify-between">
+                        <el-text>{{`已经存在试卷:${paper.paperName}`}}</el-text>
+                        <el-text type="primary">查看详情</el-text>
+                    </div>
+                </template>
+                <el-card v-for="(group, idx) in groupedQuestions" shadow="never" class="mb-5">
+                    <div slot="header" class="clearfix">
+                        <el-text class="font-bold">
+                            {{ numberToChinese(idx + 1) }}、{{ group.title }}(共{{ group.num }}题;共{{ group.score }}分)
+                        </el-text>
+                    </div>
+                    <div v-for="(q, i) in group.list" class="mb-5">
+                        <div>
+                            {{ i + 1 }}.
+                            <span style="color: #1890ff">题号:{{ q.id }}({{ q.score }}分)</span><span
+                            v-html="q.title"></span>
+                        </div>
+                    </div>
+                </el-card>
+            </el-collapse-item>
+        </el-collapse>
+    </div>
+</template>
+
+<script setup name="BuiltPaper">
+import {useInjectGlobalLoading} from "@/views/hooks/useGlobalLoading.js";
+import {getBuiltPaper} from "@/api/dz/papers.js";
+import {numberToChinese} from "@/utils/paper-helper.js";
+import {ElMessage} from "element-plus";
+
+const emits = defineEmits(['send', 'send-new', 'send-force'])
+
+const {loading} = useInjectGlobalLoading()
+const paper = ref({})
+const questions = computed(() => paper.value?.questions || [])
+const hasPaper = computed(() => paper.value?.paperId || paper.value?.id)
+
+const groupedQuestions = computed(() => {
+    const results = {}
+    questions.value.forEach(q => {
+        if (!results[q.qtpye]) results[q.qtpye] = []
+        results[q.qtpye].push(q)
+    })
+    return 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 loadBuiltPaper = async function (payload) {
+    const res = await getBuiltPaper(payload)
+    paper.value = res.data
+}
+
+const reset = function () {
+    paper.value = {}
+}
+
+const handleSend = function () {
+    emits('send')
+}
+const handleSendNew = function () {
+    return ElMessage.info('开发中,敬请期待...')
+}
+const handleSendForce = function () {
+    return ElMessage.info('开发中,敬请期待...')
+}
+
+defineExpose({hasPaper, loadBuiltPaper, reset})
+</script>
+
+<style scoped>
+
+</style>

+ 26 - 116
back-ui/src/views/dz/papers/components/plugs/class-detail.vue

@@ -1,22 +1,19 @@
 <template>
-    <el-form :model="queryParams" :rules="rules" label-width="68px" inline>
-        <el-form-item label="发送状态" v-model="queryParams.state">
-            <el-select v-model="queryParams.state" clearable @change="handleQuery" style="width: 172px">
+    <el-form label-width="68px" inline>
+        <el-form-item label="发送状态" v-model="state">
+            <el-select v-model="state" clearable style="width: 172px">
                 <el-option v-for="s in stateList" :label="s" :value="s" />
             </el-select>
         </el-form-item>
-        <el-form-item>
-            <el-button type="primary" @click="handleQuery">查询</el-button>
-        </el-form-item>
     </el-form>
-    <Table :data="list" :columns="columns" :actions="actions" @action="handleAction">
+    <Table :data="filterList" :columns="columns" :actions="actions" @action="handleAction">
         <template #rate="{row}">
-            <el-text v-if="[undefined, null].includes(row.rate)">-</el-text>
-            <el-text :type="row.rate>90?'success':row.rate>70?'primary':'danger'">{{row.rate}}%</el-text>
+            <el-text v-if="[undefined, null, NaN].includes(row.rate)">-</el-text>
+            <el-text v-else :type="row.rate>90?'success':row.rate>70?'primary':'danger'">{{row.rate}}%</el-text>
         </template>
     </Table>
     <el-dialog v-model="dialog" title="做题情况" show-close>
-        <student-detail v-if="dialog" :id="1" />
+        <student-detail v-if="dialog" :class-data="data" :student-data="dialogObj" />
     </el-dialog>
 </template>
 
@@ -25,23 +22,31 @@
 import consts from "@/utils/consts.js";
 import Table from "@/components/Table/index.vue";
 import StudentDetail from "@/views/dz/papers/components/plugs/student-detail.vue";
+import {getPaperStudentRecords} from "@/api/dz/papers.js";
 
 const props = defineProps({
-    paperId: [String, Number],
-    state: String,
+    data: Object,
     exactMode: Boolean
 })
 
 const list = ref([])
-const queryParams = ref({
-    paperId: '',
-    state: ''
-})
+const state = ref('')
 const stateList = computed(() => props.exactMode
     ? consts.config.exactColumns.map(c => c.label)
     : consts.config.fullColumns.map(c => c.label))
+const queryParams = computed(() => ({
+    buildType: props.data.buildType,
+    batchId: props.data.batchId,
+    classId: props.data.classId
+}))
 const rules = {}
 const dialog = ref(false)
+const dialogObj = ref(null)
+
+const filterList = computed(() => {
+    if (!state.value) return list.value
+    return list.value.filter(i => i.state == state.value)
+})
 
 const columns = [
     {label: '姓名', prop: 'studentName'},
@@ -53,109 +58,19 @@ const columns = [
     {label: '手机号', prop: 'mobile', minWidth: 120}
 ]
 const actions = [
-    {key: 'rate', label: '详情', permission: ['']}
+    {key: 'rate', label: '考试详情', permission: [''], disabled: r => [null, undefined, NaN].includes(r.rate)}
 ]
 
 const getList = async function() {
-    list.value = [{
-        id: 1,
-        studentId: 1,
-        studentName: '张三',
-        mobile: '13933445566',
-        batchId: 1,
-        batchName: '第一批',
-        paperName: '试卷一',
-        state: '',
-        rate: 99,
-    },{
-        studentId: 1,
-        studentName: '张三',
-        mobile: '13933445566',
-        batchId: 1,
-        batchName: '第一批',
-        paperName: '试卷一',
-        state: '',
-        rate: 80,
-    },{
-        studentId: 1,
-        studentName: '张三',
-        mobile: '13933445566',
-        batchId: 1,
-        batchName: '第一批',
-        paperName: '试卷一',
-        state: '',
-        rate: 60,
-    },{
-        studentId: 1,
-        studentName: '张三',
-        mobile: '13933445566',
-        batchId: 1,
-        batchName: '第一批',
-        paperName: '试卷一',
-        state: '',
-        rate: 55,
-    },{
-        studentId: 1,
-        studentName: '张三',
-        mobile: '13933445566',
-        batchId: 1,
-        batchName: '第一批',
-        paperName: '试卷一',
-        state: '',
-        rate: 85,
-    },{
-        studentId: 1,
-        studentName: '张三',
-        mobile: '13933445566',
-        batchId: 1,
-        batchName: '第一批',
-        state: '',
-        rate: 81,
-    },{
-        studentId: 1,
-        studentName: '张三',
-        mobile: '13933445566',
-        batchId: 1,
-        batchName: '第一批',
-        paperName: '试卷一',
-        state: '',
-        rate: 81,
-    },{
-        studentId: 1,
-        studentName: '张三',
-        mobile: '13933445566',
-        batchId: 1,
-        batchName: '第一批',
-        state: '',
-        rate: 81,
-    },{
-        studentId: 1,
-        studentName: '张三',
-        mobile: '13933445566',
-        batchId: 1,
-        batchName: '第一批',
-        state: '',
-        rate: 94,
-    },{
-        studentId: 1,
-        studentName: '张三',
-        mobile: '13933445566',
-        batchId: 1,
-        batchName: '第一批',
-        paperName: '试卷一',
-        state: '',
-        rate: 90,
-    },]
-}
-
-const handleQuery = async function () {
-    await getList()
+    const res = await getPaperStudentRecords(queryParams.value)
+    list.value = res.data
 }
 
 const handleAction = function (action, row) {
     switch (action.key) {
         case "rate":
             dialog.value = true
+            dialogObj.value = row
             break
         default:
             throw new Error(`Action type '${action.key}' not support.`)
@@ -163,12 +78,7 @@ const handleAction = function (action, row) {
     }
 }
 
-onMounted(async () => {
-    queryParams.value.paperId = props.paperId
-    queryParams.value.state = props.state
-
-    await getList()
-})
+onMounted(() => getList())
 </script>
 
 <style scoped>

+ 34 - 28
back-ui/src/views/dz/papers/components/plugs/student-detail.vue

@@ -1,47 +1,53 @@
 <template>
     <el-text type="primary" tag="b">基础信息</el-text>
     <el-descriptions border :column="4" class="mb-5 mt-2">
-        <el-descriptions-item label="组卷类型">{{detail.buildType}}</el-descriptions-item>
-        <el-descriptions-item label="批次">{{detail.batchName}}</el-descriptions-item>
-        <el-descriptions-item label="科目">{{detail.subjectName}}</el-descriptions-item>
-        <el-descriptions-item label="班级">{{detail.className}}</el-descriptions-item>
-        <el-descriptions-item label="姓名">{{detail.studentName}}</el-descriptions-item>
-        <el-descriptions-item label="总分">{{detail.total}}</el-descriptions-item>
-        <el-descriptions-item label="得分">{{detail.score}}</el-descriptions-item>
-        <el-descriptions-item label="得分率">{{detail.rate}}</el-descriptions-item>
+        <el-descriptions-item label="组卷类型">{{classData.buildTypeName}}</el-descriptions-item>
+        <el-descriptions-item label="批次">{{classData.batchName}}</el-descriptions-item>
+        <el-descriptions-item label="科目">{{studentData.subjectName}}</el-descriptions-item>
+        <el-descriptions-item label="班级">{{classData.className}}</el-descriptions-item>
+        <el-descriptions-item label="姓名">{{studentData.studentName}}</el-descriptions-item>
+        <el-descriptions-item label="总分">{{studentData.total}}</el-descriptions-item>
+        <el-descriptions-item label="得分">{{studentData.score}}</el-descriptions-item>
+        <el-descriptions-item label="得分率">{{studentData.rate}}</el-descriptions-item>
     </el-descriptions>
     <el-text type="primary" tag="b">知识点明细</el-text>
-    <Table :data="detail.knowledges" :columns="columns" style="width: 90%; margin-top: 5px"/>
+    <Table :data="detail" :columns="columns" style="width: 90%; margin-top: 5px">
+        <template #rate="{row}">
+            <el-text v-if="[undefined, null, NaN].includes(row.rate)">-</el-text>
+            <el-text v-else :type="row.rate>90?'success':row.rate>70?'primary':'danger'">{{row.rate}}%</el-text>
+        </template>
+    </Table>
 </template>
 
 <script setup name="StudentDetail">
 import Table from '@/components/Table/index.vue';
+import {getPaperStudentDetail} from "@/api/dz/papers.js";
 
-const detail = ref({
-    buildType: '定向智能',
-    batchId: 1,
-    batchName: '第一批',
-    subjectName: '职测',
-    studentName: '张三',
-    className: '2501班',
-    total: 300,
-    score: 240,
-    rate: '80%',
-    knowledges: [
-        {id: 1, name: '知识点一', num: 5, correct: 4, rate: '80%'},
-        {id: 2, name: '知识点二', num: 8, correct: 3, rate: '38%'},
-        {id: 3, name: '知识点三', num: 10, correct: 8, rate: '80%'},
-        {id: 4, name: '知识点四', num: 2, correct: 2, rate: '100%'},
-        {id: 5, name: '知识点五', num: 2, correct: 1, rate: '50%'},
-    ]
+const props = defineProps({
+    classData: Object,
+    studentData: Object
 })
 
+const detail = ref([])
+
 const columns = [
-    {label: '知识点', prop: 'name'},
+    {label: '知识点', prop: 'knowledgeName'},
     {label: '题量', prop: 'num'},
     {label: '正确数', prop: 'correct'},
-    {label: '正确率', prop: 'rate'}
+    {label: '正确率', prop: 'rate', type: 'slot', slotName: 'rate'}
 ]
+
+onMounted(async () => {
+    const query = {
+        buildType: props.classData.buildType,
+        batchId: props.classData.batchId,
+        classId: props.classData.classId,
+        paperId: props.studentData.paperId,
+        studentId: props.studentData.studentId
+    }
+    const res = await getPaperStudentDetail(query)
+    detail.value = res.data
+})
 </script>
 
 <style scoped>

+ 1 - 51
back-ui/src/views/dz/papers/detail.vue

@@ -98,13 +98,10 @@ import router from "@/router/index.js";
 import {ElMessage} from "element-plus";
 import {buildPaperExactHand, buildPaperFullHand} from "@/api/dz/papers.js";
 import {usePaperResolver} from "@/views/dz/papers/hooks/usePaperStorage.js";
+import {numberToChinese} from "@/utils/paper-helper.js";
 
 const {paperLocal, groupedQuestions, toCommitPaper} = usePaperResolver()
 
-const chnNumChar = ["零", "一", "二", "三", "四", "五", "六", "七", "八", "九"];
-const chnUnitSection = ["", "万", "亿", "万亿", "亿亿"];
-const chnUnitChar = ["", "十", "百", "千"];
-
 const groupIdx = ref(0)
 const qIdx = ref(0)
 const openGroupScore = ref(false)
@@ -115,53 +112,6 @@ const openParse = ref(false)
 const parseQuestion = ref(null)
 const parseCopy = ref(null)
 
-const sectionToChinese = function (section) {
-    let strIns = "", chnStr = "";
-    let unitPos = 0;
-    let zero = true;
-    while (section > 0) {
-        const v = section % 10;
-        if (v === 0) {
-            if (!zero) {
-                zero = true;
-                chnStr = chnNumChar[v] + chnStr;
-            }
-        } else {
-            zero = false;
-            strIns = chnNumChar[v];
-            strIns += chnUnitChar[unitPos];
-            chnStr = strIns + chnStr;
-        }
-        unitPos++;
-        section = Math.floor(section / 10);
-    }
-    return chnStr;
-}
-const numberToChinese = function (num) {
-    let unitPos = 0;
-    let strIns = "", chnStr = "";
-    let needZero = false;
-
-    if (num === 0) {
-        return chnNumChar[0];
-    }
-
-    while (num > 0) {
-        const section = num % 10000;
-        if (needZero) {
-            chnStr = chnNumChar[0] + chnStr;
-        }
-        strIns = sectionToChinese(section);
-        strIns +=
-            section !== 0 ? chnUnitSection[unitPos] : chnUnitSection[0];
-        chnStr = strIns + chnStr;
-        needZero = section < 1000 && section > 0;
-        num = Math.floor(num / 10000);
-        unitPos++;
-    }
-
-    return chnStr;
-}
 const showQuestionParse = function (q) {
     openParse.value = true
     parseQuestion.value = q

+ 9 - 2
back-ui/src/views/dz/papers/hooks/usePaperList.js

@@ -1,6 +1,8 @@
 import {useInjectGlobalLoading} from "@/views/hooks/useGlobalLoading.js";
 import {injectLocal, provideLocal} from "@vueuse/core";
 import {getPaperClasses, getPaperClassRecords} from "@/api/dz/papers.js";
+import {listToMap} from "@/utils/index.js";
+import consts from "@/utils/consts.js";
 
 const key = Symbol('PaperList')
 
@@ -87,10 +89,15 @@ export const useProvidePaperList = function (queryParams, opts = defaultOptions)
             ...toValue(queryParams)
         }
         getPaperClassRecords(query).then(response => {
+            // 自动补全组卷类型名称
+            const buildTypeMap = listToMap(consts.enums.buildTypes, i => i.id, i => i.name)
+            response.rows.forEach(r => {
+                if (r.buildTypeName) return
+                r.buildTypeName = buildTypeMap[r.buildType] || r.buildType
+            })
             list.value = response.rows
             total.value = response.total
-            loading.value = false
-        })
+        }).finally(() => loading.value = false)
     }
 
     onMounted(() => getList())

+ 0 - 253
back-ui/src/views/dz/papers/list-bak.vue

@@ -1,253 +0,0 @@
-<template>
-    <div class="app-container">
-        <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
-            <el-form-item label="试卷名称" prop="name">
-                <el-input v-model="queryParams.name" placeholder="请输入试卷名称" clearable @keyup.enter="handleQuery"/>
-            </el-form-item>
-            <el-form-item label="组卷类型" prop="buildType">
-                <el-select v-model="queryParams.buildType" clearable placeholder="请选择组卷类型" style="width: 170px;">
-                    <!--        TODO: 组卷类型        -->
-                </el-select>
-            </el-form-item>
-            <el-form-item label="试卷批次" prop="batchId">
-                <el-select v-model="queryParams.batchId" clearable placeholder="请选择批次" style="width: 170px;">
-                    <el-option v-for="b in batchList" :label="b.name" :value="b.batchId"/>
-                </el-select>
-            </el-form-item>
-            <el-form-item label="考生类型" prop="examType">
-                <el-select v-model="queryParams.examType" placeholder="请选择考生类型" clearable style="width: 170px;">
-                    <el-option v-for="dict in exam_type" :key="dict.value" :label="dict.label" :value="dict.value"/>
-                </el-select>
-            </el-form-item>
-            <el-form-item label="发送情况" prop="state">
-                <el-select v-model="queryParams.state" placeholder="请选择考生类型" clearable style="width: 170px;">
-                    <!--         TODO: 发送情况           -->
-                </el-select>
-            </el-form-item>
-            <el-form-item label="科目" prop="subjectId">
-                <el-select v-model="queryParams.subjectId" clearable placeholder="请选择科目" style="width: 170px;">
-                    <el-option v-for="s in subjectList" :label="s.subjectName" :value="s.subjectId"/>
-                </el-select>
-            </el-form-item>
-            <el-form-item>
-                <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
-                <el-button icon="Refresh" @click="resetQuery">重置</el-button>
-            </el-form-item>
-        </el-form>
-
-        <el-row :gutter="10" class="mb8">
-            <!--            <el-col :span="1.5">-->
-            <!--                <el-button-->
-            <!--                    type="primary"-->
-            <!--                    plain-->
-            <!--                    icon="Plus"-->
-            <!--                    @click="handleAdd"-->
-            <!--                    v-hasPermi="['dz:subject:add']"-->
-            <!--                >新增</el-button>-->
-            <!--            </el-col>-->
-            <!--            <el-col :span="1.5">-->
-            <!--                <el-button-->
-            <!--                    type="success"-->
-            <!--                    plain-->
-            <!--                    icon="Edit"-->
-            <!--                    :disabled="single"-->
-            <!--                    @click="handleUpdate"-->
-            <!--                    v-hasPermi="['dz:subject:edit']"-->
-            <!--                >修改</el-button>-->
-            <!--            </el-col>-->
-            <!--            <el-col :span="1.5">-->
-            <!--                <el-button-->
-            <!--                    type="danger"-->
-            <!--                    plain-->
-            <!--                    icon="Delete"-->
-            <!--                    :disabled="multiple"-->
-            <!--                    @click="handleDelete"-->
-            <!--                    v-hasPermi="['dz:subject:remove']"-->
-            <!--                >删除</el-button>-->
-            <!--            </el-col>-->
-            <!--            <el-col :span="1.5">-->
-            <!--                <el-button-->
-            <!--                    type="warning"-->
-            <!--                    plain-->
-            <!--                    icon="Download"-->
-            <!--                    @click="handleExport"-->
-            <!--                    v-hasPermi="['dz:subject:export']"-->
-            <!--                >导出</el-button>-->
-            <!--            </el-col>-->
-            <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
-        </el-row>
-
-        <el-table v-loading="loading" :data="paperList" @selection-change="handleSelectionChange">
-            <el-table-column type="selection" width="55" align="center"/>
-            <el-table-column label="试卷ID" align="center" prop="id" width="80"/>
-            <el-table-column label="试卷名称" align="center" prop="paperName"/>
-            <el-table-column label="科目" align="center" prop="subjectName"/>
-            <el-table-column label="试卷批次" align="center" prop="batchName"/>
-            <el-table-column label="组卷类型" align="center" prop="buildType"/>
-            <el-table-column label="状态" align="center" prop="state"/>
-            <el-table-column label="创建人" align="center" prop="createBy"/>
-            <el-table-column label="试卷分类" align="center" prop="paperType"/>
-            <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
-                <template #default="scope">
-                    <el-button link type="primary" icon="Edit" @click="handleEdit(scope.row)"
-                               v-hasPermi="['dz:paper:edit']">编辑
-                    </el-button>
-                    <el-button link type="primary" icon="Download" @click="handleDownload(scope.row)"
-                               v-hasPermi="['dz:paper:download']">下载
-                    </el-button>
-                    <el-button link type="primary" icon="Finished" @click="handlePublish(scope.row)"
-                               v-hasPermi="['dz:paper:download']">发布试卷
-                    </el-button>
-                </template>
-            </el-table-column>
-        </el-table>
-
-        <pagination v-show="total>0" :total="total" v-model:page="queryParams.pageNum"
-                    v-model:limit="queryParams.pageSize" @pagination="getList"/>
-
-        <!-- 添加或修改科目对话框 -->
-        <el-dialog :title="publishDialogTitle" v-model="openPublish" width="500px" append-to-body>
-            <paper-publish :paper="openPaper" />
-            <template #footer>
-                <div class="dialog-footer">
-                    <el-button type="primary" @click="handlePublishConfirm">确 定</el-button>
-                    <el-button @click="cancel">取 消</el-button>
-                </div>
-            </template>
-        </el-dialog>
-    </div>
-</template>
-
-<script setup name="PaperList">
-
-import {getPaperBatches, getPaperList, getPaperSubjects} from "@/api/dz/papers.js";
-// import PaperPublish from "@/views/dz/papers/components/paper-publish.vue";
-
-const {proxy} = getCurrentInstance()
-const {exam_type} = proxy.useDict('build_type', 'exam_type')
-
-const paperList = ref([])
-const open = ref(false)
-const loading = ref(false)
-const showSearch = ref(true)
-const ids = ref([])
-const single = ref(true)
-const multiple = ref(true)
-const total = ref(0)
-
-const subjectList = ref([])
-const batchList = ref([])
-const subjectMap = computed(() => {
-    const obj = {}
-    subjectList.value.forEach(s => obj[s.subjectId] = s.subjectName)
-    return obj
-})
-const batchMap = computed(() => {
-    const obj = {}
-    batchList.value.forEach(b => obj[b.batchId] = b.name)
-    return obj
-})
-
-const openPublish = ref(false)
-const openPaper = ref(null)
-const publishDialogTitle = computed(() => `发布试卷:${openPaper?.paperName}`)
-
-const data = reactive({
-    form: {},
-    queryParams: {
-        pageNum: 1,
-        pageSize: 10,
-        name: null,
-        buildType: null,
-        batchId: null,
-        subjectId: null,
-        state: null
-    },
-    rules: {}
-})
-
-const {queryParams, form, rules} = toRefs(data)
-
-function getList() {
-    loading.value = true
-
-    getPaperList(queryParams.value).then(response => {
-        response.rows.forEach(p => {
-            p.subjectName = subjectMap.value[p.subjectId] || ''
-            p.batchName = batchMap.value[p.batchId] || ''
-        })
-        paperList.value = response.rows
-        total.value = response.total
-        loading.value = false
-    })
-}
-
-// 取消按钮
-function cancel() {
-    open.value = false
-    reset()
-}
-
-// 表单重置
-function reset() {
-    form.value = {
-        subjectId: null,
-        subjectName: null,
-        pinyin: null,
-        sort: null,
-        locations: null,
-        examTypes: null
-    }
-    proxy.resetForm("subjectRef")
-}
-
-/** 搜索按钮操作 */
-function handleQuery() {
-    queryParams.value.pageNum = 1
-    getList()
-}
-
-/** 重置按钮操作 */
-function resetQuery() {
-    proxy.resetForm("queryRef")
-    handleQuery()
-}
-
-// 多选框选中数据
-function handleSelectionChange(selection) {
-    ids.value = selection.map(item => item.subjectId)
-    single.value = selection.length != 1
-    multiple.value = !selection.length
-}
-
-// operations
-const handleEdit = function (paper) {
-
-}
-
-const handleDownload = function (paper) {
-    proxy.download('/learn/paper/export', {
-        paperId: paper.id
-    }, `${paper.paperName}_${new Date().getTime()}.xlsx`)
-}
-
-const handlePublish = function (paper) {
-    openPublish.value = true
-    openPaper.value = paper
-}
-
-const handlePublishConfirm = function () {
-    openPublish.value = false
-}
-
-// hooks
-onMounted(async () => {
-    const resSubject = await getPaperSubjects()
-    subjectList.value = resSubject.data
-    const resBatch = await getPaperBatches()
-    batchList.value = resBatch.data
-    getList()
-})
-</script>
-
-<style lang="scss" scoped></style>