提交 d36d9426 authored 作者: 王鹏飞's avatar 王鹏飞

chore: update

上级 718c4ccf
import httpRequest from '@/utils/axios' import httpRequest from '@/utils/axios'
import type { JudgeCreateParams, JudgeUpdateParams } from './types' import type { ExpertCreateParams, ExpertUpdateParams } from './types'
// 获取评分专家列表 // 获取评分专家列表
export function getJudgeList(params?: { name?: string; page?: number; 'per-page'?: number }) { export function getExpertList(params?: { name?: string; page?: number; 'per-page'?: number }) {
return httpRequest.get('/api/resource/v1/backend/expert/list', { params }) return httpRequest.get('/api/resource/v1/backend/expert/list', { params })
} }
// 获取评分专家详情 // 获取评分专家详情
export function getJudge(params: { id: string }) { export function getExpert(params: { id: string }) {
return httpRequest.get('/api/resource/v1/backend/expert/detail', { params }) return httpRequest.get('/api/resource/v1/backend/expert/detail', { params })
} }
// 创建评分专家 // 创建评分专家
export function createJudge(data: JudgeCreateParams) { export function createExpert(data: ExpertCreateParams) {
return httpRequest.post('/api/resource/v1/backend/expert/create', data) return httpRequest.post('/api/resource/v1/backend/expert/create', data)
} }
// 修改评分专家 // 修改评分专家
export function updateJudge(data: JudgeUpdateParams) { export function updateExpert(data: ExpertUpdateParams) {
return httpRequest.post('/api/resource/v1/backend/expert/update', data) return httpRequest.post('/api/resource/v1/backend/expert/update', data)
} }
// 修改评分专家 // 修改评分专家
export function importJudge(data: { file: File }) { export function importExpert(data: { file: File }) {
return httpRequest.post('/api/resource/v1/backend/expert/import-exports', data, { return httpRequest.post('/api/resource/v1/backend/expert/import-exports', data, {
headers: { 'Content-Type': 'multipart/form-data' } headers: { 'Content-Type': 'multipart/form-data' }
}) })
} }
// 获取评分专家赛项列表 // 获取评分专家赛项列表
export function getJudgeContestList(params: { id: string }) { export function getExpertContestList(params: { id: string }) {
return httpRequest.get('/api/resource/v1/backend/expert/competitions', { params }) return httpRequest.get('/api/resource/v1/backend/expert/competitions', { params })
} }
<script setup lang="ts"> <script setup lang="ts">
import type { FormInstance, FormRules } from 'element-plus' import type { FormInstance, FormRules } from 'element-plus'
import type { Judge, JudgeCreateParams } from '../types' import type { Expert, ExpertCreateParams } from '../types'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { createJudge, updateJudge } from '../api' import { createExpert, updateExpert } from '../api'
import { useMapStore } from '@/stores/map' import { useMapStore } from '@/stores/map'
import { useArea } from '@/composables/useArea' import { useArea } from '@/composables/useArea'
interface Props { interface Props {
data?: Judge data?: Expert
} }
const props = defineProps<Props>() const props = defineProps<Props>()
...@@ -23,7 +23,7 @@ const genderList = useMapStore().getMapValuesByKey('system_gender') ...@@ -23,7 +23,7 @@ const genderList = useMapStore().getMapValuesByKey('system_gender')
const positionList = useMapStore().getMapValuesByKey('expert_position') const positionList = useMapStore().getMapValuesByKey('expert_position')
const formRef = $ref<FormInstance>() const formRef = $ref<FormInstance>()
const form = reactive<JudgeCreateParams>({ const form = reactive<ExpertCreateParams>({
name: '', name: '',
mobile: '', mobile: '',
company: '', company: '',
...@@ -74,7 +74,7 @@ function handleSubmit() { ...@@ -74,7 +74,7 @@ function handleSubmit() {
} }
// 新增 // 新增
function handleCreate() { function handleCreate() {
createJudge(form).then(() => { createExpert(form).then(() => {
ElMessage({ message: '创建成功', type: 'success' }) ElMessage({ message: '创建成功', type: 'success' })
emit('update') emit('update')
emit('update:modelValue', false) emit('update:modelValue', false)
...@@ -83,7 +83,7 @@ function handleCreate() { ...@@ -83,7 +83,7 @@ function handleCreate() {
// 修改 // 修改
function handleUpdate() { function handleUpdate() {
if (!props.data?.id) return if (!props.data?.id) return
updateJudge({ id: props.data.id, ...form }).then(() => { updateExpert({ id: props.data.id, ...form }).then(() => {
ElMessage({ message: '修改成功', type: 'success' }) ElMessage({ message: '修改成功', type: 'success' })
emit('update') emit('update')
emit('update:modelValue', false) emit('update:modelValue', false)
......
...@@ -3,7 +3,7 @@ import { Upload } from '@element-plus/icons-vue' ...@@ -3,7 +3,7 @@ import { Upload } from '@element-plus/icons-vue'
import { useFileDialog } from '@vueuse/core' import { useFileDialog } from '@vueuse/core'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { importJudge } from '../api' import { importExpert } from '../api'
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'update'): void (e: 'update'): void
...@@ -20,7 +20,7 @@ function handleImport() { ...@@ -20,7 +20,7 @@ function handleImport() {
watchEffect(() => { watchEffect(() => {
if (!files.value?.length) return if (!files.value?.length) return
const [file] = files.value const [file] = files.value
importJudge({ file }).then(() => { importExpert({ file }).then(() => {
ElMessage({ message: '导入成功', type: 'success' }) ElMessage({ message: '导入成功', type: 'success' })
emit('update') emit('update')
}) })
......
<script setup lang="ts"> <script setup lang="ts">
import type { Judge } from '../types' import type { Expert } from '../types'
import { getJudgeContestList } from '../api' import { getExpertContestList } from '../api'
import { useMapStore } from '@/stores/map' import { useMapStore } from '@/stores/map'
interface Props { interface Props {
data: Judge data: Expert
} }
const props = defineProps<Props>() const props = defineProps<Props>()
...@@ -15,7 +15,7 @@ const roleList = useMapStore().getMapValuesByKey('expert_role') ...@@ -15,7 +15,7 @@ const roleList = useMapStore().getMapValuesByKey('expert_role')
const listOptions = { const listOptions = {
hasPagination: false, hasPagination: false,
remote: { remote: {
httpRequest: getJudgeContestList, httpRequest: getExpertContestList,
params: { id: props.data.id }, params: { id: props.data.id },
callback(res: any) { callback(res: any) {
return { list: res.detail.competitions } return { list: res.detail.competitions }
......
...@@ -3,7 +3,7 @@ import AppLayout from '@/components/layout/Index.vue' ...@@ -3,7 +3,7 @@ import AppLayout from '@/components/layout/Index.vue'
export const routes: Array<RouteRecordRaw> = [ export const routes: Array<RouteRecordRaw> = [
{ {
path: '/admin/contest/judges', path: '/admin/contest/experts',
component: AppLayout, component: AppLayout,
children: [{ path: '', component: () => import('./views/Index.vue') }] children: [{ path: '', component: () => import('./views/Index.vue') }]
} }
......
export interface Judge { export interface Expert {
id: string id: string
sso_id: string sso_id: string
name: string name: string
...@@ -12,20 +12,20 @@ export interface Judge { ...@@ -12,20 +12,20 @@ export interface Judge {
updated_operator: string updated_operator: string
created_time: string created_time: string
updated_time: string updated_time: string
position: JudgePosition position: ExpertPosition
competition: JudgeCompetition competition: ExpertCompetition
check_count: 1 check_count: 1
} }
export interface JudgePosition { export interface ExpertPosition {
id: string id: string
label: string label: string
value: string value: string
} }
export interface JudgeCompetition { export interface ExpertCompetition {
id: string id: string
name: string name: string
} }
export interface JudgeCreateParams { export interface ExpertCreateParams {
name: string name: string
mobile: string mobile: string
company: string company: string
...@@ -36,4 +36,4 @@ export interface JudgeCreateParams { ...@@ -36,4 +36,4 @@ export interface JudgeCreateParams {
area: string area: string
} }
export type JudgeUpdateParams = JudgeCreateParams & { id: string } export type ExpertUpdateParams = ExpertCreateParams & { id: string }
<script setup lang="ts"> <script setup lang="ts">
import type { Judge } from '../types' import type { Expert } from '../types'
import { CirclePlus, Upload } from '@element-plus/icons-vue' import { CirclePlus, Upload } from '@element-plus/icons-vue'
import AppList from '@/components/base/AppList.vue' import AppList from '@/components/base/AppList.vue'
import { getJudgeList } from '../api' import { getExpertList } from '../api'
import { useMapStore } from '@/stores/map' import { useMapStore } from '@/stores/map'
import { useGetContestList } from '@/composables/useGetContestList' import { useGetContestList } from '@/composables/useGetContestList'
...@@ -19,7 +19,7 @@ const { contests } = useGetContestList() ...@@ -19,7 +19,7 @@ const { contests } = useGetContestList()
const listOptions = $computed(() => { const listOptions = $computed(() => {
return { return {
remote: { remote: {
httpRequest: getJudgeList, httpRequest: getExpertList,
params: { competition_id: '', name: '' } params: { competition_id: '', name: '' }
}, },
filters: [ filters: [
...@@ -41,7 +41,7 @@ const listOptions = $computed(() => { ...@@ -41,7 +41,7 @@ const listOptions = $computed(() => {
{ {
label: '性别', label: '性别',
prop: 'sex', prop: 'sex',
computed({ row }: { row: Judge }) { computed({ row }: { row: Expert }) {
const found = genderList.find(item => item.value === row.sex) const found = genderList.find(item => item.value === row.sex)
return found?.label || row.sex return found?.label || row.sex
} }
...@@ -58,11 +58,11 @@ const listOptions = $computed(() => { ...@@ -58,11 +58,11 @@ const listOptions = $computed(() => {
}) })
const importVisible = $ref(false) const importVisible = $ref(false)
const rowData = ref<Judge | undefined | null>(null) const rowData = ref<Expert | undefined | null>(null)
// 查看 // 查看
let viewDialogVisible = $ref(false) let viewDialogVisible = $ref(false)
function handleView(row: Judge) { function handleView(row: Expert) {
rowData.value = row rowData.value = row
viewDialogVisible = true viewDialogVisible = true
} }
...@@ -75,7 +75,7 @@ function handleAdd() { ...@@ -75,7 +75,7 @@ function handleAdd() {
// 编辑 // 编辑
let dialogVisible = $ref(false) let dialogVisible = $ref(false)
function handleUpdate(row: Judge) { function handleUpdate(row: Expert) {
rowData.value = row rowData.value = row
dialogVisible = true dialogVisible = true
} }
...@@ -93,7 +93,7 @@ function onUpdateSuccess() { ...@@ -93,7 +93,7 @@ function onUpdateSuccess() {
<el-button type="primary" round :icon="Upload" @click="importVisible = true">批量导入</el-button> <el-button type="primary" round :icon="Upload" @click="importVisible = true">批量导入</el-button>
</template> </template>
<template #table-x="{ row }: { row: Judge }"> <template #table-x="{ row }: { row: Expert }">
<el-button type="primary" round @click="handleView(row)" v-permission="'v1-backend-experiment-view'" <el-button type="primary" round @click="handleView(row)" v-permission="'v1-backend-experiment-view'"
>查看</el-button >查看</el-button
> >
......
...@@ -18,7 +18,6 @@ const listOptions = { ...@@ -18,7 +18,6 @@ const listOptions = {
filters: [{ type: 'input', prop: 'student_name', label: '选手姓名', placeholder: '请输入选手姓名' }], filters: [{ type: 'input', prop: 'student_name', label: '选手姓名', placeholder: '请输入选手姓名' }],
columns: [ columns: [
{ label: '序号', type: 'index', width: 60 }, { label: '序号', type: 'index', width: 60 },
{ label: '赛项名称', prop: 'competition.name' },
{ label: '选手姓名', prop: 'student.name' }, { label: '选手姓名', prop: 'student.name' },
{ label: '参赛ID', prop: 'login_id' }, { label: '参赛ID', prop: 'login_id' },
{ {
......
<script setup lang="ts">
import type { FormInstance, FormRules } from 'element-plus'
import type { ContestItem, ContestBookItem, ContestBookUpdateParams } from '../types'
import { ElMessageBox, ElMessage } from 'element-plus'
import { pick } from 'lodash-es'
import AppUpload from '@/components/base/AppUpload.vue'
import { createContestBook, updateContestBook } from '../api'
import { useMapStore } from '@/stores/map'
interface Props {
data: ContestBookItem
}
const props = defineProps<Props>()
const emit = defineEmits<{
(e: 'update'): void
(e: 'update:modelValue', visible: boolean): void
}>()
const detail = $ref<ContestItem>(inject('detail'))
// 数据状态
const status = useMapStore().getMapValuesByKey('system_status')
const formRef = $ref<FormInstance>()
const form = reactive<any>({
competition_id: detail.id,
files: [],
url: '',
type: '',
name: '',
status: '1',
protocol: false
})
watchEffect(() => {
if (!props.data) return
form.files = [JSON.parse(props.data.url)]
Object.assign(form, { protocol: true }, props.data)
})
const checkProtocol = (rule: any, value: any, callback: any) => {
if (!value) {
return callback(new Error('请阅读并同意'))
} else {
callback()
}
}
const rules = ref<FormRules>({
files: [{ type: 'array', required: true, message: '请上传评分细则' }],
name: [{ required: true, message: '请输入评分细则名称', trigger: 'blur' }],
course_id: [{ required: true, message: '请选择关联训练课程', trigger: 'change' }],
experiment_id: [{ required: true, message: '请选择关联训练', trigger: 'change' }],
protocol: [{ validator: checkProtocol, message: '请阅读并同意', trigger: 'change' }]
})
const isUpdate = $computed(() => {
return !!props.data?.id
})
function handleBeforeUpload() {
if (form.files.length) {
return ElMessageBox.confirm('系统仅支持1个评分细则,此操作将覆盖原有评分细则文件,确认上传新文件吗?', '提示')
}
return true
}
function handleUploadSuccess(file: any) {
form.name = file.name.split('.').shift()
form.type = file.raw.type || 'unknown'
}
// 提交
function handleSubmit() {
formRef?.validate().then(() => {
const [file] = form.files
const params = Object.assign({}, pick(form, ['competition_id', 'name', 'type', 'status']), {
url: JSON.stringify({ name: file.name, url: file.url, size: file.size })
})
isUpdate ? handleUpdate(params) : handleCreate(params)
})
}
// 新增
function handleCreate(params: ContestBookUpdateParams) {
createContestBook(params).then(() => {
ElMessage({ message: '创建成功', type: 'success' })
emit('update')
emit('update:modelValue', false)
})
}
// 修改
function handleUpdate(params: ContestBookUpdateParams) {
updateContestBook(params).then(() => {
ElMessage({ message: '修改成功', type: 'success' })
emit('update')
emit('update:modelValue', false)
})
}
</script>
<template>
<el-dialog
title="编辑评分细则"
:close-on-click-modal="false"
width="600px"
@update:modelValue="$emit('update:modelValue')"
>
<el-form ref="formRef" :model="form" :rules="rules" label-width="124px">
<el-form-item label="评分细则文件" prop="files">
<AppUpload
v-model="form.files"
:limit="1"
:beforeUpload="handleBeforeUpload"
accept=".doc,.docx,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,.pdf,application/pdf,.ppt,.pptx,application/vnd.ms-powerpoint,.csv,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel"
@success="handleUploadSuccess"
>
<template #tip>评分细则文件支持格式包含:doc docx xls xlsx pdf ppt pptx,大小不超过50M</template>
</AppUpload>
</el-form-item>
<el-form-item label="评分细则名称" prop="name">
<el-input v-model="form.name"></el-input>
<p class="form-tips">评分细则名称自动取值于文件名称,可以进行二次修改。</p>
</el-form-item>
<el-form-item label="关联赛项">
<el-input :value="detail.name" disabled></el-input>
</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 prop="protocol">
<el-checkbox label="我已阅读并同意" v-model="form.protocol" />
<a
href="https://view.officeapps.live.com/op/view.aspx?src=https://webapp-pub.oss-cn-beijing.aliyuncs.com/center_resource/%E7%B4%AB%E8%8D%86%E6%95%99%E8%82%B2%E7%94%A8%E6%88%B7%E5%85%A5%E9%A9%BB%E5%8F%8A%E7%BD%91%E7%BB%9C%E6%95%99%E5%AD%A6%E8%B5%84%E6%BA%90%E5%8D%8F%E8%AE%AE(1).docx"
target="_blank"
>《紫荆教育用户入驻及网络教学资源协议》</a
>
</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>
<style lang="scss" scoped>
.form-tips {
font-size: 12px;
color: #999;
}
</style>
...@@ -10,7 +10,7 @@ const emit = defineEmits<{ ...@@ -10,7 +10,7 @@ const emit = defineEmits<{
(e: 'update:modelValue', visible: boolean): void (e: 'update:modelValue', visible: boolean): void
}>() }>()
const JudgeAddDialog = defineAsyncComponent(() => import('./JudgeAddDialog.vue')) const ScoringExpertsAddDialog = defineAsyncComponent(() => import('./ScoringExpertsAddDialog.vue'))
const detail = $ref<ContestItem>(inject('detail')) const detail = $ref<ContestItem>(inject('detail'))
...@@ -104,6 +104,6 @@ function handleRemoveClass(index: number) { ...@@ -104,6 +104,6 @@ function handleRemoveClass(index: number) {
<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>
<JudgeAddDialog v-model="dialogVisible" @add="handleAdd" v-if="dialogVisible"></JudgeAddDialog> <ScoringExpertsAddDialog v-model="dialogVisible" @add="handleAdd" v-if="dialogVisible"></ScoringExpertsAddDialog>
</el-dialog> </el-dialog>
</template> </template>
...@@ -6,9 +6,10 @@ import dayjs from 'dayjs' ...@@ -6,9 +6,10 @@ import dayjs from 'dayjs'
const ViewBook = defineAsyncComponent(() => import('../components/ViewBook.vue')) const ViewBook = defineAsyncComponent(() => import('../components/ViewBook.vue'))
const ViewVideo = defineAsyncComponent(() => import('../components/ViewVideo.vue')) const ViewVideo = defineAsyncComponent(() => import('../components/ViewVideo.vue'))
const JudgingRulesDialog = defineAsyncComponent(() => import('../components/JudgingRulesDialog.vue')) const ScoringRulesDialog = defineAsyncComponent(() => import('../components/ScoringRulesDialog.vue'))
const JudgeDialog = defineAsyncComponent(() => import('../components/JudgeDialog.vue')) const ScoringExpertsDialog = defineAsyncComponent(() => import('../components/ScoringExpertsDialog.vue'))
const ContestantDialog = defineAsyncComponent(() => import('../components/ContestantDialog.vue')) const ContestantDialog = defineAsyncComponent(() => import('../components/ContestantDialog.vue'))
const ScoringBookDialog = defineAsyncComponent(() => import('../components/ScoringBookDialog.vue'))
interface Props { interface Props {
id: string id: string
...@@ -60,6 +61,8 @@ const judgingRulesVisible = $ref(false) ...@@ -60,6 +61,8 @@ const judgingRulesVisible = $ref(false)
const judgeVisible = $ref(false) const judgeVisible = $ref(false)
// 参赛选手 // 参赛选手
const contestantVisible = $ref(false) const contestantVisible = $ref(false)
// 评分细则
const judgingBookVisible = $ref(false)
</script> </script>
<template> <template>
...@@ -68,7 +71,7 @@ const contestantVisible = $ref(false) ...@@ -68,7 +71,7 @@ const contestantVisible = $ref(false)
<el-button type="primary" @click="judgingRulesVisible = true">评分规则</el-button> <el-button type="primary" @click="judgingRulesVisible = true">评分规则</el-button>
<el-button type="primary" @click="judgeVisible = true">评分专家</el-button> <el-button type="primary" @click="judgeVisible = true">评分专家</el-button>
<el-button type="primary" @click="contestantVisible = true">参赛选手</el-button> <el-button type="primary" @click="contestantVisible = true">参赛选手</el-button>
<el-button type="primary">评分细则</el-button> <el-button type="primary" @click="judgingBookVisible = true">评分细则</el-button>
</template> </template>
<div class="top" v-if="detail"> <div class="top" v-if="detail">
<div class="top-cover"> <div class="top-cover">
...@@ -99,11 +102,13 @@ const contestantVisible = $ref(false) ...@@ -99,11 +102,13 @@ const contestantVisible = $ref(false)
<ViewVideo :id="id"></ViewVideo> <ViewVideo :id="id"></ViewVideo>
</AppCard> </AppCard>
<!-- 评分规则 --> <!-- 评分规则 -->
<JudgingRulesDialog v-model="judgingRulesVisible" v-if="judgingRulesVisible && detail"></JudgingRulesDialog> <ScoringRulesDialog v-model="judgingRulesVisible" v-if="judgingRulesVisible && detail"></ScoringRulesDialog>
<!-- 评分专家 --> <!-- 评分专家 -->
<JudgeDialog v-model="judgeVisible" v-if="judgeVisible && detail"></JudgeDialog> <ScoringExpertsDialog v-model="judgeVisible" v-if="judgeVisible && detail"></ScoringExpertsDialog>
<!-- 参赛选手 --> <!-- 参赛选手 -->
<ContestantDialog v-model="contestantVisible" v-if="contestantVisible && detail"></ContestantDialog> <ContestantDialog v-model="contestantVisible" v-if="contestantVisible && detail"></ContestantDialog>
<!-- 评分细则 -->
<ScoringBookDialog v-model="judgingBookVisible" v-if="judgingBookVisible && detail"></ScoringBookDialog>
</template> </template>
<style lang="scss"> <style lang="scss">
......
...@@ -95,7 +95,7 @@ const adminMenus: IMenuItem[] = [ ...@@ -95,7 +95,7 @@ const adminMenus: IMenuItem[] = [
}, },
{ {
name: '评分专家管理', name: '评分专家管理',
path: '/admin/contest/judges' path: '/admin/contest/experts'
} }
] ]
} }
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论