<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> </template> <th v-if="form.rule === 0">总分</th> <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> </template> <td v-if="form.rule === 0 && !i" :rowspan="info.stages.length">{{ info.totalScore }}</td> <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 => { clearTimeout(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 if (endTime - now < 86400000) { // 没有到公布时间,则加定时器,到点后调用 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(util.dateCompatible(n.signUpStartTime)).getTime(); // 报名开始时间 let signUpEndTime = new Date(util.dateCompatible(n.signUpEndTime)).getTime(); // 报名结束时间 let playStartTime = new Date(util.dateCompatible(n.playStartTime)).getTime(); // 比赛开始时间 let playEndTime = new Date(util.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 console.log("🚀 ~ file: matchInfo.vue:350 ~ handleStatus ~ 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 () { 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 { teamLimit, stages, teamDetail } = this.info // teamLimit=true,则每个成员只能参加一个阶段的比赛,要获取stages里返回的所有participantAccountIds(参赛人员的accountId),然后不显示这些参赛人员 if (teamLimit) { const chooses = [] let ids = [] // 获取已经允许参赛的人员accountId stages.map(e => { const 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.frontOfficeCompetitionRanking, { pageNum: 1, pageSize: 1000, competitionId: this.id, isOverallRanking: 0, teamId }).then(({ list }) => { this.members = list }).catch(res => { }) } else { this.members = [] } } else if (row.reportId) { // 团员或者个人比赛,并且有reportId,则进入实验报告 this.toReport(row) } }, // 跳转实验报告 toReport (row) { this.$router.push(`/match/report?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>