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

chore: update

上级 e73fba5f
......@@ -32,6 +32,7 @@
"@types/ali-oss": "^6.16.4",
"@types/blueimp-md5": "^2.18.0",
"@types/file-saver": "^2.0.5",
"@types/lodash-es": "^4.17.6",
"@types/node": "^16.11.56",
"@types/qs": "^6.9.7",
"@types/ua-parser-js": "^0.7.36",
......@@ -379,13 +380,13 @@
"dev": true
},
"node_modules/@types/lodash": {
"version": "4.14.182",
"resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.182.tgz",
"integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q=="
"version": "4.14.185",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.185.tgz",
"integrity": "sha512-evMDG1bC4rgQg4ku9tKpuMh5iBNEwNa3tf9zRHdP1qlv+1WUg44xat4IxCE14gIpZRGUUWAx2VhItCZc25NfMA=="
},
"node_modules/@types/lodash-es": {
"version": "4.17.6",
"resolved": "https://registry.npmmirror.com/@types/lodash-es/-/lodash-es-4.17.6.tgz",
"resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.6.tgz",
"integrity": "sha512-R+zTeVUKDdfoRxpAryaQNRKk3105Rrgx2CFRClIgRGaqDTdjsm8h6IYA8ir584W3ePzkZfst5xIgDwYrlh9HLg==",
"dependencies": {
"@types/lodash": "*"
......@@ -5106,13 +5107,13 @@
"dev": true
},
"@types/lodash": {
"version": "4.14.182",
"resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.182.tgz",
"integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q=="
"version": "4.14.185",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.185.tgz",
"integrity": "sha512-evMDG1bC4rgQg4ku9tKpuMh5iBNEwNa3tf9zRHdP1qlv+1WUg44xat4IxCE14gIpZRGUUWAx2VhItCZc25NfMA=="
},
"@types/lodash-es": {
"version": "4.17.6",
"resolved": "https://registry.npmmirror.com/@types/lodash-es/-/lodash-es-4.17.6.tgz",
"resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.6.tgz",
"integrity": "sha512-R+zTeVUKDdfoRxpAryaQNRKk3105Rrgx2CFRClIgRGaqDTdjsm8h6IYA8ir584W3ePzkZfst5xIgDwYrlh9HLg==",
"requires": {
"@types/lodash": "*"
......
......@@ -38,6 +38,7 @@
"@types/ali-oss": "^6.16.4",
"@types/blueimp-md5": "^2.18.0",
"@types/file-saver": "^2.0.5",
"@types/lodash-es": "^4.17.6",
"@types/node": "^16.11.56",
"@types/qs": "^6.9.7",
"@types/ua-parser-js": "^0.7.36",
......
......@@ -4,7 +4,7 @@ const json2Array = function (data: Record<string, string>) {
return Object.keys(data).map(code => ({ code, label: data[code], value: data[code] }))
}
export function useArea(province: string, city: string, county: string) {
export function useArea(province?: string, city?: string, county?: string) {
const provinceValue = ref(province || '')
const cityValue = ref(city || '')
const countyValue = ref(county || '')
......
import httpRequest from '@/utils/axios'
import type { ContestantCreateParams, ContestantUpdateParams } from './types'
// 获取参赛选手列表
export function getContestantList(params?: { student_name?: string; page?: number; 'per-page'?: number }) {
return httpRequest.get('/api/resource/v1/backend/competition-competitor/list', { params })
}
// 获取参赛选手列表
export function getContestant(params: { id: string }) {
return httpRequest.get('/api/resource/v1/backend/competition-competitor/detail', { params })
}
// 创建参赛选手
export function createContestant(data: ContestantCreateParams) {
return httpRequest.post('/api/resource/v1/backend/experiment/list', data)
return httpRequest.post('/api/resource/v1/backend/competition-competitor/create', data)
}
// 修改参赛选手
export function updateContestant(data: ContestantUpdateParams) {
return httpRequest.post('/api/resource/v1/backend/experiment/list', data)
return httpRequest.post('/api/resource/v1/backend/competition-competitor/update', data)
}
// 获取参赛选手列表
// 批量导入参赛选手
export function uploadContestant(data: { file: File }) {
return httpRequest.post('/api/resource/v1/backend/experiment/list', data)
return httpRequest.post('/api/resource/v1/backend/competition-competitor/import-competitors', data, {
headers: { 'Content-Type': 'multipart/form-data' }
})
}
<script setup lang="ts">
import type { FormInstance, FormRules } from 'element-plus'
import type { Contestant, ContestantCreateParams } from '../types'
import type { Contestant } from '../types'
import { ElMessage } from 'element-plus'
import { pick } from 'lodash-es'
import AppUpload from '@/components/base/AppUpload.vue'
import { createContestant, updateContestant } from '../api'
import { useMapStore } from '@/stores/map'
import { useArea } from '@/composables/useArea'
import { contestModeList } from '@/utils/dictionary'
interface Props {
data?: Contestant | null
data: Contestant
}
const props = defineProps<Props>()
......@@ -19,30 +22,56 @@ const emit = defineEmits<{
// 性别
const genderList = useMapStore().getMapValuesByKey('system_gender')
// 证件类型
const idTypeList = useMapStore().getMapValuesByKey('system_id_type')
const formRef = $ref<FormInstance>()
const form = reactive<ContestantCreateParams>({
name: '',
phone: '',
company: '',
const form = reactive({
competition_id: '',
competition_name: '',
gender: '1',
id_number: '',
id_type: '',
mobile: '',
mode: '',
org_name: '',
province: '',
city: '',
county: ''
county: '',
student_name: '',
specialty_name: '',
grade: '',
class_name: '',
teacher_name: '',
picture: ''
})
watchEffect(() => {
if (!props.data) return
Object.assign(form, props.data)
const { student, competition } = props.data
Object.assign(form, {
competition_id: competition.id,
competition_name: competition.name,
gender: student.gender,
id_number: student.id_number,
id_type: student.id_type,
mobile: student.mobile,
mode: props.data.mode,
org_name: student.org.department_name,
province: student.info.province_name,
city: student.info.city_name,
county: student.info.county_name,
student_name: student.name,
specialty_name: student.specialty.name,
class_name: student.class.name,
teacher_name: props.data.teacher_name,
grade: props.data.grade,
picture: props.data.picture
})
})
const rules = ref<FormRules>({
name: [{ required: true, message: '请选择赛项所属部门/学校' }],
phone: [{ required: true, message: '请选择赛项课程' }],
company: [{ required: true, message: '请输入赛项名称' }],
position: [{ required: true, message: '请输入赛项学时' }],
province: [{ required: true, message: '请选择赛项类型' }],
city: [{ required: true, message: '请选择指导教师' }],
county: [{ required: true, message: '请输入赛项总成绩' }]
grade: [{ required: true, message: '请输入年级' }],
teacher_name: [{ required: true, message: '请输入指导教师' }]
})
const isUpdate = $computed(() => {
return !!props.data?.id
......@@ -51,7 +80,11 @@ const title = $computed(() => {
return isUpdate ? '编辑参赛选手信息' : '新增参赛选手'
})
const { provinceList, cityList, countyList, provinceValue, cityValue, countyValue } = useArea()
const { provinceList, cityList, countyList, provinceValue, cityValue, countyValue } = useArea(
props.data?.student.info.province_name || '',
props.data?.student.info.city_name || '',
props.data?.student.info.county_name || ''
)
watchEffect(() => {
form.province = provinceValue.value
form.city = cityValue.value
......@@ -66,7 +99,8 @@ function handleSubmit() {
}
// 新增
function handleCreate() {
createContestant(form).then(() => {
const params = pick(form, ['competition_id', 'mode', 'picture', 'grade', 'teacher_name', 'mobile', 'student_name'])
createContestant(params).then(() => {
ElMessage({ message: '创建成功', type: 'success' })
emit('update')
emit('update:modelValue', false)
......@@ -74,8 +108,8 @@ function handleCreate() {
}
// 修改
function handleUpdate() {
if (!props.data?.id) return
updateContestant({ id: props.data.id, ...form }).then(() => {
const params = pick(form, ['mode', 'picture', 'grade', 'teacher_name'])
updateContestant({ id: props.data.id, ...params }).then(() => {
ElMessage({ message: '修改成功', type: 'success' })
emit('update')
emit('update:modelValue', false)
......@@ -86,59 +120,67 @@ function handleUpdate() {
<template>
<el-dialog :title="title" :close-on-click-modal="false" width="600px" @update:modelValue="$emit('update:modelValue')">
<el-form ref="formRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="参赛形式" prop="gender">
<el-radio-group v-model="form.gender">
<el-radio v-for="item in genderList" :key="item.id" :label="item.value">{{ item.label }}</el-radio>
<el-form-item label="报名赛项">
<el-input v-model="form.competition_name" :disabled="isUpdate" />
</el-form-item>
<el-form-item label="参赛形式" prop="mode">
<el-radio-group v-model="form.mode" :disabled="isUpdate">
<el-radio v-for="item in contestModeList" :key="item.value" :label="item.value">{{ item.label }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="姓名" prop="name">
<el-input v-model="form.name" />
<el-form-item label="姓名" prop="student_name">
<el-input v-model="form.student_name" :disabled="isUpdate" />
</el-form-item>
<el-form-item label="性别" prop="gender">
<el-radio-group v-model="form.gender">
<el-radio-group v-model="form.gender" :disabled="isUpdate">
<el-radio v-for="item in genderList" :key="item.id" :label="item.value">{{ item.label }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="证件类型" prop="gender">
<el-radio-group v-model="form.gender">
<el-radio v-for="item in genderList" :key="item.id" :label="item.value">{{ item.label }}</el-radio>
<el-form-item label="证件类型" prop="id_type">
<el-radio-group v-model="form.id_type" :disabled="isUpdate">
<el-radio v-for="item in idTypeList" :key="item.id" :label="item.value">{{ item.label }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="证件号码" prop="phone">
<el-input v-model="form.phone" />
<el-form-item label="证件号码" prop="id_number">
<el-input v-model="form.id_number" :disabled="isUpdate" />
</el-form-item>
<el-form-item label="联系电话" prop="phone">
<el-input v-model="form.phone" />
<el-form-item label="联系电话" prop="mobile">
<el-input v-model="form.mobile" :disabled="isUpdate" />
</el-form-item>
<el-form-item label="学校名称" prop="name">
<el-input v-model="form.name" />
<el-form-item label="学校名称" prop="org_name">
<el-input v-model="form.org_name" :disabled="isUpdate" />
</el-form-item>
<el-form-item label="省" prop="province">
<el-select v-model="provinceValue" style="width: 100%">
<el-select v-model="provinceValue" style="width: 100%" :disabled="isUpdate">
<el-option v-for="item in provinceList" :value="item.label" :key="item.code"></el-option>
</el-select>
</el-form-item>
<el-form-item label="市" prop="city">
<el-select v-model="cityValue" style="width: 100%">
<el-select v-model="cityValue" style="width: 100%" :disabled="isUpdate">
<el-option v-for="item in cityList" :value="item.label" :key="item.code"></el-option>
</el-select>
</el-form-item>
<el-form-item label="区/县" prop="county">
<el-select v-model="countyValue" style="width: 100%">
<el-select v-model="countyValue" style="width: 100%" :disabled="isUpdate">
<el-option v-for="item in countyList" :value="item.label" :key="item.code"></el-option>
</el-select>
</el-form-item>
<el-form-item label="专业名称" prop="phone">
<el-input v-model="form.phone" />
<el-form-item label="专业名称" prop="specialty_name">
<el-input v-model="form.specialty_name" :disabled="isUpdate" />
</el-form-item>
<el-form-item label="年级" prop="grade">
<el-input v-model="form.grade" />
</el-form-item>
<el-form-item label="年级" prop="phone">
<el-input v-model="form.phone" />
<el-form-item label="班级" prop="class_name">
<el-input v-model="form.class_name" :disabled="isUpdate" />
</el-form-item>
<el-form-item label="班级" prop="phone">
<el-input v-model="form.phone" />
<el-form-item label="指导教师" prop="teacher_name">
<el-input v-model="form.teacher_name" />
</el-form-item>
<el-form-item label="指导教师" prop="phone">
<el-input v-model="form.phone" />
<el-form-item label="证件照" prop="picture">
<AppUpload v-model="form.picture" accept="image/*">
<template #tip>证件照说明:请上传蓝底1寸或蓝底2寸证件照,照片大小控制在500kb以内。</template>
</AppUpload>
</el-form-item>
<el-row justify="center">
<el-button type="primary" round auto-insert-space @click="handleSubmit">保存</el-button>
......
<script setup lang="ts">
import type { Contestant } from '../types'
import { useMapStore } from '@/stores/map'
import { contestMode } from '@/utils/dictionary'
interface Props {
data: Contestant
}
const props = defineProps<Props>()
// 参赛形式
const modeText = computed(() => {
return contestMode[props.data.mode] || props.data.mode
})
// 性别
const genderList = useMapStore().getMapValuesByKey('system_gender')
const genderText = computed(() => {
const found = genderList.find(item => item.value === props.data.student.gender)
return found?.label || props.data.student.gender
})
// 证件类型
const idTypeList = useMapStore().getMapValuesByKey('system_id_type')
const idTypeText = computed(() => {
const found = idTypeList.find(item => item.value === props.data.student.id_type)
return found?.label || props.data.student.id_type
})
</script>
<template>
<el-dialog title="查看参赛选手信息">
<el-descriptions :column="4" border>
<el-descriptions-item label="报名赛项">{{ data.competition.name }}</el-descriptions-item>
<el-descriptions-item label="参赛形式">{{ modeText }}</el-descriptions-item>
<el-descriptions-item label="姓名">{{ data.student.name }}</el-descriptions-item>
<el-descriptions-item label="性别">{{ genderText }}</el-descriptions-item>
<el-descriptions-item label="证件类型">{{ idTypeText }}</el-descriptions-item>
<el-descriptions-item label="证件号码">{{ data.student.id_number }}</el-descriptions-item>
<el-descriptions-item label="学校名称">{{ data.student.org.department_name }}</el-descriptions-item>
<el-descriptions-item label="省">{{ data.student.info.province_name }}</el-descriptions-item>
<el-descriptions-item label="市">{{ data.student.info.city_name }}</el-descriptions-item>
<el-descriptions-item label="区/县">{{ data.student.info.county_name }}</el-descriptions-item>
<el-descriptions-item label="专业名称">{{ data.student.specialty.name }}</el-descriptions-item>
<el-descriptions-item label="年级">{{ data.grade }}</el-descriptions-item>
<el-descriptions-item label="班级">{{ data.student.class.name }}</el-descriptions-item>
<el-descriptions-item label="指导教师">{{ data.teacher_name }}</el-descriptions-item>
<el-descriptions-item label="证件照"><img :src="data.picture" width="200" /></el-descriptions-item>
</el-descriptions>
<el-row justify="center" style="margin-top: 40px">
<el-button round auto-insert-space @click="$emit('update:modelValue', false)">关闭</el-button>
</el-row>
</el-dialog>
</template>
......@@ -70,5 +70,19 @@ export interface Org {
project_name: string
}
export type ContestantCreateParams = Contestant
export type ContestantUpdateParams = Contestant
export type ContestantCreateParams = {
competition_id: string
mode: string
picture?: string
grade: string
teacher_name: string
mobile: string
student_name: string
}
export type ContestantUpdateParams = {
id: string
mode: string
picture?: string
grade: string
teacher_name: string
}
<script setup lang="ts">
import type { Contestant } from '../types'
import { CirclePlus, Upload } from '@element-plus/icons-vue'
import { Upload } from '@element-plus/icons-vue'
import AppList from '@/components/base/AppList.vue'
import { getContestantList } from '../api'
import { useMapStore } from '@/stores/map'
const FormDialog = defineAsyncComponent(() => import('../components/FormDialog.vue'))
const ViewDialog = defineAsyncComponent(() => import('../components/ViewDialog.vue'))
const ImportDialog = defineAsyncComponent(() => import('../components/ImportDialog.vue'))
const appList = $ref<InstanceType<typeof AppList> | null>(null)
......@@ -53,12 +54,19 @@ const importVisible = $ref(false)
let dialogVisible = $ref(false)
const rowData = ref<Contestant | undefined | null>(null)
// 新增
function handleAdd() {
rowData.value = null
dialogVisible = true
// 查看
let viewVisible = $ref(false)
function handleView(row: Contestant) {
rowData.value = row
viewVisible = true
}
// 新增
// function handleAdd() {
// rowData.value = null
// dialogVisible = true
// }
// 编辑
function handleUpdate(row: Contestant) {
rowData.value = row
......@@ -74,19 +82,34 @@ function onUpdateSuccess() {
<AppCard title="参赛选手管理">
<AppList v-bind="listOptions" ref="appList">
<template #header-buttons>
<el-button type="primary" round :icon="CirclePlus" @click="handleAdd">新增参赛选手</el-button>
<!-- <el-button type="primary" round :icon="CirclePlus" @click="handleAdd">新增参赛选手</el-button> -->
<el-button type="primary" round :icon="Upload" @click="importVisible = true">批量导入</el-button>
</template>
<template #table-x="{ row }: { row: Contestant }">
<el-button type="primary" round v-permission="'v1-backend-experiment-view'">查看</el-button>
<el-button type="primary" round @click="handleView(row)" v-permission="'v1-backend-experiment-view'"
>查看</el-button
>
<el-button type="primary" round @click="handleUpdate(row)" v-permission="'v1-backend-experiment-update'"
>编辑</el-button
>
</template>
</AppList>
</AppCard>
<FormDialog v-model="dialogVisible" :data="rowData" @update="onUpdateSuccess" v-if="dialogVisible"></FormDialog>
<!-- 编辑 -->
<FormDialog
v-model="dialogVisible"
:data="rowData"
@update="onUpdateSuccess"
v-if="dialogVisible && rowData"
></FormDialog>
<!-- 查看 -->
<ViewDialog
v-model="viewVisible"
:data="rowData"
@update="onUpdateSuccess"
v-if="viewVisible && rowData"
></ViewDialog>
<!-- 批量导入 -->
<ImportDialog v-model="importVisible" @update="onUpdateSuccess" v-if="importVisible"></ImportDialog>
</template>
<script setup lang="ts">
import type { Judge } from '../types'
import { getJudgeContestList } from '../api'
import { useMapStore } from '@/stores/map'
interface Props {
data: Judge
}
const props = defineProps<Props>()
// 角色列表
const roleList = useMapStore().getMapValuesByKey('expert_role')
// 列表配置
const listOptions = {
hasPagination: false,
......@@ -20,7 +24,14 @@ const listOptions = {
columns: [
{ label: '序号', type: 'index', width: 60 },
{ label: '赛项名称', prop: 'name' },
{ label: '角色', prop: 'role' }
{
label: '角色',
prop: 'role',
computed({ row }: { row: any }) {
const found = roleList.find(item => item.value === row.role)
return found?.label || row.role
}
}
]
}
</script>
......
......@@ -10,8 +10,8 @@ const AdminHome = defineAsyncComponent(() => import('../components/AdminHome.vue
<template>
<div class="home">
<Total></Total>
<AdminHome v-if="userStore.role?.id === 5"></AdminHome>
<StudentHome v-else></StudentHome>
<StudentHome v-if="userStore.role?.id === 1"></StudentHome>
<AdminHome v-else></AdminHome>
</div>
<AppMessage></AppMessage>
</template>
......
......@@ -104,7 +104,7 @@ export const useMenuStore = defineStore({
getters: {
menus: state => {
const userStore = useUserStore()
return userStore.role?.id === 5 ? state.adminMenus : state.studentMenus
return userStore.role?.id === 1 ? state.studentMenus : state.adminMenus
}
},
actions: {}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论