645 lines
24 KiB
Vue
645 lines
24 KiB
Vue
<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>
|