diff --git a/.gitignore b/.gitignore index 423ed2b..7815bac 100644 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,5 @@ tests/**/coverage/ *.ntvs* *.njsproj *.sln -tsconfig.tsbuildinfo \ No newline at end of file +tsconfig.tsbuildinfo +.vscode diff --git a/.vscode/settings.json b/.vscode/settings.json index 388b96f..354c5f4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,6 @@ { "editor.formatOnType": true, - "editor.formatOnSave": true, + "editor.formatOnSave": false, "[vue]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, @@ -40,4 +40,5 @@ "v-ripple" ], "vscodeCustomCodeColor.highlightValueColor": "#b392f0", + "vue3snippets.enable-compile-vue-file-on-did-save-code": true, } \ No newline at end of file diff --git a/src/api/exam.ts b/src/api/exam.ts index 5668245..d6d567e 100644 --- a/src/api/exam.ts +++ b/src/api/exam.ts @@ -18,7 +18,18 @@ export function ImportExamInfo(id: number, file: File) { { headers: { "Content-Type": "application/x-www-form-urlencoded" - } + }, + responseType: "blob" } ); } + +/** + * @description 删除班级考试信息 + * @return {object} + */ +export function DeleteExamInfo(data: { classId: number; examId: number }) { + return http.request("post", `ExamClassInfo/DeleteExamInfo`, { + data + }); +} diff --git a/src/api/userCenter.ts b/src/api/userCenter.ts index d9abc2e..bfc6b15 100644 --- a/src/api/userCenter.ts +++ b/src/api/userCenter.ts @@ -62,6 +62,21 @@ export function cloudSchoolCombo() { } ); } +/** + * @description 获取班级信息 + * @return {object} + */ +export function getClassInfo(id) { + return http.request>("get", `userCenter/back/classes/${id}`); +} +/** + * @description 获取学校信息 + * @return {object} + */ +export function getSchoolInfo(id) { + return http.request>("get", `userCenter/back/schools/${id}`); +} + /** * @description 获取用户信息 * @return {object} diff --git a/src/components/hTable/index.vue b/src/components/hTable/index.vue index 3ebbba5..520eb75 100644 --- a/src/components/hTable/index.vue +++ b/src/components/hTable/index.vue @@ -94,7 +94,8 @@ function appStyle() { tableHeight.value = appB.value.parentElement.parentElement.offsetHeight - 145 - - appB_S.value.offsetHeight; + appB_S.value.offsetHeight + + 0; return tableHeight; } diff --git a/src/utils/http/index.ts b/src/utils/http/index.ts index 80282e0..b7c493d 100644 --- a/src/utils/http/index.ts +++ b/src/utils/http/index.ts @@ -74,7 +74,7 @@ const convertKeysToCamelCase = (data: any): T => { const defaultConfig: AxiosRequestConfig = { baseURL: import.meta.env.VITE_API_BASEURL, // 请求超时时间 - timeout: 10000, + timeout: 20 * 1000, headers: { Accept: "application/json, text/plain, */*", "Content-Type": "application/json", @@ -183,7 +183,8 @@ class PureHttp { const $config = response.config; // 关闭进度条动画 NProgress.done(); - response.data = convertKeysToCamelCase(response.data); + if (!(response.data instanceof Blob)) + response.data = convertKeysToCamelCase(response.data); // 优先判断post/get等方法是否传入回调,否则执行初始化设置等回调 if (typeof $config.beforeResponseCallback === "function") { $config.beforeResponseCallback(response); diff --git a/src/views/exam/classDetails.vue b/src/views/exam/classDetails.vue index c00839e..28e13e3 100644 --- a/src/views/exam/classDetails.vue +++ b/src/views/exam/classDetails.vue @@ -6,10 +6,13 @@ import { fa } from "element-plus/es/locales.mjs"; import { hTableAPI } from "@/api/hTable"; import { getenum } from "@/api/enum"; import { ruleRequired, ruleRequiredNumber } from "@/utils/rules"; +import { DeleteExamInfo, ImportExamInfo } from "@/api/exam"; +import { entryExamInfo } from "./examFun"; +import { ElMessage, ElMessageBox } from "element-plus"; const ControllerName = "ExamClassInfo"; defineOptions({ - name: ControllerName + name: ControllerName, }); const props = defineProps<{ @@ -33,10 +36,10 @@ const tableData: TableConfig = { { FieldName: "ExamId", FieldValue: props.data[0].id + "", - ConditionalType: ConditionalType.Equal - } + ConditionalType: ConditionalType.Equal, + }, ], // 默认查询条件 - Conditions: [] + Conditions: [], }, operationColumn: true, // 显示操作按钮 operationColumnData: [ @@ -45,21 +48,21 @@ const tableData: TableConfig = { topBtn: true, // 是头部按钮 label: "添加", btnStyle: "success", - btnType: "custom" + btnType: "custom", }, { topBtn: false, // 头部按钮 show: true, label: "删除", - btnType: "del", // 按钮类型 add edit del 不设置则 自定义按钮 - btnStyle: "danger" // topBtn: true才生效 success danger + click: deleteInfo, + btnStyle: "danger", // topBtn: true才生效 success danger }, { topBtn: false, // 头部按钮 show: true, label: "重新录入", - btnType: "custom", // 按钮类型 add edit del 不设置则 自定义按钮 - btnStyle: "primary" // topBtn: true才生效 success danger + click: reloadImportInfo, + btnStyle: "primary", // topBtn: true才生效 success danger }, { topBtn: false, // 头部按钮 @@ -71,9 +74,9 @@ const tableData: TableConfig = { title: "考试学生班级详情", // 弹出框title src: "exam/userDetails", // 组件路径 width: "1600px", // 弹框宽度 - height: "800px" // 弹框高度 - } - } + height: "880px", // 弹框高度 + }, + }, ], column: { // 行数据 @@ -83,15 +86,15 @@ const tableData: TableConfig = { searchType: ConditionalType.Like, // 搜索类型 add: false, // 字段允许添加 edit: false, // 字段允许修改 - width: "180px" + width: "180px", }, grade: { label: "年级", width: "100px", - custom: s => `${s.gradeYear}${s.gradeLevel}`, + custom: (s) => `${s.gradeYear}${s.gradeLevel}`, search: true, add: false, // 字段允许添加 - edit: false // 字段允许修改 + edit: false, // 字段允许修改 }, className: { label: "班级", @@ -99,37 +102,62 @@ const tableData: TableConfig = { search: true, searchType: ConditionalType.Like, // 搜索类型 add: false, // 字段允许添加 - edit: false // 字段允许修改 + edit: false, // 字段允许修改 }, peopleCount: { label: "参考人数", width: "100px", search: false, add: false, // 字段允许添加 - edit: false // 字段允许修改 + edit: false, // 字段允许修改 }, entryPerson: { label: "录入人", width: "200px", search: true, add: false, // 字段允许添加 - edit: false // 字段允许修改 + edit: false, // 字段允许修改 }, createTime: { label: "录入时间", width: "200px", search: true, add: false, // 字段允许添加 - edit: false // 字段允许修改 - } + edit: false, // 字段允许修改 + }, }, data: [], pageData: { - total: 0 + total: 0, }, - selectRows: [] + selectRows: [], }; +async function deleteInfo(o, row, c) { + try { + await ElMessageBox.confirm("是否删除考试信息?", "提示", { + confirmButtonText: "确定", + cancelButtonText: "取消", + type: "warning", + }); + await DeleteExamInfo({ examId: row[0].examId, classId: row[0].classId }); + } catch (error) { + ElMessage.info("取消删除"); + } +} +async function reloadImportInfo(o, row, c) { + try { + await ElMessageBox.confirm("是否重新录入考试信息?", "提示", { + confirmButtonText: "确定", + cancelButtonText: "取消", + type: "warning", + }); + await DeleteExamInfo({ examId: row[0].examId, classId: row[0].classId }); + entryExamInfo(row[0].examId); + } catch (error) { + ElMessage.info("取消重新录入"); + } +} const showTable = ref(false); onMounted(async () => { //初始化数据原 diff --git a/src/views/exam/classExam.vue b/src/views/exam/classExam.vue index 433f53e..a88d407 100644 --- a/src/views/exam/classExam.vue +++ b/src/views/exam/classExam.vue @@ -9,7 +9,7 @@ import { ruleRequired, ruleRequiredNumber } from "@/utils/rules"; const ControllerName = "ExamClassInfo"; defineOptions({ - name: "ClassExam" + name: "ClassExam", }); const props = defineProps<{ @@ -29,24 +29,25 @@ const tableData: TableConfig = { PageIndex: 0, PageSize: 20, OrderBy: "Id", // 排序 + OrderByType: 1, // 排序方式 defaultConditions: [], // 默认查询条件 - Conditions: [] + Conditions: [], }, operationColumn: true, // 显示操作按钮 operationColumnData: [ { topBtn: false, // 头部按钮 show: true, - label: "学生成绩详情", + label: "详情", btnType: "custom", btnStyle: "primary", custom: { title: "考试学生班级详情", // 弹出框title src: "exam/userDetails", // 组件路径 width: "1600px", // 弹框宽度 - height: "800px" // 弹框高度 - } - } + height: "800px", // 弹框高度 + }, + }, ], column: { // 行数据 @@ -56,51 +57,55 @@ const tableData: TableConfig = { searchType: ConditionalType.Like, // 搜索类型 add: false, // 字段允许添加 edit: false, // 字段允许修改 - width: "180px" + width: "180px", }, grade: { label: "年级", - width: "100px", - custom: s => `${s.gradeYear}${s.gradeLevel}`, + width: "120px", + custom: (s) => `${s.gradeYear}${s.gradeLevel}`, search: true, add: false, // 字段允许添加 - edit: false // 字段允许修改 + edit: false, // 字段允许修改 }, className: { label: "班级", - width: "150px", + width: "80px", search: true, searchType: ConditionalType.Like, // 搜索类型 add: false, // 字段允许添加 - edit: false // 字段允许修改 + edit: false, // 字段允许修改 + }, + examName: { + label: "最近考试", + width: "200px", + search: false, }, peopleCount: { label: "参考人数", width: "100px", search: false, - add: false, // 字段允许添加 - edit: false // 字段允许修改 }, - entryPerson: { - label: "录入人", - width: "200px", - search: true, - add: false, // 字段允许添加 - edit: false // 字段允许修改 + onLineCount: { + label: "重本人数", + width: "100px", + search: false, + }, + onLineRate: { + label: "重本率", + width: "100px", + custom: (row) => `${row.onLineRate * 100}%`, + search: false, + }, + onLineRanking: { + label: "重本率排名", + search: false, }, - createTime: { - label: "录入时间", - width: "200px", - search: true, - add: false, // 字段允许添加 - edit: false // 字段允许修改 - } }, data: [], pageData: { - total: 0 + total: 0, }, - selectRows: [] + selectRows: [], }; const showTable = ref(false); diff --git a/src/views/exam/examFun.ts b/src/views/exam/examFun.ts new file mode 100644 index 0000000..dbff05d --- /dev/null +++ b/src/views/exam/examFun.ts @@ -0,0 +1,36 @@ +import { ImportExamInfo } from "@/api/exam"; +import { ElMessage } from "element-plus"; + +export function entryExamInfo(eid: number) { + let fileE = document.createElement("input"); + fileE.type = "file"; + var formData = new window.FormData(); + fileE.onchange = async function () { + formData.append("File", fileE.files[0]); + let res = await ImportExamInfo(eid, fileE.files[0]); + if (res.code != undefined) { + if (res.code !== 200) return ElMessage.error(res.message); + else return ElMessage.success("所有数据录入成功"); + } else if (res.type === "application/json") { + let json = await res.text(); + if (json !== undefined && json.Code !== 200) { + return ElMessage.error(json.Message); + } else { + return ElMessage.success("操所有数据录入成功作成功"); + } + } else if (res === undefined || res.size === 0) + return ElMessage.success("所有数据录入成功"); + const url = res && window.URL.createObjectURL(res); + const link = document.createElement("a"); + link.href = url; + link.setAttribute("download", "未成功导入的考试信息数据" + ".xlsx"); + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + ElMessage.success("操作成功,已导出重复数据"); + }; + + try { + fileE.click(); + } catch (error) { } +} \ No newline at end of file diff --git a/src/views/exam/index.vue b/src/views/exam/index.vue index 5cd7edd..26f6ce4 100644 --- a/src/views/exam/index.vue +++ b/src/views/exam/index.vue @@ -8,10 +8,11 @@ import { getenum } from "@/api/enum"; import { ruleRequired, ruleRequiredNumber } from "@/utils/rules"; import { ImportExamInfo } from "@/api/exam"; import { ElMessage } from "element-plus"; +import { entryExamInfo } from "./examFun"; const ControllerName = "Exam"; defineOptions({ - name: ControllerName + name: ControllerName, }); function searchCallback(data) {} @@ -29,7 +30,7 @@ const tableData: TableConfig = { PageSize: 20, OrderBy: "Id", // 排序 defaultConditions: [], // 默认查询条件 - Conditions: [] + Conditions: [], }, operationColumn: true, // 显示操作按钮 operationColumnData: [ @@ -37,21 +38,21 @@ const tableData: TableConfig = { // 操作按钮 topBtn: false, // 是头部按钮 label: "修改", - btnType: "edit" // 按钮类型 add edit del custom + btnType: "edit", // 按钮类型 add edit del custom }, { // 操作按钮 topBtn: true, // 是头部按钮 label: "添加", btnStyle: "success", - btnType: "add" // 按钮类型 add edit del custom + btnType: "add", // 按钮类型 add edit del custom }, { topBtn: false, // 头部按钮 show: true, label: "删除", btnType: "del", // 按钮类型 add edit del 不设置则 自定义按钮 - btnStyle: "danger" // topBtn: true才生效 success danger + btnStyle: "danger", // topBtn: true才生效 success danger }, { topBtn: false, // 头部按钮 @@ -63,16 +64,16 @@ const tableData: TableConfig = { title: "考试班级详情", // 弹出框title src: "exam/classDetails", // 组件路径 width: "1300px", // 弹框宽度 - height: "800px" // 弹框高度 - } + height: "800px", // 弹框高度 + }, }, { topBtn: false, // 头部按钮 show: true, label: "录入成绩", click: entryExam, - btnStyle: "primary" // topBtn: true才生效 success danger - } + btnStyle: "primary", // topBtn: true才生效 success danger + }, ], column: { // 行数据 @@ -81,7 +82,7 @@ const tableData: TableConfig = { search: true, add: false, // 字段允许添加 edit: false, // 字段允许修改 - width: "150px" + width: "150px", }, name: { label: "考试名称", @@ -91,7 +92,7 @@ const tableData: TableConfig = { searchType: ConditionalType.Like, // 搜索类型 add: true, // 字段允许添加 edit: true, // 字段允许修改 - setting: {} + setting: {}, }, level: { label: "年级", @@ -101,7 +102,7 @@ const tableData: TableConfig = { setting: {}, search: true, add: true, // 字段允许添加 - edit: true // 字段允许修改 + edit: true, // 字段允许修改 }, testPaperType: { label: "试卷类型", @@ -111,7 +112,7 @@ const tableData: TableConfig = { setting: {}, search: true, add: true, // 字段允许添加 - edit: true // 字段允许修改 + edit: true, // 字段允许修改 }, type: { label: "考试类型", @@ -121,7 +122,7 @@ const tableData: TableConfig = { setting: {}, search: true, add: true, // 字段允许添加 - edit: true // 字段允许修改 + edit: true, // 字段允许修改 }, scoreLine: { label: "划线分数", @@ -130,7 +131,7 @@ const tableData: TableConfig = { width: "100px", setting: {}, add: true, // 字段允许添加 - edit: true // 字段允许修改 + edit: true, // 字段允许修改 }, startTime: { label: "考试时间", @@ -140,54 +141,24 @@ const tableData: TableConfig = { type: "datetime", setting: {}, add: true, // 字段允许添加 - edit: true // 字段允许修改 + edit: true, // 字段允许修改 }, createTime: { label: "创建时间", type: "datetime", search: true, add: false, // 字段允许添加 - edit: false // 字段允许修改 - } + edit: false, // 字段允许修改 + }, }, data: [], pageData: { - total: 0 + total: 0, }, - selectRows: [] + selectRows: [], }; function entryExam(obj, row, callBack) { - let fileE = document.createElement("input"); - fileE.type = "file"; - var formData = new window.FormData(); - fileE.onchange = async function () { - formData.append("File", fileE.files[0]); - let res = await ImportExamInfo(row[0].id, fileE.files[0]); - if (res.code != undefined) { - if (res.code !== 200) return ElMessage.error(res.message); - else return ElMessage.success("所有数据录入成功"); - } else if (res.type === "application/json") { - let json = await res.text(); - if (json !== undefined && json.Code !== 200) { - return ElMessage.error(json.Message); - } else { - return ElMessage.success("操所有数据录入成功作成功"); - } - } else if (res === undefined || res.size === 0) - return ElMessage.success("所有数据录入成功"); - const url = res && window.URL.createObjectURL(res); - const link = document.createElement("a"); - link.href = url; - link.setAttribute("download", "未成功导入的考试信息数据" + ".xlsx"); - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); - ElMessage.success("操作成功,已导出重复数据"); - }; - - try { - fileE.click(); - } catch (error) {} + entryExamInfo(row[0].id); } const showTable = ref(false); onMounted(async () => { @@ -198,9 +169,7 @@ onMounted(async () => { tableData.column.testPaperType.setting.datasource = ( await getenum("TestPaperTypeEnum") ).data; - tableData.column.type.setting.datasource = ( - await getenum("ExamTypeEnum") - ).data; + tableData.column.type.setting.datasource = (await getenum("ExamTypeEnum")).data; showTable.value = true; }); diff --git a/src/views/exam/userDetails.vue b/src/views/exam/userDetails.vue index 52bdcb3..c59a3c4 100644 --- a/src/views/exam/userDetails.vue +++ b/src/views/exam/userDetails.vue @@ -59,7 +59,13 @@ const tableData: TableConfig = { topBtn: false, // 头部按钮 label: "个人详情", btnType: "custom", - btnStyle: "primary" // topBtn: true才生效 success danger + btnStyle: "primary", + custom: { + title: "考试学生班级详情", // 弹出框title + src: "exam/userExam", // 组件路径 + width: "1600px", // 弹框宽度 + height: "800px" // 弹框高度 + } } ], column: { diff --git a/src/views/exam/userExam.vue b/src/views/exam/userExam.vue new file mode 100644 index 0000000..c84b992 --- /dev/null +++ b/src/views/exam/userExam.vue @@ -0,0 +1,173 @@ + + +