Compare commits
55 Commits
dev_review
...
master
@ -1,28 +0,0 @@ |
||||
.header{ |
||||
background-color: #242f42; |
||||
} |
||||
.login-wrap{ |
||||
background: #324157; |
||||
} |
||||
.plugins-tips{ |
||||
background: #eef1f6; |
||||
} |
||||
.plugins-tips a{ |
||||
color: #20a0ff; |
||||
} |
||||
.el-upload--text em { |
||||
color: #20a0ff; |
||||
} |
||||
.pure-button{ |
||||
background: #20a0ff; |
||||
} |
||||
.tags-li.active { |
||||
border: 1px solid #409EFF; |
||||
background-color: #409EFF; |
||||
} |
||||
.message-title{ |
||||
color: #20a0ff; |
||||
} |
||||
.collapse-btn:hover{ |
||||
background: rgb(40,52,70); |
||||
} |
@ -0,0 +1,7 @@ |
||||
/* 改变主题色变量 */ |
||||
|
||||
$--color-primary: #062c87; |
||||
|
||||
/* 改变 icon 字体路径变量,必需 */ |
||||
$--font-path: '~element-ui/lib/theme-chalk/fonts'; |
||||
@import "~element-ui/packages/theme-chalk/src/index"; |
@ -0,0 +1,189 @@ |
||||
.msg { |
||||
li { |
||||
margin-bottom: 10px; |
||||
border-top: 1px solid #f1f1f1; |
||||
&:first-child { |
||||
border-top: 0; |
||||
} |
||||
.li-wrap { |
||||
position: relative; |
||||
display: flex; |
||||
justify-content: space-between; |
||||
padding: 16px 0; |
||||
.avatar { |
||||
width: 48px; |
||||
height: 48px; |
||||
border-radius: 50%; |
||||
} |
||||
.texts { |
||||
flex: 1; |
||||
margin-left: 24px; |
||||
.name { |
||||
color: rgba(0, 0, 0, 0.85); |
||||
font-size: 16px; |
||||
} |
||||
.date { |
||||
color: rgba(0, 0, 0, 0.45); |
||||
font-size: 14px; |
||||
} |
||||
/deep/img { |
||||
max-width: 95%; |
||||
} |
||||
} |
||||
.reply-name { |
||||
color: #062c87; |
||||
} |
||||
.action { |
||||
display: inline-flex; |
||||
align-items: center; |
||||
margin: 15px 10px 0 0; |
||||
.icon { |
||||
margin: 0 5px; |
||||
color: #062c87; |
||||
font-size: 18px; |
||||
cursor: pointer; |
||||
&:hover { |
||||
opacity: 0.8; |
||||
} |
||||
&:first-child { |
||||
margin-right: 5px; |
||||
} |
||||
&.del { |
||||
color: rgba(0, 0, 0, 0.65); |
||||
border: 1px solid rgba(0, 0, 0, 0.15); |
||||
} |
||||
} |
||||
} |
||||
.like-wrap { |
||||
display: inline-flex; |
||||
align-items: center; |
||||
cursor: pointer; |
||||
} |
||||
} |
||||
.reply { |
||||
margin-top: 20px; |
||||
} |
||||
} |
||||
&.children { |
||||
margin-left: 72px; |
||||
padding-left: 24px; |
||||
background-color: rgba(0, 0, 0, 0.02); |
||||
border-radius: 8px; |
||||
li { |
||||
border-top-color: rgba(0, 0, 0, 0.06); |
||||
} |
||||
} |
||||
} |
||||
.toggle { |
||||
margin: 16px 0; |
||||
text-align: center; |
||||
color: #062c87; |
||||
font-size: 14px; |
||||
span { |
||||
cursor: pointer; |
||||
} |
||||
} |
||||
/deep/.quill { |
||||
background-color: #fff; |
||||
} |
||||
|
||||
/deep/.timeline { |
||||
padding-left: 9%; |
||||
overflow: hidden; |
||||
.el-timeline-item { |
||||
padding-bottom: 40px; |
||||
} |
||||
.el-timeline-item__node--normal { |
||||
top: 30px; |
||||
} |
||||
.el-timeline-item__wrapper { |
||||
top: 15px; |
||||
padding-left: 40px; |
||||
} |
||||
.el-timeline-item__tail { |
||||
height: 250%; |
||||
border-left-width: 1px; |
||||
} |
||||
.sign { |
||||
position: relative; |
||||
display: inline-block; |
||||
margin-left: -12.5%; |
||||
font-size: 14px; |
||||
color: #062c87; |
||||
} |
||||
.draft { |
||||
.ver, |
||||
.sign { |
||||
color: #b1b1b1; |
||||
} |
||||
} |
||||
.ver { |
||||
display: flex; |
||||
justify-content: space-between; |
||||
align-items: center; |
||||
padding-bottom: 10px; |
||||
margin: -22px 0 20px; |
||||
font-size: 15px; |
||||
color: #062c87; |
||||
border-bottom: 1px dashed #bfbfbf; |
||||
} |
||||
.des { |
||||
p, |
||||
span, |
||||
em { |
||||
font-size: 14px !important; |
||||
} |
||||
} |
||||
.withdraw { |
||||
margin-right: 10px; |
||||
font-size: 13px; |
||||
color: #979797; |
||||
} |
||||
.action { |
||||
margin-left: 15px; |
||||
i { |
||||
margin-left: 8px; |
||||
font-size: 14px; |
||||
color: #062c87; |
||||
cursor: pointer; |
||||
&:hover { |
||||
opacity: 0.9; |
||||
} |
||||
} |
||||
} |
||||
.detail { |
||||
li { |
||||
margin-bottom: 20px; |
||||
} |
||||
.name { |
||||
display: flex; |
||||
align-items: center; |
||||
margin-bottom: 5px; |
||||
font-size: 15px; |
||||
font-weight: 600; |
||||
img { |
||||
width: 20px; |
||||
margin-right: 5px; |
||||
} |
||||
} |
||||
.val { |
||||
font-size: 14px; |
||||
line-height: 1.8; |
||||
white-space: pre-wrap; |
||||
p { |
||||
position: relative; |
||||
color: #6a6a6a; |
||||
&:before { |
||||
content: ''; |
||||
display: inline-block; |
||||
width: 5px; |
||||
height: 5px; |
||||
margin: 0 10px 0 5px; |
||||
vertical-align: middle; |
||||
border-radius: 20px; |
||||
background-color: #c5b8ff; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
@ -1,29 +0,0 @@ |
||||
.header{ |
||||
background-color: #fff; |
||||
} |
||||
.login-wrap{ |
||||
background: rgba(56, 157, 170, 0.82);; |
||||
} |
||||
.plugins-tips{ |
||||
background: #f2f2f2; |
||||
} |
||||
.plugins-tips a{ |
||||
color: #00d1b2; |
||||
} |
||||
.el-upload--text em { |
||||
color: #00d1b2; |
||||
} |
||||
.pure-button{ |
||||
background: #00d1b2; |
||||
} |
||||
.pagination > .active > a, .pagination > .active > a:hover, .pagination > .active > a:focus, .pagination > .active > span, .pagination > .active > span:hover, .pagination > .active > span:focus { |
||||
background-color: #00d1b2 !important; |
||||
border-color: #00d1b2 !important; |
||||
} |
||||
.tags-li.active { |
||||
border: 1px solid #9278FF; |
||||
background-color: #9278FF; |
||||
} |
||||
.collapse-btn:hover{ |
||||
background: #00d1b2; |
||||
} |
After Width: | Height: | Size: 946 B |
After Width: | Height: | Size: 6.7 KiB |
After Width: | Height: | Size: 432 B |
After Width: | Height: | Size: 205 B |
After Width: | Height: | Size: 343 B |
After Width: | Height: | Size: 49 KiB |
After Width: | Height: | Size: 4.5 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 697 B |
After Width: | Height: | Size: 583 B |
After Width: | Height: | Size: 702 B |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 5.1 KiB |
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 2.0 KiB |
@ -0,0 +1,149 @@ |
||||
<template> |
||||
<div class="menus"> |
||||
<el-menu class="nav" :default-active="onRoutes" background-color="#062c87" text-color="#fff" |
||||
active-text-color="#333" unique-opened mode="horizontal" router @select="handleSelect"> |
||||
<template v-for="item in menus"> |
||||
<template v-if="item.subs"> |
||||
<el-submenu :index="item.index" :key="item.index"> |
||||
<template slot="title"> |
||||
<!-- <i :class="item.icon"></i> --> |
||||
<span slot="title">{{ item.title }}</span> |
||||
</template> |
||||
<template v-for="subItem in item.subs"> |
||||
<el-submenu v-if="subItem.subs" :index="subItem.index" :key="subItem.index"> |
||||
<template slot="title">{{ subItem.title }}</template> |
||||
<el-menu-item v-for="(threeItem, i) in subItem.subs" :key="i" :index="threeItem.index">{{ |
||||
threeItem.title |
||||
}}</el-menu-item> |
||||
</el-submenu> |
||||
<el-menu-item v-else :index="subItem.index" :key="subItem.index">{{ subItem.title }}</el-menu-item> |
||||
</template> |
||||
</el-submenu> |
||||
</template> |
||||
<template v-else> |
||||
<el-menu-item :index="item.index" :key="item.index"> |
||||
<!-- <i :class="item.icon"></i> --> |
||||
<span slot="title">{{ item.title }}</span> |
||||
</el-menu-item> |
||||
</template> |
||||
</template> |
||||
</el-menu> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
import Setting from '@/setting' |
||||
import addRoutes from '@/libs/route/addRoutes' |
||||
export default { |
||||
data () { |
||||
return { |
||||
menuList: [ |
||||
{ |
||||
icon: 'el-icon-school', |
||||
index: '/workbench', |
||||
title: '工作台' |
||||
}, |
||||
{ |
||||
icon: 'el-icon-user', |
||||
index: '/customer', |
||||
title: '客户管理' |
||||
}, |
||||
{ |
||||
icon: 'el-icon-shopping-bag-2', |
||||
index: '/user', |
||||
title: '用户管理' |
||||
}, |
||||
{ |
||||
icon: 'el-icon-document-checked', |
||||
index: '/order', |
||||
title: '订单管理' |
||||
}, |
||||
{ |
||||
icon: 'el-icon-office-building', |
||||
index: '/system', |
||||
title: '系统配置' |
||||
}, |
||||
], |
||||
menus: [], |
||||
onRoutes: this.$route.path |
||||
}; |
||||
}, |
||||
watch: { |
||||
"$route.path": function (val) { |
||||
this.menuList.map(e => { |
||||
if (val.replace('/', '') === e.index) { |
||||
this.handleSelect(val.replace('/', '')) |
||||
this.$forceUpdate(); |
||||
} |
||||
}) |
||||
} |
||||
}, |
||||
mounted () { |
||||
sessionStorage.getItem('token') && this.getPer() // 登录了才获取权限 |
||||
}, |
||||
methods: { |
||||
handleSelect (index) { |
||||
this.onRoutes = index |
||||
this.$store.commit('setInfoTab', '1') |
||||
this.$store.commit('setColumnId', '') |
||||
this.$store.commit('setCompetitionCache', null) |
||||
}, |
||||
initMenu () { |
||||
if (Setting.dynamicRoute) { |
||||
this.menus = this.menuList |
||||
return false |
||||
|
||||
const routes = this.$store.state.routes |
||||
const menus = [] |
||||
this.menuList.map(e => { |
||||
routes.find(n => n.path === e.index) && menus.push(e) |
||||
}) |
||||
this.menus = menus |
||||
} else { |
||||
this.menus = this.menuList |
||||
} |
||||
}, |
||||
// 获取权限列表 |
||||
getPer () { |
||||
this.$get(`${this.api.getUserRolesPermissionMenu}?platformId=${Setting.platformId}`).then(res => { |
||||
const routes = res.permissionMenu[0].children |
||||
addRoutes(routes) |
||||
this.initMenu() |
||||
this.$store.commit('setDataPer', res.dataPermissionList) |
||||
}).catch(err => { |
||||
if (err.status === 500) { |
||||
localStorage.removeItem('ms_username'); |
||||
sessionStorage.clear() |
||||
location.reload() |
||||
} |
||||
}) |
||||
}, |
||||
} |
||||
}; |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.menus { |
||||
z-index: 2000; |
||||
position: sticky; |
||||
top: 0; |
||||
display: flex; |
||||
justify-content: center; |
||||
background-color: #062c87; |
||||
|
||||
/deep/.nav { |
||||
border-bottom: 0; |
||||
|
||||
&>.el-menu-item { |
||||
height: 56px; |
||||
padding: 0 30px; |
||||
line-height: 56px; |
||||
} |
||||
|
||||
&>.el-menu-item.is-active { |
||||
background-color: #fff !important; |
||||
border-bottom: 0; |
||||
} |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,28 @@ |
||||
export default { |
||||
types: [ |
||||
{ |
||||
id: 1, |
||||
name: '演示文稿类' |
||||
}, |
||||
{ |
||||
id: 2, |
||||
name: '视频类' |
||||
}, |
||||
{ |
||||
id: 3, |
||||
name: '图形类' |
||||
}, |
||||
{ |
||||
id: 4, |
||||
name: '文本类' |
||||
}, |
||||
{ |
||||
id: 5, |
||||
name: '音频类' |
||||
}, |
||||
{ |
||||
id: 6, |
||||
name: '其他' |
||||
}, |
||||
], |
||||
} |
@ -1,204 +0,0 @@ |
||||
<template> |
||||
<div> |
||||
<el-row :gutter="20"> |
||||
<el-col :span="24"> |
||||
<el-card shadow="hover" class="mgb20"> |
||||
<div class="flex-between"> |
||||
<div class="per_title" @click="goback()"> |
||||
<i class="el-icon-arrow-left"></i> |
||||
<span class="per_back">返回</span> |
||||
<span class="per_school">添加环节</span> |
||||
</div> |
||||
<div> |
||||
<el-button type="primary" round class="mag" @click="saveAdd('form')">确定 |
||||
</el-button> |
||||
</div> |
||||
</div> |
||||
</el-card> |
||||
|
||||
<el-card shadow="hover" class="mgb20"> |
||||
<div class="flex-between mgb20 user_header"> |
||||
<div class="flex-center"> |
||||
<p class="addhr_tag"></p> |
||||
<span>环节1.1</span> |
||||
</div> |
||||
<el-button type="primary" round class="mag" @click="addcourse()">添加环节</el-button> |
||||
</div> |
||||
|
||||
<div> |
||||
<el-form :model="form" ref="form" label-width="120px" class="courseware"> |
||||
<ul class="mgb20"> |
||||
<li v-for="(item,index) in form.courseList" :key="index" class="flex-between"> |
||||
<div style="width: 50%;"> |
||||
<el-form-item label="环节名称" :prop="'courseList.' + index + '.linkName'" |
||||
:rules="{required: true, message: '请输入项目课件', trigger: 'blur'}"> |
||||
<el-input placeholder="请输入项目课件" v-model="item.linkName"></el-input> |
||||
</el-form-item> |
||||
<el-form-item label="资源添加" :prop="'courseList.' + index + '.fileLink'" |
||||
:rules="{required: true, message: '请添加文件', trigger: 'blur'}"> |
||||
<el-upload |
||||
class="link_upload" |
||||
:headers="{token}" |
||||
:action="api.uploadFiles" |
||||
:on-remove="(file, fileList)=>{return handleRemove(file, fileList, index)}" |
||||
:on-error="uploadError" |
||||
:on-success="(response, file, fileList)=>{return uploadSuccess(response, file, fileList, index)}" |
||||
:before-remove="beforeRemove" |
||||
:limit="1" |
||||
:on-exceed="handleExceed" |
||||
:file-list="item.uploadList"> |
||||
<el-button size="medium" type="primary" icon="el-icon-upload" |
||||
class="uploadTitle">点击上传 |
||||
</el-button> |
||||
</el-upload> |
||||
</el-form-item> |
||||
</div> |
||||
<div> |
||||
<el-button size="medium" type="primary" @click="delCourse(index)">删除课件 |
||||
</el-button> |
||||
</div> |
||||
</li> |
||||
</ul> |
||||
</el-form> |
||||
</div> |
||||
</el-card> |
||||
</el-col> |
||||
</el-row> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
export default { |
||||
data() { |
||||
return { |
||||
token: this.$store.state.loginToken, |
||||
form: { |
||||
courseList: [{ |
||||
projectId: this.$store.state.systemId, |
||||
courseId: this.$store.state.courseId, |
||||
linkName: "", |
||||
fileLink: "", |
||||
uploadList: [] |
||||
}] |
||||
} |
||||
}; |
||||
}, |
||||
mounted() { |
||||
this.getData(); |
||||
}, |
||||
methods: { |
||||
getData() { |
||||
let data = { |
||||
projectId: this.form.courseList[0].projectId, |
||||
courseId: this.form.courseList[0].courseId |
||||
}; |
||||
this.$get(this.api.queryLinkDetails, data).then((res) => { |
||||
res.message.map(e => { |
||||
var arr = []; |
||||
arr.push({ name: e.linkName, url: e.fileLink }); |
||||
this.$set(e, "uploadList", arr); |
||||
}); |
||||
this.form.courseList = res.message; |
||||
}).catch((res) => { |
||||
}); |
||||
}, |
||||
saveAdd(formName) { |
||||
this.$refs[formName].validate((valid) => { |
||||
if (valid) { |
||||
var arr = this.form.courseList.map(v => { |
||||
var obj = { |
||||
...v |
||||
}; |
||||
delete obj.uploadList; |
||||
return obj; |
||||
}); |
||||
let data = { |
||||
courseLink: arr |
||||
}; |
||||
this.$post(this.api.addCourseLink, data).then((res) => { |
||||
this.$message.success("添加成功!"); |
||||
this.goback(); |
||||
}).catch((res) => { |
||||
}); |
||||
} |
||||
}); |
||||
}, |
||||
addcourse() { |
||||
this.form.courseList = this.form.courseList.concat({ |
||||
projectId: this.$store.state.systemId, |
||||
courseId: this.$store.state.courseId, |
||||
linkName: "", |
||||
fileLink: "", |
||||
uploadList: [] |
||||
}); |
||||
}, |
||||
// 上传文件 |
||||
handleExceed(files, fileList) { |
||||
this.$message.warning( |
||||
`当前限制选择 1 个文件,如需更换,请删除上一个文件再重新选择!` |
||||
); |
||||
}, |
||||
uploadSuccess(response, file, fileList, idx) { |
||||
this.form.courseList[idx].uploadList.push({ name: file.name, url: response.message.fileUrl }); |
||||
this.form.courseList[idx].fileLink = response.message.fileUrl; |
||||
}, |
||||
uploadError(err, file, fileList) { |
||||
this.$message({ |
||||
message: "上传出错,请重试!", |
||||
type: "error", |
||||
center: true |
||||
}); |
||||
}, |
||||
beforeRemove(file, fileList) { |
||||
return this.$confirm(`确定移除 ${file.name}?`); |
||||
}, |
||||
handleRemove(file, fileList, idx) { |
||||
let uploadList = this.form.courseList[idx].uploadList; |
||||
uploadList.forEach((item, index) => { |
||||
if (file.name == item.name) { |
||||
uploadList.splice(index, 1); |
||||
} |
||||
}); |
||||
}, |
||||
delCourse(index) { |
||||
this.$confirm("确定要删除该课件吗?", "提示", { |
||||
type: "warning" |
||||
}) |
||||
.then(() => { |
||||
this.form.courseList.splice(index, 1); |
||||
this.$message.success("删除成功"); |
||||
}) |
||||
.catch(() => { |
||||
}); |
||||
}, |
||||
goback() { |
||||
this.$router.go(-1); |
||||
} |
||||
} |
||||
}; |
||||
</script> |
||||
|
||||
<style scoped> |
||||
/* .courseware ul .el-input{ |
||||
width: 30%; |
||||
} */ |
||||
|
||||
.courseware ul li { |
||||
margin-top: 20px; |
||||
padding: 0 0 10px 0; |
||||
border-bottom: 1px dashed #eee; |
||||
} |
||||
|
||||
.courseware ul li:first-child { |
||||
margin-top: 0; |
||||
} |
||||
|
||||
.courseware ul li:last-child { |
||||
border-bottom: none; |
||||
} |
||||
|
||||
.uploadTitle { |
||||
height: 40px !important; |
||||
font-size: 16px; |
||||
} |
||||
</style> |
@ -0,0 +1,610 @@ |
||||
<template> |
||||
<el-drawer title="添加系统资源" :visible.sync="sourceVisible" size="1200px" :close-on-click-modal="false" |
||||
custom-class="source-dia" @closed="closeDia"> |
||||
<div class="overflow" v-loading="loading"> |
||||
<div class="left"> |
||||
<div class="tabs mgb20"> |
||||
<a class="item" v-for="(item, i) in tabs" :key="i" :class="{ active: i == active }" @click="tabChange(i)">{{ |
||||
item |
||||
}}</a> |
||||
</div> |
||||
|
||||
<template v-if="active !== 'tab3'"> |
||||
<el-input class="mgb10" style="width: 300px" placeholder="请输入资源名称" prefix-icon="el-icon-search" |
||||
v-model="keyword" clearable></el-input> |
||||
|
||||
<div class="course"> |
||||
<div v-for="(course, i) in course" :key="i" class="item"> |
||||
<div class="line"> |
||||
<i :class="`el-icon-caret-right arrow ${course.shrink ? 'active' : ''}`" |
||||
@click="course.shrink = !course.shrink"></i> |
||||
<el-checkbox class="check" v-model="course.check" @change="checkCourse(course)"></el-checkbox> |
||||
<img v-if="course.coverUrl" class="cover" :src="course.coverUrl" alt=""> |
||||
<span class="course-name">{{ course.curriculumName || course.courseName }}</span> |
||||
</div> |
||||
<div v-if="course.shrink" class="chapters"> |
||||
<!-- 章节 --> |
||||
<div v-for="(chapter, j) in course.chapters" :key="j" class=""> |
||||
<div class="line"> |
||||
<i :class="`el-icon-caret-right arrow ${chapter.shrink ? 'active' : ''}`" |
||||
@click="chapter.shrink = !chapter.shrink"></i> |
||||
<el-checkbox class="check" v-model="chapter.check" @change="checkChapter(chapter, course)">{{ |
||||
chapter.name |
||||
}}</el-checkbox> |
||||
</div> |
||||
|
||||
<!-- 小节 --> |
||||
<div v-if="chapter.shrink" class="sections"> |
||||
<div v-for="(section, k) in chapter.subsections" :key="k" class="line"> |
||||
<el-checkbox class="check" v-model="section.check" @change="checkSection(section, chapter)"> |
||||
<img v-if="section.fileType === 'pptx'" src="@/assets/img/exts/ppt.png" alt=""> |
||||
<img v-else-if="section.fileType === 'mp4'" src="@/assets/img/exts/video.png" alt=""> |
||||
<img v-else-if="section.fileType === 'doc' || section.fileType === 'docx'" |
||||
src="@/assets/img/exts/word.png" alt=""> |
||||
<img v-else-if="section.fileType === 'xlsx' || section.fileType === 'xls'" |
||||
src="@/assets/img/exts/excel.png" alt=""> |
||||
<img v-else-if="section.fileType === 'txt'" src="@/assets/img/exts/txt.png" alt=""> |
||||
<img v-else-if="section.fileType === 'pdf'" src="@/assets/img/exts/pdf.png" alt=""> |
||||
<img v-else src="@/assets/img/exts/pic.png" alt=""> |
||||
{{ section.name }}</el-checkbox> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</template> |
||||
|
||||
<!-- 文件素材 --> |
||||
<div v-else class="materials"> |
||||
<div class="types"> |
||||
<div class="flex-center m-b-10"> |
||||
<p class="addhr_tag"></p> |
||||
<span>资源类型</span> |
||||
</div> |
||||
<ul class="lines"> |
||||
<li v-for="(item, i) in sourceType" :key="i" :class="['line', { active: curType === item.name }]" |
||||
@click="checkType(item)">{{ item.name }}</li> |
||||
</ul> |
||||
</div> |
||||
|
||||
<div class="sources"> |
||||
<div class="flex-center m-b-10"> |
||||
<p class="addhr_tag"></p> |
||||
<span>资源列表</span> |
||||
</div> |
||||
<el-input class="m-b-10" placeholder="请输入资源名称" prefix-icon="el-icon-search" v-model="keyword" |
||||
clearable></el-input> |
||||
<ul class="lines"> |
||||
<el-checkbox v-if="sources.length" v-model="checkAll" label="全选" @change="checkAllChange"></el-checkbox> |
||||
<li v-for="(item, i) in sources" :key="i" class="line"> |
||||
<el-checkbox v-model="item.check" :label="item.resourceName" @change="sourceChange(item)"></el-checkbox> |
||||
</li> |
||||
</ul> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div class="right"> |
||||
<div v-if="$parent.curSection.id" class="m-b-20"> |
||||
<p class="total m-b-10">原资源(共1个)</p> |
||||
<div v-html="$parent.curSection.name"></div> |
||||
</div> |
||||
<template v-if="checked.length"> |
||||
<div class="flex-between m-b-10"> |
||||
<p class="total">已选资源(共{{ checked.length }}个)</p> |
||||
<el-button type="text" @click="batchDelChecked">批量移除</el-button> |
||||
</div> |
||||
|
||||
<el-input placeholder="请输入资源名称" prefix-icon="el-icon-search" v-model="checkedKeyword" clearable></el-input> |
||||
|
||||
<div class="lines"> |
||||
<template v-for="(item, i) in checked"> |
||||
<div v-if="!item.name || item.name.includes(checkedKeyword)" :key="i" class="line"> |
||||
<div class="check-left"> |
||||
<el-checkbox v-model="item.check"></el-checkbox> |
||||
<span class="serial">{{ i + 1 }}</span> |
||||
<el-tooltip effect="dark" :content="item.name" placement="top-start"> |
||||
<p class="checked-name ellipsis">{{ item.name }}</p> |
||||
</el-tooltip> |
||||
</div> |
||||
<i class="el-icon-delete action-icon" @click="delChecked(item)"></i> |
||||
</div> |
||||
</template> |
||||
</div> |
||||
</template> |
||||
<div v-else class="empty"> |
||||
<img class="icon" src="@/assets/img/empty.svg" alt=""> |
||||
<p>暂无数据</p> |
||||
</div> |
||||
|
||||
</div> |
||||
</div> |
||||
|
||||
<div class="btns"> |
||||
<el-button @click="sourceVisible = false">取消</el-button> |
||||
<el-button type="primary" :loading="submiting" @click="submit">确定</el-button> |
||||
</div> |
||||
</el-drawer> |
||||
</template> |
||||
<script> |
||||
import Setting from '@/setting' |
||||
import Util from '@/libs/util' |
||||
import _ from 'lodash' |
||||
import SourceConst from '@/const/source' |
||||
export default { |
||||
props: ['visible'], |
||||
data () { |
||||
return { |
||||
sourceVisible: false, |
||||
active: 'tab1', |
||||
tabs: { |
||||
tab1: '教学课程', |
||||
tab2: '精品课程', |
||||
tab3: '文件素材', |
||||
}, |
||||
sourceType: [], |
||||
curType: '全部', |
||||
sources: [], |
||||
checkAll: false, |
||||
keyword: '', |
||||
searchTimer: null, |
||||
checkedKeyword: '', |
||||
|
||||
allSections: [], |
||||
course: [], |
||||
|
||||
checked: [], |
||||
submiting: false, |
||||
loading: false, |
||||
}; |
||||
}, |
||||
watch: { |
||||
'keyword': function (val) { |
||||
clearTimeout(this.searchTimer) |
||||
this.searchTimer = setTimeout(this.getCourse, 500) |
||||
}, |
||||
visible () { |
||||
this.sourceVisible = this.visible |
||||
this.visible && this.init() |
||||
} |
||||
}, |
||||
mounted () { |
||||
|
||||
}, |
||||
methods: { |
||||
// 初始化 |
||||
init () { |
||||
this.checked = [] |
||||
this.curType = '全部' |
||||
this.sourceType = [ |
||||
{ |
||||
id: '', |
||||
name: '全部' |
||||
}, |
||||
...SourceConst.types |
||||
] |
||||
this.sourceType.forEach(e => { |
||||
e.check = false |
||||
}) |
||||
this.getCourse() |
||||
}, |
||||
// 课程列表 |
||||
async getCourse () { |
||||
try { |
||||
this.loading = true |
||||
this.checkAll = false |
||||
const { checked } = this |
||||
if (this.active === 'tab3') { |
||||
const { page } = await this.$post(this.api.resourceLibrary, { |
||||
pageNum: 1, |
||||
pageSize: 10000, |
||||
platformId: Setting.platformId, |
||||
type: 2, |
||||
keyword: this.keyword, |
||||
displayFileType: this.curType === '全部' ? [] : [this.curType], |
||||
}) |
||||
const list = page.records |
||||
list.forEach(e => { |
||||
const cur = checked.find(m => m.resourceName && m.id === e.id) |
||||
e.name = e.resourceName |
||||
e.check = !!cur |
||||
}) |
||||
this.sources = list |
||||
} else { |
||||
const { list } = await this.$post(`${this.api[this.active === 'tab1' ? 'curriculumTree' : 'boutiqueCurriculumTree']}?name=${this.keyword}`) |
||||
if (list.length) { |
||||
const all = [] |
||||
list.forEach(e => { |
||||
e.shrink = false |
||||
e.check = false |
||||
e.chapters.forEach(n => { |
||||
n.shrink = false |
||||
n.check = false |
||||
all.push(...n.subsections) |
||||
n.subsections.forEach(m => { |
||||
const cur = checked.find(j => m.cid === j.cid && m.id === j.id) |
||||
m.check = !!cur |
||||
}) |
||||
}) |
||||
}) |
||||
|
||||
list.forEach(e => { |
||||
e.shrink = false |
||||
e.check = false |
||||
e.chapters.forEach(n => { |
||||
n.shrink = false |
||||
n.check = n.subsections.every(m => m.check) |
||||
}) |
||||
}) |
||||
|
||||
list.forEach(e => { |
||||
e.shrink = false |
||||
e.check = e.chapters.every(m => m.check) |
||||
}) |
||||
|
||||
list[0].shrink = true |
||||
list[0].chapters[0].shrink = true |
||||
this.allSections = all |
||||
} |
||||
this.course = list |
||||
} |
||||
} finally { |
||||
this.loading = false |
||||
} |
||||
}, |
||||
initData () { |
||||
this.page = 1; |
||||
this.getData(); |
||||
}, |
||||
tabChange (index) { |
||||
this.keyword = '' |
||||
this.active = index |
||||
this.getCourse() |
||||
}, |
||||
// 课程多选回调 |
||||
checkCourse (row) { |
||||
const { check } = row |
||||
const { checked } = this |
||||
row.chapters.forEach(e => { |
||||
e.check = check |
||||
e.subsections.forEach(n => { |
||||
n.check = check |
||||
const cur = checked.findIndex(m => m.id === n.id) |
||||
if (check) { |
||||
if (cur === -1) { |
||||
const section = _.cloneDeep(n) |
||||
section.check = false |
||||
checked.push(section) |
||||
} |
||||
} else { |
||||
cur !== -1 && checked.splice(cur, 1) |
||||
} |
||||
}) |
||||
}) |
||||
}, |
||||
// 章节多选回调 |
||||
checkChapter (row, course) { |
||||
const { check } = row |
||||
const { checked } = this |
||||
row.subsections.forEach(n => { |
||||
n.check = check |
||||
const cur = checked.findIndex(m => m.id === n.id) |
||||
if (check) { |
||||
if (cur === -1) { |
||||
const section = _.cloneDeep(n) |
||||
section.check = false |
||||
checked.push(section) |
||||
} |
||||
} else { |
||||
cur !== -1 && checked.splice(cur, 1) |
||||
} |
||||
}) |
||||
course.check = course.chapters.every(e => e.check) |
||||
}, |
||||
// 小节多选回调 |
||||
async checkSection (row, chapter) { |
||||
const { check } = row |
||||
const { checked } = this |
||||
const cur = checked.findIndex(m => m.id === row.id) |
||||
if (check) { |
||||
if (cur === -1) { |
||||
const section = _.cloneDeep(row) |
||||
section.check = false |
||||
this.checked.push(section) |
||||
} |
||||
} else { |
||||
cur !== -1 && this.checked.splice(cur, 1) |
||||
} |
||||
chapter.check = chapter.subsections.every(e => e.check) |
||||
}, |
||||
// 资源全选回调 |
||||
checkAllChange (val) { |
||||
this.sources.map(e => { |
||||
e.check = val |
||||
this.sourceChange(e) |
||||
}) |
||||
}, |
||||
// 资源类型选择回调 |
||||
checkType ({ name }) { |
||||
this.curType = name |
||||
this.getCourse() |
||||
}, |
||||
// 资源列表选择回调 |
||||
sourceChange (row) { |
||||
const { check } = row |
||||
const { checked } = this |
||||
const cur = checked.findIndex(m => m.id === row.id) |
||||
if (check) { |
||||
if (cur === -1) { |
||||
const section = _.cloneDeep(row) |
||||
section.check = false |
||||
this.checked.push(section) |
||||
} |
||||
} else { |
||||
cur !== -1 && this.checked.splice(cur, 1) |
||||
} |
||||
}, |
||||
|
||||
// 批量移除 |
||||
async batchDelChecked (val) { |
||||
try { |
||||
const checked = this.checked.filter(e => e.check) |
||||
if (checked.length) { |
||||
checked.map(e => { |
||||
const cur = this.allSections.find(n => n.id === e.id) |
||||
if (cur) { |
||||
cur.check = false |
||||
} |
||||
}) |
||||
this.checked = this.checked.filter(e => !e.check) |
||||
} else { |
||||
Util.warningMsg('请选择数据') |
||||
} |
||||
} catch (e) { } |
||||
}, |
||||
// 已选单个删除 |
||||
async delChecked (item) { |
||||
try { |
||||
const cur = this.allSections.find(e => e.id === item.id) |
||||
if (cur) cur.check = false |
||||
this.checked.splice(this.checked.findIndex(e => e.id === item.id), 1) |
||||
} catch (e) { } |
||||
}, |
||||
// 提交 |
||||
async submit () { |
||||
try { |
||||
if (this.submiting) return false |
||||
const { checked } = this |
||||
if (checked.length) { |
||||
this.submiting = true |
||||
const { chapterId, id } = this.$parent |
||||
const result = checked.map(e => { |
||||
return { |
||||
chapterId, |
||||
cid: id, |
||||
resourceId: e.id, |
||||
type: e.cid ? 0 : e.resourceName ? 2 : 1, |
||||
} |
||||
}) |
||||
|
||||
const old = this.$parent.curSection // 需要更换的资源 |
||||
if (old.id) { |
||||
// 更换资源 |
||||
await this.$post(this.api.replaceResource, { |
||||
chapterId: old.chapterId, |
||||
cid: +id, |
||||
subsectionId: old.id, |
||||
newResource: result |
||||
}) |
||||
|
||||
} else { |
||||
// 批量新增资源 |
||||
await this.$post(this.api.combinationResource, result) |
||||
} |
||||
|
||||
this.sourceVisible = false |
||||
this.$parent.switchTypeVisible = false |
||||
this.$parent.getData() |
||||
this.submiting = false |
||||
} else { |
||||
Util.warningMsg('请选择资源') |
||||
} |
||||
} catch (e) { |
||||
this.submiting = false |
||||
} |
||||
}, |
||||
// 弹框关闭回调 |
||||
closeDia () { |
||||
this.$emit('update:visible', false) |
||||
} |
||||
} |
||||
}; |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
/deep/.source-dia { |
||||
.el-drawer__header { |
||||
padding-bottom: 20px; |
||||
margin-bottom: 0; |
||||
border-bottom: 1px solid #eee; |
||||
} |
||||
|
||||
.overflow { |
||||
display: flex; |
||||
} |
||||
|
||||
.btns { |
||||
position: absolute; |
||||
bottom: 0; |
||||
left: 0; |
||||
width: 100%; |
||||
padding: 14px 0; |
||||
text-align: center; |
||||
background-color: #fff; |
||||
box-shadow: 4px -2px 6px 0px rgba(198, 198, 198, 0.3500); |
||||
} |
||||
|
||||
|
||||
.empty { |
||||
display: flex; |
||||
flex-direction: column; |
||||
justify-content: center; |
||||
align-items: center; |
||||
height: 100%; |
||||
font-size: 14px; |
||||
text-align: center; |
||||
color: #a3a3a3; |
||||
} |
||||
|
||||
.left { |
||||
width: 700px; |
||||
padding: 0 15px; |
||||
border-right: 1px solid #eee; |
||||
box-sizing: border-box; |
||||
|
||||
.course { |
||||
height: calc(100vh - 263px); |
||||
overflow: auto; |
||||
|
||||
.item { |
||||
padding: 10px; |
||||
margin-bottom: 10px; |
||||
background-color: #f9f9f9; |
||||
} |
||||
} |
||||
|
||||
.line { |
||||
display: flex; |
||||
align-items: center; |
||||
} |
||||
|
||||
.arrow { |
||||
font-size: 16px; |
||||
color: #9f9f9f; |
||||
cursor: pointer; |
||||
transition: .3s; |
||||
|
||||
&.active { |
||||
transform: rotate(90deg); |
||||
} |
||||
} |
||||
|
||||
.check { |
||||
margin: 0 10px; |
||||
|
||||
img { |
||||
vertical-align: middle; |
||||
} |
||||
} |
||||
|
||||
.cover { |
||||
width: 100px; |
||||
max-height: 80px; |
||||
margin-right: 15px; |
||||
border-radius: 6px; |
||||
} |
||||
|
||||
.course-name { |
||||
font-size: 14px; |
||||
color: #333; |
||||
} |
||||
|
||||
.chapters { |
||||
padding-left: 26px; |
||||
margin-top: 10px; |
||||
|
||||
.line { |
||||
margin-bottom: 10px; |
||||
} |
||||
} |
||||
|
||||
.chapter-name { |
||||
font-size: 13px; |
||||
color: #ccc; |
||||
} |
||||
|
||||
.sections { |
||||
padding-left: 43px; |
||||
} |
||||
} |
||||
|
||||
.right { |
||||
flex: 1; |
||||
padding: 15px; |
||||
|
||||
.total { |
||||
font-size: 15px; |
||||
color: #333; |
||||
font-weight: 600; |
||||
} |
||||
|
||||
.lines { |
||||
height: calc(100vh - 228px); |
||||
padding-right: 10px; |
||||
margin-top: 10px; |
||||
overflow: auto; |
||||
} |
||||
|
||||
.line { |
||||
display: flex; |
||||
padding: 5px 0; |
||||
color: #333; |
||||
} |
||||
|
||||
.serial { |
||||
width: 32px; |
||||
margin: 0 12px; |
||||
text-align: center; |
||||
white-space: nowrap; |
||||
} |
||||
|
||||
.check-left { |
||||
display: inline-flex; |
||||
align-items: center; |
||||
} |
||||
|
||||
.checked-name { |
||||
width: 360px; |
||||
margin-right: 20px; |
||||
} |
||||
|
||||
.action-icon { |
||||
font-size: 14px; |
||||
cursor: pointer; |
||||
} |
||||
} |
||||
|
||||
.materials { |
||||
display: flex; |
||||
gap: 20px; |
||||
} |
||||
|
||||
.types { |
||||
width: 250px; |
||||
height: calc(100vh - 223px); |
||||
padding: 15px; |
||||
background-color: #f9f9f9; |
||||
box-sizing: border-box; |
||||
overflow: auto; |
||||
|
||||
.line { |
||||
margin-bottom: 10px; |
||||
cursor: pointer; |
||||
|
||||
&.active { |
||||
font-weight: 600; |
||||
color: #062c87; |
||||
} |
||||
} |
||||
} |
||||
|
||||
.sources { |
||||
flex: 1; |
||||
padding: 10px; |
||||
|
||||
.line { |
||||
margin-top: 8px; |
||||
} |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,251 @@ |
||||
<template> |
||||
<div class="page"> |
||||
<div style="margin-bottom: 10px;text-align: right;"> |
||||
<el-button v-auth="'/shop:营销推广管理:新增'" type="primary" round @click="add">新增</el-button> |
||||
</div> |
||||
<el-table :data="list" class="table" ref="table" header-align="center" row-key="id"> |
||||
<el-table-column type="index" width="100" label="序号" align="center"></el-table-column> |
||||
<el-table-column prop="courseName" label="图片" min-width="150" align="center"> |
||||
<template slot-scope="scope"> |
||||
<img width="100" :src="scope.row.banner" alt=""> |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column prop="title" label="标题" min-width="150" align="center"></el-table-column> |
||||
<el-table-column prop="subheading" label="副标题" min-width="150" align="center"></el-table-column> |
||||
<el-table-column prop="url" label="链接" min-width="150" align="center"></el-table-column> |
||||
<el-table-column label="操作" align="center" width="250"> |
||||
<template slot-scope="scope"> |
||||
<el-switch v-model="scope.row.isOpen" :active-value="0" :inactive-value="1" |
||||
@change="switchOff($event, scope.row)" v-auth="'/shop:营销推广管理:禁用'"> |
||||
</el-switch> |
||||
<el-button style="margin-left: 10px;" v-auth="'/shop:营销推广管理:编辑'" type="text" |
||||
@click="edit(scope.row)">编辑</el-button> |
||||
<el-button v-auth="'/shop:营销推广管理:删除'" type="text" @click="handleDelete(scope.row)">删除</el-button> |
||||
</template> |
||||
</el-table-column> |
||||
</el-table> |
||||
|
||||
<el-dialog :title="(form.id ? '编辑' : '新增') + 'banner'" :visible.sync="bannerVisible" width="500px" class="dialog" |
||||
:close-on-click-modal="false"> |
||||
<el-form ref="form" label-width="60px"> |
||||
<el-form-item label="图片"> |
||||
<el-upload class="avatar-uploader" accept=".jpg,.png,.jpeg,.gif" :on-change="changeFile" |
||||
:show-file-list="false" action="" :auto-upload="false"> |
||||
<img v-if="form.banner" :src="form.banner" class="avatar"> |
||||
<div class="uploader-default" v-else> |
||||
<i class="el-icon-plus"></i> |
||||
<p>上传图片</p> |
||||
</div> |
||||
</el-upload> |
||||
</el-form-item> |
||||
<el-form-item label="标题"> |
||||
<el-input v-model="form.title" placeholder="请输入标题" maxlength="100"></el-input> |
||||
</el-form-item> |
||||
<el-form-item label="副标题"> |
||||
<el-input v-model="form.subheading" placeholder="请输入副标题" maxlength="100"></el-input> |
||||
</el-form-item> |
||||
<el-form-item label="链接"> |
||||
<el-input v-model="form.url" placeholder="请输入链接" maxlength="100"></el-input> |
||||
</el-form-item> |
||||
</el-form> |
||||
<span slot="footer" class="dialog-footer"> |
||||
<el-button @click="bannerVisible = false">取消</el-button> |
||||
<el-button type="primary" @click="submitBanner">确定</el-button> |
||||
</span> |
||||
</el-dialog> |
||||
|
||||
<!-- 剪裁组件弹窗 --> |
||||
<el-dialog title="图片裁剪" append-to-body :visible.sync="cropperModel" width="1100px" :close-on-click-modal="false"> |
||||
<Cropper ref="cropper" :img-file.sync="file" :is-upload="isUpload" :fixed="true" :fixedNumber.sync="fixedNumber" |
||||
:autoCropWidth="500" :autoCropHeight="138.8" @upload="customUpload" /> |
||||
</el-dialog> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
import Util from "@/libs/util"; |
||||
import Setting from '@/setting' |
||||
import Cropper from '@/components/img-upload/Cropper' |
||||
import Axios from 'axios' |
||||
import Oss from '@/components/upload/upload.js' |
||||
export default { |
||||
data () { |
||||
return { |
||||
headers: { |
||||
token: sessionStorage.getItem("token") |
||||
}, |
||||
list: [], |
||||
bannerVisible: false, |
||||
form: { |
||||
id: '', |
||||
banner: '', |
||||
title: '', |
||||
subheading: '', |
||||
url: '', |
||||
}, |
||||
cropperModel: false, |
||||
isUpload: false, |
||||
fixedNumber: [5.4, 1], |
||||
file: '' |
||||
}; |
||||
}, |
||||
components: { |
||||
Cropper |
||||
}, |
||||
mounted () { |
||||
this.getList() |
||||
}, |
||||
methods: { |
||||
getList () { |
||||
this.$post(this.api.listMarketing, { |
||||
pageNum: 1, |
||||
pageSize: 1000 |
||||
}).then(({ page }) => { |
||||
this.list = page.records; |
||||
this.total = page.total; |
||||
}).catch(res => { |
||||
}); |
||||
}, |
||||
// 图片裁剪上传事件 |
||||
customUpload (data) { |
||||
data.name = this.file.name |
||||
this.imgUpload(data) |
||||
}, |
||||
// 图片上传到服务器 |
||||
imgUpload (formData) { |
||||
this.isUpload = true |
||||
Oss.upload(formData).then(res => { |
||||
this.form.banner && Oss.del(this.form.banner) |
||||
this.form.banner = res.url |
||||
}) |
||||
this.$refs.cropper.isDisabled = false |
||||
this.isUpload = false |
||||
this.cropperModel = false |
||||
}, |
||||
// 图片改变钩子 |
||||
changeFile (file) { |
||||
const { size, name } = file |
||||
const ext = name.substring(name.lastIndexOf('.') + 1) |
||||
if (!Util.isImg(ext)) { |
||||
this.$message.error('请上传图片!') |
||||
return false |
||||
} |
||||
this.file = file |
||||
this.cropperModel = true |
||||
this.$nextTick(() => { |
||||
this.$refs.cropper.updateImg({ |
||||
url: window.URL.createObjectURL(file.raw), |
||||
size: file.size |
||||
}) |
||||
}) |
||||
}, |
||||
add () { |
||||
this.form = { |
||||
id: '', |
||||
banner: '', |
||||
title: '', |
||||
subheading: '', |
||||
url: '', |
||||
} |
||||
this.bannerVisible = true |
||||
}, |
||||
edit (row) { |
||||
this.form = JSON.parse(JSON.stringify(row)) |
||||
this.bannerVisible = true |
||||
}, |
||||
// banner弹框提交 |
||||
submitBanner () { |
||||
const { form } = this |
||||
if (!form.banner) return Util.errorMsg('请上传图片') |
||||
this.$post(this.api[form.id ? 'updateMarketing' : 'saveMarketing'], form).then(res => { |
||||
this.getList() |
||||
this.bannerVisible = false |
||||
}).catch(res => { }) |
||||
}, |
||||
handleDelete (row) { |
||||
this.$confirm("此删除操作不可逆,是否确认删除选中项?", "提示", { |
||||
type: "warning" |
||||
}) |
||||
.then(() => { |
||||
this.$post(`${this.api.delMarketing}?ids=${row.id}`).then(res => { |
||||
Util.successMsg("删除成功"); |
||||
this.getList(); |
||||
}).catch(res => { |
||||
}); |
||||
}) |
||||
.catch(() => { |
||||
}); |
||||
}, |
||||
switchOff (val, row) { |
||||
this.$post(`${this.api.bannerEnableOrDisable}?id=${row.id}&isDisable=${row.isOpen}`).then(res => { }).catch(err => { }) |
||||
} |
||||
} |
||||
}; |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.m-l-10 { |
||||
margin-left: 10px; |
||||
} |
||||
|
||||
$avatar-width: 104px; |
||||
|
||||
/deep/ .avatar-uploader { |
||||
.el-upload { |
||||
position: relative; |
||||
width: $avatar-width; |
||||
height: $avatar-width; |
||||
border: 1px dashed #d9d9d9; |
||||
border-radius: 2px; |
||||
cursor: pointer; |
||||
overflow: hidden; |
||||
|
||||
&:hover { |
||||
border-color: #409eff; |
||||
} |
||||
|
||||
.uploader-default { |
||||
display: flex; |
||||
flex-direction: column; |
||||
justify-content: center; |
||||
width: $avatar-width !important; |
||||
height: $avatar-width; |
||||
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 { |
||||
width: $avatar-width; |
||||
height: $avatar-width; |
||||
display: block; |
||||
} |
||||
} |
||||
|
||||
.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; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,675 @@ |
||||
<template> |
||||
<div> |
||||
<el-card shadow="hover" class="m-b-20 head-card"> |
||||
<div class="flex-between m-b-20"> |
||||
<el-page-header @back="back" content="成绩管理"></el-page-header> |
||||
</div> |
||||
|
||||
</el-card> |
||||
|
||||
<div v-loading="loading"> |
||||
<el-card v-if="method != 2" shadow="hover" class="m-b-20"> |
||||
<div class="stat"> |
||||
<div class="nums"> |
||||
<div class="item"> |
||||
<p class="name">已参加/应参加人数</p> |
||||
<p class="val">{{ isNaN(statData.totalNumber) ? '' : statData.attendance + '/' + statData.totalNumber }} |
||||
</p> |
||||
</div> |
||||
<div class="item"> |
||||
<p class="name">实验平均分</p> |
||||
<p class="val">{{ avgScore }}</p> |
||||
</div> |
||||
</div> |
||||
<div class="chart" id="chart"></div> |
||||
</div> |
||||
</el-card> |
||||
|
||||
<el-card shadow="hover" class="m-b-20"> |
||||
<div v-if="showFile" class="tabs m-b-20"> |
||||
<a class="item" v-for="(item, i) in tabs" :key="i" :class="{ active: i === active }" @click="tabChange(i)">{{ |
||||
item }}</a> |
||||
</div> |
||||
|
||||
|
||||
<div class="tool flex-between"> |
||||
<ul class="filter"> |
||||
<li> |
||||
<label>省份</label> |
||||
<el-select v-model="filter.provinceId" filterable clearable placeholder="请选择省份" @change="provinceChange" |
||||
@clear="clearProvince"> |
||||
<el-option v-for="(item, i) in provinces" :key="i" :label="item.provinceName" |
||||
:value="item.provinceId"></el-option> |
||||
</el-select> |
||||
</li> |
||||
<li> |
||||
<label>城市</label> |
||||
<el-select v-model="filter.cityId" filterable clearable placeholder="请选择城市" :disabled="!filter.provinceId" |
||||
@change="initData"> |
||||
<el-option v-for="(item, i) in cities" :key="i" :label="item.cityName" :value="item.cityId"></el-option> |
||||
</el-select> |
||||
</li> |
||||
<li> |
||||
<label>学校</label> |
||||
<el-select v-model="filter.realSchoolId" clearable filterable placeholder="请选择学校" @change="initData"> |
||||
<el-option v-for="(item, i) in schools" :key="i" :label="item.schoolName" |
||||
:value="item.schoolId"></el-option> |
||||
</el-select> |
||||
</li> |
||||
<li> |
||||
<el-input size="small" placeholder="请输入学生姓名" prefix-icon="el-icon-search" v-model="keyword" clearable |
||||
style="width: 300px"></el-input> |
||||
</li> |
||||
</ul> |
||||
<div v-if="!active"> |
||||
<el-button v-if="method == 2" type="primary" @click="batchImport">上传成绩</el-button> |
||||
<el-button type="primary" :disabled="!!multipleSelection.find(e => method != 2 && !e.reportId)" |
||||
@click="delAllData">批量删除</el-button> |
||||
<el-button type="primary" :loading="exporting" @click="exportData">{{ exporting ? '正在导出' : '批量导出' |
||||
}}</el-button> |
||||
</div> |
||||
<div v-else> |
||||
<el-button type="primary" :loading="exporting1" @click="exportData1">{{ exporting1 ? '正在导出' : '批量导出' |
||||
}}</el-button> |
||||
</div> |
||||
</div> |
||||
<template v-if="!active"> |
||||
<el-table :data="list" class="table" :key="1" ref="table" 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="provinceName" label="省份" min-width="100" align="center"></el-table-column> |
||||
<el-table-column prop="cityName" label="城市" min-width="100" align="center"></el-table-column> |
||||
<el-table-column prop="schoolName" label="学生账号归属" min-width="100" align="center"></el-table-column> |
||||
<el-table-column prop="realSchool" label="学生所在院校" min-width="100" align="center"></el-table-column> |
||||
<el-table-column v-if="competitionType" prop="teamName" label="团队名称" min-width="100" |
||||
align="center"></el-table-column> |
||||
<el-table-column prop="userName" label="学生姓名" min-width="100" align="center"></el-table-column> |
||||
<el-table-column prop="workNumber" label="学号" min-width="100" align="center"></el-table-column> |
||||
<el-table-column prop="score" label="分数" width="90" align="center"> |
||||
<template slot-scope="scope"> |
||||
{{ scope.row.submitTime ? scope.row.score : '--' }} |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column prop="timeSum" label="耗时" width="90" align="center"> |
||||
<template slot-scope="scope"> |
||||
{{ scope.row.timeSum ? scope.row.timeSum + 'min' : '--' }} |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column prop="submitTime" label="提交时间" min-width="150" align="center"> |
||||
<template slot-scope="scope"> |
||||
{{ scope.row.submitTime || '--' }} |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column label="状态" width="100" align="center"> |
||||
<template slot-scope="scope"> |
||||
{{ scope.row.reportId || method == 2 ? '已参加' : '未参加' }} |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column label="操作" align="center" width="160"> |
||||
<template slot-scope="scope"> |
||||
<el-button v-if="method != 2 && scope.row.reportId" type="text" |
||||
@click="show(scope.row)">查看成绩报告</el-button> |
||||
<el-button v-if="scope.row.reportId" type="text" @click="handleDelete(scope.row)">删除</el-button> |
||||
</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> |
||||
</template> |
||||
<template v-else> |
||||
<el-table :data="list1" class="table" :key="2" header-align="center" |
||||
@selection-change="handleSelectionChange1" 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 + (page1 - 1) * pageSize + 1 }} |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column prop="provinceName" label="省份" align="center"></el-table-column> |
||||
<el-table-column prop="cityName" label="城市" align="center"></el-table-column> |
||||
<el-table-column prop="schoolName" label="学生账号归属" align="center"></el-table-column> |
||||
<el-table-column prop="realSchool" label="学生所在院校" align="center"></el-table-column> |
||||
<el-table-column v-if="competitionType" prop="teamName" label="团队名称" align="center"></el-table-column> |
||||
<el-table-column prop="userName" label="学生姓名" align="center"></el-table-column> |
||||
<el-table-column prop="workNumber" label="学号" align="center"></el-table-column> |
||||
<el-table-column prop="fileName" label="文件名" align="center"></el-table-column> |
||||
<el-table-column prop="fileSize" label="文件大小" align="center"></el-table-column> |
||||
<el-table-column prop="fileType" label="文件类型" align="center"></el-table-column> |
||||
<el-table-column prop="fileFormat" label="文件格式" align="center"></el-table-column> |
||||
<el-table-column prop="createTime" label="提交时间" width="150" align="center"> |
||||
</el-table-column> |
||||
<el-table-column label="操作" width="200"> |
||||
<template slot-scope="scope"> |
||||
<el-button v-if="!isCompress(scope.row.fileFormat)" type="text" |
||||
@click="preview(scope.row)">预览文件</el-button> |
||||
<el-button type="primary" size="mini" :loading="scope.row.loading" |
||||
@click="exportFile(scope.row)">导出文件</el-button> |
||||
</template> |
||||
</el-table-column> |
||||
</el-table> |
||||
<div class="pagination"> |
||||
<el-pagination background layout="total, prev, pager, next" :total="total1" |
||||
@current-change="handleCurrentChange1" :current-page="page1"> |
||||
</el-pagination> |
||||
</div> |
||||
</template> |
||||
</el-card> |
||||
</div> |
||||
<el-dialog title="批量导入" :visible.sync="importVisible" width="24%" :close-on-click-modal="false" |
||||
@close="cancelUpload"> |
||||
<div style="text-align: center"> |
||||
<template v-if="!uploadFaild"> |
||||
<div style="margin-bottom: 10px;"> |
||||
<el-button type="primary" @click="download">模板下载<i class="el-icon-download el-icon--right"></i></el-button> |
||||
</div> |
||||
<el-upload ref="upload" name="file" accept=".xls,.xlsx" class="import-file" :before-upload="beforeUpload" |
||||
:on-remove="handleRemove" :on-error="uploadError" :on-success="uploadSuccess" :before-remove="beforeRemove" |
||||
:limit="1" :on-exceed="handleExceed" :action="this.api.batchImportGrades" :file-list="uploadList" |
||||
:headers="headers" :disabled="uploading" :data="{ |
||||
competitionId: this.id, |
||||
stageId: this.stageId, |
||||
systemId: 0 |
||||
}"> |
||||
<el-button type="primary" :loading="uploading" class="ml20">上传文件<i |
||||
class="el-icon-upload2 el-icon--right"></i></el-button> |
||||
</el-upload> |
||||
</template> |
||||
<template v-else> |
||||
<p style="margin: -10px 0 13px;font-size: 14px;color: #e90000;">{{ faildData.tip }}</p> |
||||
<p type="primary" |
||||
style="margin-bottom: 10px;font-size: 14px;color: #062c87;text-decoration: underline;cursor: pointer;" |
||||
@click="showFaild">部分数据导入失败,查看失败原因</p> |
||||
</template> |
||||
</div> |
||||
<span v-if="uploading" slot="footer" class="dialog-footer"> |
||||
<el-button @click="cancelUpload">停止导入</el-button> |
||||
</span> |
||||
</el-dialog> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
import util from "@/libs/util"; |
||||
import * as echarts from "echarts"; |
||||
import axios from 'axios'; |
||||
import Zip from '@/libs/zip' |
||||
export default { |
||||
data () { |
||||
return { |
||||
id: +this.$route.query.id, |
||||
stageId: +this.$route.query.stageId, |
||||
method: +this.$route.query.method, |
||||
competitionType: +this.$route.query.competitionType, |
||||
showFile: this.$route.query.showFile === 'true', |
||||
isCompress: util.isCompress, |
||||
filter: { |
||||
provinceId: '', |
||||
cityId: '', |
||||
realSchoolId: '', |
||||
reviewStatus: '', |
||||
scoreSortOrder: '', |
||||
submitTimeSortOrder: '', |
||||
}, |
||||
provinces: [], |
||||
cities: [], |
||||
schools: [], |
||||
keyword: this.$route.query.keyword || '', |
||||
searchTimer: null, |
||||
list: [], |
||||
multipleSelection: [], |
||||
page: +this.$route.query.page || 1, |
||||
pageSize: 10, |
||||
total: 0, |
||||
|
||||
list1: [], |
||||
multipleSelection1: [], |
||||
page1: 1, |
||||
total1: 0, |
||||
|
||||
avgScore: 0, // 平均分 |
||||
importVisible: false, |
||||
uploadList: [], |
||||
uploadFaild: false, |
||||
uploading: false, |
||||
faildData: null, |
||||
headers: { |
||||
token: sessionStorage.getItem("token") |
||||
}, |
||||
statData: {}, |
||||
tabs: ['成绩列表', '文件列表'], |
||||
active: 0, |
||||
loading: false, |
||||
exporting: false, |
||||
exporting1: false, |
||||
}; |
||||
}, |
||||
watch: { |
||||
keyword: function (val) { |
||||
clearTimeout(this.searchTimer); |
||||
this.searchTimer = setTimeout(() => { |
||||
this.$router.push({ |
||||
path: '/otherArchList', |
||||
query: { |
||||
...this.$route.query, |
||||
keyword: val |
||||
} |
||||
}) |
||||
this.initData(); |
||||
}, 500); |
||||
} |
||||
}, |
||||
mounted () { |
||||
this.getData() |
||||
this.getProvince() |
||||
this.getSchool() |
||||
}, |
||||
methods: { |
||||
async getData () { |
||||
this.loading = true |
||||
// 文件列表 |
||||
if (this.active) { |
||||
const { data } = await this.$post(this.api.cCompetitionStageFileList, { |
||||
pageNum: this.page1, |
||||
pageSize: this.pageSize, |
||||
competitionId: this.id, |
||||
stageId: this.stageId, |
||||
keyWord: this.keyword, |
||||
...this.filter |
||||
}) |
||||
data.records.forEach(e => { |
||||
e.loading = false |
||||
e.fileType = '其他' |
||||
if (util.isVideo(e.fileFormat)) { |
||||
e.fileType = '视频' |
||||
} else if (util.isAudio(e.fileFormat)) { |
||||
e.fileType = '音频' |
||||
} else if (util.isImg(e.fileFormat)) { |
||||
e.fileType = '图片' |
||||
} else if (util.isDoc(e.fileFormat)) { |
||||
e.fileType = '文档' |
||||
} else if (util.isCompress(e.fileFormat)) { |
||||
e.fileType = '压缩包' |
||||
} else if (e.fileType === 'pdf') { |
||||
e.fileType = 'pdf' |
||||
} |
||||
}) |
||||
this.list1 = data.records |
||||
this.total1 = data.total |
||||
this.loading = false |
||||
} else { // 成绩列表 |
||||
const { data, page } = await this.$post(this.api.stageGradeManagementList, { |
||||
pageNum: this.page, |
||||
pageSize: this.pageSize, |
||||
competitionId: this.id, |
||||
keyWord: this.keyword, |
||||
stageId: this.stageId, |
||||
isNakadai: 1, |
||||
...this.filter |
||||
}) |
||||
this.loading = false |
||||
this.total = page.total |
||||
this.list = page.records |
||||
this.statData = data |
||||
this.avgScore = (+data.avgScore).toFixed(2) |
||||
this.method != 2 && this.getChart() |
||||
} |
||||
}, |
||||
initData () { |
||||
this.page = 1 |
||||
this.getData() |
||||
}, |
||||
|
||||
// 获取省份 |
||||
async getProvince () { |
||||
const { list } = await this.$get(this.api.queryProvince) |
||||
this.provinces = list |
||||
}, |
||||
// 清除省份 |
||||
clearProvince () { |
||||
this.filter.cityId = '' |
||||
}, |
||||
// 省份选择回调 |
||||
provinceChange () { |
||||
this.clearProvince() |
||||
this.getCity() |
||||
this.initData() |
||||
}, |
||||
// 获取城市 |
||||
async getCity () { |
||||
const id = this.filter.provinceId |
||||
if (id) { |
||||
const { list } = await this.$get(this.api.queryCity, { |
||||
provinceId: id |
||||
}) |
||||
this.cities = list |
||||
} |
||||
}, |
||||
// 获取学校 |
||||
async getSchool () { |
||||
const { list } = await this.$get(this.api.querySchoolData) |
||||
this.schools = list |
||||
}, |
||||
|
||||
// 查看成绩报告 |
||||
show (row) { |
||||
this.$router.push(`/trialReport?reportId=${row.reportId}`) |
||||
}, |
||||
// 导出(有勾选:就导勾选中的;没有勾选:就导全部) |
||||
async exportData () { |
||||
if (this.list.length) { |
||||
this.exporting = true |
||||
// 有选择数据,则导出已选择的,否则导出全部 |
||||
if (this.multipleSelection.length) { |
||||
const res = await axios.post(this.api.exportExperimentalResultsInBatch, this.multipleSelection, { |
||||
headers: this.headers, |
||||
responseType: 'blob' |
||||
}) |
||||
util.downloadFileDirect(`赛事成绩.xls`, new Blob([res.data])) |
||||
this.exporting = false |
||||
} else if (this.list.length) { |
||||
const res = await axios.post(this.api.allExperimentalResultsAreDerived, { |
||||
pageNum: 1, |
||||
pageSize: 10000, |
||||
competitionId: this.id, |
||||
isNakadai: 1, |
||||
stageId: this.stageId, |
||||
}, { |
||||
headers: this.headers, |
||||
responseType: 'blob' |
||||
}) |
||||
util.downloadFileDirect(`赛事成绩.xls`, new Blob([res.data])) |
||||
this.exporting = false |
||||
} |
||||
} |
||||
}, |
||||
// 导出(有勾选:就导勾选中的;没有勾选:就导全部) |
||||
exportData1 () { |
||||
this.exporting1 = true |
||||
let list = this.list1 |
||||
if (this.multipleSelection1.length) { |
||||
list = this.multipleSelection1 |
||||
} |
||||
Zip('批量导出', list, () => { |
||||
this.exporting1 = false |
||||
}) |
||||
}, |
||||
handleDelete (row) { // 删除 |
||||
this.$confirm("确定要删除吗?", "提示", { |
||||
type: "warning" |
||||
}).then(() => { |
||||
this.$post(this.api.batchDeleteContestGrade, { |
||||
ids: [this.method == 2 ? row.scoreId : row.reportId], |
||||
competitionId: this.id, |
||||
stageId: this.stageId |
||||
}).then(res => { |
||||
util.successMsg("删除成功"); |
||||
this.getData(); |
||||
}).catch(res => { |
||||
}); |
||||
}).catch(() => { }); |
||||
}, |
||||
delAllData () { // 批量删除 |
||||
const list = this.multipleSelection |
||||
this.$confirm(list.length ? '该项目下的所有成绩报告将会删除,是否继续?' : '是否确定删除列表所有成绩数据?', "提示", { |
||||
type: "warning" |
||||
}).then(async () => { |
||||
let ids = [] |
||||
if (list.length) { |
||||
ids = list.map(item => { |
||||
return this.method == 2 ? item.scoreId : item.reportId |
||||
}); |
||||
ids = ids.filter(e => e) |
||||
} |
||||
const data = { |
||||
competitionId: this.id, |
||||
stageId: this.stageId |
||||
} |
||||
if (list.length) data.ids = ids |
||||
await this.$post(this.api.batchDeleteContestGrade, data) |
||||
this.multipleSelection = []; |
||||
this.$refs.table.clearSelection(); |
||||
util.successMsg("删除成功"); |
||||
this.getData(); |
||||
}).catch(() => { }); |
||||
}, |
||||
handleSelectionChange (val) { // 多选 |
||||
this.multipleSelection = val; |
||||
}, |
||||
handleCurrentChange (val) { // 切换分页 |
||||
this.$router.push({ |
||||
path: '/otherArchList', |
||||
query: { |
||||
...this.$route.query, |
||||
page: val |
||||
} |
||||
}) |
||||
this.page = val; |
||||
this.getData(); |
||||
}, |
||||
|
||||
handleSelectionChange1 (val) { // 多选 |
||||
this.multipleSelection1 = val; |
||||
}, |
||||
handleCurrentChange1 (val) { // 切换分页 |
||||
this.page1 = val; |
||||
this.getData(); |
||||
}, |
||||
getChart () { // 初始化折线图 |
||||
const data = [] |
||||
const { statData } = this |
||||
for (let i = 1; i <= 10; i++) { |
||||
data.push(statData['num' + i]) |
||||
} |
||||
let myChart = echarts.init(document.getElementById("chart")); |
||||
myChart.setOption({ |
||||
title: { text: "实验分数分布图" }, |
||||
tooltip: {}, |
||||
xAxis: { |
||||
name: "分数", |
||||
type: "category", |
||||
boundaryGap: false, |
||||
interval: 10, |
||||
data: ["0-10", "10-20", "20-30", "30-40", "40-50", "50-60", "60-70", "70-80", "80-90", "90-100"] |
||||
}, |
||||
yAxis: { |
||||
name: "人数", |
||||
type: "value", |
||||
minInterval: 10 |
||||
}, |
||||
series: [{ |
||||
data, |
||||
type: "line", |
||||
areaStyle: {}, |
||||
label: { |
||||
show: true, |
||||
position: 'top' |
||||
}, |
||||
color: ["#8191fd"] |
||||
}] |
||||
}); |
||||
}, |
||||
// 批量导入 |
||||
batchImport () { |
||||
this.importVisible = true |
||||
this.uploadList = [] |
||||
this.uploadFaild = false |
||||
}, |
||||
// 模板下载 |
||||
download () { |
||||
axios.get(`${this.api.gradeDownloadExcel}?competitionId=${this.id}&stageId=${this.stageId}`, { |
||||
headers: this.headers, |
||||
responseType: 'blob' |
||||
}).then((res) => { |
||||
util.downloadFileDirect('赛事成绩导入模板.xlsx', new Blob([res.data])) |
||||
}).catch(res => { }) |
||||
}, |
||||
// 上传文件 |
||||
handleExceed (files, fileList) { |
||||
util.warningMsg( |
||||
`当前限制选择 1 个文件,如需更换,请删除上一个文件再重新选择!` |
||||
) |
||||
}, |
||||
// 下载失败文件 |
||||
showFaild () { |
||||
axios.get(`${this.api.performanceExportFailure}?exportCode=${this.faildData.exportCode}&competitionType=${this.faildData.competitionType}`, { |
||||
headers: this.headers, |
||||
responseType: 'blob' |
||||
}).then((res) => { |
||||
util.downloadFileDirect(`批量导入成绩管理失败数据导出.xls`, new Blob([res.data])) |
||||
}).catch(res => { }) |
||||
}, |
||||
uploadSuccess (res) { |
||||
this.uploading = false |
||||
this.uploadFaild = false |
||||
if (res.status === 200) { |
||||
this.initData() |
||||
const { data } = res |
||||
if (data.exportCode) { |
||||
this.faildData = data |
||||
this.uploadFaild = true |
||||
} else { |
||||
util.successMsg(data.tip, 3000) |
||||
this.importVisible = false |
||||
} |
||||
} else { |
||||
util.errorMsg(res.message || '上传失败,请检查数据') |
||||
} |
||||
}, |
||||
uploadError (err, file, fileList) { |
||||
this.uploading = false |
||||
this.$message({ |
||||
message: "上传出错,请重试!", |
||||
type: "error", |
||||
center: true |
||||
}) |
||||
}, |
||||
beforeUpload (file) { |
||||
this.uploading = true |
||||
}, |
||||
beforeRemove (file, fileList) { |
||||
return this.$confirm(`确定移除 ${file.name}?`) |
||||
}, |
||||
handleRemove (file, fileList) { |
||||
this.uploadList = fileList |
||||
this.uploadFaild = false |
||||
}, |
||||
cancelUpload () { |
||||
this.uploading = false |
||||
if (this.$refs.upload) this.$refs.upload.abort() |
||||
this.keyword = '' |
||||
this.initData() |
||||
this.importVisible = false |
||||
}, |
||||
// tab回调 |
||||
tabChange (i) { |
||||
this.active = i |
||||
this.getData() |
||||
}, |
||||
// 预览附件 |
||||
preview (item) { |
||||
window.open((util.isDoc(item.fileFormat) ? 'https://view.officeapps.live.com/op/view.aspx?src=' : '') + item.filePath) |
||||
}, |
||||
// 导出文件 |
||||
exportFile (item) { |
||||
item.loading = true |
||||
const url = item.filePath |
||||
var x = new XMLHttpRequest() |
||||
x.open("GET", url, true) |
||||
x.responseType = "blob" |
||||
x.onload = function (e) { |
||||
var url = window.URL.createObjectURL(x.response) |
||||
var a = document.createElement("a") |
||||
a.href = url |
||||
a.download = item.userName + '-' + item.fileName |
||||
a.click() |
||||
item.loading = false |
||||
} |
||||
x.send() |
||||
}, |
||||
back () { |
||||
this.$router.push(this.$store.state.innerReferrer) |
||||
} |
||||
} |
||||
}; |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
/deep/ .head-card { |
||||
.el-card__body { |
||||
padding-bottom: 0px; |
||||
|
||||
.el-tabs__header { |
||||
margin-bottom: 1px; |
||||
|
||||
.el-tabs__nav-wrap::after { |
||||
display: none; |
||||
} |
||||
|
||||
.el-tabs__item { |
||||
font-size: 18px; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
.stat { |
||||
display: flex; |
||||
|
||||
.nums { |
||||
display: flex; |
||||
align-items: center; |
||||
margin-right: 20px; |
||||
|
||||
.item:nth-child(1) { |
||||
background-image: url('../../../assets/img/total.png'); |
||||
} |
||||
|
||||
.item:nth-child(2) { |
||||
background-image: url('../../../assets/img/avg.png'); |
||||
} |
||||
|
||||
.item { |
||||
width: 300px; |
||||
min-height: 145px; |
||||
padding: 30px 30px; |
||||
margin: 0 10px; |
||||
box-sizing: border-box; |
||||
border-radius: 8px; |
||||
background-size: 100% 100%; |
||||
background-repeat: no-repeat; |
||||
|
||||
p { |
||||
font-size: 18px; |
||||
color: #ffffff; |
||||
} |
||||
|
||||
.val { |
||||
margin-top: 10px; |
||||
color: #ffffff; |
||||
font-size: 36px; |
||||
} |
||||
} |
||||
} |
||||
|
||||
.chart { |
||||
flex: 1; |
||||
height: 300px; |
||||
} |
||||
} |
||||
|
||||
/deep/.import-file { |
||||
.el-progress__text, |
||||
.el-progress, |
||||
.el-upload-list__item-status-label { |
||||
display: none !important; |
||||
} |
||||
} |
||||
</style> |
@ -1,535 +0,0 @@ |
||||
<template> |
||||
<div> |
||||
<el-card shadow="hover" class="m-b-20 head-card"> |
||||
<div class="flex-between m-b-20"> |
||||
<el-page-header @back="back" content="成绩管理"></el-page-header> |
||||
</div> |
||||
|
||||
</el-card> |
||||
|
||||
<div v-loading="loading"> |
||||
<el-card v-if="method != 2" shadow="hover" class="m-b-20"> |
||||
<div class="stat"> |
||||
<div class="nums"> |
||||
<div class="item"> |
||||
<p class="name">已参加/应参加人数</p> |
||||
<p class="val">{{ isNaN(statData.totalNumber) ? '' : statData.attendance + '/' + statData.totalNumber }} |
||||
</p> |
||||
</div> |
||||
<div class="item"> |
||||
<p class="name">平均分</p> |
||||
<p class="val">{{ (+statData.avgScore).toFixed(2) }}</p> |
||||
</div> |
||||
<div class="item"> |
||||
<p class="name">最高分</p> |
||||
<p class="val">{{ statData.maxScore }} |
||||
</p> |
||||
</div> |
||||
<div class="item"> |
||||
<p class="name">最低分</p> |
||||
<p class="val">{{ statData.minScore }}</p> |
||||
</div> |
||||
</div> |
||||
<div class="chart" id="chart"></div> |
||||
</div> |
||||
</el-card> |
||||
|
||||
<el-card shadow="hover" class="m-b-20"> |
||||
<div class="tabs m-b-20"> |
||||
<a class="item" v-for="(item, i) in tabs" :key="i" :class="{ active: item.id === active }" |
||||
@click="tabChange(item.id)">{{ item.name }}</a> |
||||
</div> |
||||
|
||||
<div class="flex-between m-b-20"> |
||||
<div> |
||||
<el-input size="small" placeholder="请输入学校/学生姓名" prefix-icon="el-icon-search" v-model="keyword" clearable |
||||
style="width: 300px"></el-input> |
||||
</div> |
||||
<el-button type="primary" :loading="exporting" @click="exportData">{{ exporting ? '正在导出' : '批量导出' |
||||
}}</el-button> |
||||
</div> |
||||
<el-table :data="list" class="table" :key="1" ref="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="schoolName" label="学生账号归属" min-width="100" align="center"></el-table-column> |
||||
<el-table-column prop="realSchool" label="学生所在院校" min-width="100" align="center"></el-table-column> |
||||
<el-table-column v-if="competitionType" prop="teamName" label="团队名称" min-width="100" |
||||
align="center"></el-table-column> |
||||
<el-table-column prop="userName" label="学生姓名" min-width="100" align="center"></el-table-column> |
||||
<el-table-column prop="workNumber" label="学号" min-width="100" align="center"></el-table-column> |
||||
<el-table-column prop="score" label="分数" width="90" align="center"> |
||||
<template slot-scope="scope"> |
||||
{{ scope.row.submitTime ? scope.row.score : '--' }} |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column prop="timeSum" label="耗时" width="90" align="center"> |
||||
<template slot-scope="scope"> |
||||
{{ scope.row.timeSum ? scope.row.timeSum + 'min' : '--' }} |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column prop="submitTime" label="提交时间" min-width="150" align="center"> |
||||
<template slot-scope="scope"> |
||||
{{ scope.row.submitTime || '--' }} |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column label="状态" width="100" align="center"> |
||||
<template slot-scope="scope"> |
||||
{{ scope.row.reportId || method == 2 ? '已参加' : '未参加' }} |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column label="操作" align="center" width="160"> |
||||
<template slot-scope="scope"> |
||||
<el-button v-if="method != 2 && scope.row.reportId" type="text" |
||||
@click="show(scope.row)">查看成绩报告</el-button> |
||||
<el-button v-if="scope.row.reportId" type="text" @click="handleDelete(scope.row)">删除</el-button> |
||||
</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> |
||||
</el-card> |
||||
</div> |
||||
<el-dialog title="批量导入" :visible.sync="importVisible" width="24%" :close-on-click-modal="false" |
||||
@close="cancelUpload"> |
||||
<div style="text-align: center"> |
||||
<template v-if="!uploadFaild"> |
||||
<div style="margin-bottom: 10px;"> |
||||
<el-button type="primary" @click="download">模板下载<i class="el-icon-download el-icon--right"></i></el-button> |
||||
</div> |
||||
<el-upload ref="upload" name="file" accept=".xls,.xlsx" class="import-file" :before-upload="beforeUpload" |
||||
:on-remove="handleRemove" :on-error="uploadError" :on-success="uploadSuccess" :before-remove="beforeRemove" |
||||
:limit="1" :on-exceed="handleExceed" :action="this.api.batchImportGrades" :file-list="uploadList" |
||||
:headers="headers" :disabled="uploading" :data="{ |
||||
competitionId: this.id, |
||||
stageId: this.stageId, |
||||
systemId: 0 |
||||
}"> |
||||
<el-button type="primary" :loading="uploading" class="ml20">上传文件<i |
||||
class="el-icon-upload2 el-icon--right"></i></el-button> |
||||
</el-upload> |
||||
</template> |
||||
<template v-else> |
||||
<p style="margin: -10px 0 13px;font-size: 14px;color: #e90000;">{{ faildData.tip }}</p> |
||||
<p type="primary" |
||||
style="margin-bottom: 10px;font-size: 14px;color: #9076FF;text-decoration: underline;cursor: pointer;" |
||||
@click="showFaild">部分数据导入失败,查看失败原因</p> |
||||
</template> |
||||
</div> |
||||
<span v-if="uploading" slot="footer" class="dialog-footer"> |
||||
<el-button @click="cancelUpload">停止导入</el-button> |
||||
</span> |
||||
</el-dialog> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
import util from "@/libs/util"; |
||||
import * as echarts from "echarts"; |
||||
import axios from 'axios'; |
||||
import Zip from '@/libs/zip' |
||||
export default { |
||||
data () { |
||||
return { |
||||
id: +this.$route.query.id, |
||||
stageId: +this.$route.query.stageId, |
||||
method: +this.$route.query.method, |
||||
competitionType: +this.$route.query.competitionType, |
||||
isCompress: util.isCompress, |
||||
keyword: this.$route.query.keyword || '', |
||||
searchTimer: null, |
||||
list: [], |
||||
multipleSelection: [], |
||||
page: +this.$route.query.page || 1, |
||||
pageSize: 10, |
||||
total: 0, |
||||
|
||||
list1: [], |
||||
multipleSelection1: [], |
||||
page1: 1, |
||||
total1: 0, |
||||
|
||||
avgScore: 0, // 平均分 |
||||
importVisible: false, |
||||
uploadList: [], |
||||
uploadFaild: false, |
||||
uploading: false, |
||||
faildData: null, |
||||
headers: { |
||||
token: sessionStorage.getItem("token") |
||||
}, |
||||
statData: { |
||||
avgScore: 0, |
||||
maxScore: 0, |
||||
minScore: 0, |
||||
}, |
||||
tabs: [ |
||||
{ |
||||
id: 1, |
||||
name: '已提交' |
||||
}, |
||||
{ |
||||
id: 0, |
||||
name: '未提交' |
||||
} |
||||
], |
||||
active: 1, |
||||
loading: false, |
||||
exporting: false, |
||||
exporting1: false, |
||||
}; |
||||
}, |
||||
watch: { |
||||
keyword: function (val) { |
||||
clearTimeout(this.searchTimer); |
||||
this.searchTimer = setTimeout(() => { |
||||
this.$router.push({ |
||||
path: '/theoryArchList', |
||||
query: { |
||||
...this.$route.query, |
||||
keyword: val |
||||
} |
||||
}) |
||||
this.initData(); |
||||
}, 500); |
||||
} |
||||
}, |
||||
mounted () { |
||||
this.getData() |
||||
}, |
||||
methods: { |
||||
async getData () { |
||||
this.loading = true |
||||
const { data, page } = await this.$post(this.api.stageGradeManagementList, { |
||||
pageNum: this.page, |
||||
pageSize: this.pageSize, |
||||
competitionId: this.id, |
||||
keyWord: this.keyword, |
||||
stageId: this.stageId, |
||||
isNakadai: 1, |
||||
participatingState: this.active, |
||||
}) |
||||
this.loading = false |
||||
this.total = page.total |
||||
this.list = page.records |
||||
this.statData = data |
||||
this.getChart() |
||||
}, |
||||
initData () { |
||||
this.page = 1 |
||||
this.getData() |
||||
}, |
||||
// 查看成绩报告 |
||||
show (row) { |
||||
this.$router.push(`/theoryReport?reportId=${row.reportId}`) |
||||
}, |
||||
// 导出(有勾选:就导勾选中的;没有勾选:就导全部) |
||||
async exportData () { |
||||
if (this.list.length) { |
||||
this.exporting = true |
||||
// 有选择数据,则导出已选择的,否则导出全部 |
||||
if (this.multipleSelection.length) { |
||||
const res = await axios.post(this.api.exportExperimentalResultsInBatch, this.multipleSelection, { |
||||
headers: this.headers, |
||||
responseType: 'blob' |
||||
}) |
||||
util.downloadFileDirect(`赛事成绩.xls`, new Blob([res.data])) |
||||
this.exporting = false |
||||
} else if (this.list.length) { |
||||
const res = await axios.post(this.api.allExperimentalResultsAreDerived, { |
||||
pageNum: 1, |
||||
pageSize: 10000, |
||||
competitionId: this.id, |
||||
isNakadai: 1, |
||||
stageId: this.stageId, |
||||
participatingState: this.active, |
||||
}, { |
||||
headers: this.headers, |
||||
responseType: 'blob' |
||||
}) |
||||
util.downloadFileDirect(`赛事成绩.xls`, new Blob([res.data])) |
||||
this.exporting = false |
||||
} |
||||
} |
||||
}, |
||||
async handleDelete (row) { // 删除 |
||||
await this.$confirm(`<p>确认要删除【${row.userName}】的成绩记录吗?</p><p style="color: #f56c6c;">删除后成绩数据不可恢复,自动变为未提交</p>`, '提示', { |
||||
confirmButtonText: '确定', |
||||
cancelButtonText: '取消', |
||||
type: 'warning', |
||||
closeOnClickModal: false, |
||||
dangerouslyUseHTMLString: true, |
||||
}) |
||||
|
||||
await this.$post(this.api.batchDeleteContestGrade, { |
||||
ids: [this.method == 2 ? row.scoreId : row.reportId], |
||||
competitionId: this.id, |
||||
stageId: this.stageId |
||||
}) |
||||
util.successMsg("删除成功") |
||||
this.getData() |
||||
}, |
||||
delAllData () { // 批量删除 |
||||
const list = this.multipleSelection |
||||
this.$confirm(list.length ? '该项目下的所有成绩报告将会删除,是否继续?' : '是否确定删除列表所有成绩数据?', "提示", { |
||||
type: "warning" |
||||
}).then(async () => { |
||||
let ids = [] |
||||
if (list.length) { |
||||
ids = list.map(item => { |
||||
return this.method == 2 ? item.scoreId : item.reportId |
||||
}); |
||||
ids = ids.filter(e => e) |
||||
} |
||||
const data = { |
||||
competitionId: this.id, |
||||
stageId: this.stageId |
||||
} |
||||
if (list.length) data.ids = ids |
||||
await this.$post(this.api.batchDeleteContestGrade, data) |
||||
this.multipleSelection = []; |
||||
this.$refs.table.clearSelection(); |
||||
util.successMsg("删除成功"); |
||||
this.getData(); |
||||
}).catch(() => { }); |
||||
}, |
||||
handleSelectionChange (val) { // 多选 |
||||
this.multipleSelection = val; |
||||
}, |
||||
handleCurrentChange (val) { // 切换分页 |
||||
this.$router.push({ |
||||
path: '/theoryArchList', |
||||
query: { |
||||
...this.$route.query, |
||||
page: val |
||||
} |
||||
}) |
||||
this.page = val; |
||||
this.getData(); |
||||
}, |
||||
|
||||
handleSelectionChange1 (val) { // 多选 |
||||
this.multipleSelection1 = val; |
||||
}, |
||||
getChart () { // 初始化折线图 |
||||
const { fractionalSegmentCounts: data } = this.statData |
||||
let myChart = echarts.init(document.getElementById("chart")); |
||||
myChart.setOption({ |
||||
title: { text: "实验分数分布图" }, |
||||
tooltip: {}, |
||||
xAxis: { |
||||
name: "分数", |
||||
type: "category", |
||||
boundaryGap: false, |
||||
interval: 10, |
||||
data: data.map(e => e.range) |
||||
}, |
||||
yAxis: { |
||||
name: "人数", |
||||
type: "value", |
||||
minInterval: 10 |
||||
}, |
||||
series: [{ |
||||
data: data.map(e => e.count), |
||||
type: "line", |
||||
areaStyle: {}, |
||||
color: ["#8191fd"] |
||||
}] |
||||
}); |
||||
}, |
||||
// 批量导入 |
||||
batchImport () { |
||||
this.importVisible = true |
||||
this.uploadList = [] |
||||
this.uploadFaild = false |
||||
}, |
||||
// 模板下载 |
||||
download () { |
||||
axios.get(`${this.api.gradeDownloadExcel}?competitionId=${this.id}&stageId=${this.stageId}`, { |
||||
headers: this.headers, |
||||
responseType: 'blob' |
||||
}).then((res) => { |
||||
util.downloadFileDirect('赛事成绩导入模板.xlsx', new Blob([res.data])) |
||||
}).catch(res => { }) |
||||
}, |
||||
// 上传文件 |
||||
handleExceed (files, fileList) { |
||||
util.warningMsg( |
||||
`当前限制选择 1 个文件,如需更换,请删除上一个文件再重新选择!` |
||||
) |
||||
}, |
||||
// 下载失败文件 |
||||
showFaild () { |
||||
axios.get(`${this.api.performanceExportFailure}?exportCode=${this.faildData.exportCode}&competitionType=${this.faildData.competitionType}`, { |
||||
headers: this.headers, |
||||
responseType: 'blob' |
||||
}).then((res) => { |
||||
util.downloadFileDirect(`批量导入成绩管理失败数据导出.xls`, new Blob([res.data])) |
||||
}).catch(res => { }) |
||||
}, |
||||
uploadSuccess (res) { |
||||
this.uploading = false |
||||
this.uploadFaild = false |
||||
if (res.status === 200) { |
||||
this.initData() |
||||
const { data } = res |
||||
if (data.exportCode) { |
||||
this.faildData = data |
||||
this.uploadFaild = true |
||||
} else { |
||||
util.successMsg(data.tip, 3000) |
||||
this.importVisible = false |
||||
} |
||||
} else { |
||||
util.errorMsg(res.message || '上传失败,请检查数据') |
||||
} |
||||
}, |
||||
uploadError (err, file, fileList) { |
||||
this.uploading = false |
||||
this.$message({ |
||||
message: "上传出错,请重试!", |
||||
type: "error", |
||||
center: true |
||||
}) |
||||
}, |
||||
beforeUpload (file) { |
||||
this.uploading = true |
||||
}, |
||||
beforeRemove (file, fileList) { |
||||
return this.$confirm(`确定移除 ${file.name}?`) |
||||
}, |
||||
handleRemove (file, fileList) { |
||||
this.uploadList = fileList |
||||
this.uploadFaild = false |
||||
}, |
||||
cancelUpload () { |
||||
this.uploading = false |
||||
if (this.$refs.upload) this.$refs.upload.abort() |
||||
this.keyword = '' |
||||
this.initData() |
||||
this.importVisible = false |
||||
}, |
||||
// tab回调 |
||||
tabChange (i) { |
||||
this.multipleSelection = [] |
||||
this.$refs.table.clearSelection() |
||||
this.active = i |
||||
this.initData() |
||||
}, |
||||
// 预览附件 |
||||
preview (item) { |
||||
window.open((util.isDoc(item.fileFormat) ? 'https://view.officeapps.live.com/op/view.aspx?src=' : '') + item.filePath) |
||||
}, |
||||
// 导出文件 |
||||
exportFile (item) { |
||||
item.loading = true |
||||
const url = item.filePath |
||||
var x = new XMLHttpRequest() |
||||
x.open("GET", url, true) |
||||
x.responseType = "blob" |
||||
x.onload = function (e) { |
||||
var url = window.URL.createObjectURL(x.response) |
||||
var a = document.createElement("a") |
||||
a.href = url |
||||
a.download = item.userName + '-' + item.fileName |
||||
a.click() |
||||
item.loading = false |
||||
} |
||||
x.send() |
||||
}, |
||||
back () { |
||||
this.$router.push(this.$store.state.innerReferrer) |
||||
} |
||||
} |
||||
}; |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
/deep/ .head-card { |
||||
.el-card__body { |
||||
padding-bottom: 0px; |
||||
|
||||
.el-tabs__header { |
||||
margin-bottom: 1px; |
||||
|
||||
.el-tabs__nav-wrap::after { |
||||
display: none; |
||||
} |
||||
|
||||
.el-tabs__item { |
||||
font-size: 18px; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
.stat { |
||||
display: flex; |
||||
|
||||
.nums { |
||||
display: flex; |
||||
flex-wrap: wrap; |
||||
align-items: center; |
||||
width: 640px; |
||||
margin-right: 20px; |
||||
|
||||
.item:nth-child(1) { |
||||
background-image: url('../../../assets/img/total.png'); |
||||
} |
||||
|
||||
.item:nth-child(2) { |
||||
background-image: url('../../../assets/img/avg.png'); |
||||
} |
||||
|
||||
.item:nth-child(3) { |
||||
background-image: url('../../../assets/img/ach1.png'); |
||||
} |
||||
|
||||
.item:nth-child(4) { |
||||
background-image: url('../../../assets/img/ach2.png'); |
||||
} |
||||
|
||||
.item { |
||||
width: 300px; |
||||
min-height: 145px; |
||||
padding: 30px 30px; |
||||
margin: 0 10px; |
||||
box-sizing: border-box; |
||||
border-radius: 8px; |
||||
background-size: 100% 100%; |
||||
background-repeat: no-repeat; |
||||
|
||||
p { |
||||
font-size: 18px; |
||||
color: #ffffff; |
||||
} |
||||
|
||||
.val { |
||||
margin-top: 10px; |
||||
color: #ffffff; |
||||
font-size: 36px; |
||||
} |
||||
} |
||||
} |
||||
|
||||
.chart { |
||||
width: calc(100% - 660px); |
||||
height: 300px; |
||||
} |
||||
} |
||||
|
||||
/deep/.import-file { |
||||
.el-progress__text, |
||||
.el-progress, |
||||
.el-upload-list__item-status-label { |
||||
display: none !important; |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,672 @@ |
||||
<template> |
||||
<div class="page" style="padding-top: 0;" v-loading="loading"> |
||||
<div class="tabs mgb20"> |
||||
<a class="item" v-for="(item, i) in tabs" :key="i" :class="{ active: item.id == active }" |
||||
@click="tabChange(item.id)">{{ item.name }}</a> |
||||
</div> |
||||
<div class="tool mul"> |
||||
<ul class="filter"> |
||||
<li> |
||||
<label>入库时间:</label> |
||||
<div class="single-choice"> |
||||
<dl> |
||||
<dd> |
||||
<el-radio-group v-model="form.month" @change="changeType"> |
||||
<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> |
||||
<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> |
||||
<el-input :placeholder="`请输入资源名称、${active === 2 ? '描述' : '章节'}`" suffix-icon="el-icon-search" |
||||
v-model="form.keyword" clearable></el-input> |
||||
</li> |
||||
</ul> |
||||
</div> |
||||
<div class="tool mul"> |
||||
<ul class="filter"> |
||||
<li v-if="!active"> |
||||
<label>课程:</label> |
||||
<el-select v-if="!active" v-model="form.cid" filterable clearable @change="initData"> |
||||
<el-option v-for="(item, i) in courses" :key="i" :label="item.curriculumName" :value="item.cid"></el-option> |
||||
</el-select> |
||||
<el-select v-else v-model="form.cid" filterable clearable @change="initData"> |
||||
<el-option v-for="(item, i) in theoreticalCourses" :key="i" :label="item.courseName" |
||||
:value="item.id"></el-option> |
||||
</el-select> |
||||
</li> |
||||
<li> |
||||
<label>资源类型:</label> |
||||
<el-select v-model="form.displayFileType" multiple clearable @change="initData"> |
||||
<el-option v-for="(item, i) in types" :key="i" :label="item.name" :value="item.name"></el-option> |
||||
</el-select> |
||||
</li> |
||||
<!-- <li> |
||||
<label>编辑人:</label> |
||||
<el-select v-model="form.editor" clearable @change="initData"> |
||||
<el-option v-for="(item, i) in types" :key="i" :label="item.name" :value="item.id"></el-option> |
||||
</el-select> |
||||
</li> --> |
||||
</ul> |
||||
<div> |
||||
<el-button v-if="active === 2" type="primary" @click="uploadFile">上传文件</el-button> |
||||
<el-button type="primary" @click="delAllSelection">批量删除</el-button> |
||||
</div> |
||||
</div> |
||||
|
||||
<el-table ref="table" :data="list" class="table" 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="resourceName" min-width="160" label="资源名称" align="center"></el-table-column> |
||||
<el-table-column prop="displayFileType" width="90" label="资源类型" align="center"></el-table-column> |
||||
<template v-if="active === 2"> |
||||
<el-table-column key="1" prop="resourceDescription" min-width="160" label="资源描述" |
||||
align="center"></el-table-column> |
||||
<!-- <el-table-column key="2" prop="name" width="100" label="是否被引用" align="center"> |
||||
<template slot-scope="scope">{{ scope.row.isReferenced ? '是' : '否' }}</template> |
||||
</el-table-column> --> |
||||
</template> |
||||
<template v-else> |
||||
<el-table-column key="3" prop="curriculumName" min-width="160" label="课程名称" align="center"></el-table-column> |
||||
<el-table-column key="4" prop="chapterSubsection" min-width="160" label="章节" align="center"></el-table-column> |
||||
</template> |
||||
<el-table-column prop="createTime" label="入库时间" align="center" width="160"></el-table-column> |
||||
<el-table-column prop="editor" label="编辑人" width="130" align="center"></el-table-column> |
||||
<el-table-column label="操作" align="center" width="180"> |
||||
<template slot-scope="scope"> |
||||
<el-button type="text" @click="edit(scope.row)">编辑</el-button> |
||||
<el-button type="text" @click="download(scope.row)">下载</el-button> |
||||
<el-button type="text" @click="preview(scope.row)">预览</el-button> |
||||
<el-button type="text" @click="del(scope.row)">删除</el-button> |
||||
</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 v-show="previewImg" class="el-image-viewer__wrapper" :class="{ active: previewImg }" style="z-index: 2000"> |
||||
<div class="el-image-viewer__mask"></div> |
||||
<span class="el-image-viewer__btn el-image-viewer__close" @click="previewImg = ''"><i class="el-icon-circle-close" |
||||
style="color: #fff"></i></span> |
||||
<div class="el-image-viewer__canvas"> |
||||
<img :src="previewImg" class="el-image-viewer__img" |
||||
style="transform: scale(1) rotate(0deg);margin-top: -1px; max-height: 100%; max-width: 100%;"> |
||||
</div> |
||||
</div> |
||||
<div v-show="iframeSrc || videoSrc" class="el-image-viewer__wrapper" :class="{ active: iframeSrc }" |
||||
style="z-index: 2000"> |
||||
<div class="el-image-viewer__mask"></div> |
||||
<span class="el-image-viewer__btn el-image-viewer__close" :class="{ 'doc-close': isWord }" |
||||
:style="{ top: isWord ? '50px' : '15px' }" @click="closeIframe"><i class="el-icon-circle-close" |
||||
style="color: #fff"></i></span> |
||||
<div class="el-image-viewer__canvas"> |
||||
<iframe v-if="iframeSrc" class="fileIframe" id="fileIframe" :src="iframeSrc" frameborder="0"></iframe> |
||||
<video v-if="videoSrc" class="video" width="1200" height="600" autoplay controls> |
||||
<source :src="videoSrc" type="video/mp4"> |
||||
您的浏览器不支持 video 标签。 |
||||
</video> |
||||
<template v-if="showMask"> |
||||
<div class="mask" style="width: 200px;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-mask1" style="width: 200px;height: 50px;"></div> |
||||
<div class="word-mask" style="height: 40px;top: 48px;"></div> |
||||
<div class="word-mask2" style="top: 55px;left: 28%;width: 44%;height: calc(100% - 80px);"></div> |
||||
</template> |
||||
<template v-if="showMask2 && iframeSrc"> |
||||
<div class="excel-mask1" style="height: 48px;"></div> |
||||
</template> |
||||
</div> |
||||
</div> |
||||
<div v-show="playAuth" class="el-image-viewer__wrapper" :class="{ active: playAuth }" style="z-index: 2000"> |
||||
<div class="el-image-viewer__mask"></div> |
||||
<span class="el-image-viewer__btn el-image-viewer__close" @click="closePlayer"><i class="el-icon-circle-close" |
||||
style="color: #fff"></i></span> |
||||
<div class="player" id="player"></div> |
||||
</div> |
||||
|
||||
<Pdf :visible.sync="pdfVisible" :src.sync="pdfSrc" /> |
||||
<div class="player-download" id="playerDownload"></div> |
||||
|
||||
<Upload :visible.sync="uploadVisible" :row.sync="curRow" /> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
import { Loading } from 'element-ui' |
||||
import Setting from '@/setting' |
||||
import Util from '@/libs/util' |
||||
import SourceConst from '@/const/source' |
||||
import Pdf from '@/components/pdf' |
||||
import Upload from './upload' |
||||
export default { |
||||
components: { Pdf, Upload }, |
||||
data () { |
||||
return { |
||||
active: +this.$route.query.type || 0, |
||||
defaultTabs: [ |
||||
{ |
||||
id: 0, |
||||
name: '教学课程' |
||||
}, |
||||
{ |
||||
id: 1, |
||||
name: '精品课程' |
||||
}, |
||||
{ |
||||
id: 2, |
||||
name: '文件素材' |
||||
}, |
||||
], |
||||
tabs: [], |
||||
timer: null, |
||||
types: SourceConst.types, |
||||
courses: [], |
||||
theoreticalCourses: [], |
||||
list: [], |
||||
form: { |
||||
month: '', |
||||
keyword: '', |
||||
startTime: '', |
||||
endTime: '', |
||||
displayFileType: [], |
||||
editor: '', |
||||
}, |
||||
multipleSelection: [], |
||||
dateList: [ |
||||
{ |
||||
id: "", |
||||
name: "不限" |
||||
}, |
||||
{ |
||||
id: 1, |
||||
name: "近一个月" |
||||
}, |
||||
{ |
||||
id: 3, |
||||
name: "近三个月" |
||||
}, |
||||
{ |
||||
id: 6, |
||||
name: "近六个月" |
||||
} |
||||
], |
||||
date: [], |
||||
page: +this.$route.query.page || 1, |
||||
pageSize: 10, |
||||
total: 0, |
||||
modifyVisible: false, |
||||
curRow: null, |
||||
loading: false, |
||||
now: '', |
||||
|
||||
|
||||
sectionForm: { |
||||
sectionName: '' |
||||
}, |
||||
|
||||
fileType: "", |
||||
videoSrc: '', |
||||
playAuth: "", |
||||
player: null, |
||||
previewImg: "", |
||||
iframeSrc: "", |
||||
isWord: false, |
||||
isPPT: false, |
||||
isExcel: false, |
||||
showMask: false, |
||||
showMask1: false, |
||||
showMask2: false, |
||||
loadIns: null, |
||||
pdfVisible: false, |
||||
pdfSrc: "", |
||||
previewing: false, |
||||
|
||||
uploadVisible: false, |
||||
}; |
||||
}, |
||||
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(); |
||||
}, |
||||
'form.keyword': function (val) { |
||||
clearTimeout(this.searchTimer); |
||||
this.searchTimer = setTimeout(() => { |
||||
this.initData() |
||||
}, 500) |
||||
} |
||||
}, |
||||
mounted () { |
||||
Setting.dynamicRoute && this.initTabs() |
||||
this.insertScript() |
||||
this.getData() |
||||
this.getCourse() |
||||
}, |
||||
methods: { |
||||
initTabs () { |
||||
const { btns } = this.$store.state |
||||
const tab1 = btns.includes('/resourse:教学课程') |
||||
const tab2 = btns.includes('/resourse:精品课程') |
||||
const tab3 = btns.includes('/resourse:文件素材') |
||||
|
||||
const tabs = this.defaultTabs |
||||
tab1 && this.tabs.push(tabs[0]) |
||||
tab2 && this.tabs.push(tabs[1]) |
||||
tab3 && this.tabs.push(tabs[2]) |
||||
|
||||
const type = +this.$route.query.type |
||||
this.active = this.tabs.find(e => e.id === type) ? type : this.tabs[0].id |
||||
}, |
||||
async getData () { |
||||
this.loading = true |
||||
try { |
||||
const { form } = this |
||||
const { page } = await this.$post(this.api.resourceLibrary, { |
||||
pageNum: this.page, |
||||
pageSize: this.pageSize, |
||||
platformId: Setting.platformId, |
||||
type: this.active, |
||||
...form |
||||
}) |
||||
this.list = page.records |
||||
this.total = page.total |
||||
} finally { |
||||
this.loading = false |
||||
} |
||||
}, |
||||
// 查询课程 |
||||
async getCourse () { |
||||
// 教学课程 |
||||
if (!this.courses.length) { |
||||
const sid = this.$store.state.dataPer.find(e => e.permissionName === '课程管理') |
||||
const { page } = await this.$post(this.api.curriculumList, { |
||||
pageNum: 1, |
||||
pageSize: 1000, |
||||
supplierId: sid ? sid.supplierId : '', |
||||
platformId: Setting.platformId |
||||
}) |
||||
this.courses = page.records |
||||
} |
||||
|
||||
// 精品课程 |
||||
// if (!this.theoreticalCourses.length) { |
||||
// const { page } = await this.$post(this.api.listTheoreticalCourse, { |
||||
// pageNum: 1, |
||||
// pageSize: 1000, |
||||
// createPlatform: 0, |
||||
// platformSource: Setting.platformSource, |
||||
// }) |
||||
// this.theoreticalCourses = page.records |
||||
// } |
||||
}, |
||||
tabChange (id) { |
||||
this.active = id |
||||
this.form.cid = '' |
||||
this.$refs.table.clearSelection() |
||||
this.initData() |
||||
this.getCourse() |
||||
this.$router.push({ |
||||
path: '/resourse', |
||||
query: { |
||||
...this.$route.query, |
||||
type: id |
||||
} |
||||
}) |
||||
}, |
||||
changeType () { |
||||
this.$refs.table.clearSelection() |
||||
this.initData() |
||||
}, |
||||
initData () { |
||||
this.page = 1 |
||||
this.getData() |
||||
}, |
||||
handleSelectionChange (val) { |
||||
this.multipleSelection = val |
||||
}, |
||||
handleCurrentChange (val) { |
||||
this.page = val |
||||
this.$router.push(`/resourse?page=${val}`) |
||||
this.getData() |
||||
}, |
||||
// 上传文件 |
||||
uploadFile () { |
||||
this.curRow = null |
||||
this.uploadVisible = true |
||||
}, |
||||
// 批量删除 |
||||
delAllSelection () { |
||||
const list = this.multipleSelection |
||||
if (list.length) { |
||||
this.$confirm('删除后用户将无法再查看和使用这些资源,确定删除?', '提示', { |
||||
type: "warning" |
||||
}).then(async () => { |
||||
const ids = list.map(e => e.id) |
||||
const tab = this.active |
||||
if (!tab) { |
||||
// 教学课程 |
||||
await this.$post(this.api.deleteSubsectionBatch, { |
||||
subsectionIds: ids |
||||
}) |
||||
} else if (tab === 1) { |
||||
// 精品课程 |
||||
await this.$post(this.api.batchDeletionTheoretical, ids) |
||||
} else { |
||||
// 文件素材 |
||||
await this.$post(this.api.resourceDel, ids) |
||||
} |
||||
this.getData() |
||||
this.$message.success("删除成功") |
||||
this.$refs.table.clearSelection() |
||||
}).catch(() => { }) |
||||
} else { |
||||
this.$message.warning("请先选择数据 !") |
||||
} |
||||
}, |
||||
|
||||
edit (row) { |
||||
this.curRow = row |
||||
this.uploadVisible = true |
||||
}, |
||||
// 下载资源 |
||||
download (row) { |
||||
const { fileType, fileId } = row |
||||
// 下载ppt |
||||
if (fileType === 'pptx') { |
||||
this.downloadFile(row.originalFileName || row.name, row.fileUrl) |
||||
} else if (fileId) { |
||||
// 阿里云点播视频,先生成视频,再拿到视频地址去下载(现在已经去掉视频点播的方法,但是还需要兼容历史数据) |
||||
this.$get(`${this.api.getPlayAuth}/${fileId}`).then(res => { |
||||
new Aliplayer({ |
||||
id: "playerDownload", |
||||
width: "100%", |
||||
autoplay: false, |
||||
vid: fileId, |
||||
playauth: res.playAuth, |
||||
encryptType: 1 //当播放私有加密流时需要设置。 |
||||
}, player => { |
||||
this.downloadFile(row.name, player._urls[0].Url) |
||||
}) |
||||
}).catch(res => { }) |
||||
} else { |
||||
this.downloadFile(row.originalFileName, row.fileUrl) |
||||
} |
||||
}, |
||||
transferType (ext) { |
||||
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 "视频"; |
||||
return ext; |
||||
}, |
||||
insertScript () { |
||||
const linkTag = document.createElement("link"); |
||||
linkTag.rel = "stylesheet"; |
||||
linkTag.href = "https://g.alicdn.com/de/prismplayer/2.8.2/skins/default/aliplayer-min.css"; |
||||
document.body.appendChild(linkTag); |
||||
|
||||
const scriptTag = document.createElement("script"); |
||||
scriptTag.type = "text/javascript"; |
||||
scriptTag.src = "https://g.alicdn.com/de/prismplayer/2.8.2/aliplayer-min.js"; |
||||
document.body.appendChild(scriptTag); |
||||
}, |
||||
async preview (row) { |
||||
if (this.transferType(row.fileType) == "视频") { |
||||
// 阿里云视频点播 |
||||
if (row.fileId) { |
||||
this.$get(`${this.api.getPlayAuth}/${row.fileId}`).then(res => { |
||||
this.playAuth = res.playAuth; |
||||
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 { |
||||
this.videoSrc = row.fileUrl |
||||
} |
||||
} else if (this.transferType(row.fileType) == "图片") { |
||||
this.previewImg = row.fileUrl; |
||||
} else if (row.fileType == "pdf") { |
||||
this.pdfSrc = row.fileUrl; |
||||
this.pdfVisible = true; |
||||
} else { |
||||
this.previewing = true; |
||||
this.loadIns = Loading.service(); |
||||
this.$route.fullPath.includes("#file") || history.pushState({ file: true }, "文件预览", "#" + this.$route.fullPath + "#file"); |
||||
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 |
||||
} |
||||
this.iframeSrc = 'https://view.officeapps.live.com/op/view.aspx?src=' + row.fileUrl |
||||
this.$nextTick(() => { |
||||
this.iframeOnload() |
||||
}) |
||||
} |
||||
}, |
||||
iframeOnload () { |
||||
document.querySelector("#fileIframe").onload = e => { |
||||
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.loadIns.close(); |
||||
}; |
||||
}, |
||||
del (row) { |
||||
this.$confirm('删除后用户将无法再查看和使用此资源,确定删除?', '提示', { |
||||
type: 'warning' |
||||
}).then(async () => { |
||||
const tab = this.active |
||||
if (!tab) { |
||||
// 教学课程 |
||||
await this.$post(this.api.deleteSubsectionBatch, { |
||||
chapterId: row.chapterId, |
||||
subsectionIds: [row.id] |
||||
}) |
||||
} else if (tab === 1) { |
||||
// 精品课程 |
||||
await this.$post(this.api.batchDeletionTheoretical, [row.id]) |
||||
} else { |
||||
// 文件素材 |
||||
await this.$post(this.api.resourceDel, [row.id]) |
||||
} |
||||
this.$message.success("删除成功") |
||||
this.getData() |
||||
}).catch(() => { }) |
||||
}, |
||||
sectionNameSubmit () { |
||||
if (!this.sectionForm.sectionName) return this.$message.warning("请填写资源名称") |
||||
let data = { |
||||
id: this.sectionId, |
||||
cid: this.id, |
||||
chapterId: this.chapterId, |
||||
name: this.sectionForm.sectionName |
||||
} |
||||
this.$put(this.api.editSubsection, data).then(res => { |
||||
this.$message.success("修改成功") |
||||
this.sectionNameVisible = false |
||||
this.getData() |
||||
}).catch(err => { }) |
||||
}, |
||||
closePlayer () { |
||||
this.playAuth = '' |
||||
this.player.pause(); |
||||
}, |
||||
closeIframe () { |
||||
this.iframeSrc = '' |
||||
this.videoSrc = '' |
||||
this.showMask = false; |
||||
this.showMask1 = false; |
||||
this.showMask2 = false; |
||||
this.previewing = false; |
||||
}, |
||||
} |
||||
}; |
||||
</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; |
||||
} |
||||
} |
||||
} |
||||
|
||||
.el-image-viewer__wrapper { |
||||
transform: translateY(-10px); |
||||
transition: transform 0.5s; |
||||
|
||||
&.active { |
||||
transform: translateY(0); |
||||
} |
||||
} |
||||
|
||||
.el-image-viewer__close { |
||||
z-index: 10000; |
||||
top: 15px; |
||||
right: 15px; |
||||
|
||||
&.doc-close { |
||||
i { |
||||
color: #000 !important; |
||||
} |
||||
} |
||||
} |
||||
|
||||
.player { |
||||
position: absolute; |
||||
top: 50%; |
||||
left: 50%; |
||||
transform: translate(-50%, -50%); |
||||
width: 1200px !important; |
||||
height: 600px !important; |
||||
} |
||||
|
||||
.player-download { |
||||
position: absolute; |
||||
top: -9999px; |
||||
} |
||||
|
||||
.fileIframe { |
||||
z-index: 1; |
||||
position: absolute; |
||||
top: 0; |
||||
left: 0; |
||||
bottom: 0; |
||||
right: 0; |
||||
width: 100%; |
||||
height: 100%; |
||||
} |
||||
|
||||
.mask { |
||||
z-index: 1000; |
||||
position: fixed; |
||||
background-color: rgb(57, 58, 61); |
||||
} |
||||
|
||||
.word-mask { |
||||
z-index: 1000; |
||||
position: fixed; |
||||
right: 0; |
||||
width: 100%; |
||||
background-color: rgb(243, 242, 241); |
||||
} |
||||
|
||||
.word-mask1 { |
||||
z-index: 1000; |
||||
position: fixed; |
||||
top: 0; |
||||
right: 0; |
||||
background-color: #2b579a; |
||||
} |
||||
|
||||
.word-mask2 { |
||||
z-index: 1000; |
||||
position: fixed; |
||||
background-color: transparent; |
||||
} |
||||
|
||||
.excel-mask1 { |
||||
z-index: 9; |
||||
position: absolute; |
||||
top: 0; |
||||
left: 20%; |
||||
width: 80%; |
||||
background-color: #107c41; |
||||
} |
||||
</style> |
@ -0,0 +1,210 @@ |
||||
<template> |
||||
<el-drawer title="上传文件" :visible.sync="uploadVisible" size="600px" :close-on-click-modal="false" |
||||
custom-class="source-dia" @closed="closeDia"> |
||||
<el-form label-width="80px" style="padding: 20px"> |
||||
<el-form-item prop="userName"> |
||||
<el-upload name="file" ref="upload" class="import-file" drag :limit="10000" :before-upload="beforeUpload" |
||||
:on-remove="handleRemove" :on-error="uploadError" :before-remove="beforeRemove" :disabled="uploading" |
||||
v-loading="uploading" :on-exceed="handleExceed" :file-list="uploadList" action="" |
||||
:http-request="handleRequest"> |
||||
<!-- <img v-if="form.coverUrl" :src="form.coverUrl" class="avatar"> --> |
||||
<i class="el-icon-upload"></i> |
||||
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div> |
||||
<div class="el-upload__tip" slot="tip" style="line-height: 1.8;"> |
||||
<p>视频请上传MP4格式,大小不超过150M;</p> |
||||
<p>其他格式文件大小不要超过10M</p> |
||||
</div> |
||||
</el-upload> |
||||
</el-form-item> |
||||
<el-form-item label="资源名称"> |
||||
<el-input v-model="form.resourceName" placeholder="请输入资源名称" /> |
||||
</el-form-item> |
||||
<el-form-item label="资源类型"> |
||||
<el-select v-model="form.displayFileType" disabled> |
||||
<el-option v-for="(item, i) in types" :key="i" :label="item.name" :value="item.name"></el-option> |
||||
</el-select> |
||||
</el-form-item> |
||||
<el-form-item v-if="$parent.active === 2" label="资源描述"> |
||||
<el-input type="textarea" :rows="3" v-model="form.resourceDescription" placeholder="请输入资源描述" /> |
||||
</el-form-item> |
||||
</el-form> |
||||
<div class="btns"> |
||||
<el-button @click="uploadVisible = false">取消</el-button> |
||||
<el-button type="primary" :loading="submiting" @click="submit">确定</el-button> |
||||
</div> |
||||
</el-drawer> |
||||
</template> |
||||
<script> |
||||
import Util from '@/libs/util' |
||||
import Setting from '@/setting' |
||||
import SourceConst from '@/const/source' |
||||
import _ from 'lodash' |
||||
import Oss from '@/components/upload/upload.js' |
||||
export default { |
||||
props: ['visible', 'row'], |
||||
data () { |
||||
return { |
||||
uploadVisible: false, |
||||
types: SourceConst.types, |
||||
uploadList: [], |
||||
uploading: false, |
||||
submiting: false, |
||||
form: { |
||||
fileType: '', |
||||
fileUrl: '', |
||||
fileName: '', |
||||
originalFileName: '', |
||||
resourceName: '', |
||||
displayFileType: '', |
||||
resourceDescription: '', |
||||
}, |
||||
originForm: {}, |
||||
}; |
||||
}, |
||||
watch: { |
||||
visible () { |
||||
this.uploadVisible = this.visible |
||||
this.visible && this.init() |
||||
} |
||||
}, |
||||
mounted () { |
||||
this.originForm = _.cloneDeep(this.form) |
||||
}, |
||||
methods: { |
||||
init () { |
||||
const { row } = this |
||||
if (row) { |
||||
this.uploadList = [{ |
||||
name: row.originalFileName, |
||||
url: row.fileUrl |
||||
}] |
||||
this.form = _.cloneDeep(this.row) |
||||
} else { |
||||
this.uploadList = [] |
||||
this.form = _.cloneDeep(this.originForm) |
||||
} |
||||
}, |
||||
|
||||
// 上传文件 |
||||
handleExceed () { |
||||
Util.warningMsg( |
||||
`当前限制选择 1 个文件,如需更换,请删除上一个文件再重新选择!` |
||||
) |
||||
}, |
||||
// 判断文件类型 |
||||
async handleType (ext) { |
||||
const res = await this.$post(`${this.api.getFileType}?fileType=${ext}`) |
||||
this.form.resourceType = 1 |
||||
this.form.displayFileType = res.data |
||||
}, |
||||
// 自定义上传 |
||||
async handleRequest ({ file }) { |
||||
Oss.upload(file).then(res => { |
||||
this.uploading = false |
||||
this.form.fileType = res.format |
||||
this.form.fileUrl = res.url |
||||
this.form.fileName = res.name |
||||
this.handleType(res.format) |
||||
|
||||
this.uploadList = [{ |
||||
name: res.name, |
||||
url: res.url |
||||
}] |
||||
}) |
||||
}, |
||||
uploadError () { |
||||
this.uploading = false |
||||
this.$message({ |
||||
message: "上传出错,请重试!", |
||||
type: "error", |
||||
center: true |
||||
}) |
||||
}, |
||||
beforeUpload (file) { |
||||
this.uploading = true |
||||
this.form.originalFileName = file.name |
||||
this.form.resourceName = file.name.substring(0, file.name.lastIndexOf('.')) |
||||
}, |
||||
beforeRemove (file, fileList) { |
||||
return this.$confirm(`确定移除 ${file.name}?`) |
||||
}, |
||||
handleRemove (file, fileList) { |
||||
file.url && Oss.del(file.url) |
||||
this.form.fileUrl = '' |
||||
this.uploadList = fileList |
||||
}, |
||||
async submit () { |
||||
if (this.submiting) return false |
||||
const { form, row } = this |
||||
const tab = this.$parent.active |
||||
if (!form.fileUrl) return Util.warningMsg('请上传资源') |
||||
if (!form.resourceName) return Util.warningMsg('请填写资源名称') |
||||
this.submiting = true |
||||
|
||||
if (!tab) { |
||||
// 教学课程 |
||||
await this.$put(this.api.editSubsection, { |
||||
id: row.id, |
||||
cid: row.cid, |
||||
chapterId: row.chapterId, |
||||
fileId: row.fileId || '', |
||||
name: form.resourceName, |
||||
fileUrl: form.fileUrl, |
||||
fileName: form.fileName, |
||||
fileType: form.fileType, |
||||
originalFileName: form.originalFileName |
||||
}) |
||||
} else if (tab === 1) { |
||||
await this.$put(this.api.editSubsectionTheoretical, { |
||||
id: row.id, |
||||
// courseId: this.id, |
||||
chapterId: row.chapterId, |
||||
fileId: row.fileId || '', |
||||
name: form.resourceName, |
||||
fileUrl: form.fileUrl, |
||||
fileName: form.fileName, |
||||
fileType: form.fileType, |
||||
originalFileName: form.originalFileName |
||||
}) |
||||
} else { |
||||
await this.$post(this.api.resourceSave, { |
||||
platformId: Setting.platformId, |
||||
...form |
||||
}) |
||||
} |
||||
this.submiting = false |
||||
this.uploadVisible = false |
||||
}, |
||||
// 弹框关闭回调 |
||||
closeDia () { |
||||
this.$parent.initData() |
||||
this.$emit('update:visible', false) |
||||
} |
||||
} |
||||
}; |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
/deep/.import-file { |
||||
.el-upload__tip { |
||||
margin-top: 0; |
||||
} |
||||
|
||||
.el-progress__text, |
||||
.el-progress, |
||||
.el-upload-list__item-status-label { |
||||
display: none !important; |
||||
} |
||||
} |
||||
|
||||
.btns { |
||||
position: absolute; |
||||
bottom: 0; |
||||
left: 0; |
||||
width: 100%; |
||||
padding: 14px 0; |
||||
text-align: center; |
||||
background-color: #fff; |
||||
box-shadow: 4px -2px 6px 0px rgba(198, 198, 198, 0.3500); |
||||
} |
||||
</style> |