实现赛程表导出功能
- 添加 exportSchedule API 调用后端导出接口 - 实现 handleExport 方法,支持下载 Excel 文件 - 文件名格式:赛程表_赛事名称.xlsx 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -183,3 +183,16 @@ export const saveDispatch = (data) => {
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出赛程表
|
||||
* @param {Number} competitionId - 赛事ID
|
||||
*/
|
||||
export const exportSchedule = (competitionId) => {
|
||||
return request({
|
||||
url: '/martial/export/schedule',
|
||||
method: 'get',
|
||||
params: { competitionId },
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
|
||||
355
src/views/martial/order/index.vue.bak
Normal file
355
src/views/martial/order/index.vue.bak
Normal file
@@ -0,0 +1,355 @@
|
||||
<template>
|
||||
<div class="martial-order-container">
|
||||
<el-card shadow="hover">
|
||||
<div class="page-header">
|
||||
<h2 class="page-title">订单管理</h2>
|
||||
</div>
|
||||
<el-form :inline="true" :model="searchForm" class="search-form">
|
||||
<el-form-item>
|
||||
<el-input
|
||||
v-model="searchForm.keyword"
|
||||
placeholder="搜索赛事名称"
|
||||
clearable
|
||||
size="small"
|
||||
style="width: 240px"
|
||||
>
|
||||
<i slot="prefix" class="el-input__icon el-icon-search"></i>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-select
|
||||
v-model="searchForm.status"
|
||||
placeholder="赛事状态"
|
||||
clearable
|
||||
size="small"
|
||||
style="width: 180px"
|
||||
>
|
||||
<el-option label="未开始" :value="1"></el-option>
|
||||
<el-option label="报名中" :value="2"></el-option>
|
||||
<el-option label="进行中" :value="3"></el-option>
|
||||
<el-option label="已结束" :value="4"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" size="small" @click="handleSearch">查询</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="tableData"
|
||||
border
|
||||
stripe
|
||||
size="small"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-table-column type="index" label="序号" width="60" align="center"></el-table-column>
|
||||
<el-table-column prop="competitionName" label="赛事名称" min-width="200" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column prop="competitionCode" label="赛事编号" width="150"></el-table-column>
|
||||
<el-table-column prop="organizer" label="主办单位" min-width="150" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column prop="location" label="举办地点" width="120"></el-table-column>
|
||||
<el-table-column prop="registrationTime" label="报名时间" width="180" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<span>{{ formatDateRange(scope.row.registrationStartTime, scope.row.registrationEndTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="competitionTime" label="比赛时间" width="180" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<span>{{ formatDateRange(scope.row.competitionStartTime, scope.row.competitionEndTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" label="状态" width="90" align="center">
|
||||
<template #default="scope">
|
||||
<el-tag :type="getStatusType(scope.row.status)" size="small">
|
||||
{{ getStatusText(scope.row.status) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="320" align="center" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button type="primary" size="small" @click="handleRegistrationDetail(scope.row)">报名详情</el-button>
|
||||
<el-button type="success" size="small" @click="handleSchedule(scope.row)">编排</el-button>
|
||||
<el-button
|
||||
type="warning"
|
||||
size="small"
|
||||
@click="handleDispatch(scope.row)"
|
||||
:title="isScheduleCompleted(scope.row.id) ? '进入调度' : '请先完成编排'"
|
||||
>
|
||||
调度
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<el-pagination
|
||||
class="pagination"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="pagination.current"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:page-size="pagination.size"
|
||||
layout="total, sizes, prev, pager, next"
|
||||
:total="pagination.total"
|
||||
small
|
||||
></el-pagination>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getCompetitionList } from '@/api/martial/competition'
|
||||
import { getScheduleResult } from '@/api/martial/activitySchedule'
|
||||
|
||||
export default {
|
||||
name: 'MartialOrderList',
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
searchForm: {
|
||||
keyword: '',
|
||||
status: null
|
||||
},
|
||||
tableData: [],
|
||||
pagination: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
total: 0
|
||||
},
|
||||
scheduleStatusMap: {} // 存储每个赛事的编排状态
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.loadCompetitionList()
|
||||
},
|
||||
activated() {
|
||||
// 当页面被激活时(从其他页面返回),重新加载编排状态
|
||||
if (this.tableData.length > 0) {
|
||||
this.loadScheduleStatus()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 加载赛事列表
|
||||
loadCompetitionList() {
|
||||
this.loading = true
|
||||
const params = {}
|
||||
|
||||
if (this.searchForm.keyword) {
|
||||
params.competitionName = this.searchForm.keyword
|
||||
}
|
||||
if (this.searchForm.status !== null && this.searchForm.status !== '') {
|
||||
params.status = this.searchForm.status
|
||||
}
|
||||
|
||||
getCompetitionList(this.pagination.current, this.pagination.size, params)
|
||||
.then(res => {
|
||||
console.log('赛事列表返回数据:', res)
|
||||
const responseData = res.data?.data
|
||||
if (responseData && responseData.records) {
|
||||
// 处理赛事数据,兼容驼峰和下划线命名
|
||||
this.tableData = responseData.records.map(competition => ({
|
||||
id: competition.id,
|
||||
competitionName: competition.competitionName || competition.competition_name,
|
||||
competitionCode: competition.competitionCode || competition.competition_code,
|
||||
organizer: competition.organizer,
|
||||
location: competition.location,
|
||||
venue: competition.venue,
|
||||
registrationStartTime: competition.registrationStartTime || competition.registration_start_time,
|
||||
registrationEndTime: competition.registrationEndTime || competition.registration_end_time,
|
||||
competitionStartTime: competition.competitionStartTime || competition.competition_start_time,
|
||||
competitionEndTime: competition.competitionEndTime || competition.competition_end_time,
|
||||
status: competition.status,
|
||||
createTime: competition.createTime || competition.create_time
|
||||
}))
|
||||
this.pagination.total = responseData.total || 0
|
||||
|
||||
// 加载每个赛事的编排状态
|
||||
this.loadScheduleStatus()
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('加载赛事列表失败', err)
|
||||
this.$message.error('加载赛事列表失败')
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
|
||||
// 加载编排状态
|
||||
async loadScheduleStatus() {
|
||||
for (const competition of this.tableData) {
|
||||
try {
|
||||
const res = await getScheduleResult(competition.id)
|
||||
if (res.data?.data) {
|
||||
this.$set(this.scheduleStatusMap, competition.id, res.data.data.isCompleted || false)
|
||||
} else {
|
||||
this.$set(this.scheduleStatusMap, competition.id, false)
|
||||
}
|
||||
} catch (err) {
|
||||
// 如果获取失败,默认为未完成
|
||||
this.$set(this.scheduleStatusMap, competition.id, false)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 检查编排是否完成
|
||||
isScheduleCompleted(competitionId) {
|
||||
return this.scheduleStatusMap[competitionId] === true
|
||||
},
|
||||
|
||||
handleSearch() {
|
||||
this.pagination.current = 1
|
||||
this.loadCompetitionList()
|
||||
},
|
||||
|
||||
handleSizeChange(size) {
|
||||
this.pagination.size = size
|
||||
this.pagination.current = 1
|
||||
this.loadCompetitionList()
|
||||
},
|
||||
|
||||
handleCurrentChange(current) {
|
||||
this.pagination.current = current
|
||||
this.loadCompetitionList()
|
||||
},
|
||||
|
||||
// 查看报名详情 - 传递赛事ID
|
||||
handleRegistrationDetail(row) {
|
||||
this.$router.push({
|
||||
path: '/martial/registration/detail',
|
||||
query: { competitionId: row.id }
|
||||
})
|
||||
},
|
||||
|
||||
// 编排 - 传递赛事ID
|
||||
handleSchedule(row) {
|
||||
this.$router.push({
|
||||
path: '/martial/schedule/list',
|
||||
query: { competitionId: row.id }
|
||||
})
|
||||
},
|
||||
|
||||
// 调度 - 传递赛事ID
|
||||
handleDispatch(row) {
|
||||
// 检查编排是否完成
|
||||
if (!this.isScheduleCompleted(row.id)) {
|
||||
this.$message.warning('请先完成编排后再进行调度')
|
||||
return
|
||||
}
|
||||
|
||||
this.$router.push({
|
||||
path: '/martial/dispatch/list',
|
||||
query: { competitionId: row.id }
|
||||
})
|
||||
},
|
||||
|
||||
// 格式化日期范围
|
||||
formatDateRange(startTime, endTime) {
|
||||
if (!startTime || !endTime) return '-'
|
||||
// 简单格式化,只显示日期部分
|
||||
const start = startTime.split(' ')[0]
|
||||
const end = endTime.split(' ')[0]
|
||||
return `${start} ~ ${end}`
|
||||
},
|
||||
|
||||
getStatusType(status) {
|
||||
const statusMap = {
|
||||
1: 'info', // 未开始
|
||||
2: 'success', // 报名中
|
||||
3: 'warning', // 进行中
|
||||
4: 'info' // 已结束
|
||||
}
|
||||
return statusMap[status] || 'info'
|
||||
},
|
||||
|
||||
getStatusText(status) {
|
||||
const statusMap = {
|
||||
1: '未开始',
|
||||
2: '报名中',
|
||||
3: '进行中',
|
||||
4: '已结束'
|
||||
}
|
||||
return statusMap[status] || '未知'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.martial-order-container {
|
||||
min-height: 100%;
|
||||
padding: 15px;
|
||||
background: #fff;
|
||||
|
||||
.page-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 15px;
|
||||
|
||||
.page-title {
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #2c3e50;
|
||||
}
|
||||
}
|
||||
|
||||
.tip-message {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
padding: 10px 14px;
|
||||
margin-bottom: 15px;
|
||||
background: linear-gradient(90deg, #ffd54f 0%, #ffecb3 100%);
|
||||
border: 1px solid #ffc107;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 4px rgba(255, 193, 7, 0.2);
|
||||
|
||||
.tip-header {
|
||||
flex-shrink: 0;
|
||||
|
||||
.tip-number {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: #ff9800;
|
||||
color: #fff;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.tip-content {
|
||||
flex: 1;
|
||||
color: #5d4037;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
|
||||
.tip-subtitle {
|
||||
margin-top: 3px;
|
||||
color: #6d4c41;
|
||||
font-size: 11px;
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search-form {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.amount-text {
|
||||
color: #e6a23c;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
margin-top: 15px;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
990
src/views/martial/participant/index.vue.bak
Normal file
990
src/views/martial/participant/index.vue.bak
Normal file
@@ -0,0 +1,990 @@
|
||||
<template>
|
||||
<div class="participant-container">
|
||||
<!-- 列表视图 -->
|
||||
<div v-if="currentView === 'list'" class="list-view">
|
||||
<el-card shadow="hover">
|
||||
<div class="list-header">
|
||||
<h2 class="page-title">参赛选手管理</h2>
|
||||
<el-button type="primary" icon="el-icon-plus" @click="handleCreate">
|
||||
添加选手
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<el-form :inline="true" :model="searchForm" class="search-form">
|
||||
<el-form-item>
|
||||
<el-input
|
||||
v-model="searchForm.keyword"
|
||||
placeholder="搜索选手姓名"
|
||||
clearable
|
||||
size="small"
|
||||
style="width: 240px"
|
||||
>
|
||||
<template #prefix>
|
||||
<i class="el-input__icon el-icon-search"></i>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-select v-model="searchForm.competitionId" placeholder="选择赛事" clearable size="small" style="width: 200px">
|
||||
<el-option label="全部赛事" :value="null" />
|
||||
<el-option
|
||||
v-for="item in allCompetitionOptions"
|
||||
:key="item.id"
|
||||
:label="item.competitionName"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" size="small" @click="handleSearch">查询</el-button>
|
||||
<el-button size="small" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="displayList"
|
||||
border
|
||||
stripe
|
||||
style="width: 100%"
|
||||
class="data-table"
|
||||
>
|
||||
<el-table-column
|
||||
type="index"
|
||||
label="序号"
|
||||
width="60"
|
||||
align="center"
|
||||
/>
|
||||
|
||||
<el-table-column
|
||||
prop="playerName"
|
||||
label="选手姓名"
|
||||
width="120"
|
||||
/>
|
||||
|
||||
<el-table-column
|
||||
prop="competitionName"
|
||||
label="所属赛事"
|
||||
min-width="180"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
|
||||
<el-table-column
|
||||
prop="projectName"
|
||||
label="参赛项目"
|
||||
width="120"
|
||||
/>
|
||||
|
||||
<el-table-column
|
||||
prop="category"
|
||||
label="组别"
|
||||
width="100"
|
||||
/>
|
||||
|
||||
<el-table-column
|
||||
label="性别"
|
||||
width="80"
|
||||
align="center"
|
||||
>
|
||||
<template #default="scope">
|
||||
<el-tag :type="scope.row.gender === 1 ? 'primary' : 'danger'" size="small">
|
||||
{{ scope.row.gender === 1 ? '男' : '女' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="age"
|
||||
label="年龄"
|
||||
width="80"
|
||||
align="center"
|
||||
/>
|
||||
|
||||
<el-table-column
|
||||
prop="organization"
|
||||
label="所属单位"
|
||||
min-width="150"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
|
||||
<el-table-column
|
||||
prop="contactPhone"
|
||||
label="联系电话"
|
||||
width="120"
|
||||
/>
|
||||
|
||||
<el-table-column
|
||||
prop="orderNum"
|
||||
label="出场顺序"
|
||||
width="100"
|
||||
align="center"
|
||||
/>
|
||||
|
||||
<el-table-column
|
||||
label="操作"
|
||||
width="220"
|
||||
fixed="right"
|
||||
align="center"
|
||||
>
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
type="primary"
|
||||
link
|
||||
size="small"
|
||||
icon="el-icon-view"
|
||||
@click="handleView(scope.row)"
|
||||
>
|
||||
查看
|
||||
</el-button>
|
||||
<el-button
|
||||
type="warning"
|
||||
link
|
||||
size="small"
|
||||
icon="el-icon-edit"
|
||||
@click="handleEdit(scope.row)"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
link
|
||||
size="small"
|
||||
icon="el-icon-delete"
|
||||
@click="handleDelete(scope.row)"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<el-pagination
|
||||
v-if="pagination.total > 0"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handlePageChange"
|
||||
:current-page="pagination.current"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:page-size="pagination.size"
|
||||
:total="pagination.total"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
style="margin-top: 20px; text-align: right"
|
||||
/>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<!-- 表单视图 -->
|
||||
<div v-else class="form-view">
|
||||
<el-card shadow="hover" v-loading="loading">
|
||||
<div class="page-header">
|
||||
<el-button
|
||||
icon="el-icon-arrow-left"
|
||||
@click="backToList"
|
||||
>
|
||||
返回列表
|
||||
</el-button>
|
||||
<h2 class="page-title">{{ pageTitle }}</h2>
|
||||
<div class="header-actions" v-if="currentView !== 'view'">
|
||||
<el-button @click="backToList">取消</el-button>
|
||||
<el-button type="primary" @click="handleSave">
|
||||
{{ currentView === 'create' ? '创建' : '保存' }}
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="header-actions" v-else>
|
||||
<el-button type="primary" @click="switchToEdit">编辑</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="formRules"
|
||||
label-width="120px"
|
||||
:disabled="currentView === 'view'"
|
||||
class="participant-form"
|
||||
>
|
||||
<!-- 基本信息 -->
|
||||
<div class="form-section">
|
||||
<div class="section-title">
|
||||
<i class="el-icon-user"></i>
|
||||
基本信息
|
||||
</div>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="选手姓名" prop="playerName">
|
||||
<el-input
|
||||
v-model="formData.playerName"
|
||||
placeholder="请输入选手姓名"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="性别" prop="gender">
|
||||
<el-radio-group v-model="formData.gender">
|
||||
<el-radio :label="1">男</el-radio>
|
||||
<el-radio :label="2">女</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="年龄" prop="age">
|
||||
<el-input-number
|
||||
v-model="formData.age"
|
||||
:min="6"
|
||||
:max="100"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="身份证号" prop="idCard">
|
||||
<el-input
|
||||
v-model="formData.idCard"
|
||||
placeholder="请输入身份证号"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="联系电话" prop="contactPhone">
|
||||
<el-input
|
||||
v-model="formData.contactPhone"
|
||||
placeholder="请输入联系电话"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-form-item label="所属单位" prop="organization">
|
||||
<el-input
|
||||
v-model="formData.organization"
|
||||
placeholder="请输入所属单位"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<!-- 赛事信息 -->
|
||||
<div class="form-section">
|
||||
<div class="section-title">
|
||||
<i class="el-icon-trophy"></i>
|
||||
赛事信息
|
||||
</div>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="所属赛事" prop="competitionId">
|
||||
<el-select
|
||||
v-model="formData.competitionId"
|
||||
placeholder="请选择赛事"
|
||||
style="width: 100%"
|
||||
@change="handleCompetitionChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in availableCompetitionOptions"
|
||||
: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="projectId">
|
||||
<el-select
|
||||
v-model="formData.projectId"
|
||||
placeholder="请选择参赛项目"
|
||||
style="width: 100%"
|
||||
@change="handleProjectChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in projectOptions"
|
||||
:key="item.id"
|
||||
:label="item.projectName"
|
||||
: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="category">
|
||||
<el-input
|
||||
v-model="formData.category"
|
||||
placeholder="例如:成年男子组"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="出场顺序" prop="orderNum">
|
||||
<el-input-number
|
||||
v-model="formData.orderNum"
|
||||
:min="1"
|
||||
:max="9999"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
<!-- 其他信息 -->
|
||||
<div class="form-section">
|
||||
<div class="section-title">
|
||||
<i class="el-icon-document"></i>
|
||||
其他信息
|
||||
</div>
|
||||
|
||||
<el-form-item label="选手简介" prop="introduction">
|
||||
<el-input
|
||||
v-model="formData.introduction"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
placeholder="请输入选手简介"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input
|
||||
v-model="formData.remark"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入备注"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getCompetitionList } from '@/api/martial/competition'
|
||||
import { getInfoPublishList } from '@/api/martial/infoPublish'
|
||||
import { getProjectsByCompetition } from '@/api/martial/project'
|
||||
import {
|
||||
getParticipantList,
|
||||
getParticipantDetail,
|
||||
addParticipant,
|
||||
updateParticipant,
|
||||
removeParticipant
|
||||
} from '@/api/martial/participant'
|
||||
|
||||
export default {
|
||||
name: 'ParticipantManagement',
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
currentView: 'list', // list, create, edit, view
|
||||
participantId: null,
|
||||
searchForm: {
|
||||
keyword: '',
|
||||
competitionId: null
|
||||
},
|
||||
pagination: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
total: 0
|
||||
},
|
||||
competitionOptions: [], // 已发布的可报名赛事列表(用于新建)
|
||||
allCompetitionOptions: [], // 所有赛事列表(用于搜索和编辑)
|
||||
projectOptions: [], // 项目列表
|
||||
participantList: [],
|
||||
formData: {
|
||||
orderId: null,
|
||||
competitionId: null,
|
||||
competitionName: '',
|
||||
playerName: '',
|
||||
gender: 1,
|
||||
age: null,
|
||||
contactPhone: '',
|
||||
organization: '',
|
||||
idCard: '',
|
||||
projectId: null,
|
||||
category: '',
|
||||
orderNum: 1,
|
||||
introduction: '',
|
||||
remark: '',
|
||||
attachments: []
|
||||
},
|
||||
formRules: {
|
||||
playerName: [
|
||||
{ required: true, message: '请输入选手姓名', trigger: 'blur' }
|
||||
],
|
||||
gender: [
|
||||
{ required: true, message: '请选择性别', trigger: 'change' }
|
||||
],
|
||||
age: [
|
||||
{ required: true, message: '请输入年龄', trigger: 'blur' }
|
||||
],
|
||||
contactPhone: [
|
||||
{ required: true, message: '请输入联系电话', trigger: 'blur' },
|
||||
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur' }
|
||||
],
|
||||
competitionId: [
|
||||
{ required: true, message: '请选择赛事', trigger: 'change' }
|
||||
],
|
||||
projectId: [
|
||||
{ required: true, message: '请选择参赛项目', trigger: 'change' }
|
||||
]
|
||||
}
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
pageTitle() {
|
||||
const titleMap = {
|
||||
create: '添加参赛选手',
|
||||
edit: '编辑参赛选手',
|
||||
view: '查看参赛选手'
|
||||
};
|
||||
return titleMap[this.currentView] || '参赛选手信息';
|
||||
},
|
||||
displayList() {
|
||||
return this.participantList;
|
||||
},
|
||||
// 根据不同模式返回不同的赛事选项
|
||||
availableCompetitionOptions() {
|
||||
// 编辑和查看模式:显示所有赛事(因为可能编辑已过报名期的选手)
|
||||
if (this.currentView === 'edit' || this.currentView === 'view') {
|
||||
return this.allCompetitionOptions;
|
||||
}
|
||||
// 新建模式:只显示可报名的赛事
|
||||
return this.competitionOptions;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'$route.query': {
|
||||
handler(query) {
|
||||
this.initPage();
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.loadAvailableCompetitions();
|
||||
this.loadAllCompetitions();
|
||||
},
|
||||
methods: {
|
||||
initPage() {
|
||||
const { mode, id } = this.$route.query;
|
||||
this.currentView = mode || 'list';
|
||||
// 不使用 parseInt,保持 ID 为字符串避免精度丢失
|
||||
this.participantId = id || null;
|
||||
|
||||
if (this.currentView === 'list') {
|
||||
this.loadParticipantList();
|
||||
} else if (this.currentView !== 'list' && this.participantId) {
|
||||
this.loadParticipantData();
|
||||
} else if (this.currentView === 'create') {
|
||||
this.resetFormData();
|
||||
}
|
||||
},
|
||||
|
||||
// 加载可报名的赛事(从已发布的信息中获取)
|
||||
loadAvailableCompetitions() {
|
||||
getInfoPublishList(1, 100, { isPublished: 1 })
|
||||
.then(res => {
|
||||
console.log('已发布信息列表返回数据:', res);
|
||||
const responseData = res.data?.data;
|
||||
if (responseData && responseData.records) {
|
||||
const publishedCompetitionIds = new Set(
|
||||
responseData.records
|
||||
.filter(item => item.competitionId)
|
||||
.map(item => item.competitionId)
|
||||
);
|
||||
|
||||
console.log('已发布的赛事ID列表:', Array.from(publishedCompetitionIds));
|
||||
|
||||
if (publishedCompetitionIds.size > 0) {
|
||||
this.loadPublishedCompetitions(Array.from(publishedCompetitionIds));
|
||||
} else {
|
||||
// 如果没有发布信息,直接加载所有赛事作为可报名赛事
|
||||
console.log('没有已发布信息,加载所有赛事');
|
||||
this.loadPublishedCompetitions([]);
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('加载已发布信息列表失败', err);
|
||||
// 出错时也加载所有赛事
|
||||
this.loadPublishedCompetitions([]);
|
||||
});
|
||||
},
|
||||
|
||||
// 加载已发布的赛事详细信息,并过滤出可报名的赛事
|
||||
loadPublishedCompetitions(competitionIds) {
|
||||
getCompetitionList(1, 100, {})
|
||||
.then(res => {
|
||||
console.log('赛事列表返回数据:', res);
|
||||
const responseData = res.data?.data;
|
||||
if (responseData && responseData.records) {
|
||||
const now = new Date();
|
||||
|
||||
this.competitionOptions = responseData.records
|
||||
.filter(item => {
|
||||
// 如果没有发布信息(competitionIds为空数组),则显示所有在报名期内的赛事
|
||||
if (competitionIds.length > 0 && !competitionIds.includes(item.id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查报名时间
|
||||
if (!item.registrationStartTime || !item.registrationEndTime) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const regStart = new Date(item.registrationStartTime);
|
||||
const regEnd = new Date(item.registrationEndTime);
|
||||
return now >= regStart && now <= regEnd;
|
||||
})
|
||||
.map(item => ({
|
||||
id: item.id,
|
||||
competitionName: item.competitionName,
|
||||
registrationStartTime: item.registrationStartTime,
|
||||
registrationEndTime: item.registrationEndTime
|
||||
}));
|
||||
|
||||
console.log('可报名的赛事列表:', this.competitionOptions);
|
||||
|
||||
if (this.competitionOptions.length === 0) {
|
||||
console.log('当前没有可以报名的赛事(报名时间范围外)');
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('加载赛事列表失败', err);
|
||||
this.$message.error('加载赛事列表失败');
|
||||
});
|
||||
},
|
||||
|
||||
// 加载所有赛事(用于搜索过滤)
|
||||
loadAllCompetitions() {
|
||||
getCompetitionList(1, 100, {})
|
||||
.then(res => {
|
||||
const responseData = res.data?.data;
|
||||
if (responseData && responseData.records) {
|
||||
this.allCompetitionOptions = responseData.records.map(item => ({
|
||||
id: item.id,
|
||||
competitionName: item.competitionName
|
||||
}));
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('加载所有赛事失败', err);
|
||||
});
|
||||
},
|
||||
|
||||
loadParticipantList() {
|
||||
this.loading = true;
|
||||
const params = {};
|
||||
|
||||
if (this.searchForm.keyword) {
|
||||
params.playerName = this.searchForm.keyword;
|
||||
}
|
||||
|
||||
if (this.searchForm.competitionId) {
|
||||
params.competitionId = this.searchForm.competitionId;
|
||||
}
|
||||
|
||||
getParticipantList(null, this.pagination.current, this.pagination.size, params)
|
||||
.then(res => {
|
||||
console.log('参赛人员列表返回数据:', res);
|
||||
const responseData = res.data?.data;
|
||||
if (responseData && responseData.records) {
|
||||
this.participantList = responseData.records;
|
||||
this.pagination.total = responseData.total || 0;
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('加载参赛人员列表失败', err);
|
||||
this.$message.error('加载参赛人员列表失败');
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
|
||||
loadParticipantData() {
|
||||
if (!this.participantId) return;
|
||||
|
||||
this.loading = true;
|
||||
getParticipantDetail(this.participantId)
|
||||
.then(res => {
|
||||
const detailData = res.data?.data;
|
||||
if (detailData) {
|
||||
this.formData = { ...detailData };
|
||||
|
||||
// 将 attachments 字符串转换为数组(前端需要数组格式)
|
||||
if (typeof this.formData.attachments === 'string') {
|
||||
try {
|
||||
this.formData.attachments = JSON.parse(this.formData.attachments);
|
||||
} catch (e) {
|
||||
console.warn('解析 attachments 失败,使用空数组', e);
|
||||
this.formData.attachments = [];
|
||||
}
|
||||
} else if (!this.formData.attachments) {
|
||||
this.formData.attachments = [];
|
||||
}
|
||||
|
||||
// 加载该赛事的项目列表
|
||||
if (detailData.competitionId) {
|
||||
this.loadProjectsByCompetition(detailData.competitionId);
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('加载参赛人员详情失败', err);
|
||||
this.$message.error('加载参赛人员详情失败');
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
|
||||
handlePageChange(current) {
|
||||
this.pagination.current = current;
|
||||
this.loadParticipantList();
|
||||
},
|
||||
|
||||
handleSizeChange(size) {
|
||||
this.pagination.size = size;
|
||||
this.pagination.current = 1;
|
||||
this.loadParticipantList();
|
||||
},
|
||||
|
||||
handleSearch() {
|
||||
this.pagination.current = 1;
|
||||
this.loadParticipantList();
|
||||
},
|
||||
|
||||
handleReset() {
|
||||
this.searchForm = {
|
||||
keyword: '',
|
||||
competitionId: null
|
||||
};
|
||||
this.pagination.current = 1;
|
||||
this.loadParticipantList();
|
||||
},
|
||||
|
||||
handleCreate() {
|
||||
this.$router.push({
|
||||
path: '/martial/participant/list',
|
||||
query: { mode: 'create' }
|
||||
});
|
||||
},
|
||||
|
||||
handleView(row) {
|
||||
this.$router.push({
|
||||
path: '/martial/participant/list',
|
||||
query: { mode: 'view', id: row.id }
|
||||
});
|
||||
},
|
||||
|
||||
handleEdit(row) {
|
||||
this.$router.push({
|
||||
path: '/martial/participant/list',
|
||||
query: { mode: 'edit', id: row.id }
|
||||
});
|
||||
},
|
||||
|
||||
switchToEdit() {
|
||||
this.$router.push({
|
||||
path: '/martial/participant/list',
|
||||
query: { mode: 'edit', id: this.participantId }
|
||||
});
|
||||
},
|
||||
|
||||
handleDelete(row) {
|
||||
this.$confirm('确定要删除该选手吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.loading = true;
|
||||
removeParticipant(row.id.toString())
|
||||
.then(res => {
|
||||
this.$message.success('删除成功');
|
||||
this.loadParticipantList();
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('删除失败', err);
|
||||
this.$message.error('删除失败');
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
}).catch(() => {});
|
||||
},
|
||||
|
||||
handleCompetitionChange(competitionId) {
|
||||
// 从可用的选项列表中查找赛事
|
||||
const competition = this.availableCompetitionOptions.find(item => item.id === competitionId);
|
||||
if (competition) {
|
||||
this.formData.competitionName = competition.competitionName;
|
||||
}
|
||||
// 加载该赛事的项目列表
|
||||
this.loadProjectsByCompetition(competitionId);
|
||||
// 清空已选项目
|
||||
this.formData.projectId = null;
|
||||
},
|
||||
|
||||
handleProjectChange(projectId) {
|
||||
const project = this.projectOptions.find(item => item.id === projectId);
|
||||
if (project) {
|
||||
// 自动填充组别信息
|
||||
if (project.category && !this.formData.category) {
|
||||
this.formData.category = project.category;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
loadProjectsByCompetition(competitionId) {
|
||||
if (!competitionId) {
|
||||
this.projectOptions = [];
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('加载赛事项目,赛事ID:', competitionId);
|
||||
|
||||
getProjectsByCompetition(competitionId)
|
||||
.then(res => {
|
||||
console.log('项目列表返回数据:', res);
|
||||
const responseData = res.data?.data;
|
||||
|
||||
// 兼容两种数据格式:分页数据(有records)和直接数组
|
||||
let projectList = [];
|
||||
if (responseData) {
|
||||
if (Array.isArray(responseData)) {
|
||||
// 直接是数组
|
||||
projectList = responseData;
|
||||
console.log('返回的是直接数组,长度:', projectList.length);
|
||||
} else if (responseData.records && Array.isArray(responseData.records)) {
|
||||
// 分页数据
|
||||
projectList = responseData.records;
|
||||
console.log('返回的是分页数据,记录数:', projectList.length);
|
||||
} else {
|
||||
console.warn('未知的数据格式:', responseData);
|
||||
}
|
||||
}
|
||||
|
||||
if (projectList.length > 0) {
|
||||
this.projectOptions = projectList.map(item => ({
|
||||
id: item.id,
|
||||
projectName: item.projectName,
|
||||
projectCode: item.projectCode,
|
||||
category: item.category
|
||||
}));
|
||||
console.log('可选项目列表:', this.projectOptions);
|
||||
} else {
|
||||
this.projectOptions = [];
|
||||
console.log('该赛事没有项目数据');
|
||||
this.$message.warning('该赛事还没有配置项目,请先添加项目');
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('加载项目列表失败', err);
|
||||
this.$message.error('加载项目列表失败: ' + (err.message || '未知错误'));
|
||||
this.projectOptions = [];
|
||||
});
|
||||
},
|
||||
|
||||
handleSave() {
|
||||
this.$refs.formRef.validate((valid) => {
|
||||
if (valid) {
|
||||
this.loading = true;
|
||||
|
||||
// 确保有赛事名称
|
||||
if (!this.formData.competitionName) {
|
||||
const competition = this.availableCompetitionOptions.find(item => item.id === this.formData.competitionId);
|
||||
if (competition) {
|
||||
this.formData.competitionName = competition.competitionName;
|
||||
}
|
||||
}
|
||||
|
||||
const submitData = { ...this.formData };
|
||||
|
||||
console.log('=== 提交前的 formData ===', this.formData);
|
||||
console.log('formData.orderId:', this.formData.orderId);
|
||||
|
||||
// 将 attachments 数组转换为 JSON 字符串(后端需要 String 类型)
|
||||
if (Array.isArray(submitData.attachments)) {
|
||||
submitData.attachments = JSON.stringify(submitData.attachments);
|
||||
}
|
||||
|
||||
// 临时方案: 如果没有 orderId,使用 competitionId 作为 orderId
|
||||
// 警告: 这是临时解决方案,后续应修改数据库表结构或后端逻辑
|
||||
if (!submitData.orderId && submitData.competitionId) {
|
||||
submitData.orderId = submitData.competitionId;
|
||||
console.warn('⚠️ 临时方案: 使用 competitionId 作为 orderId', submitData.competitionId);
|
||||
}
|
||||
|
||||
console.log('=== 提交的数据 submitData ===', submitData);
|
||||
console.log('submitData.orderId:', submitData.orderId);
|
||||
|
||||
if (this.currentView === 'create') {
|
||||
// 新建
|
||||
addParticipant(submitData)
|
||||
.then(res => {
|
||||
this.$message.success('添加成功');
|
||||
this.backToList();
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('添加失败', err);
|
||||
this.$message.error('添加失败');
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
} else if (this.currentView === 'edit') {
|
||||
// 编辑
|
||||
submitData.id = this.participantId;
|
||||
updateParticipant(submitData)
|
||||
.then(res => {
|
||||
this.$message.success('保存成功');
|
||||
this.backToList();
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('保存失败', err);
|
||||
this.$message.error('保存失败');
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
this.$message.error('请完善必填信息');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
backToList() {
|
||||
this.$router.push({
|
||||
path: '/martial/participant/list'
|
||||
});
|
||||
},
|
||||
|
||||
resetFormData() {
|
||||
this.formData = {
|
||||
orderId: null,
|
||||
competitionId: null,
|
||||
competitionName: '',
|
||||
playerName: '',
|
||||
gender: 1,
|
||||
age: null,
|
||||
contactPhone: '',
|
||||
organization: '',
|
||||
idCard: '',
|
||||
projectId: null,
|
||||
category: '',
|
||||
orderNum: 1,
|
||||
introduction: '',
|
||||
remark: '',
|
||||
attachments: []
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.participant-container {
|
||||
padding: 20px;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
min-height: calc(100vh - 120px);
|
||||
}
|
||||
|
||||
.list-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 20px;
|
||||
border-bottom: 2px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.search-form {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.data-table {
|
||||
:deep(.el-table__header) {
|
||||
th {
|
||||
background-color: #fafafa;
|
||||
color: #333;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-button--text) {
|
||||
padding: 0 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.page-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
margin-bottom: 30px;
|
||||
padding-bottom: 20px;
|
||||
border-bottom: 2px solid #f0f0f0;
|
||||
|
||||
.page-title {
|
||||
flex: 1;
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.participant-form {
|
||||
max-width: 1200px;
|
||||
}
|
||||
|
||||
.form-section {
|
||||
margin-bottom: 30px;
|
||||
padding: 20px;
|
||||
background: #fafafa;
|
||||
border-radius: 8px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.section-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-bottom: 20px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
|
||||
i {
|
||||
color: #dc2626;
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
</style>
|
||||
@@ -380,7 +380,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 } from '@/api/martial/activitySchedule'
|
||||
import { getScheduleResult, saveAndLockSchedule, saveDraftSchedule, triggerAutoArrange, moveScheduleGroup, exportSchedule } from '@/api/martial/activitySchedule'
|
||||
|
||||
export default {
|
||||
name: 'MartialScheduleList',
|
||||
@@ -1113,8 +1113,23 @@ export default {
|
||||
group.items.splice(itemIndex + 1, 0, temp)
|
||||
this.$message.success('下移成功')
|
||||
},
|
||||
handleExport() {
|
||||
this.$message.success('导出功能开发中')
|
||||
async handleExport() {
|
||||
try {
|
||||
this.loading = true
|
||||
const res = await exportSchedule(this.competitionId)
|
||||
const blob = new Blob([res], { type: 'application/vnd.ms-excel' })
|
||||
const link = document.createElement('a')
|
||||
link.href = window.URL.createObjectURL(blob)
|
||||
link.download = `赛程表_${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
|
||||
}
|
||||
},
|
||||
handleConfirm() {
|
||||
this.confirmDialogVisible = true
|
||||
|
||||
1019
src/views/martial/schedule/index.vue.bak
Normal file
1019
src/views/martial/schedule/index.vue.bak
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user