提交 ac5e09be authored 作者: lhh's avatar lhh

11.27需求修改

上级 5cd99fb3
...@@ -21,7 +21,7 @@ watchEffect(() => { ...@@ -21,7 +21,7 @@ watchEffect(() => {
...item, ...item,
old_score: parseFloat(item.old_score), old_score: parseFloat(item.old_score),
ratio: parseFloat(item.ratio), ratio: parseFloat(item.ratio),
score: isNaN(parseFloat(item.score)) ? null : parseFloat(item.score) score: isNaN(parseFloat(item.score)) ? 'null' : parseFloat(item.score)
} }
}) })
}) })
...@@ -43,7 +43,9 @@ const score = $computed(() => { ...@@ -43,7 +43,9 @@ const score = $computed(() => {
// 提交 // 提交
function handleSubmit() { function handleSubmit() {
const scores = tableList.map((item: any) => { const scores = tableList.map((item: any) => {
if (item.type === '2') { item.score = 0 } if (item.type === '2') {
item.score = 0
}
return { id: item.id, score: item.score } return { id: item.id, score: item.score }
}) })
const params = { id: detail.id, scores: JSON.stringify(scores) } const params = { id: detail.id, scores: JSON.stringify(scores) }
...@@ -75,7 +77,7 @@ const handleScoreRule = function () { ...@@ -75,7 +77,7 @@ const handleScoreRule = function () {
<el-form-item label="选手姓名">{{ detail.student_name }}</el-form-item> <el-form-item label="选手姓名">{{ detail.student_name }}</el-form-item>
<el-form-item label="选手ID">{{ detail.login_id }}</el-form-item> <el-form-item label="选手ID">{{ detail.login_id }}</el-form-item>
<div style="display: flex; justify-content: space-between"> <div style="display: flex; justify-content: space-between">
<el-form-item label="报告"> <el-form-item label="报告" v-if="reportList.length">
<el-dropdown> <el-dropdown>
<el-button text> <el-button text>
查看报告<el-icon class="el-icon--right"><arrow-down /></el-icon> 查看报告<el-icon class="el-icon--right"><arrow-down /></el-icon>
...@@ -89,7 +91,7 @@ const handleScoreRule = function () { ...@@ -89,7 +91,7 @@ const handleScoreRule = function () {
</template> </template>
</el-dropdown> </el-dropdown>
</el-form-item> </el-form-item>
<el-button type="primary" @click="handleScoreRule">查看评分规则</el-button> <el-button type="primary" style="margin-bottom: 20px" @click="handleScoreRule">查看评分规则</el-button>
</div> </div>
</el-form> </el-form>
<el-table :data="tableList" :header-cell-style="{ background: '#ededed' }"> <el-table :data="tableList" :header-cell-style="{ background: '#ededed' }">
...@@ -100,6 +102,7 @@ const handleScoreRule = function () { ...@@ -100,6 +102,7 @@ const handleScoreRule = function () {
<el-table-column label="评分" prop="score" align="center"> <el-table-column label="评分" prop="score" align="center">
<template #default="{ row }"> <template #default="{ row }">
<el-input-number <el-input-number
:disabled="row.type === '2'"
:controls="false" :controls="false"
v-model="row.score" v-model="row.score"
step-strictly step-strictly
...@@ -107,10 +110,11 @@ const handleScoreRule = function () { ...@@ -107,10 +110,11 @@ const handleScoreRule = function () {
:min="0" :min="0"
:max="row.old_score" :max="row.old_score"
style="width: 100%" style="width: 100%"
placeholder="--"
/> />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" align="center"> <el-table-column label="操作" align="center" v-if="false">
<template #default="{ row }"> <template #default="{ row }">
<el-button text type="primary" v-if="row.type === '2'"> <el-button text type="primary" v-if="row.type === '2'">
<a :href="`${qaURL}/exam/markingPaper?exam_id=${row.exam_id}&id_number=${detail.id_number}`" target="_blank" <a :href="`${qaURL}/exam/markingPaper?exam_id=${row.exam_id}&id_number=${detail.id_number}`" target="_blank"
......
...@@ -29,7 +29,7 @@ function scoreMethodText(value: string) { ...@@ -29,7 +29,7 @@ function scoreMethodText(value: string) {
</script> </script>
<template> <template>
<el-dialog title="同步1+X考试成绩" :close-on-click-modal="false"> <el-dialog title="同步1+同步线上考试成绩" :close-on-click-modal="false">
<el-form> <el-form>
<el-form-item label="赛项名称"> <el-form-item label="赛项名称">
<el-select v-model="form.competition" value-key="id"> <el-select v-model="form.competition" value-key="id">
......
...@@ -29,10 +29,10 @@ onMounted(() => { ...@@ -29,10 +29,10 @@ onMounted(() => {
fetchCompetition() fetchCompetition()
}) })
const platformKey = ref('career_data_analysis') const platformKey = ref('data_marketing')
const platformKeys = ref([ const platformKeys = ref([
{ platform_key: 'career_data_analysis', name: '商业数据分析实验' }, { platform_key: 'career_data_analysis', name: '商业数据分析实验' },
{ platform_key: 'data_marketing', name: '数据营销实操' }, { platform_key: 'data_marketing', name: '数据营销实操' }
]) ])
// async function fetchPlatformKeys(competition_id: string) { // async function fetchPlatformKeys(competition_id: string) {
// const res = await getPlatformKeys({ competition_id }) // const res = await getPlatformKeys({ competition_id })
...@@ -62,7 +62,7 @@ onUnmounted(() => { ...@@ -62,7 +62,7 @@ onUnmounted(() => {
const statistics = reactive({ const statistics = reactive({
competitor_count: 0, competitor_count: 0,
complete_answer_competitor_count: 0, complete_answer_competitor_count: 0,
starting_answer_competitor_count: 0, starting_answer_competitor_count: 0
}) })
async function fetchStatistics(competition_id: string, platform_key = 'career_data_analysis') { async function fetchStatistics(competition_id: string, platform_key = 'career_data_analysis') {
const res = await getCompetitionStatistics({ competition_id, platform_key }) const res = await getCompetitionStatistics({ competition_id, platform_key })
...@@ -97,8 +97,8 @@ const submittedListOptions = { ...@@ -97,8 +97,8 @@ const submittedListOptions = {
{ label: '所在专业', prop: 'student.specialty_name' }, { label: '所在专业', prop: 'student.specialty_name' },
{ label: '所在班级', prop: 'student.class_name' }, { label: '所在班级', prop: 'student.class_name' },
{ label: '提交时间', prop: 'commit_time' }, { label: '提交时间', prop: 'commit_time' },
{ label: '作答用时', prop: 'answer_time' }, { label: '作答用时', prop: 'answer_time' }
], ]
} }
const submittedLis = computed(() => { const submittedLis = computed(() => {
return competitorsTableData.value.filter((item: any) => item.commit_status == 3) return competitorsTableData.value.filter((item: any) => item.commit_status == 3)
...@@ -114,9 +114,9 @@ const answeringListOptions = { ...@@ -114,9 +114,9 @@ const answeringListOptions = {
{ label: '所在班级', prop: 'student.class_name' }, { label: '所在班级', prop: 'student.class_name' },
{ {
label: '作答用时', label: '作答用时',
prop: 'answer_time', prop: 'answer_time'
}, }
], ]
} }
const answeringList = computed(() => { const answeringList = computed(() => {
return competitorsTableData.value.filter((item: any) => item.commit_status == 2 || item.commit_status == 4) return competitorsTableData.value.filter((item: any) => item.commit_status == 2 || item.commit_status == 4)
...@@ -137,44 +137,44 @@ const listOptions = { ...@@ -137,44 +137,44 @@ const listOptions = {
prop: 'module_1', prop: 'module_1',
computed({ row }: { row: any }) { computed({ row }: { row: any }) {
return getModuleStatus(row, 0) return getModuleStatus(row, 0)
}, }
}, },
{ {
label: '模块二', label: '模块二',
prop: 'module_2', prop: 'module_2',
computed({ row }: { row: any }) { computed({ row }: { row: any }) {
return getModuleStatus(row, 1) return getModuleStatus(row, 1)
}, }
}, },
{ {
label: '模块三', label: '模块三',
prop: 'module_3', prop: 'module_3',
computed({ row }: { row: any }) { computed({ row }: { row: any }) {
return getModuleStatus(row, 2) return getModuleStatus(row, 2)
}, }
}, },
{ {
label: '模块四', label: '模块四',
prop: 'module_4', prop: 'module_4',
computed({ row }: { row: any }) { computed({ row }: { row: any }) {
return getModuleStatus(row, 3) return getModuleStatus(row, 3)
}, }
}, },
{ {
label: '模块五', label: '模块五',
prop: 'module_5', prop: 'module_5',
computed({ row }: { row: any }) { computed({ row }: { row: any }) {
return getModuleStatus(row, 4) return getModuleStatus(row, 4)
}, }
}, },
{ {
label: '模块六', label: '模块六',
prop: 'module_6', prop: 'module_6',
computed({ row }: { row: any }) { computed({ row }: { row: any }) {
return getModuleStatus(row, 5) return getModuleStatus(row, 5)
}, }
}, }
], ]
} }
function getModuleStatus(row: any, index: number) { function getModuleStatus(row: any, index: number) {
try { try {
...@@ -201,12 +201,13 @@ function getModuleStatus(row: any, index: number) { ...@@ -201,12 +201,13 @@ function getModuleStatus(row: any, index: number) {
<el-select v-model="currentCompetition" value-key="id" size="large" style="margin-right: 20px"> <el-select v-model="currentCompetition" value-key="id" size="large" style="margin-right: 20px">
<el-option v-for="item in competitionList" :key="item.id" :value="item" :label="item.name"></el-option> <el-option v-for="item in competitionList" :key="item.id" :value="item" :label="item.name"></el-option>
</el-select> </el-select>
<el-select v-model="platformKey" size="large"> <el-select v-model="platformKey" size="large" v-if="false">
<el-option <el-option
v-for="item in platformKeys" v-for="item in platformKeys"
:key="item.platform_key" :key="item.platform_key"
:value="item.platform_key" :value="item.platform_key"
:label="item.name"></el-option> :label="item.name"
></el-option>
</el-select> </el-select>
</el-row> </el-row>
<ul class="statistics"> <ul class="statistics">
......
...@@ -37,6 +37,7 @@ const listOptions = $computed(() => { ...@@ -37,6 +37,7 @@ const listOptions = $computed(() => {
columns: [ columns: [
{ label: '序号', type: 'index', width: 60 }, { label: '序号', type: 'index', width: 60 },
{ label: '专家姓名', prop: 'name' }, { label: '专家姓名', prop: 'name' },
{ label: '电话', prop: 'mobile' },
{ label: '所在单位', prop: 'company' }, { label: '所在单位', prop: 'company' },
{ {
label: '性别', label: '性别',
......
...@@ -20,6 +20,7 @@ const listOptions = { ...@@ -20,6 +20,7 @@ const listOptions = {
{ label: '序号', type: 'index', width: 60 }, { label: '序号', type: 'index', width: 60 },
{ label: '选手姓名', prop: 'student.name' }, { label: '选手姓名', prop: 'student.name' },
{ label: '参赛ID', prop: 'login_id' }, { label: '参赛ID', prop: 'login_id' },
{ label: '电话', prop: 'mobile' },
{ {
label: '性别', label: '性别',
prop: 'student.gender', prop: 'student.gender',
......
<script setup lang="ts">
import type { FormInstance, FormRules } from 'element-plus'
import type { ContestItem, ContestCreateParams, ContestUpdateParams } from '../types'
import { ElMessage } from 'element-plus'
import { pick } from 'lodash-es'
import dayjs from 'dayjs'
import isBetween from 'dayjs/plugin/isBetween'
import { createContest, updateContest, getExamList } from '../api'
import { useMapStore } from '@/stores/map'
import { useGetTeacherList } from '../composables/useGetTeacherList'
import { useAppConfig } from '@/composables/useAppConfig'
const appConfig = useAppConfig()
interface Props {
data?: ContestItem | null
}
const props = defineProps<Props>()
const emit = defineEmits<{
(e: 'update'): void
(e: 'update:modelValue', visible: boolean): void
}>()
dayjs.extend(isBetween)
// 赛项类型
const types = useMapStore().getMapValuesByKey('competition_type')
// 主办单位
const hostUnitList = useMapStore().getMapValuesByKey('host_unit')
// 承办单位
const organizerList = useMapStore().getMapValuesByKey('organizer')
// 技术支持单位
const technicalSupportUnitList = useMapStore().getMapValuesByKey('technical_support_unit')
// 数据状态
const status = useMapStore().getMapValuesByKey('system_status')
// 指导老师
const { teachers } = useGetTeacherList()
const formRef = $ref<FormInstance>()
const form = reactive({
id: '',
name: '',
client_id: '',
host_unit_id: '',
organizer_ids: [],
technical_support_unit_id: '',
type: '1',
teacher_ids: [],
apply_expiration_date: '',
status: '1',
logo: '',
cover: '',
train_platform_uri: '',
competition_uri: '',
dateRange: undefined,
date: undefined,
datetimeRange: undefined,
datetimeRange2: undefined,
is_switchable_theory_practice: 0,
train_platform_configs: [
{ name: appConfig.xTrainLabel || '1+X理论考试', is_show: '1', type: '1', url: '', platform_key: 'x_exam' },
{
name: appConfig.labTrainLabel || '商业数据分析实验',
is_show: '0',
type: '2',
url: '',
platform_key: 'career_data_analysis'
},
{ name: '数据营销实操', is_show: '0', type: '2', url: '', platform_key: 'data_marketing' }
],
competition_platform_configs: [
{
name: appConfig.xExamLabel || '1+X理论考试',
is_show: '1',
type: '1',
url: '',
exam_id: '',
platform_key: 'x_exam'
},
// {
// name: appConfig.labExamLabel || '商业数据分析实验',
// is_show: '0',
// type: '2',
// url: '',
// platform_key: 'career_data_analysis'
// },
{ name: '数据营销实操', is_show: '0', type: '2', url: '', platform_key: 'data_marketing' }
]
})
watchEffect(() => {
if (!props.data) return
const host_unit_id = props.data.host_unit.id
const organizer_ids = props.data.organizers.map(item => item.id)
const technical_support_unit_id = props.data.technical_support_unit.id
const teacher_ids = props.data.teachers.map(item => item.id)
const dateRange = [new Date(props.data.start_range * 1000), new Date(props.data.end_range * 1000)]
const date = new Date(props.data.start_at * 1000)
const datetimeRange = [new Date(props.data.start_at * 1000), new Date(props.data.end_at * 1000)]
const datetimeRange2 = [
new Date(props.data.operational_start_time * 1000),
new Date(props.data.operational_end_time * 1000)
]
const is_switchable_theory_practice = parseInt(props.data.is_switchable_theory_practice)
const apply_expiration_date = props.data.apply_expiration_date * 1000
Object.assign(form, props.data, {
host_unit_id,
organizer_ids,
technical_support_unit_id,
teacher_ids,
dateRange,
date,
datetimeRange,
datetimeRange2,
apply_expiration_date,
is_switchable_theory_practice
})
})
const checkApplyExpirationDate = (rule: any, value: any, callback: any) => {
if (!value) {
callback(new Error('请选择报名截止日期'))
} else {
const [firstDate, secondDate] = form.dateRange || []
if (
!dayjs(value).isBetween(firstDate, secondDate, 'date', '[]') ||
!dayjs(value).isBefore(dayjs(form.date), 'date')
) {
callback(new Error('请选择赛项周期内的日期,且必须早于正式比赛日期'))
}
callback()
}
}
const checkTrainPlatformConfigs = (rule: any, value: any, callback: any) => {
const findItem = function (a: any, b: any) {
return form.train_platform_configs.find((item: any) => item[a] === b)
}
// 判断最少选择一项目
if (!findItem('is_show', '1')) {
callback(new Error('最少选择一项'))
} else {
form.train_platform_configs.forEach((item: any) => {
if (item.is_show === '1') {
if (item.type === '1') {
if (item.exam_id === '') {
callback(new Error(`请选择${item.name}`))
} else {
callback()
}
} else {
if (item.url === '') {
callback(new Error(`请填写${item.name}的链接`))
} else {
callback()
}
}
}
})
}
}
const checkCompetitionPlatformConfigs = (rule: any, value: any, callback: any) => {
const findItem = function (a: any, b: any) {
return form.competition_platform_configs.find((item: any) => item[a] === b)
}
// 判断最少选择一项目
if (!findItem('is_show', '1')) {
callback(new Error('最少选择一项'))
} else {
form.competition_platform_configs.forEach((item: any) => {
if (item.is_show === '1') {
if (item.type === '1') {
if (item.exam_id === '') {
callback(new Error(`请选择${item.name}`))
} else {
callback()
}
} else {
if (item.url === '') {
callback(new Error(`请填写${item.name}的链接`))
} else {
callback()
}
}
}
})
}
}
const rules = ref<FormRules>({
name: [{ required: true, message: '请输入赛项名称' }],
host_unit_id: [{ required: true, message: '请选择主办单位' }],
organizer_ids: [{ type: 'array', required: true, message: '请选择承办单位' }],
technical_support_unit_id: [{ required: true, message: '请选择技术支持单位' }],
type: [{ required: true, message: '请选择赛项类型' }],
teacher_ids: [{ type: 'array', required: true, message: '请选择指导教师', trigger: 'change' }],
dateRange: [{ type: 'array', required: true, message: '请选择赛项周期', trigger: 'change' }],
date: [{ required: true, message: '请选择正式比赛日期', trigger: 'change' }],
datetimeRange: [{ type: 'array', required: true, message: '正式比赛理论答题时间', trigger: 'change' }],
datetimeRange2: [{ type: 'array', required: true, message: '正式比赛实操答题时间', trigger: 'change' }],
apply_expiration_date: [
{ required: true, message: '请选择报名截止日期' },
{
validator: checkApplyExpirationDate,
message: '请选择赛项周期内的日期,且必须早于正式比赛日期'
}
],
// train_platform_uri: [{ required: true, message: '请输入训练平台地址' }],
// competition_uri: [{ required: true, message: '请输入正式比赛地址' }],
status: [{ required: true, message: '请选择有效状态' }],
is_switchable_theory_practice: [{ required: true, message: '请选择' }],
logo: [{ required: true, message: '请上传赛项LOGO' }],
cover: [{ required: true, message: '请上传赛项封面' }],
train_platform_configs: [{ required: true, message: '' }, { validator: checkTrainPlatformConfigs }],
competition_platform_configs: [{ required: true, message: '' }, { validator: checkCompetitionPlatformConfigs }]
})
const isUpdate = $computed(() => {
return !!form.id
})
const title = $computed(() => {
return isUpdate ? '编辑赛项' : '新增赛项'
})
// 是否禁用赛项周期
// const disabledRange = $computed(() => {
// const [firstDate, secondDate] = form.dateRange || []
// return isUpdate && dayjs().isBetween(firstDate, secondDate, 'date', '[]')
// })
// 提交
function handleSubmit() {
function containsNumber(A: number, B: number): boolean {
// 将数字A和B转换成字符串,并检查A的字符串是否包含B的字符串
return A.toString().includes(B.toString())
}
formRef?.validate().then(() => {
const [firstDate, secondDate] = form.dateRange || []
const [firstDatetime, secondDatetime] = form.datetimeRange || []
const [firstDatetime2, secondDatetime2] = form.datetimeRange2 || []
const year = dayjs(form.date).year()
const month = dayjs(form.date).month()
const date = dayjs(form.date).date()
const mergedForm = {
...form,
organizer_ids: JSON.stringify(form.organizer_ids),
// teacher_ids: form.teacher_ids.join(','),
start_range: dayjs(firstDate).unix(),
end_range: dayjs(secondDate).endOf('date').unix(),
start_at: dayjs(firstDatetime).year(year).month(month).date(date).unix(),
end_at: dayjs(secondDatetime).year(year).month(month).date(date).unix(),
operational_start_time: dayjs(firstDatetime2).year(year).month(month).date(date).unix(),
operational_end_time: dayjs(secondDatetime2).year(year).month(month).date(date).unix(),
apply_expiration_date: dayjs(form.apply_expiration_date).endOf('date').unix()
}
// 判断正式比赛理论答题时间和选择的考试
const findExam = examList.find(item => item.exam_id === form.competition_platform_configs[0].exam_id)
const examStartTime = new Date(findExam?.start_time || '').getTime()
const examEndTime = new Date(findExam?.end_time || '').getTime()
// console.log(containsNumber(examStartTime, mergedForm.start_at), containsNumber(examEndTime, mergedForm.end_at))
const findXItem = form.competition_platform_configs.find(item => item.type === '1')
console.log(findXItem, 'findXItem', form.competition_platform_configs)
if (findXItem?.is_show === '1') {
if (
containsNumber(examStartTime, mergedForm.start_at) !== true ||
containsNumber(examEndTime, mergedForm.end_at) !== true
) {
ElMessage({ message: `正式比赛理论答题时间与${findExam?.name}的考试时间不符`, type: 'warning' })
return false
}
}
const params: ContestUpdateParams = pick(mergedForm, [
'operational_start_time',
'operational_end_time',
'id',
'name',
'client_id',
'host_unit_id',
'organizer_ids',
'technical_support_unit_id',
'type',
'start_range',
'end_range',
'start_at',
'end_at',
'apply_expiration_date',
'status',
'logo',
'cover',
// 'train_platform_uri',
// 'competition_uri',
'teacher_ids',
'train_platform_configs',
'competition_platform_configs',
'is_switchable_theory_practice'
])
console.log(isUpdate, 'isUpdate')
isUpdate ? handleUpdate(params) : handleCreate(params)
})
}
// 新增
function handleCreate(params: ContestCreateParams) {
// console.log(params, 'aaa')
createContest(params).then(() => {
ElMessage({ message: '创建成功', type: 'success' })
emit('update')
emit('update:modelValue', false)
})
}
// 修改
function handleUpdate(params: ContestUpdateParams) {
updateContest(params).then(() => {
ElMessage({ message: '修改成功', type: 'success' })
emit('update')
emit('update:modelValue', false)
})
}
// 赛项周期改变
function handleDateRangeChange(value: any) {
if (value) {
const [, secondDate] = form.dateRange || []
form.date = secondDate
}
}
const clientList = [
{ label: '商务数据分析师赛项', value: 'business_data_analyst' },
{ label: '全媒体运营师赛项', value: 'all_media_operator' },
{ label: '网络主播赛项', value: 'network_anchor_competition' }
]
let examList = $ref<Record<string, any>[]>([])
// 获取关联考试列表
function fetchExamList() {
getExamList({ project: 'x1', 'per-page': 1000 }).then(res => {
examList = res.data.list || []
})
}
onMounted(() => {
fetchExamList()
})
</script>
<template>
<el-dialog
:title="title"
:close-on-click-modal="false"
align-center
width="600px"
@update:modelValue="value => $emit('update:modelValue', value)"
>
<el-form ref="formRef" :model="form" :rules="rules" label-width="165px">
<el-form-item label="客户端标识" prop="client_id">
<el-select v-model="form.client_id" style="width: 100%" clearable>
<el-option v-for="item in clientList" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="赛项名称" prop="name">
<el-input v-model="form.name" :disabled="isUpdate" />
</el-form-item>
<el-form-item label="主办单位" prop="host_unit_id">
<el-select v-model="form.host_unit_id" style="width: 100%">
<el-option v-for="item in hostUnitList" :key="item.id" :label="item.label" :value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="承办单位" prop="organizer_ids">
<el-select v-model="form.organizer_ids" multiple style="width: 100%">
<el-option v-for="item in organizerList" :key="item.id" :label="item.label" :value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="技术支持单位" prop="technical_support_unit_id">
<el-select v-model="form.technical_support_unit_id" style="width: 100%">
<el-option
v-for="item in technicalSupportUnitList"
:key="item.id"
:label="item.label"
:value="item.id"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="赛项类型" prop="type">
<el-radio-group v-model="form.type">
<el-radio v-for="item in types" :key="item.id" :label="item.value">{{ item.label }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="指导教师" prop="teacher_ids">
<el-select v-model="form.teacher_ids" multiple style="width: 100%">
<el-option v-for="item in teachers" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="赛项周期" prop="dateRange">
<el-date-picker
type="daterange"
range-separator="至"
v-model="form.dateRange"
style="width: 100%"
@change="handleDateRangeChange"
/>
</el-form-item>
<el-form-item label="正式比赛日期" prop="date">
<el-date-picker type="date" v-model="form.date" style="width: 100%" />
</el-form-item>
<el-form-item label="正式比赛理论答题时间" prop="datetimeRange">
<el-time-picker
is-range
range-separator="至"
start-placeholder="开始时间"
end-placeholder="结束时间"
v-model="form.datetimeRange"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="正式比赛实操答题时间" prop="datetimeRange2">
<el-time-picker
is-range
range-separator="至"
start-placeholder="开始时间"
end-placeholder="结束时间"
v-model="form.datetimeRange2"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="报名截止日期" prop="apply_expiration_date">
<el-date-picker type="date" v-model="form.apply_expiration_date" style="width: 100%" />
</el-form-item>
<el-form-item label="训练平台地址" prop="train_platform_configs">
<el-checkbox
true-label="1"
false-label="0"
style="margin-bottom: 10px"
v-model="item.is_show"
v-for="item in form.train_platform_configs"
:key="item.platform_key"
>
<div style="display: flex; align-items: center">
<!-- <span style="margin-right: 10px; width: 180px">{{ item.name }}</span> -->
<el-input v-model="item.name" style="margin-right: 10px; max-width: 130px" />
<el-input v-model="item.url" style="width: 200px" />
</div>
</el-checkbox>
</el-form-item>
<el-form-item label="正式比赛地址" prop="competition_platform_configs">
<el-checkbox
true-label="1"
false-label="0"
style="margin-bottom: 10px"
v-model="item.is_show"
v-for="item in form.competition_platform_configs"
:key="item.platform_key"
>
<div style="display: flex; align-items: center">
<!-- <span style="margin-right: 10px; width: 180px">{{ item.name }}</span> -->
<el-input v-model="item.name" style="margin-right: 10px; max-width: 130px" />
<el-input v-model="item.url" v-if="item.type === '2'" style="width: 200px" />
<el-select v-model="item.exam_id" filterable style="width: 200px" v-if="item.type === '1'">
<el-option
v-for="item in examList"
:key="item.exam_id"
:label="item.name"
:value="item.exam_id"
></el-option>
</el-select>
</div>
</el-checkbox>
</el-form-item>
<el-form-item label="是否允许客户端切换" prop="is_switchable_theory_practice">
<el-radio-group v-model="form.is_switchable_theory_practice">
<el-radio :label="0"></el-radio>
<el-radio :label="1"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="有效状态" prop="status">
<el-radio-group v-model="form.status">
<el-radio v-for="item in status" :key="item.id" :label="item.value">{{ item.label }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="赛项LOGO" prop="logo">
<AppUpload v-model="form.logo" accept="image/*"></AppUpload>
</el-form-item>
<el-form-item label="赛项封面" prop="cover">
<AppUpload v-model="form.cover" accept="image/*"></AppUpload>
</el-form-item>
<el-row justify="center">
<el-button type="primary" round auto-insert-space @click="handleSubmit">保存</el-button>
<el-button round auto-insert-space @click="$emit('update:modelValue', false)">取消</el-button>
</el-row>
</el-form>
</el-dialog>
</template>
...@@ -60,6 +60,7 @@ const form = reactive({ ...@@ -60,6 +60,7 @@ const form = reactive({
datetimeRange: undefined, datetimeRange: undefined,
datetimeRange2: undefined, datetimeRange2: undefined,
is_switchable_theory_practice: 0, is_switchable_theory_practice: 0,
is_customer_anti_cheat: 0,
train_platform_configs: [ train_platform_configs: [
{ name: appConfig.xTrainLabel || '1+X理论考试', is_show: '1', type: '1', url: '', platform_key: 'x_exam' }, { name: appConfig.xTrainLabel || '1+X理论考试', is_show: '1', type: '1', url: '', platform_key: 'x_exam' },
{ {
...@@ -104,6 +105,9 @@ watchEffect(() => { ...@@ -104,6 +105,9 @@ watchEffect(() => {
new Date(props.data.operational_end_time * 1000) new Date(props.data.operational_end_time * 1000)
] ]
const is_switchable_theory_practice = parseInt(props.data.is_switchable_theory_practice) const is_switchable_theory_practice = parseInt(props.data.is_switchable_theory_practice)
const is_customer_anti_cheat = parseInt(props.data?.is_customer_anti_cheat) || 0
const type = props.data?.type + ''
const status = props.data?.status + ''
const apply_expiration_date = props.data.apply_expiration_date * 1000 const apply_expiration_date = props.data.apply_expiration_date * 1000
Object.assign(form, props.data, { Object.assign(form, props.data, {
host_unit_id, host_unit_id,
...@@ -115,7 +119,10 @@ watchEffect(() => { ...@@ -115,7 +119,10 @@ watchEffect(() => {
datetimeRange, datetimeRange,
datetimeRange2, datetimeRange2,
apply_expiration_date, apply_expiration_date,
is_switchable_theory_practice is_switchable_theory_practice,
is_customer_anti_cheat,
type,
status
}) })
}) })
const checkApplyExpirationDate = (rule: any, value: any, callback: any) => { const checkApplyExpirationDate = (rule: any, value: any, callback: any) => {
...@@ -210,6 +217,7 @@ const rules = ref<FormRules>({ ...@@ -210,6 +217,7 @@ const rules = ref<FormRules>({
// competition_uri: [{ required: true, message: '请输入正式比赛地址' }], // competition_uri: [{ required: true, message: '请输入正式比赛地址' }],
status: [{ required: true, message: '请选择有效状态' }], status: [{ required: true, message: '请选择有效状态' }],
is_switchable_theory_practice: [{ required: true, message: '请选择' }], is_switchable_theory_practice: [{ required: true, message: '请选择' }],
is_customer_anti_cheat: [{ required: true, message: '请选择' }],
logo: [{ required: true, message: '请上传赛项LOGO' }], logo: [{ required: true, message: '请上传赛项LOGO' }],
cover: [{ required: true, message: '请上传赛项封面' }], cover: [{ required: true, message: '请上传赛项封面' }],
train_platform_configs: [{ required: true, message: '' }, { validator: checkTrainPlatformConfigs }], train_platform_configs: [{ required: true, message: '' }, { validator: checkTrainPlatformConfigs }],
...@@ -218,9 +226,6 @@ const rules = ref<FormRules>({ ...@@ -218,9 +226,6 @@ const rules = ref<FormRules>({
const isUpdate = $computed(() => { const isUpdate = $computed(() => {
return !!form.id return !!form.id
}) })
const title = $computed(() => {
return isUpdate ? '编辑赛项' : '新增赛项'
})
// 是否禁用赛项周期 // 是否禁用赛项周期
// const disabledRange = $computed(() => { // const disabledRange = $computed(() => {
// const [firstDate, secondDate] = form.dateRange || [] // const [firstDate, secondDate] = form.dateRange || []
...@@ -292,7 +297,8 @@ function handleSubmit() { ...@@ -292,7 +297,8 @@ function handleSubmit() {
'teacher_ids', 'teacher_ids',
'train_platform_configs', 'train_platform_configs',
'competition_platform_configs', 'competition_platform_configs',
'is_switchable_theory_practice' 'is_switchable_theory_practice',
'is_customer_anti_cheat'
]) ])
console.log(isUpdate, 'isUpdate') console.log(isUpdate, 'isUpdate')
isUpdate ? handleUpdate(params) : handleCreate(params) isUpdate ? handleUpdate(params) : handleCreate(params)
...@@ -343,52 +349,22 @@ onMounted(() => { ...@@ -343,52 +349,22 @@ onMounted(() => {
</script> </script>
<template> <template>
<el-dialog
:title="title"
:close-on-click-modal="false"
align-center
width="600px"
@update:modelValue="value => $emit('update:modelValue', value)"
>
<el-form ref="formRef" :model="form" :rules="rules" label-width="165px"> <el-form ref="formRef" :model="form" :rules="rules" label-width="165px">
<el-form-item label="客户端标识" prop="client_id"> <div style="display: flex">
<el-select v-model="form.client_id" style="width: 100%" clearable> <div style="flex: 1; margin-right: 10px">
<el-option v-for="item in clientList" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="赛项名称" prop="name"> <el-form-item label="赛项名称" prop="name">
<el-input v-model="form.name" :disabled="isUpdate" /> <el-input v-model="form.name" />
</el-form-item>
<el-form-item label="主办单位" prop="host_unit_id">
<el-select v-model="form.host_unit_id" style="width: 100%">
<el-option v-for="item in hostUnitList" :key="item.id" :label="item.label" :value="item.id"></el-option>
</el-select>
</el-form-item> </el-form-item>
<el-form-item label="承办单位" prop="organizer_ids"> <el-form-item label="承办单位" prop="organizer_ids">
<el-select v-model="form.organizer_ids" multiple style="width: 100%"> <el-select v-model="form.organizer_ids" multiple style="width: 100%">
<el-option v-for="item in organizerList" :key="item.id" :label="item.label" :value="item.id"></el-option> <el-option v-for="item in organizerList" :key="item.id" :label="item.label" :value="item.id"></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="技术支持单位" prop="technical_support_unit_id">
<el-select v-model="form.technical_support_unit_id" style="width: 100%">
<el-option
v-for="item in technicalSupportUnitList"
:key="item.id"
:label="item.label"
:value="item.id"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="赛项类型" prop="type"> <el-form-item label="赛项类型" prop="type">
<el-radio-group v-model="form.type"> <el-radio-group v-model="form.type">
<el-radio v-for="item in types" :key="item.id" :label="item.value">{{ item.label }}</el-radio> <el-radio v-for="item in types" :key="item.id" :label="item.value">{{ item.label }}</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="指导教师" prop="teacher_ids">
<el-select v-model="form.teacher_ids" multiple style="width: 100%">
<el-option v-for="item in teachers" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="赛项周期" prop="dateRange"> <el-form-item label="赛项周期" prop="dateRange">
<el-date-picker <el-date-picker
type="daterange" type="daterange"
...@@ -411,19 +387,6 @@ onMounted(() => { ...@@ -411,19 +387,6 @@ onMounted(() => {
style="width: 100%" style="width: 100%"
/> />
</el-form-item> </el-form-item>
<el-form-item label="正式比赛实操答题时间" prop="datetimeRange2">
<el-time-picker
is-range
range-separator="至"
start-placeholder="开始时间"
end-placeholder="结束时间"
v-model="form.datetimeRange2"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="报名截止日期" prop="apply_expiration_date">
<el-date-picker type="date" v-model="form.apply_expiration_date" style="width: 100%" />
</el-form-item>
<el-form-item label="训练平台地址" prop="train_platform_configs"> <el-form-item label="训练平台地址" prop="train_platform_configs">
<el-checkbox <el-checkbox
true-label="1" true-label="1"
...@@ -440,6 +403,69 @@ onMounted(() => { ...@@ -440,6 +403,69 @@ onMounted(() => {
</div> </div>
</el-checkbox> </el-checkbox>
</el-form-item> </el-form-item>
<el-form-item label="指导教师" prop="teacher_ids">
<el-select v-model="form.teacher_ids" multiple style="width: 100%">
<el-option v-for="item in teachers" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="实操赛题标签名称" prop="name">
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="实操环境标签名称" prop="name">
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="实操报告标签名称" prop="name">
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="实操答题标签名称" prop="name">
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="有效状态" prop="status">
<el-radio-group v-model="form.status">
<el-radio v-for="item in status" :key="item.id" :label="item.value">{{ item.label }}</el-radio>
</el-radio-group>
</el-form-item>
</div>
<div style="flex: 1; margin-left: 10px">
<el-form-item label="主办单位" prop="host_unit_id">
<el-select v-model="form.host_unit_id" style="width: 100%">
<el-option v-for="item in hostUnitList" :key="item.id" :label="item.label" :value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="技术支持单位" prop="technical_support_unit_id">
<el-select v-model="form.technical_support_unit_id" style="width: 100%">
<el-option
v-for="item in technicalSupportUnitList"
:key="item.id"
:label="item.label"
:value="item.id"
></el-option>
</el-select>
</el-form-item>
<!-- <el-form-item label="客户端" prop="type">
<el-radio-group v-model="form.type">
<el-radio v-for="item in types" :key="item.id" :label="item.value">{{ item.label }}</el-radio>
</el-radio-group>
</el-form-item> -->
<el-form-item label="客户端标识" prop="client_id">
<el-select v-model="form.client_id" style="width: 100%" clearable>
<el-option v-for="item in clientList" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="报名截止日期" prop="apply_expiration_date">
<el-date-picker type="date" v-model="form.apply_expiration_date" style="width: 100%" />
</el-form-item>
<el-form-item label="正式比赛实操答题时间" prop="datetimeRange2">
<el-time-picker
is-range
range-separator="至"
start-placeholder="开始时间"
end-placeholder="结束时间"
v-model="form.datetimeRange2"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="正式比赛地址" prop="competition_platform_configs"> <el-form-item label="正式比赛地址" prop="competition_platform_configs">
<el-checkbox <el-checkbox
true-label="1" true-label="1"
...@@ -470,21 +496,31 @@ onMounted(() => { ...@@ -470,21 +496,31 @@ onMounted(() => {
<el-radio :label="1"></el-radio> <el-radio :label="1"></el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="有效状态" prop="status"> <el-form-item label="客户端防作弊" prop="is_customer_anti_cheat">
<el-radio-group v-model="form.status"> <el-radio-group v-model="form.is_customer_anti_cheat">
<el-radio v-for="item in status" :key="item.id" :label="item.value">{{ item.label }}</el-radio> <el-radio :label="0"></el-radio>
<el-radio :label="1"></el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="客户端切换理论与实操" prop="is_switchable_theory_practice">
<el-radio-group v-model="form.is_switchable_theory_practice">
<el-radio :label="0"></el-radio>
<el-radio :label="1"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="赛项LOGO" prop="logo"> <el-form-item label="赛项LOGO" prop="logo">
<AppUpload v-model="form.logo" accept="image/*"></AppUpload> <AppUpload v-model="form.logo" accept="image/*"></AppUpload>
</el-form-item> </el-form-item>
<el-form-item label="赛项封面" prop="cover"> <el-form-item label="赛项封面" prop="cover">
<AppUpload v-model="form.cover" accept="image/*"></AppUpload> <AppUpload v-model="form.cover" accept="image/*"></AppUpload>
</el-form-item> </el-form-item>
</div>
</div>
<el-row justify="center"> <el-row justify="center">
<el-button type="primary" round auto-insert-space @click="handleSubmit">保存</el-button> <el-button type="primary" round auto-insert-space @click="handleSubmit">保存</el-button>
<el-button round auto-insert-space @click="$emit('update:modelValue', false)">取消</el-button> <el-button round auto-insert-space @click="$emit('update:modelValue', false)">取消</el-button>
</el-row> </el-row>
</el-form> </el-form>
</el-dialog>
</template> </template>
...@@ -43,6 +43,7 @@ const listOptions = $computed(() => { ...@@ -43,6 +43,7 @@ const listOptions = $computed(() => {
{ type: 'expand', slots: 'class' }, { type: 'expand', slots: 'class' },
{ label: '序号', type: 'index', width: 60 }, { label: '序号', type: 'index', width: 60 },
{ label: '专家姓名', prop: 'name' }, { label: '专家姓名', prop: 'name' },
{ label: '电话', prop: 'mobile' },
{ label: '所在单位', prop: 'company' }, { label: '所在单位', prop: 'company' },
{ {
label: '性别', label: '性别',
......
...@@ -11,7 +11,8 @@ export const routes: Array<RouteRecordRaw> = [ ...@@ -11,7 +11,8 @@ export const routes: Array<RouteRecordRaw> = [
component: AppLayout, component: AppLayout,
children: [ children: [
{ path: '', component: () => import('./views/Index.vue') }, { path: '', component: () => import('./views/Index.vue') },
{ path: ':id', component: () => import('./views/View.vue'), props: true } { path: ':id', component: () => import('./views/View.vue'), props: true },
{ path: 'edit/:id', component: () => import('./views/Edit.vue'), props: true }
] ]
} }
] ]
...@@ -34,7 +34,8 @@ export interface ContestItem { ...@@ -34,7 +34,8 @@ export interface ContestItem {
expert_count: number expert_count: number
train_platform_configs: any[] train_platform_configs: any[]
competition_platform_configs: any[] competition_platform_configs: any[]
is_switchable_theory_practice: string is_switchable_theory_practice: string,
is_customer_anti_cheat: string
} }
export interface ContestCreateParams { export interface ContestCreateParams {
......
<script setup lang="ts">
import type { ContestItem } from '../types'
// import { ElMessage } from 'element-plus'
import { getContest } from '../api'
const FormDialog = defineAsyncComponent(() => import('../components/FormDialog.vue'))
interface Props {
id: string
}
const props = defineProps<Props>()
let detail = $ref<ContestItem | null>(null)
provide('detail', $$(detail))
// 获取赛项信息
function fetchInfo() {
getContest({ id: props.id }).then(res => {
detail = res.data.detail
})
}
onMounted(() => {
if (props.id === '1') return
fetchInfo()
})
</script>
<template>
<AppCard title="编辑赛项">
<FormDialog :data="detail"></FormDialog>
</AppCard>
</template>
<style lang="scss">
.top {
display: flex;
.el-descriptions {
flex: 1;
margin-top: 30px;
}
}
.top-cover {
width: 300px;
margin-right: 20px;
p {
font-weight: normal;
line-height: 30px;
font-size: 14px;
}
img {
width: 100%;
}
}
</style>
...@@ -8,7 +8,7 @@ import { useMapStore } from '@/stores/map' ...@@ -8,7 +8,7 @@ import { useMapStore } from '@/stores/map'
// 赛项类型 // 赛项类型
const types = useMapStore().getMapValuesByKey('competition_type') const types = useMapStore().getMapValuesByKey('competition_type')
const FormDialog = defineAsyncComponent(() => import('../components/FormDialog.vue')) // const FormDialog = defineAsyncComponent(() => import('../components/FormDialog.vue'))
const appList = $ref<InstanceType<typeof AppList> | null>(null) const appList = $ref<InstanceType<typeof AppList> | null>(null)
...@@ -50,31 +50,34 @@ const listOptions = { ...@@ -50,31 +50,34 @@ const listOptions = {
] ]
} }
let dialogVisible = $ref(false) // let dialogVisible = $ref(false)
const rowData = ref<ContestItem | undefined | null>(null) // const rowData = ref<ContestItem | undefined | null>(null)
// 新增 // 新增
function handleAdd() { // function handleAdd() {
rowData.value = null // rowData.value = null
dialogVisible = true // dialogVisible = true
} // }
// 编辑 // // 编辑
function handleUpdate(row: ContestItem) { // function handleUpdate(row: ContestItem) {
rowData.value = row // rowData.value = row
dialogVisible = true // dialogVisible = true
} // }
function onUpdateSuccess() { // function onUpdateSuccess() {
appList?.refetch() // appList?.refetch()
} // }
</script> </script>
<template> <template>
<AppCard title="赛项管理"> <AppCard title="赛项管理">
<AppList v-bind="listOptions" ref="appList"> <AppList v-bind="listOptions" ref="appList">
<template #header-buttons> <template #header-buttons>
<el-button type="primary" :icon="CirclePlus" v-permission="'competition-create'" @click="handleAdd"> <!-- <el-button type="primary" :icon="CirclePlus" v-permission="'competition-create'" @click="handleAdd">
新增赛项 新增赛项
</el-button> -->
<el-button type="primary" :icon="CirclePlus" round v-permission="'competition-create'">
<router-link :to="`/admin/contest/items/edit/1`" target="_blank">新增赛项</router-link>
</el-button> </el-button>
</template> </template>
...@@ -82,9 +85,14 @@ function onUpdateSuccess() { ...@@ -82,9 +85,14 @@ function onUpdateSuccess() {
<el-button type="primary" round v-permission="'competition-detail'"> <el-button type="primary" round v-permission="'competition-detail'">
<router-link :to="`/admin/contest/items/${row.id}`" target="_blank">查看</router-link> <router-link :to="`/admin/contest/items/${row.id}`" target="_blank">查看</router-link>
</el-button> </el-button>
<el-button type="primary" round @click="handleUpdate(row)" v-permission="'competition-edit'">编辑</el-button> <el-button type="primary" round v-permission="'competition-detail'">
<router-link :to="`/admin/contest/items/edit/${row.id}`" target="_blank" v-permission="'competition-edit'"
>编辑</router-link
>
</el-button>
<!-- <el-button type="primary" round @click="handleUpdate(row)" v-permission="'competition-edit'">编辑</el-button> -->
</template> </template>
</AppList> </AppList>
</AppCard> </AppCard>
<FormDialog v-model="dialogVisible" :data="rowData" @update="onUpdateSuccess" v-if="dialogVisible"></FormDialog> <!-- <FormDialog v-model="dialogVisible" :data="rowData" @update="onUpdateSuccess" v-if="dialogVisible"></FormDialog> -->
</template> </template>
...@@ -161,16 +161,16 @@ function handleExperts() { ...@@ -161,16 +161,16 @@ function handleExperts() {
<AppCard title="训练指导书"> <AppCard title="训练指导书">
<ViewBook :id="id"></ViewBook> <ViewBook :id="id"></ViewBook>
</AppCard> </AppCard>
<AppCard title="操作视频"> <AppCard title="训练操作视频">
<ViewVideo :id="id"></ViewVideo> <ViewVideo :id="id"></ViewVideo>
</AppCard> </AppCard>
<AppCard title="大赛试题"> <AppCard title="比赛实操赛题">
<ViewQuestion :id="id"></ViewQuestion> <ViewQuestion :id="id"></ViewQuestion>
</AppCard> </AppCard>
<AppCard title="大赛试卷"> <AppCard title="比赛实操试卷">
<ViewExam :id="id"></ViewExam> <ViewExam :id="id"></ViewExam>
</AppCard> </AppCard>
<AppCard title="关联实验"> <AppCard title="关联营销实验">
<ViewExperiment :id="detail?.id || ''" :pid="id"></ViewExperiment> <ViewExperiment :id="detail?.id || ''" :pid="id"></ViewExperiment>
</AppCard> </AppCard>
<AppCard title="抽签加密"> <AppCard title="抽签加密">
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论