<template> <div> <div v-show="!setVisible" class="page"> <div class="page-content"> <div class="p-title">比赛内容设置</div> <el-form label-width="170px" label-suffix=":" size="small" :disabled="!!(!editing && id)"> <div v-for="(item, i) in form" :key="i" class="step"> <div class="title"> <span>{{ item.stageName }}(第{{ nums[i] }}阶段) | {{ methods.find(e => e.id === item.method).name }} </span> <el-button v-if="item.method !== 2" type="primary" @click="toSet(i)">设置</el-button> </div> <el-form-item class="req" prop="time" label="比赛时间"> <span v-if="item.method !== 2 && item.startTime">{{ item.startTime + ' 至 ' + item.endTime }}</span> <div style="display: flex;align-items: center;" v-if="item.method === 2"> <el-date-picker v-model="item.time" type="datetimerange" range-separator="~" start-placeholder="开始日期" end-placeholder="结束日期" format="yyyy-MM-dd HH:mm:ss" value-format="yyyy-MM-dd HH:mm:ss" @change="timeChange"> </el-date-picker> <el-alert style="width: auto;padding: 0px 16px;margin-left: 10px;" :title="'(请设置在 ' + step1.playStartTime + ' ~ ' + step1.playEndTime + '间)'" type="error" :closable="false" effect="dark"> </el-alert> </div> </el-form-item> <template v-if="item.method === 2"> <el-form-item class="req" label="比赛地点"> <el-input v-model="item.offlineAddress" style="width: 80%"></el-input> </el-form-item> <el-form-item label="系统链接"> <el-input v-model="item.competitionStageContentSetting.systemLink" style="width: 80%"></el-input> </el-form-item> <el-form-item label="是否支持上传文件"> <div> <el-radio v-model="item.competitionStageContentSetting.whetherToUploadFiles" :label="0">否</el-radio> </div> <div class="flex a-center"> <el-radio v-model="item.competitionStageContentSetting.whetherToUploadFiles" :label="1">是</el-radio> <template v-if="item.competitionStageContentSetting.whetherToUploadFiles"> <el-upload class="file-upload" :on-remove="(file, fileList) => handleRemove(file, fileList, item)" :on-error="uploadError" :before-remove="beforeRemove" :on-preview="handlePreview" action="" :file-list="item.competitionStageContentSetting.fileList" :http-request="res => handleRequest(res, item)"> <el-button size="small" type="primary">上传文件</el-button> </el-upload> </template> </div> <div style="display: flex;align-items: flex-start;margin-top: 10px"> <span style="margin: 0 10px 0 30px;">说明</span> <el-input maxlength="1000" placeholder="请输入内容" type="textarea" v-model="item.competitionStageContentSetting.stageExplain" style="width: calc(80% - 216px);"></el-input> </div> </el-form-item> <el-form-item class="req" label="比赛内容"> <el-input v-model="item.contentDescription" type="textarea" style="width: 80%"></el-input> </el-form-item> <el-form-item class="req" label="评分规则"> <el-input v-model="item.scoreRule" type="textarea" style="width: 80%"></el-input> </el-form-item> </template> <template v-else> <el-form-item class="req" prop="cid" label="课程系统"> {{ item.systemName }} </el-form-item> <el-form-item class="req" prop="assessmentId" label="已选择考核"> {{ item.projectName }} </el-form-item> <el-form-item class="req" prop="resultAnnouncementTime" label="比赛地点"> <div class="line"> <el-checkbox v-model="item.onlineButton">线上</el-checkbox> <el-input v-model="item.onlineAddress" clearable placeholder="请输入比赛网址" :disabled="!item.onlineButton" style="width: 400px;margin-left: 10px"></el-input> </div> <div class="line"> <el-checkbox v-model="item.offlineButton">线下</el-checkbox> <el-input v-model="item.offlineAddress" clearable placeholder="请输入地址" :disabled="!item.offlineButton" style="width: 400px;margin-left: 10px"></el-input> </div> </el-form-item> </template> </div> </el-form> </div> </div> <set v-if="setVisible" :form.sync="form[curStep]" :step1.sync="step1" @hideSet="hideSet" /> <el-dialog title="提示" :visible.sync="tipsVisible" width="500px" :close-on-click-modal="false" custom-class="tips-dia"> <p style="font-size: 17px;text-align: center;color: #9076ff;">编辑发布成功!</p> <p style="margin: 5px 0px 10px;line-height: 1.6"> 温馨提示:报名结束后更改报名时间或赛程规则,不影响已分配的阶段参赛人员且后续添加的人员不会自动分配。如需重新自动分配所有团队,请到报名列表执行全员重新分配操作。 </p> <el-checkbox v-model="closeStatus">不再提示</el-checkbox> <span slot="footer" class="dialog-footer"> <el-button size="small" type="primary" @click="closePopup">关闭</el-button> </span> </el-dialog> </div> </template> <script> import Oss from '@/components/upload/upload.js' import Util from "@/libs/util"; import Setting from "@/setting"; import set from './set' export default { props: ['setupId', 'competitionId', 'editing'], data () { return { headers: { token: Util.local.get(Setting.tokenKey) }, id: this.$route.query.id, updateTime: 0, step1: this.$parent.$refs.step1.form, cache: this.$store.state.match.cache, nums: ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十'], methods: [ { id: 0, name: '实操' }, { id: 1, name: '理论' }, { id: 2, name: '线下' } ], originForm: { cid: '', mallId: '', contentDescription: '', endTime: '', scoreRule: '', stageId: '', startTime: '', systemId: '', offlineAddress: '', offlineButton: 0, onlineAddress: '', onlineButton: 0, time: [] }, form: [], setVisible: false, curStep: 0, pass: 0, curOriginForm: {}, closeStatus: false, tipsVisible: false, }; }, components: { set }, watch: { // 监听信息是否有更改,有的话页面离开的时候要询问是否要保存 form: { handler () { this.updateTime++ }, deep: true }, }, mounted () { this.handleForm() }, methods: { // 如果是从自定义项目入口进去后返回的,要恢复上次的阶段和数据 resumeData () { if (this.cache) { this.curStep = this.cache.curStep if (this.cache.form) this.form = this.cache.form this.setVisible = true this.$store.commit('match/setCache', null) } }, // 处理form handleForm () { // 根据赛事id查询赛事规则 this.$post(`${this.api.queryCompetitionStageBySetupId}?setupId=${this.setupId}`).then(res => { res.competitionStages.map(e => { const form = e.competitionContent || JSON.parse(JSON.stringify(this.originForm)) if (form.startTime) { form.time = [form.startTime, form.endTime] } else { form.time = [] } // 线下赛事要另外加一个对象处理系统链接等字段 if (e.method === 2) { if (!form.competitionStageContentSetting) { form.competitionStageContentSetting = { whetherToUploadFiles: 0, stageExplain: '', fileUrl: '', systemLink: '', fileList: [] } } // 文件路径名称处理 if (form.competitionStageContentSetting.fileUrl) { const urls = form.competitionStageContentSetting.fileUrl.split('|') const names = form.competitionStageContentSetting.fileName.split('|') form.competitionStageContentSetting.fileList = [] urls.map((n, i) => { form.competitionStageContentSetting.fileList.push({ name: names[i], url: n }) }) } else { form.competitionStageContentSetting.fileList = [] } form.competitionStageContentSetting.competitionId = this.id form.competitionStageContentSetting.stageId = e.stageId } form.offlineButton = !!form.offlineButton form.onlineButton = !!form.onlineButton form.method = e.method form.stageId = e.stageId form.stageName = e.stageName this.form.push(form) }) this.resumeData() this.$nextTick(() => { this.updateTime = 0 }) }).catch(res => { }) }, // 显示设置页面 toSet (i) { this.curOriginForm = JSON.parse(JSON.stringify(this.form[i])) this.curStep = i this.$parent.showBtns = false this.setVisible = true }, // 隐藏设置 hideSet (form) { if (form) this.form[this.curStep] = form this.setVisible = false this.$parent.showBtns = true }, // 时间选择回调 timeChange (val) { if (val.length) { const startTime = new Date(val[0]) const endTime = new Date(val[1]) const { playStartTime, playEndTime } = this.step1 if (startTime < new Date(playStartTime) || endTime > new Date(playEndTime)) return Util.warningMsg('设置的阶段比赛时间必须要在第一步设置的竞赛时间范围内,请重新设置。') const { form, curStep } = this for (const i in form) { // 判断其他阶段的时间跟当前选的时间是否重叠 if (i !== curStep) { const time1 = new Date(form[i].startTime) const time2 = new Date(form[i].endTime) if ((startTime >= time1 && startTime <= time2) || (endTime >= time1 && endTime <= time2)) { Util.warningMsg('请注意,所设置的时间与已设置的阶段时间重合。') break } } } } }, // 附件上传前 beforeUpload (file) { const isLt2M = file.size / 1024 / 1024 < 10 if (!isLt2M) Util.warningMsg('请上传小于10MB的附件!') if (isLt2M) { this.fileName = file.name return true } else { return false } }, uploadError (err, file, fileList) { this.$message({ message: "上传出错,请重试!", type: "error", center: true }) }, downloadFile () { // const { name, url } = this.fileList[0] // Util.downloadFile(name, url) }, handlePreview (file) { window.open((Util.isDoc(Util.getFileExt(file.name)) ? 'https://view.officeapps.live.com/op/view.aspx?src=' : '') + file.url) }, beforeRemove (file, fileList) { return this.$confirm(`确定移除 ${file.name}?`); }, handleRemove (file, fileList, item) { Oss.del(file.url) item.competitionStageContentSetting.fileList = fileList }, // 自定义上传 async handleRequest ({ file }, item) { Oss.upload(file).then(res => { item.competitionStageContentSetting.fileList.push({ name: res.name, url: res.url }) }) }, // 发布赛事 publish () { this.competitionId && this.$post(`${this.api.publishCompetition}?competitionId=${this.competitionId}&publishStatus=1`).then(res => { }).catch(err => { }) }, // 关闭编辑的提示弹框 async closePopup () { if (this.closeStatus) await this.$post(`${this.api.closePopup}?competitionId=${this.competitionId}`) this.$emit('next', 0) }, // 自动分配人员 async automaticAllocation (assignOrNot, next) { await this.$post(this.api.updateEventAllocationRecord, { assignOrNot, competitionId: this.competitionId, }) this.$emit('next', next) }, // 自动分配人员弹框 async autoAllocationConfirm (next) { // 查询是否有分配信息 const { data } = await this.$post(`${this.api.viewEventAllocationInformation}?competitionId=${this.competitionId}`) if (!data || data.assignOrNot === undefined || !this.form[0].contentId) { // 首次发布 or 新增 才需要弹框 const now = await Util.getNow() // 报名结束时间还没到 if (new Date(this.$parent.$refs.step1.form.signUpEndTime) > now) { this.$confirm('<p>团队赛发布成功,您是否要启用自动分配阶段参赛人员功能?</p><p style="margin-top: 10px;color: #a9a9a9;">(点击“是”将会在报名截止时清空已有分配,并为所有团队重新自动分配。)</p>', '提示', { confirmButtonText: '是', cancelButtonText: '否', type: 'success', closeOnClickModal: false, dangerouslyUseHTMLString: true, }).then(() => { this.automaticAllocation(1, next) }).catch(() => { this.automaticAllocation(0, next) }) } else { this.$confirm('团队赛发布成功,由于您设置的报名时间已结束,如需自动分配阶段参赛人员,请前往报名人员列表进行设置', '提示', { confirmButtonText: '关闭', type: 'success', closeOnClickModal: false, dangerouslyUseHTMLString: true, showClose: false, }).then(() => { this.$emit('next', next) }).catch(() => { }) } } else if (data.whetherToHidePopUps) { // 编辑的提示弹框如果没勾选不再提示,则弹框提示 this.tipsVisible = true } else { this.$emit('next', next) } }, // 提交 save (status, next = 0, releaseType, cb) { const { form } = this if (!form.length) { this.$parent.hideLoad() Util.successMsg('保存成功') this.$emit('next', next) return } let invalid = 0 const { playStartTime, playEndTime } = this.step1 for (const e of form) { // 发布才需要判断必填 if (status) { if (!e.time.length) { invalid = 1 Util.errorMsg('请选择比赛时间') break } if (new Date(e.time[0]) < new Date(playStartTime) || new Date(e.time[1]) > new Date(playEndTime)) { invalid = 1 Util.errorMsg('设置的阶段比赛时间必须要在第一步设置的竞赛时间范围内,请重新设置。') break } e.startTime = e.time[0] e.endTime = e.time[1] if (e.method !== 2 && !e.cid) { invalid = 1 Util.errorMsg('请选择课程') break } if (e.method === 2) { // 线下 if (!e.offlineAddress) { invalid = 1 Util.errorMsg('请输入比赛地点') break } if (!e.contentDescription) { invalid = 1 Util.errorMsg('请输入比赛内容') break } if (!e.scoreRule) { invalid = 1 Util.errorMsg('请输入评分规则') break } } else { if (e.onlineButton && !e.onlineAddress) { invalid = 1 Util.errorMsg('请输入线上地点') break } if (e.offlineButton && !e.offlineAddress) { invalid = 1 Util.errorMsg('请输入线下地点') break } if (!e.onlineAddress && !e.offlineAddress) { invalid = 1 Util.errorMsg('请输入比赛地点') break } } } e.startTime = e.time[0] e.endTime = e.time[1] } if (invalid) return // 处理单选框 for (const e of form) { e.offlineButton = e.offlineButton ? 1 : 0 e.onlineButton = e.onlineButton ? 1 : 0 if (e.competitionStageContentSetting && e.competitionStageContentSetting.fileList && e.competitionStageContentSetting.fileList.length) { e.competitionStageContentSetting.fileName = e.competitionStageContentSetting.fileList.map(n => n.name).join('|') e.competitionStageContentSetting.fileUrl = e.competitionStageContentSetting.fileList.map(n => n.url).join('|') } } this.$parent.showLoad() this.$post(this.api[form[0].contentId ? 'editCompetitionContent' : 'addCompetitionContent'], { competitionContents: form }).then(res => { this.updateTime = 0 this.pass = 1 this.$parent.hideLoad() // 新增赛事,并且点的是发布按钮,则发布该赛事 status && this.publish(status) Util.successMsg((status ? '发布' : '保存') + '成功') if (status && this.$parent.$refs.step1.form.completeCompetitionSetup.competitionType) { this.autoAllocationConfirm() // 团队并且第一次发布才需要弹框询问是否自动分配人员 } else { this.$emit('next', next) } }).catch(err => { this.$parent.hideLoad() }) }, } }; </script> <style scoped lang="scss"> .step { padding-bottom: 10px; background-color: #f9f9f9; .title { display: flex; justify-content: space-between; align-items: center; padding: 10px 15px; margin-bottom: 10px; background-color: #ededed; } } .line { margin-bottom: 10px; } /deep/.req { .el-form-item__label { &:before { content: '*'; margin-right: 5px; font-size: 18px; vertical-align: middle; color: #f00; } } } /deep/.file-upload { width: 500px; .download { position: absolute; bottom: -63px; right: 0; font-size: 12px; color: $main-color; cursor: pointer; } } </style>