添加资源库模块

dev_202412
yujialong 2 months ago
parent fd1c5ef8be
commit 6fd6232cb4
  1. 5
      src/api/index.js
  2. 28
      src/const/source.js
  3. 650
      src/pages/resourse/list/index.vue
  4. 175
      src/pages/resourse/upload.vue
  5. 23
      src/router/modules/resourse.js

@ -546,6 +546,11 @@ export default {
deleteSubsectionCurriculm: `nakadai/nakadai/curriculum/subsection/deleteSubsection`,
schoolCourseShelf: `nakadai/nakadai/curriculum/schoolCourseShelf`,
resourceLibrary: `nakadai/resourceLibrary/resourceLibrary`,
resourceDel: `nakadai/resourceLibrary/batchDeletion`,
resourceFind: `nakadai/resourceLibrary/findById`,
resourceSave: `nakadai/resourceLibrary/saveOrUpdate`,
// 教师评语
addComment: `evaluation/cevaluation/comment/addComment`,
queryComment: `evaluation/evaluation/ccomment/queryComment`,

@ -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: '其他'
},
],
}

@ -0,0 +1,650 @@
<template>
<div class="page" style="padding-top: 0;" v-loading="loading">
<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="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 !== 2">
<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" 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>
<el-dialog title="修改资源名称" :visible.sync="sectionNameVisible" width="540px" :close-on-click-modal="false">
<el-form @submit.native.prevent>
<el-form-item>
<el-input placeholder="请输入资源名称" v-model="sectionForm.sectionName" maxlength="50"
@keyup.enter.native="sectionNameSubmit()"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="sectionNameVisible = false">取消</el-button>
<el-button type="primary" @click="sectionNameSubmit">确定</el-button>
</span>
</el-dialog>
<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" />
</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,
tabs: [
{
id: 0,
name: '教学课程'
},
{
id: 1,
name: '精品课程'
},
{
id: 2,
name: '文件素材'
},
],
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: {
playingStages: []
},
loading: false,
now: '',
sectionNameVisible: false,
sectionForm: {
sectionName: ''
},
fileType: "",
videoSrc: '',
playAuth: "",
player: null,
previewImg: "",
iframeSrc: "",
curFile: {},
isAddSection: false,
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 () {
this.insertScript()
this.getData()
this.getCourse()
},
methods: {
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 { page } = await this.$post(this.api.curriculumList, {
pageNum: 1,
pageSize: 1000,
platformId: Setting.platformId
})
this.courses = page.records
}
//
if (!this.theoreticalCourses.length) {
const { page } = await this.$post(this.api.listTheoreticalCourse, {
pageNum: 1,
pageSize: 1000,
createPlatform: 1,
platformSource: Setting.platformSource,
})
this.theoreticalCourses = page.records
}
},
tabChange (id) {
this.active = id
this.form.cid = ''
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.uploadVisible = true
},
//
delAllSelection () {
const list = this.multipleSelection
if (list.length) {
this.$confirm('删除后用户将无法再查看和使用这些资源,确定删除?', '提示', {
type: "warning"
}).then(() => {
this.$post(this.api.resourceDel, list.map(e => e.id)).then(res => {
this.getData()
this.$message.success("删除成功")
this.$refs.table.clearSelection()
}).catch(err => { })
}).catch(() => { })
} else {
this.$message.warning("请先选择数据 !")
}
},
edit (row, chapterId) {
this.chapterId = chapterId
this.sectionId = row.id
this.sectionForm.sectionName = row.name
this.sectionNameVisible = true
},
//
download (row) {
const { fileType, fileId } = row
// ppt
if (fileType === 'pptx') {
Util.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 => {
Util.downloadFile(row.name, player._urls[0].Url)
})
}).catch(res => { })
} else {
Util.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);
},
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.$get(`${this.api.curriculumGetSubsection}/${row.id}`).then(res => {
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 = res.previewUrl;
this.$nextTick(() => {
this.iframeOnload();
});
}).catch(err => { })
}
},
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(() => {
this.$post(this.api.resourceDel, [row.id]).then(res => {
this.$message.success("删除成功")
this.getData()
}).catch(res => { })
}).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,175 @@
<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 :before-upload="beforeUpload"
:on-remove="handleRemove" :on-error="uploadError" :before-remove="beforeRemove" :limit="1"
: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.resourceType" disabled>
<el-option v-for="(item, i) in types" :key="i" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item 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'],
data () {
return {
uploadVisible: false,
types: SourceConst.types,
uploadList: [],
uploading: false,
submiting: false,
form: {
fileType: '',
fileUrl: '',
fileName: '',
originalFileName: '',
resourceName: '',
resourceType: '',
resourceDescription: '',
},
originForm: {},
};
},
watch: {
visible () {
this.uploadVisible = this.visible
this.visible && this.init()
}
},
mounted () {
this.originForm = _.cloneDeep(this.form)
},
methods: {
init () {
this.uploadList = []
this.form = _.cloneDeep(this.originForm)
},
//
handleExceed () {
Util.warningMsg(
`当前限制选择 1 个文件,如需更换,请删除上一个文件再重新选择!`
)
},
//
handleType (ext) {
let type = 6
if (Util.isVideo(ext)) {
type = 2
} else if (Util.isAudio(ext)) {
type = 5
} else if (Util.isImg(ext)) {
type = 3
} else if (Util.isDoc(ext) || ext === 'pdf') {
type = 1
} else if (ext === 'txt') {
type = 4
}
this.form.resourceType = type
},
//
async handleRequest ({ file }) {
Oss.upload(file).then(res => {
console.log("🚀 ~ Oss.upload ~ res:", res, file)
this.uploading = false
this.form.fileType = res.format
this.form.fileUrl = res.url
this.form.fileName = res.name
this.handleType(res.format)
})
},
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) {
this.uploadList = fileList
},
async submit () {
if (this.submiting) return false
const { form } = this
if (!form.fileUrl) return Util.warningMsg('请上传资源')
if (!form.resourceName) return Util.warningMsg('请填写资源名称')
this.submiting = true
await this.$post(this.api.resourceSave, {
platformId: Setting.platformId,
...form
})
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>

@ -0,0 +1,23 @@
import BasicLayout from "@/layouts/home";
const meta = {};
const pre = "resourse-";
export default {
path: "/resourse",
name: "resourse",
redirect: {
name: `${pre}list`
},
meta,
component: BasicLayout,
children: [
{
name: `${pre}list`,
path: `list`,
component: () => import("@/pages/resourse/list"),
meta: { title: "资源库" }
}
]
};
Loading…
Cancel
Save