You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

627 lines
25 KiB

<template>
<div style="padding: 0 100px;">
<el-card shadow="hover" class="m-b-20 head-card">
<div class="flex-between">
<el-page-header @back="$router.back()" content="参赛信息与成绩"></el-page-header>
</div>
</el-card>
<el-card shadow="hover" class="m-b-20">
<div style="display: flex;align-items: center">
<table v-if="form.completeCompetitionSetup.competitionType" class="table m-b-20 m-r-10">
<tr>
<th width="150">团队名称:</th>
<td>
<el-input :disabled="!editing" v-model="info.team.teamName"></el-input>
</td>
<th width="150">团队邀请码:</th>
<td>
<el-input :disabled="!editing" v-model="info.team.invitationCode"></el-input>
</td>
</tr>
</table>
<div v-if="form.completeCompetitionSetup.competitionType && status < 4" class="m-b-20 text-center">
<el-button type="primary" @click="edit(1)">{{ editing ? '保存' : '编辑' }}</el-button>
</div>
</div>
<table class="table">
<template v-if="form.completeCompetitionSetup.competitionType === 0">
<tr>
<th width="150">姓名:</th>
<td>{{ info.person.userName }}</td>
</tr>
<tr>
<th>学号:</th>
<td>{{ info.person.workNumber }}</td>
</tr>
<tr>
<th>学校:</th>
<td>{{ info.person.schoolName }}</td>
</tr>
</template>
<template v-if="form.completeCompetitionSetup.competitionType">
<template>
<tr>
<th>队长:</th>
<td>{{ info.caption.userName }}{{ info.caption.schoolName && ',' + info.caption.schoolName }}{{ info.caption.workNumber && ',' + info.caption.workNumber }}</td>
</tr>
<tr>
<th>团队成员:</th>
<td>
<el-tag v-for="(item, i) in info.teamDetail" :key="i" style="margin-right: 5px">{{ item.userName }}</el-tag>
</td>
</tr>
</template>
</template>
<tr>
<th width="130">指导老师:</th>
<td>
<div v-if="status < 5" class="plus">
<i class="el-icon-circle-plus-outline icon" @click="addAdvisor"></i>
</div>
<div v-for="(item, i) in info.teamInstructors" :key="i" class="line">
<el-input placeholder="请输入姓名" v-model="item.name" clearable size="mini" :disabled="!item.edit"></el-input>
<el-input placeholder="请输入职务" maxlength="10" v-model="item.position" clearable size="mini" :disabled="!item.edit"></el-input>
<el-input placeholder="请输入手机号" maxlength="11" v-model="item.phone" clearable size="mini" :disabled="!item.edit"></el-input>
<template v-if="status < 5">
<i v-if="item.edit" class="el-icon-check icon" @click="submitAdvisor(item)"></i>
<i v-else class="el-icon-edit icon" @click="editAdvisor(item)"></i>
<i class="el-icon-delete icon" @click="delAdvisor(item, i)"></i>
</template>
</div>
</td>
</tr>
<tr>
<th>竞赛阶段:</th>
<td>
<table class="table tc">
<tr>
<th width="80">序号</th>
<th>赛项阶段名称</th>
<template v-if="form.completeCompetitionSetup.competitionType">
<th width="110">参赛人数限制</th>
<th>允许参赛人员</th>
<th v-if="form.rule === 0">总分</th>
</template>
<th>竞赛成绩</th>
</tr>
<template v-if="info.stages.length">
<tr v-for="(item, i) in info.stages" :key="i">
<td>{{ i + 1 }}</td>
<td>{{ item.stageName }}</td>
<template v-if="form.completeCompetitionSetup.competitionType">
<td>{{ item.teamNumLimit || '不限制' }}</td>
<td>
<template v-if="item.participants">
<el-tag
v-for="tag in item.participants"
:key="tag.name"
class="m-r-5"
closable
@close="removePar(tag, item)">
{{tag.name}}
</el-tag>
</template>
<span v-else class="m-r-5">无</span>
<i class="el-icon-edit icon" @click="selectPar(item)"></i>
</td>
<td v-if="form.rule === 0 && !i" :rowspan="info.stages.length">{{ info.totalScore }}</td>
</template>
<td>
<span v-if="item.score > 0" class="m-r-10">分数{{item.score}}</span>
<el-button type="text" :disabled="item.resultsDetails === 1 || (form.completeCompetitionSetup.competitionType && !item.reportId) || (form.completeCompetitionSetup.competitionType === 0 && !item.reportId)" @click="show(item)">查看成绩详情</el-button>
</td>
</tr>
</template>
<tr v-else>
<td colspan="6">暂无数据</td>
</tr>
</table>
<el-alert
v-if="form.completeCompetitionSetup.competitionType"
style="margin-top: 10px;"
:title="'注:请团长(团队创建人)设置各阶段参赛成员,只有被选择的允许参赛成员可进入对应阶段比赛' + (info.teamLimit ? ',每个团队成员只能参加一个赛项阶段' : '') + '!'"
type="warning"
show-icon>
</el-alert>
</td>
</tr>
</table>
<template v-if="form.completeCompetitionSetup.competitionType">
<div class="l-title m-t-20">团队成员</div>
<div class="flex-center">
<p>队长:{{ info.caption.userName }}</p>
<el-button type="primary" @click="transfer">转让队长</el-button>
</div>
<el-table :data="info.teamDetail" stripe header-align="center">
<el-table-column prop="userName" label="成员姓名" min-width="100" align="center"></el-table-column>
<el-table-column prop="schoolName" label="学校" min-width="100" align="center"></el-table-column>
<el-table-column prop="workNumber" label="学号" min-width="100" align="center"></el-table-column>
<el-table-column prop="createTime" label="加入时间" width="180" align="center"></el-table-column>
<el-table-column label="操作" align="center" width="160">
<template slot-scope="scope">
<el-button v-if="scope.row.captain" type="text" @click="removeLine(scope.row)">踢出团队</el-button>
</template>
</el-table-column>
</el-table>
</template>
</el-card>
<el-dialog title="选择参赛成员" :visible.sync="transferVisible" :close-on-click-modal="false" width="400px">
<template v-for="(item, i) in info.teamDetail">
<el-radio v-if="item.captain" :key="i" v-model="checkedPlayer" :label="item.teamId">{{ item.userName }}</el-radio>
</template>
<span slot="footer" class="dialog-footer">
<el-button size="small" type="primary" @click="transferSubmit">确定</el-button>
<el-button size="small" @click="transferVisible = false">取消</el-button>
</span>
</el-dialog>
<el-dialog title="选择参赛成员" :visible.sync="chooseVisible" :close-on-click-modal="false" width="400px">
<el-checkbox-group v-model="checkedMembers">
<el-checkbox v-for="(item, i) in chooses" :key="i" :label="item.accountId">{{ item.userName }}</el-checkbox>
</el-checkbox-group>
<p v-if="info.teamLimit && curRow.teamNumLimit" style="margin-top: 15px;font-size: 12px;">注:当前阶段限制{{ curRow.teamNumLimit }}人参赛,且此竞赛每个成员只能参加一个阶段赛项。</p>
<span slot="footer" class="dialog-footer">
<el-button size="small" type="primary" @click="chooseSubmit">确定</el-button>
<el-button size="small" @click="chooseVisible = false">取消</el-button>
</span>
</el-dialog>
<el-dialog title="团队得分详情" :visible.sync="memberVisible" width="900px" :close-on-click-modal="false">
<h6 v-if="members.length" style="margin-bottom: 10px;font-size: 16px;">团队名称:{{ members[0].teamName }} 阶段名称:{{ curRow.stageName }}</h6>
<table class="table tc">
<tr>
<th width="60">序号</th>
<th width="100">姓名</th>
<th width="100">学校</th>
<th width="100">用时</th>
<th width="100">分数</th>
<th width="100">得分详情</th>
</tr>
<template v-if="members.length">
<tr v-for="(item, i) in members" :key="i">
<td>{{ i + 1 }}</td>
<td>{{ item.userName }}</td>
<td>{{ item.schoolName }}</td>
<td>{{ item.timeSum }}min</td>
<td>{{ item.score }}</td>
<td>
<el-button type="text" @click="toReport(item)">查看</el-button>
</td>
</tr>
</template>
<tr v-else>
<td colspan="6">暂无数据</td>
</tr>
</table>
<span slot="footer" class="dialog-footer">
<el-button size="small" type="primary" @click="memberVisible = false">确定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import Setting from "@/setting";
import util from "@/libs/util";
export default {
data() {
return {
id: +this.$route.query.id,
accountId: +this.$route.query.accountId,
status: 5,
form: {
competitionStage: [],
completeCompetitionSetup: {},
competitionRegistration: {}
},
info: {
isCaption: 0,
person: {},
caption: {},
team: {
captain: 1,
invitationCode: ''
},
stages: [],
teamDetail: [],
teamInstructors: []
},
memberVisible: false,
members: [],
curRow: {},
teamVisible: false,
teams: [],
teamNameRepeat: false,
teamForm: {
accountId: +this.$route.query.accountId,
identification: 1,
competitionId: this.$route.query.id,
registrationInvitationCode: '',
teamName: '',
invitationCode: '',
whetherSignUp: 1
},
curStage: null,
originInfo: {},
originIns: {
position: '',
name: '',
phone: '',
},
checkedPlayer: '',
transferVisible: false,
editing: false,
memberVisible: false,
members: [],
curRow: {},
chooseVisible: false,
checkedMember: '',
checkedMembers: [],
chooses: [],
timerList: [],
timer: null
};
},
mounted() {
this.$once('hook:beforeDestroy', function() {
clearInterval(this.timer)
this.timerList.forEach(n => {
clearInterval(n)
})
this.timerList = []
})
this.getData()
},
methods: {
getData() {
this.$post(`${this.api.getCompetition}?competitionId=${this.id}`).then(({ competition }) => {
this.form = competition
this.timer = setInterval(this.handleStatus, 1000)
this.getInfo()
}).catch(err => {})
},
// 获取竞赛信息
getInfo() {
this.$post(`${this.api.entryInformation}?competitionId=${this.id}&accountId=${this.accountId}`).then(res => {
const info = res.entryInformation
// 如果是队长,并且没有指导老师,默认添加一个空的
if (!info.teamInstructors.length) info.teamInstructors.push(JSON.parse(JSON.stringify(this.originIns)))
if (info.personalDetail) {
info.team = {}
info.teamDetail = []
} else {
info.isCaption = info.team.caption
}
const caption = info.teamDetail.find(e => !e.caption)
info.caption = caption ? caption : {}
info.person = info.personalDetail || info.teamDetail.find(e => e.accountId == info.team.accountId)
this.originInfo = JSON.parse(JSON.stringify(info))
// 把参赛人员的名字和accountId处理成一个数组
info.stages && info.stages.map(e => {
if (e.participantAccountIds && e.teamParticipantIds) {
const accountIds = e.participantAccountIds.split(',').map(n => +n)
const names = e.teamParticipantIds.split(',')
const participants = []
accountIds.map((n, i) => {
participants.push({
id: n,
name: names[i]
})
})
e.participants = participants
}
})
// 设置定时器,阶段比赛结束后公布成绩,到时间后调本接口
const now = Date.now()
this.form.competitionStage.map(e => {
// 如果公布成绩详情勾选的是
if (!e.resultsDetails) {
const endTime = new Date(e.endTime).getTime() + e.resultAnnouncementTime * 3600000 // 阶段结束时间+成绩公布时间(成绩公布时间单位是小时,所以要转化为毫秒)
if (now > endTime) { // 如果到了公布时间
info.stages.find(n => n.stageId == e.stageId).showDetail = 1
} else { // 没有到公布时间,则加定时器,到点后调用
this.timerList.push(setTimeout(this.getInfo, endTime - now))
}
}
})
this.info = info
}).catch(err => {});
},
// 报名时间、比赛时间、状态处理
handleStatus() {
let status
const n = this.form
let now = new Date().getTime();
let signUpStartTime = new Date(this.dateCompatible(n.signUpStartTime)).getTime(); // 报名开始时间
let signUpEndTime = new Date(this.dateCompatible(n.signUpEndTime)).getTime(); // 报名结束时间
let playStartTime = new Date(this.dateCompatible(n.playStartTime)).getTime(); // 比赛开始时间
let playEndTime = new Date(this.dateCompatible(n.playEndTime)).getTime(); // 比赛结束时间
if (now < signUpStartTime) { // 报名没开始
status = 0;
} else if (now > signUpStartTime && now < signUpEndTime) { // 报名进行中
status = n.competitionRegistration ? 1 : 2 // 1已报名,2立即报名
} else if (now > signUpEndTime && now < playStartTime) { // 报名结束了,但比赛没开始
status = 3;
} else if (now > playStartTime && now < playEndTime) { // 比赛进行中
status = 4
} else if (now > playEndTime) { // 比赛结束
status = 5;
}
this.status = status
},
// 编辑保存
edit(showMsg) {
if (this.editing || !showMsg) {
const { teamId, teamName, invitationCode } = this.info.team
this.$post(this.api.editCompetitionTeam, {
accountId: this.accountId,
identification: 1,
competitionId: this.id,
teamId,
teamName,
invitationCode,
whetherSignUp: 0
}).then(res => {
this.editing = false
this.getInfo()
showMsg && util.successMsg('保存成功')
}).catch(res => {})
} else {
this.editing = !this.editing
}
},
// 删除指导老师
delAdvisor(row, i) {
if (row.id) {
this.$confirm('确定要删除吗?', '提示', {
type: 'warning'
}).then(() => {
this.$post(`${this.api.deleteAnAdvisor}?id=${row.id}`).then(res => {
util.successMsg('删除成功')
this.getInfo()
}).catch(res => {})
}).catch(() => {})
} else {
this.info.teamInstructors.splice(i, 1)
}
},
// 添加指导老师
addAdvisor() {
if (this.info.teamInstructors.length > 4) return util.errorMsg('指导老师仅限添加5个!')
this.info.teamInstructors.push(JSON.parse(JSON.stringify(this.originIns)))
},
// 编辑导老师
editAdvisor(row) {
this.$set(row, 'edit', 1)
},
// 提交指导老师
submitAdvisor(row) {
if (!row.name) return util.errorMsg('请输入姓名')
const { phone } = row
if (phone && !/^1[3456789]\d{9}$/.test(phone)) return util.errorMsg('请输入正确手机号格式')
this.$post(this.api.addAnAdvisor, {
name: row.name,
competitionId: this.id,
id: row.id,
teamId: this.info.teamId,
phone: row.phone,
position: row.position,
}).then(res => {
util.successMsg((row.id ? '修改' : '新增') + '成功')
this.getInfo()
}).catch(res => {})
},
// 显示转让队长
transfer() {
// 取每个阶段的开始结束时间,有任何阶段开始了都不能转让队长和踢出队员
const now = new Date()
let start = 0
for (const e of this.form.competitionStage) {
if (now >= new Date(e.startTime) && now <= new Date(e.endTime)) {
util.errorMsg('比赛已经开始,无法转让队长!')
start = 1
break
}
}
if (!start) this.transferVisible = true
},
// 转让队长提交
transferSubmit() {
if (!this.checkedPlayer) return util.errorMsg('请选择成员')
this.$post(this.api.captainOfTransfer, {
captainId: this.info.caption.teamId,
playerId: this.checkedPlayer
}).then(res => {
this.checkedPlayer = ''
util.successMsg('转让成功')
this.transferVisible = false
this.getInfo()
}).catch(res => {})
},
// 踢出团队
removeLine(row) {
// 取每个阶段的开始结束时间,有任何阶段开始了都不能转让队长和踢出队员
const now = new Date()
let start = 0
for (const e of this.form.competitionStage) {
if (now >= new Date(e.startTime) && now <= new Date(e.endTime)) {
util.errorMsg('比赛已经开始,无法踢出成员!')
start = 1
break
}
}
if (!start) {
let include
for (const e of this.info.stages) {
if (e.participantAccountIds) {
const ids = e.participantAccountIds.split(',').map(n => +n)
if (ids.includes(row.accountId)) {
include = e.stageName
break
}
}
}
this.$confirm(include ? `该成员已被指定参加${include},踢出后需重新指定成员参加,是否确认踢出团队?` : '确定要踢出该成员吗?', '提示', {
type: 'warning'
}).then(() => {
this.$post(`${this.api.removeTheLine}?teamId=${this.info.teamId}&competitionId=${this.id}&accountId=${row.accountId}`).then(res => {
util.successMsg('移除成功')
this.getInfo()
}).catch(res => {})
}).catch(() => {})
}
},
// 移除参赛人员
removePar(e, stage) {
this.$confirm('确定要移除该成员吗?', '提示', {
type: 'warning'
}).then(() => {
this.$post(this.api.cancelParticipant, {
accountId: e.id,
competitionId: this.id,
stageId: stage.stageId,
teamId: this.info.teamId
}).then(res => {
util.successMsg('移除成功')
this.getInfo()
}).catch(res => {})
}).catch(() => {})
},
// 选择参赛人员
selectPar(row) {
const item = this.form.competitionStage.find(e => e.stageId == row.stageId)
if (item) {
// 该阶段已经开始比赛则不能修改
const now = new Date()
if (now >= new Date(item.startTime) && now <= new Date(item.endTime)) {
return util.errorMsg('该阶段比赛已经开始,无法修改允许参赛人员!')
} else {
const { teamLimit, stages, teamDetail } = this.info
// teamLimit=true,则每个成员只能参加一个阶段的比赛,要获取stages里返回的所有participantAccountIds(参赛人员的accountId),然后不显示这些参赛人员
if (teamLimit) {
const chooses = []
let ids = []
// 获取已经允许参赛的人员accountId
stages.map(e => {
let id = e.participantAccountIds
if (e.stageId != row.stageId && id) ids.push(...id.split(',').map(n => +n))
})
ids = [...new Set(ids)]
teamDetail.map(e => {
ids.includes(e.accountId) || chooses.push(e) // 没有参赛的人员则显示出来
})
this.chooses = chooses
} else {
this.chooses = this.info.teamDetail
}
this.curRow = row
this.checkedMembers = []
this.chooseVisible = true
}
}
},
// 选择参赛人员提交
chooseSubmit() {
const accountIds = this.checkedMembers
if (!accountIds.length) return util.errorMsg('请选择参赛成员!')
const limit = this.curRow.teamNumLimit // 参赛人数限制
if (limit && accountIds.length > limit) return util.errorMsg(`请选择${limit}个以下参赛成员!`) // 选择的参赛人员个数不能大于参赛人数限制
this.$post(this.api.stageSelectParticipants, {
accountIds,
competitionId: this.id,
stageId: this.curRow.stageId,
teamId: this.info.teamId
}).then(res => {
this.checkedMembers = []
util.successMsg('修改成功')
this.getInfo()
this.chooseVisible = false
}).catch(res => {})
},
// 查看成绩详情
show(row) {
// 团队展示弹框,个人跳转实验报告
if (this.form.completeCompetitionSetup.competitionType) { // 团队比赛并且是队长,则展示团队成员成绩详情
this.curRow = row
this.memberVisible = true
const teamId = this.info.teamId
if (teamId) {
this.$post(this.api.stageGradeManagementList, {
pageNum: 1,
pageSize: 1000,
competitionId: this.id,
stageId: row.stageId,
isNakadai: 0
}).then(({ page }) => {
this.members = page.records.filter(e => e.teamId === teamId)
}).catch(res => {})
} else {
this.members = []
}
} else if (row.reportId) { // 团员或者个人比赛,并且有reportId,则进入实验报告
this.toReport(row)
}
},
// 跳转实验报告
toReport(row) {
this.$router.push(`/matchReport?reportId=${row.reportId}`)
},
}
};
</script>
<style lang="scss" scoped>
.m-r-5 {
margin-right: 5px;
}
.l-title {
margin-top: 20px;
font-size: 18px;
}
.table {
width: 100%;
border-collapse: collapse;
th, td {
padding: 12px;
border: 1px solid #ebeef5;
}
&.tc {
text-align: center;
}
th {
text-align: center;
background-color: #f8faff;
}
.icon {
margin-right: 10px;
font-size: 16px;
color: #7a7a7a;
cursor: pointer;
&:hover {
color: #007EFF;
}
}
.plus {
margin-bottom: 10px;
text-align: right;
}
.line {
display: flex;
align-items: center;
margin-bottom: 10px;
.el-input {
margin-right: 15px;
}
}
}
.flex-center {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
}
.text-center {
text-align: center;
}
</style>