【修改】出题知识点可选择,数据时效性,MYSQL判分语句增加默认权值

【增加】试卷任务参数,在已有的试卷抽卷
This commit is contained in:
YOHO\20373
2025-06-09 10:31:14 +08:00
committed by 陆光LG
parent 5cd9e9dfbf
commit a54e22610d
49 changed files with 3727 additions and 2186 deletions

View File

@@ -43,9 +43,9 @@
<el-form-item label="难度" prop="quLevel">
<el-select v-model="form.quLevel" placeholder="请选择难度" :disabled="isUpdate">
<el-option label="全部" :value="3" />
<el-option label="简单" :value="0" />
<el-option label="一般" :value="1" />
<el-option label="难" :value="2" />
<el-option label="" :value="0" />
<el-option label="" :value="1" />
<el-option label="难" :value="2" />
</el-select>
</el-form-item>
@@ -346,7 +346,7 @@ const save = async () => {
const fn = isUpdate.value ? updateScheme : addScheme
await fn(payload)
emit('done')
visible.value = false
// visible.value = false
} finally {
loading.value = false
}

View File

@@ -1,106 +1,399 @@
<!-- 编辑弹窗 -->
<template>
<Dialog v-model="isVisible" :title="'添加试卷'" width="460" @open="handleOpen" center>
<el-form
ref="formRef"
:model="form"
:rules="rules"
label-width="80px"
@submit.prevent=""
>
<el-form-item label="试卷数目" prop="num">
<el-input
clearable
v-model="form.num"
placeholder="请输入试卷数目"
/>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="handleCancel">取消</el-button>
<el-button type="primary" :loading="loading" @click="save">
保存
</el-button>
</template>
</Dialog>
</template>
<script setup>
import { ref, reactive, nextTick } from 'vue';
import { useFormData } from '@/utils/use-form-data';
import { addPaper } from '@/api/system/paper';
const message = useMessage() // 消息弹窗
const props = defineProps({
/** 修改回显的数据 */
data: Object,
taskId: String ,
taskSpecialty: String,
});
const emit = defineEmits(['done']);
/** 弹窗是否打开 */
const isVisible = defineModel({ type: Boolean });
/** 提交状态 */
const loading = ref(false);
/** 表单实例 */
const formRef = ref(null);
/** 表单数据 */
const [form, resetFields, assignFields] = useFormData({
num: '',
taskId: ''
});
/** 表单验证规则 */
const rules = reactive({
num: [
{ required: true, message: '请输入试卷数目', trigger: 'blur' },
{ pattern: /^[1-9]\d*$/, message: '请输入正整数', trigger: 'blur' }
]
});
<Dialog v-model="isVisible" :title="'添加试卷'" width="460" @open="handleOpen" center>
<el-form
ref="formRef"
:model="form"
:rules="rules"
label-width="80px"
@submit.prevent=""
>
<el-form-item label="试卷数目" prop="num">
<el-input
clearable
v-model="form.num"
placeholder="请输入试卷数目"
/>
</el-form-item>
/** 关闭弹窗 */
const handleCancel = () => {
isVisible.value = false;
<!-- 是否启用组卷范围 -->
<el-form-item label=" " label-width="0">
<div style="display: flex; align-items: center; gap: 10px;">
<el-checkbox v-model="form.useCustomScope">
自定义组卷范围
</el-checkbox>
<el-button v-if="form.useCustomScope" @click="handleScopeSetting">
组卷范围
</el-button>
</div>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="handleCancel">取消</el-button>
<el-button type="primary" :loading="loading" @click="save">
保存
</el-button>
</template>
</Dialog>
<el-dialog v-model="scopeDialogVisible" title="设置组卷范围" width="80%" @closed="handleDialogClose">
<div style="display: flex;">
<!-- 左侧 -->
<div style="width: 40%; padding-right: 16px;">
<el-form-item label="分组类型">
<el-select v-model="selectedGroupType" placeholder="请选择" @change="loadLeftList">
<el-option label="练习" value="0" />
<el-option label="考试" value="1" />
<el-option label="冲刺练习" value="3" />
</el-select>
</el-form-item>
<el-tree
:data="leftTreeData"
node-key="id"
:props="{ label: 'label', children: 'children' }"
@node-click="handleNodeClick"
/>
</div>
<!-- 右侧 -->
<div style="width: 60%; padding-left: 16px;">
<div style="font-weight: bold; margin-bottom: 8px;">已选试卷</div>
<el-table
:data="rightList"
border
height="340"
:fit="true"
>
<el-table-column prop="taskName" label="任务名称" align="center"/>
<el-table-column label="任务分组" align="center">
<template #default="{ row }">
{{ getTaskTypeLabel(row.taskType) }}
</template>
</el-table-column>
<el-table-column prop="num" label="试卷编号" align="center" />
<el-table-column prop="que" label="题型" align="center" />
<el-table-column width="160" label="操作" align="center">
<template #default="{ row }">
<el-button type="text" size="small" @click="removeFromRightList(row)">移除</el-button>
<el-button type="text" size="small" @click="openQueDialog(row)">设置题型</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
<!-- 弹窗底部按钮 -->
<template #footer>
<el-button @click="onCancel">取消</el-button>
<el-button type="primary" @click="handleScopeConfirm">确认</el-button>
</template>
</el-dialog>
<el-dialog v-model="queDialogVisible" title="选择题型" width="400px" center>
<el-checkbox
v-model="checkAll"
@change="handleCheckAllChange"
style="margin-bottom: 10px;"
>
题型名称
</el-checkbox>
<el-checkbox-group v-model="selectedQue" style="display: flex; flex-direction: column; gap: 8px;">
<el-checkbox
v-for="item in currentSpNames"
:key="item"
:label="item"
>{{ item }}</el-checkbox>
</el-checkbox-group>
<template #footer>
<el-button @click="queDialogVisible = false">取消</el-button>
<el-button type="primary" @click="confirmQue">确定</el-button>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, reactive, nextTick } from 'vue';
import * as SmsChannelApi from '@/api/system/task/index';
import { useFormData } from '@/utils/use-form-data';
import { addPaper ,addPaperBypaper} from '@/api/system/paper';
const message = useMessage() // 消息弹窗
const props = defineProps({
/** 修改回显的数据 */
data: Object,
taskId: String ,
taskSpecialty: String,
});
const queryParams = reactive({
pageNo: 1,
pageSize: 100,
signature: undefined,
status: undefined,
taskName:undefined,
createTime: [],
taskType:'3'
})
const emit = defineEmits(['done']);
/** 弹窗是否打开 */
const isVisible = defineModel({ type: Boolean });
/** 提交状态 */
const loading = ref(false);
/** 表单实例 */
const formRef = ref(null);
/** 表单数据 */
const [form, resetFields, assignFields] = useFormData({
num: '',
taskId: ''
});
/** 表单验证规则 */
const rules = reactive({
num: [
{ required: true, message: '请输入试卷数目', trigger: 'blur' },
{ pattern: /^[1-9]\d*$/, message: '请输入正整数', trigger: 'blur' }
]
});
//组卷范围
const scopeDialogVisible = ref(false);
let isConfirmClosing = false;
const queDialogVisible = ref(false);
const selectedGroupType = ref('');
const leftList = ref([]);
const rightList = ref([]);
const leftTreeData = ref([]);
// 选中某个分组类型时,加载左侧列表
const loadLeftList = async () => {
// 示例:根据 selectedGroupType 获取数据
queryParams.taskType=selectedGroupType.value
const res = await SmsChannelApi.pageTaskPapers(queryParams)
leftTreeData.value = convertToTreeData(res.list);
};
// 从右侧列表中移除
const removeFromRightList = (row) => {
rightList.value = rightList.value.filter((item) => item.id !== row.id);
};
// 点击确认
const handleScopeConfirm = () => {
isConfirmClosing = true;
scopeDialogVisible.value = false;
// 提交 rightList.value 到后台或保存状态
console.log('选中的试卷:', rightList.value);
};
const handleScopeSetting = () => {
scopeDialogVisible.value = true;
};
const convertToTreeData = (taskList) => {
return taskList.map(task => {
return {
label: task.taskName,
children: (task.educationPaperList || []).map(paper => ({
label: paper.num || '未命名试卷',
id: paper.paperId,
num:paper.num,
taskName: task.taskName,
taskType: task.taskType,
que: '全部' ,
educationPaperSchemeList:task.educationPaperSchemeList
}))
};
/** 保存编辑 */
const save = () => {
formRef.value?.validate?.((valid) => {
if (!valid) {
return;
}
loading.value = true;
addPaper({ num: form.num,taskid: props.taskId ,taskSpecialty:form.taskSpecialty})
.then((msg) => {
loading.value = false;
message.success('新增成功!');
handleCancel();
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
});
};
const handleNodeClick = (data) => {
if (!data.children) {
// 是试卷节点
if (!rightList.value.find(p => p.id === data.id)) {
rightList.value.push(data);
}
}
};
const getTaskTypeLabel = (type) => {
const map = {
'0': '练习',
'1': '考试',
'3': '冲刺练习'
};
return map[type] || '未知';
};
const handleDialogClose = () => {
if (!isConfirmClosing) {
selectedGroupType.value='',
rightList.value = [];
leftTreeData.value=[] // 只有不是确认才清空
}
isConfirmClosing = false; // 重置标志位
}
const onCancel = () => {
isConfirmClosing = false;
selectedGroupType.value='',
rightList.value = [];
leftTreeData.value=[]
scopeDialogVisible.value = false;
};
const checkAll = ref(false);
const selectedQue = ref<string[]>([]);
const currentSpNames = ref<Array<string>>([]); // 当前题型名列表
const selectedRow = ref<any>(null); // 当前选中的试卷数据(可选)
const openQueDialog = (row) => {
// 设置当前选中的题型列表
currentSpNames.value = row.educationPaperSchemeList?.map(item => item.spName) || [];
// 设置当前行(选中的试卷)用于后续保存
selectedRow.value = row;
queDialogVisible.value = true;
};
///
watch(selectedQue, (val) => {
if (val.length === currentSpNames.value.length) {
checkAll.value = true;
} else {
checkAll.value = false;
}
});
const handleCheckAllChange = (val: boolean) => {
if (val) {
selectedQue.value = [...currentSpNames.value];
} else {
selectedQue.value = [];
}
};
// 确认选择题型把逗号分隔字符串赋给该行que字段
const confirmQue = async () => {
if (selectedRow.value) {
try {
const payload = {
taskId: props.taskId,
que: selectedQue.value // 数组形式传递
};
const res= await SmsChannelApi.checkType(payload);
// 可选:赋值用于前端展示(逗号拼接)
selectedRow.value.que = selectedQue.value.join(',');
ElMessage.success('题型设置成功');
} catch (err) {
console.error(err);
ElMessage.error('题型设置失败');
}
}
// 关闭弹窗 & 清空数据
queDialogVisible.value = false;
selectedRow.value = null;
selectedQue.value = [];
checkAll.value = false;
};
/** 关闭弹窗 */
const handleCancel = () => {
isVisible.value = false;
};
/** 保存编辑 */
const save = () => {
formRef.value?.validate?.((valid) => {
if (!valid) {
return;
}
loading.value = true;
if (form.useCustomScope) {
console.log( form.num+"num")
console.log(rightList.value+"rightList.value")
if (!rightList.value || rightList.value.length === 0) {
ElMessage.warning('请先设置组卷范围!');
loading.value = false;
return; // 阻止后续逻辑
}
console.log( props.taskId)
const payload = {
num: form.num,
taskId: props.taskId,
paperList: rightList.value, // 如果是数组字段名建议有“List”或“Array”
};
addPaperBypaper(payload)
.then((msg) => {
loading.value = false;
message.success('新增成功!');
handleCancel();
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
console.log("自定义范围!");
}else{
console.log("不是自定义范围!");
addPaper({ num: form.num,taskid: props.taskId ,taskSpecialty:form.taskSpecialty})
.then((msg) => {
loading.value = false;
message.success('新增成功!');
handleCancel();
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
}
});
};
/** 弹窗打开事件 */
const handleOpen = () => {
resetFields();
form.taskId = props.taskId; // 新增时赋值 taskId
form.taskSpecialty = props.taskSpecialty; // 新增时赋值 taskSpecialty
nextTick(() => {
nextTick(() => {
formRef.value?.clearValidate?.();
});
});
};
defineExpose({ open })
</script>
/** 弹窗打开事件 */
const handleOpen = () => {
resetFields();
form.taskId = props.taskId; // 新增时赋值 taskId
form.taskSpecialty = props.taskSpecialty; // 新增时赋值 taskSpecialty
nextTick(() => {
nextTick(() => {
formRef.value?.clearValidate?.();
});
});
};
defineExpose({ open })
</script>

View File

@@ -22,7 +22,8 @@
<dict-tag :type="DICT_TYPE.EXAM_QUE_DIFF" :value="scope.row.quLevel" />
</template>
</el-table-column>
<el-table-column label="知识点" prop="pointNames" align="left" />
<el-table-column label="章节" prop="pointNamesVo" align="left" />
<el-table-column label="知识点" prop="chapteridDictTextVo" align="left" />
</el-table>
</div>
@@ -172,14 +173,14 @@
<Dialog v-model="visibleChange" :title="'换题列表'" width="80%" center @close="handleCancelQue" >
<ContentWrap>
<div style="display: flex; gap: 20px;height: 500px; width: 100%;">
<div style="display: flex; gap: 20px;height: 600px; width: 100%;">
<!-- 左侧题目表格 -->
<div style="flex: 3;">
<!-- 搜索条件区域 -->
<div style="margin-bottom: 16px; display: flex; gap: 12px; align-items: center; flex-wrap: wrap;">
<el-input
<!-- <el-input
v-model="queryParams.pointNames"
placeholder="试题知识点"
clearable
@@ -194,7 +195,7 @@
<el-option label="简单" value="0" />
<el-option label="一般" value="1" />
<el-option label="困难" value="2" />
</el-select>
</el-select> -->
<el-input
v-model="queryParams.quNum"
placeholder="试题编号"
@@ -216,13 +217,13 @@
<el-table-column label="试题编号" align="center" prop="quNum" :show-overflow-tooltip="true"/>
<el-table-column label="专业" align="center" prop="specialtyName" width="120" />
<el-table-column label="课程" align="center" prop="courseName" :show-overflow-tooltip="true" />
<el-table-column label="章节名称" align="center" prop="chapteridDictText" :show-overflow-tooltip="true" />
<!-- <el-table-column label="章节名称" align="center" prop="chapteridDictText" :show-overflow-tooltip="true" /> -->
<el-table-column label="难度" align="center" prop="quLevel" :show-overflow-tooltip="true">
<template #default="scope">
<dict-tag :type="DICT_TYPE.EXAM_QUE_DIFF" :value="scope.row.quLevel" />
</template>
</el-table-column>
<el-table-column label="知识点" align="center" prop="pointNames" :show-overflow-tooltip="true" />
<!-- <el-table-column label="知识点" align="center" prop="pointNames" :show-overflow-tooltip="true" /> -->
<!-- <el-table-column label="审核状态" align="center" prop="audit" :show-overflow-tooltip="true">
<template #default="scope">
<dict-tag :type="DICT_TYPE.QUESTION_AUDIT" :value="scope.row.audit" />
@@ -447,6 +448,8 @@ const handleChange =async () => {
message.warning('请先选中一个原题');
return;
}
console.log(selectedQuestion.value.quId+"selectedQuestion.value.quId")
visibleChange.value = true;
await getList();
};
@@ -519,6 +522,11 @@ const handleRowClick = (row: any) => {
const getList = async () => {
loading.value = true
queryParams.subjectName=selectedQuestion.value.subjectName
queryParams.pointNames=selectedQuestion.value.pointNames
queryParams.chapteridDictText=selectedQuestion.value.chapteridDictText
queryParams.quLevel=selectedQuestion.value.quLevel
queryParams.specialtyName=selectedQuestion.value.specialtyName
queryParams.courseName=selectedQuestion.value.courseName
try {
const data = await QuestionApi.getQuestionlistAnswer(queryParams);
list.value = data.list

View File

@@ -54,7 +54,7 @@
plain
@click="openSet"
>
<Icon icon="ep:set-up" class="mr-5px" /> 抽卷调整
<Icon icon="ep:set-up" class="mr-5px" /> 抽卷方式
</el-button>
<el-button
type="primary"
@@ -117,7 +117,6 @@
link
type="primary"
@click="openLook('look', scope.row.paperId)"
v-hasPermi="['system:sms-channel:update']"
>
查看
</el-button>
@@ -125,15 +124,13 @@
link
type="primary"
@click="openEdit('update', scope.row)"
v-hasPermi="['system:sms-channel:update']"
>
编辑
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.paperId)"
v-hasPermi="['system:sms-channel:delete']"
@click="handleDelete(scope.row)"
>
删除
</el-button>
@@ -344,10 +341,14 @@ const openLook = (type: string, paperId?: number) => {
// 删除操作
const handleDelete = async (id: number) => {
const handleDelete = async (row?: any) => {
if (row?.counts > 0) {
ElMessage.warning('当前试卷使用次数大于0不允许删除');
return;
}
try {
await message.delConfirm();
await PaperApi.removePaper(id);
await PaperApi.removePaper(row.paperId);
message.success(t('common.delSuccess'));
await getList();
} catch (error) {

View File

@@ -5,15 +5,11 @@
<!-- 第一个 tab - 通用参数 -->
<el-tab-pane label="通用参数" name="tab1">
<el-form :model="form" label-width="200px" style="margin-top: 20px;">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="是否显示试题编号">
<el-switch v-model="form.isAnswerId" active-value="0" inactive-value="1" active-text="是"
inactive-text="" @change="handleFormChange" />
</el-form-item>
<!-- 是否使用监考密码验证 -->
<!-- <el-form-item label="是否使用监考密码验证">
<el-form-item label="是否使用监考密码验证">
<el-switch
v-model="form.isExamPassword"
active-value="0"
@@ -21,12 +17,49 @@
active-text=""
inactive-text=""
@change="handleFormChange" />
</el-form-item> -->
</el-form-item>
<!-- 监考密码 -->
<!-- <el-form-item label="监考密码" v-if="form.isExamPassword === '0'">
<el-form-item label="监考密码" v-if="form.isExamPassword === '0'">
<el-input v-model="form.examPassword" placeholder="请输入监考密码" @input="handleFormChange" />
</el-form-item> -->
</el-form-item>
</el-col>
<el-col :span="12">
<!-- 练习成绩保存 -->
<el-form-item label="练习成绩保存">
<el-radio-group v-model="form.saveGrades" @change="handleFormChange">
<el-radio label="0">最高成绩</el-radio>
<el-radio label="1">最新成绩</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<!-- <el-col :span="12">
<el-form-item label="是否显示重答按钮">
<el-switch
v-model="form.isRepeat"
active-value="0"
inactive-value="1"
active-text=""
inactive-text=""
@change="handleFormChange" />
</el-form-item>
</el-col> -->
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="考生答题时是否显示试题编号">
<el-switch v-model="form.isAnswerId" active-value="0" inactive-value="1" active-text="是"
inactive-text="" @change="handleFormChange" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="是否显示试卷编号">
@@ -69,31 +102,8 @@
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<!-- 练习成绩保存 -->
<el-form-item label="练习成绩保存">
<el-radio-group v-model="form.saveGrades" @change="handleFormChange">
<el-radio label="0">最高成绩</el-radio>
<el-radio label="1">最新成绩</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<!-- <el-col :span="12">
<el-form-item label="是否显示重答按钮">
<el-switch
v-model="form.isRepeat"
active-value="0"
inactive-value="1"
active-text=""
inactive-text=""
@change="handleFormChange" />
</el-form-item>
</el-col> -->
<el-col :span="12">
<el-form-item label="是否有测评时长限制">
@@ -101,20 +111,6 @@
@change="handleFormChange" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<!-- <el-col :span="12">
<el-form-item label="是否有测评时长限制">
<el-switch
v-model="form.isTime"
active-value="0"
inactive-value="1"
active-text=""
inactive-text=""
@change="handleFormChange" />
</el-form-item>
</el-col> -->
<el-col :span="12">
<el-form-item label="测评时长">
<el-time-picker v-model="form.examTime" value-format="HH:mm:ss" placeholder="请设置测评时长" class="ele-fluid"
@@ -135,17 +131,31 @@
</el-form-item>
</el-col> -->
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<!-- 禁止学生使用U盘 -->
<el-form-item label="是否显示成绩">
<el-switch v-model="form.isScore" active-value="0" inactive-value="1" active-text="是" inactive-text="否"
@change="handleFormChange" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="是否显示成绩明细">
<el-switch v-model="form.isScoreDetail" active-value="0" inactive-value="1" active-text="是" inactive-text="否"
@change="handleFormChange" />
</el-form-item>
</el-col>
<!-- <el-form-item label="定时检查与学生端联通性,每">
<el-input-number v-model="form.isConnect" label="分钟" @change="handleFormChange" />
<span>分钟传一次,断联直接交卷</span>
</el-form-item> -->
</el-col>
</el-row>
@@ -175,13 +185,7 @@
<span>分钟传一次</span>
</el-form-item>
<!-- 完成考试后是否删除考试目录 -->
<!-- <el-form-item label="完成考试后是否删除考试目录">
<el-radio-group v-model="form.isDel" @change="handleFormChange">
<el-radio label="0"></el-radio>
<el-radio label="1"></el-radio>
</el-radio-group>
</el-form-item> -->
</el-form>
</el-tab-pane>
@@ -225,6 +229,17 @@
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="是否允许复制题干">
<el-switch v-model="form.isCpoy" active-value="0" inactive-value="1" active-text="是" inactive-text="否"
@change="handleFormChange" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-tab-pane>
@@ -261,7 +276,7 @@ const form = ref({
driver: '', // 存放系统盘
directory: '', // 考试目录名称
uploadTime: '', // 上传间隔时间
isDel: '',
isCpoy: '',
isRepeat: '', // 是否删除目录
isAnswer: '',
isLook: '',
@@ -269,7 +284,9 @@ const form = ref({
isFile: '',
isNet: '',
isScreen: '',
warn: ''
warn: '',
isScore:'',
isScoreDetail:'',
})
const activeTab = ref('tab1')

View File

@@ -187,7 +187,7 @@ const removeBatch = async () => {
}
await ElMessageBox.confirm(
'确定要删除选中的人员吗',
'只能删除待考状态的学生,是否确认删除',
'警告',
{
confirmButtonText: '确定',

View File

@@ -196,7 +196,15 @@ const handleDeletes = async () => {
message.error('请至少选择一条数据');
return;
}
await ElMessageBox.confirm(
'只能删除待考状态的学生,是否确认删除?',
'警告',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
);
selectedRows.value = rows.map((d: any) => d.id); // 保存选中的行数据
const deleteData = {