Files
pengcheng-exam-teacher/src/views/paper/question/CdesignForm.vue
2025-08-13 09:02:53 +08:00

645 lines
24 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="program-edit">
<Dialog v-model="dialogVisible" :title="dialogTitle" width="70%" top="10vh">
<el-scrollbar height="600px">
<div class="main">
<el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
<el-tab-pane label="基本内容" name="common">
<div class="line">
<div class="title-text">试题题目</div>
<div class="block">
<Editor v-model="content" height="150px" />
</div>
</div>
<div class="line">
<div class="title-text">答题程序模板</div>
<ElTextarea v-model="textarea" :rows="4" />
</div>
<div class="line">
<div class="title-text">基本信息</div>
<el-form
label-width="80"
:inline="false"
:model="formData"
class="demo-form-inline"
>
<el-form-item label="知识点">
<el-input disabled placeholder="请输入知识点" size="large" />
</el-form-item>
<el-form-item label="试题版本">
<p>测试测试</p>
</el-form-item>
<el-form-item label="来源">
<p>测试测试</p>
</el-form-item>
<el-form-item label="创建人">
<p>测试测试</p>
</el-form-item>
<el-form-item label="创建时间">
<p>测试测试</p>
</el-form-item>
<el-form-item label="修改人">
<p>测试测试</p>
</el-form-item>
<el-form-item label="修改时间">
<p>测试测试</p>
</el-form-item>
</el-form>
</div>
</el-tab-pane>
<el-tab-pane label="判分设置" name="score">
<div class="line">
<div class="title-text">测试程序参考答案</div>
<div class="block">
<div class="tip">
<p
>此处的程序可以用来验证测试用例的有效性非自动判分的试题在人工批阅时可作为批阅的参考答案
<br />
注意: 为确保系统能正确捕获程序运行的输出结果要求 scanf() 函数不能加参数,
不能采用类似 scanf("请输入: %s") 的形式</p
>
</div>
<ElTextarea v-model="textarea" :rows="4" />
<div class="btn-line">
<el-button type="primary" plain>添加为关键字</el-button>
<el-button type="primary" plain>上传程序文件</el-button>
<el-button type="primary" plain>运行并测试</el-button>
</div>
<el-checkbox
v-model="programData.checkAutoScore"
label="自动判分方式"
size="large"
/>
</div>
</div>
<div class="line">
<div class="title-text">测试用例</div>
<div class="block">
<div class="flex">
<el-checkbox
v-model="programData.checkKeyword"
label="检查代码关键字"
size="large"
/>
<div class="flex" style="margin-left: 20px">
编译得分比例
<el-input
v-model="programData.percent"
type="number"
placeholder="Please input"
>
<template #append>%</template>
</el-input>
</div>
</div>
<div>
<el-checkbox
v-model="programData.checkKeyword"
label="使用测试用例"
size="large"
/>
<div>
<div class="flex">
<el-checkbox
v-model="programData.checkKeyword"
label="测试用例全对时直接得满分s"
size="large"
/>
</div>
<div class="tip">
<p
>判分时测试用例得分比例 = 100% - 关键字得分比例 - 编译得分比例默认最小
10% 得分比例<br />
设置测试用例全对时直接得满分测试用例结果全对时忽略关键字得分直接获得试题满分否则按上述条件计算得分</p
>
</div>
<el-radio-group v-model="programData.radio1" class="ml-4">
<el-radio label="1" size="large">测试用例部分对时得分</el-radio>
<el-radio label="2" size="large">测试用例全对时得分</el-radio>
</el-radio-group>
<div class="btn-line" style="margin-bottom: 10px">
<el-button type="primary" plain>添加用例</el-button>
<el-button type="primary" plain>导入用例</el-button>
<el-button type="primary" plain>导出模板</el-button>
<el-button type="primary" plain>删除全部</el-button>
<el-button type="primary" plain>测试所有用例</el-button>
<el-button type="primary" plain>均分权重</el-button>
</div>
<el-table
:data="examList"
style="width: 100%"
@selection-change="handleExamSelectionChange"
>
<el-table-column type="index" width="50" />
<el-table-column type="selection" width="55" />
<el-table-column prop="type" label="输入" width="80" />
<el-table-column
prop="title"
label="输出"
width="180"
show-overflow-tooltip
/>
<el-table-column prop="displayIndex" label="权重(%)" />
<el-table-column prop="size" label="隐藏用例" />
<el-table-column prop="size" label="仅隐藏输出" />
<el-table-column label="操作">
<template #default="scope">
<el-button type="primary" @click="delExam(scope)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
</div>
<div class="line">
<div class="title-text">代码关键字</div>
<div class="block">
<div class="flex">
<el-checkbox
v-model="programData.checkKeyword"
label="检查代码关键字"
size="large"
/>
<div class="flex" style="margin-left: 20px">
关键字得分比例
<el-input
v-model="programData.percent"
type="number"
placeholder="Please input"
>
<template #append>%</template>
</el-input>
</div>
<div class="flex">
关键字得分临界值
<el-input
v-model="programData.percent"
type="number"
placeholder="Please input"
>
<template #append>%</template>
</el-input>
</div>
</div>
<div class="tip" style="margin-top: 10px">
<p
>提示关键字支持正则表达式匹配方式在新建或编辑中设置<br />
判分时关键字正确比例小于关键字得分临界值时忽略验证编译及测试用例得分比例仅获得关键字正确比例分数<br />
判分时关键字正确比例大于等于关键字得分临界值编译通过且测试用例结果全对时忽略关键字得分直接获得试题满分<br />
判分时关键字正确比例大于等于关键字得分临界值编译不一定通过且测试用例不一定全对时获得分数
= 关键字得分 + 编译得分 + 测试用例结果得分</p
>
</div>
<div class="btn-line" style="margin-bottom: 10px">
<el-button type="primary" plain>新建</el-button>
<el-button type="primary" plain>导入</el-button>
<el-button type="primary" plain>删除全部</el-button>
<el-button type="primary" plain>校验关键字</el-button>
</div>
<el-table
:data="scoreKeyList"
style="width: 100%"
@selection-change="handleScoreSelectionChange"
>
<el-table-column type="index" width="50" />
<el-table-column type="selection" width="55" />
<el-table-column
prop="title"
label="关键字"
width="180"
show-overflow-tooltip
/>
<el-table-column prop="displayIndex" label="权重(%)" />
<el-table-column label="操作">
<template #default="scope">
<el-button type="primary" @click="delScore(scope)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
<div class="line">
<div class="title-text">其它选项</div>
<div>
<div class="flex">
时间限制
<el-input
v-model="programData.percent"
type="number"
placeholder="Please input"
/>
ms毫秒1 等于 1000毫秒
</div>
<div class="flex">
内存限制
<el-input
v-model="programData.percent"
type="number"
placeholder="Please input"
/>
MB
</div>
<div class="flex">
代码长度限制
<el-input
v-model="programData.percent"
type="number"
placeholder="Please input"
/>
KB
</div>
</div>
</div>
</el-tab-pane>
<el-tab-pane label="试题解析" name="analyse">
<div class="block">
<ElTextarea v-model="textarea" :rows="4" />
</div>
</el-tab-pane>
<el-tab-pane name="keyword">
<template #label>
<div class="custom-tabs-label">
<p>关键字</p>
<el-dropdown>
<span class="el-dropdown-link" @click.stop="false">
<div class="setting_icon"></div>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="editKeyword('create')">新建</el-dropdown-item>
<el-dropdown-item @click="editKeyword('create')">编辑</el-dropdown-item>
<el-dropdown-item @click="editKeyword('delete')">删除</el-dropdown-item>
<el-dropdown-item @click="editKeyword('deleteall')"
>删除全部</el-dropdown-item
>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</template>
<div class="block">
<el-table
:data="keywordList"
style="width: 100%"
height="410"
@selection-change="handleKeywordSelectionChange"
>
<el-table-column type="index" width="50" />
<el-table-column type="selection" width="55" />
<el-table-column prop="keyword" label="关键字" />
</el-table>
<el-dialog
v-model="keyVisible"
title="编辑关键字"
width="50%"
style="height: auto;"
:before-close="keyDialogClose"
:close-on-click-modal="false"
:close-on-press-escape="false"
>
<div class="main" style="width: 100%; height: 100%">
<el-input v-model="keyWord" placeholder="请输入关键字" size="large" />
<div class="dialog-footer" style="margin-top: 20px">
<el-button @click="keyDialogClose">取消</el-button>
<el-button type="primary" @click="confirmKeyDialogVisible"> 确定 </el-button>
</div>
</div>
</el-dialog>
</div>
</el-tab-pane>
<el-tab-pane name="media">
<template #label>
<div class="custom-tabs-label">
<p>媒体文件</p>
<el-dropdown>
<span class="el-dropdown-link" @click.stop="false">
<div class="setting_icon"></div>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>
<el-upload
v-model:file-list="fileList"
class="upload-demo"
action="https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15"
>
<el-button>导入</el-button>
</el-upload>
</el-dropdown-item>
<el-dropdown-item>导出</el-dropdown-item>
<el-dropdown-item>播放</el-dropdown-item>
<el-dropdown-item>编辑</el-dropdown-item>
<el-dropdown-item>删除选中</el-dropdown-item>
<el-dropdown-item>删除全部</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</template>
<div class="block">
<el-table
:data="mediumList"
style="width: 100%"
height="410"
@selection-change="handleMediumSelectionChange"
>
<el-table-column type="index" width="50" />
<el-table-column type="selection" width="55" />
<el-table-column prop="type" label="媒体类型" width="80" />
<el-table-column prop="title" label="标题" />
<el-table-column prop="displayIndex" label="显示序号" />
<el-table-column prop="size" label="大小" />
</el-table>
</div>
</el-tab-pane>
</el-tabs>
</div>
</el-scrollbar>
<template #footer>
<el-button :disabled="formLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
</template>
</Dialog>
</div>
</template>
<script lang="ts" setup>
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { CommonStatusEnum } from '@/utils/constants'
import ElTextarea from './components/el-textarea.vue'
import { defaultProps, handleTree } from '@/utils/tree'
import * as PostApi from '@/api/system/post'
import * as DeptApi from '@/api/system/dept'
import * as UserApi from '@/api/system/user'
import { FormRules } from 'element-plus'
defineOptions({ name: 'SystemUserForm' })
const { t } = useI18n() // 国际化
const message = useMessage() // 消息弹窗
const dialogVisible = ref(false) // 弹窗的是否展示
const dialogTitle = ref('') // 弹窗的标题
const formLoading = ref(false) // 表单的加载中1修改时的数据加载2提交的按钮禁用
const formType = ref('') // 表单的类型create - 新增update - 修改
const formData = ref({
content: '',
specialtyName: '',
courseName: '',
quBankName: '',
required: '',
chapteridDictText: '',
analysis: ''
})
const formRules = reactive<FormRules>({
specialtyName: [{ required: true, message: '用户名称不能为空', trigger: 'blur' }]
})
const formRef = ref() // 表单 Ref
const deptList = ref<Tree[]>([]) // 树形结构
const postList = ref([] as PostApi.PostVO[]) // 岗位列表
/** 页面内容开始 */
const activeName = ref('common')
const content = ref('')
const textarea = ref('')
const handleClick = (tab, e) => {
activeName.value = tab.paneName.value
}
/** 页面内容结束 */
/** 打开弹窗 */
const open = async (type: string, id?: number) => {
dialogVisible.value = true
dialogTitle.value = t('action.' + type)
formType.value = type
resetForm()
// 修改时,设置数据
if (id) {
formLoading.value = true
try {
formData.value = await UserApi.getUser(id)
} finally {
formLoading.value = false
}
}
// 加载部门树
deptList.value = handleTree(await DeptApi.getSimpleDeptList())
// 加载岗位列表
postList.value = await PostApi.getSimplePostList()
}
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
const programData = ref({
title: '',
checkAutoScore: false,
checkKeyword: false,
percent: 0,
radio1: ''
})
const examList = ref([] as any)
const multipleSelection = ref([] as any)
const handleExamSelectionChange = (val: any) => {
multipleSelection.value = val
}
const delExam = (val: any) => {
console.log(val)
}
const scoreKeyList = ref([] as any)
const multipleScoreSelection = ref([] as any)
const handleScoreSelectionChange = (val: any) => {
multipleScoreSelection.value = val
}
const delScore = (val: any) => {
console.log(val)
}
// 关键字
const keywordList = ref([] as any)
const multipleKeywordSelection = ref([] as any)
const handleKeywordSelectionChange = (val: any) => {
multipleKeywordSelection.value = val
}
const keyVisible = ref(false)
const keyEditType = ref('')
const keyWord = ref([null])
const editKeyword = (key) => {
keyEditType.value = key
keyVisible.value = true
}
const keyDialogClose = () => {
keyVisible.value = false
}
const confirmKeyDialogVisible = () => {
if (keyEditType.value === 'create') {
keywordList.value.push({
keyword: keyWord.value
})
}
keyVisible.value = false
}
// 媒体文件
const mediumList = ref([] as any)
const multipleMediumSelection = ref([] as any)
const handleMediumSelectionChange = (val: any) => {
multipleMediumSelection.value = val
}
const fileList = []
/** 提交表单 */
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
const submitForm = async () => {
console.log(textarea.value)
// 校验表单
if (!formRef) return
const valid = await formRef.value.validate()
if (!valid) return
// 提交请求
formLoading.value = true
try {
const data = formData.value as unknown as UserApi.UserVO
if (formType.value === 'create') {
await UserApi.createUser(data)
message.success(t('common.createSuccess'))
} else {
await UserApi.updateUser(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
// 发送操作成功的事件
emit('success')
} finally {
formLoading.value = false
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
content: '',
specialtyName: '',
courseName: '',
quBankName: '',
required: '',
chapteridDictText: '',
analysis: ''
}
formRef.value?.resetFields()
}
</script>
<style lang="scss" scoped>
.program-edit {
:deep(.el-dialog) {
display: flex;
flex-direction: column;
height: 85vh;
.el-dialog__header {
border-bottom: 1px solid #ededed;
}
.el-dialog__footer {
border-top: 1px solid #ededed;
}
.el-dialog__body {
flex: 1;
overflow: hidden;
.main {
height: 100%;
.el-tabs {
height: 100%;
.el-tabs__content {
flex: 1;
overflow-y: auto;
.line {
margin-bottom: 10px;
.title-text {
font-size: 18px;
font-weight: 600;
margin-bottom: 8px;
}
.block {
.tip {
color: #8a6d3b;
background-color: #fcf8e3;
border: 1px solid transparent;
border-color: #faebcc;
padding: 15px;
border-radius: 4px;
margin-bottom: 10px;
> p {
margin: 0;
}
}
.btn-line {
display: flex;
margin-top: 10px;
}
.flex {
display: flex;
align-items: center;
}
}
}
.el-input {
width: 45%;
}
}
.custom-tabs-label {
display: flex;
align-items: center;
.setting_icon {
width: 16px;
height: 16px;
background: url('@/assets/icon/setting_blue.png') no-repeat center;
background-size: 100%;
margin-left: 3px;
display: none;
}
}
.is-active {
.custom-tabs-label {
.setting_icon {
display: block;
}
}
}
:deep(.ele-pro-table) {
flex: 1;
margin-top: 10px;
.el-table--fit {
height: 100%;
}
}
}
}
}
}
}
:deep(.tox-tinymce) {
.tox-statusbar {
display: none;
}
}
:deep(.el-table) {
.el-table__header-wrapper {
.el-table__header {
thead {
tr {
th {
background: #ebebeb;
}
}
}
}
}
}
</style>