From 2729bd4b9b375466cc02ab4ea8edb136f5acfde1 Mon Sep 17 00:00:00 2001
From: fuliqi <fuliqi@qq.com>
Date: 星期二, 18 六月 2024 16:12:15 +0800
Subject: [PATCH] 教学资源
---
src/api/educationResource.js | 9 +
package-lock.json | 56 ++++++
src/components/UploadC.vue | 132 ++++++++++++++
package.json | 1
src/views/education/resource/list.vue | 322 +++++++++++++++++++++++++++++++++++
src/router.js | 6
6 files changed, 526 insertions(+), 0 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 7132a21..d1cc00a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,6 +9,7 @@
"version": "3.9.0",
"license": "AGPL-3.0",
"dependencies": {
+ "@vue-office/pdf": "^2.0.2",
"axios": "^0.19.2",
"clipboard": "^2.0.11",
"codemirror": "^5.65.16",
@@ -2289,6 +2290,22 @@
"dev": true,
"engines": {
"node": ">= 8"
+ }
+ },
+ "node_modules/@vue-office/pdf": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmmirror.com/@vue-office/pdf/-/pdf-2.0.2.tgz",
+ "integrity": "sha512-bQFqGxSOnKbvCS7OoJniYoTz1VIm1XOrRD27Msorxny9NFJ8RsQK1A4uhlnISJRFMaUwp1qlcVE9jMAhsiIyjg==",
+ "hasInstallScript": true,
+ "peerDependencies": {
+ "@vue/composition-api": "^1.7.1",
+ "vue": "^2.0.0 || >=3.0.0",
+ "vue-demi": "^0.14.6"
+ },
+ "peerDependenciesMeta": {
+ "@vue/composition-api": {
+ "optional": true
+ }
}
},
"node_modules/@vue/babel-helper-vue-jsx-merge-props": {
@@ -17408,6 +17425,32 @@
"resolved": "https://registry.npmmirror.com/vue-count-to/-/vue-count-to-1.0.13.tgz",
"integrity": "sha512-6R4OVBVNtQTlcbXu6SJ8ENR35M2/CdWt3Jmv57jOUM+1ojiFmjVGvZPH8DfHpMDSA+ITs+EW5V6qthADxeyYOQ=="
},
+ "node_modules/vue-demi": {
+ "version": "0.14.8",
+ "resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.8.tgz",
+ "integrity": "sha512-Uuqnk9YE9SsWeReYqK2alDI5YzciATE0r2SkA6iMAtuXvNTMNACJLJEXNXaEy94ECuBe4Sk6RzRU80kjdbIo1Q==",
+ "hasInstallScript": true,
+ "peer": true,
+ "bin": {
+ "vue-demi-fix": "bin/vue-demi-fix.js",
+ "vue-demi-switch": "bin/vue-demi-switch.js"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ },
+ "peerDependencies": {
+ "@vue/composition-api": "^1.0.0-rc.1",
+ "vue": "^3.0.0-0 || ^2.6.0"
+ },
+ "peerDependenciesMeta": {
+ "@vue/composition-api": {
+ "optional": true
+ }
+ }
+ },
"node_modules/vue-eslint-parser": {
"version": "5.0.0",
"resolved": "https://registry.npmmirror.com/vue-eslint-parser/-/vue-eslint-parser-5.0.0.tgz",
@@ -20555,6 +20598,12 @@
"dev": true
}
}
+ },
+ "@vue-office/pdf": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmmirror.com/@vue-office/pdf/-/pdf-2.0.2.tgz",
+ "integrity": "sha512-bQFqGxSOnKbvCS7OoJniYoTz1VIm1XOrRD27Msorxny9NFJ8RsQK1A4uhlnISJRFMaUwp1qlcVE9jMAhsiIyjg==",
+ "requires": {}
},
"@vue/babel-helper-vue-jsx-merge-props": {
"version": "1.4.0",
@@ -32599,6 +32648,13 @@
"resolved": "https://registry.npmmirror.com/vue-count-to/-/vue-count-to-1.0.13.tgz",
"integrity": "sha512-6R4OVBVNtQTlcbXu6SJ8ENR35M2/CdWt3Jmv57jOUM+1ojiFmjVGvZPH8DfHpMDSA+ITs+EW5V6qthADxeyYOQ=="
},
+ "vue-demi": {
+ "version": "0.14.8",
+ "resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.8.tgz",
+ "integrity": "sha512-Uuqnk9YE9SsWeReYqK2alDI5YzciATE0r2SkA6iMAtuXvNTMNACJLJEXNXaEy94ECuBe4Sk6RzRU80kjdbIo1Q==",
+ "peer": true,
+ "requires": {}
+ },
"vue-eslint-parser": {
"version": "5.0.0",
"resolved": "https://registry.npmmirror.com/vue-eslint-parser/-/vue-eslint-parser-5.0.0.tgz",
diff --git a/package.json b/package.json
index 1002a34..a01a867 100644
--- a/package.json
+++ b/package.json
@@ -35,6 +35,7 @@
]
},
"dependencies": {
+ "@vue-office/pdf": "^2.0.2",
"axios": "^0.19.2",
"clipboard": "^2.0.11",
"codemirror": "^5.65.16",
diff --git a/src/api/educationResource.js b/src/api/educationResource.js
new file mode 100644
index 0000000..d176ee8
--- /dev/null
+++ b/src/api/educationResource.js
@@ -0,0 +1,9 @@
+import { post, get } from '@/utils/request'
+
+export default {
+ page: query => get('/api/admin/education/resource/page', query),
+ add: data => post('/api/admin/education/resource', data),
+ update: data => post('/api/admin/education/resource/edit', data),
+ list: () => post('/api/admin/education/resource/list'),
+ remove: (data) => post('/api/admin/education/resource/remove', data)
+}
diff --git a/src/components/UploadC.vue b/src/components/UploadC.vue
new file mode 100644
index 0000000..1a2e57f
--- /dev/null
+++ b/src/components/UploadC.vue
@@ -0,0 +1,132 @@
+<template>
+ <div>
+ <el-upload :action="uploadUrl" :show-file-list="true" :limit="uploadNum" :accept="acceptList" multiple
+ :file-list="fileUrl" :on-remove="handleRemove" :before-remove="beforeRemove" :on-success="handleUploadSuccess"
+ :before-upload="beforeUpload">
+ <el-button size="small" type="primary">鐐瑰嚮涓婁紶</el-button>
+ <div slot="tip" class="el-upload__tip">鍙兘涓婁紶pdf銆乵p4銆乤vi銆乸ng銆乯pg銆乯pge鏂囦欢锛屼笖涓嶈秴杩噞{ fileSizeLimitM }}M</div>
+ <div v-if="fileUrl && fileUrl.length > 0 && uploadNum === 1">
+ <video controls class="returnShow" v-if="fileType === 'video'" :src="'/api/files/' + fileUrl[0].url"></video>
+ <img class="returnShow" v-if="fileType === 'img'" :src="'/api/files/' + fileUrl[0].url" />
+ </div>
+ </el-upload>
+ </div>
+</template>
+
+<script>
+
+export default {
+ name: "UploadC",
+ props: {
+ uploadNum: {
+ required: false,
+ default: 1,
+ type: Number
+ },
+ fileType: {
+ required: false,
+ type: String
+ },
+ fileSizeLimitM: {
+ required: false,
+ default: 1,
+ type: Number
+ },
+ fileUrl: {
+ type: Array,
+ required: true,
+ default: () => []
+ }
+ },
+ data() {
+ return {
+ uploadUrl: "http://localhost:8000/api/upload/upload",
+ fileTypeList: {
+ 'video': ['mp4', 'avi'],
+ 'img': ['jpg', 'png', 'jpeg'],
+ 'pdf': ['pdf'],
+ 'file': ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'png', 'jpg', 'jpeg', 'pdf'],
+ }
+ };
+ },
+ methods: {
+ clearFile() {
+ this.fileUrl = [];
+ },
+ beforeRemove(file, fileList) {
+ if (file && file.status === "success") {
+ return this.$confirm(`纭畾绉婚櫎 ${file.name}锛焋);
+ }
+ },
+ handleRemove(file, fileList) {
+ this.$emit('removeFile', this.fileUrl, file.name);
+ },
+ handleUploadSuccess(res, file) {
+ this.fileUrl.push(res.data);
+ this.$emit('getUploadUrl', this.fileUrl);
+ },
+ beforeUpload(file) {
+ const { type } = file;
+ const typeList = this.fileTypeList[this.fileType];
+ let limitType = true;
+ if (typeList) {
+ const tempType = typeList.find(item => {
+ if (type.includes(item)) {
+ return true;
+ } else {
+ return false;
+ }
+ });
+ if (!tempType) {
+ this.$message.error(`璇蜂笂浼犳纭殑鏂囦欢鏍煎紡锛乣);
+ limitType = false;
+ }
+ }
+ const limit = file.size / 1024 / 1024 < this.fileSizeLimitM;
+ if (!limit) {
+ this.$message.error(`涓婁紶鏂囦欢澶у皬涓嶈兘瓒呰繃 ${this.fileSizeLimitM}MB!`);
+ }
+ return limitType && limit;
+ },
+ },
+ computed: {
+ acceptList() {
+ let temp = '.*';
+ if (this.fileTypeList[this.fileType]) {
+ temp = this.fileTypeList[this.fileType].map(item => '.' + item).join(',');
+ }
+ return temp;
+ }
+ }
+};
+</script>
+
+<style scoped>
+.returnShow {
+ width: 300px;
+ height: 200px;
+}
+
+.avatar-uploader {
+ text-align: center;
+ width: 100%
+}
+
+.avatar-uploader-icon:hover {
+ border-color: #409EFF;
+}
+
+.avatar-uploader-icon {
+ font-size: 28px;
+ color: #8c939d;
+ text-align: center;
+ border: 1px dashed #d9d9d9;
+ border-radius: 6px;
+ cursor: pointer;
+
+}
+
+.avatar {
+ display: block;
+}
+</style>
diff --git a/src/router.js b/src/router.js
index 922ffb7..e21caf6 100644
--- a/src/router.js
+++ b/src/router.js
@@ -243,6 +243,12 @@
name: 'EducationSubjectEditPage',
meta: { title: '瀛︾缂栬緫', noCache: true, activeMenu: '/education/subject/list' },
hidden: true
+ },
+ {
+ path: 'resource/list',
+ component: () => import('@/views/education/resource/list'),
+ name: 'EducationResourcePage',
+ meta: { title: '鏁欏璧勬簮', noCache: true }
}
]
},
diff --git a/src/views/education/resource/list.vue b/src/views/education/resource/list.vue
new file mode 100644
index 0000000..04229c2
--- /dev/null
+++ b/src/views/education/resource/list.vue
@@ -0,0 +1,322 @@
+<template>
+ <div class="warp">
+ <div class="search">
+ <el-form :inline="true" :model="searchForm" class="demo-form-inline">
+ <el-form-item label="涓婚">
+ <el-input v-model="searchForm.introduction" size="small" placeholder="涓婚鍐呭" clearable @clear="page"></el-input>
+ </el-form-item>
+ <el-form-item label="绉戠洰">
+ <el-select v-model="searchForm.subjectId" clearable @clear="page" @change="page" placeholder="绉戠洰">
+ <el-option v-for="item in typeList" :key="item.id" :label="item.name" :value="item.id">
+ </el-option>
+ </el-select>
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="page" size="small">鏌ヨ</el-button>
+ </el-form-item>
+ </el-form>
+ <div>
+ <el-button type="primary" @click="handlerAdd" size="small">娣诲姞</el-button>
+ <el-button type="danger" @click="batchRemove" size="small" style="margin-left: 5px">鍒犻櫎</el-button>
+ </div>
+ </div>
+
+
+ <el-table :data="tableData" border @selection-change="handleSelectionChange" style="width: 100%">
+ <el-table-column type="selection" width="55">
+ </el-table-column>
+ <el-table-column fixed prop="introduction" label="涓婚绠�浠�">
+ </el-table-column>
+ <el-table-column prop="typeName" label="绉戠洰">
+ </el-table-column>
+ <el-table-column prop="contentType" :formatter="typeFormatter" label="鏂囦欢绫诲瀷">
+ </el-table-column>
+ <el-table-column label="鏂囦欢鍐呭" width="240">
+ <template slot-scope="scope">
+ <video controls v-if="scope.row.contentType === 'video'" :src="'/api/files/' + scope.row.contentUrl.url"
+ class="showContent" />
+ <el-image v-if="scope.row.contentType === 'img'" :src="'/api/files/' + scope.row.contentUrl.url"
+ class="showContent"></el-image>
+ <!-- <img v-if="scope.row.contentType === 'img'" :src="'/api/files/' + scope.row.contentUrl.url"
+ class="showContent" /> -->
+ <el-link type="primary" v-if="scope.row.contentType === 'pdf'" class="showContent"
+ @click="checkPdf('/api/files/' + scope.row.contentUrl.url)">鐐瑰嚮鏌ョ湅</el-link>
+ </template>
+ </el-table-column>
+ <el-table-column prop="attachment" label="闄勪欢">
+ <template slot-scope="scope">
+ <div v-for="item in scope.row.attachment" :key="item.url">
+ <el-link type="primary" :href="'/api/upload/download?url=' + item.url +'&fileName=' + item.name" >{{ item.name }}</el-link>
+ </div>
+ </template>
+ </el-table-column>
+ <el-table-column fixed="right" label="鎿嶄綔" width="140">
+ <template slot-scope="scope">
+ <el-button @click="handleUpdate(scope.row)" type="primary" size="small"
+ style="margin-right: 5px">淇敼</el-button>
+ <el-popconfirm :title="getTitle(scope.row.typeName)" @confirm="remove(scope.row.id)">
+ <el-button slot="reference" type="danger" size="small">鍒犻櫎</el-button>
+ </el-popconfirm>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <pagination v-show="total > 0" :total="total" :page.sync="searchForm.pageNum" :limit.sync="searchForm.pageSize"
+ @pagination="page" />
+
+ <el-dialog :title="dialogTitle" :visible.sync="open" width="600px" :close-on-click-modal="false"
+ :before-close="handleClose">
+ <el-form label-position="left" label-width="120px" ref="form" :rules="rules" :model="form">
+ <el-form-item label="涓婚绠�浠�" prop="introduction">
+ <el-input v-model="form.introduction" placeholder="涓婚鍐呭"></el-input>
+ </el-form-item>
+ <el-form-item label="绉戠洰" prop="subjectId">
+ <el-select v-model="form.subjectId" placeholder="绉戠洰">
+ <el-option v-for="item in typeList" :key="item.id" :label="item.name" :value="item.id">
+ </el-option>
+ </el-select>
+ </el-form-item>
+ <el-form-item label="鏂囦欢绫诲瀷" prop="contentType">
+ <el-select v-model="form.contentType" placeholder="涓嶅悓绫诲瀷鐨勬枃浠堕槄瑙堟柟寮忎笉鍚岋紝澶氫綑鏂囦欢璇蜂互闄勪欢褰㈠紡涓婁紶" @change="fileChange">
+ <el-option label="瑙嗛" value="video"></el-option>
+ <el-option label="PDF" value="pdf"></el-option>
+ <el-option label="鍥剧墖" value="img"></el-option>
+ </el-select>
+ </el-form-item>
+ <el-form-item label="涓婁紶鏂囦欢(涓�涓�)" prop="contentUrl">
+ <upload v-show="form.contentType" ref="upload" :fileUrl="form.contentUrl" :fileType="form.contentType"
+ :fileSizeLimitM="1024" :uploadNum="1" @getUploadUrl="getUploadUrl" @removeFile="removeFile" />
+ </el-form-item>
+ <el-form-item label="闄勪欢(鏈�澶�3涓�)" prop="attachment">
+ <upload :fileSizeLimitM="1024" :uploadNum="3" :fileUrl="form.attachment"
+ @getUploadUrl="getUploadAttachmentUrl" @removeFile="removeAttachmentFile" />
+ </el-form-item>
+ </el-form>
+ <span slot="footer" class="dialog-footer">
+ <el-button @click="open = false">鍙� 娑�</el-button>
+ <el-button type="primary" @click="handlerSubmit">淇� 瀛�</el-button>
+ </span>
+ </el-dialog>
+
+ <el-dialog title="PDF鏌ョ湅" :visible.sync="pdfDialog" width="80%" :before-close="closePdfDialog">
+ <vue-office-pdf :src="pdf" @rendered="rendered" style="min-height: 400px; max-height: 800px;"/>
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+import Pagination from '@/components/Pagination';
+import EducationResourceAPI from '@/api/educationResource';
+import SubjectAPI from '@/api/subject';
+import Upload from '@/components/UploadC';
+
+import VueOfficePdf from '@vue-office/pdf';
+export default {
+ name: 'type',
+ components: { Upload, Pagination, VueOfficePdf },
+ computed: {
+ fileContentUrl: () => {
+ return this.form ? this.form.contentUrl ? [this.form.contentUrl] : [] : [];
+ }
+ },
+ data() {
+ return {
+ pdf: '',
+ dialogTitle: '娣诲姞瀛︿範鍐呭',
+ ids: [],
+ typeList: [],
+ searchForm: {
+ pageNum: 1,
+ pageSize: 5,
+ subjectId: null,
+ introduction: null
+ },
+ total: 0,
+ tableData: [],
+ open: false,
+ pdfDialog: false,
+ form: {
+ contentType: 'video',
+ introduction: '',
+ belongType: 2,
+ contentUrl: [],
+ attachment: [],
+ temp: []
+ },
+ rules: {
+ contentUrl: [
+ { required: true, message: '璇蜂笂浼犳枃浠�', trigger: 'blur' },
+ ],
+ introduction: [
+ { required: true, message: '璇疯緭鍏ヤ富棰樺唴瀹�', trigger: 'blur' },
+ ],
+ belongType: [
+ { required: true, message: '璇烽�夋嫨瀛︿範鍒嗙被', trigger: 'change' }
+ ],
+ contentType: [
+ { required: true, message: '璇烽�夋嫨鏂囦欢绫诲瀷', trigger: 'change' }
+ ]
+ }
+ };
+ },
+ methods: {
+ checkPdf(url) {
+ this.pdf = url;
+ this.pdfDialog = true;
+ },
+ closePdfDialog() {
+ this.pdfDialog = false;
+ },
+ rendered() {
+
+ },
+ fileChange() {
+ this.form.contentUrl = [];
+ },
+ handleSelectionChange(val) {
+ this.ids = val.map(item => item.id);
+ },
+ typeFormatter(row) {
+ if (row.contentType === 'video') {
+ return "瑙嗛";
+ }
+ if (row.contentType === 'img') {
+ return "鍥剧墖";
+ }
+ if (row.contentType === 'pdf') {
+ return "PDF";
+ }
+ },
+ clearFile() {
+ this.form.contentUrl = [];
+ this.$refs.upload.clearFile();
+ },
+ removeFile() {
+ this.form.contentUrl = [];
+ },
+ removeAttachmentFile (fileList, fileName) {
+ this.form.attachment = fileList.filter(item => item.name !== fileName);
+ },
+ getUploadAttachmentUrl (uploadData) {
+ this.form.attachment = uploadData;
+ },
+ getUploadUrl (uploadData) {
+ this.form.contentUrl = uploadData;
+ },
+ remove (id) {
+ EducationResourceAPI.remove([id]).then(res => {
+ if (res.code === 1) {
+ this.$message.success('鍒犻櫎鎴愬姛');
+ this.page()
+ }
+ });
+ },
+ batchRemove() {
+ if (this.ids.length < 1) {
+ this.$message.warning("璇烽�夋嫨瑕佸垹闄ょ殑鏁版嵁");
+ }
+ EducationResourceAPI.remove(this.ids).then(res => {
+ if (res.code === 1) {
+ this.$message.success('鍒犻櫎鎴愬姛');
+ this.ids = [];
+ }
+ });
+ },
+ getTitle (typeName) {
+ return '纭畾瑕佸垹闄�' + typeName + '杩欎釜鏂囦欢鍚楋紵';
+ },
+ handlerSubmit () {
+ this.$refs['form'].validate((valid) => {
+ if (valid) {
+ const temp = JSON.parse(JSON.stringify(this.form));
+ // this.form.contentUrl = this.form.contentUrl[0]
+ temp.contentUrl = temp.contentUrl[0];
+ if (temp.id) {
+ EducationResourceAPI.update(temp).then(res => {
+ if (res.code === 1) {
+ this.$message.success('淇敼鎴愬姛');
+ this.open = false;
+ this.page();
+ }
+ });
+ } else {
+ EducationResourceAPI.add(temp).then(res => {
+ if (res.code === 1) {
+ this.$message.success('娣诲姞鎴愬姛');
+ this.open = false;
+ this.page();
+ }
+ });
+ }
+ }
+ });
+ },
+ resetForm() {
+ this.form = {
+ contentType: 'video',
+ introduction: '',
+ belongType: 2,
+ contentUrl: [],
+ attachment: [],
+ temp: []
+ };
+ },
+ handleClose() {
+ this.open = false;
+ this.resetForm();
+ },
+ handlerAdd() {
+ this.resetForm();
+ this.open = true;
+ this.dialogTitle = '娣诲姞瀛︿範鍐呭';
+ },
+ page() {
+ EducationResourceAPI.page(this.searchForm).then(res => {
+ if (res.code === 1) {
+ this.tableData = res.data;
+ this.total = res.total;
+ }
+ });
+ },
+ handleUpdate(row) {
+ this.form.id = row.id;
+ this.form.contentType = row.contentType;
+ this.form.contentUrl = [row.contentUrl] || [];
+ this.form.attachment = row.attachment || [];
+ this.form.introduction = row.introduction;
+ this.form.belongType = row.belongType;
+ this.dialogTitle = '淇敼瀛︿範鍐呭';
+ this.open = true;
+ }
+ },
+ mounted() {
+ this.page();
+ SubjectAPI.list().then(res => {
+ if (res.code === 1) {
+ this.typeList = res.data;
+ }
+ });
+ }
+};
+</script>
+
+<style scoped>
+.showContent {
+ width: 100%;
+ min-height: 80px;
+ object-fit: contain;
+}
+
+.warp {
+ margin: 40px 10px;
+}
+
+.search {
+ margin-top: 10px;
+}
+::v-deep .el-image__error {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+}
+</style>
--
Gitblit v1.8.0