学生端的创业活动复制到教师端

Branch_d40a2540
yujialong 2 years ago
parent 93c7304222
commit 747726392c
  1. 4
      src/api/index.js
  2. BIN
      src/assets/img/activity-bg.jpg
  3. BIN
      src/assets/img/match-bg3.png
  4. BIN
      src/assets/img/match-bg4.png
  5. BIN
      src/assets/img/match-bg5.png
  6. 75
      src/components/breadcrumb/index.vue
  7. 570
      src/pages/activity/add/index.vue
  8. 776
      src/pages/activity/details/index.vue
  9. 974
      src/pages/activity/list/index.vue
  10. 622
      src/pages/activity/manage/add/index.vue
  11. 123
      src/pages/activity/manage/index.vue
  12. 433
      src/pages/activity/manage/list/index.vue
  13. 129
      src/pages/activity/manage/manage/index.vue
  14. 0
      src/pages/activity/manage/manage/matchProgress.vue
  15. 224
      src/pages/activity/manage/manage/matchSignup.vue
  16. 0
      src/pages/activity/manage/manage/notice.vue
  17. 318
      src/pages/activity/manage/manage/noticeDetail.vue
  18. 174
      src/pages/activity/manage/matchSignup.vue
  19. 307
      src/pages/activity/manage/noticeDetail.vue
  20. 563
      src/pages/activity/manage/preview/index.vue
  21. 170
      src/pages/activity/noticeDetail/index.vue
  22. 527
      src/pages/activity/preview/index.vue
  23. 503
      src/pages/course/preview/index.vue
  24. 5
      src/pages/product/list/index.vue
  25. 20
      src/pages/product/show/index.vue
  26. 27
      src/router/modules/activity.js
  27. 567
      src/styles/common.scss

@ -329,13 +329,15 @@ export default {
// 创业活动 // 创业活动
activityList: `occupationlab/occupationlab/activity/activityList`, activityList: `occupationlab/occupationlab/activity/activityList`,
schoolActivities: `occupationlab/occupationlab/activity/schoolActivities`,
batchDeletionActivity: `occupationlab/occupationlab/activity/batchDeletion`, batchDeletionActivity: `occupationlab/occupationlab/activity/batchDeletion`,
disabledEventsActivity: `occupationlab/occupationlab/activity/disabledEvents`, disabledEventsActivity: `occupationlab/occupationlab/activity/disabledEvents`,
findByIdActivity: `occupationlab/occupationlab/activity/findById`, findByIdActivity: `occupationlab/occupationlab/activity/findById`,
getRedisCacheActivity: `occupationlab/occupationlab/activity/getRedisCache`, getRedisCacheActivity: `occupationlab/occupationlab/activity/getRedisCache`,
saveActivity: `occupationlab/occupationlab/activity/save`, saveActivity: `occupationlab/occupationlab/activity/save`,
updateActivity: `occupationlab/occupationlab/activity/update`, updateActivity: `occupationlab/occupationlab/activity/update`,
delActivityApplicant: `occupationlab/occupationlab/activity/applicant/batchDeletion`, myActivities: `occupationlab/occupationlab/activity/myActivities`,
delActivityApplicant: `occupationlab/occupationlab/activity/applicant/delete`,
findByIdActivityApplicant: `occupationlab/occupationlab/activity/applicant/findById`, findByIdActivityApplicant: `occupationlab/occupationlab/activity/applicant/findById`,
saveActivityApplicant: `occupationlab/occupationlab/activity/applicant/save`, saveActivityApplicant: `occupationlab/occupationlab/activity/applicant/save`,
updateActivityApplicant: `occupationlab/occupationlab/activity/applicant/update`, updateActivityApplicant: `occupationlab/occupationlab/activity/applicant/update`,

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 389 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

@ -3,15 +3,13 @@
<div class="breadcrumb"> <div class="breadcrumb">
<el-breadcrumb separator=">"> <el-breadcrumb separator=">">
<template v-for="(item, index) in pages"> <template v-for="(item, index) in pages">
<el-breadcrumb-item <el-breadcrumb-item v-if="index != pages.length - 1"
v-if="index != pages.length - 1" :key="index"
:key="index" :to="{ path: route, query }">
:to="{ path: route, query }">
{{item}} {{item}}
</el-breadcrumb-item> </el-breadcrumb-item>
<el-breadcrumb-item <el-breadcrumb-item v-else
v-else :key="index">
:key="index">
{{item}} {{item}}
</el-breadcrumb-item> </el-breadcrumb-item>
</template> </template>
@ -21,44 +19,45 @@
<script> <script>
export default { export default {
props: { props: {
data: { data: {
type: String, type: String,
required: true required: true
},
route: {
type: String,
default: 'list'
},
query: {
type: Object
}
}, },
data() { route: {
return { type: String,
pages: this.data.split('/') default: 'list'
};
}, },
methods: { query: {
update(data){ type: Object
this.pages = data.split('/')
}
} }
},
data () {
return {
pages: this.data.split('/')
};
},
methods: {
update (data) {
this.pages = data.split('/')
}
}
}; };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.breadcrumb { .breadcrumb {
margin: 4px 0 16px; margin: 4px 0 16px;
/deep/.el-breadcrumb__item { /deep/.el-breadcrumb__item {
.is-link, .el-breadcrumb__separator { .is-link,
font-weight: 400; .el-breadcrumb__separator {
color: #007EFF; font-weight: 400;
color: #9278ff;
}
&:last-child {
.is-link {
color: #0b1d30;
}
}
} }
&:last-child {
.is-link {
color: #0B1D30;
}
}
}
} }
</style> </style>

@ -1,570 +0,0 @@
<template>
<div>
<el-card v-if="!id" shadow="hover" class="m-b-20">
<div class="flex-between">
<el-page-header @back="back" :content="'创建项目'"></el-page-header>
</div>
</el-card>
<div class="page">
<div class="page-content">
<el-form label-width="170px" label-suffix=":" size="small">
<el-form-item label="项目封面(选填)">
<el-upload
class="avatar-uploader"
accept=".jpg,.png,.jpeg,.gif"
:on-success="uploadSuccess"
:action="this.api.fileupload"
:headers="headers"
:limit="1"
:on-exceed="handleExceed"
:before-remove="beforeRemove"
:on-remove="handleRemove"
:on-error="uploadError"
name="file"
>
<img v-if="form.coverUrl" :src="form.coverUrl" class="avatar">
<div class="uploader-default" v-else>
<i class="el-icon-plus"></i>
<p>上传封面</p>
</div>
<div slot="tip" class="el-upload__tip">
<p>展示宽度为220高度140JPG/PNG/GIF3MB以内</p>
</div>
</el-upload>
</el-form-item>
<el-form-item label="项目封面长图(选填)">
<el-upload
class="avatar-uploader avatar-uploader-lg"
accept=".jpg,.png,.jpeg,.gif"
:on-success="uploadLgSuccess"
:action="this.api.fileupload"
:headers="headers"
:limit="1"
:on-exceed="handleExceed"
:before-remove="beforeRemove"
:on-remove="handleCarouselRemove"
:on-error="uploadError"
name="file"
>
<img v-if="form.carouselUrl" :src="form.carouselUrl" class="avatar-lg">
<div class="uploader-default" v-else>
<i class="el-icon-plus"></i>
<p>上传封面</p>
</div>
<div slot="tip" class="el-upload__tip">
<p>展示宽度为1920高度300JPG/PNG/GIF3MB以内</p>
</div>
</el-upload>
</el-form-item>
<el-form-item class="req" label="项目名称">
<div class="d-inline-block">
<el-input placeholder="请输入项目名称" v-model="form.projectName" clearable></el-input>
</div>
</el-form-item>
<el-form-item class="req" label="发起方">
<div class="inline-input">
<div class="input-wrap" v-for="(item,index) in sponsorList" :key="index">
<el-input placeholder="发起方名称" v-model="sponsorList[index]"></el-input>
<i v-if="sponsorList.length > 1" class="remove" @click="delSponsor(index)"></i>
<button v-if="index == 0" class="add-btn" type="button" @click="addSponsor">
<i class="el-icon-plus"></i>
<span>添加</span>
</button>
</div>
</div>
</el-form-item>
<el-form-item class="req" label="报名时间">
<el-date-picker v-model="signupTime" value-format="yyyy-MM-dd HH:mm:ss" type="datetimerange"
range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"
:picker-options="pickerOptions"></el-date-picker>
</el-form-item>
<el-form-item class="req" label="项目时间">
<el-date-picker v-model="playTime" value-format="yyyy-MM-dd HH:mm:ss" type="datetimerange"
range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"
:picker-options="pickerOptions"></el-date-picker>
</el-form-item>
<el-form-item class="req" label="发布范围">
<div>
<el-radio v-model="scope" :label="0" disabled>本校内</el-radio>
</div>
</el-form-item>
<el-form-item class="req" label="报名人数上限">
<div class="input-center">
<el-input placeholder="请输入人数" v-model.number="form.maximumNumber" type="number"></el-input>
</div>
</el-form-item>
<el-form-item class="req" label="报名邀请码">
<div class="input-center" style="width: 550px;">
<el-radio v-model="form.isNeedCode" :label="0">不需要</el-radio>
<el-radio v-model="form.isNeedCode" :label="1">需要</el-radio>
<el-input style="width: 250px" placeholder="请输入4位邀请码或点击随机生成" v-model="form.invitationCode" :disabled="form.isNeedCode === 0"></el-input>
<el-button v-if="form.isNeedCode === 1" @click="randomInv">随机</el-button>
</div>
</el-form-item>
<el-form-item class="req" label="项目详情">
<quill ref="quill" :border="true" v-model="form.projectDescribe" :height="400" />
</el-form-item>
<el-form-item label="附件">
<el-upload
:on-remove="handleAnnexRemove"
:on-error="uploadError"
:before-upload="beforeUpload"
:on-success="uploadAnnexSuccess"
:on-exceed="handleExceedAnnex"
:limit="5"
:action="this.api.fileupload"
:headers="headers"
:file-list="form.activityFileList"
name="file"
>
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">
<p>支持扩展名.rar .zip .doc .docx .pdf .jpg...</p>
</div>
</el-upload>
</el-form-item>
</el-form>
<div class="btns">
<el-button @click="save(0)">保存</el-button>
<el-button type="primary" @click="save(1)">发布</el-button>
<el-button type="danger" @click="preview">预览</el-button>
<el-button @click="back">取消</el-button>
</div>
</div>
</div>
</div>
</template>
<script>
import util from "@/libs/util";
import quill from "@/components/quill";
import Setting from "@/setting";
export default {
data() {
return {
id: this.$route.query.id || '',
headers: {
token: util.local.get(Setting.tokenKey)
},
scope: 0,
form: {
id: this.$route.query.id || '',
founder: 1,
isOpen: 0, // (0 1 0)
maximumNumber: '',
carouselUrl: '',
coverUrl: '',
activityFileList: [], //
initiator: '',
isNeedCode: 0,
invitationCode: '',
maximumNumber: 0,
signUpStartTime: '',
signUpEndTime: '',
playStartTime: '',
playEndTime: '',
projectDescribe: '',
projectName: '',
publishStatus: 0,
},
pickerOptions: {
disabledDate: time => {
return this.$route.query.id ? false : time.getTime() < new Date().getTime() - 86400000;
}
},
fileName: '',
signupTime: [],
playTime: [],
sponsorList: [""],
fileList: [],
submiting: false,
pass: false,
updateTime: 0,
};
},
components: {
quill,
},
watch: {
// ,
form: {
handler(){
this.updateTime++
},
deep:true
},
signupTime: function(val) {
const { form } = this
if (val) {
form.signUpStartTime = val[0];
form.signUpEndTime = val[1];
} else {
form.signUpStartTime = ''
form.signUpEndTime = ''
}
},
playTime: function(val) {
const { form } = this
if (val) {
form.playStartTime = val[0]
form.playEndTime = val[1]
} else {
form.playStartTime = ''
form.playEndTime = ''
}
}
},
//
beforeRouteLeave(to, from, next) {
if (this.submiting) {
next()
} else if (!this.pass) {
//
if (this.updateTime) {
this.$confirm(`所填写内容暂未保存,是否保存?`, '提示', {
type: 'warning'
}).then(() => {
this.save(this.form.publishStatus)
}).catch(() => {
next()
})
} else {
next()
}
} else {
next()
}
},
mounted() {
this.getData()
},
methods: {
getData() {
const { id } = this.form
id && this.$post(`${this.api.findByIdActivity}?id=${id}`).then(({ data }) => {
if (data.signUpStartTime) this.signupTime = [data.signUpStartTime, data.signUpEndTime]
if (data.playStartTime) this.playTime = [data.playStartTime, data.playEndTime]
this.sponsorList = data.initiator.split(",")
//
const fileList = data.activityFileList
if (fileList) {
fileList.map(e => {
e.name = e.fileName
e.url = e.filePath
})
} else {
data.activityFileList = []
}
this.form = data
this.$nextTick(() => {
this.updateTime = 0
})
}).catch(err => {})
},
handleExceed(files, fileList) {
util.warningMsg(`当前限制选择 1 个文件,如需更换,请删除上一个文件再重新选择!`);
},
beforeRemove(file, fileList) {
return this.$confirm(`确定移除 ${file.name}`);
},
handleRemove(file, fileList) {
this.form.coverUrl = ''
},
handleCarouselRemove(file, fileList) {
this.form.carouselUrl = ''
},
uploadError(err, file, fileList) {
this.$message({
message: "上传出错,请重试!",
type: "error",
center: true
})
},
uploadSuccess(res) {
this.form.coverUrl = res.data.filesResult.fileUrl
},
uploadLgSuccess(res) {
this.form.carouselUrl = res.data.filesResult.fileUrl
},
//
uploadAnnexSuccess(res) {
const file = res.data.filesResult
const url = file.fileUrl || file.fileId
const data = {
activityId: this.form.id || '',
fileName: this.fileName,
name: this.fileName,
filePath: url,
url
}
this.form.activityFileList.push(data)
},
handleExceedAnnex(files, fileList) {
util.warningMsg(`当前限制选择 5 个文件,如需更换,请删除一个文件再重新选择!`);
},
//
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
}
},
handleAnnexRemove(file, fileList) {
this.form.activityFileList = fileList
},
//
randomInv() {
let result = ''
for (let i = 0; i < 4; i++) {
result += Math.floor(Math.random() * 10);
}
this.form.invitationCode = result
},
//
save(status) {
const { form } = this
form.initiator = this.sponsorList.filter(d => d).join();
if (!form.projectName) return util.warningMsg("请填写项目名称");
//
if (status) {
if (!form.initiator) return util.warningMsg("请填写发起方");
if (!form.signUpStartTime) return util.warningMsg("请选择报名时间");
let now = new Date().getTime();
let signUpStartTime = new Date(form.signUpStartTime).getTime();
let signUpEndTime = new Date(form.signUpEndTime).getTime();
let playStartTime = new Date(form.playStartTime).getTime();
// if (signUpStartTime && now > signUpStartTime) return util.warningMsg("");
if (!form.playStartTime) return util.warningMsg("请选择项目时间");
if (playStartTime && signUpEndTime && playStartTime < signUpEndTime) return util.warningMsg("项目时间不能早于报名结束时间");
if (form.isNeedCode && (!form.invitationCode || form.invitationCode.length !== 4)) return util.warningMsg('请填写四位数邀请码')
if (!form.projectDescribe) return util.warningMsg("请填写项目详情");
}
form.publishStatus = status
form.id = this.$route.query.id
if (this.submiting) return false
this.submiting = true
if (form.id) {
this.$post(this.api.updateActivity, form).then(res => {
this.backList()
util.successMsg("修改成功");
}).catch(err => {
this.submiting = false
});
} else {
this.$post(this.api.saveActivity, form).then(res => {
this.backList()
util.successMsg("创建成功");
}).catch(err => {
this.submiting = false
});
}
},
//
preview() {
util.local.set('activity', this.form)
window.open(this.$router.resolve('preview').href)
},
addSponsor() {
this.sponsorList.push("");
},
delSponsor(index) {
this.sponsorList.splice(index, 1);
},
backList() {
this.pass = true
this.updateTime = 0
this.$router.push(`/activity?page=${this.$store.state.activity.page}`)
},
back() {
this.pass = true
//
if (this.updateTime) {
this.$confirm(`编辑的内容未保存,是否保存?`, '提示', {
type: 'warning'
}).then(() => {
this.save(this.form.publishStatus)
}).catch(() => {
this.backList()
})
} else {
this.backList()
}
},
}
};
</script>
<style scoped lang="scss">
$upload-width: 220px;
$upload-height: 140px;
$upload-lg-height: 150px;
/deep/ .avatar-uploader {
.el-upload {
position: relative;
width: $upload-width;
height: $upload-height;
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
overflow: hidden;
&:hover {
border-color: #cb221c;
}
.uploader-default {
display: flex;
height: $upload-height;
flex-direction: column;
justify-content: center;
text-align: center;
background: rgba(0, 0, 0, 0.04);
i {
font-size: 20px;
font-weight: bold;
color: #8c939d;
}
p {
margin-top: 10px;
font-size: 14px;
color: rgba(0, 0, 0, 0.65);
line-height: 1;
}
}
}
&.avatar-uploader-lg {
.el-upload {
width: 100%;
max-width: 960px;
height: $upload-lg-height;
.uploader-default {
height: $upload-lg-height;
}
}
}
.avatar {
display: block;
width: $upload-width;
height: $upload-height;
}
.avatar-lg {
display: block;
width: 100%;
height: $upload-lg-height;
}
.el-upload__tip {
margin-top: 0;
p {
font-size: 14px;
color: rgba(0, 0, 0, 0.45);
line-height: 1;
&:first-child {
margin-bottom: 5px;
}
}
}
}
/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;
}
}
.add-btn {
display: flex;
justify-content: center;
align-items: center;
width: 216px;
line-height: 32px;
font-size: 14px;
color: rgba(0, 0, 0, 0.65);
background-color: transparent;
border: 1px dashed rgba(0, 0, 0, 0.15);
border-radius: 4px;
cursor: pointer;
i {
margin-right: 8px;
font-size: 14px;
font-weight: bold;
}
}
.range-check {
display: inline-block;
margin: 0 0 10px 10px;
}
/deep/.range-cas {
.el-tag {
display: none;
}
}
.input-center {
display: flex;
align-items: center;
width: 216px;
white-space: nowrap;
.el-input {
margin-right: 5px;
}
}
.el-steps {
justify-content: center;
}
/deep/.req {
.el-form-item__label {
&:before {
content: '*';
margin-right: 5px;
font-size: 18px;
vertical-align: middle;
color: #f00;
}
}
}
.btns {
display: flex;
justify-content: center;
text-align: center;
}
</style>

@ -0,0 +1,776 @@
<template>
<div class="wrap index">
<div class="banner"
:style="{backgroundImage: 'url(' + (form.carouselUrl || 'https://huoran.oss-cn-shenzhen.aliyuncs.com/20230515/jpg/1658017103770836992.jpg') + ')'}">创业活动详情</div>
<div class="center-con">
<div class="center-wrap">
<breadcrumb ref="breadcrumb"
:data="'全部项目/' + form.projectName"></breadcrumb>
<div class="content">
<div class="tool flex-between">
<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>
<a class="status"
:class="{wait: status == 0,signing: status == 2,signed: status == 1,finish: status == 3 || status == 4}"
:title="statusList[status]"
@click.stop="signup">{{ statusList[status] }}</a>
</div>
</div>
<div class="info"
id="part1">
<h6 class="title">{{ form.projectName }}</h6>
<div class="meta">最近编辑时间{{ form.updateTime }}</div>
</div>
<div v-show="curType < 4">
<div class="l-title"><img src="@/assets/img/label.png"
alt=""> 项目信息</div>
<div v-if="form.projectDescribe"
class="texts ql-editor"
v-html="form.projectDescribe"></div>
<template v-if="form.activityFileList">
<h6 class="p-title">附件下载</h6>
<ul class="files">
<li v-for="(item, i) in form.activityFileList"
: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>
<!-- 进展 -->
<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>
</div>
</div>
</div>
<el-dialog title="报名"
:visible.sync="signupVisible"
:close-on-click-modal="false"
width="300px">
<el-form class="dia-form">
<el-form-item>
<el-input placeholder="请输入4位数大赛邀请码"
maxlength="4"
v-model="invitationCode"></el-input>
</el-form-item>
</el-form>
<span slot="footer"
class="dialog-footer">
<el-button size="small"
type="primary"
@click="signupSubmit">报名</el-button>
<el-button size="small"
@click="signupVisible = 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'
export default {
name: 'matchdetail',
data () {
return {
token: util.local.get(Setting.tokenKey),
id: +this.$route.query.id,
end: '',
status: '',
statusList: ["待报名", "取消报名", "马上报名", "报名截止", "已结束"],
endList: ["报名开始", "报名截止", "报名截止", "项目开始", "项目结束"],
form: {
founder: 1,
isOpen: 0, // (0 1 0)
maximumNumber: '',
carouselUrl: '',
coverUrl: '',
activityFileList: [], //
initiator: '',
isNeedCode: 0,
maximumNumber: 0,
signUpStartTime: '',
signUpEndTime: '',
playStartTime: '',
playEndTime: '',
projectDescribe: '',
projectName: '',
publishStatus: 0,
},
curType: '1',
typeList: [
{
id: '1',
name: '项目信息'
},
{
id: '2',
name: '项目进展'
},
{
id: '3',
name: '通知公告'
},
],
progress: [],
timer: null,
notices: [],
noticeDetail: {},
signupVisible: false,
invitationCode: ''
};
},
components: {
breadcrumb
},
mounted () {
this.$once('hook:beforeDestroy', function () {
clearInterval(this.timer)
})
this.getData()
this.getProgress()
this.getNotice()
},
methods: {
getData () { //
clearInterval(this.timer)
this.$post(`${this.api.findByIdActivity}?id=${this.id}`).then(({ data }) => {
const list = data.activityFileList
//
if (list) {
list.map(e => {
const { filePath } = e
e.canPreview = util.canPreview(filePath.substr(filePath.lastIndexOf('.') + 1))
})
}
this.form = data
this.$refs.breadcrumb.update('全部项目/' + data.projectName)
this.handleStatus()
}).catch(err => { })
},
//
handleStatus () {
const { form } = this
let total = ''
let time = ''
let status = ''
let signUpStartTime = new Date(form.signUpStartTime) //
let signUpEndTime = new Date(form.signUpEndTime) //
let playStartTime = new Date(form.playStartTime) //
let playEndTime = new Date(form.playEndTime) //
this.timer = setInterval(() => {
const now = new Date()
if (now < signUpStartTime) { //
status = 0
total = signUpStartTime - now
} else if (now > signUpStartTime && now < signUpEndTime) { //
status = this.form.whetherToSignUp === undefined ? 2 : 1 // 12
total = signUpEndTime - now
} else if (now > signUpEndTime && now < playStartTime) { // ,
status = 3
total = playStartTime - now
} else if (now > playEndTime) { //
status = 4
}
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 = `${util.formateTime(hours)}:${util.formateTime(minutes)}:${util.formateTime(seconds)}`
if (total > 0) this.end = time
} else if (this.status === 4) { //
clearInterval(this.timer)
}
}, 1000)
},
getProgress () { //
this.$get(this.api.listActivityProgress, {
activityId: this.id
}).then(res => {
this.progress = res.activityProgressList.reverse()
}).catch(err => { });
},
//
getNotice () {
this.$post(`${this.api.listActivityAnnouncement}?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 () {
document.querySelector(`#part${this.curType}`).scrollIntoView()
},
//
toNotice (item) {
this.$router.push(`notice?id=${item.id}&matchId=${this.id}&name=${this.form.projectName}&end=${this.end}&status=${this.status}`)
},
//
toReport (row) {
this.$router.push(`/record/show?reportId=${row.reportId}&matchId=${this.id}&matchName=${this.form.name}`)
},
//
signupSubmit () {
this.$post(this.api.saveActivityApplicant, {
activityId: this.id,
registrationInvitationCode: this.invitationCode
}).then(res => {
this.signupVisible = false
this.getData()
this.$message.success('报名成功')
}).catch(res => { })
},
//
signup () {
const { status, id } = this
if (status == 2) { // //
if (this.form.isNeedCode) {
this.invitationCode = ''
this.signupVisible = true
} else {
this.$post(this.api.saveActivityApplicant, {
activityId: id
}).then(res => {
this.getData()
this.$message.success('报名成功')
}).catch(res => { })
}
} else if (status == 1) {
//
this.$confirm('是否要取消报名?', '提示', {
type: 'success'
}).then(() => {
this.$post(`${this.api.delActivityApplicant}?id=${this.form.cancelId}`).then(res => {
this.getData()
this.$message.success('取消报名成功')
}).catch(res => { })
}).catch(() => { })
}
},
// 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', escape(form.systemName))
util.cookies.set('systemId', form.systemId)
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('fromManager', '', -1)
// 8pythoncookiesystemId
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, projectId, cid, stageId } = 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://120.78.139.126:8879?systemId=${systemId}&courseId=${cid}&projectId=${projectId}&token=${token}&userId=${this.userId}&classId=1&competitionId=${competitionId}&stageId=${stageId}&teamId=${teamId}`);
} else {
// python
this.toPython(this.curProject)
}
}
}
};
</script>
<style lang="scss" scoped>
.wrap {
margin: -24px;
}
.banner {
width: 100%;
height: 350px;
padding: 120px 0 0 24%;
font-size: 34px;
font-weight: 600;
color: #fff;
background-size: 100% 100%;
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 {
width: 1000px;
margin: 30px auto 0;
}
.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;
}
.info .meta {
padding: 16px 0;
font-size: 12px;
color: #999;
text-align: center;
}
.action {
display: inline-flex;
align-items: center;
}
.status {
max-width: 120px;
padding: 0 16px;
margin-left: 20px;
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;
}
}
</style>

File diff suppressed because it is too large Load Diff

@ -0,0 +1,622 @@
<template>
<div>
<el-card v-if="!id"
shadow="hover"
class="m-b-20">
<div class="flex-between">
<el-page-header @back="back"
:content="'创建项目'"></el-page-header>
</div>
</el-card>
<div class="page">
<div class="page-content">
<el-form label-width="170px"
label-suffix=":"
size="small">
<el-form-item label="项目封面(选填)">
<el-upload class="avatar-uploader"
accept=".jpg,.png,.jpeg,.gif"
:on-success="uploadSuccess"
:action="this.api.fileupload"
:headers="headers"
:limit="1"
:on-exceed="handleExceed"
:before-remove="beforeRemove"
:on-remove="handleRemove"
:on-error="uploadError"
name="file">
<img v-if="form.coverUrl"
:src="form.coverUrl"
class="avatar">
<div class="uploader-default"
v-else>
<i class="el-icon-plus"></i>
<p>上传封面</p>
</div>
<div slot="tip"
class="el-upload__tip">
<p>展示宽度为220高度140JPG/PNG/GIF3MB以内</p>
</div>
</el-upload>
</el-form-item>
<el-form-item label="项目封面长图(选填)">
<el-upload class="avatar-uploader avatar-uploader-lg"
accept=".jpg,.png,.jpeg,.gif"
:on-success="uploadLgSuccess"
:action="this.api.fileupload"
:headers="headers"
:limit="1"
:on-exceed="handleExceed"
:before-remove="beforeRemove"
:on-remove="handleCarouselRemove"
:on-error="uploadError"
name="file">
<img v-if="form.carouselUrl"
:src="form.carouselUrl"
class="avatar-lg">
<div class="uploader-default"
v-else>
<i class="el-icon-plus"></i>
<p>上传封面</p>
</div>
<div slot="tip"
class="el-upload__tip">
<p>展示宽度为1920高度300JPG/PNG/GIF3MB以内</p>
</div>
</el-upload>
</el-form-item>
<el-form-item class="req"
label="项目名称">
<div class="d-inline-block">
<el-input placeholder="请输入项目名称"
v-model="form.projectName"
clearable></el-input>
</div>
</el-form-item>
<el-form-item class="req"
label="发起方">
<div class="inline-input">
<div class="input-wrap"
v-for="(item,index) in sponsorList"
:key="index">
<el-input placeholder="发起方名称"
v-model="sponsorList[index]"></el-input>
<i v-if="sponsorList.length > 1"
class="remove"
@click="delSponsor(index)"></i>
<button v-if="index == 0"
class="add-btn"
type="button"
@click="addSponsor">
<i class="el-icon-plus"></i>
<span>添加</span>
</button>
</div>
</div>
</el-form-item>
<el-form-item class="req"
label="报名时间">
<el-date-picker v-model="signupTime"
value-format="yyyy-MM-dd HH:mm:ss"
type="datetimerange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:picker-options="pickerOptions"></el-date-picker>
</el-form-item>
<el-form-item class="req"
label="项目时间">
<el-date-picker v-model="playTime"
value-format="yyyy-MM-dd HH:mm:ss"
type="datetimerange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:picker-options="pickerOptions"></el-date-picker>
</el-form-item>
<el-form-item class="req"
label="发布范围">
<div>
<el-radio v-model="scope"
:label="0"
disabled>本校内</el-radio>
</div>
</el-form-item>
<el-form-item class="req"
label="报名人数上限">
<div class="input-center">
<el-input placeholder="请输入人数"
v-model.number="form.maximumNumber"
type="number"></el-input>
</div>
</el-form-item>
<el-form-item class="req"
label="报名邀请码">
<div class="input-center"
style="width: 550px;">
<el-radio v-model="form.isNeedCode"
:label="0">不需要</el-radio>
<el-radio v-model="form.isNeedCode"
:label="1">需要</el-radio>
<el-input style="width: 250px"
placeholder="请输入4位邀请码或点击随机生成"
v-model="form.invitationCode"
:disabled="form.isNeedCode === 0"></el-input>
<el-button v-if="form.isNeedCode === 1"
@click="randomInv">随机</el-button>
</div>
</el-form-item>
<el-form-item class="req"
label="项目详情">
<quill ref="quill"
:border="true"
v-model="form.projectDescribe"
:height="400" />
</el-form-item>
<el-form-item label="附件">
<el-upload :on-remove="handleAnnexRemove"
:on-error="uploadError"
:before-upload="beforeUpload"
:on-success="uploadAnnexSuccess"
:on-exceed="handleExceedAnnex"
:limit="5"
:action="this.api.fileupload"
:headers="headers"
:file-list="form.activityFileList"
name="file">
<el-button size="small"
type="primary">点击上传</el-button>
<div slot="tip"
class="el-upload__tip">
<p>支持扩展名.rar .zip .doc .docx .pdf .jpg...</p>
</div>
</el-upload>
</el-form-item>
</el-form>
<div class="btns">
<el-button @click="save(0)">保存</el-button>
<el-button type="primary"
@click="save(1)">发布</el-button>
<el-button type="danger"
@click="preview">预览</el-button>
<el-button @click="back">取消</el-button>
</div>
</div>
</div>
</div>
</template>
<script>
import util from "@/libs/util";
import quill from "@/components/quill";
import Setting from "@/setting";
export default {
data () {
return {
id: this.$route.query.id || '',
headers: {
token: util.local.get(Setting.tokenKey)
},
scope: 0,
form: {
id: this.$route.query.id || '',
founder: 1,
isOpen: 0, // (0 1 0)
maximumNumber: '',
carouselUrl: '',
coverUrl: '',
activityFileList: [], //
initiator: '',
isNeedCode: 0,
invitationCode: '',
maximumNumber: 0,
signUpStartTime: '',
signUpEndTime: '',
playStartTime: '',
playEndTime: '',
projectDescribe: '',
projectName: '',
publishStatus: 0,
},
pickerOptions: {
disabledDate: time => {
return this.$route.query.id ? false : time.getTime() < new Date().getTime() - 86400000;
}
},
fileName: '',
signupTime: [],
playTime: [],
sponsorList: [""],
fileList: [],
submiting: false,
pass: false,
updateTime: 0,
};
},
components: {
quill,
},
watch: {
// ,
form: {
handler () {
this.updateTime++
},
deep: true
},
signupTime: function (val) {
const { form } = this
if (val) {
form.signUpStartTime = val[0];
form.signUpEndTime = val[1];
} else {
form.signUpStartTime = ''
form.signUpEndTime = ''
}
},
playTime: function (val) {
const { form } = this
if (val) {
form.playStartTime = val[0]
form.playEndTime = val[1]
} else {
form.playStartTime = ''
form.playEndTime = ''
}
}
},
//
beforeRouteLeave (to, from, next) {
if (this.submiting) {
next()
} else if (!this.pass) {
//
if (this.updateTime) {
this.$confirm(`所填写内容暂未保存,是否保存?`, '提示', {
type: 'warning'
}).then(() => {
this.save(this.form.publishStatus)
}).catch(() => {
next()
})
} else {
next()
}
} else {
next()
}
},
mounted () {
this.getData()
},
methods: {
getData () {
const { id } = this.form
id && this.$post(`${this.api.findByIdActivity}?id=${id}`).then(({ data }) => {
if (data.signUpStartTime) this.signupTime = [data.signUpStartTime, data.signUpEndTime]
if (data.playStartTime) this.playTime = [data.playStartTime, data.playEndTime]
this.sponsorList = data.initiator.split(",")
//
const fileList = data.activityFileList
if (fileList) {
fileList.map(e => {
e.name = e.fileName
e.url = e.filePath
})
} else {
data.activityFileList = []
}
this.form = data
this.$nextTick(() => {
this.updateTime = 0
})
}).catch(err => { })
},
handleExceed (files, fileList) {
util.warningMsg(`当前限制选择 1 个文件,如需更换,请删除上一个文件再重新选择!`);
},
beforeRemove (file, fileList) {
return this.$confirm(`确定移除 ${file.name}`);
},
handleRemove (file, fileList) {
this.form.coverUrl = ''
},
handleCarouselRemove (file, fileList) {
this.form.carouselUrl = ''
},
uploadError (err, file, fileList) {
this.$message({
message: "上传出错,请重试!",
type: "error",
center: true
})
},
uploadSuccess (res) {
this.form.coverUrl = res.data.filesResult.fileUrl
},
uploadLgSuccess (res) {
this.form.carouselUrl = res.data.filesResult.fileUrl
},
//
uploadAnnexSuccess (res) {
const file = res.data.filesResult
const url = file.fileUrl || file.fileId
const data = {
activityId: this.form.id || '',
fileName: this.fileName,
name: this.fileName,
filePath: url,
url
}
this.form.activityFileList.push(data)
},
handleExceedAnnex (files, fileList) {
util.warningMsg(`当前限制选择 5 个文件,如需更换,请删除一个文件再重新选择!`);
},
//
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
}
},
handleAnnexRemove (file, fileList) {
this.form.activityFileList = fileList
},
//
randomInv () {
let result = ''
for (let i = 0; i < 4; i++) {
result += Math.floor(Math.random() * 10);
}
this.form.invitationCode = result
},
//
save (status) {
const { form } = this
form.initiator = this.sponsorList.filter(d => d).join();
if (!form.projectName) return util.warningMsg("请填写项目名称");
//
if (status) {
if (!form.initiator) return util.warningMsg("请填写发起方");
if (!form.signUpStartTime) return util.warningMsg("请选择报名时间");
let now = new Date().getTime();
let signUpStartTime = new Date(form.signUpStartTime).getTime();
let signUpEndTime = new Date(form.signUpEndTime).getTime();
let playStartTime = new Date(form.playStartTime).getTime();
// if (signUpStartTime && now > signUpStartTime) return util.warningMsg("");
if (!form.playStartTime) return util.warningMsg("请选择项目时间");
if (playStartTime && signUpEndTime && playStartTime < signUpEndTime) return util.warningMsg("项目时间不能早于报名结束时间");
if (form.isNeedCode && (!form.invitationCode || form.invitationCode.length !== 4)) return util.warningMsg('请填写四位数邀请码')
if (!form.projectDescribe) return util.warningMsg("请填写项目详情");
}
form.publishStatus = status
form.id = this.$route.query.id
if (this.submiting) return false
this.submiting = true
if (form.id) {
this.$post(this.api.updateActivity, form).then(res => {
this.backList()
util.successMsg("修改成功");
}).catch(err => {
this.submiting = false
});
} else {
this.$post(this.api.saveActivity, form).then(res => {
this.backList()
util.successMsg("创建成功");
}).catch(err => {
this.submiting = false
});
}
},
//
preview () {
util.local.set('activity', this.form)
window.open(this.$router.resolve('preview').href)
},
addSponsor () {
this.sponsorList.push("");
},
delSponsor (index) {
this.sponsorList.splice(index, 1);
},
backList () {
this.pass = true
this.updateTime = 0
this.$router.back()
},
back () {
this.pass = true
//
if (this.updateTime) {
this.$confirm(`编辑的内容未保存,是否保存?`, '提示', {
type: 'warning'
}).then(() => {
this.save(this.form.publishStatus)
}).catch(() => {
this.backList()
})
} else {
this.backList()
}
},
}
};
</script>
<style scoped lang="scss">
$upload-width: 220px;
$upload-height: 140px;
$upload-lg-height: 150px;
/deep/ .avatar-uploader {
.el-upload {
position: relative;
width: $upload-width;
height: $upload-height;
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
overflow: hidden;
&:hover {
border-color: #cb221c;
}
.uploader-default {
display: flex;
height: $upload-height;
flex-direction: column;
justify-content: center;
text-align: center;
background: rgba(0, 0, 0, 0.04);
i {
font-size: 20px;
font-weight: bold;
color: #8c939d;
}
p {
margin-top: 10px;
font-size: 14px;
color: rgba(0, 0, 0, 0.65);
line-height: 1;
}
}
}
&.avatar-uploader-lg {
.el-upload {
width: 100%;
max-width: 960px;
height: $upload-lg-height;
.uploader-default {
height: $upload-lg-height;
}
}
}
.avatar {
display: block;
width: $upload-width;
height: $upload-height;
}
.avatar-lg {
display: block;
width: 100%;
height: $upload-lg-height;
}
.el-upload__tip {
margin-top: 0;
p {
font-size: 14px;
color: rgba(0, 0, 0, 0.45);
line-height: 1;
&:first-child {
margin-bottom: 5px;
}
}
}
}
/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;
}
}
.add-btn {
display: flex;
justify-content: center;
align-items: center;
width: 216px;
line-height: 32px;
font-size: 14px;
color: rgba(0, 0, 0, 0.65);
background-color: transparent;
border: 1px dashed rgba(0, 0, 0, 0.15);
border-radius: 4px;
cursor: pointer;
i {
margin-right: 8px;
font-size: 14px;
font-weight: bold;
}
}
.range-check {
display: inline-block;
margin: 0 0 10px 10px;
}
/deep/.range-cas {
.el-tag {
display: none;
}
}
.input-center {
display: flex;
align-items: center;
width: 216px;
white-space: nowrap;
.el-input {
margin-right: 5px;
}
}
.el-steps {
justify-content: center;
}
/deep/.req {
.el-form-item__label {
&:before {
content: '*';
margin-right: 5px;
font-size: 18px;
vertical-align: middle;
color: #f00;
}
}
}
.btns {
display: flex;
justify-content: center;
text-align: center;
}
</style>

@ -1,123 +0,0 @@
<template>
<!-- 赛事管理 -->
<div>
<el-card shadow="hover" class="m-b-20">
<div class="flex-between">
<el-page-header @back="back" :content="name + '/管理'"></el-page-header>
</div>
</el-card>
<div class="page" style="margin-bottom: 24px">
<div class="tabs">
<a class="item" v-for="(item,index) in tabs" :key="index" :class="{active: index == active}" @click="tabChange(index)">{{ item }}</a>
</div>
<MatchDetail v-if="active == 'tab1'" ref="detail" />
<MatchProgress v-else-if="active == 'tab2'" />
<notice v-else-if="active == 'tab3'" />
<MatchSignup v-else-if="active == 'tab4'" />
</div>
</div>
</template>
<script>
import Setting from "@/setting";
import MatchDetail from "../add";
import MatchProgress from "./matchProgress";
import notice from "./notice";
import MatchSignup from "./matchSignup";
import { mapState } from "vuex";
export default {
data() {
return {
name: this.$route.query.name,
active: this.$route.query.tab || "tab1",
tabs: {
tab1: "项目详情",
tab2: "项目进展",
tab3: "公告通知",
tab4: "报名人员"
},
};
},
components: {
MatchDetail,
MatchProgress,
notice,
MatchSignup
},
computed: {
...mapState("user", [
'page'
]),
...mapState('auth', [
'btns'
])
},
beforeRouteLeave(to, from, next) {
const detail = this.$refs.detail
if (detail && detail.updateTime) {
this.$confirm(`编辑的内容未保存,是否保存并且发布?`, '提示.......', {
type: 'warning'
}).then(() => {
detail.save(detail.form.publishStatus)
}).catch(() => {
next()
})
} else {
next()
}
},
mounted() {
},
methods: {
back() {
this.handleSave(0) && this.backPage()
},
// confirm
handleSave(i) {
//
if (this.active === 'tab1') {
const detail = this.$refs.detail
if (detail && detail.updateTime) {
this.$confirm(`编辑的内容未保存,是否保存并且发布?`, '提示', {
type: 'warning'
}).then(() => {
detail.save(detail.form.publishStatus)
this.backOrTab(i)
}).catch(() => {
this.backOrTab(i)
})
} else {
this.backOrTab(i)
}
return false
} else {
return true
}
},
//
backPage(){
console.log(444, this.$store.state)
this.$router.push(`/activity?page=${this.$store.state.activity.page}`)
},
// tab
tabSwitch(i) {
this.active = i
this.$router.push(`/activity/manage?id=${this.$route.query.id}&tab=${i}&name=${this.name}`)
},
// tab
backOrTab(i) {
i ? this.tabSwitch(i) : this.backPage()
},
// tab
tabChange(i) {
this.handleSave(i) && this.tabSwitch(i)
}
}
};
</script>
<style scoped>
</style>

@ -0,0 +1,433 @@
<template>
<div>
<el-card shadow="hover"
class="m-b-20">
<div class="flex-between">
<el-page-header @back="$router.push('/activity/list')"
content="管理项目"></el-page-header>
</div>
</el-card>
<div class="page">
<h6 class="p-title">筛选</h6>
<div class="tool mul">
<ul class="filter">
<li>
<label>创建时间</label>
<div class="single-choice">
<dl>
<dd>
<el-radio-group v-model="form.month"
@change="initData">
<el-radio v-for="(item,index) in dateList"
:key="index"
:label="item.id"
border>{{ item.name }}</el-radio>
</el-radio-group>
</dd>
</dl>
</div>
</li>
<li>
<label>创建区间</label>
<el-date-picker v-model="date"
align="right"
unlink-panels
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
format="yyyy-MM-dd"
value-format="yyyy-MM-dd"
clearable></el-date-picker>
</li>
<li>
<label>搜索</label>
<el-input placeholder="请输入项目名称/创建人"
suffix-icon="el-icon-search"
v-model="keyword"
clearable></el-input>
</li>
</ul>
</div>
<div class="tool mul">
<ul class="filter">
<li>
<label>状态</label>
<dl>
<dd>
<el-radio-group v-model="form.publishStatus"
@change="initData">
<el-radio v-for="(item,index) in statuses"
:key="index"
:label="item.id"
border>{{ item.name }}</el-radio>
</el-radio-group>
</dd>
</dl>
</li>
<li>
<label>来源</label>
<el-select v-model="form.founder"
@change="initData">
<el-option v-for="(item, i) in founders"
:key="i"
:label="item.name"
:value="item.id"></el-option>
</el-select>
</li>
</ul>
<div>
<el-button type="primary"
round
@click="add"
v-auth="'/activity/list:创建项目'">创建项目</el-button>
<el-button type="primary"
round
@click="delAllSelection"
v-auth="'/activity/list:批量删除'">批量删除</el-button>
</div>
</div>
<el-table ref="table"
:data="activityData"
class="table"
stripe
header-align="center"
@selection-change="handleSelectionChange"
row-key="id">
<el-table-column type="selection"
width="55"
align="center"
:reserve-selection="true"></el-table-column>
<el-table-column type="index"
width="60"
label="序号"
align="center">
<template slot-scope="scope">
{{ scope.$index + (page - 1) * pageSize + 1 }}
</template>
</el-table-column>
<el-table-column prop="projectName"
label="项目名称"
align="center"></el-table-column>
<el-table-column prop="applicantNum"
label="报名人数"
align="center"
width="150"></el-table-column>
<el-table-column prop="status"
label="状态"
align="center"
width="90">
<template slot-scope="scope">
{{ scope.row.publishStatus ? '已发布' : '未发布' }}
</template>
</el-table-column>
<el-table-column prop="time"
label="项目时间"
align="center"
width="300">
<template slot-scope="scope">
{{ scope.row.playStartTime }} ~ {{ scope.row.playEndTime }}
</template>
</el-table-column>
<el-table-column prop="createTime"
label="创建时间"
align="center"
width="160"></el-table-column>
<el-table-column prop="founderName"
label="创建人"
align="center"
width="130">
<template slot-scope="scope">
{{ scope.row.founderName || '学校超管' }}
</template>
</el-table-column>
<el-table-column label="操作"
align="center"
width="170">
<template slot-scope="scope">
<el-button v-auth="'/activity/list:管理'"
type="text"
@click="manage(scope.row)">管理</el-button>
<el-button v-auth="'/activity/list:删除'"
type="text"
@click="delData(scope.row)">删除</el-button>
<el-switch v-if="scope.row.publishStatus"
v-auth="'/activity/list:禁用'"
v-model="scope.row.schoolOpen"
:active-value="0"
:inactive-value="1"
style="margin: 0 10px 0 5px"
:active-text="scope.row.schoolOpen ? '关' : '开'"
@change="switchOff($event,scope.row,scope.$index)"></el-switch>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination background
layout="total, prev, pager, next"
:total="total"
@current-change="handleCurrentChange"
:current-page="page">
</el-pagination>
</div>
</div>
</div>
</template>
<script>
import util from "@/libs/util";
import Setting from "@/setting";
import { mapMutations } from "vuex";
import { Loading } from 'element-ui'
export default {
data () {
return {
timer: null,
keyword: "",
activityData: [],
statuses: [
{
id: '',
name: '不限'
},
{
id: 0,
name: '待发布'
},
{
id: 1,
name: '已发布'
}
],
founders: [
{
id: '',
name: '不限'
},
{
id: 1,
name: '老师'
},
{
id: 2,
name: '学生'
}
],
form: {
month: "",
publishStatus: "",
startTime: "",
endTime: "",
founder: ''
},
multipleSelection: [],
dateList: [
{
id: "",
name: "不限"
},
{
id: 1,
name: "近一个月"
},
{
id: 3,
name: "近三个月"
},
{
id: 6,
name: "近六个月"
}
],
date: [],
page: +this.$route.query.page || 1,
pageSize: 10,
total: 0,
transferPublishStatus: ["未发布", "已发布"],
modifyVisible: false,
curRow: {
playingStages: []
},
timer: null,
redisTimer: null,
pickerOptions: {
shortcuts: [{
text: '此刻',
onClick (picker) {
picker.$emit('pick', new Date(Date.now() + 5000))
}
}]
}
};
},
watch: {
"form.month": function (val) {
if (val) {
let unit = 24 * 60 * 60 * 1000;
this.date = [util.formatDate("yyyy-MM-dd", new Date(new Date().getTime() - unit * 30 * val)), util.formatDate("yyyy-MM-dd", new Date(new Date().getTime() + unit))];
} else {
this.date = [];
}
},
date: function (val) {
if (val) {
this.form.startTime = val[0];
this.form.endTime = val[1];
} else {
this.form.startTime = "";
this.form.endTime = "";
}
this.initData();
},
keyword: function (val) {
clearTimeout(this.searchTimer);
this.searchTimer = setTimeout(() => {
this.initData();
}, 500);
}
},
mounted () {
this.getData()
this.$once('hook:beforeDestroy', function () {
clearInterval(this.timer)
clearInterval(this.redisTimer)
})
},
methods: {
...mapMutations('activity', [
'setPage'
]),
getList () {
// const load = Loading.service()
const { form } = this
this.$post(this.api.activityList, {
pageNum: this.page,
pageSize: this.pageSize,
endTime: form.endTime || null,
keyWords: this.keyword || null,
platformSource: 1, // (0:1 2)
startTime: form.startTime || null,
publishStatus: form.publishStatus === '' ? null : form.publishStatus,
founder: form.founder
}).then(({ data }) => {
// load.close()
this.activityData = data.records
this.total = data.total
this.$refs.table.clearSelection()
if (!this.activityData.length && this.total) {
this.page--
this.getData()
}
}).catch(res => {
// load.close()
})
},
getData () {
this.getList()
},
initData () {
this.page = 1;
this.getData();
},
// redis
getRedis () {
this.$post(this.api.getRedisCacheActivity).then(({ data }) => {
if (data) {
localStorage.getItem('activityTimestamp') !== data && this.getList() // redis
localStorage.setItem('activityTimestamp', data)
}
}).catch(res => { })
},
getData () {
this.getList()
// if (!Setting.isDev) {
clearInterval(this.redisTimer)
this.redisTimer = setInterval(this.getRedis, 1000)
// }
},
add () {
this.$router.push("add");
},
manage (row) {
this.$router.push(`manageDetail?id=${row.id}&name=${row.projectName}`)
},
delData (row) {
this.$confirm("此删除操作不可逆,是否确认删除选中项?", "提示", {
type: "warning"
})
.then(() => {
this.$post(this.api.batchDeletionActivity, [row.id]).then(res => {
util.successMsg("删除成功");
this.getData();
}).catch(res => {
});
})
.catch(() => {
});
},
handleSelectionChange (val) {
this.multipleSelection = val;
},
//
delAllSelection () {
if (this.multipleSelection.length) {
this.$confirm("确定要删除吗?", "提示", {
type: "warning"
}).then(() => {
let ids = this.multipleSelection.map(e => e.id);
this.$post(this.api.batchDeletionActivity, this.multipleSelection.map(e => e.id)).then(res => {
this.getData();
this.$message.success("删除成功");
this.$refs.table.clearSelection()
}).catch(err => {
});
}).catch(() => {
});
} else {
this.$message.warning("请先选择项目 !");
}
},
handleCurrentChange (val) {
this.page = val;
this.$router.push(`list?page=${val}`)
this.getData()
this.setPage(val)
},
transferTime (date, type) {
if (date == "0000-00-00 00:00:00") return "---";
return date;
},
switchOff (val, row) {
this.$post(this.api.disabledEventsActivity, {
activityId: row.id,
isOpen: val,
type: 1 // (01 2.)
}).then(res => { }).catch(err => {
row.schoolOpen = val ? 0 : 1
})
},
}
};
</script>
<style lang="scss" scoped>
/deep/ .tool {
.filter {
.el-input {
min-width: 190px;
}
}
}
@media (max-width: 1640px) {
.page .page-content .tool .filter {
flex-wrap: wrap;
margin-bottom: -15px;
li {
min-width: 34%;
margin-bottom: 15px;
}
}
}
</style>

@ -0,0 +1,129 @@
<template>
<!-- 赛事管理 -->
<div>
<el-card shadow="hover"
class="m-b-20">
<div class="flex-between">
<el-page-header @back="back"
:content="name + '/管理'"></el-page-header>
</div>
</el-card>
<div class="page"
style="margin-bottom: 24px">
<div class="tabs">
<a class="item"
v-for="(item,index) in tabs"
:key="index"
:class="{active: index == active}"
@click="tabChange(index)">{{ item }}</a>
</div>
<MatchDetail v-if="active == 'tab1'"
ref="detail" />
<MatchProgress v-else-if="active == 'tab2'" />
<notice v-else-if="active == 'tab3'" />
<MatchSignup v-else-if="active == 'tab4'" />
</div>
</div>
</template>
<script>
import Setting from "@/setting";
import MatchDetail from "../add";
import MatchProgress from "./matchProgress";
import notice from "./notice";
import MatchSignup from "./matchSignup";
import { mapState } from "vuex";
export default {
data () {
return {
name: this.$route.query.name,
active: this.$route.query.tab || "tab1",
tabs: {
tab1: "项目详情",
tab2: "项目进展",
tab3: "公告通知",
tab4: "报名人员"
},
};
},
components: {
MatchDetail,
MatchProgress,
notice,
MatchSignup
},
computed: {
...mapState("user", [
'page'
]),
...mapState('auth', [
'btns'
])
},
beforeRouteLeave (to, from, next) {
const detail = this.$refs.detail
if (detail && detail.updateTime) {
this.$confirm(`编辑的内容未保存,是否保存并且发布?`, '提示.......', {
type: 'warning'
}).then(() => {
detail.save(detail.form.publishStatus)
}).catch(() => {
next()
})
} else {
next()
}
},
mounted () {
},
methods: {
back () {
this.handleSave(0) && this.backPage()
},
// confirm
handleSave (i) {
//
if (this.active === 'tab1') {
const detail = this.$refs.detail
if (detail && detail.updateTime) {
this.$confirm(`编辑的内容未保存,是否保存并且发布?`, '提示', {
type: 'warning'
}).then(() => {
detail.save(detail.form.publishStatus)
this.backOrTab(i)
}).catch(() => {
this.backOrTab(i)
})
} else {
this.backOrTab(i)
}
return false
} else {
return true
}
},
//
backPage () {
this.$router.push(`/activity/manage?page=${this.$store.state.activity.page}`)
},
// tab
tabSwitch (i) {
this.active = i
this.$router.push(`manageDetail?id=${this.$route.query.id}&tab=${i}&name=${this.name}`)
},
// tab
backOrTab (i) {
i ? this.tabSwitch(i) : this.backPage()
},
// tab
tabChange (i) {
this.handleSave(i) && this.tabSwitch(i)
}
}
};
</script>
<style scoped>
</style>

@ -0,0 +1,224 @@
<template>
<!-- 报名人员 -->
<div class="page-content"
style="padding: 24px">
<div class="tool">
<ul class="filter">
<li>
<label>搜索</label>
<el-input placeholder="请输入姓名/手机号/学号"
prefix-icon="el-icon-search"
v-model="keyword"
clearable
size="mini"
style="width: 250px"></el-input>
</li>
<li>
<label>报名人员状态</label>
<el-select v-model="isDisable"
@change="initData">
<el-option v-for="(item, i) in statusList"
:key="i"
:label="item.name"
:value="item.id"></el-option>
</el-select>
</li>
</ul>
<div>
<el-button type="primary"
round
@click="exportAll">批量导出</el-button>
</div>
</div>
<el-table ref="table"
:data="listData"
class="table"
stripe
header-align="center"
@selection-change="handleSelectionChange"
row-key="id"
@sort-change="sortChange">
<el-table-column type="selection"
width="80"
align="center"
:reserve-selection="true"></el-table-column>
<el-table-column type="index"
width="60"
label="序号"
align="center">
<template slot-scope="scope">
{{ scope.$index + (page - 1) * pageSize + 1 }}
</template>
</el-table-column>
<el-table-column prop="schoolName"
label="学校"
sortable="custom">
</el-table-column>
<el-table-column prop="username"
label="姓名">
</el-table-column>
<el-table-column prop="workNumber"
label="学号/工号">
</el-table-column>
<el-table-column prop="phone"
label="手机号">
</el-table-column>
<el-table-column label="操作"
align="center"
width="320">
<template slot-scope="scope">
<el-button type="text"
@click="delData(scope.row)">删除</el-button>
<el-switch v-model="scope.row.isDisable"
:active-text="scope.row.isDisable ? '关' : '开'"
:active-value="0"
:inactive-value="1"
style="margin-left: 5px"
@change="switchOff($event,scope.row,scope.$index)"></el-switch>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination background
layout="total, prev, pager, next"
:total="total"
@current-change="handleCurrentChange"
:current-page="page">
</el-pagination>
</div>
</div>
</template>
<script>
import util from "@/libs/util";
import axios from 'axios'
import Setting from "@/setting";
export default {
name: "matchSignup",
data () {
return {
token: util.local.get(Setting.tokenKey),
id: +this.$route.query.id,
isDisable: '',
statusList: [
{
id: '',
name: '不限'
},
{
id: 1,
name: '已禁用'
},
{
id: 0,
name: '未禁用'
}
],
keyword: "",
listData: [],
multipleSelection: [],
page: 1,
pageSize: 10,
total: 0,
};
},
watch: {
keyword: function (val) {
clearTimeout(this.searchTimer);
this.searchTimer = setTimeout(() => {
this.initData();
}, 500);
}
},
mounted () {
this.initData()
},
methods: {
getData () {
this.$post(this.api.ApplicantsList, {
pageNum: this.page,
pageSize: this.pageSize,
activityId: this.id,
keyWords: this.keyword,
isDisable: this.isDisable,
}).then(({ data }) => {
this.listData = data.data.records;
this.total = data.data.total;
}).catch(res => {
});
},
initData () {
this.page = 1
this.getData()
},
handleSelectionChange (val) {
this.multipleSelection = val;
},
handleCurrentChange (val) {
this.page = val;
this.getData();
},
switchOff (val, row, index) {
this.$put(`${this.api.disableActivityApplicant}?competitionRegistrationId=${row.id}&isDisable=${val}`).then(res => { }).catch(err => { });
},
delData (row) {
this.$confirm("此删除操作不可逆,是否确认删除选中项?", "提示", {
type: "warning"
})
.then(() => {
this.$post(`${this.api.delActivityApplicant}?id=${row.id}`).then(res => {
util.successMsg("删除成功");
this.getData();
}).catch(res => {
});
})
.catch(() => {
});
},
//
sortChange (column) {
// 12
if (column.prop === 'school') this.schoolOrder = column.order ? column.order === 'ascending' ? 2 : 1 : ''
if (column.prop === 'teamName') this.teamOrder = column.order ? column.order === 'ascending' ? 2 : 1 : ''
this.getData()
},
exportAll () {
const data = this.multipleSelection
if (data.length) {
data.map((e, i) => e.id = i + 1)
axios.post(this.api.exportDataInBatchesApplicant, data, {
headers: {
token: this.token
},
responseType: 'blob'
}).then((res) => {
util.downloadFileDirect(`报名人员.xls`, new Blob([res.data]))
}).catch(res => { })
} else {
axios.get(`${this.api.excelExportApplicant}?activityId=${this.id}`, {
headers: {
token: this.token
},
responseType: 'blob'
}).then((res) => {
util.downloadFileDirect(`报名人员.xls`, new Blob([res.data]))
}).catch(res => { })
}
}
}
};
</script>
<style lang="scss" scoped>
/deep/.dia-form {
.w-100 {
width: 100%;
}
.tips {
display: flex;
justify-content: center;
align-items: center;
}
}
</style>

@ -0,0 +1,318 @@
<template>
<!-- 大赛详情 -->
<div>
<el-card shadow="hover"
style="margin-bottom: 20px">
<div class="flex-between">
<el-page-header @back="back"
:content="(form.id ? '编辑' : '创建') + '公告'"></el-page-header>
</div>
</el-card>
<div class="page">
<div class="page-content">
<el-form label-width="170px"
label-suffix=":"
size="small">
<el-form-item label="公告标题">
<div class="d-inline-block">
<el-input placeholder="请输入公告名称"
v-model="form.announcementTitle"
clearable></el-input>
</div>
</el-form-item>
<el-form-item label="正文">
<quill :border="true"
v-model="form.announcementText"
:height="400" />
</el-form-item>
<el-form-item label="附件">
<el-upload :on-remove="handleRemove"
:on-error="uploadError"
:on-success="uploadSuccess"
:before-upload="beforeUpload"
:before-remove="beforeRemove"
:limit="5"
:on-exceed="handleExceed"
:action="this.api.fileupload"
:headers="headers"
:file-list="fileList"
name="file">
<el-button size="small"
type="primary">点击上传</el-button>
<div slot="tip"
class="el-upload__tip">
<p>支持扩展名.rar .zip .doc .docx .pdf .jpg...</p>
</div>
</el-upload>
</el-form-item>
<el-form-item>
<el-button v-if="!form.id"
@click="save(0)">草稿</el-button>
<el-button type="primary"
@click="save(1)">发布</el-button>
<el-button @click="back">取消</el-button>
</el-form-item>
</el-form>
</div>
</div>
</div>
</template>
<script>
import quill from "@/components/quill";
import util from "@/libs/util";
import Setting from "@/setting";
export default {
name: "matchDetail",
data () {
return {
headers: {
token: util.local.get(Setting.tokenKey)
},
form: {
id: this.$route.query.id,
activityId: this.$route.query.activityId,
announcementText: '',
announcementTitle: '',
announcementAnnexList: [],
isOpen: 1
},
updateTime: 0,
fileName: '',
fileList: [],
};
},
components: {
quill
},
watch: {
// ,
form: {
handler () {
this.updateTime++
},
deep: true
},
},
mounted () {
this.form.id && this.getData()
},
methods: {
getData () {
this.$post(`${this.api.findActivityAnnouncement}?id=${this.form.id}`).then(({ data }) => {
this.form = data
//
const fileList = data.announcementAnnexList
if (fileList) {
const files = []
fileList.map(e => {
files.push({
name: e.fileName,
url: e.filePath
})
})
this.fileList = files
} else {
data.announcementAnnexList = []
}
}).catch(err => { })
},
//
save (status) {
const form = this.form
if (!form.announcementTitle) return util.warningMsg('请填写公告标题')
if (!form.announcementText) return util.warningMsg('请填写正文')
form.status = status
if (form.id) {
form.isOpen = 0
delete form.announcementAnnexList
this.$post(this.api.updateActivityAnnouncement, form).then(res => {
util.successMsg("修改成功")
this.$router.back()
}).catch(err => { })
} else {
form.isOpen = status ? 0 : 1
this.$post(this.api.addActivityAnnouncement, form).then(res => {
util.successMsg("创建成功")
this.$router.back()
}).catch(err => { })
}
},
handleExceed (files, fileList) {
util.warningMsg(`当前限制选择 1 个文件,如需更换,请删除上一个文件再重新选择!`);
},
//
uploadSuccess (res) {
const file = res.data.filesResult
const { id } = this.form
const data = {
announcementId: id || '',
fileName: this.fileName,
filePath: file.fileUrl || file.fileId
}
this.form.announcementAnnexList.push(data)
//
id && this.$post(this.api.saveActivityAnnouncementAnnex, data).then(res => { }).catch(res => { })
},
//
beforeUpload (file) {
this.fileName = file.name
},
uploadError (err, file, fileList) {
this.$message({
message: "上传出错,请重试!",
type: "error",
center: true
});
},
beforeRemove (file, fileList) {
return this.$confirm(`确定移除 ${file.name}`);
},
handleRemove (file, fileList) {
if (file.url) {
this.$del(`${this.api.fileDeletion}?keys=${file.url}`).then(res => { }).catch(res => { })
const id = this.form.announcementAnnexList.find(e => e.fileName === file.name).id
this.$post(`${this.api.delActivityAnnouncementAnnex}?id=${id}`).then(res => { }).catch(res => { })
}
},
back () {
this.$router.back()
}
}
};
</script>
<style scoped lang="scss">
$upload-width: 220px;
$upload-height: 140px;
$upload-lg-height: 150px;
/deep/ .avatar-uploader {
.el-upload {
position: relative;
width: $upload-width;
height: $upload-height;
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
overflow: hidden;
&:hover {
border-color: #cb221c;
}
.uploader-default {
display: flex;
height: $upload-height;
flex-direction: column;
justify-content: center;
text-align: center;
background: rgba(0, 0, 0, 0.04);
i {
font-size: 20px;
font-weight: bold;
color: #8c939d;
}
p {
margin-top: 10px;
font-size: 14px;
color: rgba(0, 0, 0, 0.65);
line-height: 1;
}
}
}
&.avatar-uploader-lg {
.el-upload {
width: 100%;
max-width: 960px;
height: $upload-lg-height;
.uploader-default {
height: $upload-lg-height;
}
}
}
.avatar {
display: block;
width: $upload-width;
height: $upload-height;
}
.avatar-lg {
display: block;
width: 100%;
height: $upload-lg-height;
}
.el-upload__tip {
margin-top: 0;
p {
font-size: 14px;
color: rgba(0, 0, 0, 0.45);
line-height: 1;
&:first-child {
margin-bottom: 5px;
}
}
}
}
/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;
}
}
.add-btn {
display: flex;
justify-content: center;
align-items: center;
width: 216px;
line-height: 32px;
font-size: 14px;
color: rgba(0, 0, 0, 0.65);
background-color: transparent;
border: 1px dashed rgba(0, 0, 0, 0.15);
border-radius: 4px;
cursor: pointer;
i {
margin-right: 8px;
font-size: 14px;
font-weight: bold;
}
}
</style>

@ -1,174 +0,0 @@
<template>
<!-- 报名人员 -->
<div class="page-content" style="padding: 24px">
<div class="tool">
<ul class="filter">
<li>
<label>搜索</label>
<el-input placeholder="请输入姓名/手机号/学号" prefix-icon="el-icon-search" v-model="keyword" clearable size="mini" style="width: 250px"></el-input>
</li>
<li>
<label>报名人员状态</label>
<el-select v-model="isDisable" @change="initData">
<el-option v-for="(item, i) in statusList" :key="i" :label="item.name" :value="item.id"></el-option>
</el-select>
</li>
</ul>
<div>
<el-button type="primary" round @click="exportAll">批量导出</el-button>
</div>
</div>
<el-table ref="table" :data="listData" class="table" stripe header-align="center" @selection-change="handleSelectionChange" row-key="id" @sort-change="sortChange">
<el-table-column type="selection" width="80" align="center" :reserve-selection="true"></el-table-column>
<el-table-column type="index" width="60" label="序号" align="center">
<template slot-scope="scope">
{{ scope.$index + (page - 1) * pageSize + 1 }}
</template>
</el-table-column>
<el-table-column prop="schoolName" label="学校" sortable="custom">
</el-table-column>
<el-table-column prop="username" label="学生姓名">
</el-table-column>
<el-table-column prop="workNumber" label="学号">
</el-table-column>
<el-table-column prop="phone" label="手机号">
</el-table-column>
<el-table-column label="操作" align="center" width="320">
<template slot-scope="scope">
<el-switch
v-model="scope.row.isDisable"
:active-text="scope.row.isDisable ? '关' : '开'"
:active-value="0"
:inactive-value="1"
style="margin: 0 10px 0 5px"
@change="switchOff($event,scope.row,scope.$index)"
></el-switch>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination background layout="total, prev, pager, next" :total="total" @current-change="handleCurrentChange" :current-page="page">
</el-pagination>
</div>
</div>
</template>
<script>
import util from "@/libs/util";
import axios from 'axios'
import Setting from "@/setting";
export default {
name: "matchSignup",
data() {
return {
token: util.local.get(Setting.tokenKey),
id: +this.$route.query.id,
isDisable: '',
statusList: [
{
id: '',
name: '不限'
},
{
id: 1,
name: '已禁用'
},
{
id: 0,
name: '未禁用'
}
],
keyword: "",
listData: [],
multipleSelection: [],
page: 1,
pageSize: 10,
total: 0,
};
},
watch: {
keyword: function(val) {
clearTimeout(this.searchTimer);
this.searchTimer = setTimeout(() => {
this.initData();
}, 500);
}
},
mounted() {
this.initData()
},
methods: {
getData() {
this.$post(this.api.ApplicantsList, {
pageNum: this.page,
pageSize: this.pageSize,
activityId: this.id,
keyWords: this.keyword,
isDisable: this.isDisable,
}).then(({ data }) => {
this.listData = data.data.records;
this.total = data.data.total;
}).catch(res => {
});
},
initData() {
this.page = 1
this.getData()
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
handleCurrentChange(val) {
this.page = val;
this.getData();
},
switchOff(val, row, index) {
this.$put(`${this.api.disableActivityApplicant}?competitionRegistrationId=${row.id}&isDisable=${val}`).then(res => {}).catch(err => {});
},
//
sortChange(column) {
// 12
if (column.prop === 'school') this.schoolOrder = column.order ? column.order === 'ascending' ? 2 : 1 : ''
if (column.prop === 'teamName') this.teamOrder = column.order ? column.order === 'ascending' ? 2 : 1 : ''
this.getData()
},
exportAll() {
const data = this.multipleSelection
if (data.length) {
data.map((e, i) => e.id = i + 1)
axios.post(this.api.exportDataInBatchesApplicant, data, {
headers: {
token: this.token
},
responseType: 'blob'
}).then((res) => {
util.downloadFileDirect(`报名人员.xls`, new Blob([res.data]))
}).catch(res => {})
} else {
axios.get(`${this.api.excelExportApplicant}?activityId=${this.id}`, {
headers: {
token: this.token
},
responseType: 'blob'
}).then((res) => {
util.downloadFileDirect(`报名人员.xls`, new Blob([res.data]))
}).catch(res => {})
}
}
}
};
</script>
<style lang="scss" scoped>
/deep/.dia-form {
.w-100 {
width: 100%;
}
.tips {
display: flex;
justify-content: center;
align-items: center;
}
}
</style>

@ -1,307 +0,0 @@
<template>
<!-- 大赛详情 -->
<div>
<el-card shadow="hover" style="margin-bottom: 20px">
<div class="flex-between">
<el-page-header @back="back" :content="(form.id ? '编辑' : '创建') + '公告'"></el-page-header>
</div>
</el-card>
<div class="page">
<div class="page-content">
<el-form label-width="170px" label-suffix=":" size="small">
<el-form-item label="公告标题">
<div class="d-inline-block">
<el-input placeholder="请输入公告名称" v-model="form.announcementTitle" clearable></el-input>
</div>
</el-form-item>
<el-form-item label="正文">
<quill :border="true" v-model="form.announcementText" :height="400" />
</el-form-item>
<el-form-item label="附件">
<el-upload
:on-remove="handleRemove"
:on-error="uploadError"
:on-success="uploadSuccess"
:before-upload="beforeUpload"
:before-remove="beforeRemove"
:limit="5"
:on-exceed="handleExceed"
:action="this.api.fileupload"
:headers="headers"
:file-list="fileList"
name="file"
>
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">
<p>支持扩展名.rar .zip .doc .docx .pdf .jpg...</p>
</div>
</el-upload>
</el-form-item>
<el-form-item>
<el-button v-if="!form.id" @click="save(0)">草稿</el-button>
<el-button type="primary" @click="save(1)">发布</el-button>
<el-button @click="back">取消</el-button>
</el-form-item>
</el-form>
</div>
</div>
</div>
</template>
<script>
import quill from "@/components/quill";
import util from "@/libs/util";
import Setting from "@/setting";
export default {
name: "matchDetail",
data() {
return {
headers: {
token: util.local.get(Setting.tokenKey)
},
form: {
id: this.$route.query.id,
activityId: this.$route.query.activityId,
announcementText: '',
announcementTitle: '',
announcementAnnexList: [],
isOpen: 1
},
updateTime: 0,
fileName: '',
fileList: [],
};
},
components: {
quill
},
watch: {
// ,
form: {
handler(){
this.updateTime++
},
deep:true
},
},
mounted() {
this.form.id && this.getData()
},
methods: {
getData() {
this.$post(`${this.api.findActivityAnnouncement}?id=${this.form.id}`).then(({ data }) => {
this.form = data
//
const fileList = data.announcementAnnexList
if (fileList) {
const files = []
fileList.map(e => {
files.push({
name: e.fileName,
url: e.filePath
})
})
this.fileList = files
} else {
data.announcementAnnexList = []
}
}).catch(err => {})
},
//
save(status) {
const form = this.form
if (!form.announcementTitle) return util.warningMsg('请填写公告标题')
if (!form.announcementText) return util.warningMsg('请填写正文')
form.status = status
if (form.id) {
form.isOpen = 0
delete form.announcementAnnexList
this.$post(this.api.updateActivityAnnouncement, form).then(res => {
util.successMsg("修改成功")
this.$router.back()
}).catch(err => {})
} else {
form.isOpen = status ? 0 : 1
this.$post(this.api.addActivityAnnouncement, form).then(res => {
util.successMsg("创建成功")
this.$router.back()
}).catch(err => {})
}
},
handleExceed(files, fileList) {
util.warningMsg(`当前限制选择 1 个文件,如需更换,请删除上一个文件再重新选择!`);
},
//
uploadSuccess(res) {
const file = res.data.filesResult
const { id } = this.form
const data = {
announcementId: id || '',
fileName: this.fileName,
filePath: file.fileUrl || file.fileId
}
this.form.announcementAnnexList.push(data)
//
id && this.$post(this.api.saveActivityAnnouncementAnnex, data).then(res => {}).catch(res => {})
},
//
beforeUpload(file) {
this.fileName = file.name
},
uploadError(err, file, fileList) {
this.$message({
message: "上传出错,请重试!",
type: "error",
center: true
});
},
beforeRemove(file, fileList) {
return this.$confirm(`确定移除 ${file.name}`);
},
handleRemove(file, fileList) {
if (file.url) {
this.$del(`${this.api.fileDeletion}?keys=${file.url}`).then(res => {}).catch(res => {})
const id = this.form.announcementAnnexList.find(e => e.fileName === file.name).id
this.$post(`${this.api.delActivityAnnouncementAnnex}?id=${id}`).then(res => {}).catch(res => {})
}
},
back() {
this.$router.back()
}
}
};
</script>
<style scoped lang="scss">
$upload-width: 220px;
$upload-height: 140px;
$upload-lg-height: 150px;
/deep/ .avatar-uploader {
.el-upload {
position: relative;
width: $upload-width;
height: $upload-height;
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
overflow: hidden;
&:hover {
border-color: #cb221c;
}
.uploader-default {
display: flex;
height: $upload-height;
flex-direction: column;
justify-content: center;
text-align: center;
background: rgba(0, 0, 0, 0.04);
i {
font-size: 20px;
font-weight: bold;
color: #8c939d;
}
p {
margin-top: 10px;
font-size: 14px;
color: rgba(0, 0, 0, 0.65);
line-height: 1;
}
}
}
&.avatar-uploader-lg {
.el-upload {
width: 100%;
max-width: 960px;
height: $upload-lg-height;
.uploader-default {
height: $upload-lg-height;
}
}
}
.avatar {
display: block;
width: $upload-width;
height: $upload-height;
}
.avatar-lg {
display: block;
width: 100%;
height: $upload-lg-height;
}
.el-upload__tip {
margin-top: 0;
p {
font-size: 14px;
color: rgba(0, 0, 0, 0.45);
line-height: 1;
&:first-child {
margin-bottom: 5px;
}
}
}
}
/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;
}
}
.add-btn {
display: flex;
justify-content: center;
align-items: center;
width: 216px;
line-height: 32px;
font-size: 14px;
color: rgba(0, 0, 0, 0.65);
background-color: transparent;
border: 1px dashed rgba(0, 0, 0, 0.15);
border-radius: 4px;
cursor: pointer;
i {
margin-right: 8px;
font-size: 14px;
font-weight: bold;
}
}
</style>

@ -0,0 +1,563 @@
<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.projectName"></breadcrumb>
<div class="content">
<div class="tool flex-between">
<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="status wait">等待报名</div>
</div>
<div class="info">
<h6 class="title">{{ form.projectName }}</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.projectDescribe"
class="texts ql-editor"
v-html="form.projectDescribe"></div>
<template v-if="form.activityFileList">
<h6 class="p-title">附件下载</h6>
<ul class="files">
<li v-for="(item, i) in form.activityFileList"
: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>
<!-- 进展 -->
<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>
</div>
</div>
</div>
</div>
</template>
<script>
import breadcrumb from '@/components/breadcrumb'
import util from '@/libs/util'
import Setting from "@/setting"
export default {
data () {
return {
form: util.local.get('activity'),
curType: '1',
typeList: [
{
id: '1',
name: '项目信息'
},
{
id: '2',
name: '项目进展'
},
{
id: '3',
name: '通知公告'
},
],
progress: [],
timer: null,
notices: [],
};
},
components: {
breadcrumb
},
mounted () {
if (this.form.id) {
this.getProgress()
this.getNotice()
}
},
methods: {
getProgress () { //
this.$get(this.api.listActivityProgress, {
activityId: this.form.id
}).then(res => {
this.progress = res.activityProgressList.reverse()
}).catch(err => { });
},
//
getNotice () {
this.$post(`${this.api.listActivityAnnouncement}?pageNum=1&pageSize=1000&competitionId=${this.form.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 () {
document.querySelector(`#part${type}`).scrollIntoView()
},
}
};
</script>
<style lang="scss" scoped>
.wrap {
margin: -24px;
}
.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 {
width: 1000px;
margin: 40px auto 0;
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;
}
.info .meta {
padding: 16px 0;
font-size: 12px;
color: #999;
text-align: center;
}
.action {
display: inline-flex;
align-items: center;
}
.status {
max-width: 120px;
padding: 0 16px;
margin-left: 20px;
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;
}
}
</style>

@ -0,0 +1,170 @@
<template>
<div class="wrap">
<div class="breadcrumb">
<el-breadcrumb separator=">">
<template v-for="(item, i) in breadPath">
<el-breadcrumb-item
v-if="!i"
:key="i"
:to="{ path: 'list' }">
{{item}}
</el-breadcrumb-item>
<el-breadcrumb-item
v-else-if="breadPath.length > 2 && i === 1"
:to="{ path: 'details', query: { end, status, id } }"
:key="i">
{{item}}
</el-breadcrumb-item>
<el-breadcrumb-item
v-else
:key="i">
{{item}}
</el-breadcrumb-item>
</template>
</el-breadcrumb>
</div>
<div class="page">
<h6 class="title">{{ form.announcementTitle }}</h6>
<div class="metas">
<span>{{ form.updateTime }}</span>
</div>
<div class="content ql-editor" v-html="form.announcementText"></div>
<template v-if="form.announcementAnnexList">
<h6 class="p-title">附件下载</h6>
<ul class="files">
<li v-for="(item, i) in form.announcementAnnexList" :key="i">
<el-link class="m-r-10" type="primary" @click="preview(item)">{{ item.fileName }}</el-link>
<el-link type="primary" :underline="false" @click="download(item)">下载</el-link>
</li>
</ul>
</template>
</div>
</div>
</template>
<script>
import { Loading } from 'element-ui';
import 'quill/dist/quill.core.css';
import 'quill/dist/quill.snow.css';
import 'quill/dist/quill.bubble.css';
import breadcrumb from '@/components/breadcrumb'
import util from '@/libs/util'
export default {
data() {
return {
id: this.$route.query.matchId,
end: this.$route.query.end,
status: this.$route.query.status,
breadPath: ['全部项目', this.$route.query.name],
form: {
id: this.$route.query.id,
announcementText: '',
announcementTitle: '',
announcementAnnexList: []
},
loadIns: null
}
},
components: {
breadcrumb
},
mounted() {
this.getData()
},
methods: {
//
getData() {
this.loadIns = Loading.service()
this.$post(`${this.api.findActivityAnnouncement}?id=${this.form.id}`).then(({ data }) => {
this.form = data
this.breadPath.push(data.announcementTitle)
this.loadIns.close()
}).catch(err => {
this.loadIns.close()
})
},
//
preview(item) {
const { filePath } = item
const suffix = filePath.substr(filePath.lastIndexOf('.') + 1)
window.open((util.isDoc(suffix) || suffix === 'pdf' ? 'https://view.officeapps.live.com/op/view.aspx?src=' : '') + item.filePath)
},
//
download(item) {
util.downloadFile(item.fileName, item.filePath)
}
}
};
</script>
<style lang="scss" scoped>
.breadcrumb {
margin: 4px 0 16px;
/deep/.el-breadcrumb__item {
.is-link, .el-breadcrumb__separator {
font-weight: 400;
color: $main-color;
}
&:last-child {
.is-link {
color: #0B1D30;
}
}
}
}
.wrap {
padding-bottom: 20px;
.title{
margin-top: 30px;
text-align: center;
font-size: 28px;
font-weight: 500;
color: #0B1D30;
}
.metas{
display: flex;
justify-content: center;
align-items: center;
padding-bottom: 32px;
margin: 16px 0 32px;
span{
display: inline-flex;
align-items: center;
color: #999;
font-size: 12px;
img{
width: 18px;
margin-right: 5px;
}
}
.el-divider {
margin: 0 16px;
}
}
.cover{
margin: 20px 0;
text-align: center;
img{
width: 800px;
}
}
.content{
margin-bottom: 20px;
line-height: 1.8;
font-size: 14px;
text-indent: 2em;
/deep/img{
max-width: 100%;
}
}
}
.files {
margin-bottom: 30px;
li {
display: flex;
align-items: center;
margin: 10px 0;
}
}
</style>

@ -1,527 +0,0 @@
<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.projectName"></breadcrumb>
<div class="content">
<div class="tool flex-between">
<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="status wait">等待报名</div>
</div>
<div class="info">
<h6 class="title">{{ form.projectName }}</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.projectDescribe" class="texts ql-editor" v-html="form.projectDescribe"></div>
<template v-if="form.activityFileList">
<h6 class="p-title">附件下载</h6>
<ul class="files">
<li v-for="(item, i) in form.activityFileList" :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>
<!-- 进展 -->
<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>
</div>
</div>
</div>
</div>
</template>
<script>
import breadcrumb from '@/components/breadcrumb'
import util from '@/libs/util'
import Setting from "@/setting"
export default {
data() {
return {
form: util.local.get('activity'),
curType: '1',
typeList: [
{
id: '1',
name: '项目信息'
},
{
id: '2',
name: '项目进展'
},
{
id: '3',
name: '通知公告'
},
],
progress: [],
timer: null,
notices: [],
};
},
components: {
breadcrumb
},
mounted() {
if (this.form.id) {
this.getProgress()
this.getNotice()
}
},
methods: {
getProgress() { //
this.$get(this.api.listActivityProgress, {
activityId: this.form.id
}).then(res => {
this.progress = res.activityProgressList.reverse()
}).catch(err => {});
},
//
getNotice() {
this.$post(`${this.api.listActivityAnnouncement}?pageNum=1&pageSize=1000&competitionId=${this.form.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() {
document.querySelector(`#part${type}`).scrollIntoView()
},
}
};
</script>
<style lang="scss" scoped>
.wrap {
margin: -24px;
}
.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 {
width: 1000px;
margin: 40px auto 0;
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;
}
.info .meta{
padding: 16px 0;
font-size: 12px;
color: #999;
text-align: center;
}
.action {
display: inline-flex;
align-items: center;
}
.status {
max-width: 120px;
padding: 0 16px;
margin-left: 20px;
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;
}
}
</style>

@ -1,76 +1,111 @@
<template> <template>
<!-- 课程预览 --> <!-- 课程预览 -->
<div> <div>
<el-card shadow="hover" class="m-b-20"> <el-card shadow="hover"
<div class="flex-between"> class="m-b-20">
<el-page-header @back="goBack" :content="'课程预览'"></el-page-header> <div class="flex-between">
<el-page-header @back="goBack"
:content="'课程预览'"></el-page-header>
</div>
</el-card>
<el-card shadow="hover"
class="m-b-20"
style="background: none;">
<div class="flex">
<div class="cover"
:class="{'is-word': showMask1}">
<img v-if="coverUrl"
:src="coverUrl"
alt=""
width="100%"
height="100%">
<template v-else-if="iframeSrc">
<iframe class="inner fileIframe"
id="fileIframe"
:src="iframeSrc"
frameborder="0"></iframe>
<template v-if="showMask">
<div class="mask"
style="width: 500px;height: 30px;top: 53px;right: 320px"></div>
<div class="mask"
style="width: 175px;height: 30px;top: 53px;right: 5px"></div>
</template>
<template v-if="showMask1">
<div class="word-mask"
style="height: 40px;"></div>
<div class="word-mask2"
style="top: 55px;left: 28%;width: 44%;height: calc(100% - 80px);"></div>
</template>
<template v-if="showMask2">
<div class="excel-mask1"
style="height: 48px;"></div>
</template>
</template>
<div class="pdf inner"
v-else-if="pdfSrc">
<p class="arrow">
<span @click="changePdfPage(0)"
class="turn el-icon-arrow-left"
:class="{grey: currentPage==1}"></span>
{{ currentPage }} / {{ pageCount }}
<span @click="changePdfPage(1)"
class="turn el-icon-arrow-right"
:class="{grey: currentPage==pageCount}"></span>
</p>
<pdf class="pdf-wrap"
:src="pdfSrc"
:page="currentPage"
@num-pages="pageCount=$event"
@page-loaded="currentPage=$event"
@loaded="loadPdfHandler">
</pdf>
</div>
<div class="inner"
v-else-if="playAuth">
<div class="video_wid"
id="player"></div>
</div>
</div>
<div class="catalog flex-1">
<div class="list">
<h4 class="title">{{ courseName }}</h4>
<div class="desc-wrap">
<div class="desc"
:class="{active: desShrink}"
v-html="description"></div>
<i class="arrow"
:class="{active: desShrink}"
v-if="description.length > 40">
<span>...</span>
<img src="@/assets/img/arrow-down.png"
alt=""
@click="desShrink = !desShrink">
</i>
</div> </div>
</el-card> <div class="chapters">
<template v-if="videoList.length">
<el-card shadow="hover" class="m-b-20" style="background: none;"> <div class="chapter"
<div class="flex"> v-for="(item,index) in videoList"
<div class="cover" :class="{'is-word': showMask1}"> :key="index">
<img v-if="coverUrl" :src="coverUrl" alt="" width="100%" height="100%"> <div class="chapterName">{{ item.name }}</div>
<template v-else-if="iframeSrc"> <div class="section"
<iframe class="inner fileIframe" id="fileIframe" :src="iframeSrc" frameborder="0"></iframe> v-if="item.subsectionList.length">
<template v-if="showMask"> <div v-for="(section,i) in item.subsectionList"
<div class="mask" style="width: 500px;height: 30px;top: 53px;right: 320px"></div> :key="i"
<div class="mask" style="width: 175px;height: 30px;top: 53px;right: 5px"></div> @click="preview(section, item.name)">
</template> <p class="sectionName"
<template v-if="showMask1"> :class="{active: curLink === `${item.name}${section.name}`}">{{ section.name }}</p>
<div class="word-mask" style="height: 40px;"></div>
<div class="word-mask2" style="top: 55px;left: 28%;width: 44%;height: calc(100% - 80px);"></div>
</template>
<template v-if="showMask2">
<div class="excel-mask1" style="height: 48px;"></div>
</template>
</template>
<div class="pdf inner" v-else-if="pdfSrc">
<p class="arrow">
<span @click="changePdfPage(0)" class="turn el-icon-arrow-left" :class="{grey: currentPage==1}"></span>
{{ currentPage }} / {{ pageCount }}
<span @click="changePdfPage(1)" class="turn el-icon-arrow-right" :class="{grey: currentPage==pageCount}"></span>
</p>
<pdf
class="pdf-wrap"
:src="pdfSrc"
:page="currentPage"
@num-pages="pageCount=$event"
@page-loaded="currentPage=$event"
@loaded="loadPdfHandler">
</pdf>
</div>
<div class="inner" v-else-if="playAuth">
<div class="video_wid" id="player"></div>
</div>
</div>
<div class="catalog flex-1">
<div class="list">
<h4 class="title">{{ courseName }}</h4>
<div class="desc-wrap">
<div class="desc" :class="{active: desShrink}" v-html="description"></div>
<i class="arrow" :class="{active: desShrink}" v-if="description.length > 40">
<span>...</span>
<img src="@/assets/img/arrow-down.png" alt="" @click="desShrink = !desShrink">
</i>
</div>
<div class="chapters">
<template v-if="videoList.length">
<div class="chapter" v-for="(item,index) in videoList" :key="index">
<div class="chapterName">{{ item.name }}</div>
<div class="section" v-if="item.subsectionList.length">
<div v-for="(section,i) in item.subsectionList" :key="i" @click="preview(section, item.name)">
<p class="sectionName" :class="{active: curLink === `${item.name}${section.name}`}">{{ section.name }}</p>
</div>
</div>
</div>
</template>
</div>
</div> </div>
</div>
</div> </div>
</template>
</div> </div>
</el-card> </div>
</div> </div>
</div>
</el-card>
</div>
</template> </template>
<script> <script>
@ -82,177 +117,178 @@ import "quill/dist/quill.snow.css";
import "quill/dist/quill.bubble.css"; import "quill/dist/quill.bubble.css";
export default { export default {
name: "coursePreview", name: "coursePreview",
data() { data () {
return { return {
id: this.$route.query.id, id: this.$route.query.id,
video: "http://liuwanr.oss-cn-shenzhen.aliyuncs.com/mp4/20200519/1589871025648.mp4", video: "http://liuwanr.oss-cn-shenzhen.aliyuncs.com/mp4/20200519/1589871025648.mp4",
videoSrc: "", videoSrc: "",
videoList: [], videoList: [],
courseName: "", courseName: "",
description: "", description: "",
coverUrl: "", coverUrl: "",
playAuth: "", playAuth: "",
player: null, player: null,
previewImg: "", previewImg: "",
iframeSrc: "", iframeSrc: "",
isWord: false, isWord: false,
isPPT: false, isPPT: false,
isExcel: false, isExcel: false,
showMask: false, showMask: false,
showMask1: false, showMask1: false,
showMask2: false, showMask2: false,
closePosi: { closePosi: {
top: "80px" top: "80px"
}, },
pdfVisible: false, pdfVisible: false,
pdfSrc: "", pdfSrc: "",
currentPage: 0, // pdf currentPage: 0, // pdf
pageCount: 0, // pdf pageCount: 0, // pdf
fileType: "pdf", // fileType: "pdf", //
desShrink: false, desShrink: false,
curLink: "", // curLink: "", //
}; };
},
components: { pdf },
mounted () {
this.insertScript();
this.getData();
this.getChapter();
},
methods: {
goBack () {
this.$router.back();
},
async getData () {
let res = await this.$post(`${this.api.findTheoreticalCourse}?id=${this.id}`);
this.courseName = res.data.courseName;
this.description = res.data.courseIntroduction;
this.coverUrl = res.data.coverUrl;
}, },
components: { pdf }, async getChapter () {
mounted() { let res = await this.$get(`${this.api.queryChaptersAndSubsections}?courseId=${this.id}`);
this.insertScript(); this.videoList = res.chapterList
this.getData();
this.getChapter();
}, },
methods: { insertScript () {
goBack() { const linkTag = document.createElement("link");
this.$router.back(); linkTag.rel = "stylesheet";
}, linkTag.href = "https://g.alicdn.com/de/prismplayer/2.8.2/skins/default/aliplayer-min.css";
async getData() { document.body.appendChild(linkTag);
let res = await this.$post(`${this.api.findTheoreticalCourse}?id=${this.id}`);
this.courseName = res.data.courseName; const scriptTag = document.createElement("script");
this.description = res.data.courseIntroduction; scriptTag.type = "text/javascript";
this.coverUrl = res.data.coverUrl; scriptTag.src = "https://g.alicdn.com/de/prismplayer/2.8.2/aliplayer-min.js";
}, document.body.appendChild(scriptTag);
async getChapter() { },
let res = await this.$get(`${this.api.queryChaptersAndSubsections}?courseId=${this.id}`); transferType (ext) {
this.videoList = res.chapterList if ("jpg,jpeg,png,gif,svg,psd".includes(ext)) return "图片";
}, if ("mp4,3gp,mov,m4v,avi,dat,mkv,flv,vob,rmvb,rm,qlv".includes(ext)) return "视频";
insertScript() { return ext;
const linkTag = document.createElement("link"); },
linkTag.rel = "stylesheet"; preview (row, chapterName) {
linkTag.href = "https://g.alicdn.com/de/prismplayer/2.8.2/skins/default/aliplayer-min.css"; this.curLink = `${chapterName}${row.name}`;
document.body.appendChild(linkTag); this.player = null;
this.playauth = "";
const scriptTag = document.createElement("script"); this.coverUrl = "";
scriptTag.type = "text/javascript"; this.pdfSrc = "";
scriptTag.src = "https://g.alicdn.com/de/prismplayer/2.8.2/aliplayer-min.js"; this.iframeSrc = "";
document.body.appendChild(scriptTag); if (this.transferType(row.fileType) == "视频") {
}, this.$get(`${this.api.getPlayAuth}/${row.fileId}`).then(res => {
transferType(ext) { this.playAuth = res.data.playAuth;
if ("jpg,jpeg,png,gif,svg,psd".includes(ext)) return "图片"; this.$nextTick(() => {
if ("mp4,3gp,mov,m4v,avi,dat,mkv,flv,vob,rmvb,rm,qlv".includes(ext)) return "视频"; if (this.player) {
return ext; this.player.replayByVidAndPlayAuth(row.fileId, this.playAuth);
},
preview(row, chapterName) {
this.curLink = `${chapterName}${row.name}`;
this.player = null;
this.playauth = "";
this.coverUrl = "";
this.pdfSrc = "";
this.iframeSrc = "";
if (this.transferType(row.fileType) == "视频") {
this.$get(`${this.api.getPlayAuth}/${row.fileId}`).then(res => {
this.playAuth = res.data.playAuth;
this.$nextTick(() => {
if (this.player) {
this.player.replayByVidAndPlayAuth(row.fileId, this.playAuth);
} else {
this.player = new Aliplayer({
id: "player",
width: "100%",
autoplay: false,
vid: row.fileId,
playauth: this.playAuth,
encryptType: 1 //
});
}
});
}).catch(res => {
});
} else if (this.transferType(row.fileType) == "图片") {
this.coverUrl = row.fileUrl;
} else if (row.fileType == "pdf") {
this.pdfSrc = row.fileUrl;
this.pdfVisible = true;
} else { } else {
this.$get(`${this.api.getSubsection}?subsectionId=${row.id}`).then(res => { this.player = new Aliplayer({
if (row.fileType == "pptx") { id: "player",
this.isPPT = true; width: "100%",
this.isWord = false; autoplay: false,
this.isExcel = false; vid: row.fileId,
} else if (row.fileType == "doc" || row.fileType == "docx") { playauth: this.playAuth,
this.isPPT = false; encryptType: 1 //
this.isWord = true; });
this.isExcel = false;
} else if (row.fileType == "xls" || row.fileType == "xlsx") {
this.isExcel = true;
this.isPPT = false;
this.isWord = false;
} else {
this.isPPT = false;
this.isWord = false;
this.isExcel = false;
}
if (this.isPPT) {
this.showMask = true;
} else {
this.showMask = false;
}
if (this.isWord) {
this.showMask1 = true;
} else {
this.showMask1 = false;
}
if (this.isExcel) {
this.showMask2 = true;
} else {
this.showMask2 = false;
}
this.iframeSrc = res.previewUrl;
})
.catch(err => {
});
} }
}, });
closePlayer() {
this.playAuth = ""; }).catch(res => {
this.player.pause(); });
}, } else if (this.transferType(row.fileType) == "图片") {
closeIframe() { this.coverUrl = row.fileUrl;
this.iframeSrc = ""; } else if (row.fileType == "pdf") {
this.pdfSrc = row.fileUrl;
this.pdfVisible = true;
} else {
this.$get(`${this.api.getSubsection}?subsectionId=${row.id}`).then(res => {
if (row.fileType == "pptx") {
this.isPPT = true;
this.isWord = false;
this.isExcel = false;
} else if (row.fileType == "doc" || row.fileType == "docx") {
this.isPPT = false;
this.isWord = true;
this.isExcel = false;
} else if (row.fileType == "xls" || row.fileType == "xlsx") {
this.isExcel = true;
this.isPPT = false;
this.isWord = false;
} else {
this.isPPT = false;
this.isWord = false;
this.isExcel = false;
}
if (this.isPPT) {
this.showMask = true;
} else {
this.showMask = false; this.showMask = false;
}
if (this.isWord) {
this.showMask1 = true;
} else {
this.showMask1 = false; this.showMask1 = false;
}, }
closePdf() { if (this.isExcel) {
this.pdfSrc = ""; this.showMask2 = true;
this.currentPage = 1; } else {
}, this.showMask2 = false;
changePdfPage(val) { }
if (val === 0 && this.currentPage > 1) { this.iframeSrc = res.previewUrl;
this.currentPage--; })
} .catch(err => {
if (val === 1 && this.currentPage < this.pageCount) { });
this.currentPage++; }
} },
}, closePlayer () {
loadPdfHandler(e) { this.playAuth = "";
this.currentPage = 1; this.player.pause();
} },
closeIframe () {
this.iframeSrc = "";
this.showMask = false;
this.showMask1 = false;
},
closePdf () {
this.pdfSrc = "";
this.currentPage = 1;
},
changePdfPage (val) {
if (val === 0 && this.currentPage > 1) {
this.currentPage--;
}
if (val === 1 && this.currentPage < this.pageCount) {
this.currentPage++;
}
},
loadPdfHandler (e) {
this.currentPage = 1;
} }
}
}; };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
$height: 700px; $height: 700px;
.video_wid, .cover { .video_wid,
.cover {
position: relative; position: relative;
width: 76%; width: 76%;
max-width: 1400px; max-width: 1400px;
@ -274,7 +310,8 @@ $height: 700px;
height: $height !important; height: $height !important;
} }
.video_wid, .inner { .video_wid,
.inner {
width: 100%; width: 100%;
height: 100% !important; height: 100% !important;
border: 0; border: 0;
@ -379,8 +416,8 @@ $height: 700px;
color: rgba(0, 0, 0, 0.65); color: rgba(0, 0, 0, 0.65);
cursor: pointer; cursor: pointer;
@include ellipsis; @include ellipsis;
&.active{ &.active {
color: #9278FF; color: #9278ff;
} }
} }
} }
@ -389,10 +426,10 @@ $height: 700px;
.el-image-viewer__wrapper { .el-image-viewer__wrapper {
transform: translateY(-10px); transform: translateY(-10px);
transition: transform .5s; transition: transform 0.5s;
&.active { &.active {
transform: translateY(0) transform: translateY(0);
} }
} }
@ -403,7 +440,7 @@ $height: 700px;
&.doc-close { &.doc-close {
i { i {
color: #000 !important; // color: #000 !important;
} }
} }
} }

@ -178,7 +178,7 @@ export default {
}, },
{ {
id: 2, id: 2,
name: '产品精选' name: '官方精选'
}, },
{ {
id: 3, id: 3,
@ -325,7 +325,6 @@ export default {
// //
getData () { getData () {
const { category } = this const { category } = this
console.log(33, this.category)
this.loadIns = Loading.service() this.loadIns = Loading.service()
this.$post(this.api.listOfGoods, { this.$post(this.api.listOfGoods, {
...this.form, ...this.form,
@ -431,8 +430,10 @@ export default {
// tab // tab
tabChange ({ id }) { tabChange ({ id }) {
this.curTab = id this.curTab = id
this.category = []
this.form.hotTag = 1 this.form.hotTag = 1
this.form.selection = '' this.form.selection = ''
this.form.tagId = ''
if (id === 3) { if (id === 3) {
this.form.hotTag = 2 this.form.hotTag = 2
} else if (id === 2) { } else if (id === 2) {

@ -1,14 +1,23 @@
<template> <template>
<div class="wrap"> <div class="wrap">
<el-card shadow="hover"
class="m-b-20">
<div class="flex-between">
<el-page-header @back="$router.back()"
:content="form.mall.productName"></el-page-header>
</div>
</el-card>
<div class="inner"> <div class="inner">
<div class="top"> <div class="top">
<div v-if="form.interfaceDiagrams && height" <div v-if="form.interfaceDiagrams && height"
class="pics" class="pics"
:style="{height: form.interfaceDiagrams.length === 1 ? height: 'auto'}"> :style="{height: form.interfaceDiagrams.length === 1 ? height: 'auto'}">
<img v-for="(pic, i) in form.interfaceDiagrams" <el-image class="pic"
:key="i" v-for="(pic, i) in form.interfaceDiagrams"
:src="pic" :key="i"
alt=""> :src="pic"
:preview-src-list="form.interfaceDiagrams">
</el-image>
</div> </div>
<div class="right" <div class="right"
id="fields"> id="fields">
@ -318,7 +327,7 @@ export default {
.pics { .pics {
width: 436px; width: 436px;
margin-right: 24px; margin-right: 24px;
img { .pic {
width: 140px; width: 140px;
height: 62px; height: 62px;
margin-right: 8px; margin-right: 8px;
@ -433,6 +442,7 @@ export default {
padding: 20px 24px; padding: 20px 24px;
background-color: #fff; background-color: #fff;
border-radius: 10px; border-radius: 10px;
overflow: hidden;
} }
} }
.courses { .courses {

@ -6,8 +6,9 @@ const pre = "activity-";
export default { export default {
path: "/activity", path: "/activity",
name: "activity",
redirect: { redirect: {
path: `/activity/list` name: `${pre}list`
}, },
meta, meta,
component: BasicLayout, component: BasicLayout,
@ -17,20 +18,32 @@ export default {
component: () => import("@/pages/activity/list"), component: () => import("@/pages/activity/list"),
}, },
{ {
path: `add`, path: `details`,
component: () => import("@/pages/activity/add"), component: () => import("@/pages/activity/details"),
},
{
path: `noticeDetail`,
component: () => import("@/pages/activity/manage/manage/noticeDetail"),
}, },
{ {
path: `manage`, path: `manage`,
component: () => import("@/pages/activity/manage"), component: () => import("@/pages/activity/manage/list"),
}, },
{ {
path: `noticeDetail`, path: `add`,
component: () => import("@/pages/activity/manage/noticeDetail"), component: () => import("@/pages/activity/manage/add"),
},
{
path: `manageDetail`,
component: () => import("@/pages/activity/manage/manage"),
}, },
{ {
path: `preview`, path: `preview`,
component: () => import("@/pages/activity/preview"), component: () => import("@/pages/activity/manage/preview"),
}, },
{
path: `notice`,
component: () => import("@/pages/activity/noticeDetail"),
}
] ]
}; };

@ -1,383 +1,402 @@
@import "./default/index.scss"; @import './default/index.scss';
@font-face { @font-face {
font-family: youshe; font-family: youshe;
src: url('font/YouSheBiaoTiHei.ttf'); src: url('font/YouSheBiaoTiHei.ttf');
} }
[v-cloak] { [v-cloak] {
display: none; display: none;
} }
::-webkit-scrollbar { ::-webkit-scrollbar {
width: 8px; width: 8px;
height: 8px; height: 8px;
} }
::-webkit-scrollbar-thumb { ::-webkit-scrollbar-thumb {
width: 5px; width: 5px;
border-radius: 6px; border-radius: 6px;
background: #d7d7d7; background: #d7d7d7;
} }
.flex-between { .flex-between {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
} }
.el-button--primary.action-btn { .el-button--primary.action-btn {
color: $--color-primary !important; color: $--color-primary !important;
font-size: 14px !important; font-size: 14px !important;
background-color: #fff !important; background-color: #fff !important;
border-radius: 4px !important; border-radius: 4px !important;
} }
.el-button--info.action-btn { .el-button--info.action-btn {
color: #fff !important; color: #fff !important;
font-size: 14px !important; font-size: 14px !important;
background-color: $--color-primary !important; background-color: $--color-primary !important;
border-radius: 4px !important; border-radius: 4px !important;
border: none; border: none;
} }
.el-input { .el-input {
.el-input__inner { .el-input__inner {
border-color: rgba(0, 0, 0, 0.15); border-color: rgba(0, 0, 0, 0.15);
} }
} }
.p-title { .p-title {
padding-left: 5px; padding-left: 5px;
margin-bottom: 24px; margin-bottom: 24px;
line-height: 1; line-height: 1;
font-size: 14px; font-size: 14px;
color: #585858; color: #585858;
border-left: 3px solid $--color-primary; border-left: 3px solid $--color-primary;
} }
.page { .page {
position: relative; position: relative;
padding: 24px; padding: 24px;
background-color: #fff; background-color: #fff;
border-radius: 8px; border-radius: 8px;
.tool { .tool {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
margin-bottom: 24px; margin-bottom: 24px;
.filter { .filter {
display: inline-flex; display: inline-flex;
//flex-wrap: wrap; //flex-wrap: wrap;
align-items: center; align-items: center;
flex: 1; flex: 1;
li { li {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
margin-right: 30px; margin-right: 30px;
label { label {
margin-right: 6px; margin-right: 6px;
font-size: 14px; font-size: 14px;
line-height: 14px; line-height: 14px;
color: rgba(0, 0, 0, .65); color: rgba(0, 0, 0, 0.65);
white-space: nowrap; white-space: nowrap;
}
}
} }
}
}
.el-button--primary { .el-button--primary {
@extend .action-btn; @extend .action-btn;
} }
.el-button--info { .el-button--info {
@extend .action-btn; @extend .action-btn;
} }
&.mul { &.mul {
margin-bottom: 0; margin-bottom: 0;
.filter { .filter {
width: 100vw; width: 100vw;
li { li {
margin-bottom: 24px; margin-bottom: 24px;
}
}
} }
}
} }
}
} }
.pagination { .pagination {
margin: 20px 0; margin: 20px 0;
text-align: center; text-align: center;
button, .number { button,
color: rgba(0, 0, 0, .65) !important; .number {
background-color: transparent !important; color: rgba(0, 0, 0, 0.65) !important;
border: 1px solid rgba(0, 0, 0, 0.15) !important; background-color: transparent !important;
border-radius: 4px !important; border: 1px solid rgba(0, 0, 0, 0.15) !important;
} border-radius: 4px !important;
}
button i { button i {
color: #333; color: #333;
} }
.active { .active {
color: #fff !important; color: #fff !important;
background-color: $--color-primary !important; background-color: $--color-primary !important;
} }
} }
.el-table { .el-table {
border-radius: 8px; border-radius: 8px;
border: 1px solid rgba(0, 0, 0, 0.06); border: 1px solid rgba(0, 0, 0, 0.06);
border-bottom: 0; border-bottom: 0;
.cell { .cell {
font-size: 12px; font-size: 12px;
line-height: 35px; line-height: 35px;
} }
th { th {
background: $--color-primary !important; background: $--color-primary !important;
.cell { .cell {
color: #fff; color: #fff;
font-size: 14px; font-size: 14px;
font-weight: normal; font-weight: normal;
}
} }
}
} }
.tabs { .tabs {
display: flex; display: flex;
align-items: center; align-items: center;
padding: 0 24px; padding: 0 24px;
border-bottom: 1px solid rgba(0, 0, 0, .06); border-bottom: 1px solid rgba(0, 0, 0, 0.06);
.item { .item {
position: relative; position: relative;
padding: 20px 0; padding: 20px 0;
margin-right: 40px; margin-right: 40px;
font-size: 16px; font-size: 16px;
color: rgba(0, 0, 0, 0.65); color: rgba(0, 0, 0, 0.65);
cursor: pointer; cursor: pointer;
&:after { &:after {
content: ''; content: '';
position: absolute; position: absolute;
bottom: 0; bottom: 0;
left: 0; left: 0;
width: 100%; width: 100%;
height: 3px; height: 3px;
border-bottom: 3px solid transparent; border-bottom: 3px solid transparent;
border-radius: 2px; border-radius: 2px;
} }
&.active { &.active {
font-weight: 500; font-weight: 500;
color: rgba(0, 0, 0, 0.85); color: rgba(0, 0, 0, 0.85);
} }
&.active:after { &.active:after {
border-bottom-color: $--color-primary; border-bottom-color: $--color-primary;
}
} }
}
} }
.el-message { .el-message {
padding: 11px 20px; padding: 11px 20px;
top:1.2rem!important; top: 1.2rem !important;
.el-message__icon { .el-message__icon {
font-size: 16px; font-size: 16px;
} }
.el-message__content { .el-message__content {
font-size: 14px; font-size: 14px;
color: rgba(0, 0, 0, 0.65); color: rgba(0, 0, 0, 0.65);
} }
.el-icon-close { .el-icon-close {
font-size: 14px; font-size: 14px;
color: #92998d; color: #92998d;
} }
.el-message--success { .el-message--success {
border: 1px solid #B7EB8F; border: 1px solid #b7eb8f;
background: #F6FFED; background: #f6ffed;
.el-message__icon { .el-message__icon {
color: #00c700; color: #00c700;
}
} }
}
.el-message--warning { .el-message--warning {
border: 1px solid #FFE58F; border: 1px solid #ffe58f;
background: #FFFBE6; background: #fffbe6;
.el-message__icon { .el-message__icon {
color: #ffa900; color: #ffa900;
}
} }
}
} }
.el-message-box { .el-message-box {
padding-bottom: 24px; padding-bottom: 24px;
.el-message-box__header { .el-message-box__header {
padding: 32px 32px 12px 50px; padding: 32px 32px 12px 50px;
span { span {
font-size: 16px; font-size: 16px;
color: rgba(0, 0, 0, 0.85); color: rgba(0, 0, 0, 0.85);
font-weight: 500; font-weight: 500;
}
} }
}
.el-message-box__status { .el-message-box__status {
top: -30px; top: -30px;
} }
.el-message-box__status + .el-message-box__message { .el-message-box__status + .el-message-box__message {
font-size: 14px; font-size: 14px;
color: rgba(0, 0, 0, 0.65); color: rgba(0, 0, 0, 0.65);
} }
.el-message-box__btns { .el-message-box__btns {
padding-right: 32px; padding-right: 32px;
&.el-icon-warning { &.el-icon-warning {
color: #ffa900; color: #ffa900;
}
} }
}
// &:not(.normal) {
// &:not(.normal) { // .el-button--primary {
// .el-button--primary { // color: #606266;
// color: #606266; // background: #fff;
// background: #fff; // border-color: #DCDFE6;
// border-color: #DCDFE6;
// &:hover {
// &:hover { // color: $--color-primary;
// color: $--color-primary; // border-color: #efbdbb;
// border-color: #efbdbb; // background-color: #fae9e8;
// background-color: #fae9e8; // }
// } // }
// }
// }
// }
} }
.el-dialog__wrapper { .el-dialog__wrapper {
.el-dialog { .el-dialog {
border-radius: 4px; border-radius: 4px;
.el-dialog__header { .el-dialog__header {
border-bottom: 1px solid rgba(0, 0, 0, 0.06); border-bottom: 1px solid rgba(0, 0, 0, 0.06);
.el-dialog__title { .el-dialog__title {
font-size: 16px; font-size: 16px;
color: rgba(0, 0, 0, 0.85); color: rgba(0, 0, 0, 0.85);
} }
} }
.el-dialog__footer { .el-dialog__footer {
padding: 10px 16px; padding: 10px 16px;
border-top: 1px solid rgba(0, 0, 0, 0.06); border-top: 1px solid rgba(0, 0, 0, 0.06);
.el-button { .el-button {
font-size: 14px; font-size: 14px;
border-radius: 4px; border-radius: 4px;
border-color: rgba(0, 0, 0, 0.15); border-color: rgba(0, 0, 0, 0.15);
} }
}
} }
}
} }
.upload-wrap { .upload-wrap {
position: relative; position: relative;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
padding: 34px 0; padding: 34px 0;
.el-button { .el-button {
span { span {
display: flex; display: flex;
align-items: center; align-items: center;
color: rgba(0, 0, 0, 0.65); color: rgba(0, 0, 0, 0.65);
font-size: 14px; font-size: 14px;
img { img {
margin-right: 8px; margin-right: 8px;
} }
}
} }
}
& > .el-button { & > .el-button {
margin-right: 32px; margin-right: 32px;
} }
.el-upload-list { .el-upload-list {
position: absolute; position: absolute;
bottom: 0; bottom: 0;
left: 0; left: 0;
width: 100%; width: 100%;
max-width: 400px; max-width: 400px;
} }
.link { .link {
position: absolute; position: absolute;
bottom: -20px; bottom: -20px;
left: 0; left: 0;
width: 100%; width: 100%;
text-align: center; text-align: center;
} }
&.lg { &.lg {
padding-bottom: 50px; padding-bottom: 50px;
} }
} }
@media(max-width: 1600px) { .empty {
.el-table { display: flex;
.el-switch__label--right.is-active { justify-content: center;
left: 8px; align-items: center;
padding: 50px 0;
text-align: center;
img {
width: 471px;
}
p {
margin-top: 40px;
font-size: 18px;
color: rgba(0, 0, 0, 0.25);
}
}
@media (max-width: 1600px) {
.el-table {
.el-switch__label--right.is-active {
left: 8px;
}
} }
}
} }
.el-upload-list{ .el-upload-list {
width: 100%; width: 100%;
max-width: 400px; max-width: 400px;
} }
.el-switch__label span { .el-switch__label span {
font-size: 12px; font-size: 12px;
} }
.el-tooltip__popper.is-dark { .el-tooltip__popper.is-dark {
padding: 10px; padding: 10px;
color: #606266; color: #606266;
line-height: 1.8; line-height: 1.8;
background-color: #fff; background-color: #fff;
border: .0625rem solid #ebeef5; border: 0.0625rem solid #ebeef5;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.2); box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.2);
border-radius: 8px; border-radius: 8px;
} }
.el-tooltip__popper[x-placement^="top"] { .el-tooltip__popper[x-placement^='top'] {
.popper__arrow { .popper__arrow {
border-top-color: #fff; border-top-color: #fff;
&:after { &:after {
border-top-color: #fff; border-top-color: #fff;
}
} }
}
} }
.course-cas { .course-cas {
.el-cascader-menu:first-child { .el-cascader-menu:first-child {
.el-radio { .el-radio {
display: none; display: none;
}
} }
} }
} .el-image-viewer__close {
color: #fff;
}

Loading…
Cancel
Save