|
|
@@ -1,10 +1,13 @@
|
|
|
<template>
|
|
|
<div class="page-container">
|
|
|
<div class="page-header">
|
|
|
- <h2 class="page-title">课前资料</h2>
|
|
|
+ <h2 class="page-title">课程资料</h2>
|
|
|
<div class="filter-bar">
|
|
|
- <el-select v-model="filterClassId" placeholder="全部班次" clearable style="width:200px" @change="fetchList">
|
|
|
- <el-option v-for="c in classList" :key="c.id" :label="c.name" :value="c.id" />
|
|
|
+ <el-select v-model="filterCourseId" placeholder="全部课程" clearable style="width:180px" @change="onCourseFilterChange">
|
|
|
+ <el-option v-for="c in courseList" :key="c.id" :label="c.level + ' ' + c.name" :value="c.id" />
|
|
|
+ </el-select>
|
|
|
+ <el-select v-model="filterSectionId" placeholder="全部版块" clearable style="width:160px" @change="fetchList">
|
|
|
+ <el-option v-for="s in sectionList" :key="s.id" :label="s.title" :value="s.id" />
|
|
|
</el-select>
|
|
|
<el-button type="primary" icon="el-icon-plus" @click="openEdit()">新增资料</el-button>
|
|
|
<el-button icon="el-icon-refresh" @click="fetchList">刷新</el-button>
|
|
|
@@ -12,39 +15,83 @@
|
|
|
</div>
|
|
|
|
|
|
<el-table :data="list" v-loading="loading" border stripe style="width:100%">
|
|
|
- <el-table-column prop="id" label="ID" width="80" />
|
|
|
- <el-table-column prop="title" label="资料标题" min-width="200" />
|
|
|
- <el-table-column label="适用班次" width="140">
|
|
|
+ <el-table-column prop="id" label="ID" width="70" />
|
|
|
+ <el-table-column prop="title" label="资料标题" min-width="180">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <a v-if="scope.row.fileUrl" :href="scope.row.fileUrl" target="_blank" class="link">{{ scope.row.title }}</a>
|
|
|
+ <span v-else>{{ scope.row.title }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="分类" width="90">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-tag :type="categoryType(scope.row.category)" size="small">{{ categoryLabel(scope.row.category) }}</el-tag>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="适用课程" width="140">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-tag v-if="scope.row.courseId" size="small">课程 #{{ scope.row.courseId }}</el-tag>
|
|
|
+ <el-tag v-else-if="scope.row.classId" size="small" type="warning">班次 #{{ scope.row.classId }}</el-tag>
|
|
|
+ <el-tag v-else size="small" type="info">通用</el-tag>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="所属版块" width="110">
|
|
|
<template slot-scope="scope">
|
|
|
- <el-tag v-if="scope.row.classId" size="small" type="warning">班次 #{{ scope.row.classId }}</el-tag>
|
|
|
+ <el-tag v-if="scope.row.sectionId" size="small">版块 #{{ scope.row.sectionId }}</el-tag>
|
|
|
<el-tag v-else size="small" type="info">通用</el-tag>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column prop="sort" label="排序" width="80" />
|
|
|
- <el-table-column prop="fileUrl" label="文件地址" min-width="220" show-overflow-tooltip />
|
|
|
- <el-table-column prop="createdAt" label="创建时间" width="170" />
|
|
|
+ <el-table-column prop="sort" label="排序" width="70" />
|
|
|
+ <el-table-column label="文件" width="80">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-button v-if="scope.row.fileUrl" type="text" size="small" @click="preview(scope.row)">预览</el-button>
|
|
|
+ <span v-else class="muted">未上传</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="createdAt" label="创建时间" width="160" />
|
|
|
<el-table-column label="操作" width="120" fixed="right">
|
|
|
<template slot-scope="scope">
|
|
|
<el-button type="text" size="small" @click="openEdit(scope.row)">编辑</el-button>
|
|
|
+ <el-button type="text" size="small" class="danger-text" @click="handleDelete(scope.row)">删除</el-button>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
</el-table>
|
|
|
|
|
|
- <el-empty v-if="!loading && list.length === 0" description="暂无课前资料" />
|
|
|
+ <el-empty v-if="!loading && list.length === 0" description="暂无课程资料" />
|
|
|
|
|
|
<el-dialog :title="form.id ? '编辑资料' : '新增资料'" :visible.sync="dialogVisible" width="560px">
|
|
|
<el-form :model="form" label-width="90px">
|
|
|
<el-form-item label="资料标题" required>
|
|
|
<el-input v-model="form.title" placeholder="如:课前预习手册" />
|
|
|
</el-form-item>
|
|
|
+ <el-form-item label="所属课程">
|
|
|
+ <el-select v-model="form.courseId" placeholder="留空 = 通用资料" clearable style="width:100%" @change="onFormCourseChange">
|
|
|
+ <el-option v-for="c in courseList" :key="c.id" :label="c.level + ' ' + c.name" :value="c.id" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="所属版块">
|
|
|
+ <el-select v-model="form.sectionId" placeholder="留空 = 通用版块" clearable style="width:100%">
|
|
|
+ <el-option v-for="s in sectionList" :key="s.id" :label="s.title" :value="s.id" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
<el-form-item label="适用班次">
|
|
|
<el-select v-model="form.classId" placeholder="留空 = 通用资料" clearable style="width:100%">
|
|
|
<el-option v-for="c in classList" :key="c.id" :label="c.name" :value="c.id" />
|
|
|
</el-select>
|
|
|
<div class="form-tip">留空则所有班次学员可见(通用资料)</div>
|
|
|
</el-form-item>
|
|
|
- <el-form-item label="文件地址">
|
|
|
- <el-input v-model="form.fileUrl" placeholder="https://…(图片/PDF 链接,可后补)" />
|
|
|
+ <el-form-item label="分类">
|
|
|
+ <el-select v-model="form.category" placeholder="选择分类" clearable style="width:100%">
|
|
|
+ <el-option label="课前" value="pre" />
|
|
|
+ <el-option label="课中" value="course" />
|
|
|
+ <el-option label="课后" value="after" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="文件">
|
|
|
+ <div class="upload-row">
|
|
|
+ <el-input v-model="form.fileUrl" placeholder="点击上传或粘贴 https://… 链接" />
|
|
|
+ <el-button type="primary" icon="el-icon-upload" :loading="uploading" @click="triggerUpload">上传</el-button>
|
|
|
+ <input ref="fileInput" type="file" accept=".pdf,.jpg,.jpeg,.png,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.zip" style="display:none" @change="handleFileChange" />
|
|
|
+ </div>
|
|
|
</el-form-item>
|
|
|
<el-form-item label="排序">
|
|
|
<el-input-number v-model="form.sort" :min="0" :max="9999" />
|
|
|
@@ -60,33 +107,83 @@
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
-import { materialList, materialSave } from '@/api/material'
|
|
|
+import { materialList, materialSave, materialDelete } from '@/api/material'
|
|
|
import { classList as fetchClasses } from '@/api/class'
|
|
|
+import { courseList as fetchCourses } from '@/api/course'
|
|
|
+import { sectionList as fetchSections } from '@/api/course'
|
|
|
+import { uploadFile } from '@/api/upload'
|
|
|
|
|
|
export default {
|
|
|
name: 'Materials',
|
|
|
data: function () {
|
|
|
return {
|
|
|
list: [],
|
|
|
+ courseList: [],
|
|
|
+ sectionList: [],
|
|
|
classList: [],
|
|
|
- filterClassId: null,
|
|
|
+ filterCourseId: null,
|
|
|
+ filterSectionId: null,
|
|
|
loading: false,
|
|
|
saving: false,
|
|
|
+ uploading: false,
|
|
|
dialogVisible: false,
|
|
|
form: {
|
|
|
id: null,
|
|
|
title: '',
|
|
|
+ courseId: null,
|
|
|
+ sectionId: null,
|
|
|
classId: null,
|
|
|
+ category: null,
|
|
|
fileUrl: '',
|
|
|
sort: 0
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
mounted: function () {
|
|
|
+ this.loadCourses()
|
|
|
this.loadClasses()
|
|
|
this.fetchList()
|
|
|
},
|
|
|
methods: {
|
|
|
+ categoryType: function (c) {
|
|
|
+ var map = { pre: '', course: 'success', after: 'warning' }
|
|
|
+ return map[c] || 'info'
|
|
|
+ },
|
|
|
+ categoryLabel: function (c) {
|
|
|
+ var map = { pre: '课前', course: '课中', after: '课后' }
|
|
|
+ return map[c] || '通用'
|
|
|
+ },
|
|
|
+ loadCourses: function () {
|
|
|
+ var self = this
|
|
|
+ fetchCourses().then(function (res) {
|
|
|
+ self.courseList = res.data || []
|
|
|
+ }).catch(function () {
|
|
|
+ self.$message.error('获取课程列表失败')
|
|
|
+ })
|
|
|
+ },
|
|
|
+ loadSections: function (courseId) {
|
|
|
+ var self = this
|
|
|
+ if (!courseId) {
|
|
|
+ self.sectionList = []
|
|
|
+ return
|
|
|
+ }
|
|
|
+ fetchSections(courseId).then(function (res) {
|
|
|
+ self.sectionList = res.data || []
|
|
|
+ }).catch(function () {
|
|
|
+ self.sectionList = []
|
|
|
+ })
|
|
|
+ },
|
|
|
+ onCourseFilterChange: function (courseId) {
|
|
|
+ var self = this
|
|
|
+ self.filterSectionId = null
|
|
|
+ self.loadSections(courseId)
|
|
|
+ self.fetchList()
|
|
|
+ },
|
|
|
+ onFormCourseChange: function (courseId) {
|
|
|
+ var self = this
|
|
|
+ self.form.sectionId = null
|
|
|
+ self.loadSections(courseId)
|
|
|
+ },
|
|
|
loadClasses: function () {
|
|
|
var self = this
|
|
|
fetchClasses().then(function (res) {
|
|
|
@@ -98,23 +195,35 @@ export default {
|
|
|
fetchList: function () {
|
|
|
var self = this
|
|
|
self.loading = true
|
|
|
- materialList({ classId: self.filterClassId || undefined }).then(function (res) {
|
|
|
+ materialList({
|
|
|
+ courseId: self.filterCourseId || undefined,
|
|
|
+ sectionId: self.filterSectionId || undefined
|
|
|
+ }).then(function (res) {
|
|
|
self.list = res.data || []
|
|
|
}).catch(function () {
|
|
|
- self.$message.error('获取课前资料失败')
|
|
|
+ self.$message.error('获取资料列表失败')
|
|
|
}).finally(function () {
|
|
|
self.loading = false
|
|
|
})
|
|
|
},
|
|
|
openEdit: function (row) {
|
|
|
- this.form = {
|
|
|
+ var self = this
|
|
|
+ self.form = {
|
|
|
id: row ? row.id : null,
|
|
|
title: row ? row.title : '',
|
|
|
+ courseId: row ? row.courseId : null,
|
|
|
+ sectionId: row ? row.sectionId : null,
|
|
|
classId: row ? row.classId : null,
|
|
|
+ category: row ? row.category : null,
|
|
|
fileUrl: row ? row.fileUrl : '',
|
|
|
sort: row ? row.sort : 0
|
|
|
}
|
|
|
- this.dialogVisible = true
|
|
|
+ if (self.form.courseId) {
|
|
|
+ self.loadSections(self.form.courseId)
|
|
|
+ } else {
|
|
|
+ self.sectionList = []
|
|
|
+ }
|
|
|
+ self.dialogVisible = true
|
|
|
},
|
|
|
handleSave: function () {
|
|
|
var self = this
|
|
|
@@ -126,7 +235,10 @@ export default {
|
|
|
materialSave({
|
|
|
id: self.form.id,
|
|
|
title: self.form.title.trim(),
|
|
|
+ courseId: self.form.courseId || null,
|
|
|
+ sectionId: self.form.sectionId || null,
|
|
|
classId: self.form.classId || null,
|
|
|
+ category: self.form.category || null,
|
|
|
fileUrl: self.form.fileUrl || null,
|
|
|
sort: self.form.sort || 0
|
|
|
}).then(function () {
|
|
|
@@ -138,6 +250,42 @@ export default {
|
|
|
}).finally(function () {
|
|
|
self.saving = false
|
|
|
})
|
|
|
+ },
|
|
|
+ handleDelete: function (row) {
|
|
|
+ var self = this
|
|
|
+ self.$confirm('确认删除资料「' + row.title + '」?', '提示', { type: 'warning' }).then(function () {
|
|
|
+ return materialDelete(row.id)
|
|
|
+ }).then(function () {
|
|
|
+ self.$message.success('删除成功')
|
|
|
+ self.fetchList()
|
|
|
+ }).catch(function () {})
|
|
|
+ },
|
|
|
+ triggerUpload: function () {
|
|
|
+ this.$refs.fileInput.click()
|
|
|
+ },
|
|
|
+ handleFileChange: function (e) {
|
|
|
+ var self = this
|
|
|
+ var file = e.target.files && e.target.files[0]
|
|
|
+ if (!file) return
|
|
|
+ self.uploading = true
|
|
|
+ uploadFile(file).then(function (res) {
|
|
|
+ if (res && res.data) {
|
|
|
+ self.form.fileUrl = res.data.url
|
|
|
+ self.$message.success('上传成功')
|
|
|
+ } else {
|
|
|
+ self.$message.error('上传失败')
|
|
|
+ }
|
|
|
+ }).catch(function () {
|
|
|
+ self.$message.error('上传失败')
|
|
|
+ }).finally(function () {
|
|
|
+ self.uploading = false
|
|
|
+ e.target.value = ''
|
|
|
+ })
|
|
|
+ },
|
|
|
+ preview: function (row) {
|
|
|
+ if (row && row.fileUrl) {
|
|
|
+ window.open(row.fileUrl, '_blank')
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -169,4 +317,27 @@ export default {
|
|
|
margin-top: 4px;
|
|
|
line-height: 1.4;
|
|
|
}
|
|
|
+
|
|
|
+.link {
|
|
|
+ color: #409EFF;
|
|
|
+ text-decoration: none;
|
|
|
+}
|
|
|
+
|
|
|
+.link:hover {
|
|
|
+ text-decoration: underline;
|
|
|
+}
|
|
|
+
|
|
|
+.danger-text {
|
|
|
+ color: #F56C6C;
|
|
|
+}
|
|
|
+
|
|
|
+.muted {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #909399;
|
|
|
+}
|
|
|
+
|
|
|
+.upload-row {
|
|
|
+ display: flex;
|
|
|
+ gap: 8px;
|
|
|
+}
|
|
|
</style>
|