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.
 
 
 
 
 

525 lines
22 KiB

<template>
<div>
<div class="page">
<div class="page-content">
<div class="p-title">赛程与规则设置</div>
<el-form :model="form" :rules="validRules" label-width="170px" label-suffix=":" size="small"
:disabled="!!(!editing && id)">
<el-form-item label="竞赛类型">
{{ step1.completeCompetitionSetup.competitionType ? '团队赛(' + step1.completeCompetitionSetup.minTeamSize +
'-' + step1.completeCompetitionSetup.maxTeamSize + '人/队)' : '个人赛' }} <span
class="tips">如需修改请返回上一步</span>
</el-form-item>
<el-form-item prop="rule" label="赛制">
<el-radio v-for="(rule, i) in rules" :key="i" v-model="form.rule" :label="rule.id">{{ rule.name
}}</el-radio>
<p class="tips">积分赛——包含多个竞赛阶段,每个阶段的成绩都包含在最终总成绩里,最后一轮结束后总成绩排名靠前的参赛者得到获奖资格。</p>
<p class="tips">淘汰赛——包含多个竞赛阶段,每个阶段结束后之后只有部分参赛者能晋级下一阶段,晋级最后一轮且在最后一轮排名靠前的参赛者得到获奖资格。</p>
<p class="tips">单项赛——仅包含一个竞赛阶段,单项的成绩排名即为最终排名,排名靠前的参赛者得到获奖资格。</p>
<p class="tips">注:系统默认排名规则,优先按分数排名(分数高则排名靠前),分数相同则按用时排名(用时短则排名靠前)。</p>
</el-form-item>
<template v-if="form.rule !== 2">
<el-form-item prop="stageNum" label="阶段数量">
<div class="input-center">
<el-select v-model="form.stageNum" @change="stageChange">
<el-option v-for="i in 10" :key="i" :label="i" :value="i"></el-option>
</el-select>
</div>
<div v-if="step1.completeCompetitionSetup.competitionType" class="tips">
(团队赛是否限制队内每个成员只能参加一个阶段赛项?
<el-radio v-model="form.teamLimit" :label="1">是</el-radio>
<el-radio v-model="form.teamLimit" :label="0">否</el-radio>
)
</div>
</el-form-item>
<el-form-item v-if="!form.rule" prop="resultCalculationMethod" label="总成绩计算方式">
<el-radio v-model="form.resultCalculationMethod" :label="0">各阶段成绩加权求和</el-radio>
<el-radio v-model="form.resultCalculationMethod" :label="1">各阶段成绩直接求和</el-radio>
<el-radio v-model="form.resultCalculationMethod" :label="2">各阶段成绩取平均值</el-radio>
<p class="tips">(若选择加权求和,则需要设置每个阶段成绩所占权重,且权重总和须为100%)</p>
</el-form-item>
<el-form-item prop="stageNum" label="阶段设置">
<div v-for="(item, i) in form.competitionStageList" :key="i" class="step-set">
<div class="line">
第{{ serials[i] }}阶段 <el-input v-model="item.stageName" clearable placeholder="请输入阶段名称,如“初赛”"
style="width: 200px"></el-input>
</div>
<div class="line">
<span class="req">*</span>
比赛方式:
<el-radio v-for="(method, i) in methods" :key="i" v-model="item.method" :label="method.id">{{
method.name }}</el-radio>
</div>
<div v-if="step1.completeCompetitionSetup.competitionType" class="line">
<span class="req">*</span>
团队参赛人数限制:
<el-radio v-model="item.teamNumLimit" :label="0">不限制</el-radio>
<el-radio v-model="item.teamNumLimit" :label="1">自定义</el-radio>
<el-input v-model.number="item.customNumber" type="number" min="0" style="width: 150px;"
:disabled="item.teamNumLimit === 0"></el-input> 人
<span class="tips">(可限制本阶段单个团队的出战人数)</span>
</div>
<div v-if="step1.completeCompetitionSetup.competitionType" class="line">
<span class="req">*</span>
团队成绩计算方式:
<el-radio v-for="(j, i) in teamCalculationMethods" :key="i" v-model="item.teamCalculationMethod"
:label="j.id">{{ j.name }}</el-radio>
<span class="tips">(可设置本阶段的团队取分规则)</span>
</div>
<div v-if="form.rule === 1 && i !== form.competitionStageList.length - 1" class="line"
style="display: flex;">
<p>
<span class="req">*</span>晋级规则:
</p>
<div>
<div class="line">
本阶段成绩排名前
<el-input v-model.number="item.peopleLimit" type="number" min="0" style="width: 100px"></el-input>
队,可晋级下一阶段比赛
</div>
<div class="line">
本阶段成绩排名前
<el-input v-model.number="item.percentageLimit" type="number" min="0"
style="width: 100px"></el-input>
%,可晋级下一阶段比赛
</div>
<div>
本阶段成绩
<el-select v-model="item.operator" style="width: 80px;margin-right: 10px">
<el-option v-for="i in operators" :key="i" :label="i" :value="i"></el-option>
</el-select>
<el-input v-model="item.score" type="number" min="0" style="width: 100px"></el-input>
分,可晋级下一阶段比赛
</div>
</div>
</div>
<div v-if="!form.rule" class="line">
<span class="req">*</span>
占总成绩权重:
<el-input v-model.number="item.pointWeight" type="number" min="0"
:disabled="form.resultCalculationMethod != 0" style="width: 150px;"></el-input> %
</div>
<div class="line">
成绩公布时间:
(阶段)比赛结束后
<el-input v-model.number="item.resultAnnouncementTime" type="number" min="0"
style="width: 120px"></el-input>
小时,公布(阶段)比赛成绩。(为空则不公布成绩,为0则阶段比赛结束后立马公布成绩)
</div>
<div
v-if="item.resultAnnouncementTime !== '' && item.resultAnnouncementTime !== null && item.resultAnnouncementTime !== undefined"
class="line">
是否公布成绩详情:
<el-radio v-model="item.resultsDetails" :label="0">是</el-radio>
<el-radio v-model="item.resultsDetails" :label="1">否</el-radio>
<p class="tips">若选择“是”,则公布成绩详情,竞赛结束后参赛者可查看自己的比赛成绩得分详情;</p>
<p class="tips">若选择“否”,则不公布成绩详情,参赛者只能知晓自己的分数及排名,不能查看得分详情。</p>
</div>
</div>
</el-form-item>
</template>
<template v-else>
<el-form-item prop="stageNum" label="规则设置">
<div class="step-set">
<div class="line">
<span class="req">*</span>
比赛方式:
<el-radio v-for="(method, i) in methods" :key="i" v-model="form.competitionStageList[0].method"
:label="method.id">{{ method.name }}</el-radio>
</div>
<div v-if="step1.completeCompetitionSetup.competitionType" class="line">
<span class="req">*</span>
团队成绩计算方式:
<el-radio v-for="(j, i) in teamCalculationMethods" :key="i"
v-model="form.competitionStageList[0].teamCalculationMethod" :label="j.id">{{ j.name }}</el-radio>
<span class="tips">(可设置本阶段的团队取分规则)</span>
</div>
</div>
</el-form-item>
<el-form-item label="成绩公布时间">
(阶段)比赛结束后
<el-input v-model.number="form.competitionStageList[0].resultAnnouncementTime" type="number" min="0"
style="width: 120px"></el-input>
小时,公布(阶段)比赛成绩。(为空则不公布成绩,为0则阶段比赛结束后立马公布成绩)
</el-form-item>
<el-form-item
v-if="form.competitionStageList[0].resultAnnouncementTime !== '' && form.competitionStageList[0].resultAnnouncementTime !== null && form.competitionStageList[0].resultAnnouncementTime !== undefined"
prop="resultsDetails" label="是否公布成绩详情">
<el-radio v-model="form.competitionStageList[0].resultsDetails" :label="0">是</el-radio>
<el-radio v-model="form.competitionStageList[0].resultsDetails" :label="1"></el-radio>
<p class="tips">若选择则公布成绩详情竞赛结束后参赛者可查看自己的比赛成绩得分详情</p>
<p class="tips">若选择则不公布成绩详情参赛者只能知晓自己的分数及排名不能查看得分详情</p>
</el-form-item>
</template>
</el-form>
</div>
</div>
</div>
</template>
<script>
import util from "@/libs/util";
import Const from '@/const/match'
import _ from 'lodash'
export default {
props: ['setupId', 'editing'],
data () {
return {
id: this.$route.query.id,
updateTime: 0,
step1: this.$parent.$refs.step1.form,
serials: ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十'],
form: {
resultCalculationMethod: 0,
rule: 0,
stageNum: 3,
teamLimit: 1,
competitionStageList: [
{
method: 0,
number: 1,
pointWeight: '',
stageName: '',
teamCalculationMethod: 0,
peopleLimit: '',
percentageLimit: '',
scoreLimit: '',
operator: '>',
score: '',
customNumber: '',
teamNumLimit: 0,
resultAnnouncementTime: '',
resultsDetails: '',
},
{
method: 0,
number: 2,
pointWeight: '',
stageName: '',
teamCalculationMethod: 0,
peopleLimit: '',
percentageLimit: '',
scoreLimit: '',
operator: '>',
score: '',
customNumber: '',
teamNumLimit: 0,
resultAnnouncementTime: '',
resultsDetails: '',
},
{
method: 0,
number: 3,
pointWeight: '',
stageName: '',
teamCalculationMethod: 0,
peopleLimit: '',
percentageLimit: '',
scoreLimit: '',
operator: '>',
score: '',
customNumber: '',
teamNumLimit: 0,
resultAnnouncementTime: '',
resultsDetails: '',
}
]
},
validRules: {
rule: [
{ required: true, trigger: 'change' }
],
stageNum: [
{ required: true, trigger: 'change' }
],
resultCalculationMethod: [
{ required: true, trigger: 'change' }
],
resultAnnouncementTime: [
{ required: true, message: '请输入成绩公布时间', trigger: 'change' }
],
resultsDetails: [
{ required: true, trigger: 'change' }
],
},
originForm: null,
ruleForm: {},
rules: Const.rules,
methods: Const.methods,
teamCalculationMethods: Const.teamCalculationMethods,
operators: ['>', '>=', '=', '<', '<=']
};
},
watch: {
// 监听信息是否有更改,有的话页面离开的时候要询问是否要保存
form: {
handler () {
this.updateTime++
},
deep: true
},
},
mounted () {
this.ruleForm = JSON.parse(JSON.stringify(this.form.competitionStageList[0]))
this.id && this.getData()
this.step1 || this.getStep1() // 如果没有第一步的数据,则直接接口获取
},
methods: {
getData () {
this.$get(this.api.getCompetitionRule, {
competitionId: this.id
}).then(res => {
const rule = res.competitionRule
if (rule) {
rule.competitionStageList.map(e => {
const limit = e.scoreLimit
if (limit) {
e.operator = limit.replace(/\d+/, '')
const num = limit.replace(/\D+/, '')
if (num) e.score = num
}
e.teamCalculationMethod = +e.teamCalculationMethod
})
this.originForm = _.cloneDeep(rule)
this.form = rule
}
this.$nextTick(() => {
this.updateTime = 0
})
}).catch(res => { })
},
// 获取第二部的数据
getStep1 () {
this.$post(`${this.api.getCompetition}?competitionId=${this.id}`).then(({ competition }) => {
this.step1 = competition
const { minTeamSize, maxTeamSize, competitionType } = this.step1.completeCompetitionSetup
competitionType && minTeamSize !== '' && maxTeamSize !== '' && minTeamSize == maxTeamSize && this.teamCalculationMethods.pop() // 团队上下限人数相等,则不显示求和
}).catch(err => { })
},
// 阶段数量选择回调
stageChange (val) {
const stages = this.form.competitionStageList
const { ruleId } = this.form
if (stages.length < val) {
const len = stages.length
for (let i = 1; i <= val - len; i++) {
const form = JSON.parse(JSON.stringify(this.ruleForm))
form.number = len + i
if (ruleId) form.ruleId = ruleId
this.form.competitionStageList.push(form)
}
} else {
this.form.competitionStageList = stages.slice(0, val)
}
},
// 保存自动分配人员条件
async automaticAllocation (next) {
// 团队赛
if (this.step1.completeCompetitionSetup.competitionType) {
const { form, originForm } = this
// 赛制、阶段数量、是否限制成员只参加一个阶段、参赛人数限制。这些字段有改一个,则调接口查询其他3个条件;一共4个条件都满足后,才需要弹框;否则直接进入下一步
let changeLimit = 0
for (const i in form.competitionStageList) {
const e = form.competitionStageList[i]
if (e.teamNumLimit !== originForm.competitionStageList[i].teamNumLimit || e.customNumber !== originForm.competitionStageList[i].customNumber) {
changeLimit = 1
break
}
}
if (form.rule !== originForm.rule || form.stageNum !== originForm.stageNum || form.teamLimit !== originForm.teamLimit || changeLimit) {
await this.$post(this.api.updateEventAllocationRecord, {
competitionId: +this.id,
whetherToModifyTheRule: 1,
})
this.$emit('next', next)
} else {
this.$emit('next', next)
}
} else {
this.$emit('next', next)
}
},
// 提交
save (status, next = 0, releaseType, cb) {
const form = _.cloneDeep(this.form)
const { rule } = form
let invalid = 0
let pointWeight = 0
const { step1 } = this
// 下一步需要校验
if (next === 2) {
const stages = form.competitionStageList
if (form.rule === 2) { // 单项赛只需要输入成绩公布时间
const e = stages[0]
e.stageName = step1.name
if (e.resultsDetails === 0 && e.resultAnnouncementTime !== '') {
if (e.resultAnnouncementTime < 0) {
return util.errorMsg('成绩公布时间不得小于0')
}
if (e.resultAnnouncementTime % 1) {
return util.errorMsg('成绩公布时间须为整数')
}
e.resultAnnouncementTime = +e.resultAnnouncementTime
}
form.competitionStageList = stages.slice(0, 1) // 单项赛只需要存第一个阶段的数据
} else { // 非积分赛则全部字段校验
let customNumber = 0
const { competitionType, minTeamSize, maxTeamSize } = step1.completeCompetitionSetup // 0为个人赛,1为团队赛
for (const i in stages) {
const e = stages[i]
if (rule !== 2 && !e.stageName) {
invalid = 1
util.errorMsg('请输入阶段名称')
break
}
// rule: 0为积分赛,1为淘汰赛,2为单项赛
// 积分赛
if (!rule) {
// 个人
if (form.resultCalculationMethod == 0 && (e.pointWeight === '' || e.pointWeight === undefined)) {
invalid = 1
util.errorMsg('请输入权重')
break
}
pointWeight += e.pointWeight // 权重求和
} else if (rule === 1) { // 淘汰赛
// 晋级规则必须至少填一个(最后一个阶段不用填写)
if (i != stages.length - 1 && e.peopleLimit === '' && e.percentageLimit === '' && e.score === '') {
invalid = 1
util.errorMsg('请至少填写一条晋级规则')
break
}
if (e.score !== '') e.scoreLimit = e.operator + e.score
}
if (rule !== 2 && competitionType && e.teamNumLimit) {
if (e.customNumber === '' || e.customNumber === undefined) {
invalid = 1
util.errorMsg('请输入团队参数人数限制')
break
} else if (e.customNumber < 0) {
invalid = 1
util.errorMsg('团队参数人数不得小于0')
break
} else if (maxTeamSize !== '' && e.customNumber > maxTeamSize) {
invalid = 1
util.errorMsg('团队参数人数不得大于团队人数上限')
break
}
}
if (e.resultsDetails === 0 && (e.resultAnnouncementTime !== '' && e.resultAnnouncementTime !== undefined)) {
if (e.resultAnnouncementTime < 0) {
invalid = 1
util.errorMsg('成绩公布时间不得小于0')
break
}
if (e.resultAnnouncementTime % 1) {
invalid = 1
util.errorMsg('成绩公布时间须为整数')
break
}
e.resultAnnouncementTime = +e.resultAnnouncementTime
}
if (e.teamNumLimit && e.customNumber) customNumber += e.customNumber // 各阶段自定义的人数之和
if (!e.teamNumLimit) e.customNumber = ''
}
if (invalid) return
if (form.teamLimit && competitionType) {
if (stages.length > minTeamSize) return util.errorMsg('阶段数不得大于团队人数下限')
if (customNumber > minTeamSize) return util.errorMsg('各阶段自定义的参赛人数之和不得大于团队人数下限')
}
if (form.resultCalculationMethod == 0 && !rule && pointWeight > 0 && pointWeight !== 100) return util.errorMsg('权重须等于100,请重新输入')
}
} else { // 保存草稿的情况下,只保存输入了阶段名称的阶段
form.competitionStageList = form.competitionStageList.filter(e => e.stageName)
}
this.$parent.showLoad()
this.pass = 1
if (form.ruleId) {
this.$post(this.api.editCompetitionRule, form).then(res => {
this.$parent.hideLoad()
this.updateTime && util.successMsg("修改成功");
this.updateTime = 0
this.automaticAllocation(next)
}).catch(err => {
this.$parent.hideLoad()
})
} else {
form.setupId = this.setupId
this.$post(this.api.addCompetitionRule, form).then(res => {
this.$parent.hideLoad()
util.successMsg("创建成功");
this.$emit('next', next, cb)
}).catch(err => {
this.$parent.hideLoad()
})
}
},
}
};
</script>
<style scoped lang="scss">
/deep/ .d-inline-block {
width: 216px;
.el-select,
.el-input {
width: 100%;
}
}
.inline-input {
.input-wrap {
display: flex;
align-items: center;
margin-bottom: 10px;
.el-input {
display: inline-block;
width: 216px;
margin-right: 8px;
}
.remove {
width: 16px;
height: 16px;
background: url('../../../assets/img/close.png') 0 0 / cover no-repeat;
cursor: pointer;
}
}
.add-btn {
margin-left: 32px;
}
}
.input-center {
display: flex;
align-items: center;
width: 216px;
white-space: nowrap;
.el-input {
margin-right: 5px;
}
}
.step-set {
padding: 15px;
background-color: #fbfbfb;
}
.tips {
font-size: 13px;
color: #959595;
}
.req {
color: #f00;
}
.line {
margin-bottom: 10px;
}
</style>