This commit is contained in:
2025-12-17 09:31:14 +08:00
parent 1a99a45729
commit d8730cc2c2
15 changed files with 1032 additions and 380 deletions

View File

@@ -45,7 +45,7 @@ export const getDeductionDetail = (id) => {
*/
export const addDeduction = (data) => {
return request({
url: '/api/blade-martial/deductionItem/save',
url: '/api/blade-martial/deductionItem/submit',
method: 'post',
data
})
@@ -57,7 +57,7 @@ export const addDeduction = (data) => {
*/
export const updateDeduction = (data) => {
return request({
url: '/api/blade-martial/deductionItem/update',
url: '/api/blade-martial/deductionItem/submit',
method: 'post',
data
})

View File

@@ -45,7 +45,7 @@ export const getDeductionDetail = (id) => {
*/
export const addDeduction = (data) => {
return request({
url: '/api/blade-martial/deductionItem/save',
url: '/api/blade-martial/deductionItem/submit',
method: 'post',
data
})
@@ -57,7 +57,7 @@ export const addDeduction = (data) => {
*/
export const updateDeduction = (data) => {
return request({
url: '/api/blade-martial/deductionItem/update',
url: '/api/blade-martial/deductionItem/submit',
method: 'post',
data
})

View File

@@ -14,7 +14,7 @@ import request from '@/axios';
*/
export const getJudgeInviteList = (current, size, params) => {
return request({
url: '/api/blade-martial/judgeInvite/list',
url: '/api/martial/judgeInvite/list',
method: 'get',
params: {
current,
@@ -30,7 +30,7 @@ export const getJudgeInviteList = (current, size, params) => {
*/
export const getJudgeInviteDetail = (id) => {
return request({
url: '/api/blade-martial/judgeInvite/detail',
url: '/api/martial/judgeInvite/detail',
method: 'get',
params: { id }
})
@@ -48,7 +48,7 @@ export const getJudgeInviteDetail = (id) => {
*/
export const sendInvite = (data) => {
return request({
url: '/api/blade-martial/judgeInvite/send',
url: '/api/martial/judgeInvite/send',
method: 'post',
data
})
@@ -60,7 +60,7 @@ export const sendInvite = (data) => {
*/
export const updateInvite = (data) => {
return request({
url: '/api/blade-martial/judgeInvite/update',
url: '/api/martial/judgeInvite/submit',
method: 'post',
data
})
@@ -72,7 +72,7 @@ export const updateInvite = (data) => {
*/
export const removeInvite = (ids) => {
return request({
url: '/api/blade-martial/judgeInvite/remove',
url: '/api/martial/judgeInvite/remove',
method: 'post',
params: { ids }
})
@@ -87,7 +87,7 @@ export const removeInvite = (ids) => {
*/
export const batchSendInvites = (data) => {
return request({
url: '/api/blade-martial/judgeInvite/batch-send',
url: '/api/martial/judgeInvite/batch-send',
method: 'post',
data
})
@@ -99,7 +99,7 @@ export const batchSendInvites = (data) => {
*/
export const resendInvite = (id) => {
return request({
url: `/api/blade-martial/judgeInvite/resend/${id}`,
url: `/api/martial/judgeInvite/resend/${id}`,
method: 'post'
})
}
@@ -114,7 +114,7 @@ export const resendInvite = (id) => {
*/
export const replyInvite = (data) => {
return request({
url: '/api/blade-martial/judgeInvite/reply',
url: '/api/martial/judgeInvite/reply',
method: 'post',
data
})
@@ -127,7 +127,7 @@ export const replyInvite = (data) => {
*/
export const cancelInvite = (id, reason) => {
return request({
url: `/api/blade-martial/judgeInvite/cancel/${id}`,
url: `/api/martial/judgeInvite/cancel/${id}`,
method: 'post',
params: { reason }
})
@@ -139,7 +139,7 @@ export const cancelInvite = (id, reason) => {
*/
export const confirmInvite = (id) => {
return request({
url: `/api/blade-martial/judgeInvite/confirm/${id}`,
url: `/api/martial/judgeInvite/confirm/${id}`,
method: 'post'
})
}
@@ -150,7 +150,7 @@ export const confirmInvite = (id) => {
*/
export const getInviteStatistics = (competitionId) => {
return request({
url: '/api/blade-martial/judgeInvite/statistics',
url: '/api/martial/judgeInvite/statistics',
method: 'get',
params: { competitionId }
})
@@ -162,7 +162,7 @@ export const getInviteStatistics = (competitionId) => {
*/
export const getAcceptedJudges = (competitionId) => {
return request({
url: '/api/blade-martial/judgeInvite/accepted-judges',
url: '/api/martial/judgeInvite/accepted-judges',
method: 'get',
params: { competitionId }
})
@@ -175,7 +175,7 @@ export const getAcceptedJudges = (competitionId) => {
*/
export const importFromJudgePool = (competitionId, judgeIds) => {
return request({
url: '/api/blade-martial/judgeInvite/import/pool',
url: '/api/martial/judgeInvite/import/pool',
method: 'post',
params: { competitionId, judgeIds }
})
@@ -187,7 +187,7 @@ export const importFromJudgePool = (competitionId, judgeIds) => {
*/
export const exportInvites = (params) => {
return request({
url: '/api/blade-martial/judgeInvite/export',
url: '/api/martial/judgeInvite/export',
method: 'get',
params,
responseType: 'blob'
@@ -201,7 +201,7 @@ export const exportInvites = (params) => {
*/
export const sendReminder = (id, message) => {
return request({
url: `/api/blade-martial/judgeInvite/reminder/${id}`,
url: `/api/martial/judgeInvite/reminder/${id}`,
method: 'post',
params: { message }
})
@@ -219,7 +219,7 @@ export const sendReminder = (id, message) => {
*/
export const generateInviteCode = (data) => {
return request({
url: '/api/blade-martial/judgeInvite/generate',
url: '/api/martial/judgeInvite/generate',
method: 'post',
data
})
@@ -235,7 +235,7 @@ export const generateInviteCode = (data) => {
*/
export const batchGenerateInviteCode = (data) => {
return request({
url: '/api/blade-martial/judgeInvite/generate/batch',
url: '/api/martial/judgeInvite/generate/batch',
method: 'post',
data
})
@@ -247,7 +247,7 @@ export const batchGenerateInviteCode = (data) => {
*/
export const regenerateInviteCode = (inviteId) => {
return request({
url: `/api/blade-martial/judgeInvite/regenerate/${inviteId}`,
url: `/api/martial/judgeInvite/regenerate/${inviteId}`,
method: 'put'
})
}
@@ -259,7 +259,7 @@ export const regenerateInviteCode = (inviteId) => {
*/
export const getInviteByJudge = (competitionId, judgeId) => {
return request({
url: '/api/blade-martial/judgeInvite/byJudge',
url: '/api/martial/judgeInvite/byJudge',
method: 'get',
params: { competitionId, judgeId }
})

View File

@@ -9,7 +9,9 @@ import request from '@/axios';
* @param {Object} params - 查询参数
* @param {Number} params.competitionId - 赛事ID
* @param {String} params.projectName - 项目名称(可选)
* @param {String} params.category - 分组类别(可选)
* @param {Number} params.category - 分组类别(可选)
* @param {Number} params.eventType - 项目类型(可选)
* @param {Number} params.participantType - 参赛类型(可选,1-单人,2-集体)
*/
export const getProjectList = (current, size, params) => {
return request({
@@ -65,17 +67,16 @@ export const updateProject = (data) => {
* @param {Number} data.competitionId - 赛事ID
* @param {String} data.projectName - 项目名称
* @param {String} data.projectCode - 项目编码
* @param {String} data.category - 组别(男子组/女子组)
* @param {Number} data.type - 类型(1-个人,2-双人,3-集体)
* @param {Number} data.minParticipants - 最少参赛人数
* @param {Number} data.maxParticipants - 最多参赛人数
* @param {Number} data.minAge - 最小年龄
* @param {Number} data.maxAge - 最大年龄
* @param {Number} data.genderLimit - 性别限制(0-不限,1-仅男,2-仅女)
* @param {Number} data.estimatedDuration - 预估时长(分钟)
* @param {Number} data.price - 报名费用
* @param {Number} data.difficultyCoefficient - 难度系数
* @param {String} data.description - 项目描述
* @param {Number} data.category - 分组类别(1-男子,2-女子,3-团体,4-混合)
* @param {Number} data.eventType - 项目类型(1-套路,2-散打,3-器械,4-对练)
* @param {Number} data.participantType - 参赛类型(1-单人,2-集体)
* @param {Number} data.registrationFee - 报名费用
* @param {String} data.registrationStartTime - 报名开始时间
* @param {String} data.registrationEndTime - 报名结束时间
* @param {Number} data.maxParticipants - 最大参赛人数
* @param {Number} data.sortOrder - 排序序号
* @param {String} data.rules - 比赛规则
* @param {String} data.remark - 备注
*/
export const submitProject = (data) => {
return request({

View File

@@ -2,7 +2,7 @@ import request from '@/axios';
export const getList = (current, size, params) => {
return request({
url: '/blade-system/menu/list',
url: '/api/blade-system/menu/list',
method: 'get',
params: {
...params,
@@ -14,7 +14,7 @@ export const getList = (current, size, params) => {
export const getLazyList = (parentId, params) => {
return request({
url: '/blade-system/menu/lazy-list',
url: '/api/blade-system/menu/lazy-list',
method: 'get',
params: {
...params,
@@ -25,7 +25,7 @@ export const getLazyList = (parentId, params) => {
export const getLazyMenuList = (parentId, params) => {
return request({
url: '/blade-system/menu/lazy-menu-list',
url: '/api/blade-system/menu/lazy-menu-list',
method: 'get',
params: {
...params,
@@ -36,7 +36,7 @@ export const getLazyMenuList = (parentId, params) => {
export const getMenuList = (current, size, params) => {
return request({
url: '/blade-system/menu/menu-list',
url: '/api/blade-system/menu/menu-list',
method: 'get',
params: {
...params,
@@ -48,7 +48,7 @@ export const getMenuList = (current, size, params) => {
export const getMenuTree = tenantId => {
return request({
url: '/blade-system/menu/tree',
url: '/api/blade-system/menu/tree',
method: 'get',
params: {
tenantId,
@@ -58,7 +58,7 @@ export const getMenuTree = tenantId => {
export const remove = ids => {
return request({
url: '/blade-system/menu/remove',
url: '/api/blade-system/menu/remove',
method: 'post',
params: {
ids,
@@ -68,7 +68,7 @@ export const remove = ids => {
export const add = row => {
return request({
url: '/blade-system/menu/submit',
url: '/api/blade-system/menu/submit',
method: 'post',
data: row,
});
@@ -76,7 +76,7 @@ export const add = row => {
export const update = row => {
return request({
url: '/blade-system/menu/submit',
url: '/api/blade-system/menu/submit',
method: 'post',
data: row,
});
@@ -84,7 +84,7 @@ export const update = row => {
export const getMenu = id => {
return request({
url: '/blade-system/menu/detail',
url: '/api/blade-system/menu/detail',
method: 'get',
params: {
id,
@@ -94,13 +94,13 @@ export const getMenu = id => {
export const getTopMenu = () =>
request({
url: '/blade-system/menu/top-menu',
url: '/api/blade-system/menu/top-menu',
method: 'get',
});
export const getRoutes = topMenuId =>
request({
url: '/blade-system/menu/routes',
url: '/api/blade-system/menu/routes',
method: 'get',
params: {
topMenuId,

View File

@@ -4,7 +4,7 @@ import website from '@/config/website';
export const loginByUsername = (tenantId, deptId, roleId, username, password, type, key, code) =>
request({
url: '/blade-auth/oauth/token',
url: '/api/blade-auth/oauth/token',
method: 'post',
headers: {
'Tenant-Id': tenantId,
@@ -25,7 +25,7 @@ export const loginByUsername = (tenantId, deptId, roleId, username, password, ty
export const loginBySocial = (tenantId, source, code, state) =>
request({
url: '/blade-auth/oauth/token',
url: '/api/blade-auth/oauth/token',
method: 'post',
headers: {
'Tenant-Id': tenantId,
@@ -42,7 +42,7 @@ export const loginBySocial = (tenantId, source, code, state) =>
export const loginBySso = (state, code) =>
request({
url: '/blade-auth/oauth/token',
url: '/api/blade-auth/oauth/token',
method: 'post',
headers: {
'Tenant-Id': state,
@@ -58,7 +58,7 @@ export const loginBySso = (state, code) =>
export const refreshToken = (refresh_token, tenantId, deptId, roleId) =>
request({
url: '/blade-auth/oauth/token',
url: '/api/blade-auth/oauth/token',
method: 'post',
headers: {
'Tenant-Id': tenantId,
@@ -75,7 +75,7 @@ export const refreshToken = (refresh_token, tenantId, deptId, roleId) =>
export const registerUser = (tenantId, name, account, password, phone, email) =>
request({
url: '/blade-auth/oauth/token',
url: '/api/blade-auth/oauth/token',
method: 'post',
headers: {
'Tenant-Id': tenantId,
@@ -94,7 +94,7 @@ export const registerUser = (tenantId, name, account, password, phone, email) =>
export const registerGuest = (form, oauthId) =>
request({
url: '/blade-system/user/register-guest',
url: '/api/blade-system/user/register-guest',
method: 'post',
params: {
tenantId: form.tenantId,
@@ -107,40 +107,40 @@ export const registerGuest = (form, oauthId) =>
export const getButtons = () =>
request({
url: '/blade-system/menu/buttons',
url: '/api/blade-system/menu/buttons',
method: 'get',
});
export const getCaptcha = () =>
request({
url: '/blade-auth/oauth/captcha',
url: '/api/blade-auth/oauth/captcha',
method: 'get',
authorization: false,
});
export const logout = () =>
request({
url: '/blade-auth/oauth/logout',
url: '/api/blade-auth/oauth/logout',
method: 'get',
authorization: false,
});
export const getUserInfo = () =>
request({
url: '/blade-auth/oauth/user-info',
url: '/api/blade-auth/oauth/user-info',
method: 'get',
});
export const sendLogs = list =>
request({
url: '/blade-auth/oauth/logout',
url: '/api/blade-auth/oauth/logout',
method: 'post',
data: list,
});
export const clearCache = () =>
request({
url: '/blade-auth/oauth/clear-cache',
url: '/api/blade-auth/oauth/clear-cache',
method: 'get',
authorization: false,
});

View File

@@ -3,12 +3,40 @@
<!-- 搜索区域 -->
<el-card shadow="never" class="search-card">
<el-form :inline="true" :model="queryParams" class="search-form">
<el-form-item label="选择赛事" required>
<el-select
v-model="queryParams.competitionId"
placeholder="请选择赛事"
clearable
filterable
:loading="competitionLoading"
:disabled="competitionLoading"
style="width: 250px"
@change="handleCompetitionChange"
>
<template #empty>
<div style="padding: 20px; text-align: center; color: #909399;">
<p>暂无赛事数据</p>
<p style="font-size: 12px; margin-top: 5px;">
请先在"赛事管理"中创建赛事
</p>
</div>
</template>
<el-option
v-for="item in competitionList"
:key="item.id"
:label="item.competitionName"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="所属项目">
<el-select
v-model="queryParams.projectId"
placeholder="请选择项目"
clearable
filterable
:disabled="!queryParams.competitionId"
style="width: 250px"
>
<el-option
@@ -40,21 +68,31 @@
<el-card shadow="never" class="toolbar-card">
<div class="toolbar">
<div class="toolbar-left">
<el-button type="primary" :icon="Plus" @click="handleAdd">
<el-button
type="primary"
:icon="Plus"
:disabled="!queryParams.competitionId"
@click="handleAdd"
>
新增扣分项
</el-button>
<el-button
type="danger"
:icon="Delete"
:disabled="!selection.length"
:disabled="!selection.length || !queryParams.competitionId"
@click="handleBatchDelete"
>
批量删除
</el-button>
<el-button type="success" :icon="DocumentCopy" @click="handleClone">
<!-- <el-button type="success" :icon="DocumentCopy" @click="handleClone">
克隆扣分项
</el-button>
<el-button type="warning" :icon="Download" @click="handleExport">
</el-button> -->
<el-button
type="warning"
:icon="Download"
:disabled="!queryParams.competitionId"
@click="handleExport"
>
导出模板
</el-button>
</div>
@@ -65,7 +103,12 @@
</el-icon>
</el-tooltip>
<el-tooltip content="刷新" placement="top">
<el-button circle :icon="Refresh" @click="fetchData" />
<el-button
circle
:icon="Refresh"
:disabled="!queryParams.competitionId"
@click="fetchData"
/>
</el-tooltip>
</div>
</div>
@@ -135,9 +178,6 @@
<el-button link type="primary" :icon="Edit" @click="handleEdit(row)">
编辑
</el-button>
<el-button link type="success" :icon="DocumentCopy" @click="handleCloneSingle(row)">
克隆
</el-button>
<el-button link type="danger" :icon="Delete" @click="handleDelete(row)">
删除
</el-button>
@@ -173,6 +213,22 @@
:rules="rules"
label-width="120px"
>
<el-form-item label="所属赛事" prop="competitionId">
<el-select
v-model="form.competitionId"
placeholder="请选择赛事"
filterable
disabled
style="width: 100%"
>
<el-option
v-for="item in competitionList"
:key="item.id"
:label="item.competitionName"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="所属项目" prop="projectId">
<el-select
v-model="form.projectId"
@@ -295,7 +351,6 @@ import {
Delete,
Edit,
Download,
DocumentCopy,
InfoFilled,
Rank
} from '@element-plus/icons-vue'
@@ -310,6 +365,7 @@ import {
import { getProjectList } from '@/api/martial/project'
import dayjs from 'dayjs'
import Sortable from 'sortablejs'
import { getCompetitionList } from '@/api/martial/competition'
// 数据定义
const loading = ref(false)
@@ -324,20 +380,22 @@ const cloneDialogVisible = ref(false)
const dialogTitle = ref('')
const formRef = ref(null)
const cloneFormRef = ref(null)
const competitionList = ref([])
const competitionLoading = ref(false)
// 查询参数
const queryParams = reactive({
current: 1,
size: 10,
projectId: '',
itemName: ''
competitionId: null,
projectId: null,
})
// 表单数据
const form = reactive({
id: null,
projectId: '',
itemName: '',
competitionId: null,
projectId: null,
deductionPoints: 0.5,
sortOrder: 0,
description: ''
@@ -353,6 +411,9 @@ const cloneForm = reactive({
// 表单验证规则
const rules = {
competitionId: [
{ required: true, message: '请选择赛事', trigger: 'change' }
],
projectId: [
{ required: true, message: '请选择所属项目', trigger: 'change' }
],
@@ -375,20 +436,72 @@ const cloneRules = {
]
}
// 加载项目列表
const loadProjectList = async () => {
// 加载赛事列表
const loadCompetitionList = async () => {
competitionLoading.value = true
try {
const res = await getProjectList(1, 1000, {})
if (res.data && res.data.records) {
projectList.value = res.data.records
const resCompe = await getCompetitionList(1, 1000, {})
const recordsCompe = resCompe.data?.data?.records || []
competitionList.value = recordsCompe
if (recordsCompe.length === 0) {
console.warn('赛事列表为空,请先在"赛事管理"中创建赛事')
}
} catch (error) {
console.error('加载赛事列表失败:', error)
ElMessage.error('加载赛事列表失败')
} finally {
competitionLoading.value = false
}
}
// 加载项目列表根据赛事ID
const loadProjectList = async (competitionId) => {
if (!competitionId) {
projectList.value = []
return
}
try {
const res = await getProjectList(1, 1000, { competitionId })
// 根据axios响应拦截器的处理数据在 res.data.data.records 中
const records = res.data?.data?.records || []
projectList.value = records
if (records.length === 0) {
console.warn('该赛事下暂无项目,请先在"轮编管理"中创建项目')
}
} catch (error) {
console.error('加载项目列表失败:', error)
ElMessage.error('加载项目列表失败')
}
}
// 赛事选择变化
const handleCompetitionChange = (competitionId) => {
// 清空项目选择和表格数据
queryParams.projectId = null
tableData.value = []
total.value = 0
// 加载该赛事下的项目
if (competitionId) {
loadProjectList(competitionId)
// 自动查询数据
fetchData()
} else {
projectList.value = []
}
}
// 查询数据
const fetchData = async () => {
// 必须选择赛事才能查询
if (!queryParams.competitionId) {
ElMessage.warning('请先选择赛事')
return
}
loading.value = true
try {
const res = await getDeductionList(
@@ -396,10 +509,10 @@ const fetchData = async () => {
queryParams.size,
queryParams
)
if (res.data) {
tableData.value = res.data.records || []
total.value = res.data.total || 0
}
// 根据axios响应拦截器的处理数据在 res.data.data 中
const data = res.data?.data || {}
tableData.value = data.records || []
total.value = data.total || 0
} catch (error) {
ElMessage.error('获取数据失败')
console.error(error)
@@ -416,19 +529,28 @@ const handleSearch = () => {
// 重置
const handleReset = () => {
const competitionId = queryParams.competitionId
Object.assign(queryParams, {
current: 1,
size: 10,
projectId: '',
competitionId: competitionId,
projectId: null,
itemName: ''
})
fetchData()
if (competitionId) {
fetchData()
}
}
// 新增
const handleAdd = () => {
if (!queryParams.competitionId) {
ElMessage.warning('请先选择赛事')
return
}
dialogTitle.value = '新增扣分项'
resetForm()
form.competitionId = queryParams.competitionId
dialogVisible.value = true
}
@@ -480,29 +602,6 @@ const handleBatchDelete = () => {
.catch(() => {})
}
// 克隆单个扣分项
const handleCloneSingle = (row) => {
cloneForm.sourceProjectId = row.projectId
cloneForm.sourceProjectName = row.projectName
cloneForm.targetProjectId = ''
cloneForm.itemCount = 1
cloneDialogVisible.value = true
}
// 克隆扣分项(批量)
const handleClone = () => {
if (!queryParams.projectId) {
ElMessage.warning('请先选择源项目(通过搜索筛选)')
return
}
const sourceProject = projectList.value.find(p => p.id === queryParams.projectId)
cloneForm.sourceProjectId = queryParams.projectId
cloneForm.sourceProjectName = sourceProject?.projectName || ''
cloneForm.targetProjectId = ''
cloneForm.itemCount = total.value
cloneDialogVisible.value = true
}
// 提交克隆
const handleCloneSubmit = async () => {
@@ -568,7 +667,8 @@ const handleDialogClose = () => {
const resetForm = () => {
Object.assign(form, {
id: null,
projectId: '',
competitionId: null,
projectId: null,
itemName: '',
deductionPoints: 0.5,
sortOrder: 0,
@@ -639,8 +739,7 @@ const formatDate = (date) => {
// 生命周期
onMounted(() => {
loadProjectList()
fetchData()
loadCompetitionList()
initSortable()
})
</script>

View File

@@ -9,9 +9,19 @@
placeholder="请选择赛事"
clearable
filterable
:loading="competitionLoading"
:disabled="competitionLoading"
style="width: 250px"
@change="handleCompetitionChange"
>
<template #empty>
<div style="padding: 20px; text-align: center; color: #909399;">
<p>暂无赛事数据</p>
<p style="font-size: 12px; margin-top: 5px;">
请先在"赛事管理"中创建赛事
</p>
</div>
</template>
<el-option
v-for="item in competitionList"
:key="item.id"
@@ -41,19 +51,6 @@
<el-option label="三级" value="三级" />
</el-select>
</el-form-item>
<el-form-item label="邀请状态">
<el-select
v-model="queryParams.inviteStatus"
placeholder="请选择"
clearable
style="width: 130px"
>
<el-option label="待回复" :value="0" />
<el-option label="已接受" :value="1" />
<el-option label="已拒绝" :value="2" />
<el-option label="已取消" :value="3" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" :icon="Search" @click="handleSearch">
搜索
@@ -63,82 +60,30 @@
</el-form>
</el-card>
<!-- 统计卡片 -->
<el-row :gutter="20" class="stats-row">
<el-col :span="6">
<el-card shadow="hover" class="stats-card">
<div class="stats-content">
<div class="stats-icon" style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%)">
<el-icon :size="30"><User /></el-icon>
</div>
<div class="stats-info">
<div class="stats-value">{{ statistics.totalInvites || 0 }}</div>
<div class="stats-label">总邀请数</div>
</div>
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card shadow="hover" class="stats-card">
<div class="stats-content">
<div class="stats-icon" style="background: linear-gradient(135deg, #fccb90 0%, #d57eeb 100%)">
<el-icon :size="30"><Clock /></el-icon>
</div>
<div class="stats-info">
<div class="stats-value">{{ statistics.pendingCount || 0 }}</div>
<div class="stats-label">待回复</div>
</div>
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card shadow="hover" class="stats-card">
<div class="stats-content">
<div class="stats-icon" style="background: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%)">
<el-icon :size="30"><CircleCheck /></el-icon>
</div>
<div class="stats-info">
<div class="stats-value">{{ statistics.acceptedCount || 0 }}</div>
<div class="stats-label">已接受</div>
</div>
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card shadow="hover" class="stats-card">
<div class="stats-content">
<div class="stats-icon" style="background: linear-gradient(135deg, #ff9a9e 0%, #fecfef 100%)">
<el-icon :size="30"><CircleClose /></el-icon>
</div>
<div class="stats-info">
<div class="stats-value">{{ statistics.rejectedCount || 0 }}</div>
<div class="stats-label">已拒绝</div>
</div>
</div>
</el-card>
</el-col>
</el-row>
<!-- 工具栏 -->
<el-card shadow="never" class="toolbar-card">
<div class="toolbar">
<div class="toolbar-left">
<el-button type="primary" :icon="Plus" @click="handleSendInvite">
发送邀请
</el-button>
<el-button type="success" :icon="DocumentCopy" @click="handleBatchGenerateCode">
批量生成邀请码
</el-button>
<el-button type="warning" :icon="FolderOpened" @click="handleImportFromPool">
<el-button
type="warning"
:icon="FolderOpened"
:disabled="competitionLoading || queryParams.competitionId === null || queryParams.competitionId === ''"
:loading="competitionLoading"
@click="handleImportFromPool"
>
从评委库导入
</el-button>
<el-button :icon="Download" @click="handleExport">
<el-button
:icon="Download"
:disabled="competitionLoading || queryParams.competitionId === null || queryParams.competitionId === ''"
@click="handleExport"
>
导出数据
</el-button>
</div>
<div class="toolbar-right">
<el-tooltip content="刷新" placement="top">
<el-button circle :icon="Refresh" @click="fetchData" />
<el-button circle :icon="Refresh" :disabled="competitionLoading" @click="fetchData" />
</el-tooltip>
</div>
</div>
@@ -154,15 +99,15 @@
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column prop="judgeName" label="评委姓名" width="120" />
<el-table-column prop="judgeLevel" label="评委等级" width="100" align="center">
<el-table-column prop="judgeName" label="评委姓名" />
<el-table-column prop="judgeLevel" label="评委等级" align="center">
<template #default="{ row }">
<el-tag :type="getLevelType(row.judgeLevel)" size="small">
{{ row.judgeLevel }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="inviteCode" label="邀请码" width="200" align="center">
<el-table-column prop="inviteCode" label="邀请码" align="center">
<template #default="{ row }">
<!-- 已有邀请码显示邀请码 + 重新生成按钮 -->
<div v-if="row.inviteCode" style="display: flex; align-items: center; justify-content: center; gap: 8px;">
@@ -198,66 +143,22 @@
</el-button>
</template>
</el-table-column>
<el-table-column prop="contactPhone" label="联系电话" width="130" />
<el-table-column prop="contactEmail" label="联系邮箱" min-width="180" show-overflow-tooltip />
<el-table-column prop="inviteStatus" label="邀请状态" width="100" align="center">
<el-table-column prop="refereeType" label="裁判类型" align="center">
<template #default="{ row }">
<el-tag :type="getStatusType(row.inviteStatus)" size="small">
{{ getStatusText(row.inviteStatus) }}
<el-tag :type="row.refereeType === 1 ? 'danger' : 'primary'" size="small">
{{ row.refereeType === 1 ? '主裁判' : '普通裁判' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="inviteTime" label="邀请时间" width="160" align="center">
<el-table-column prop="contactPhone" label="联系电话" />
<el-table-column prop="contactEmail" label="擅长项目" show-overflow-tooltip />
<el-table-column label="操作" width="150" align="center" fixed="right">
<template #default="{ row }">
{{ formatDateTime(row.inviteTime) }}
</template>
</el-table-column>
<el-table-column prop="replyTime" label="回复时间" width="160" align="center">
<template #default="{ row }">
{{ row.replyTime ? formatDateTime(row.replyTime) : '-' }}
</template>
</el-table-column>
<el-table-column prop="replyNote" label="回复备注" min-width="150" show-overflow-tooltip />
<el-table-column label="操作" width="280" align="center" fixed="right">
<template #default="{ row }">
<el-button
v-if="row.inviteStatus === 0"
link
type="primary"
:icon="Refresh"
@click="handleResend(row)"
>
重发
</el-button>
<el-button
v-if="row.inviteStatus === 0"
link
type="warning"
:icon="Bell"
@click="handleReminder(row)"
>
提醒
</el-button>
<el-button
v-if="row.inviteStatus === 0"
link
type="danger"
:icon="Close"
@click="handleCancel(row)"
>
取消
</el-button>
<el-button link type="primary" :icon="View" @click="handleView(row)">
查看
</el-button>
<el-button
v-if="row.inviteStatus === 1"
link
type="success"
:icon="CircleCheck"
@click="handleConfirm(row)"
>
确认
<el-button link type="danger" :icon="Delete" @click="handleDelete(row)">
删除
</el-button>
</template>
</el-table-column>
@@ -276,6 +177,108 @@
/>
</div>
</el-card>
<!-- 裁判选择对话框 -->
<el-dialog
v-model="judgeDialogVisible"
title="从评委库导入"
width="900px"
:close-on-click-modal="false"
>
<!-- 搜索表单 -->
<el-form :inline="true" :model="judgeQueryParams" class="judge-search-form">
<el-form-item label="姓名">
<el-input
v-model="judgeQueryParams.name"
placeholder="请输入姓名"
clearable
style="width: 150px"
/>
</el-form-item>
<el-form-item label="手机号">
<el-input
v-model="judgeQueryParams.phone"
placeholder="请输入手机号"
clearable
style="width: 150px"
/>
</el-form-item>
<el-form-item label="裁判类型">
<el-select
v-model="judgeQueryParams.refereeType"
placeholder="请选择"
clearable
style="width: 130px"
>
<el-option label="主裁判" :value="1" />
<el-option label="普通裁判" :value="2" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" :icon="Search" @click="handleJudgeSearch">
搜索
</el-button>
<el-button :icon="Refresh" @click="handleJudgeReset">重置</el-button>
</el-form-item>
</el-form>
<!-- 裁判列表 -->
<el-table
v-loading="judgeLoading"
:data="judgeList"
stripe
border
max-height="400"
@selection-change="handleJudgeSelectionChange"
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column prop="name" label="姓名" width="100" />
<el-table-column prop="gender" label="性别" width="80" align="center">
<template #default="{ row }">
{{ row.gender === 1 ? '男' : '女' }}
</template>
</el-table-column>
<el-table-column prop="phone" label="手机号" width="130" />
<el-table-column prop="refereeType" label="裁判类型" width="100" align="center">
<template #default="{ row }">
<el-tag :type="row.refereeType === 1 ? 'danger' : 'primary'" size="small">
{{ row.refereeType === 1 ? '主裁判' : '普通裁判' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="level" label="等级/职称" width="120" />
<el-table-column prop="specialty" label="擅长项目" min-width="150" show-overflow-tooltip />
</el-table>
<!-- 分页 -->
<div class="judge-pagination">
<el-pagination
v-model:current-page="judgeQueryParams.current"
v-model:page-size="judgeQueryParams.size"
:page-sizes="[10, 20, 50]"
:total="judgeTotal"
layout="total, sizes, prev, pager, next"
@size-change="loadJudgeList"
@current-change="loadJudgeList"
/>
</div>
<template #footer>
<div class="dialog-footer">
<span style="margin-right: auto; color: #909399;">
已选择 {{ selectedJudges.length }} 位裁判
</span>
<el-button @click="judgeDialogVisible = false">取消</el-button>
<el-button
type="primary"
:disabled="selectedJudges.length === 0"
@click="handleConfirmImport"
>
确定导入
</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
@@ -285,36 +288,22 @@ import { ElMessage, ElMessageBox } from 'element-plus'
import {
Search,
Refresh,
Plus,
Delete,
Download,
DocumentCopy,
FolderOpened,
Upload,
View,
Close,
Bell,
CircleCheck,
CircleClose,
User,
Clock
} from '@element-plus/icons-vue'
import {
getJudgeInviteList,
sendInvite,
batchSendInvites,
resendInvite,
cancelInvite,
confirmInvite,
getInviteStatistics,
importFromJudgePool,
exportInvites,
sendReminder,
generateInviteCode,
batchGenerateInviteCode,
regenerateInviteCode
regenerateInviteCode,
removeInvite
} from '@/api/martial/judgeInvite'
import { getCompetitionList } from '@/api/martial/competition'
import { getRefereeList } from '@/api/martial/referee'
import dayjs from 'dayjs'
// 数据状态
@@ -323,6 +312,21 @@ const tableData = ref([])
const total = ref(0)
const selection = ref([])
const competitionList = ref([])
const competitionLoading = ref(false) // 赛事列表加载状态
// 裁判选择对话框
const judgeDialogVisible = ref(false)
const judgeLoading = ref(false)
const judgeList = ref([])
const judgeTotal = ref(0)
const selectedJudges = ref([])
const judgeQueryParams = reactive({
current: 1,
size: 10,
name: '',
phone: '',
refereeType: null
})
// 统计数据
const statistics = ref({
@@ -336,7 +340,7 @@ const statistics = ref({
const queryParams = reactive({
current: 1,
size: 10,
competitionId: '',
competitionId: null,
judgeName: '',
judgeLevel: '',
inviteStatus: ''
@@ -344,17 +348,33 @@ const queryParams = reactive({
// 加载赛事列表
const loadCompetitionList = async () => {
competitionLoading.value = true
try {
const res = await getCompetitionList(1, 1000, { status: 1 })
if (res.data && res.data.records) {
competitionList.value = res.data.records
if (competitionList.value.length > 0 && !queryParams.competitionId) {
// 查询所有赛事
const res = await getCompetitionList(1, 1000, {})
// 根据axios响应拦截器的处理数据结构为: res.data.data.records
// res.data = 后端返回的整个JSON对象 { code, success, data, msg }
// res.data.data = 后端返回的data字段 { records, total, size, current, pages }
// res.data.data.records = 实际的赛事列表数组
const records = res.data?.data?.records || []
competitionList.value = records
if (competitionList.value.length > 0) {
// 如果没有选中赛事,自动选择第一个
if (queryParams.competitionId === null || queryParams.competitionId === '') {
queryParams.competitionId = competitionList.value[0].id
handleCompetitionChange(queryParams.competitionId)
}
} else {
ElMessage.warning('暂无可用赛事,请先创建赛事')
}
} catch (error) {
console.error('加载赛事列表失败:', error)
ElMessage.error(`加载赛事列表失败: ${error.response?.data?.msg || error.message || '请检查网络连接'}`)
} finally {
competitionLoading.value = false
}
}
@@ -366,7 +386,7 @@ const handleCompetitionChange = (competitionId) => {
// 加载统计数据
const loadStatistics = async () => {
if (!queryParams.competitionId) return
if (queryParams.competitionId === null || queryParams.competitionId === '') return
try {
const res = await getInviteStatistics(queryParams.competitionId)
@@ -380,7 +400,7 @@ const loadStatistics = async () => {
// 获取数据
const fetchData = async () => {
if (!queryParams.competitionId) return
if (queryParams.competitionId === null || queryParams.competitionId === '') return
loading.value = true
try {
@@ -389,10 +409,10 @@ const fetchData = async () => {
queryParams.size,
queryParams
)
if (res.data) {
tableData.value = res.data.records || []
total.value = res.data.total || 0
}
// 根据axios响应拦截器的处理数据在 res.data.data 中
const data = res.data?.data || {}
tableData.value = data.records || []
total.value = data.total || 0
} catch (error) {
ElMessage.error('加载数据失败')
console.error(error)
@@ -419,96 +439,134 @@ const handleReset = () => {
fetchData()
}
// 发送邀请
const handleSendInvite = async () => {
if (!queryParams.competitionId) {
ElMessage.warning('请先选择赛事')
return
}
// TODO: 打开发送邀请对话框
ElMessage.info('请先生成邀请码,然后通过邮件/短信发送给评委')
}
// 从评委库导入
const handleImportFromPool = async () => {
if (!queryParams.competitionId) {
if (competitionLoading.value) {
ElMessage.warning('赛事列表加载中,请稍候...')
return
}
if (competitionList.value.length === 0) {
ElMessage.warning('暂无可用赛事,请先创建赛事')
return
}
if (queryParams.competitionId === null || queryParams.competitionId === '') {
ElMessage.warning('请先选择赛事')
return
}
// 打开裁判选择对话框
judgeDialogVisible.value = true
selectedJudges.value = []
loadJudgeList()
}
// 加载裁判列表
const loadJudgeList = async () => {
judgeLoading.value = true
try {
// TODO: 打开评委选择对话框
ElMessage.info('请先在评委管理中添加评委,然后在此处生成邀请码')
const params = {}
if (judgeQueryParams.name) {
params.name = judgeQueryParams.name
}
if (judgeQueryParams.phone) {
params.phone = judgeQueryParams.phone
}
if (judgeQueryParams.refereeType !== null && judgeQueryParams.refereeType !== '') {
params.refereeType = judgeQueryParams.refereeType
}
const res = await getRefereeList(
judgeQueryParams.current,
judgeQueryParams.size,
params
)
if (res.data && res.data.data && res.data.data.records) {
judgeList.value = res.data.data.records
judgeTotal.value = res.data.data.total || 0
} else if (res.data && res.data.records) {
judgeList.value = res.data.records
judgeTotal.value = res.data.total || 0
}
} catch (error) {
ElMessage.error('导入失败')
console.error('加载裁判列表失败:', error)
ElMessage.error('加载裁判列表失败')
} finally {
judgeLoading.value = false
}
}
// 重发
const handleResend = async (row) => {
try {
await resendInvite(row.id)
ElMessage.success('重发成功')
fetchData()
} catch (error) {
ElMessage.error('重发失败')
}
// 裁判搜索
const handleJudgeSearch = () => {
judgeQueryParams.current = 1
loadJudgeList()
}
// 提醒
const handleReminder = async (row) => {
try {
await sendReminder(row.id, '请尽快回复邀请')
ElMessage.success('提醒发送成功')
} catch (error) {
ElMessage.error('提醒发送失败')
}
// 裁判搜索重置
const handleJudgeReset = () => {
judgeQueryParams.name = ''
judgeQueryParams.phone = ''
judgeQueryParams.refereeType = null
judgeQueryParams.current = 1
loadJudgeList()
}
// 取消邀请
const handleCancel = async (row) => {
// 裁判选择改变
const handleJudgeSelectionChange = (val) => {
selectedJudges.value = val
}
// 确认导入裁判
const handleConfirmImport = async () => {
if (selectedJudges.value.length === 0) {
ElMessage.warning('请至少选择一位裁判')
return
}
try {
const { value: reason } = await ElMessageBox.prompt('请输入取消原因', '取消邀请', {
confirmButtonText: '确定',
cancelButtonText: '取消',
inputPlaceholder: '请输入取消原因',
inputValidator: (value) => {
if (!value || value.trim() === '') {
return '请输入取消原因'
}
return true
await ElMessageBox.confirm(
`确定为选中的 ${selectedJudges.value.length} 位裁判生成邀请码吗?`,
'确认导入',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'info'
}
)
loading.value = true
const judgeIds = selectedJudges.value.map(item => item.id)
const res = await batchGenerateInviteCode({
competitionId: queryParams.competitionId,
judgeIds: judgeIds,
role: 'judge',
expireDays: 30
})
await cancelInvite(row.id, reason)
ElMessage.success('取消成功')
fetchData()
loadStatistics()
// 根据axios响应拦截器的处理数据在 res.data.data 中
const invites = res.data?.data || []
if (Array.isArray(invites) && invites.length > 0) {
ElMessage.success(`成功为 ${invites.length} 位裁判生成邀请码`)
judgeDialogVisible.value = false
await fetchData()
await loadStatistics()
} else if (Array.isArray(invites) && invites.length === 0) {
ElMessage.warning('所有裁判都已有有效邀请码,无需重复生成')
} else {
ElMessage.error(res.data?.msg || '生成邀请码失败')
}
} catch (error) {
if (error !== 'cancel') {
ElMessage.error('取消失败')
console.error('导入裁判失败:', error)
ElMessage.error(error.response?.data?.msg || error.message || '导入裁判失败')
}
} finally {
loading.value = false
}
}
// 确认
const handleConfirm = async (row) => {
ElMessageBox.confirm('确认接受该评委的邀请回复?', '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning'
})
.then(async () => {
try {
await confirmInvite(row.id)
ElMessage.success('确认成功')
fetchData()
} catch (error) {
ElMessage.error('确认失败')
}
})
.catch(() => {})
}
// 查看
const handleView = async (row) => {
try {
@@ -547,13 +605,21 @@ const handleView = async (row) => {
/**
* 生成单个邀请码
* 注意:此功能仅用于已有邀请记录但未生成邀请码的情况
* 如果需要为新裁判生成邀请码,请使用"从评委库导入"功能
*/
const handleGenerateCode = async (row) => {
if (!queryParams.competitionId) {
if (queryParams.competitionId === null || queryParams.competitionId === '') {
ElMessage.warning('请先选择赛事')
return
}
// 检查是否有judgeId
if (!row.judgeId) {
ElMessage.error('数据异常缺少裁判ID请使用"从评委库导入"功能')
return
}
try {
loading.value = true
const res = await generateInviteCode({
@@ -622,52 +688,31 @@ const handleRegenerateCode = async (row) => {
}
/**
* 批量生成邀请码
* 删除邀请记录
*/
const handleBatchGenerateCode = async () => {
if (!queryParams.competitionId) {
ElMessage.warning('请先选择赛事')
return
}
if (selection.value.length === 0) {
ElMessage.warning('请先选择评委')
return
}
const handleDelete = async (row) => {
try {
await ElMessageBox.confirm(
`确定为选中的 ${selection.value.length} 位评委批量生成邀请码吗?`,
'批量生成邀请码',
`确定要删除评委"${row.judgeName}"的邀请记录吗?`,
'删除确认',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'info'
type: 'warning'
}
)
loading.value = true
const judgeIds = selection.value.map(item => item.judgeId)
await removeInvite(row.id)
ElMessage.success('删除成功')
const res = await batchGenerateInviteCode({
competitionId: queryParams.competitionId,
judgeIds: judgeIds,
role: 'judge',
expireDays: 30
})
if (res.data && Array.isArray(res.data)) {
ElMessage.success(`成功生成 ${res.data.length} 个邀请码`)
// 刷新列表
await fetchData()
await loadStatistics()
} else {
ElMessage.error(res.msg || '批量生成失败')
}
// 刷新列表和统计数据
await fetchData()
await loadStatistics()
} catch (error) {
if (error !== 'cancel') {
console.error('批量生成邀请码失败:', error)
ElMessage.error(error.response?.data?.msg || error.message || '批量生成邀请码失败')
console.error('删除失败:', error)
ElMessage.error(error.response?.data?.msg || error.message || '删除失败')
}
} finally {
loading.value = false
@@ -854,4 +899,25 @@ onMounted(() => {
justify-content: flex-end;
}
}
// 裁判选择对话框样式
.judge-search-form {
margin-bottom: 15px;
.el-form-item {
margin-bottom: 0;
}
}
.judge-pagination {
margin-top: 15px;
display: flex;
justify-content: flex-end;
}
.dialog-footer {
display: flex;
align-items: center;
justify-content: flex-end;
}
</style>

View File

@@ -73,7 +73,6 @@
type="warning"
size="small"
@click="handleDispatch(scope.row)"
:disabled="!isScheduleCompleted(scope.row.id)"
:title="isScheduleCompleted(scope.row.id) ? '进入调度' : '请先完成编排'"
>
调度

View File

@@ -53,6 +53,17 @@
<el-option label="对练" value="4" />
</el-select>
</el-form-item>
<el-form-item label="参赛类型">
<el-select
v-model="queryParams.participantType"
placeholder="请选择参赛类型"
clearable
style="width: 150px"
>
<el-option label="单人" :value="1" />
<el-option label="集体" :value="2" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" :icon="Search" @click="handleSearch">
查询
@@ -144,6 +155,12 @@
<span v-else-if="row.eventType === 4">对练</span>
</template>
</el-table-column>
<el-table-column prop="participantType" label="参赛类型" width="100" align="center">
<template #default="{ row }">
<el-tag v-if="row.participantType === 1" type="success" size="small">单人</el-tag>
<el-tag v-else-if="row.participantType === 2" type="warning" size="small">集体</el-tag>
</template>
</el-table-column>
<el-table-column
prop="registrationFee"
label="报名费(元)"
@@ -297,6 +314,20 @@
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="参赛类型" prop="participantType">
<el-select
v-model="form.participantType"
placeholder="请选择参赛类型"
style="width: 100%"
>
<el-option label="单人" :value="1" />
<el-option label="集体" :value="2" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="报名费(元)" prop="registrationFee">
<el-input-number
@@ -409,6 +440,10 @@
<span v-else-if="detailData.eventType === 3">器械</span>
<span v-else-if="detailData.eventType === 4">对练</span>
</el-descriptions-item>
<el-descriptions-item label="参赛类型">
<el-tag v-if="detailData.participantType === 1" type="success" size="small">单人</el-tag>
<el-tag v-else-if="detailData.participantType === 2" type="warning" size="small">集体</el-tag>
</el-descriptions-item>
<el-descriptions-item label="报名费">
<span style="color: #f56c6c; font-weight: bold">
¥{{ detailData.registrationFee || 0 }}
@@ -490,7 +525,8 @@ const queryParams = reactive({
competitionId: '',
projectName: '',
category: '',
eventType: ''
eventType: '',
participantType: ''
})
// 表单数据
@@ -501,6 +537,7 @@ const form = reactive({
projectName: '',
category: null,
eventType: null,
participantType: null,
registrationFee: 0,
registrationStartTime: '',
registrationEndTime: '',
@@ -539,6 +576,9 @@ const rules = {
eventType: [
{ required: true, message: '请选择项目类型', trigger: 'change' }
],
participantType: [
{ required: true, message: '请选择参赛类型', trigger: 'change' }
],
registrationFee: [
{ required: true, message: '请输入报名费', trigger: 'blur' }
],
@@ -610,7 +650,8 @@ const handleReset = () => {
competitionId: '',
projectName: '',
category: '',
eventType: ''
eventType: '',
participantType: ''
})
fetchData()
}
@@ -721,6 +762,7 @@ const resetForm = () => {
projectName: '',
category: null,
eventType: null,
participantType: null,
registrationFee: 0,
registrationStartTime: '',
registrationEndTime: '',

View File

@@ -143,7 +143,17 @@
</el-col>
<el-col :span="12">
<el-form-item label="等级/职称" prop="level">
<el-input v-model="formData.level" placeholder="请输入等级/职称" clearable></el-input>
<el-select
v-model="formData.level"
placeholder="请选择等级"
clearable
style="width: 130px"
>
<el-option label="国家级" value="国家级" />
<el-option label="一级" value="一级" />
<el-option label="二级" value="二级" />
<el-option label="三级" value="三级" />
</el-select>
</el-form-item>
</el-col>
</el-row>

View File

@@ -26,7 +26,6 @@
size="small"
:type="activeTab === 'competition' ? 'primary' : ''"
@click="activeTab = 'competition'"
:disabled="isScheduleCompleted"
>
竞赛分组
</el-button>
@@ -34,7 +33,6 @@
size="small"
:type="activeTab === 'venue' ? 'primary' : ''"
@click="activeTab = 'venue'"
:disabled="isScheduleCompleted"
>
场地
</el-button>
@@ -168,10 +166,6 @@
</template>
</el-table-column>
</el-table>
<div class="venue-footer-hints">
<p class="footer-hint-text">完成编排前的现阶段, 点击放开次文本; 完成编排前在可导列</p>
</div>
</div>
</div>