【新增】监控管理试卷任务监控、细节优化
This commit is contained in:
@@ -54,6 +54,8 @@ export const MonitorApi = {
|
||||
|
||||
updateMonitorStatus:async( data)=>{
|
||||
return await request.post({ url: `/exam/monitor/updateMonitorStatus` , data })
|
||||
}
|
||||
|
||||
},
|
||||
getMonitorTaskPage: async (params: any) => {
|
||||
return await request.get({ url: `/exam/monitorTask/page`, params })
|
||||
},
|
||||
}
|
||||
|
||||
@@ -36,11 +36,7 @@ export async function addScheme(data) {
|
||||
* 修改试卷方案
|
||||
*/
|
||||
export async function updateScheme(data) {
|
||||
|
||||
|
||||
return await request.put({ url: '/exam/scheme' , data })
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<el-form label-width="80px" class="px-4 pt-2">
|
||||
<el-form-item label="考试状态">
|
||||
<el-radio-group v-model="selectedStatus">
|
||||
<el-radio :label="'0'">代考</el-radio>
|
||||
<el-radio :label="'0'">待考</el-radio>
|
||||
<el-radio :label="'1'">考试中</el-radio>
|
||||
<el-radio :label="'2'">考试完成</el-radio>
|
||||
</el-radio-group>
|
||||
@@ -17,7 +17,23 @@
|
||||
<el-button type="primary" @click="confirmChange">确认</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog
|
||||
v-model="initDialogVisible"
|
||||
title="试卷任务监控列表"
|
||||
width="90%"
|
||||
top="5vh"
|
||||
class="-mb-15px"
|
||||
:close-on-click-modal="false"
|
||||
:show-close="true"
|
||||
@close="handleNextStepCancel"
|
||||
>
|
||||
|
||||
<taskMonitor @row-clicked="handleTaskSelected" />
|
||||
<template #footer>
|
||||
<el-button @click="handleNextStepCancel">取消</el-button>
|
||||
<el-button type="primary" @click="handleNextStep">下一步</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<ContentWrap>
|
||||
<!-- 搜索工作栏 -->
|
||||
@@ -226,10 +242,22 @@ import download from '@/utils/download'
|
||||
import { MonitorApi, MonitorVO } from '@/api/monitor'
|
||||
import MonitorForm from './MonitorForm.vue'
|
||||
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
||||
import taskMonitor from './task-monitor.vue'
|
||||
import * as ClassApi from '@/api/exam/class'
|
||||
|
||||
import { ref } from 'vue'
|
||||
|
||||
const selectedTaskId = ref<string | null>(null)
|
||||
|
||||
// 接收子组件传递的taskId
|
||||
const handleTaskSelected = (taskId: string) => {
|
||||
queryParams.taskId = taskId
|
||||
console.log('父组件接收到的taskId:', taskId)
|
||||
}
|
||||
/** 监控管理 列表 */
|
||||
defineOptions({ name: 'Monitor' })
|
||||
|
||||
// 新增:初始弹框开关
|
||||
const initDialogVisible = ref(true);
|
||||
// 弹窗开关
|
||||
const dialogVisible = ref(false)
|
||||
const message = useMessage() // 消息弹窗
|
||||
@@ -242,7 +270,8 @@ const classNameList = ref();
|
||||
const queryParams = reactive({
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
monitorId:'',
|
||||
monitorId:undefined,
|
||||
taskId:'',
|
||||
username: undefined,
|
||||
nickname: undefined,
|
||||
taskType:undefined,
|
||||
@@ -264,6 +293,7 @@ const getList = async () => {
|
||||
classNameList.value = await ClassApi.ClassApi.getClassName()
|
||||
try {
|
||||
const data = await MonitorApi.getMonitorPage(queryParams)
|
||||
queryParams.taskId = ''
|
||||
list.value = data.list
|
||||
total.value = data.total
|
||||
} finally {
|
||||
@@ -342,6 +372,7 @@ const openForm = (type: string, id?: number) => {
|
||||
|
||||
ElMessage.success('考试状态更新成功')
|
||||
dialogVisible.value = false
|
||||
getList()
|
||||
}
|
||||
/** 删除按钮操作 */
|
||||
const handleDelete = async (id: number) => {
|
||||
@@ -395,9 +426,20 @@ const fetchTaskList = async (taskType: string) => {
|
||||
console.error('获取试卷任务失败', error)
|
||||
}
|
||||
}
|
||||
const handleNextStep = () => {
|
||||
getList()
|
||||
initDialogVisible.value = false
|
||||
}
|
||||
const handleNextStepCancel = () => {
|
||||
queryParams.taskId = ''
|
||||
getList()
|
||||
initDialogVisible.value = false
|
||||
}
|
||||
|
||||
|
||||
/** 初始化 **/
|
||||
onMounted(() => {
|
||||
getList()
|
||||
|
||||
initDialogVisible.value = true; // 显示初始弹框
|
||||
})
|
||||
</script>
|
||||
284
src/views/monitor/monitor/task-monitor.vue
Normal file
284
src/views/monitor/monitor/task-monitor.vue
Normal file
@@ -0,0 +1,284 @@
|
||||
<template>
|
||||
<!-- 状态选择弹窗 -->
|
||||
<el-dialog v-model="dialogVisible" title="请选择考试状态" width="400px">
|
||||
|
||||
<el-form label-width="80px" class="px-4 pt-2">
|
||||
<el-form-item label="考试状态">
|
||||
<el-radio-group v-model="selectedStatus">
|
||||
<el-radio :label="'0'">待考</el-radio>
|
||||
<el-radio :label="'1'">考试中</el-radio>
|
||||
<el-radio :label="'2'">考试完成</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="confirmChange">确认</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
|
||||
<ContentWrap>
|
||||
<!-- 搜索工作栏 -->
|
||||
<el-form
|
||||
class="-mb-15px"
|
||||
:model="queryParams"
|
||||
ref="queryFormRef"
|
||||
:inline="true"
|
||||
label-width="68px"
|
||||
>
|
||||
<el-form-item label="任务编号" prop="taskNum">
|
||||
<el-input
|
||||
v-model="queryParams.taskNum"
|
||||
placeholder="请输入任务编号"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
class="!w-240px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="任务名称" prop="taskName">
|
||||
<el-input
|
||||
v-model="queryParams.taskName"
|
||||
placeholder="请输入任务名称"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
class="!w-240px"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="考试状态" prop="status">
|
||||
<el-select
|
||||
v-model="queryParams.status"
|
||||
placeholder="请选择考试状态"
|
||||
clearable
|
||||
class="!w-240px"
|
||||
>
|
||||
<el-option label="启用" :value="0" />
|
||||
<el-option label="停用" :value="1" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
|
||||
<el-form-item label="任务类别" prop="taskType">
|
||||
<el-select v-model="queryParams.taskType" placeholder="任务类别" class="!w-240px" @change="fetchTaskList">
|
||||
<el-option
|
||||
v-for="dict in getIntDictOptions(DICT_TYPE.TASK_TYPE)"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<el-form-item>
|
||||
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
|
||||
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
|
||||
<!-- <el-button type="primary" @click="openDialog"><Icon icon="ep:edit" class="mr-5px" />考试状态改变</el-button> -->
|
||||
<!-- <el-button
|
||||
type="primary"
|
||||
plain
|
||||
@click="openForm('create')"
|
||||
|
||||
>
|
||||
<Icon icon="ep:plus" class="mr-5px" /> 新增
|
||||
</el-button> -->
|
||||
<!-- <el-button
|
||||
type="success"
|
||||
plain
|
||||
@click="handleExport"
|
||||
:loading="exportLoading"
|
||||
|
||||
>
|
||||
<Icon icon="ep:download" class="mr-5px" /> 导出
|
||||
</el-button> -->
|
||||
</el-form-item>
|
||||
|
||||
|
||||
</el-form>
|
||||
</ContentWrap>
|
||||
|
||||
<!-- 列表 -->
|
||||
<ContentWrap>
|
||||
<el-table v-loading="loading" :data="list" highlight-current-row ref="tableRef" @row-click="handleRowClick">
|
||||
<el-table-column label="任务编号" align="center" prop="taskNum" />
|
||||
<el-table-column label="任务名称" align="center" prop="taskName" />
|
||||
<el-table-column label="任务模式" align="center" prop="taskType">
|
||||
<template #default="scope">
|
||||
<dict-tag :type="DICT_TYPE.TASK_TYPE" :value="scope.row.taskType" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="考试状态" align="center" prop="status">
|
||||
<template #default="scope">
|
||||
<dict-tag :type="DICT_TYPE.SYS_STATUS" :value="scope.row.status" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="专业" align="center" prop="taskSpecialty" />
|
||||
<el-table-column label="试卷设置" align="center">
|
||||
<template #default="{row}">
|
||||
{{ row.paperCount == 0 ? '未设置': `试卷${row.paperCount}张/${row.paperScore}分/${row.queNum}题` }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
|
||||
<el-table-column label="参与人数" align="center" prop="joinCount" />
|
||||
<el-table-column label="未考人数" align="center" prop="notReadCount" />
|
||||
|
||||
<el-table-column label="考试人数" align="center" prop="haveReadCount" />
|
||||
<el-table-column label="完成人数" align="center" prop="passCount" />
|
||||
</el-table>
|
||||
<!-- 分页 -->
|
||||
<Pagination
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNo"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</ContentWrap>
|
||||
|
||||
<!-- 表单弹窗:添加/修改 -->
|
||||
<!-- <MonitorForm ref="formRef" @success="getList" /> -->
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { dateFormatter } from '@/utils/formatTime'
|
||||
import download from '@/utils/download'
|
||||
import { MonitorApi, MonitorVO } from '@/api/monitor'
|
||||
import MonitorForm from './MonitorForm.vue'
|
||||
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
||||
import * as ClassApi from '@/api/exam/class'
|
||||
import { defineEmits } from 'vue'
|
||||
/** 监控管理 列表 */
|
||||
defineOptions({ name: 'Monitor' })
|
||||
const emit = defineEmits(['row-clicked'])
|
||||
// 弹窗开关
|
||||
const tableRef = ref()
|
||||
const dialogVisible = ref(false)
|
||||
const message = useMessage() // 消息弹窗
|
||||
const { t } = useI18n() // 国际化
|
||||
const selectedStatus = ref<string | null>(null);
|
||||
const loading = ref(true) // 列表的加载中
|
||||
const list = ref<MonitorVO[]>([]) // 列表的数据
|
||||
const total = ref(0) // 列表的总页数
|
||||
const classNameList = ref();
|
||||
const queryParams = reactive({
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
monitorId:undefined,
|
||||
taskNum: undefined,
|
||||
nickname: undefined,
|
||||
taskType:undefined,
|
||||
className: undefined,
|
||||
status: undefined,
|
||||
score: undefined,
|
||||
paperNum: undefined,
|
||||
taskName: undefined,
|
||||
ip: undefined,
|
||||
remainingTime: [],
|
||||
createTime: [],
|
||||
})
|
||||
const queryFormRef = ref() // 搜索的表单
|
||||
const exportLoading = ref(false) // 导出的加载中
|
||||
/** 查询列表 */
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
classNameList.value = await ClassApi.ClassApi.getClassName()
|
||||
try {
|
||||
console.log("进入考试")
|
||||
const data = await MonitorApi.getMonitorTaskPage(queryParams)
|
||||
list.value = data.list
|
||||
total.value = data.total
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 打开弹窗
|
||||
|
||||
const currentRow = ref<any>(null) // 存储当前选中行
|
||||
|
||||
const handleRowClick = (row: any, column: any, event: Event) => {
|
||||
// 如果点击的是操作按钮区域,则不触发选中
|
||||
currentRow.value = row
|
||||
tableRef.value!.setCurrentRow(row) // 高亮选中行
|
||||
selections.value = row.taskId// 将selections设置为只包含当前行的数组
|
||||
emit('row-clicked', row.taskId) // 触发自定义事件
|
||||
}
|
||||
/** 表格选中数据 */
|
||||
const selections = ref([]);
|
||||
const taskList = ref([]);
|
||||
const handleSelectionChange = (rows) => {
|
||||
selections.value = rows;
|
||||
}
|
||||
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.pageNo = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value.resetFields()
|
||||
handleQuery()
|
||||
}
|
||||
|
||||
/** 添加/修改操作 */
|
||||
const formRef = ref()
|
||||
const openForm = (type: string, id?: number) => {
|
||||
formRef.value.open(type, id)
|
||||
}
|
||||
// 提交状态变更
|
||||
const confirmChange = async () => {
|
||||
|
||||
if (selectedStatus.value === null) {
|
||||
ElMessage.error('请选择考试状态');
|
||||
return;
|
||||
}
|
||||
|
||||
const rows = selections.value;
|
||||
|
||||
const monitorIds = rows.map((row: any) => row.monitorId);
|
||||
|
||||
|
||||
await MonitorApi.updateMonitorStatus({
|
||||
monitorIds, // 这是数组
|
||||
status: selectedStatus.value // 这是 0,1,2
|
||||
});
|
||||
|
||||
|
||||
ElMessage.success('考试状态更新成功')
|
||||
dialogVisible.value = false
|
||||
getList()
|
||||
}
|
||||
|
||||
|
||||
const selectedRows = ref<string[]>([]);
|
||||
/** 导出按钮操作 */
|
||||
|
||||
const fetchTaskList = async (taskType: string) => {
|
||||
|
||||
try {
|
||||
const res = await MonitorApi.getPaperTaskList( taskType )
|
||||
taskList.value = res
|
||||
} catch (error) {
|
||||
taskList.value = []
|
||||
console.error('获取试卷任务失败', error)
|
||||
}
|
||||
}
|
||||
// 暴露方法供父组件获取选中行
|
||||
defineExpose({
|
||||
getSelectedTask: () => currentRow.value?.taskId
|
||||
})
|
||||
/** 初始化 **/
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
</script>
|
||||
@@ -87,7 +87,7 @@
|
||||
</el-form-item>
|
||||
|
||||
|
||||
<el-form-item label="排序" prop="sort">
|
||||
<el-form-item label="别名排序" prop="sort">
|
||||
<el-input-number v-model="form.sort" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@@ -168,7 +168,6 @@ const form = ref<{
|
||||
const rules = reactive({
|
||||
spName: [{ required: true, message: '请选择题型', trigger: 'change' }],
|
||||
quLevel: [{ required: true, message: '请选择难度', trigger: 'change' }],
|
||||
sort: [{ required: true, message: '请设置排序', trigger: 'change' }],
|
||||
quTitle: [{ required: true, message: '请输入别名', trigger: 'change' }],
|
||||
pointName: [{ required: true, message: '请选择知识点', trigger: 'change' }],
|
||||
quNumbers: [{ required: true, message: '请输入试题数量', trigger: 'blur' }],
|
||||
@@ -223,11 +222,29 @@ const open = async (type: 'create' | 'update', data?: any) => {
|
||||
sort: undefined,
|
||||
taskSpecialty: props.taskSpecialty
|
||||
}
|
||||
// 清除校验
|
||||
await nextTick()
|
||||
const allKeys = getAllTreeKeys(pointOptions.value).map(String)
|
||||
form.value.pointName = allKeys
|
||||
treeRef.value?.setCheckedKeys(allKeys)
|
||||
}
|
||||
|
||||
// 清除校验
|
||||
await nextTick()
|
||||
formRef.value?.clearValidate?.()
|
||||
|
||||
}
|
||||
function getAllTreeKeys(tree: TreeNode[]): number[] {
|
||||
const keys: number[] = []
|
||||
|
||||
const traverse = (nodes: TreeNode[]) => {
|
||||
for (const node of nodes) {
|
||||
keys.push(node.value)
|
||||
if (node.children?.length) {
|
||||
traverse(node.children)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
traverse(tree)
|
||||
return keys
|
||||
}
|
||||
|
||||
/** --------- 拉取扁平知识点并建树 --------- **/
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<!-- 列表 -->
|
||||
<ContentWrap>
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="方案ID" align="center" prop="taskId" />
|
||||
<!-- <el-table-column label="方案ID" align="center" prop="taskId" /> -->
|
||||
<el-table-column label="题型" align="center" prop="spName" />
|
||||
<el-table-column label="难度" align="center" prop="quLevel">
|
||||
<template #default="scope">
|
||||
@@ -47,14 +47,26 @@
|
||||
<span v-else>未知</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="试题别名" align="center" prop="quTitle"/>
|
||||
|
||||
<!-- <el-table-column label="关键字" align="center" prop="keywords" /> -->
|
||||
<el-table-column label="试题数量" align="center" prop="quNumbers"/>
|
||||
|
||||
<el-table-column label="每题分数" align="center" prop="quScores"/>
|
||||
<el-table-column label="小计分数" align="center" prop="subtotalScore"/>
|
||||
|
||||
<el-table-column label="试题别名" align="center" prop="quTitle"/>
|
||||
<el-table-column label="别名排序" align="center">
|
||||
<template #default="scope">
|
||||
<el-input-number
|
||||
v-model="scope.row.sort"
|
||||
placeholder="请输入排序"
|
||||
size="small"
|
||||
:min="0"
|
||||
style="width: 100px"
|
||||
@change="(val) => handleSortChange(scope.row, val)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="操作" align="center">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
@@ -76,6 +88,11 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- ✅ 总分展示区域 -->
|
||||
<div style="display: flex; justify-content: flex-end; padding: 5px; margin: 10px 0; font-weight: bold;">
|
||||
总分:{{ totalScore }}
|
||||
</div>
|
||||
<!-- 分页 -->
|
||||
<Pagination
|
||||
:total="total"
|
||||
@@ -153,7 +170,40 @@ const queryParams = reactive({
|
||||
taskId: props.taskId,
|
||||
spName:undefined
|
||||
})
|
||||
const totalScore = computed(() => {
|
||||
return list.value.reduce((sum, item) => {
|
||||
// 确保字段存在且为数字
|
||||
const score = parseFloat(item.subtotalScore) || 0;
|
||||
return sum + score;
|
||||
}, 0);
|
||||
});
|
||||
// 排序值修改后自动调用接口
|
||||
// 排序值修改后自动调用接口
|
||||
const handleSortChange = async (row, newValue) => {
|
||||
if (newValue < 0) {
|
||||
message.error('排序不能小于 0')
|
||||
row.sort = 0
|
||||
return
|
||||
}
|
||||
|
||||
// 1. 获取所有 quTitle 相同的项
|
||||
const sameTitleItems = list.value.filter(item => item.quTitle === row.quTitle)
|
||||
|
||||
// 2. 批量更新 sort 值
|
||||
const updateList = sameTitleItems.map(item => ({
|
||||
...item,
|
||||
sort: newValue
|
||||
}))
|
||||
|
||||
try {
|
||||
// 假设后端支持批量更新接口
|
||||
await Promise.all(updateList.map(item => SmsChannelApi.updateScheme(item)))
|
||||
message.success('同别名方案的排序已同步更新')
|
||||
getList()
|
||||
} catch (error) {
|
||||
message.error('排序更新失败')
|
||||
}
|
||||
}
|
||||
/** 查询列表 */
|
||||
const getList = async () => {
|
||||
// 1. 并行拉下拉所需的选项
|
||||
|
||||
@@ -1,211 +0,0 @@
|
||||
<template>
|
||||
|
||||
<ContentWrap>
|
||||
<el-form
|
||||
class="-mb-15px"
|
||||
:model="queryParams"
|
||||
ref="queryFormRef"
|
||||
:inline="true"
|
||||
label-width="68px"
|
||||
>
|
||||
|
||||
<el-form-item>
|
||||
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
|
||||
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
@click="openForm('create')"
|
||||
v-hasPermi="['system:sms-channel:create']"
|
||||
>
|
||||
<Icon icon="ep:plus" class="mr-5px" /> 新增</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ContentWrap>
|
||||
|
||||
<!-- 列表 -->
|
||||
<ContentWrap>
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="试卷编号" align="center" prop="paperId" />
|
||||
<el-table-column label="使用次数" align="center" prop="counts" />
|
||||
<el-table-column label="抽卷方式" align="center" prop="rollUp">
|
||||
<template #default="scope">
|
||||
<span v-if="scope.row.quLevel === '0'">固定</span>
|
||||
<span v-else-if="scope.row.quLevel === '1'">AB卷</span>
|
||||
<span v-else-if="scope.row.quLevel === '2'">随机</span>
|
||||
<span v-else-if="scope.row.quLevel === '3'">自选</span>
|
||||
<span v-else>未知</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="AB卷" align="center" prop="isAb">
|
||||
<template #default="scope">
|
||||
<span v-if="scope.row.quLevel === '0'">A卷</span>
|
||||
<span v-else-if="scope.row.quLevel === '1'">B卷</span>
|
||||
<span v-else>未知</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="是否启用" align="center" prop="status" >
|
||||
<template #default="scope">
|
||||
<dict-tag :type="DICT_TYPE.SYS_YES_NO" :value="scope.row.status" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="操作" align="center">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
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.id)"
|
||||
v-hasPermi="['system:sms-channel:delete']"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页 -->
|
||||
<Pagination
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNo"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</ContentWrap>
|
||||
|
||||
|
||||
|
||||
|
||||
<paper-add v-model="showAdd" :task-Id="taskId" :task-specialty="taskSpecialty" />
|
||||
<paper-edit v-model="showEdit" :data="current" />
|
||||
<!-- <paper-look v-model="showLook" :paper-id="paperId" /> -->
|
||||
<paper-set v-model="showSet" :task-Id="taskId" />
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
||||
|
||||
import * as SmsChannelApi from '@/api/system/paper';
|
||||
import PaperEdit from './components/step-edit.vue';
|
||||
import PaperAdd from './components/step-add.vue';
|
||||
import PaperLook from './components/step-look.vue';
|
||||
import PaperSet from './components/step-set.vue';
|
||||
import PaperSearch from './components/step-search.vue';
|
||||
import { pagePapers, removePapers, exportPapers } from '@/api/system/paper';
|
||||
|
||||
|
||||
|
||||
defineOptions({ name: 'SystemPaper' });
|
||||
const props = defineProps({
|
||||
taskSpecialty: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
taskId: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
|
||||
const { t } = useI18n() // 国际化
|
||||
const message = useMessage() // 消息弹窗
|
||||
|
||||
|
||||
/** 当前编辑数据 */
|
||||
const current = ref<object>();
|
||||
|
||||
/** 是否显示编辑弹窗 */
|
||||
const showEdit = ref(false);
|
||||
|
||||
const showLook = ref(false);
|
||||
|
||||
const showAdd = ref(false);
|
||||
|
||||
const showSet = ref(false);
|
||||
|
||||
|
||||
const smsChannelFormRef = ref()
|
||||
const taskEditRef = ref()
|
||||
const taskAddRef = ref()
|
||||
const taskTempRef = ref()
|
||||
|
||||
|
||||
|
||||
const loading = ref(false) // 列表的加载中
|
||||
const total = ref(0) // 列表的总页数
|
||||
const list = ref([]) // 列表的数据
|
||||
const queryFormRef = ref() // 搜索的表单
|
||||
const queryParams = reactive({
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
signature: undefined,
|
||||
status: undefined,
|
||||
createTime: []
|
||||
})
|
||||
|
||||
/** 查询列表 */
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await SmsChannelApi.pagePapers(queryParams)
|
||||
console.log(res)
|
||||
list.value = res
|
||||
total.value = res.total
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.pageNo = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value.resetFields()
|
||||
handleQuery()
|
||||
}
|
||||
|
||||
/** 添加/修改操作 */
|
||||
const formRef = ref();
|
||||
const openForm = (type: string, id?: number) => {
|
||||
showAdd.value = true
|
||||
taskAddRef.value?.open(type, id)
|
||||
}
|
||||
|
||||
const openEdit = (type: string, row?: object) => {
|
||||
showEdit.value = true
|
||||
current.value = row
|
||||
console.log( current.value )
|
||||
taskEditRef.value?.open(type, row)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** 删除按钮操作 */
|
||||
const handleDelete = async (id: number) => {
|
||||
try {
|
||||
// 删除的二次确认
|
||||
await message.delConfirm()
|
||||
// 发起删除
|
||||
await SmsChannelApi.removePaper(id)
|
||||
message.success(t('common.delSuccess'))
|
||||
// 刷新列表
|
||||
await getList()
|
||||
} catch {}
|
||||
}
|
||||
|
||||
/** 初始化 **/
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
</script>
|
||||
@@ -74,7 +74,7 @@
|
||||
|
||||
<!-- 多选列 -->
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column label="试卷id" align="center" prop="paperId" />
|
||||
<!-- <el-table-column label="试卷id" align="center" prop="paperId" /> -->
|
||||
<el-table-column label="试卷编号" align="center" prop="num" />
|
||||
<el-table-column label="使用次数" align="center" prop="counts" />
|
||||
<el-table-column label="抽卷方式" align="center" prop="rollUp">
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
label-width="80px"
|
||||
@submit.prevent=""
|
||||
>
|
||||
<el-form-item label="任务编号" prop="taskNum">
|
||||
<el-input clearable v-model="form.taskNum" placeholder="请输入编号" disabled/>
|
||||
</el-form-item>
|
||||
<el-form-item label="任务名称" prop="taskName">
|
||||
<el-input
|
||||
clearable
|
||||
@@ -124,6 +127,7 @@ const specialtyOptions = ref([]);
|
||||
const [form, resetFields, assignFields] = useFormData({
|
||||
taskId: void 0,
|
||||
taskName: '',
|
||||
taskNum:'',
|
||||
taskSpecialty: '',
|
||||
taskType: '1',
|
||||
isTemplate: '',
|
||||
@@ -203,6 +207,23 @@ const fetchSpecialtyOptions = async () => {
|
||||
resetFields();
|
||||
isUpdate.value = false;
|
||||
}
|
||||
// 设置批次为 当前时间 + 5位随机数
|
||||
const now = new Date();
|
||||
const pad = (n) => n.toString().padStart(2, '0');
|
||||
const datetimeStr = [
|
||||
now.getFullYear(),
|
||||
pad(now.getMonth() + 1),
|
||||
pad(now.getDate()),
|
||||
pad(now.getHours()),
|
||||
pad(now.getMinutes()),
|
||||
pad(now.getSeconds())
|
||||
].join('');
|
||||
|
||||
const randomNum = Math.floor(Math.random() * 100000).toString().padStart(5, '0');
|
||||
//taskNum 赋值 randomNum
|
||||
|
||||
// 把 taskNum 设置为当前时间+随机数
|
||||
form.taskNum = `${datetimeStr}${randomNum}`;
|
||||
nextTick(() => {
|
||||
nextTick(() => {
|
||||
formRef.value?.clearValidate?.();
|
||||
@@ -212,5 +233,5 @@ const fetchSpecialtyOptions = async () => {
|
||||
onMounted(() => {
|
||||
fetchSpecialtyOptions();
|
||||
});
|
||||
|
||||
defineExpose({ handleOpen })
|
||||
</script>
|
||||
@@ -73,6 +73,7 @@
|
||||
<ContentWrap>
|
||||
<el-table v-loading="loading" :data="list" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column label="任务编号" align="center" prop="taskNum" />
|
||||
<el-table-column label="任务名称" align="center" prop="taskName" />
|
||||
<el-table-column label="专业" align="center" prop="taskSpecialty" />
|
||||
<el-table-column label="试卷任务模式" align="center" prop="taskType">
|
||||
@@ -240,14 +241,19 @@ const handleSelectionChange = (rows) => {
|
||||
const formRef = ref();
|
||||
const openForm = (type: string, id?: number) => {
|
||||
showAdd.value = true
|
||||
taskAddRef.value?.open(type, id)
|
||||
|
||||
nextTick(() => {
|
||||
taskAddRef.value?.open(type, id)
|
||||
});
|
||||
}
|
||||
|
||||
const openEdit = (type: string, row?: object) => {
|
||||
showEdit.value = true
|
||||
current.value = row
|
||||
console.log( current.value )
|
||||
taskEditRef.value?.open(type, row)
|
||||
nextTick(() => {
|
||||
taskEditRef.value?.open(type, row)
|
||||
});
|
||||
}
|
||||
|
||||
const openBank = () => {
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
</el-form-item>
|
||||
|
||||
|
||||
<el-form-item label="排序" prop="sort">
|
||||
<el-form-item label="别名排序" prop="sort">
|
||||
<el-input-number v-model="form.sort" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@@ -223,11 +223,29 @@ const open = async (type: 'create' | 'update', data?: any) => {
|
||||
sort: undefined,
|
||||
taskSpecialty: props.taskSpecialty
|
||||
}
|
||||
// 清除校验
|
||||
await nextTick()
|
||||
const allKeys = getAllTreeKeys(pointOptions.value).map(String)
|
||||
form.value.pointName = allKeys
|
||||
treeRef.value?.setCheckedKeys(allKeys)
|
||||
}
|
||||
|
||||
// 清除校验
|
||||
await nextTick()
|
||||
formRef.value?.clearValidate?.()
|
||||
|
||||
}
|
||||
function getAllTreeKeys(tree: TreeNode[]): number[] {
|
||||
const keys: number[] = []
|
||||
|
||||
const traverse = (nodes: TreeNode[]) => {
|
||||
for (const node of nodes) {
|
||||
keys.push(node.value)
|
||||
if (node.children?.length) {
|
||||
traverse(node.children)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
traverse(tree)
|
||||
return keys
|
||||
}
|
||||
|
||||
/** --------- 拉取扁平知识点并建树 --------- **/
|
||||
|
||||
@@ -47,14 +47,24 @@
|
||||
<span v-else>未知</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="试题别名" align="center" prop="quTitle"/>
|
||||
|
||||
<!-- <el-table-column label="关键字" align="center" prop="keywords" /> -->
|
||||
<el-table-column label="试题数量" align="center" prop="quNumbers"/>
|
||||
|
||||
<el-table-column label="每题分数" align="center" prop="quScores"/>
|
||||
<el-table-column label="小计分数" align="center" prop="subtotalScore"/>
|
||||
|
||||
<el-table-column label="试题别名" align="center" prop="quTitle"/>
|
||||
<el-table-column label="别名排序" align="center">
|
||||
<template #default="scope">
|
||||
<el-input-number
|
||||
v-model="scope.row.sort"
|
||||
placeholder="请输入排序"
|
||||
size="small"
|
||||
:min="0"
|
||||
style="width: 100px"
|
||||
@change="(val) => handleSortChange(scope.row, val)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
@@ -76,6 +86,10 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- ✅ 总分展示区域 -->
|
||||
<div style="display: flex; justify-content: flex-end; padding: 5px; margin: 10px 0; font-weight: bold;">
|
||||
总分:{{ totalScore }}
|
||||
</div>
|
||||
<!-- 分页 -->
|
||||
<Pagination
|
||||
:total="total"
|
||||
@@ -153,7 +167,39 @@ const queryParams = reactive({
|
||||
taskId: props.taskId ,
|
||||
spName:undefined
|
||||
})
|
||||
const totalScore = computed(() => {
|
||||
return list.value.reduce((sum, item) => {
|
||||
// 确保字段存在且为数字
|
||||
const score = parseFloat(item.subtotalScore) || 0;
|
||||
return sum + score;
|
||||
}, 0);
|
||||
});
|
||||
// 排序值修改后自动调用接口
|
||||
const handleSortChange = async (row, newValue) => {
|
||||
if (newValue < 0) {
|
||||
message.error('排序不能小于 0')
|
||||
row.sort = 0
|
||||
return
|
||||
}
|
||||
|
||||
// 1. 获取所有 quTitle 相同的项
|
||||
const sameTitleItems = list.value.filter(item => item.quTitle === row.quTitle)
|
||||
|
||||
// 2. 批量更新 sort 值
|
||||
const updateList = sameTitleItems.map(item => ({
|
||||
...item,
|
||||
sort: newValue
|
||||
}))
|
||||
|
||||
try {
|
||||
// 假设后端支持批量更新接口
|
||||
await Promise.all(updateList.map(item => SmsChannelApi.updateScheme(item)))
|
||||
message.success('同别名方案的排序已同步更新')
|
||||
getList()
|
||||
} catch (error) {
|
||||
message.error('排序更新失败')
|
||||
}
|
||||
}
|
||||
/** 查询列表 */
|
||||
const getList = async () => {
|
||||
// 1. 并行拉下拉所需的选项
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
label-width="80px"
|
||||
@submit.prevent=""
|
||||
>
|
||||
|
||||
<el-form-item label="任务编号" prop="taskNum">
|
||||
<el-input clearable v-model="form.taskNum" placeholder="请输入编号" disabled/>
|
||||
</el-form-item>
|
||||
<el-form-item label="任务名称" prop="taskName">
|
||||
<el-input
|
||||
clearable
|
||||
@@ -124,6 +128,7 @@ const specialtyOptions = ref([]);
|
||||
const [form, resetFields, assignFields] = useFormData({
|
||||
taskId: void 0,
|
||||
taskName: '',
|
||||
taskNum:'',
|
||||
taskSpecialty: '',
|
||||
taskType: '6',
|
||||
isTemplate: '',
|
||||
@@ -195,14 +200,32 @@ const fetchSpecialtyOptions = async () => {
|
||||
};
|
||||
|
||||
/** 弹窗打开事件 */
|
||||
const handleOpen = () => {
|
||||
if (props.data) {
|
||||
assignFields(props.data);
|
||||
isUpdate.value = true;
|
||||
} else {
|
||||
resetFields();
|
||||
isUpdate.value = false;
|
||||
}
|
||||
const open = () => {
|
||||
// if (props.data) {
|
||||
// assignFields(props.data);
|
||||
// isUpdate.value = true;
|
||||
// } else {
|
||||
// resetFields();
|
||||
// isUpdate.value = false;
|
||||
// }
|
||||
|
||||
// 设置批次为 当前时间 + 5位随机数
|
||||
const now = new Date();
|
||||
const pad = (n) => n.toString().padStart(2, '0');
|
||||
const datetimeStr = [
|
||||
now.getFullYear(),
|
||||
pad(now.getMonth() + 1),
|
||||
pad(now.getDate()),
|
||||
pad(now.getHours()),
|
||||
pad(now.getMinutes()),
|
||||
pad(now.getSeconds())
|
||||
].join('');
|
||||
|
||||
const randomNum = Math.floor(Math.random() * 100000).toString().padStart(5, '0');
|
||||
//taskNum 赋值 randomNum
|
||||
|
||||
// 把 taskNum 设置为当前时间+随机数
|
||||
form.taskNum = `${datetimeStr}${randomNum}`;
|
||||
nextTick(() => {
|
||||
nextTick(() => {
|
||||
formRef.value?.clearValidate?.();
|
||||
@@ -212,5 +235,5 @@ const fetchSpecialtyOptions = async () => {
|
||||
onMounted(() => {
|
||||
fetchSpecialtyOptions();
|
||||
});
|
||||
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
@@ -73,6 +73,7 @@
|
||||
<ContentWrap>
|
||||
<el-table v-loading="loading" :data="list" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column label="任务编号" align="center" prop="taskNum" />
|
||||
<el-table-column label="任务名称" align="center" prop="taskName" />
|
||||
<el-table-column label="专业" align="center" prop="taskSpecialty" />
|
||||
<el-table-column label="试卷任务模式" align="center" prop="taskType">
|
||||
@@ -222,7 +223,9 @@ const handleSelectionChange = (rows) => {
|
||||
const formRef = ref();
|
||||
const openForm = (type: string, id?: number) => {
|
||||
showAdd.value = true
|
||||
taskAddRef.value?.open(type, id)
|
||||
nextTick(() => {
|
||||
taskAddRef.value?.open(type, id)
|
||||
});
|
||||
}
|
||||
|
||||
/** 状态切换处理 */
|
||||
@@ -248,7 +251,9 @@ const openEdit = (type: string, row?: object) => {
|
||||
showEdit.value = true
|
||||
current.value = row
|
||||
console.log( current.value )
|
||||
taskEditRef.value?.open(type, row)
|
||||
nextTick(() => {
|
||||
taskEditRef.value?.open(type, row)
|
||||
});
|
||||
}
|
||||
|
||||
const openBank = () => {
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
</el-form-item>
|
||||
|
||||
|
||||
<el-form-item label="排序" prop="sort">
|
||||
<el-form-item label="别名排序" prop="sort">
|
||||
<el-input-number v-model="form.sort" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@@ -223,13 +223,30 @@ const open = async (type: 'create' | 'update', data?: any) => {
|
||||
sort: undefined,
|
||||
taskSpecialty: props.taskSpecialty
|
||||
}
|
||||
// 清除校验
|
||||
await nextTick()
|
||||
const allKeys = getAllTreeKeys(pointOptions.value).map(String)
|
||||
form.value.pointName = allKeys
|
||||
treeRef.value?.setCheckedKeys(allKeys)
|
||||
}
|
||||
|
||||
// 清除校验
|
||||
await nextTick()
|
||||
formRef.value?.clearValidate?.()
|
||||
}
|
||||
|
||||
}
|
||||
function getAllTreeKeys(tree: TreeNode[]): number[] {
|
||||
const keys: number[] = []
|
||||
|
||||
const traverse = (nodes: TreeNode[]) => {
|
||||
for (const node of nodes) {
|
||||
keys.push(node.value)
|
||||
if (node.children?.length) {
|
||||
traverse(node.children)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
traverse(tree)
|
||||
return keys
|
||||
}
|
||||
/** --------- 拉取扁平知识点并建树 --------- **/
|
||||
async function loadPointTree() {
|
||||
try {
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<!-- 列表 -->
|
||||
<ContentWrap>
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="方案ID" align="center" prop="taskId" />
|
||||
<!-- <el-table-column label="方案ID" align="center" prop="taskId" /> -->
|
||||
<el-table-column label="题型" align="center" prop="spName" />
|
||||
<el-table-column label="难度" align="center" prop="quLevel">
|
||||
<template #default="scope">
|
||||
@@ -47,14 +47,23 @@
|
||||
<span v-else>未知</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="试题别名" align="center" prop="quTitle"/>
|
||||
<!-- <el-table-column label="关键字" align="center" prop="keywords" /> -->
|
||||
<el-table-column label="试题数量" align="center" prop="quNumbers"/>
|
||||
|
||||
<el-table-column label="每题分数" align="center" prop="quScores"/>
|
||||
<el-table-column label="小计分数" align="center" prop="subtotalScore"/>
|
||||
|
||||
<el-table-column label="试题别名" align="center" prop="quTitle"/>
|
||||
<el-table-column label="别名排序" align="center">
|
||||
<template #default="scope">
|
||||
<el-input-number
|
||||
v-model="scope.row.sort"
|
||||
placeholder="请输入排序"
|
||||
size="small"
|
||||
:min="0"
|
||||
style="width: 100px"
|
||||
@change="(val) => handleSortChange(scope.row, val)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
@@ -76,6 +85,10 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- ✅ 总分展示区域 -->
|
||||
<div style="display: flex; justify-content: flex-end; padding: 5px; margin: 10px 0; font-weight: bold;">
|
||||
总分:{{ totalScore }}
|
||||
</div>
|
||||
<!-- 分页 -->
|
||||
<Pagination
|
||||
:total="total"
|
||||
@@ -199,8 +212,38 @@ const openEdit = (type: string, row?: object) => {
|
||||
})
|
||||
}
|
||||
|
||||
const totalScore = computed(() => {
|
||||
return list.value.reduce((sum, item) => {
|
||||
// 确保字段存在且为数字
|
||||
const score = parseFloat(item.subtotalScore) || 0;
|
||||
return sum + score;
|
||||
}, 0);
|
||||
});
|
||||
// 排序值修改后自动调用接口
|
||||
const handleSortChange = async (row, newValue) => {
|
||||
if (newValue < 0) {
|
||||
message.error('排序不能小于 0')
|
||||
row.sort = 0
|
||||
return
|
||||
}
|
||||
// 1. 获取所有 quTitle 相同的项
|
||||
const sameTitleItems = list.value.filter(item => item.quTitle === row.quTitle)
|
||||
|
||||
// 2. 批量更新 sort 值
|
||||
const updateList = sameTitleItems.map(item => ({
|
||||
...item,
|
||||
sort: newValue
|
||||
}))
|
||||
|
||||
try {
|
||||
// 假设后端支持批量更新接口
|
||||
await Promise.all(updateList.map(item => SmsChannelApi.updateScheme(item)))
|
||||
message.success('同别名方案的排序已同步更新')
|
||||
getList()
|
||||
} catch (error) {
|
||||
message.error('排序更新失败')
|
||||
}
|
||||
}
|
||||
/** 删除按钮操作 */
|
||||
const handleDelete = async (id: number) => {
|
||||
try {
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
label-width="80px"
|
||||
@submit.prevent=""
|
||||
>
|
||||
<el-form-item label="任务编号" prop="taskNum">
|
||||
<el-input clearable v-model="form.taskNum" placeholder="请输入编号" disabled/>
|
||||
</el-form-item>
|
||||
<el-form-item label="任务名称" prop="taskName">
|
||||
<el-input
|
||||
clearable
|
||||
@@ -124,6 +127,7 @@ const specialtyOptions = ref([]);
|
||||
const [form, resetFields, assignFields] = useFormData({
|
||||
taskId: void 0,
|
||||
taskName: '',
|
||||
taskNum:'',
|
||||
taskSpecialty: '',
|
||||
taskType: '2',
|
||||
isTemplate: '',
|
||||
@@ -196,13 +200,30 @@ const fetchSpecialtyOptions = async () => {
|
||||
|
||||
/** 弹窗打开事件 */
|
||||
const handleOpen = () => {
|
||||
if (props.data) {
|
||||
assignFields(props.data);
|
||||
isUpdate.value = true;
|
||||
} else {
|
||||
resetFields();
|
||||
isUpdate.value = false;
|
||||
}
|
||||
// if (props.data) {
|
||||
// assignFields(props.data);
|
||||
// isUpdate.value = true;
|
||||
// } else {
|
||||
// resetFields();
|
||||
// isUpdate.value = false;
|
||||
// }
|
||||
// 设置批次为 当前时间 + 5位随机数
|
||||
const now = new Date();
|
||||
const pad = (n) => n.toString().padStart(2, '0');
|
||||
const datetimeStr = [
|
||||
now.getFullYear(),
|
||||
pad(now.getMonth() + 1),
|
||||
pad(now.getDate()),
|
||||
pad(now.getHours()),
|
||||
pad(now.getMinutes()),
|
||||
pad(now.getSeconds())
|
||||
].join('');
|
||||
|
||||
const randomNum = Math.floor(Math.random() * 100000).toString().padStart(5, '0');
|
||||
//taskNum 赋值 randomNum
|
||||
|
||||
// 把 taskNum 设置为当前时间+随机数
|
||||
form.taskNum = `${datetimeStr}${randomNum}`;
|
||||
nextTick(() => {
|
||||
nextTick(() => {
|
||||
formRef.value?.clearValidate?.();
|
||||
@@ -212,5 +233,5 @@ const fetchSpecialtyOptions = async () => {
|
||||
onMounted(() => {
|
||||
fetchSpecialtyOptions();
|
||||
});
|
||||
|
||||
defineExpose({ handleOpen })
|
||||
</script>
|
||||
@@ -73,6 +73,7 @@
|
||||
<ContentWrap>
|
||||
<el-table v-loading="loading" :data="list" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column label="任务编号" align="center" prop="taskNum" />
|
||||
<el-table-column label="任务名称" align="center" prop="taskName" />
|
||||
<el-table-column label="专业" align="center" prop="taskSpecialty" />
|
||||
<el-table-column label="试卷任务模式" align="center" prop="taskType">
|
||||
@@ -222,7 +223,11 @@ const handleSelectionChange = (rows) => {
|
||||
const formRef = ref();
|
||||
const openForm = (type: string, id?: number) => {
|
||||
showAdd.value = true
|
||||
taskAddRef.value?.open(type, id)
|
||||
|
||||
nextTick(() => {
|
||||
taskAddRef.value?.open(type, id)
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/** 状态切换处理 */
|
||||
@@ -248,7 +253,10 @@ const openEdit = (type: string, row?: object) => {
|
||||
showEdit.value = true
|
||||
current.value = row
|
||||
console.log( current.value )
|
||||
taskEditRef.value?.open(type, row)
|
||||
nextTick(() => {
|
||||
taskEditRef.value?.open(type, row)
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
const openBank = () => {
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
</el-form-item>
|
||||
|
||||
|
||||
<el-form-item label="排序" prop="sort">
|
||||
<el-form-item label="别名排序" prop="sort">
|
||||
<el-input-number v-model="form.sort" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@@ -223,11 +223,29 @@ const open = async (type: 'create' | 'update', data?: any) => {
|
||||
sort: undefined,
|
||||
taskSpecialty: props.taskSpecialty
|
||||
}
|
||||
// 清除校验
|
||||
await nextTick()
|
||||
const allKeys = getAllTreeKeys(pointOptions.value).map(String)
|
||||
form.value.pointName = allKeys
|
||||
treeRef.value?.setCheckedKeys(allKeys)
|
||||
}
|
||||
|
||||
// 清除校验
|
||||
await nextTick()
|
||||
formRef.value?.clearValidate?.()
|
||||
|
||||
}
|
||||
function getAllTreeKeys(tree: TreeNode[]): number[] {
|
||||
const keys: number[] = []
|
||||
|
||||
const traverse = (nodes: TreeNode[]) => {
|
||||
for (const node of nodes) {
|
||||
keys.push(node.value)
|
||||
if (node.children?.length) {
|
||||
traverse(node.children)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
traverse(tree)
|
||||
return keys
|
||||
}
|
||||
|
||||
/** --------- 拉取扁平知识点并建树 --------- **/
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<!-- 列表 -->
|
||||
<ContentWrap>
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="方案ID" align="center" prop="taskId" />
|
||||
<!-- <el-table-column label="方案ID" align="center" prop="taskId" /> -->
|
||||
<el-table-column label="题型" align="center" prop="spName" />
|
||||
<el-table-column label="难度" align="center" prop="quLevel">
|
||||
<template #default="scope">
|
||||
@@ -47,14 +47,25 @@
|
||||
<span v-else>未知</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="试题别名" align="center" prop="quTitle"/>
|
||||
|
||||
<!-- <el-table-column label="关键字" align="center" prop="keywords" /> -->
|
||||
<el-table-column label="试题数量" align="center" prop="quNumbers"/>
|
||||
|
||||
<el-table-column label="每题分数" align="center" prop="quScores"/>
|
||||
<el-table-column label="小计分数" align="center" prop="subtotalScore"/>
|
||||
|
||||
<el-table-column label="试题别名" align="center" prop="quTitle"/>
|
||||
<el-table-column label="别名排序" align="center">
|
||||
<template #default="scope">
|
||||
<el-input-number
|
||||
v-model="scope.row.sort"
|
||||
placeholder="请输入排序"
|
||||
size="small"
|
||||
:min="0"
|
||||
style="width: 100px"
|
||||
@change="(val) => handleSortChange(scope.row, val)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
@@ -76,6 +87,10 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div style="display: flex; justify-content: flex-end; padding: 5px; margin: 10px 0; font-weight: bold;">
|
||||
总分:{{ totalScore }}
|
||||
</div>
|
||||
<!-- 分页 -->
|
||||
<Pagination
|
||||
:total="total"
|
||||
@@ -198,8 +213,38 @@ const openEdit = (type: string, row?: object) => {
|
||||
taskEditRef.value?.open(type, row)
|
||||
})
|
||||
}
|
||||
const totalScore = computed(() => {
|
||||
return list.value.reduce((sum, item) => {
|
||||
// 确保字段存在且为数字
|
||||
const score = parseFloat(item.subtotalScore) || 0;
|
||||
return sum + score;
|
||||
}, 0);
|
||||
});
|
||||
// 排序值修改后自动调用接口
|
||||
const handleSortChange = async (row, newValue) => {
|
||||
if (newValue < 0) {
|
||||
message.error('排序不能小于 0')
|
||||
row.sort = 0
|
||||
return
|
||||
}
|
||||
// 1. 获取所有 quTitle 相同的项
|
||||
const sameTitleItems = list.value.filter(item => item.quTitle === row.quTitle)
|
||||
|
||||
// 2. 批量更新 sort 值
|
||||
const updateList = sameTitleItems.map(item => ({
|
||||
...item,
|
||||
sort: newValue
|
||||
}))
|
||||
|
||||
try {
|
||||
// 假设后端支持批量更新接口
|
||||
await Promise.all(updateList.map(item => SmsChannelApi.updateScheme(item)))
|
||||
message.success('同别名方案的排序已同步更新')
|
||||
getList()
|
||||
} catch (error) {
|
||||
message.error('排序更新失败')
|
||||
}
|
||||
}
|
||||
|
||||
/** 删除按钮操作 */
|
||||
const handleDelete = async (id: number) => {
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
label-width="80px"
|
||||
@submit.prevent=""
|
||||
>
|
||||
<el-form-item label="任务编号" prop="taskNum">
|
||||
<el-input clearable v-model="form.taskNum" placeholder="请输入编号" disabled/>
|
||||
</el-form-item>
|
||||
<el-form-item label="任务名称" prop="taskName">
|
||||
<el-input
|
||||
clearable
|
||||
@@ -124,6 +127,7 @@ const specialtyOptions = ref([]);
|
||||
const [form, resetFields, assignFields] = useFormData({
|
||||
taskId: void 0,
|
||||
taskName: '',
|
||||
taskNum:'',
|
||||
taskSpecialty: '',
|
||||
taskType: '5',
|
||||
isTemplate: '',
|
||||
@@ -196,13 +200,31 @@ const fetchSpecialtyOptions = async () => {
|
||||
|
||||
/** 弹窗打开事件 */
|
||||
const handleOpen = () => {
|
||||
if (props.data) {
|
||||
assignFields(props.data);
|
||||
isUpdate.value = true;
|
||||
} else {
|
||||
resetFields();
|
||||
isUpdate.value = false;
|
||||
}
|
||||
// if (props.data) {
|
||||
// assignFields(props.data);
|
||||
// isUpdate.value = true;
|
||||
// } else {
|
||||
// resetFields();
|
||||
// isUpdate.value = false;
|
||||
// }
|
||||
|
||||
// 设置批次为 当前时间 + 5位随机数
|
||||
const now = new Date();
|
||||
const pad = (n) => n.toString().padStart(2, '0');
|
||||
const datetimeStr = [
|
||||
now.getFullYear(),
|
||||
pad(now.getMonth() + 1),
|
||||
pad(now.getDate()),
|
||||
pad(now.getHours()),
|
||||
pad(now.getMinutes()),
|
||||
pad(now.getSeconds())
|
||||
].join('');
|
||||
|
||||
const randomNum = Math.floor(Math.random() * 100000).toString().padStart(5, '0');
|
||||
//taskNum 赋值 randomNum
|
||||
|
||||
// 把 taskNum 设置为当前时间+随机数
|
||||
form.taskNum = `${datetimeStr}${randomNum}`;
|
||||
nextTick(() => {
|
||||
nextTick(() => {
|
||||
formRef.value?.clearValidate?.();
|
||||
@@ -212,5 +234,5 @@ const fetchSpecialtyOptions = async () => {
|
||||
onMounted(() => {
|
||||
fetchSpecialtyOptions();
|
||||
});
|
||||
|
||||
defineExpose({ handleOpen })
|
||||
</script>
|
||||
@@ -73,6 +73,7 @@
|
||||
<ContentWrap>
|
||||
<el-table v-loading="loading" :data="list" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column label="任务编号" align="center" prop="taskNum" />
|
||||
<el-table-column label="任务名称" align="center" prop="taskName" />
|
||||
<el-table-column label="专业" align="center" prop="taskSpecialty" />
|
||||
<el-table-column label="试卷任务模式" align="center" prop="taskType">
|
||||
@@ -222,7 +223,10 @@ const handleSelectionChange = (rows) => {
|
||||
const formRef = ref();
|
||||
const openForm = (type: string, id?: number) => {
|
||||
showAdd.value = true
|
||||
taskAddRef.value?.open(type, id)
|
||||
|
||||
nextTick(() => {
|
||||
taskAddRef.value?.open(type, id)
|
||||
});
|
||||
}
|
||||
|
||||
/** 状态切换处理 */
|
||||
@@ -248,7 +252,10 @@ const openEdit = (type: string, row?: object) => {
|
||||
showEdit.value = true
|
||||
current.value = row
|
||||
console.log( current.value )
|
||||
taskEditRef.value?.open(type, row)
|
||||
|
||||
nextTick(() => {
|
||||
taskEditRef.value?.open(type, row)
|
||||
});
|
||||
}
|
||||
|
||||
const openBank = () => {
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
</el-form-item>
|
||||
|
||||
|
||||
<el-form-item label="排序" prop="sort">
|
||||
<el-form-item label="别名排序" prop="sort">
|
||||
<el-input-number v-model="form.sort" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@@ -223,11 +223,27 @@ const open = async (type: 'create' | 'update', data?: any) => {
|
||||
sort: undefined,
|
||||
taskSpecialty: props.taskSpecialty
|
||||
}
|
||||
// 清除校验
|
||||
await nextTick()
|
||||
const allKeys = getAllTreeKeys(pointOptions.value).map(String)
|
||||
form.value.pointName = allKeys
|
||||
treeRef.value?.setCheckedKeys(allKeys)
|
||||
}
|
||||
}
|
||||
function getAllTreeKeys(tree: TreeNode[]): number[] {
|
||||
const keys: number[] = []
|
||||
|
||||
const traverse = (nodes: TreeNode[]) => {
|
||||
for (const node of nodes) {
|
||||
keys.push(node.value)
|
||||
if (node.children?.length) {
|
||||
traverse(node.children)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 清除校验
|
||||
await nextTick()
|
||||
formRef.value?.clearValidate?.()
|
||||
traverse(tree)
|
||||
return keys
|
||||
}
|
||||
|
||||
/** --------- 拉取扁平知识点并建树 --------- **/
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<!-- 列表 -->
|
||||
<ContentWrap>
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="方案ID" align="center" prop="taskId" />
|
||||
<!-- <el-table-column label="方案ID" align="center" prop="taskId" /> -->
|
||||
<el-table-column label="题型" align="center" prop="spName" />
|
||||
<el-table-column label="难度" align="center" prop="quLevel">
|
||||
<template #default="scope">
|
||||
@@ -47,14 +47,23 @@
|
||||
<span v-else>未知</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="试题别名" align="center" prop="quTitle"/>
|
||||
|
||||
<!-- <el-table-column label="关键字" align="center" prop="keywords" /> -->
|
||||
<el-table-column label="试题数量" align="center" prop="quNumbers"/>
|
||||
|
||||
<el-table-column label="每题分数" align="center" prop="quScores"/>
|
||||
<el-table-column label="小计分数" align="center" prop="subtotalScore"/>
|
||||
|
||||
<el-table-column label="试题别名" align="center" prop="quTitle"/>
|
||||
<el-table-column label="别名排序" align="center">
|
||||
<template #default="scope">
|
||||
<el-input-number
|
||||
v-model="scope.row.sort"
|
||||
placeholder="请输入排序"
|
||||
size="small"
|
||||
:min="0"
|
||||
style="width: 100px"
|
||||
@change="(val) => handleSortChange(scope.row, val)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
@@ -76,6 +85,10 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div style="display: flex; justify-content: flex-end; padding: 5px; margin: 10px 0; font-weight: bold;">
|
||||
总分:{{ totalScore }}
|
||||
</div>
|
||||
<!-- 分页 -->
|
||||
<Pagination
|
||||
:total="total"
|
||||
@@ -172,7 +185,38 @@ const getList = async () => {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
const totalScore = computed(() => {
|
||||
return list.value.reduce((sum, item) => {
|
||||
// 确保字段存在且为数字
|
||||
const score = parseFloat(item.subtotalScore) || 0;
|
||||
return sum + score;
|
||||
}, 0);
|
||||
});
|
||||
// 排序值修改后自动调用接口
|
||||
const handleSortChange = async (row, newValue) => {
|
||||
if (newValue < 0) {
|
||||
message.error('排序不能小于 0')
|
||||
row.sort = 0
|
||||
return
|
||||
}
|
||||
// 1. 获取所有 quTitle 相同的项
|
||||
const sameTitleItems = list.value.filter(item => item.quTitle === row.quTitle)
|
||||
|
||||
// 2. 批量更新 sort 值
|
||||
const updateList = sameTitleItems.map(item => ({
|
||||
...item,
|
||||
sort: newValue
|
||||
}))
|
||||
|
||||
try {
|
||||
// 假设后端支持批量更新接口
|
||||
await Promise.all(updateList.map(item => SmsChannelApi.updateScheme(item)))
|
||||
message.success('同别名方案的排序已同步更新')
|
||||
getList()
|
||||
} catch (error) {
|
||||
message.error('排序更新失败')
|
||||
}
|
||||
}
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.pageNo = 1
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
label-width="80px"
|
||||
@submit.prevent=""
|
||||
>
|
||||
<el-form-item label="任务编号" prop="taskNum">
|
||||
<el-input clearable v-model="form.taskNum" placeholder="请输入编号" disabled/>
|
||||
</el-form-item>
|
||||
<el-form-item label="任务名称" prop="taskName">
|
||||
<el-input
|
||||
clearable
|
||||
@@ -124,6 +127,7 @@ const specialtyOptions = ref([]);
|
||||
const [form, resetFields, assignFields] = useFormData({
|
||||
taskId: void 0,
|
||||
taskName: '',
|
||||
taskNum:'',
|
||||
taskSpecialty: '',
|
||||
taskType: '4',
|
||||
isTemplate: '',
|
||||
@@ -196,13 +200,31 @@ const fetchSpecialtyOptions = async () => {
|
||||
|
||||
/** 弹窗打开事件 */
|
||||
const handleOpen = () => {
|
||||
if (props.data) {
|
||||
assignFields(props.data);
|
||||
isUpdate.value = true;
|
||||
} else {
|
||||
resetFields();
|
||||
isUpdate.value = false;
|
||||
}
|
||||
// if (props.data) {
|
||||
// assignFields(props.data);
|
||||
// isUpdate.value = true;
|
||||
// } else {
|
||||
// resetFields();
|
||||
// isUpdate.value = false;
|
||||
// }
|
||||
|
||||
// 设置批次为 当前时间 + 5位随机数
|
||||
const now = new Date();
|
||||
const pad = (n) => n.toString().padStart(2, '0');
|
||||
const datetimeStr = [
|
||||
now.getFullYear(),
|
||||
pad(now.getMonth() + 1),
|
||||
pad(now.getDate()),
|
||||
pad(now.getHours()),
|
||||
pad(now.getMinutes()),
|
||||
pad(now.getSeconds())
|
||||
].join('');
|
||||
|
||||
const randomNum = Math.floor(Math.random() * 100000).toString().padStart(5, '0');
|
||||
//taskNum 赋值 randomNum
|
||||
|
||||
// 把 taskNum 设置为当前时间+随机数
|
||||
form.taskNum = `${datetimeStr}${randomNum}`;
|
||||
nextTick(() => {
|
||||
nextTick(() => {
|
||||
formRef.value?.clearValidate?.();
|
||||
@@ -212,5 +234,5 @@ const fetchSpecialtyOptions = async () => {
|
||||
onMounted(() => {
|
||||
fetchSpecialtyOptions();
|
||||
});
|
||||
|
||||
defineExpose({ handleOpen })
|
||||
</script>
|
||||
@@ -73,6 +73,7 @@
|
||||
<ContentWrap>
|
||||
<el-table v-loading="loading" :data="list" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column label="任务编号" align="center" prop="taskNum" />
|
||||
<el-table-column label="任务名称" align="center" prop="taskName" />
|
||||
<el-table-column label="专业" align="center" prop="taskSpecialty" />
|
||||
<el-table-column label="试卷任务模式" align="center" prop="taskType">
|
||||
@@ -223,6 +224,10 @@ const formRef = ref();
|
||||
const openForm = (type: string, id?: number) => {
|
||||
showAdd.value = true
|
||||
taskAddRef.value?.open(type, id)
|
||||
|
||||
nextTick(() => {
|
||||
taskAddRef.value?.open(type, id)
|
||||
});
|
||||
}
|
||||
|
||||
/** 状态切换处理 */
|
||||
@@ -248,7 +253,10 @@ const openEdit = (type: string, row?: object) => {
|
||||
showEdit.value = true
|
||||
current.value = row
|
||||
console.log( current.value )
|
||||
taskEditRef.value?.open(type, row)
|
||||
|
||||
nextTick(() => {
|
||||
taskEditRef.value?.open(type, row)
|
||||
});
|
||||
}
|
||||
|
||||
const openBank = () => {
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
</el-form-item>
|
||||
|
||||
|
||||
<el-form-item label="排序" prop="sort">
|
||||
<el-form-item label="别名排序" prop="sort">
|
||||
<el-input-number v-model="form.sort" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@@ -168,7 +168,7 @@ const form = ref<{
|
||||
const rules = reactive({
|
||||
spName: [{ required: true, message: '请选择题型', trigger: 'change' }],
|
||||
quLevel: [{ required: true, message: '请选择难度', trigger: 'change' }],
|
||||
sort: [{ required: true, message: '请设置排序', trigger: 'change' }],
|
||||
// sort: [{ required: true, message: '请设置排序', trigger: 'change' }],
|
||||
quTitle: [{ required: true, message: '请输入别名', trigger: 'change' }],
|
||||
pointName: [{ required: true, message: '请选择知识点', trigger: 'change' }],
|
||||
quNumbers: [{ required: true, message: '请输入试题数量', trigger: 'blur' }],
|
||||
@@ -223,11 +223,29 @@ const open = async (type: 'create' | 'update', data?: any) => {
|
||||
sort: undefined,
|
||||
taskSpecialty: props.taskSpecialty
|
||||
}
|
||||
// 清除校验
|
||||
await nextTick()
|
||||
const allKeys = getAllTreeKeys(pointOptions.value).map(String)
|
||||
form.value.pointName = allKeys
|
||||
treeRef.value?.setCheckedKeys(allKeys)
|
||||
}
|
||||
|
||||
// 清除校验
|
||||
await nextTick()
|
||||
formRef.value?.clearValidate?.()
|
||||
|
||||
}
|
||||
function getAllTreeKeys(tree: TreeNode[]): number[] {
|
||||
const keys: number[] = []
|
||||
|
||||
const traverse = (nodes: TreeNode[]) => {
|
||||
for (const node of nodes) {
|
||||
keys.push(node.value)
|
||||
if (node.children?.length) {
|
||||
traverse(node.children)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
traverse(tree)
|
||||
return keys
|
||||
}
|
||||
|
||||
/** --------- 拉取扁平知识点并建树 --------- **/
|
||||
@@ -329,7 +347,7 @@ const save = async () => {
|
||||
const fn = isUpdate.value ? updateScheme : addScheme
|
||||
await fn(payload)
|
||||
emit('done')
|
||||
visible.value = false
|
||||
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<!-- 列表 -->
|
||||
<ContentWrap>
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="方案ID" align="center" prop="taskId" />
|
||||
<!-- <el-table-column label="方案ID" align="center" prop="taskId" /> -->
|
||||
<el-table-column label="题型" align="center" prop="spName" />
|
||||
<el-table-column label="难度" align="center" prop="quLevel">
|
||||
<template #default="scope">
|
||||
@@ -47,14 +47,24 @@
|
||||
<span v-else>未知</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="试题别名" align="center" prop="quTitle"/>
|
||||
<!-- <el-table-column label="关键字" align="center" prop="keywords" /> -->
|
||||
<el-table-column label="试题数量" align="center" prop="quNumbers"/>
|
||||
|
||||
<el-table-column label="每题分数" align="center" prop="quScores"/>
|
||||
<el-table-column label="小计分数" align="center" prop="subtotalScore"/>
|
||||
|
||||
<el-table-column label="试题别名" align="center" prop="quTitle"/>
|
||||
<el-table-column label="别名排序" align="center">
|
||||
<template #default="scope">
|
||||
<el-input-number
|
||||
v-model="scope.row.sort"
|
||||
placeholder="请输入排序"
|
||||
size="small"
|
||||
:min="0"
|
||||
style="width: 100px"
|
||||
@change="(val) => handleSortChange(scope.row, val)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="操作" align="center">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
@@ -76,6 +86,12 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- ✅ 总分展示区域 -->
|
||||
<div style="display: flex; justify-content: flex-end; padding: 5px; margin: 10px 0; font-weight: bold;">
|
||||
总分:{{ totalScore }}
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<Pagination
|
||||
:total="total"
|
||||
@@ -179,6 +195,40 @@ const handleQuery = () => {
|
||||
getList()
|
||||
}
|
||||
|
||||
const totalScore = computed(() => {
|
||||
return list.value.reduce((sum, item) => {
|
||||
// 确保字段存在且为数字
|
||||
const score = parseFloat(item.subtotalScore) || 0;
|
||||
return sum + score;
|
||||
}, 0);
|
||||
});
|
||||
// 排序值修改后自动调用接口
|
||||
const handleSortChange = async (row, newValue) => {
|
||||
if (newValue < 0) {
|
||||
message.error('排序不能小于 0')
|
||||
row.sort = 0
|
||||
return
|
||||
}
|
||||
|
||||
// 1. 获取所有 quTitle 相同的项
|
||||
const sameTitleItems = list.value.filter(item => item.quTitle === row.quTitle)
|
||||
|
||||
// 2. 批量更新 sort 值
|
||||
const updateList = sameTitleItems.map(item => ({
|
||||
...item,
|
||||
sort: newValue
|
||||
}))
|
||||
|
||||
try {
|
||||
// 假设后端支持批量更新接口
|
||||
await Promise.all(updateList.map(item => SmsChannelApi.updateScheme(item)))
|
||||
message.success('同别名方案的排序已同步更新')
|
||||
getList()
|
||||
} catch (error) {
|
||||
message.error('排序更新失败')
|
||||
}
|
||||
}
|
||||
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value.resetFields()
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
|
||||
<!-- 多选列 -->
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column label="试卷id" align="center" prop="paperId" />
|
||||
<!-- <el-table-column label="试卷id" align="center" prop="paperId" /> -->
|
||||
<el-table-column label="试卷编号" align="center" prop="num" />
|
||||
<el-table-column label="使用次数" align="center" prop="counts" />
|
||||
<el-table-column label="抽卷方式" align="center" prop="rollUp">
|
||||
|
||||
@@ -19,6 +19,15 @@
|
||||
<el-form-item label="批次" prop="batch">
|
||||
<el-input clearable v-model="form.batch" placeholder="请输入批次" disabled/>
|
||||
</el-form-item>
|
||||
<el-form-item label="考试时长" prop="answerTime">
|
||||
<el-time-picker
|
||||
v-model="form.answerTime"
|
||||
value-format="HH:mm:ss"
|
||||
placeholder="请选择考试时长"
|
||||
class="ele-fluid"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
|
||||
<el-form-item label="考试开始时间" prop="startTime">
|
||||
<el-date-picker
|
||||
@@ -37,6 +46,7 @@
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
placeholder="请选择考试结束时间"
|
||||
class="ele-fluid"
|
||||
disabled
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
@@ -99,6 +109,8 @@
|
||||
import { ref, reactive, nextTick } from 'vue'
|
||||
import { addSession, updateSession } from '@/api/system/session'
|
||||
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
||||
import { watch } from 'vue'
|
||||
import dayjs from 'dayjs'
|
||||
const emit = defineEmits(['done'])
|
||||
const props = defineProps({
|
||||
data: Object,
|
||||
@@ -116,6 +128,7 @@ const form = ref({
|
||||
taskId: props.taskId ?? '',
|
||||
batch: '',
|
||||
startTime: '',
|
||||
answerTime:'',
|
||||
endTime: '',
|
||||
allowEntry: '',
|
||||
endAllowEntry: '',
|
||||
@@ -149,6 +162,7 @@ const open = async (type: 'create' | 'update', data?: any) => {
|
||||
taskId: props.taskId ?? '',
|
||||
batch: '',
|
||||
startTime: '',
|
||||
answerTime:'01:00:00',
|
||||
endTime: '',
|
||||
allowEntry: '',
|
||||
endAllowEntry: '',
|
||||
@@ -178,7 +192,20 @@ const open = async (type: 'create' | 'update', data?: any) => {
|
||||
await nextTick()
|
||||
formRef.value?.clearValidate?.()
|
||||
}
|
||||
|
||||
// 监听考试开始时间和考试时长,自动计算考试结束时间
|
||||
watch(() => [form.value.startTime, form.value.answerTime], ([startTime, answerTime]) => {
|
||||
if (startTime && answerTime) {
|
||||
const [hours, minutes, seconds] = answerTime.split(':').map(Number)
|
||||
const end = dayjs(startTime)
|
||||
.add(hours, 'hour')
|
||||
.add(minutes, 'minute')
|
||||
.add(seconds, 'second')
|
||||
.format('YYYY-MM-DD HH:mm:ss')
|
||||
form.value.endTime = end
|
||||
} else {
|
||||
form.value.endTime = ''
|
||||
}
|
||||
})
|
||||
// 保存按钮
|
||||
const save = async () => {
|
||||
await formRef.value.validate()
|
||||
@@ -192,6 +219,6 @@ const save = async () => {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({ open })
|
||||
|
||||
</script>
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
label-width="80px"
|
||||
@submit.prevent=""
|
||||
>
|
||||
<el-form-item label="任务编号" prop="taskNum">
|
||||
<el-input clearable v-model="form.taskNum" placeholder="请输入编号" disabled/>
|
||||
</el-form-item>
|
||||
<el-form-item label="任务名称" prop="taskName">
|
||||
<el-input
|
||||
clearable
|
||||
@@ -123,6 +126,7 @@ const specialtyOptions = ref([]);
|
||||
/** 表单数据 */
|
||||
const [form, resetFields, assignFields] = useFormData({
|
||||
taskId: void 0,
|
||||
taskNum:'',
|
||||
taskName: '',
|
||||
taskSpecialty: '',
|
||||
taskType: '3',
|
||||
@@ -195,14 +199,31 @@ const fetchSpecialtyOptions = async () => {
|
||||
};
|
||||
|
||||
/** 弹窗打开事件 */
|
||||
const handleOpen = () => {
|
||||
if (props.data) {
|
||||
assignFields(props.data);
|
||||
isUpdate.value = true;
|
||||
} else {
|
||||
resetFields();
|
||||
isUpdate.value = false;
|
||||
}
|
||||
const open = () => {
|
||||
// if (props.data) {
|
||||
// assignFields(props.data);
|
||||
// isUpdate.value = true;
|
||||
// } else {
|
||||
// resetFields();
|
||||
// isUpdate.value = false;
|
||||
// }
|
||||
// 设置批次为 当前时间 + 5位随机数
|
||||
const now = new Date();
|
||||
const pad = (n) => n.toString().padStart(2, '0');
|
||||
const datetimeStr = [
|
||||
now.getFullYear(),
|
||||
pad(now.getMonth() + 1),
|
||||
pad(now.getDate()),
|
||||
pad(now.getHours()),
|
||||
pad(now.getMinutes()),
|
||||
pad(now.getSeconds())
|
||||
].join('');
|
||||
|
||||
const randomNum = Math.floor(Math.random() * 100000).toString().padStart(5, '0');
|
||||
//taskNum 赋值 randomNum
|
||||
|
||||
// 把 taskNum 设置为当前时间+随机数
|
||||
form.taskNum = `${datetimeStr}${randomNum}`;
|
||||
nextTick(() => {
|
||||
nextTick(() => {
|
||||
formRef.value?.clearValidate?.();
|
||||
@@ -212,5 +233,5 @@ const fetchSpecialtyOptions = async () => {
|
||||
onMounted(() => {
|
||||
fetchSpecialtyOptions();
|
||||
});
|
||||
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
@@ -73,6 +73,7 @@
|
||||
<ContentWrap>
|
||||
<el-table v-loading="loading" :data="list" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column label="任务编号" align="center" prop="taskNum" />
|
||||
<el-table-column label="任务名称" align="center" prop="taskName" />
|
||||
<el-table-column label="专业" align="center" prop="taskSpecialty" />
|
||||
<el-table-column label="试卷任务模式" align="center" prop="taskType">
|
||||
@@ -240,14 +241,17 @@ const handleSelectionChange = (rows) => {
|
||||
const formRef = ref();
|
||||
const openForm = (type: string, id?: number) => {
|
||||
showAdd.value = true
|
||||
taskAddRef.value?.open(type, id)
|
||||
nextTick(() => {
|
||||
taskAddRef.value?.open(type, id)
|
||||
});
|
||||
}
|
||||
|
||||
const openEdit = (type: string, row?: object) => {
|
||||
showEdit.value = true
|
||||
current.value = row
|
||||
console.log( current.value )
|
||||
taskEditRef.value?.open(type, row)
|
||||
nextTick(() => {
|
||||
taskEditRef.value?.open(type, row)
|
||||
});
|
||||
}
|
||||
|
||||
const openBank = () => {
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
</el-form-item>
|
||||
|
||||
|
||||
<el-form-item label="排序" prop="sort">
|
||||
<el-form-item label="别名排序" prop="sort">
|
||||
<el-input-number v-model="form.sort" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@@ -223,11 +223,28 @@ const open = async (type: 'create' | 'update', data?: any) => {
|
||||
sort: undefined,
|
||||
taskSpecialty: props.taskSpecialty
|
||||
}
|
||||
// 清除校验
|
||||
await nextTick()
|
||||
const allKeys = getAllTreeKeys(pointOptions.value).map(String)
|
||||
form.value.pointName = allKeys
|
||||
treeRef.value?.setCheckedKeys(allKeys)
|
||||
}
|
||||
|
||||
}
|
||||
function getAllTreeKeys(tree: TreeNode[]): number[] {
|
||||
const keys: number[] = []
|
||||
|
||||
const traverse = (nodes: TreeNode[]) => {
|
||||
for (const node of nodes) {
|
||||
keys.push(node.value)
|
||||
if (node.children?.length) {
|
||||
traverse(node.children)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 清除校验
|
||||
await nextTick()
|
||||
formRef.value?.clearValidate?.()
|
||||
traverse(tree)
|
||||
return keys
|
||||
}
|
||||
|
||||
/** --------- 拉取扁平知识点并建树 --------- **/
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
<!-- 列表 -->
|
||||
<ContentWrap>
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="方案ID" align="center" prop="schemeId" />
|
||||
<!-- <el-table-column label="方案ID" align="center" prop="schemeId" /> -->
|
||||
<el-table-column label="题型" align="center" prop="spName" />
|
||||
<el-table-column label="难度" align="center" prop="quLevel">
|
||||
<template #default="scope">
|
||||
@@ -48,14 +48,24 @@
|
||||
<span v-else>未知</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="试题别名" align="center" prop="quTitle"/>
|
||||
|
||||
<!-- <el-table-column label="关键字" align="center" prop="keywords" /> -->
|
||||
<el-table-column label="试题数量" align="center" prop="quNumbers"/>
|
||||
|
||||
<el-table-column label="每题分数" align="center" prop="quScores"/>
|
||||
<el-table-column label="小计分数" align="center" prop="subtotalScore"/>
|
||||
|
||||
<el-table-column label="试题别名" align="center" prop="quTitle"/>
|
||||
<el-table-column label="别名排序" align="center">
|
||||
<template #default="scope">
|
||||
<el-input-number
|
||||
v-model="scope.row.sort"
|
||||
placeholder="请输入排序"
|
||||
size="small"
|
||||
:min="0"
|
||||
style="width: 100px"
|
||||
@change="(val) => handleSortChange(scope.row, val)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
@@ -77,6 +87,10 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- ✅ 总分展示区域 -->
|
||||
<div style="text-align: right; margin: 10px 0; font-weight: bold;">
|
||||
总分:{{ totalScore }}
|
||||
</div>
|
||||
<!-- 分页 -->
|
||||
<Pagination
|
||||
:total="total"
|
||||
@@ -136,7 +150,38 @@ const taskEditRef = ref()
|
||||
const taskAddRef = ref()
|
||||
const taskTempRef = ref()
|
||||
|
||||
const totalScore = computed(() => {
|
||||
return list.value.reduce((sum, item) => {
|
||||
// 确保字段存在且为数字
|
||||
const score = parseFloat(item.subtotalScore) || 0;
|
||||
return sum + score;
|
||||
}, 0);
|
||||
});
|
||||
// 排序值修改后自动调用接口
|
||||
const handleSortChange = async (row, newValue) => {
|
||||
if (newValue < 0) {
|
||||
message.error('排序不能小于 0')
|
||||
row.sort = 0
|
||||
return
|
||||
}
|
||||
// 1. 获取所有 quTitle 相同的项
|
||||
const sameTitleItems = list.value.filter(item => item.quTitle === row.quTitle)
|
||||
|
||||
// 2. 批量更新 sort 值
|
||||
const updateList = sameTitleItems.map(item => ({
|
||||
...item,
|
||||
sort: newValue
|
||||
}))
|
||||
|
||||
try {
|
||||
// 假设后端支持批量更新接口
|
||||
await Promise.all(updateList.map(item => SmsChannelApi.updateScheme(item)))
|
||||
message.success('同别名方案的排序已同步更新')
|
||||
getList()
|
||||
} catch (error) {
|
||||
message.error('排序更新失败')
|
||||
}
|
||||
}
|
||||
|
||||
const loading = ref(false) // 列表的加载中
|
||||
const total = ref(0) // 列表的总页数
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
|
||||
<!-- 多选列 -->
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column label="试卷id" align="center" prop="paperId" />
|
||||
<!-- <el-table-column label="试卷id" align="center" prop="paperId" /> -->
|
||||
<el-table-column label="试卷编号" align="center" prop="num" />
|
||||
<el-table-column label="使用次数" align="center" prop="counts" />
|
||||
<el-table-column label="抽卷方式" align="center" prop="rollUp">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!-- 编辑弹窗 -->
|
||||
<template>
|
||||
<Dialog v-model="visible" :title="'添加试卷任务'" width="460" @open="handleOpen" center>
|
||||
<Dialog v-model="visible" :title="'添加试卷任务'" width="460" center>
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="form"
|
||||
@@ -8,6 +8,10 @@
|
||||
label-width="80px"
|
||||
@submit.prevent=""
|
||||
>
|
||||
|
||||
<el-form-item label="任务编号" prop="taskNum">
|
||||
<el-input clearable v-model="form.taskNum" placeholder="请输入编号" disabled/>
|
||||
</el-form-item>
|
||||
<el-form-item label="任务名称" prop="taskName">
|
||||
<el-input
|
||||
clearable
|
||||
@@ -124,6 +128,7 @@ const specialtyOptions = ref([]);
|
||||
const [form, resetFields, assignFields] = useFormData({
|
||||
taskId: void 0,
|
||||
taskName: '',
|
||||
taskNum:'',
|
||||
taskSpecialty: '',
|
||||
taskType: '0',
|
||||
isTemplate: '',
|
||||
@@ -178,6 +183,7 @@ const fetchSpecialtyOptions = async () => {
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
visible.value = true;
|
||||
loading.value = true;
|
||||
const saveOrUpdate = isUpdate.value ? updateTask : addTask;
|
||||
saveOrUpdate(form)
|
||||
@@ -195,14 +201,31 @@ const fetchSpecialtyOptions = async () => {
|
||||
};
|
||||
|
||||
/** 弹窗打开事件 */
|
||||
const handleOpen = () => {
|
||||
if (props.data) {
|
||||
assignFields(props.data);
|
||||
isUpdate.value = true;
|
||||
} else {
|
||||
resetFields();
|
||||
isUpdate.value = false;
|
||||
}
|
||||
const open = async (type, row) => {
|
||||
// if (props.data) {
|
||||
// assignFields(props.data);
|
||||
// isUpdate.value = true;
|
||||
// } else {
|
||||
// resetFields();
|
||||
// isUpdate.value = false;
|
||||
// }
|
||||
// 设置批次为 当前时间 + 5位随机数
|
||||
const now = new Date();
|
||||
const pad = (n) => n.toString().padStart(2, '0');
|
||||
const datetimeStr = [
|
||||
now.getFullYear(),
|
||||
pad(now.getMonth() + 1),
|
||||
pad(now.getDate()),
|
||||
pad(now.getHours()),
|
||||
pad(now.getMinutes()),
|
||||
pad(now.getSeconds())
|
||||
].join('');
|
||||
|
||||
const randomNum = Math.floor(Math.random() * 100000).toString().padStart(5, '0');
|
||||
//taskNum 赋值 randomNum
|
||||
|
||||
// 把 taskNum 设置为当前时间+随机数
|
||||
form.taskNum = `${datetimeStr}${randomNum}`;
|
||||
nextTick(() => {
|
||||
nextTick(() => {
|
||||
formRef.value?.clearValidate?.();
|
||||
@@ -210,7 +233,8 @@ const fetchSpecialtyOptions = async () => {
|
||||
});
|
||||
};
|
||||
onMounted(() => {
|
||||
|
||||
fetchSpecialtyOptions();
|
||||
});
|
||||
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
@@ -71,7 +71,6 @@ const props = defineProps({
|
||||
})
|
||||
const isVisible = defineModel({ type: Boolean })
|
||||
|
||||
const isUpdate = ref(false)
|
||||
const activeStep = ref(0)
|
||||
|
||||
const stepTitles = ['试卷方案', '试卷管理', '参数设置', '考场设置', '人员设置']
|
||||
@@ -97,9 +96,7 @@ async function handleStepClick(index) {
|
||||
const open = async (type, row) => {
|
||||
isVisible.value = true
|
||||
assignFields(row)
|
||||
isUpdate.value = true
|
||||
activeStep.value = 0
|
||||
|
||||
nextTick(() => {
|
||||
formRef.value?.clearValidate?.()
|
||||
})
|
||||
|
||||
@@ -73,6 +73,7 @@
|
||||
<ContentWrap>
|
||||
<el-table v-loading="loading" :data="list" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column label="任务编号" align="center" prop="taskNum" />
|
||||
<el-table-column label="任务名称" align="center" prop="taskName" />
|
||||
<el-table-column label="专业" align="center" prop="taskSpecialty" />
|
||||
<el-table-column label="试卷任务模式" align="center" prop="taskType">
|
||||
@@ -222,15 +223,20 @@ const handleSelectionChange = (rows) => {
|
||||
const formRef = ref();
|
||||
const openForm = (type: string, id?: number) => {
|
||||
showAdd.value = true
|
||||
taskAddRef.value?.open(type, id)
|
||||
nextTick(() => {
|
||||
taskAddRef.value?.open(type, id)
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
const openEdit = (type: string, row?: object) => {
|
||||
showEdit.value = true
|
||||
current.value = row
|
||||
console.log( current.value )
|
||||
taskEditRef.value?.open(type, row)
|
||||
}
|
||||
showEdit.value = true;
|
||||
current.value = row;
|
||||
nextTick(() => {
|
||||
taskEditRef.value?.open(type, row);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const openBank = () => {
|
||||
showOpenTemplate.value = true
|
||||
|
||||
Reference in New Issue
Block a user