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.
2144 lines
78 KiB
2144 lines
78 KiB
<template> |
|
<div class="wrap index"> |
|
|
|
<div class="banner" |
|
:style="{backgroundImage: 'url(' + (form.carouselUrl || 'https://huoran.oss-cn-shenzhen.aliyuncs.com/20220613/png/1536269450851409920.png') + ')'}"></div> |
|
<div class="center-con"> |
|
<div class="center-wrap"> |
|
<breadcrumb ref="breadcrumb" |
|
:data="'全部赛事/' + form.name"></breadcrumb> |
|
<div class="content"> |
|
<div :class="['tool flex-between', {logView: !logView}]"> |
|
<el-tabs v-model="curType" |
|
@tab-click="typeChange"> |
|
<el-tab-pane v-for="(item, index) in typeList" |
|
:key="index" |
|
:label="item.name" |
|
:name="item.id"></el-tab-pane> |
|
</el-tabs> |
|
<div class="action"> |
|
<p class="end-text" |
|
v-if="end"> |
|
距离{{ endList[status] }}还有 |
|
<em>{{ end }}</em> |
|
</p> |
|
<div class="m-l-20"> |
|
<p v-if="status" |
|
:class="['sign-status', {signing: status == 2,signed: status == 1,playing: status == 4}]">{{ form.competitionRegistration ? '已报名' : '未报名' }}</p> |
|
<el-dropdown v-if="playingStages.length > 1" |
|
@command="chooseStage"> |
|
<el-button type="primary" |
|
style="background-color: #f96d6d;border: 0;"> |
|
选择竞赛<i class="el-icon-arrow-down el-icon--right"></i> |
|
</el-button> |
|
<el-dropdown-menu slot="dropdown"> |
|
<el-dropdown-item v-for="(item, i) in playingStages" |
|
:key="i" |
|
:command="item">进入{{ item.stageName }}</el-dropdown-item> |
|
</el-dropdown-menu> |
|
</el-dropdown> |
|
<div v-else-if="status != 4 || (status == 4 && curStage)" |
|
class="status" |
|
:class="{wait: status == 0,signing: status == 2,signed: status == 1,playing: status == 4,finish: status == 3 || status == 5}" |
|
:title="statusList[status]" |
|
@click.stop="signup">{{ statusList[status] }}</div> |
|
</div> |
|
</div> |
|
</div> |
|
<div class="info"> |
|
<h6 class="title">{{ form.name }}</h6> |
|
<div class="meta">最近编辑时间:{{ form.updateTime }}</div> |
|
</div> |
|
|
|
<div v-show="curType < 4"> |
|
<div class="l-title" |
|
id="part1"><img src="@/assets/img/label.png" |
|
alt=""> 竞赛信息</div> |
|
<div v-if="form.description" |
|
class="texts ql-editor" |
|
v-html="form.description"></div> |
|
<template v-if="form.competitionAnnexList"> |
|
<h6 class="p-title">附件下载</h6> |
|
<ul class="files"> |
|
<li v-for="(item, i) in form.competitionAnnexList" |
|
:key="i"> |
|
<el-link v-if="item.canPreview" |
|
class="m-r-10" |
|
type="primary" |
|
@click="preview(item)">{{ item.fileName }}</el-link> |
|
<span v-else |
|
class="fileName">{{ item.fileName }}</span> |
|
<el-link type="primary" |
|
:underline="false" |
|
@click="download(item)">下载</el-link> |
|
</li> |
|
</ul> |
|
</template> |
|
|
|
<template v-if="form.releaseType"> |
|
<div class="l-title"><img src="@/assets/img/label.png" |
|
alt=""> 赛程、规则与内容</div> |
|
<h6 class="rule-title">共{{ form.competitionStage.length }}个竞赛阶段<template v-if="info.teamLimit">,同一个团队每个成员只能参加一个阶段赛项</template></h6> |
|
<div v-for="(rule, i) in form.competitionStage" |
|
:key="i" |
|
class="rule"> |
|
<p style="font-size: 16px;color: #333;">{{ rule.stageName }}</p> |
|
<p>比赛时间:{{ rule.startTime && rule.startTime + ' ~ ' + rule.endTime }}</p> |
|
<p>比赛方式:{{ methods.find(e => e.id == rule.method) && methods.find(e => e.id == rule.method).name }}</p> |
|
<p v-if="rule.method != 2">课程系统:{{ rule.systemName }}</p> |
|
<p v-if="rule.onlineButton && rule.method != 2">线上地点:{{ rule.onlineAddress }}</p> |
|
<p v-if="rule.offlineButton">线下地点:{{ rule.offlineAddress }}</p> |
|
<template v-if="rule.method === 2"> |
|
<p>比赛地点:{{ rule.offlineAddress }}</p> |
|
<p>比赛内容:{{ rule.contentDescription }}</p> |
|
<p>评分规则:{{ rule.scoreRule }}</p> |
|
</template> |
|
|
|
<template v-if="form.completeCompetitionSetup.competitionType"> |
|
<p>每个团队参赛人数限制:{{ rule.teamNumLimit || '不限制' }}</p> |
|
<p>团队成绩计算方式:{{ teamCalculationMethods.find(e => e.id == rule.teamCalculationMethod) && teamCalculationMethods.find(e => e.id == rule.teamCalculationMethod).name }}</p> |
|
</template> |
|
<!-- <p v-if="rule.resultAnnouncementTime != 0">阶段比赛结束后{{ rule.resultAnnouncementTime }}小时,公布阶段比赛成绩。</p> --> |
|
<div v-if="form.rule === 1 && i !== form.competitionStage.length - 1" |
|
class="flex"> |
|
<p>晋级规则:</p> |
|
<div> |
|
<p v-if="rule.peopleLimit">本阶段成绩排名前{{ rule.peopleLimit }}队,可晋级下一阶段比赛</p> |
|
<p v-if="rule.percentageLimit">本阶段成绩排名前{{ rule.percentageLimit }}%,可晋级下一阶段比赛</p> |
|
<p v-if="rule.scoreLimit">本阶段成绩{{ rule.scoreLimit }}分,可晋级下一阶段比赛</p> |
|
</div> |
|
</div> |
|
</div> |
|
</template> |
|
|
|
<!-- 进展 --> |
|
<div class="l-title" |
|
id="part2"><img src="@/assets/img/label.png" |
|
alt=""> 竞赛进展</div> |
|
<ul class="progress" |
|
v-if="progress.length"> |
|
<li v-for="(item,index) in progress" |
|
:key="index" |
|
:class="item.status == 0 ? 'not' : (item.status == 1 ? 'ing' : 'done')"> |
|
<i class="dot"></i> |
|
<p class="name">{{item.title}}</p> |
|
<p class="desc">{{item.description}}</p> |
|
</li> |
|
<img class="rocket" |
|
src="@/assets/img/rocket.png" |
|
alt=""> |
|
</ul> |
|
<template v-else> |
|
<div class="empty"> |
|
<div> |
|
<img src="@/assets/img/none.png" |
|
alt=""> |
|
<p>暂无数据</p> |
|
</div> |
|
</div> |
|
</template> |
|
|
|
<!-- 公告 --> |
|
<div class="l-title" |
|
id="part3"><img src="@/assets/img/label.png" |
|
alt=""> 通知公告</div> |
|
<ul class="notice-list" |
|
v-if="notices.length"> |
|
<li v-for="(item, i) in notices" |
|
:key="i" |
|
@click="toNotice(item)"> |
|
<h6>{{ item.announcementTitle }}</h6> |
|
<p class="meta">{{ item.updateTime }}</p> |
|
<div class="des" |
|
v-html="item.announcementText"></div> |
|
</li> |
|
</ul> |
|
<template v-else> |
|
<div class="empty"> |
|
<div> |
|
<img src="@/assets/img/none.png" |
|
alt=""> |
|
<p>暂无通知公告</p> |
|
</div> |
|
</div> |
|
</template> |
|
</div> |
|
|
|
<!-- 竞赛排名 --> |
|
<template v-if="curType == 4"> |
|
<div class="l-title"><img src="@/assets/img/label.png" |
|
alt=""> 竞赛排名</div> |
|
<el-tabs v-model="curArch" |
|
@tab-click="getRank"> |
|
<el-tab-pane v-for="(item, index) in arches" |
|
:key="index" |
|
:label="item.stageName + '排名'" |
|
:name="item.stageId"></el-tab-pane> |
|
</el-tabs> |
|
<el-table ref="table" |
|
:data="ranks" |
|
stripe |
|
header-align="center"> |
|
<el-table-column type="index" |
|
width="60" |
|
label="排名" |
|
align="center"></el-table-column> |
|
<template v-if="form.completeCompetitionSetup.competitionType"> |
|
<el-table-column prop="teamName" |
|
label="团队名称"></el-table-column> |
|
<el-table-column prop="leaderName" |
|
label="队长"></el-table-column> |
|
</template> |
|
<el-table-column v-else |
|
prop="userName" |
|
label="姓名"></el-table-column> |
|
<el-table-column prop="schoolName" |
|
label="学校"></el-table-column> |
|
<el-table-column prop="school" |
|
label="用时"> |
|
<template slot-scope="scope"> |
|
{{ scope.row.timeSum }}min |
|
</template> |
|
</el-table-column> |
|
<el-table-column prop="score" |
|
label="分数"></el-table-column> |
|
</el-table> |
|
</template> |
|
|
|
<template v-if="curType == 5"> |
|
<div class="l-title m-t-20"><img src="@/assets/img/label.png" |
|
alt=""> 参赛信息</div> |
|
<table v-if="form.completeCompetitionSetup.competitionType && info.team.captain === 0" |
|
class="table m-b-20"> |
|
<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 && info.team.captain === 0 && status < 4" |
|
class="m-b-20 text-center"> |
|
<el-button type="primary" |
|
@click="edit(1)">{{ editing ? '保存' : '编辑' }}</el-button> |
|
</div> |
|
<table class="table"> |
|
<template v-if="!form.completeCompetitionSetup.competitionType || info.team.captain"> |
|
<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"> |
|
<tr v-if="info.team.captain"> |
|
<th width="150">团队名称:</th> |
|
<td> |
|
<span>{{ info.team.teamName }}</span> |
|
</td> |
|
</tr> |
|
<template v-if="info.team.captain"> |
|
<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> |
|
<tr v-if="info.team.captain"> |
|
<th>团队邀请码:</th> |
|
<td> |
|
<span>{{ info.team.invitationCode }}</span> |
|
</td> |
|
</tr> |
|
</template> |
|
</template> |
|
<tr> |
|
<th width="130">指导老师:</th> |
|
<td v-if="info.team.captain === 0 || !form.completeCompetitionSetup.competitionType"> |
|
<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> |
|
<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> |
|
<td v-else> |
|
<table class="table tc"> |
|
<tr> |
|
<th width="60">姓名</th> |
|
<th width="100">职务</th> |
|
<th width="100">手机号</th> |
|
</tr> |
|
<template v-if="info.teamInstructors.length"> |
|
<tr v-for="(item, i) in info.teamInstructors" |
|
:key="i"> |
|
<td width="60">{{ item.name }}</td> |
|
<td width="100">{{ item.position }}</td> |
|
<td width="100">{{ item.phone }}</td> |
|
</tr> |
|
</template> |
|
<tr v-else> |
|
<td colspan="3">暂无数据</td> |
|
</tr> |
|
</table> |
|
</td> |
|
</tr> |
|
<tr> |
|
<th>竞赛阶段:</th> |
|
<td> |
|
<table class="table tc"> |
|
<tr> |
|
<th width="70">序号</th> |
|
<th width="120">赛项阶段名称</th> |
|
<template v-if="form.completeCompetitionSetup.competitionType"> |
|
<th width="110">参赛人数限制</th> |
|
<th>允许参赛人员</th> |
|
</template> |
|
<th v-if="form.rule === 0" |
|
width="70">总分</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 || form.name }}</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 m-b-5" |
|
:closable="info.team.captain === 0 && status < 4" |
|
@close="removePar(tag, item)"> |
|
{{tag.name}} |
|
</el-tag> |
|
</template> |
|
<span v-else |
|
class="m-r-5">无</span> |
|
<i v-if="info.team.captain === 0 && status < 4" |
|
class="el-icon-edit icon" |
|
@click="selectPar(item)"></i> |
|
</td> |
|
</template> |
|
<!-- 积分赛才需要显示总分这个字段,直接第一行合并表格(填了成绩公布时间才显示分数,不然为空) --> |
|
<td v-if="form.rule === 0 && !i" |
|
:rowspan="info.stages.length">{{ item.resultAnnouncementTime ? info.totalScore || 0 : '' }}</td> |
|
<td> |
|
<span v-if="item.score >= 0 && item.resultAnnouncementTime" |
|
class="m-r-10">分数{{item.score}}</span> |
|
<el-button v-if="item.showDetail && item.resultAnnouncementTime && item.resultsDetails === 0 && item.reportId" |
|
type="text" |
|
@click="show(item)">查看成绩详情</el-button> |
|
</td> |
|
</tr> |
|
</template> |
|
<tr v-else> |
|
<td colspan="6">暂无数据</td> |
|
</tr> |
|
</table> |
|
<!-- 团队&&队长才显示 --> |
|
<el-alert v-if="form.completeCompetitionSetup.competitionType && info.team.captain === 0" |
|
style="margin-top: 10px;" |
|
:title="'注:请团长(团队创建人)设置各阶段参赛成员,只有被选择的允许参赛成员可进入对应阶段比赛' + (info.teamLimit ? ',每个团队成员只能参加一个赛项阶段' : '') + '!'" |
|
type="warning" |
|
show-icon> |
|
</el-alert> |
|
</td> |
|
</tr> |
|
</table> |
|
|
|
<!-- 团队&&队长才显示 --> |
|
<template v-if="form.completeCompetitionSetup.competitionType && info.team.captain === 0"> |
|
<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-alert style="margin: 10px 0;" |
|
title="请确保团队成员人数满足大赛要求,否则无法参加比赛" |
|
type="success" |
|
:closable="false"> |
|
</el-alert> |
|
<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> |
|
</template> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<el-dialog title="报名" |
|
:visible.sync="peopleSignupVisible" |
|
:close-on-click-modal="false" |
|
width="300px"> |
|
<el-form class="dia-form"> |
|
<el-form-item> |
|
<el-input placeholder="请输入4位数大赛邀请码" |
|
maxlength="4" |
|
v-model="peopleSignupForm.registrationInvitationCode"></el-input> |
|
</el-form-item> |
|
</el-form> |
|
<span slot="footer" |
|
class="dialog-footer"> |
|
<el-button size="small" |
|
type="primary" |
|
@click="peopleSignupSubmit">报名</el-button> |
|
<el-button size="small" |
|
@click="peopleSignupVisible = false">取消</el-button> |
|
</span> |
|
</el-dialog> |
|
<el-dialog title="报名" |
|
:visible.sync="enterVisible" |
|
:close-on-click-modal="false" |
|
width="300px" |
|
@close="enterClose"> |
|
<el-form class="dia-form"> |
|
<p style="margin-bottom: 5px">请选择要加入的团队</p> |
|
<el-form-item> |
|
<el-select class="w-100" |
|
v-model="enterForm.teamId" |
|
filterable> |
|
<el-option v-for="(item, i) in teams" |
|
:key="i" |
|
:label="item.teamName" |
|
:value="item.teamId"></el-option> |
|
</el-select> |
|
</el-form-item> |
|
<el-form-item> |
|
<el-input placeholder="请输入团队邀请码" |
|
maxlength="6" |
|
v-model="enterForm.invitationCode"></el-input> |
|
</el-form-item> |
|
<el-form-item v-if="form.completeCompetitionSetup.isNeedCode"> |
|
<el-input placeholder="请输入大赛邀请码" |
|
maxlength="6" |
|
v-model="enterForm.registrationInvitationCode"></el-input> |
|
</el-form-item> |
|
<p class="tips"> |
|
查找不到团队?点击 <el-link :underline="false" |
|
type="primary" |
|
@click="toTeam">创建团队</el-link> |
|
</p> |
|
</el-form> |
|
<span slot="footer" |
|
class="dialog-footer"> |
|
<el-button size="small" |
|
type="primary" |
|
@click="enterSubmit">报名</el-button> |
|
<el-button size="small" |
|
@click="enterVisible = false">取消</el-button> |
|
</span> |
|
</el-dialog> |
|
<el-dialog title="创建团队" |
|
:visible.sync="teamVisible" |
|
:close-on-click-modal="false" |
|
width="300px" |
|
@close="teamClose"> |
|
<el-form class="dia-form"> |
|
<el-form-item> |
|
<el-input placeholder="请输入团队名称" |
|
maxlength="10" |
|
v-model="teamForm.teamName"></el-input> |
|
</el-form-item> |
|
<el-form-item> |
|
<el-input placeholder="请设置团队邀请码" |
|
maxlength="6" |
|
v-model="teamForm.invitationCode"></el-input> |
|
</el-form-item> |
|
<el-form-item v-if="form.completeCompetitionSetup.isNeedCode"> |
|
<el-input placeholder="请输入大赛邀请码" |
|
maxlength="6" |
|
v-model="teamForm.registrationInvitationCode"></el-input> |
|
</el-form-item> |
|
</el-form> |
|
<span slot="footer" |
|
class="dialog-footer"> |
|
<el-button size="small" |
|
type="primary" |
|
@click="teamSubmit">创建并报名</el-button> |
|
<el-button size="small" |
|
@click="teamVisible = false">取消</el-button> |
|
</span> |
|
</el-dialog> |
|
|
|
<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 :disabled="!item.reportId" |
|
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> |
|
|
|
<el-dialog :title="curStage ? curStage.stageName : ''" |
|
:visible.sync="stageVisible" |
|
:close-on-click-modal="false" |
|
width="600px" |
|
@close="stageClose"> |
|
<template v-if="curStage && curStage.competitionStageContentSetting"> |
|
<div v-if="curStage.competitionStageContentSetting.systemLink" |
|
class="m-b-20"> |
|
<span class="fs-14">进入比赛:</span> |
|
<el-button type="danger" |
|
style="font-size: 13px" |
|
@click="toOffline">进入{{ curStage.stageName }}</el-button> |
|
</div> |
|
<div v-if="curStage.competitionStageContentSetting.fileUrl" |
|
class="flex m-b-20 fs-14"> |
|
<span style="padding-top: 7px">文件下载:</span> |
|
<div> |
|
<div v-for="(file, i) in curStage.competitionStageContentSetting.fileList" |
|
:key="i"> |
|
<span style="margin-right: 10px;color: #606266;">{{ file.name }}</span> |
|
<el-button type="text" |
|
style="font-size: 14px" |
|
@click="download({fileName: file.name, filePath: file.url})">点击下载</el-button> |
|
</div> |
|
</div> |
|
</div> |
|
<div class="flex m-b-20"> |
|
<span class="fs-14">文件上传:</span> |
|
<el-upload class="file-upload flex-1" |
|
:disabled="uploading" |
|
:before-upload="beforeUpload" |
|
:on-remove="handleRemove" |
|
:on-error="uploadError" |
|
:before-remove="beforeRemove" |
|
:on-preview="handlePreview" |
|
:limit="1" |
|
action="" |
|
:on-exceed="handleExceed" |
|
:file-list="fileList" |
|
:http-request="handleRequest" |
|
name="file"> |
|
<el-button size="small" |
|
type="primary" |
|
:loading="uploading" |
|
:disabled="!!(fileList && fileList.length) || uploading">{{ uploading ? '正在上传' : fileList && fileList.length ? '已上传' : '上传文件' }}</el-button> |
|
<div slot="tip" |
|
class="el-upload__tip relative"> |
|
<el-progress v-if="uploading" |
|
class="m-b-5" |
|
:stroke-width="3" |
|
:percentage="uploadProgress"></el-progress> |
|
<p>请上传大小1G以内的文件,支持常见文件格式。</p> |
|
<p>只允许上传一个文件,如有多个文件则需打包再上传。</p> |
|
<div v-if="fileList.length" |
|
class="download" |
|
@click="downloadFile">下载</div> |
|
</div> |
|
</el-upload> |
|
</div> |
|
|
|
<div class="fs-14">说明:{{ curStage.competitionStageContentSetting.stageExplain }}</div> |
|
</template> |
|
<span slot="footer" |
|
class="dialog-footer"> |
|
<el-button size="small" |
|
@click="stageVisible = false">关闭</el-button> |
|
</span> |
|
</el-dialog> |
|
</div> |
|
</template> |
|
|
|
<script> |
|
import { mapState, mapMutations } from "vuex"; |
|
import breadcrumb from '@/components/breadcrumb' |
|
import Util from '@/libs/util' |
|
import Setting from "@/setting" |
|
import Const from '@/const/match' |
|
import OSS from 'ali-oss' |
|
import OssConfig from '@/components/upload/config.js' |
|
import Oss from '@/components/upload/upload.js' |
|
export default { |
|
name: 'matchdetail', |
|
data () { |
|
return { |
|
headers: { |
|
token: Util.local.get(Setting.tokenKey) |
|
}, |
|
token: Util.local.get(Setting.tokenKey), |
|
id: +this.$route.query.id, |
|
end: '', |
|
status: '', |
|
statusList: ["等待报名", "取消报名", "立即报名", "报名截止", "进入竞赛", "已结束"], |
|
endList: ["报名开始", "报名截止", "报名截止", "竞赛开始", "竞赛结束", ""], |
|
rules: Const.rules, |
|
methods: Const.methods, |
|
teamCalculationMethods: Const.teamCalculationMethods, |
|
timerList: [], |
|
form: { |
|
name: '', |
|
coverUrl: '', |
|
description: '', |
|
signUpStartTime: '', |
|
signUpEndTime: '', |
|
playStartTime: '', |
|
playEndTime: '', |
|
competitionStage: [], |
|
completeCompetitionSetup: {}, |
|
competitionRegistration: {} |
|
}, |
|
curType: '1', |
|
typeList: [ |
|
{ |
|
id: '1', |
|
name: '竞赛信息' |
|
}, |
|
{ |
|
id: '2', |
|
name: '竞赛进展' |
|
}, |
|
{ |
|
id: '3', |
|
name: '通知公告' |
|
}, |
|
{ |
|
id: '4', |
|
name: '竞赛排名' |
|
}, |
|
], |
|
progress: [], |
|
timer: null, |
|
rankTimer: null, |
|
notices: [], |
|
noticeDetail: {}, |
|
curArch: '0', |
|
arches: [], |
|
ranks: [], |
|
|
|
enterVisible: false, |
|
enterForm: { |
|
competitionId: this.$route.query.id, |
|
teamId: '', |
|
invitationCode: '', |
|
registrationInvitationCode: '', |
|
whetherSignUp: 1 |
|
}, |
|
|
|
teamVisible: false, |
|
teams: [], |
|
teamNameRepeat: false, |
|
teamForm: { |
|
competitionId: this.$route.query.id, |
|
registrationInvitationCode: '', |
|
teamName: '', |
|
invitationCode: '', |
|
whetherSignUp: 1 |
|
}, |
|
curStage: null, |
|
choosing: false, |
|
originInfo: {}, |
|
info: { |
|
isCaption: 0, |
|
person: {}, |
|
caption: {}, |
|
team: { |
|
captain: 1, |
|
invitationCode: '' |
|
}, |
|
stages: [], |
|
teamDetail: [], |
|
teamInstructors: [] |
|
}, |
|
originIns: { |
|
id: '', |
|
position: '', |
|
name: '', |
|
phone: '', |
|
}, |
|
checkedPlayer: '', |
|
transferVisible: false, |
|
editing: false, |
|
memberVisible: false, |
|
members: [], |
|
curRow: {}, |
|
chooseVisible: false, |
|
checkedMember: '', |
|
checkedMembers: [], |
|
chooses: [], |
|
lastType: 1, |
|
playingStages: [], |
|
peopleSignupVisible: false, |
|
peopleSignupForm: { |
|
registrationInvitationCode: '' |
|
}, |
|
submiting: false, |
|
|
|
stageVisible: false, |
|
filesResult: {}, |
|
fileList: [], |
|
curFileId: '', |
|
|
|
|
|
client: null, |
|
uploading: false, |
|
uploadProgress: 0, |
|
now: '' |
|
}; |
|
}, |
|
computed: { |
|
...mapState("user", [ |
|
"userId", 'account', 'logView' |
|
]), |
|
}, |
|
components: { |
|
breadcrumb |
|
}, |
|
mounted () { |
|
this.$once('hook:beforeDestroy', function () { |
|
clearInterval(this.timer) |
|
clearInterval(this.rankTimer) |
|
this.timerList.forEach(n => { |
|
clearTimeout(n) |
|
}) |
|
this.timerList = [] |
|
}) |
|
this.getData() |
|
this.getProgress() |
|
this.getNotice() |
|
this.getTeam() |
|
|
|
this.initOss() |
|
}, |
|
methods: { |
|
...mapMutations('match', [ |
|
'SET_SOURCE' |
|
]), |
|
getData () { // 获取竞赛信息 |
|
clearInterval(this.timer) |
|
this.$post(`${this.api.getCompetition}?competitionId=${this.id}`).then(async ({ competition }) => { |
|
const list = competition.competitionAnnexList |
|
// 附件 |
|
if (list) { |
|
list.map(e => { |
|
const { filePath } = e |
|
e.canPreview = Util.canPreview(filePath.substr(filePath.lastIndexOf('.') + 1)) |
|
}) |
|
} |
|
|
|
this.form = competition |
|
const reg = competition.competitionRegistration |
|
// 选择的赛事类型为设置完整比赛的才展示竞赛排名和参赛信息 |
|
if (competition.releaseType) { |
|
const arches = [] |
|
// 积分赛才有总分排名 |
|
competition.rule === 0 ? |
|
arches.push({ |
|
stageId: '0', |
|
stageName: '总分' |
|
}) : |
|
(this.curArch = competition.competitionStage[0].stageId + '') |
|
arches.push(...competition.competitionStage) |
|
arches.map(e => e.stageId = e.stageId + '') |
|
this.arches = arches |
|
|
|
// 报名后才显示参赛信息 |
|
if (reg && !this.typeList.find(e => e.id == 5)) { |
|
this.typeList.push({ |
|
id: '5', |
|
name: '参赛信息' |
|
}) |
|
this.getInfo() |
|
} |
|
this.token && this.intervalRank() |
|
} else { |
|
this.typeList = this.typeList.slice(0, 3) |
|
} |
|
this.$refs.breadcrumb.update('全部赛事/' + competition.name) |
|
|
|
this.now = await Util.getNow() |
|
this.handleStatus() |
|
this.timer = setInterval(() => { |
|
this.now = new Date(this.now.setSeconds(this.now.getSeconds() + 1)) |
|
this.handleStatus() |
|
}, 1000) |
|
}).catch(err => { }) |
|
}, |
|
// 定时处理时间及状态 |
|
handleStatus () { |
|
const { form } = this |
|
let total = '' |
|
let time = '' |
|
let status = '' |
|
let signUpStartTime = new Date(this.core.dateCompatible(form.signUpStartTime)) // 报名开始时间 |
|
let signUpEndTime = new Date(this.core.dateCompatible(form.signUpEndTime)) // 报名结束时间 |
|
let playStartTime = new Date(this.core.dateCompatible(form.playStartTime)) // 比赛开始时间 |
|
let playEndTime = new Date(this.core.dateCompatible(form.playEndTime)) // 比赛结束时间 |
|
const { now } = this |
|
if (now < signUpStartTime) { // 报名没开始 |
|
status = 0 |
|
total = signUpStartTime - now |
|
} else if (now > signUpStartTime && now < signUpEndTime) { // 报名进行中 |
|
// 1已报名,2立即报名(没登录的情况下,直接显示立即报名,登录了则取报名信息,有则已报名,无则立即报名) |
|
status = this.token ? |
|
(form.competitionRegistration ? |
|
1 : |
|
2) : |
|
2 |
|
total = signUpEndTime - now |
|
} else if (now > signUpEndTime && now < playStartTime) { // 报名结束了,但比赛没开始 |
|
status = 3 |
|
total = playStartTime - now |
|
} else if (now > playStartTime && now < playEndTime) { // 比赛进行中 |
|
// 如果是完整比赛 |
|
if (form.releaseType) { |
|
// 进行中的赛事,则遍历每个阶段的开始结束时间,看阶段比赛是否开始 |
|
let curStage = null |
|
const stages = form.competitionStage |
|
if (stages) { |
|
this.playingStages = [] |
|
form.competitionRegistration && stages.forEach(e => { |
|
if (now >= new Date(e.startTime) && now <= new Date(e.endTime) && (e.method !== 2 || this.offlineCanEntry(e))) this.playingStages.push(e) |
|
}) |
|
let endText = '' |
|
for (const i in stages) { |
|
const e = stages[i] |
|
const startTime = new Date(e.startTime) |
|
const endTime = new Date(e.endTime) |
|
if (now < startTime) { // 阶段比赛未开始,不显示进入比赛按钮 |
|
endText = '阶段开始' |
|
total = startTime - now |
|
break |
|
} else if (now >= startTime && now <= endTime) { // 阶段比赛进行中,显示进入比赛按钮 |
|
// 非线下赛事 |
|
if (e.method !== 2) { |
|
if (form.competitionRegistration) { // 报名了才能进入比赛 |
|
this.statusList[4] = e.count ? '已提交' : '进入' + e.stageName |
|
curStage = e |
|
} else if (!this.token) { |
|
this.statusList[4] = '进入' + e.stageName |
|
curStage = e |
|
} |
|
} else if (this.offlineCanEntry(e) && form.competitionRegistration) { // 线下(输入了系统链接或者上传文件选择了是,才需要显示进入按钮) |
|
// 当系统链接为空,且上传文件为否时,无需展示入口 |
|
// 当系统链接不为空,且上传文件为否时,点击入口,直接跳转到链接页面,无需弹窗 |
|
// 当上传文件为是时,点击入口需弹窗,共两种样式 |
|
this.statusList[4] = '进入' + e.stageName |
|
curStage = e |
|
} |
|
endText = '阶段结束' |
|
total = endTime - now |
|
break |
|
} else if (stages[i + 1] && now > endTime && now < new Date(stages[i + 1].startTime)) { // 过了该阶段的结束时间,但是没到下个阶段的开始时间,不显示进入比赛按钮 |
|
endText = '阶段开始' |
|
total = new Date(stages[i + 1].startTime) - now |
|
break |
|
} else if (i === stages.length - 1) { // 当前时间在比赛开始结束时间之间,并且是最后一个阶段结束时间之后 |
|
this.$set(form, 'stageName', '') |
|
endText = '竞赛结束' |
|
total = playEndTime - now |
|
break |
|
} |
|
} |
|
this.endList[4] = endText |
|
} |
|
if (!this.choosing) this.curStage = curStage |
|
} else { // 仅发布信息 |
|
total = playEndTime - now |
|
} |
|
status = 4 |
|
} else if (now > playEndTime) { // 比赛结束 |
|
status = 5 |
|
} |
|
this.status = status |
|
total = total / 1000 |
|
--total |
|
if (total > 86400) { // 超过一天则显示天数 |
|
// clearInterval(this.timer) |
|
this.end = Math.floor(total / 86400) + '天' |
|
} else if (total > 0) { // 一天之内,显示时分秒 |
|
let hours = Math.floor(total / (60 * 60)) |
|
let minutes = Math.floor(total % (60 * 60) / 60) |
|
let seconds = Math.floor(total % (60 * 60) % 60) |
|
time = `${this.core.formateTime(hours)}:${this.core.formateTime(minutes)}:${this.core.formateTime(seconds)}` |
|
if (total > 0) this.end = time |
|
} else if (this.status === 5) { // 竞赛结束,清除定时器 |
|
clearInterval(this.timer) |
|
} |
|
}, |
|
// 该阶段是否符合线下能进入比赛的条件 |
|
offlineCanEntry (stage) { |
|
return stage.method === 2 && stage.competitionStageContentSetting && !!(stage.competitionStageContentSetting.systemLink || stage.competitionStageContentSetting.whetherToUploadFiles) |
|
}, |
|
// 获取竞赛信息 |
|
getInfo () { |
|
this.$post(`${this.api.entryInformation}?competitionId=${this.id}`).then(async res => { |
|
const info = res.entryInformation |
|
// 如果是队长,并且没有指导老师,默认添加一个空的 |
|
if (info.team && !info.team.captain && !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 = await Util.getNow() |
|
this.form.competitionStage && 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 => { }); |
|
}, |
|
// 编辑保存 |
|
edit (showMsg) { |
|
if (this.editing || !showMsg) { |
|
const { teamId, teamName, invitationCode } = this.info.team |
|
this.$post(this.api.editCompetitionTeam, { |
|
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 |
|
} |
|
}, |
|
getProgress () { // 获取竞赛进展 |
|
this.$get(this.api.getCompetitionProgress, { |
|
competitionId: this.id |
|
}).then(res => { |
|
this.progress = res.competitionProgressList.reverse() |
|
}).catch(err => { }); |
|
}, |
|
// 公告列表 |
|
getNotice () { |
|
this.$post(`${this.api.queryAnnouncementByCompetitionId}?pageNum=1&pageSize=1000&competitionId=${this.id}`).then(({ data }) => { |
|
const records = data.records.filter(e => e.status) // 只显示已发布的(status 0草稿 1为已发布) |
|
records.map(e => { |
|
e.announcementText = e.announcementText.replace(/<img.*?(?:>|\/>)/gi, '') |
|
}) |
|
this.notices = records |
|
}).catch(res => { }) |
|
}, |
|
// 预览附件 |
|
preview (item) { |
|
const { filePath } = item |
|
const suffix = filePath.substr(filePath.lastIndexOf('.') + 1) |
|
window.open((Util.isDoc(suffix) ? 'https://view.officeapps.live.com/op/view.aspx?src=' : '') + item.filePath) |
|
}, |
|
// 下载附件 |
|
download (item) { |
|
Util.downloadFile(item.fileName, item.filePath) |
|
}, |
|
// tab切换 前三个滚动,后两个切换 |
|
typeChange () { |
|
const type = +this.curType |
|
// 如果上个选中的是参赛信息,则检查修改数据后有没保存(团队名称、邀请码、指导老师) |
|
if (this.lastType == 5) { |
|
const { team, teamInstructors } = this.info |
|
const { originInfo } = this |
|
let notSave = 0 |
|
// 如果团队名称或者邀请码有修改 |
|
if (team.teamName !== originInfo.team.teamName || team.invitationCode !== originInfo.team.invitationCode) { |
|
notSave = 1 |
|
} else if (JSON.stringify(teamInstructors) !== JSON.stringify(originInfo.teamInstructors)) { |
|
notSave = 2 |
|
} |
|
if (notSave) { |
|
this.$confirm('所填写内容暂未保存,是否保存?', "提示", { |
|
type: "warning" |
|
}).then(() => { |
|
// 保存团队名称和邀请码 |
|
if (notSave === 1) { |
|
this.edit() |
|
} else { // 保存指导老师 |
|
teamInstructors.map(e => { |
|
e.name && this.$post(this.api.addAnAdvisor, { |
|
name: e.name, |
|
competitionId: this.id, |
|
id: e.id, |
|
teamId: this.form.competitionRegistration ? this.form.competitionRegistration.teamId : '', |
|
phone: e.phone, |
|
position: e.position, |
|
}).then(res => { }).catch(res => { }) |
|
}) |
|
} |
|
}).catch(() => { }) |
|
} else { |
|
type < 4 && document.querySelector(`#part${type}`).scrollIntoView() |
|
} |
|
} else { |
|
type == 5 && this.getInfo() |
|
type < 4 && document.querySelector(`#part${type}`).scrollIntoView() |
|
} |
|
this.editing = false |
|
this.lastType = type |
|
}, |
|
// 跳转公告详情 |
|
toNotice (item) { |
|
this.$router.push(`noticeDetail?id=${item.id}&matchId=${this.id}&name=${this.form.name}&end=${this.end}&status=${this.status}`) |
|
}, |
|
// 获取排名 |
|
getRank () { |
|
const cur = +this.curArch |
|
const data = { |
|
pageNum: 1, |
|
pageSize: 1000, |
|
competitionId: this.id, |
|
isOverallRanking: cur ? 0 : 1 |
|
} |
|
data.stageIds = cur ? cur : '' |
|
this.token && this.$post(this.api.frontOfficeCompetitionRanking, data).then(({ list }) => { |
|
this.ranks = list |
|
}).catch(res => { }) |
|
}, |
|
// 定时调获取排名接口 |
|
intervalRank () { |
|
this.getRank() |
|
// this.rankTimer = setInterval(this.getRank, 1000) |
|
}, |
|
|
|
// 删除指导老师 |
|
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, i) { |
|
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.form.competitionRegistration ? this.form.competitionRegistration.teamId : '', |
|
phone: row.phone, |
|
position: row.position, |
|
}).then(({ id }) => { |
|
Util.successMsg((row.id ? '修改' : '新增') + '成功') |
|
if (!row.id) { |
|
this.info.teamInstructors[i].id = id |
|
} |
|
this.info.teamInstructors[i].edit = 0 |
|
// this.getInfo() |
|
}).catch(res => { }) |
|
}, |
|
// 显示转让队长 |
|
async transfer () { |
|
// 取每个阶段的开始结束时间,有任何阶段开始了都不能转让队长和踢出队员 |
|
const now = await Util.getNow() |
|
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 => { }) |
|
}, |
|
// 踢出团队 |
|
async removeLine (row) { |
|
// 取每个阶段的开始结束时间,有任何阶段开始了都不能转让队长和踢出队员 |
|
const now = await Util.getNow() |
|
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(() => { }) |
|
} |
|
}, |
|
// 移除参赛人员 |
|
async removePar (e, stage) { |
|
const item = this.form.competitionStage.find(e => e.stageId == stage.stageId) |
|
if (item) { |
|
// 该阶段已经开始比赛则不能修改 |
|
const now = await Util.getNow() |
|
if (now >= new Date(item.startTime) && now <= new Date(item.endTime)) { |
|
return Util.errorMsg('该阶段比赛已经开始,无法修改允许参赛人员!') |
|
} else { |
|
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(() => { }) |
|
} |
|
} |
|
}, |
|
// 选择参赛人员 |
|
async selectPar (row) { |
|
const item = this.form.competitionStage.find(e => e.stageId == row.stageId) |
|
if (item) { |
|
// 该阶段已经开始比赛则不能修改 |
|
const now = await Util.getNow() |
|
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 => { |
|
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 = row.participantAccountIds ? row.participantAccountIds.split(',').map(e => +e) : [] // 选中了的人员要回显 |
|
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, |
|
platformId: 1 |
|
}).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.form.competitionRegistration.teamId |
|
if (teamId) { |
|
this.$post(this.api.stageTeamScoreDetails, { |
|
pageNum: 1, |
|
pageSize: 1000, |
|
competitionId: this.id, |
|
stageId: row.stageId, |
|
teamId |
|
}).then(({ page }) => { |
|
this.members = page.records |
|
}).catch(res => { }) |
|
} else { |
|
this.members = [] |
|
} |
|
} else if (row.reportId) { // 个人比赛,并且有reportId,则进入实验报告 |
|
this.toReport(row) |
|
} |
|
}, |
|
// 跳转实验报告 |
|
toReport (row) { |
|
this.$router.push(`/record/show?reportId=${row.reportId}&matchId=${this.id}&matchName=${this.form.name}`) |
|
}, |
|
|
|
// 个人报名提交 |
|
peopleSignupSubmit () { |
|
this.$post(this.api.addCompetitionRegistration, { |
|
competitionId: this.id, |
|
registrationInvitationCode: this.peopleSignupForm.registrationInvitationCode |
|
}).then(res => { |
|
this.peopleSignupVisible = false |
|
this.getData() |
|
this.$message.success('报名成功') |
|
}).catch(res => { }) |
|
}, |
|
// 团队报名提交 |
|
enterSubmit () { |
|
const form = this.enterForm |
|
if (!form.teamId) return Util.errorMsg('请选择团队') |
|
if (!form.invitationCode) return Util.errorMsg('请输入团队邀请码') |
|
if (this.form.completeCompetitionSetup.isNeedCode && !form.registrationInvitationCode) return Util.errorMsg('请输入大赛邀请码') |
|
this.$post(this.api.joinCompetitionTeam, form).then(res => { |
|
this.status = 1 |
|
this.enterVisible = false |
|
this.getData() |
|
Util.successMsg('报名成功!') |
|
}).catch(res => { }) |
|
}, |
|
// 团队关闭 |
|
enterClose () { |
|
this.enterForm = { |
|
competitionId: this.id, |
|
teamId: '', |
|
registrationInvitationCode: '', |
|
invitationCode: '', |
|
whetherSignUp: 1 |
|
} |
|
}, |
|
|
|
|
|
// 创建团队 |
|
toTeam () { |
|
this.teamVisible = true |
|
}, |
|
// 获取团队列表 |
|
getTeam () { |
|
this.$get(this.api.searchTeam, { |
|
teamName: '', |
|
competitionId: this.id |
|
}).then(({ teamList }) => { |
|
this.teams = teamList |
|
}).catch(res => { }) |
|
}, |
|
// 团队提交 |
|
teamSubmit () { |
|
const form = this.teamForm |
|
if (!form.teamName) return Util.errorMsg('请输入团队名称') |
|
if (this.teamNameRepeat) return Util.errorMsg('团队名称重复,请重新输入') |
|
if (form.invitationCode.length !== 6) return Util.errorMsg('请输入6位数团队邀请码') |
|
if (this.form.completeCompetitionSetup.isNeedCode && !form.registrationInvitationCode) return Util.errorMsg('请输入大赛邀请码') |
|
this.$post(this.api.addCompetitionTeam, form).then(({ status, data, message }) => { |
|
this.teamVisible = false |
|
this.enterVisible = false |
|
this.getData() |
|
Util.successMsg('报名成功!') |
|
}).catch(res => { }) |
|
}, |
|
// 团队关闭 |
|
teamClose () { |
|
this.teamForm = { |
|
competitionId: this.id, |
|
teamName: '', |
|
invitationCode: '', |
|
registrationInvitationCode: '', |
|
whetherSignUp: 1 |
|
} |
|
}, |
|
|
|
initOss () { |
|
this.client = new OSS(OssConfig.config) |
|
}, |
|
// 附件上传前 |
|
beforeUpload (file) { |
|
const oversize = file.size / 1024 / 1024 < 1000 |
|
if (!oversize) Util.warningMsg('请上传小于1GB的附件!') |
|
if (oversize) { |
|
return true |
|
} else { |
|
return false |
|
} |
|
}, |
|
// 自定义进度条 |
|
handleProgress (progress) { |
|
this.uploadProgress = Number((progress * 100).toFixed(2)) |
|
}, |
|
// 自定义上传 |
|
async handleRequest ({ file }) { |
|
try { |
|
this.fileList = [] |
|
this.uploadProgress = 0 |
|
this.uploading = true |
|
// 先传到阿里云oss,再把url传给后端 |
|
const { name } = await this.client.multipartUpload(Date.now() + '.' + Util.getFileExt(file.name), file, { |
|
progress: this.handleProgress |
|
}); |
|
|
|
this.uploading = false |
|
const url = 'https://huoran.oss-cn-shenzhen.aliyuncs.com/' + name |
|
this.fileList = [{ |
|
name: file.name, |
|
url |
|
}] |
|
|
|
// 把上传成功后的url存进文件表 |
|
const res = await this.$post(this.api.cCompetitionStageFileSave, { |
|
competitionId: this.id, |
|
fileFormat: Util.getFileExt(file.name), |
|
fileName: file.name, |
|
filePath: url, |
|
fileSize: file.size, |
|
stageId: this.curStage.stageId, |
|
teamId: this.form.competitionRegistration.teamId |
|
}) |
|
this.curFileId = res.message |
|
Util.successMsg(`上传成功!`); |
|
} catch (error) { } |
|
}, |
|
|
|
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) |
|
}, |
|
uploadError (err, file, fileList) { |
|
this.$message({ |
|
message: "上传出错,请重试!", |
|
type: "error", |
|
center: true |
|
}) |
|
}, |
|
beforeRemove (file, fileList) { |
|
return this.$confirm(`确定移除 ${file.name}?`); |
|
}, |
|
handleExceed (files, fileList) { |
|
Util.warningMsg(`当前限制选择 1 个文件,如需更换,请删除上一个文件再重新选择!`); |
|
}, |
|
// 删除文件表里的文件 |
|
handleRemove (file) { |
|
Oss.del(file.url) |
|
this.fileList = [] |
|
this.curFileId && this.$post(this.api.cCompetitionStageFileDel, [this.curFileId]).then(res => { |
|
this.curFileId = '' |
|
}).catch(res => { }) |
|
}, |
|
|
|
// 提交阶段内容 |
|
stageSubmit () { |
|
if (this.submiting) return false |
|
this.submiting = true |
|
}, |
|
// 阶段弹框关闭回调 |
|
stageClose () { |
|
this.choosing = false |
|
this.fileList = [] |
|
this.getData() |
|
}, |
|
|
|
// 选择要进入的阶段 |
|
chooseStage (e) { |
|
this.choosing = true |
|
this.curStage = e |
|
this.signup() |
|
}, |
|
// 判断是否能进赛事 |
|
getAllow () { |
|
// 是否允许参加赛事(淘汰赛制) |
|
if (this.form.rule === 1) { |
|
this.$post(this.api.allowedParticipateCompetition, { |
|
competitionId: this.id, |
|
number: this.curStage.number, |
|
stageId: this.curStage.stageId, |
|
teamId: this.form.competitionRegistration.teamId, |
|
}).then(res => { |
|
this.toSub() |
|
}).catch(res => { }) |
|
} else { |
|
this.toSub() |
|
} |
|
}, |
|
// 立即报名 |
|
signup () { |
|
const { status, form } = this |
|
// 如果登录了 |
|
if (Util.local.get(Setting.tokenKey)) { |
|
const { competitionType } = form.completeCompetitionSetup |
|
if (status == 4) { // 进入比赛 |
|
// 线下(规则见handleStatus方法) |
|
if (this.curStage.method == 2) { |
|
// 直接打开系统链接 |
|
if (!this.curStage.competitionStageContentSetting.whetherToUploadFiles) { |
|
window.open(this.curStage.competitionStageContentSetting.systemLink) |
|
} else { // 显示上传文件弹框 |
|
this.stageVisible = true |
|
|
|
// 文件路径名称处理 |
|
if (this.curStage.competitionStageContentSetting && this.curStage.competitionStageContentSetting.fileUrl) { |
|
const urls = this.curStage.competitionStageContentSetting.fileUrl.split('|') |
|
const names = this.curStage.competitionStageContentSetting.fileName.split('|') |
|
this.curStage.competitionStageContentSetting.fileList = [] |
|
urls.map((n, i) => { |
|
this.curStage.competitionStageContentSetting.fileList.push({ |
|
name: names[i], |
|
url: n |
|
}) |
|
}) |
|
} |
|
|
|
const file = this.curStage.competitionStageFile |
|
if (file) { |
|
this.curFileId = file.id |
|
this.fileList = [{ |
|
name: file.fileName, |
|
url: file.filePath, |
|
}] |
|
} |
|
} |
|
} else { |
|
// 参加过比赛不让参加 |
|
if (this.curStage && this.curStage.count) return Util.errorMsg('您已经参加过该阶段竞赛!') |
|
if (form.competitionRegistration.isDisable === 1) return Util.errorMsg('当前用户已被禁赛,如有疑问,请联系平台管理员。') // 被禁用的用户不能进入大赛 |
|
// 团队赛,则判断是否为参赛人员 |
|
if (competitionType) { |
|
this.$post(this.api.isParticipant, { |
|
competitionId: this.id, |
|
stageId: this.curStage.stageId, |
|
teamId: form.competitionRegistration.teamId, |
|
}).then(res => { |
|
this.getAllow() |
|
}).catch(res => { }) |
|
} else { |
|
this.getAllow() |
|
} |
|
} |
|
} else if (status == 2) { // 报名 |
|
// 团队赛报名 |
|
if (competitionType) { |
|
this.enterVisible = true |
|
} else { // 个人赛报名 |
|
if (form.completeCompetitionSetup.isNeedCode) { |
|
this.peopleSignupForm.registrationInvitationCode = '' |
|
this.peopleSignupVisible = true |
|
} else { |
|
this.$post(this.api.addCompetitionRegistration, { |
|
competitionId: this.id |
|
}).then(res => { |
|
this.getData() |
|
this.$message.success('报名成功') |
|
}).catch(res => { }) |
|
} |
|
} |
|
} else if (status == 1) { |
|
// 已报名,点击取消报名 |
|
this.$confirm('是否要取消报名?', '提示', { |
|
type: 'success' |
|
}).then(() => { |
|
this.$post(`${this.api.cancelRegistration}?competitionId=${this.id}`).then(res => { |
|
this.status = 2 |
|
this.$message.success('取消报名成功') |
|
this.getData() |
|
}).catch(res => { }) |
|
}).catch(() => { }) |
|
} |
|
} else { // 如果没登录,提示去登录 |
|
this.$confirm('请先登录,是否直接前往登录?', "提示", { |
|
type: 'success' |
|
}).then(() => { |
|
this.SET_SOURCE(this.id) |
|
this.$router.push('/login') |
|
}).catch(() => { }) |
|
} |
|
}, |
|
// 线下比赛方式点击进入跳转<比赛地点> |
|
toOffline () { |
|
window.open(this.curStage.competitionStageContentSetting.systemLink) |
|
}, |
|
// 进入python系统 |
|
toPython () { |
|
const form = this.curStage |
|
let token = Util.local.get(Setting.tokenKey); |
|
Util.cookies.set('assessmentId', '', -1) |
|
Util.cookies.set('startTime', '', -1) |
|
Util.cookies.set('stopTime', '', -1) |
|
Util.cookies.set('projectId', form.projectId) |
|
Util.cookies.set('token', token) |
|
Util.cookies.set('courseId', form.cid) |
|
Util.cookies.set('curriculumName', encodeURIComponent(form.systemName)) |
|
Util.cookies.set('systemId', form.systemId) |
|
Util.cookies.set('isSubmit', '', -1) |
|
Util.cookies.set('className', '', -1) |
|
Util.cookies.set('competitionId', this.form.id) |
|
Util.cookies.set('stageId', form.stageId) |
|
Util.cookies.set('teamId', this.form.competitionRegistration.teamId) |
|
Util.cookies.set('stopTime', form.endTime) |
|
Util.cookies.set('resultsDetails', form.resultsDetails) |
|
Util.cookies.set('resultAnnouncementTime', form.resultAnnouncementTime) |
|
Util.cookies.set('mallId', form.mallId) |
|
Util.cookies.set('fromManager', '', -1) |
|
Util.cookies.set('language', '', -1) |
|
// 8个python子系统都跳这个地址,子系统会通过cookie里的systemId识别展示哪套系统 |
|
location.href = process.env.NODE_ENV === 'development' ? |
|
`http://${location.hostname}:8085/#/` : |
|
Setting.isPro ? |
|
`https://${location.hostname}/pyTrials` : |
|
`${location.origin}/pyTrials` |
|
}, |
|
// 进入子系统 |
|
toSub () { |
|
const { form } = this |
|
const { systemId, systemName, projectId, cid, stageId, startTime, endTime, mallId } = this.curStage |
|
const competitionId = form.id |
|
const teamId = form.competitionRegistration.teamId |
|
let token = Util.local.get(Setting.tokenKey); |
|
if (systemId == 11) { |
|
// 银行系统 |
|
location.href = `${Setting.systemPath}/#/index/list?curriculumName=${this.curriculumName}&token=${token}&cid=${cid}&systemId=${systemId}&projectId=${projectId}&competitionId=${competitionId}&stageId=${stageId}&teamId=${teamId}&assessmentId=&classId=&stopTime=&test=true` |
|
} else if (systemId == 12) { |
|
// 众筹系统 |
|
window.open(`http://${Setting.zcPath}?systemId=${systemId}&courseId=${cid}&projectId=${projectId}&token=${token}&userId=${this.userId}&classId=1&competitionId=${competitionId}&stageId=${stageId}&teamId=${teamId}&startTime=${startTime}&endTime=${endTime}&mallId=${mallId}${Setting.isTest ? '&beta=1' : ''}`); |
|
} else if (systemId == 19) { |
|
// 沙盘 |
|
location.href = `${Setting.sandPath}/#/?curriculumName=${systemName}&token=${token}&cid=${cid}&mallId=${mallId}&systemId=${systemId}&projectId=${projectId}&assessmentId=&classId=&startTime=&stopTime=${endTime}&competitionId=${competitionId}&stageId=${stageId}&teamId=${teamId}&userId=${this.userId}&account=${this.account}&referrer=${encodeURIComponent(location.href)}` |
|
} else { |
|
// python系统 |
|
this.toPython(this.curProject) |
|
} |
|
} |
|
} |
|
}; |
|
</script> |
|
|
|
<style lang="scss" scoped> |
|
.banner { |
|
width: 100%; |
|
height: 350px; |
|
padding: 120px 0 0 20%; |
|
color: #fff; |
|
background-size: 100% 350px; |
|
background-repeat: no-repeat; |
|
} |
|
.l-title { |
|
font-size: 18px; |
|
} |
|
.main .center-con { |
|
background: url(../../../assets/img/match-bg1.png) (0px 95px) / auto auto no-repeat, |
|
url(../../../assets/img/match-bg2.png) (98% 300px) / auto auto no-repeat; |
|
} |
|
.main .center-wrap { |
|
margin-top: 30px; |
|
} |
|
.rule-title { |
|
margin-bottom: 10px; |
|
font-size: 16px; |
|
} |
|
.rule { |
|
padding: 15px; |
|
margin-bottom: 15px; |
|
border: 1px solid #dfdfdf; |
|
p { |
|
font-size: 14px; |
|
line-height: 30px; |
|
color: #6e6e6e; |
|
} |
|
} |
|
/deep/.el-tabs__item { |
|
box-shadow: none !important; |
|
} |
|
.content { |
|
position: relative; |
|
padding: 20px 40px; |
|
margin-top: 30px; |
|
background-color: #fff; |
|
.title { |
|
width: 67%; |
|
margin: 0 auto; |
|
font-size: 28px; |
|
text-align: center; |
|
color: #0b1d30; |
|
} |
|
.tool { |
|
z-index: 100; |
|
position: sticky; |
|
top: 64px; |
|
margin-bottom: 20px; |
|
background-color: #fff; |
|
&.logView { |
|
z-index: 0; |
|
} |
|
} |
|
.info .meta { |
|
padding: 16px 0; |
|
font-size: 12px; |
|
color: #999; |
|
text-align: center; |
|
} |
|
.action { |
|
display: inline-flex; |
|
align-items: center; |
|
} |
|
.sign-status { |
|
margin-bottom: 10px; |
|
text-align: center; |
|
font-size: 14px; |
|
color: $main-color; |
|
&.signing { |
|
color: $main-color; |
|
} |
|
&.signed { |
|
color: #52c41a; |
|
} |
|
&.playing { |
|
color: #f96d6d; |
|
} |
|
&:last-child { |
|
margin-bottom: 0; |
|
} |
|
} |
|
.status { |
|
max-width: 120px; |
|
padding: 0 16px; |
|
line-height: 34px; |
|
font-size: 14px; |
|
color: #fff; |
|
background-color: #52c41a; |
|
border-radius: 4px; |
|
cursor: pointer; |
|
@include ellipsis(); |
|
&.wait { |
|
background-color: #faad14; |
|
} |
|
&.signing { |
|
background-color: $main-color; |
|
} |
|
&.signed { |
|
background-color: #52c41a; |
|
} |
|
&.playing { |
|
background-color: #f96d6d; |
|
} |
|
&.finish { |
|
background-color: #ccc; |
|
} |
|
} |
|
.end-text { |
|
font-size: 12px; |
|
color: #666; |
|
em { |
|
font-style: normal; |
|
color: #f00; |
|
} |
|
} |
|
.texts { |
|
margin: 20px 0 50px; |
|
font-size: 14px; |
|
line-height: 1.6; |
|
text-indent: 2em; |
|
overflow: hidden; |
|
/deep/img { |
|
max-width: 100%; |
|
} |
|
} |
|
.progress { |
|
position: relative; |
|
width: 95%; |
|
padding: 50px 0; |
|
margin: 40px auto 80px; |
|
text-align: left; |
|
&:before { |
|
content: ''; |
|
position: absolute; |
|
top: 0; |
|
left: 50%; |
|
width: 2px; |
|
height: 100%; |
|
background-color: #e1e6f2; |
|
} |
|
&:after { |
|
content: ''; |
|
position: absolute; |
|
top: -10px; |
|
left: 430px; |
|
border: 8px solid transparent; |
|
border-bottom-color: #e1e6f2; |
|
} |
|
.rocket { |
|
position: absolute; |
|
bottom: -50px; |
|
left: 425px; |
|
} |
|
li { |
|
position: relative; |
|
width: 400px; |
|
margin-bottom: 42px; |
|
.dot { |
|
position: absolute; |
|
top: 12px; |
|
left: 431px; |
|
width: 15px; |
|
height: 15px; |
|
background-color: #dcdcdc; |
|
border-radius: 50%; |
|
} |
|
.name { |
|
display: inline-block; |
|
padding: 0 19px; |
|
margin-bottom: 16px; |
|
line-height: 40px; |
|
text-align: center; |
|
font-size: 16px; |
|
color: #fff; |
|
border-radius: 20px; |
|
background-color: #c4c4c4; |
|
} |
|
.desc { |
|
position: relative; |
|
color: #333; |
|
font-size: 14px; |
|
} |
|
&.ing, |
|
&.done { |
|
.dot { |
|
top: 8px; |
|
background-color: #007eff; |
|
} |
|
.name { |
|
background-color: #007eff; |
|
} |
|
} |
|
&.ing { |
|
.dot { |
|
width: 27px; |
|
height: 27px; |
|
border: 6px solid #e2f1fb; |
|
} |
|
} |
|
&:nth-child(odd) { |
|
text-align: right; |
|
&.ing { |
|
.dot { |
|
left: auto; |
|
right: -51px; |
|
} |
|
} |
|
.name { |
|
&:before { |
|
content: ''; |
|
z-index: 2; |
|
position: absolute; |
|
top: 14px; |
|
right: -35px; |
|
border: 18px solid transparent; |
|
border-top-width: 6px; |
|
border-bottom-width: 6px; |
|
border-left-color: #c4c4c4; |
|
} |
|
} |
|
.desc { |
|
text-align: right; |
|
} |
|
&.ing, |
|
&.done { |
|
.name { |
|
&:before { |
|
border-left-color: #007eff; |
|
} |
|
} |
|
} |
|
} |
|
&:nth-child(even) { |
|
margin-left: 482px; |
|
.dot { |
|
left: -51px; |
|
} |
|
&.ing { |
|
.dot { |
|
left: -57px; |
|
} |
|
} |
|
.name { |
|
text-align: left; |
|
&:after { |
|
content: ''; |
|
z-index: 2; |
|
position: absolute; |
|
top: 14px; |
|
left: -35px; |
|
border: 18px solid transparent; |
|
border-top-width: 6px; |
|
border-bottom-width: 6px; |
|
border-right-color: #c4c4c4; |
|
} |
|
} |
|
.desc { |
|
&:before { |
|
left: auto; |
|
right: -16px; |
|
border: 8px solid transparent; |
|
border-left-color: #fff; |
|
} |
|
&:after { |
|
left: auto; |
|
right: -18px; |
|
border: 9px solid transparent; |
|
border-left-color: #e6e6e6; |
|
} |
|
} |
|
|
|
&.ing, |
|
&.done { |
|
.name { |
|
&:after { |
|
border-right-color: #007eff; |
|
} |
|
} |
|
} |
|
} |
|
&:last-child { |
|
margin-bottom: 0; |
|
} |
|
} |
|
} |
|
} |
|
.files { |
|
margin-bottom: 30px; |
|
li { |
|
display: flex; |
|
align-items: center; |
|
margin: 10px 0; |
|
} |
|
.fileName { |
|
margin-right: 10px; |
|
font-size: 12px; |
|
} |
|
} |
|
.notice-list { |
|
text-align: left; |
|
li { |
|
padding: 16px; |
|
margin-bottom: 12px; |
|
transition: all 0.3s; |
|
cursor: pointer; |
|
border-radius: 6px; |
|
background-color: #fff; |
|
border-bottom: 1px dashed #ebebeb; |
|
&:last-child { |
|
border-bottom: 0; |
|
} |
|
} |
|
h6 { |
|
font-size: 20px; |
|
font-weight: 500; |
|
color: #0b1d30; |
|
&:hover { |
|
color: #007eff; |
|
} |
|
} |
|
.meta { |
|
margin: 10px 0; |
|
font-size: 14px; |
|
color: #666; |
|
} |
|
.des { |
|
font-size: 14px; |
|
color: #333; |
|
line-height: 24px; |
|
display: -webkit-box; |
|
display: -moz-box; |
|
-webkit-box-orient: vertical; |
|
-moz-box-orient: vertical; |
|
-webkit-line-clamp: 2; |
|
-moz-line-clamp: 2; |
|
overflow: hidden; |
|
text-overflow: ellipsis; |
|
} |
|
} |
|
.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; |
|
} |
|
/deep/.dia-form { |
|
.w-100 { |
|
width: 100%; |
|
} |
|
.tips { |
|
display: flex; |
|
justify-content: center; |
|
align-items: center; |
|
} |
|
} |
|
/deep/.file-upload { |
|
.el-upload__tip { |
|
color: #727272; |
|
} |
|
.el-progress { |
|
white-space: nowrap; |
|
} |
|
.download { |
|
position: absolute; |
|
bottom: -25px; |
|
right: 0; |
|
font-size: 12px; |
|
color: #007eff; |
|
cursor: pointer; |
|
} |
|
.el-upload-list__item { |
|
width: 70%; |
|
&:first-child { |
|
margin-top: 5px; |
|
} |
|
} |
|
} |
|
</style> |