Compare commits
4 Commits
a1b26208a4
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b67a1e039c | ||
|
|
c7e78612bf | ||
|
|
49c1cd81c6 | ||
|
|
420bd29eff |
@@ -196,3 +196,13 @@ export const exportSchedule = (competitionId) => {
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
|
||||
// Export schedule template 2 (competition time format)
|
||||
export const exportScheduleTemplate2 = (competitionId, venueId, venueName, timeSlot) => {
|
||||
return request({
|
||||
url: '/martial/export/schedule2',
|
||||
method: 'get',
|
||||
params: { competitionId, venueId, venueName, timeSlot },
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -141,3 +141,16 @@ export const getOrderAmountStats = (orderId) => {
|
||||
params: { orderId }
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取单位统计
|
||||
* @param {Number} competitionId - 赛事ID
|
||||
*/
|
||||
export const getOrganizationStats = (competitionId) => {
|
||||
return request({
|
||||
url: '/api/martial/registrationOrder/organization-stats',
|
||||
method: 'get',
|
||||
params: { competitionId }
|
||||
})
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ export default [
|
||||
redirect: '/martial/order/list',
|
||||
children: [
|
||||
{
|
||||
path: 'competition/list',
|
||||
path: 'competition/index',
|
||||
name: '赛事管理',
|
||||
meta: {
|
||||
keepAlive: false,
|
||||
|
||||
@@ -1581,7 +1581,7 @@ export default {
|
||||
|
||||
handleCreate() {
|
||||
this.$router.push({
|
||||
path: '/martial/competition/list',
|
||||
path: '/martial/competition/index',
|
||||
query: { mode: 'create' }
|
||||
});
|
||||
},
|
||||
@@ -1589,21 +1589,21 @@ export default {
|
||||
handleView(row) {
|
||||
console.log(row)
|
||||
this.$router.push({
|
||||
path: '/martial/competition/list',
|
||||
path: '/martial/competition/index',
|
||||
query: { mode: 'view', id: row.id }
|
||||
});
|
||||
},
|
||||
|
||||
handleEdit(row) {
|
||||
this.$router.push({
|
||||
path: '/martial/competition/list',
|
||||
path: '/martial/competition/index',
|
||||
query: { mode: 'edit', id: row.id }
|
||||
});
|
||||
},
|
||||
|
||||
switchToEdit() {
|
||||
this.$router.push({
|
||||
path: '/martial/competition/list',
|
||||
path: '/martial/competition/index',
|
||||
query: { mode: 'edit', id: this.competitionId }
|
||||
});
|
||||
},
|
||||
@@ -1882,7 +1882,7 @@ export default {
|
||||
|
||||
backToList() {
|
||||
this.$router.push({
|
||||
path: '/martial/competition/list'
|
||||
path: '/martial/competition/index'
|
||||
});
|
||||
// 路由跳转后,在 initPage 中会自动加载列表
|
||||
},
|
||||
|
||||
@@ -174,11 +174,7 @@
|
||||
{{ row.maxParticipants || 0 }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="所属场地" width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
<span>{{ getVenueName(row.venueId) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="createTime"
|
||||
label="创建时间"
|
||||
@@ -240,7 +236,6 @@
|
||||
placeholder="请选择赛事"
|
||||
filterable
|
||||
style="width: 100%"
|
||||
@change="handleCompetitionChangeInForm"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in competitionList"
|
||||
@@ -251,34 +246,6 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="所属场地" prop="venueId">
|
||||
<el-select
|
||||
v-model="form.venueId"
|
||||
placeholder="请选择场地"
|
||||
clearable
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in venueList"
|
||||
:key="item.id"
|
||||
:label="item.venueName"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="项目编码" prop="projectCode">
|
||||
<el-input
|
||||
v-model="form.projectCode"
|
||||
placeholder="请输入项目编码"
|
||||
maxlength="50"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
@@ -486,7 +453,6 @@ import {
|
||||
exportProjects
|
||||
} from '@/api/martial/project'
|
||||
import { getCompetitionList } from '@/api/martial/competition'
|
||||
import { getVenuesByCompetition } from '@/api/martial/venue'
|
||||
import { getToken } from '@/utils/auth'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
@@ -497,8 +463,6 @@ const tableData = ref([])
|
||||
const total = ref(0)
|
||||
const selection = ref([])
|
||||
const competitionList = ref([])
|
||||
const venueList = ref([])
|
||||
const allVenuesCache = ref(new Map()) // 全局场地缓存
|
||||
const dialogVisible = ref(false)
|
||||
const detailVisible = ref(false)
|
||||
const dialogTitle = ref('')
|
||||
@@ -520,7 +484,6 @@ const queryParams = reactive({
|
||||
const form = reactive({
|
||||
id: null,
|
||||
competitionId: '',
|
||||
venueId: null,
|
||||
projectCode: '',
|
||||
projectName: '',
|
||||
category: null,
|
||||
@@ -549,10 +512,6 @@ const rules = {
|
||||
competitionId: [
|
||||
{ required: true, message: '请选择所属赛事', trigger: 'change' }
|
||||
],
|
||||
projectCode: [
|
||||
{ required: true, message: '请输入项目编码', trigger: 'blur' },
|
||||
{ min: 2, max: 50, message: '长度在 2 到 50 个字符', trigger: 'blur' }
|
||||
],
|
||||
projectName: [
|
||||
{ required: true, message: '请输入项目名称', trigger: 'blur' },
|
||||
{ min: 2, max: 100, message: '长度在 2 到 100 个字符', trigger: 'blur' }
|
||||
@@ -589,20 +548,6 @@ const loadCompetitionList = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 表单中赛事变更时加载场地列表
|
||||
const handleCompetitionChangeInForm = async (competitionId) => {
|
||||
form.venueId = null
|
||||
venueList.value = []
|
||||
if (competitionId) {
|
||||
try {
|
||||
const res = await getVenuesByCompetition(competitionId)
|
||||
venueList.value = res.data?.data?.records || []
|
||||
} catch (error) {
|
||||
console.error('加载场地列表失败:', error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 查询数据
|
||||
const fetchData = async () => {
|
||||
loading.value = true
|
||||
@@ -623,8 +568,6 @@ const fetchData = async () => {
|
||||
if (res.data && res.data.data) {
|
||||
tableData.value = res.data.data.records || []
|
||||
total.value = res.data.data.total || 0
|
||||
// 加载项目对应的场地信息
|
||||
await loadVenuesForProjects(tableData.value)
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error('获取数据失败')
|
||||
@@ -634,24 +577,6 @@ const fetchData = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 加载项目对应的场地信息
|
||||
const loadVenuesForProjects = async (projects) => {
|
||||
// 获取所有不同的赛事ID
|
||||
const competitionIds = [...new Set(projects.map(p => p.competitionId).filter(Boolean))]
|
||||
for (const compId of competitionIds) {
|
||||
try {
|
||||
const res = await getVenuesByCompetition(compId)
|
||||
const venues = res.data?.data?.records || []
|
||||
// 缓存场地信息
|
||||
venues.forEach(v => {
|
||||
allVenuesCache.value.set(v.id, v.venueName)
|
||||
})
|
||||
} catch (err) {
|
||||
console.error('加载场地失败:', err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索
|
||||
const handleSearch = () => {
|
||||
queryParams.current = 1
|
||||
@@ -689,15 +614,6 @@ const handleEdit = async (row) => {
|
||||
if (row.price !== undefined) {
|
||||
form.registrationFee = row.price
|
||||
}
|
||||
// 加载该赛事的场地列表
|
||||
if (row.competitionId) {
|
||||
try {
|
||||
const res = await getVenuesByCompetition(row.competitionId)
|
||||
venueList.value = res.data?.data?.records || []
|
||||
} catch (error) {
|
||||
console.error('加载场地列表失败:', error)
|
||||
}
|
||||
}
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
@@ -870,18 +786,6 @@ const getCompetitionName = (competitionId) => {
|
||||
return competition ? competition.competitionName : '-'
|
||||
}
|
||||
|
||||
const getVenueName = (venueId) => {
|
||||
if (!venueId) return '-'
|
||||
// 先从当前场地列表查找
|
||||
let venue = venueList.value.find(item => item.id === venueId)
|
||||
if (venue) return venue.venueName
|
||||
// 再从全局缓存查找
|
||||
if (allVenuesCache.value.has(venueId)) {
|
||||
return allVenuesCache.value.get(venueId)
|
||||
}
|
||||
return '-'
|
||||
}
|
||||
|
||||
// 格式化日期
|
||||
const formatDate = (date) => {
|
||||
if (!date) return '-'
|
||||
|
||||
931
src/views/martial/project/index.vue.backup
Normal file
931
src/views/martial/project/index.vue.backup
Normal file
@@ -0,0 +1,931 @@
|
||||
<template>
|
||||
<div class="project-container">
|
||||
<!-- 搜索区域 -->
|
||||
<el-card shadow="never" class="search-card">
|
||||
<el-form :inline="true" :model="queryParams" class="search-form">
|
||||
<el-form-item label="赛事">
|
||||
<el-select
|
||||
v-model="queryParams.competitionId"
|
||||
placeholder="请选择赛事"
|
||||
clearable
|
||||
filterable
|
||||
style="width: 200px"
|
||||
>
|
||||
<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-input
|
||||
v-model="queryParams.projectName"
|
||||
placeholder="请输入项目名称"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="分组类别">
|
||||
<el-input
|
||||
v-model="queryParams.category"
|
||||
placeholder="请输入分组类别"
|
||||
clearable
|
||||
style="width: 150px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="项目类型">
|
||||
<el-select
|
||||
v-model="queryParams.eventType"
|
||||
placeholder="请选择项目类型"
|
||||
clearable
|
||||
style="width: 150px"
|
||||
>
|
||||
<el-option label="套路" :value="1" />
|
||||
<el-option label="散打" :value="2" />
|
||||
<el-option label="器械" :value="3" />
|
||||
<el-option label="对练" :value="4" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="参赛类型">
|
||||
<el-select
|
||||
v-model="queryParams.type"
|
||||
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">
|
||||
查询
|
||||
</el-button>
|
||||
<el-button :icon="Refresh" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<!-- 工具栏 -->
|
||||
<el-card shadow="never" class="toolbar-card">
|
||||
<div class="toolbar">
|
||||
<div class="toolbar-left">
|
||||
<el-button type="primary" :icon="Plus" @click="handleAdd">
|
||||
新增项目
|
||||
</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
:icon="Delete"
|
||||
:disabled="!selection.length"
|
||||
@click="handleBatchDelete"
|
||||
>
|
||||
批量删除
|
||||
</el-button>
|
||||
<el-upload
|
||||
:action="uploadUrl"
|
||||
:headers="uploadHeaders"
|
||||
:before-upload="beforeUpload"
|
||||
:on-success="handleUploadSuccess"
|
||||
:on-error="handleUploadError"
|
||||
:show-file-list="false"
|
||||
accept=".xlsx,.xls"
|
||||
>
|
||||
<el-button type="success" :icon="Upload">导入Excel</el-button>
|
||||
</el-upload>
|
||||
<el-button type="warning" :icon="Download" @click="handleExport">
|
||||
导出Excel
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="toolbar-right">
|
||||
<el-tooltip content="刷新" placement="top">
|
||||
<el-button circle :icon="Refresh" @click="fetchData" />
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<el-card shadow="never" class="table-card">
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="tableData"
|
||||
stripe
|
||||
border
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column
|
||||
prop="projectCode"
|
||||
label="项目编码"
|
||||
width="120"
|
||||
align="center"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="projectName"
|
||||
label="项目名称"
|
||||
min-width="180"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column label="所属赛事" min-width="150" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
{{ getCompetitionName(row.competitionId) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="category" label="分组类别" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<span>{{ row.category || '-' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="eventType" label="项目类型" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-if="row.eventType === 1" type="primary" size="small">套路</el-tag>
|
||||
<el-tag v-else-if="row.eventType === 2" type="danger" size="small">散打</el-tag>
|
||||
<el-tag v-else-if="row.eventType === 3" type="success" size="small">器械</el-tag>
|
||||
<el-tag v-else-if="row.eventType === 4" type="warning" size="small">对练</el-tag>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="type" label="参赛类型" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-if="row.type === 1" type="success" size="small">单人</el-tag>
|
||||
<el-tag v-else-if="row.type === 2" type="warning" size="small">集体</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="price"
|
||||
label="报名费(元)"
|
||||
width="110"
|
||||
align="center"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<span style="color: #f56c6c">¥{{ row.price || 0 }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="estimatedDuration" label="预计时长" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<span>{{ row.estimatedDuration || 5 }}分钟</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="单位容纳人数" width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.maxParticipants || 0 }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="所属场地" width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
<span>{{ getVenueName(row.venueId) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="createTime"
|
||||
label="创建时间"
|
||||
width="160"
|
||||
align="center"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
{{ formatDate(row.createTime) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="200" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="primary" :icon="Edit" @click="handleEdit(row)">
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button link type="primary" :icon="View" @click="handleView(row)">
|
||||
查看
|
||||
</el-button>
|
||||
<el-button link type="danger" :icon="Delete" @click="handleDelete(row)">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination-container">
|
||||
<el-pagination
|
||||
v-model:current-page="queryParams.current"
|
||||
v-model:page-size="queryParams.size"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:total="total"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="fetchData"
|
||||
@current-change="fetchData"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 新增/编辑弹窗 -->
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
:title="dialogTitle"
|
||||
width="800px"
|
||||
:close-on-click-modal="false"
|
||||
@close="handleDialogClose"
|
||||
>
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
label-width="120px"
|
||||
>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="所属赛事" prop="competitionId">
|
||||
<el-select
|
||||
v-model="form.competitionId"
|
||||
placeholder="请选择赛事"
|
||||
filterable
|
||||
style="width: 100%"
|
||||
@change="handleCompetitionChangeInForm"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in competitionList"
|
||||
:key="item.id"
|
||||
:label="item.competitionName"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="所属场地" prop="venueId">
|
||||
<el-select
|
||||
v-model="form.venueId"
|
||||
placeholder="请选择场地"
|
||||
clearable
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in venueList"
|
||||
:key="item.id"
|
||||
:label="item.venueName"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="项目编码" prop="projectCode">
|
||||
<el-input
|
||||
v-model="form.projectCode"
|
||||
placeholder="请输入项目编码"
|
||||
maxlength="50"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="项目名称" prop="projectName">
|
||||
<el-input
|
||||
v-model="form.projectName"
|
||||
placeholder="请输入项目名称"
|
||||
maxlength="100"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="分组类别" prop="category">
|
||||
<el-select
|
||||
v-model="form.category"
|
||||
placeholder="请选择分组类别"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option label="男子" :value="1" />
|
||||
<el-option label="女子" :value="2" />
|
||||
<el-option label="团体" :value="3" />
|
||||
<el-option label="混合" :value="4" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="项目类型" prop="eventType">
|
||||
<el-select
|
||||
v-model="form.eventType"
|
||||
placeholder="请选择项目类型"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option label="套路" :value="1" />
|
||||
<el-option label="散打" :value="2" />
|
||||
<el-option label="器械" :value="3" />
|
||||
<el-option label="对练" :value="4" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="参赛类型" prop="type">
|
||||
<el-select
|
||||
v-model="form.type"
|
||||
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="estimatedDuration">
|
||||
<el-input-number
|
||||
v-model="form.estimatedDuration"
|
||||
:min="1"
|
||||
:max="120"
|
||||
placeholder="每人/队预计比赛时长"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="报名费(元)" prop="registrationFee">
|
||||
<el-input-number
|
||||
v-model="form.registrationFee"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
:step="10"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="单位容纳人数" prop="maxParticipants">
|
||||
<el-input-number
|
||||
v-model="form.maxParticipants"
|
||||
:min="1"
|
||||
:max="1000"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="排序序号" prop="sortOrder">
|
||||
<el-input-number
|
||||
v-model="form.sortOrder"
|
||||
:min="0"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item label="比赛规则" prop="rules">
|
||||
<el-input
|
||||
v-model="form.rules"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
placeholder="请输入比赛规则说明"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input
|
||||
v-model="form.remark"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入备注信息"
|
||||
maxlength="200"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="submitLoading" @click="handleSubmit">
|
||||
确定
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 查看详情弹窗 -->
|
||||
<el-dialog v-model="detailVisible" title="项目详情" width="700px">
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="项目编码">
|
||||
{{ detailData.projectCode }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="项目名称">
|
||||
{{ detailData.projectName }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="所属赛事">
|
||||
{{ getCompetitionName(detailData.competitionId) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="分组类别">
|
||||
<el-tag v-if="detailData.category === 1" type="primary">男子</el-tag>
|
||||
<el-tag v-else-if="detailData.category === 2" type="danger">女子</el-tag>
|
||||
<el-tag v-else-if="detailData.category === 3" type="success">团体</el-tag>
|
||||
<el-tag v-else-if="detailData.category === 4" type="warning">混合</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="项目类型">
|
||||
<span v-if="detailData.eventType === 1">套路</span>
|
||||
<span v-else-if="detailData.eventType === 2">散打</span>
|
||||
<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.type === 1" type="success" size="small">单人</el-tag>
|
||||
<el-tag v-else-if="detailData.type === 2" type="warning" size="small">集体</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="报名费">
|
||||
<span style="color: #f56c6c; font-weight: bold">
|
||||
¥{{ detailData.registrationFee || 0 }}
|
||||
</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="单位容纳人数">
|
||||
{{ detailData.maxParticipants }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="已报名人数">
|
||||
<span :style="{
|
||||
color: detailData.currentCount >= detailData.maxParticipants ? '#f56c6c' : '#67c23a',
|
||||
fontWeight: 'bold'
|
||||
}">
|
||||
{{ detailData.currentCount || 0 }}
|
||||
</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="创建时间" :span="2">
|
||||
{{ formatDate(detailData.createTime) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="比赛规则" :span="2">
|
||||
{{ detailData.rules || '暂无' }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="备注" :span="2">
|
||||
{{ detailData.remark || '暂无' }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted, computed } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import {
|
||||
Search,
|
||||
Refresh,
|
||||
Plus,
|
||||
Delete,
|
||||
Edit,
|
||||
View,
|
||||
Upload,
|
||||
Download
|
||||
} from '@element-plus/icons-vue'
|
||||
import {
|
||||
getProjectList,
|
||||
submitProject,
|
||||
removeProject,
|
||||
importProjects,
|
||||
exportProjects
|
||||
} from '@/api/martial/project'
|
||||
import { getCompetitionList } from '@/api/martial/competition'
|
||||
import { getVenuesByCompetition } from '@/api/martial/venue'
|
||||
import { getToken } from '@/utils/auth'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
// 数据定义
|
||||
const loading = ref(false)
|
||||
const submitLoading = ref(false)
|
||||
const tableData = ref([])
|
||||
const total = ref(0)
|
||||
const selection = ref([])
|
||||
const competitionList = ref([])
|
||||
const venueList = ref([])
|
||||
const allVenuesCache = ref(new Map()) // 全局场地缓存
|
||||
const dialogVisible = ref(false)
|
||||
const detailVisible = ref(false)
|
||||
const dialogTitle = ref('')
|
||||
const formRef = ref(null)
|
||||
const detailData = ref({})
|
||||
|
||||
// 查询参数
|
||||
const queryParams = reactive({
|
||||
current: 1,
|
||||
size: 10,
|
||||
competitionId: '',
|
||||
projectName: '',
|
||||
category: '',
|
||||
eventType: '',
|
||||
type: ''
|
||||
})
|
||||
|
||||
// 表单数据
|
||||
const form = reactive({
|
||||
id: null,
|
||||
competitionId: '',
|
||||
venueId: null,
|
||||
projectCode: '',
|
||||
projectName: '',
|
||||
category: null,
|
||||
eventType: null,
|
||||
type: null,
|
||||
estimatedDuration: 5,
|
||||
registrationFee: 0,
|
||||
maxParticipants: 100,
|
||||
sortOrder: 0,
|
||||
rules: '',
|
||||
remark: ''
|
||||
})
|
||||
|
||||
// 上传配置
|
||||
const uploadUrl = computed(() => {
|
||||
return import.meta.env.VITE_APP_BASE_URL + '/api/blade-martial/project/import'
|
||||
})
|
||||
const uploadHeaders = computed(() => {
|
||||
return {
|
||||
'Blade-Auth': 'bearer ' + getToken()
|
||||
}
|
||||
})
|
||||
|
||||
// 表单验证规则
|
||||
const rules = {
|
||||
competitionId: [
|
||||
{ required: true, message: '请选择所属赛事', trigger: 'change' }
|
||||
],
|
||||
projectCode: [
|
||||
{ required: true, message: '请输入项目编码', trigger: 'blur' },
|
||||
{ min: 2, max: 50, message: '长度在 2 到 50 个字符', trigger: 'blur' }
|
||||
],
|
||||
projectName: [
|
||||
{ required: true, message: '请输入项目名称', trigger: 'blur' },
|
||||
{ min: 2, max: 100, message: '长度在 2 到 100 个字符', trigger: 'blur' }
|
||||
],
|
||||
category: [
|
||||
{ required: true, message: '请选择分组类别', trigger: 'change' }
|
||||
],
|
||||
eventType: [
|
||||
{ required: true, message: '请选择项目类型', trigger: 'change' }
|
||||
],
|
||||
estimatedDuration: [
|
||||
{ required: true, message: '请输入预计时长', trigger: 'blur' }
|
||||
],
|
||||
type: [
|
||||
{ required: true, message: '请选择参赛类型', trigger: 'change' }
|
||||
],
|
||||
registrationFee: [
|
||||
{ required: true, message: '请输入报名费', trigger: 'blur' }
|
||||
],
|
||||
maxParticipants: [
|
||||
{ required: true, message: '请输入单位容纳人数', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
|
||||
// 加载赛事列表
|
||||
const loadCompetitionList = async () => {
|
||||
try {
|
||||
const res = await getCompetitionList(1, 1000, {})
|
||||
if (res.data && res.data.data && res.data.data.records) {
|
||||
competitionList.value = res.data.data.records
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载赛事列表失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 表单中赛事变更时加载场地列表
|
||||
const handleCompetitionChangeInForm = async (competitionId) => {
|
||||
form.venueId = null
|
||||
venueList.value = []
|
||||
if (competitionId) {
|
||||
try {
|
||||
const res = await getVenuesByCompetition(competitionId)
|
||||
venueList.value = res.data?.data?.records || []
|
||||
} catch (error) {
|
||||
console.error('加载场地列表失败:', error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 查询数据
|
||||
const fetchData = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
// Only pass parameters that backend supports
|
||||
const params = {
|
||||
competitionId: queryParams.competitionId || undefined,
|
||||
projectName: queryParams.projectName || undefined,
|
||||
category: queryParams.category || undefined,
|
||||
eventType: queryParams.eventType || undefined,
|
||||
type: queryParams.type || undefined
|
||||
}
|
||||
const res = await getProjectList(
|
||||
queryParams.current,
|
||||
queryParams.size,
|
||||
params
|
||||
)
|
||||
if (res.data && res.data.data) {
|
||||
tableData.value = res.data.data.records || []
|
||||
total.value = res.data.data.total || 0
|
||||
// 加载项目对应的场地信息
|
||||
await loadVenuesForProjects(tableData.value)
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error('获取数据失败')
|
||||
console.error(error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 加载项目对应的场地信息
|
||||
const loadVenuesForProjects = async (projects) => {
|
||||
// 获取所有不同的赛事ID
|
||||
const competitionIds = [...new Set(projects.map(p => p.competitionId).filter(Boolean))]
|
||||
for (const compId of competitionIds) {
|
||||
try {
|
||||
const res = await getVenuesByCompetition(compId)
|
||||
const venues = res.data?.data?.records || []
|
||||
// 缓存场地信息
|
||||
venues.forEach(v => {
|
||||
allVenuesCache.value.set(v.id, v.venueName)
|
||||
})
|
||||
} catch (err) {
|
||||
console.error('加载场地失败:', err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索
|
||||
const handleSearch = () => {
|
||||
queryParams.current = 1
|
||||
fetchData()
|
||||
}
|
||||
|
||||
// 重置
|
||||
const handleReset = () => {
|
||||
Object.assign(queryParams, {
|
||||
current: 1,
|
||||
size: 10,
|
||||
competitionId: '',
|
||||
projectName: '',
|
||||
category: '',
|
||||
eventType: '',
|
||||
type: ''
|
||||
})
|
||||
fetchData()
|
||||
}
|
||||
|
||||
// 新增
|
||||
const handleAdd = () => {
|
||||
dialogTitle.value = '新增项目'
|
||||
resetForm()
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
// 编辑
|
||||
const handleEdit = async (row) => {
|
||||
dialogTitle.value = '编辑项目'
|
||||
Object.keys(form).forEach((key) => {
|
||||
form[key] = row[key]
|
||||
})
|
||||
// 处理字段名映射:后端返回 price,表单使用 registrationFee
|
||||
if (row.price !== undefined) {
|
||||
form.registrationFee = row.price
|
||||
}
|
||||
// 加载该赛事的场地列表
|
||||
if (row.competitionId) {
|
||||
try {
|
||||
const res = await getVenuesByCompetition(row.competitionId)
|
||||
venueList.value = res.data?.data?.records || []
|
||||
} catch (error) {
|
||||
console.error('加载场地列表失败:', error)
|
||||
}
|
||||
}
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
// 查看
|
||||
const handleView = (row) => {
|
||||
detailData.value = { ...row }
|
||||
detailVisible.value = true
|
||||
}
|
||||
|
||||
// 删除
|
||||
const handleDelete = (row) => {
|
||||
ElMessageBox.confirm('确定要删除该项目吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
.then(async () => {
|
||||
try {
|
||||
await removeProject(row.id)
|
||||
ElMessage.success('删除成功')
|
||||
fetchData()
|
||||
} catch (error) {
|
||||
ElMessage.error('删除失败')
|
||||
}
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
|
||||
// 批量删除
|
||||
const handleBatchDelete = () => {
|
||||
ElMessageBox.confirm(`确定要删除选中的 ${selection.value.length} 个项目吗?`, '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
.then(async () => {
|
||||
try {
|
||||
const ids = selection.value.map((item) => item.id).join(',')
|
||||
await removeProject(ids)
|
||||
ElMessage.success('删除成功')
|
||||
fetchData()
|
||||
} catch (error) {
|
||||
ElMessage.error('删除失败')
|
||||
}
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
|
||||
// 提交表单
|
||||
const handleSubmit = async () => {
|
||||
if (!formRef.value) return
|
||||
|
||||
await formRef.value.validate(async (valid) => {
|
||||
if (valid) {
|
||||
submitLoading.value = true
|
||||
try {
|
||||
// 构建提交数据,确保字段名与后端一致
|
||||
const submitData = {
|
||||
...form,
|
||||
price: form.registrationFee // 后端使用 price 字段
|
||||
}
|
||||
if (form.id) {
|
||||
await submitProject(submitData)
|
||||
ElMessage.success('修改成功')
|
||||
} else {
|
||||
await submitProject(submitData)
|
||||
ElMessage.success('新增成功')
|
||||
}
|
||||
dialogVisible.value = false
|
||||
fetchData()
|
||||
} catch (error) {
|
||||
ElMessage.error(form.id ? '修改失败' : '新增失败')
|
||||
} finally {
|
||||
submitLoading.value = false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 选择变化
|
||||
const handleSelectionChange = (val) => {
|
||||
selection.value = val
|
||||
}
|
||||
|
||||
// 关闭弹窗
|
||||
const handleDialogClose = () => {
|
||||
resetForm()
|
||||
}
|
||||
|
||||
// 重置表单
|
||||
const resetForm = () => {
|
||||
Object.assign(form, {
|
||||
id: null,
|
||||
competitionId: '',
|
||||
projectCode: '',
|
||||
projectName: '',
|
||||
category: null,
|
||||
eventType: null,
|
||||
type: null,
|
||||
estimatedDuration: 5,
|
||||
registrationFee: 0,
|
||||
maxParticipants: 100,
|
||||
sortOrder: 0,
|
||||
rules: '',
|
||||
remark: ''
|
||||
})
|
||||
if (formRef.value) {
|
||||
formRef.value.clearValidate()
|
||||
}
|
||||
}
|
||||
|
||||
// 上传前检查
|
||||
const beforeUpload = (file) => {
|
||||
if (!queryParams.competitionId) {
|
||||
ElMessage.warning('请先选择赛事')
|
||||
return false
|
||||
}
|
||||
const isExcel =
|
||||
file.type === 'application/vnd.ms-excel' ||
|
||||
file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||||
if (!isExcel) {
|
||||
ElMessage.error('只能上传 Excel 文件!')
|
||||
return false
|
||||
}
|
||||
const isLt5M = file.size / 1024 / 1024 < 5
|
||||
if (!isLt5M) {
|
||||
ElMessage.error('文件大小不能超过 5MB!')
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// 上传成功
|
||||
const handleUploadSuccess = (response) => {
|
||||
if (response.success) {
|
||||
ElMessage.success('导入成功')
|
||||
fetchData()
|
||||
} else {
|
||||
ElMessage.error(response.msg || '导入失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 上传失败
|
||||
const handleUploadError = () => {
|
||||
ElMessage.error('导入失败')
|
||||
}
|
||||
|
||||
// 导出
|
||||
const handleExport = async () => {
|
||||
try {
|
||||
const res = await exportProjects(queryParams)
|
||||
const blob = new Blob([res], {
|
||||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||||
})
|
||||
const link = document.createElement('a')
|
||||
link.href = window.URL.createObjectURL(blob)
|
||||
link.download = `项目列表_${dayjs().format('YYYYMMDDHHmmss')}.xlsx`
|
||||
link.click()
|
||||
window.URL.revokeObjectURL(link.href)
|
||||
ElMessage.success('导出成功')
|
||||
} catch (error) {
|
||||
ElMessage.error('导出失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 根据ID获取赛事名称
|
||||
const getCompetitionName = (competitionId) => {
|
||||
if (!competitionId) return '-'
|
||||
const competition = competitionList.value.find(item => item.id === competitionId)
|
||||
return competition ? competition.competitionName : '-'
|
||||
}
|
||||
|
||||
const getVenueName = (venueId) => {
|
||||
if (!venueId) return '-'
|
||||
// 先从当前场地列表查找
|
||||
let venue = venueList.value.find(item => item.id === venueId)
|
||||
if (venue) return venue.venueName
|
||||
// 再从全局缓存查找
|
||||
if (allVenuesCache.value.has(venueId)) {
|
||||
return allVenuesCache.value.get(venueId)
|
||||
}
|
||||
return '-'
|
||||
}
|
||||
|
||||
// 格式化日期
|
||||
const formatDate = (date) => {
|
||||
if (!date) return '-'
|
||||
return dayjs(date).format('YYYY-MM-DD HH:mm:ss')
|
||||
}
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
loadCompetitionList()
|
||||
fetchData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.project-container {
|
||||
padding: 20px;
|
||||
|
||||
.search-card,
|
||||
.toolbar-card,
|
||||
.table-card {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.search-form {
|
||||
.el-form-item {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.toolbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.toolbar-left {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.pagination-container {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -87,6 +87,7 @@
|
||||
<span class="project-meta">{{ getTeamCount(group) }}队</span>
|
||||
<span class="project-meta">{{ group.items?.length || 0 }}组</span>
|
||||
<span class="project-meta">{{ group.code }}</span>
|
||||
<span class="project-table-no">表号: {{ generateTableNo(group) }}</span>
|
||||
</div>
|
||||
<div class="project-actions" @click.stop>
|
||||
<el-popover
|
||||
@@ -276,7 +277,15 @@
|
||||
|
||||
<div class="footer-actions">
|
||||
<el-button size="small" @click="handleSaveDraft" v-if="!isScheduleCompleted">保存草稿</el-button>
|
||||
<el-button size="small" @click="handleExport" v-if="isScheduleCompleted">导出</el-button>
|
||||
<el-dropdown v-if="isScheduleCompleted" @command="handleExportCommand" trigger="click">
|
||||
<el-button size="small">导出 <i class="el-icon-arrow-down el-icon--right"></i></el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="template1">模板1 - 详细赛程表</el-dropdown-item>
|
||||
<el-dropdown-item command="template2">模板2 - 比赛时间表</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
<el-button size="small" type="primary" @click="handleConfirm" v-if="!isScheduleCompleted">完成编排</el-button>
|
||||
</div>
|
||||
|
||||
@@ -380,7 +389,7 @@
|
||||
import { ArrowDown, ArrowRight } from '@element-plus/icons-vue'
|
||||
import { getVenuesByCompetition } from '@/api/martial/venue'
|
||||
import { getCompetitionDetail } from '@/api/martial/competition'
|
||||
import { getScheduleResult, saveAndLockSchedule, saveDraftSchedule, triggerAutoArrange, moveScheduleGroup, exportSchedule } from '@/api/martial/activitySchedule'
|
||||
import { getScheduleResult, saveAndLockSchedule, saveDraftSchedule, triggerAutoArrange, moveScheduleGroup, exportSchedule, exportScheduleTemplate2 } from '@/api/martial/activitySchedule'
|
||||
import { updateCheckInStatus, getScheduleConfig } from '@/api/martial/schedulePlan'
|
||||
|
||||
export default {
|
||||
@@ -496,6 +505,44 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 生成表号: 场地(1位) + 时段(1位,上午=1/下午=2) + 序号(2位)
|
||||
generateTableNo(group) {
|
||||
// 1. 获取场地编号
|
||||
let venueNo = 1
|
||||
if (group.venueId) {
|
||||
const venue = this.venues.find(v => v.id === group.venueId || String(v.id) === String(group.venueId))
|
||||
if (venue && venue.venueName) {
|
||||
// 从场地名称提取数字
|
||||
const match = venue.venueName.match(/\d+/)
|
||||
if (match) {
|
||||
venueNo = parseInt(match[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 获取时段:上午=1, 下午=2
|
||||
let period = 1
|
||||
if (group.timeSlot) {
|
||||
const hour = parseInt(group.timeSlot.split(':')[0])
|
||||
period = hour < 12 ? 1 : 2
|
||||
}
|
||||
|
||||
// 3. 获取序号:在同场地同时段中的顺序
|
||||
const sameSlotGroups = this.competitionGroups.filter(g => {
|
||||
const gVenueMatch = String(g.venueId) === String(group.venueId)
|
||||
if (!gVenueMatch) return false
|
||||
const gHour = parseInt((g.timeSlot || '08:30').split(':')[0])
|
||||
const gPeriod = gHour < 12 ? 1 : 2
|
||||
return gPeriod === period
|
||||
})
|
||||
// 按id排序保持稳定顺序
|
||||
sameSlotGroups.sort((a, b) => (a.id || 0) - (b.id || 0))
|
||||
const orderIndex = sameSlotGroups.findIndex(g => g.id === group.id) + 1
|
||||
|
||||
// 4. 格式化: 场地(1位) + 时段(1位) + 序号(2位)
|
||||
return `${venueNo}${period}${String(orderIndex).padStart(2, '0')}`
|
||||
},
|
||||
|
||||
// 检查项目是否展开
|
||||
isProjectExpanded(groupId) {
|
||||
return this.expandedProjects[groupId] === true
|
||||
@@ -1148,6 +1195,34 @@ export default {
|
||||
group.items.splice(itemIndex + 1, 0, temp)
|
||||
this.$message.success('下移成功')
|
||||
},
|
||||
handleExportCommand(command) {
|
||||
if (command === 'template1') {
|
||||
this.handleExport()
|
||||
} else if (command === 'template2') {
|
||||
this.handleExportTemplate2()
|
||||
}
|
||||
},
|
||||
async handleExportTemplate2() {
|
||||
try {
|
||||
this.loading = true
|
||||
const venueId = this.selectedVenueId
|
||||
const venue = this.venues.find(v => v.id === venueId)
|
||||
const venueName = venue ? venue.venueName : null
|
||||
const res = await exportScheduleTemplate2(this.competitionId, venueId, venueName, null)
|
||||
const blob = new Blob([res.data], { type: 'application/vnd.ms-excel' })
|
||||
const link = document.createElement('a')
|
||||
link.href = window.URL.createObjectURL(blob)
|
||||
link.download = `比赛时间_${venueName || '全部场地'}_${this.competitionInfo.competitionName || this.competitionId}.xlsx`
|
||||
link.click()
|
||||
window.URL.revokeObjectURL(link.href)
|
||||
this.$message.success('导出成功')
|
||||
} catch (error) {
|
||||
console.error('导出失败:', error)
|
||||
this.$message.error('导出失败,请稍后重试')
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
async handleExport() {
|
||||
try {
|
||||
this.loading = true
|
||||
@@ -1421,6 +1496,16 @@ export default {
|
||||
color: #606266;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.project-table-no {
|
||||
color: #409EFF;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
margin-left: 10px;
|
||||
padding: 2px 8px;
|
||||
background-color: #ecf5ff;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.project-actions {
|
||||
|
||||
@@ -94,7 +94,8 @@
|
||||
|
||||
<el-table-column label="总裁判分数" width="120" align="center" fixed="right">
|
||||
<template #default="scope">
|
||||
<span class="total-score">{{ formatScore(scope.row.totalScore) }}</span>
|
||||
<span v-if="scope.row.scoreStatus === 2" class="total-score">{{ formatScore(scope.row.chiefJudgeScore) }}</span>
|
||||
<span v-else class="pending-score">待确认</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
@@ -153,12 +154,17 @@
|
||||
|
||||
<div class="total-score-display">
|
||||
<span class="label">总分:</span>
|
||||
<span class="value">{{ formatScore(currentDetail.totalScore) }}</span>
|
||||
<div class="calculation-note">
|
||||
<span v-if="currentDetail.judgeScores.length > 2">
|
||||
(去掉最高分和最低分后的平均分)
|
||||
</span>
|
||||
</div>
|
||||
<template v-if="currentDetail.scoreStatus === 2">
|
||||
<span class="value">{{ formatScore(currentDetail.chiefJudgeScore) }}</span>
|
||||
<div class="calculation-note">(主裁判已确认)</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span class="value pending">待确认最终得分</span>
|
||||
<div class="calculation-note">
|
||||
裁判员评分: {{ formatScore(currentDetail.totalScore) }}
|
||||
<span v-if="currentDetail.judgeScores.length > 2">(去掉最高最低分后平均)</span>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -398,7 +404,9 @@ export default {
|
||||
playerNo: score.playerNo || '',
|
||||
judgeScores: [],
|
||||
scoreDetails: [],
|
||||
totalScore: 0
|
||||
totalScore: 0,
|
||||
chiefJudgeScore: score.chiefJudgeScore,
|
||||
scoreStatus: score.scoreStatus || 0
|
||||
})
|
||||
}
|
||||
|
||||
@@ -565,6 +573,16 @@ export default {
|
||||
}
|
||||
|
||||
.total-score {
|
||||
}
|
||||
|
||||
.pending-score {
|
||||
color: #e6a23c;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.value.pending {
|
||||
color: #e6a23c;
|
||||
font-weight: 500;
|
||||
color: #1b7c5e;
|
||||
font-weight: 700;
|
||||
font-size: 14px;
|
||||
|
||||
Reference in New Issue
Block a user