|
@@ -0,0 +1,401 @@
|
|
|
+<template>
|
|
|
+ <div class="offline-training-container">
|
|
|
+ <el-card class="box-card">
|
|
|
+ <div slot="header" class="clearfix">
|
|
|
+ <span>考试拿证流程介绍</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <viewer ref="imageWrapper" :images="previewImages" style="opacity: 1;position: absolute;top: -9999px;">
|
|
|
+ <img v-for="(image, index) in previewImages" :src="image" :key="index" />
|
|
|
+ </viewer>
|
|
|
+
|
|
|
+ <el-form ref="form" :model="form" label-width="120px">
|
|
|
+ <div class="form-section">
|
|
|
+ <el-form-item label="分类名称" prop="typeName">
|
|
|
+ <el-input v-model="form.typeName" placeholder="请输入分类名称"></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="form-section">
|
|
|
+ <el-form-item label="分类封面" prop="coverImage">
|
|
|
+ <div class="upload-area">
|
|
|
+ <el-upload
|
|
|
+ class="cover-uploader"
|
|
|
+ action="#"
|
|
|
+ :show-file-list="false"
|
|
|
+ :on-change="handleCoverChange"
|
|
|
+ :auto-upload="false"
|
|
|
+ :before-upload="beforeCoverUpload">
|
|
|
+ <img v-if="form.coverImage" :src="form.coverImage" class="cover-preview">
|
|
|
+ <i v-else class="el-icon-plus cover-uploader-icon"></i>
|
|
|
+ <div v-if="form.coverImage" class="cover-mask">
|
|
|
+ <el-link icon="el-icon-view" type="success" @click.stop="previewImage(form.coverImage)" :underline="false">查看</el-link>
|
|
|
+ <el-link icon="el-icon-edit" type="success" :underline="false" style="margin-left: 10px;">修改</el-link>
|
|
|
+ </div>
|
|
|
+ </el-upload>
|
|
|
+ <div class="upload-tip">建议尺寸:800x600px,大小不超过5MB</div>
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="form-section">
|
|
|
+ <el-form-item label="内容上传" prop="type">
|
|
|
+ <el-radio-group v-model="form.type" @change="handleContentTypeChange">
|
|
|
+ <el-radio label="image">图片</el-radio>
|
|
|
+ <el-radio label="video">视频</el-radio>
|
|
|
+ </el-radio-group>
|
|
|
+
|
|
|
+ <div class="upload-area" v-if="form.type === 'image'">
|
|
|
+ <el-upload
|
|
|
+ action="#"
|
|
|
+ :show-file-list="false"
|
|
|
+ :on-change="handleImageChange"
|
|
|
+ :auto-upload="false"
|
|
|
+ accept="image/*"
|
|
|
+ :before-upload="beforeImageUpload">
|
|
|
+ <el-button size="small" type="primary">点击上传图片</el-button>
|
|
|
+ </el-upload>
|
|
|
+ <div class="upload-preview" v-if="form.contentImage">
|
|
|
+ <img :src="form.contentImage" class="content-preview" @click="previewImage(form.contentImage)">
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="upload-area" v-else-if="form.type === 'video'">
|
|
|
+ <el-upload
|
|
|
+ action="#"
|
|
|
+ :show-file-list="false"
|
|
|
+ :on-change="handleVideoChange"
|
|
|
+ :auto-upload="false"
|
|
|
+ accept="video/*"
|
|
|
+ :before-upload="beforeVideoUpload">
|
|
|
+ <el-button size="small" type="primary">点击上传视频</el-button>
|
|
|
+ </el-upload>
|
|
|
+ <div class="upload-preview" v-if="form.contentVideo">
|
|
|
+ <video controls class="video-preview">
|
|
|
+ <source :src="form.contentVideo" type="video/mp4">
|
|
|
+ </video>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="action-buttons">
|
|
|
+ <el-button type="primary" @click="submitForm" :loading="submitLoading">提交</el-button>
|
|
|
+ <el-button @click="resetForm" :loading="submitLoading">重置</el-button>
|
|
|
+ </div>
|
|
|
+ </el-form>
|
|
|
+ </el-card>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import { post, checkAndAddUpload } from '../../api'
|
|
|
+export default {
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ form: {
|
|
|
+ typeName: '',
|
|
|
+ coverImage: '',
|
|
|
+ type: 'image',
|
|
|
+ contentImage: '',
|
|
|
+ contentVideo: ''
|
|
|
+ },
|
|
|
+ previewImages: [],
|
|
|
+ submitLoading: false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ previewImage(url) {
|
|
|
+ this.previewImages = [url];
|
|
|
+ this.$nextTick(() => {
|
|
|
+ if (this.$refs.imageWrapper && this.$refs.imageWrapper.$viewer) {
|
|
|
+ this.$refs.imageWrapper.$viewer.show();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ checkAndAddUpload(str) {
|
|
|
+ if(!str) return '';
|
|
|
+ return str.includes('/upload/') ? str : '/upload/' + str;
|
|
|
+ },
|
|
|
+
|
|
|
+ handleCoverChange(file) {
|
|
|
+ const isImage = file.raw.type.includes('image');
|
|
|
+ const isLt5M = file.raw.size / 1024 / 1024 < 5;
|
|
|
+
|
|
|
+ if (!isImage) {
|
|
|
+ this.$message.error('只能上传图片文件!');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (!isLt5M) {
|
|
|
+ this.$message.error('图片大小不能超过5MB!');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const formData = new FormData();
|
|
|
+ formData.append('multipartFile', file.raw);
|
|
|
+
|
|
|
+ this.http.uploadFile('/common/uploadFile', formData, res => {
|
|
|
+ if (res.code === "ok") {
|
|
|
+ this.form.coverImage = this.checkAndAddUpload(res.data);
|
|
|
+ this.$message.success('封面图片上传成功');
|
|
|
+ } else {
|
|
|
+ this.$message.error(res.msg || '上传失败');
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ beforeCoverUpload(file) {
|
|
|
+ const isImage = file.type.includes('image');
|
|
|
+ const isLt5M = file.size / 1024 / 1024 < 5;
|
|
|
+
|
|
|
+ if (!isImage) {
|
|
|
+ this.$message.error('只能上传图片文件!');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (!isLt5M) {
|
|
|
+ this.$message.error('图片大小不能超过5MB!');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ },
|
|
|
+
|
|
|
+ handleImageChange(file) {
|
|
|
+ const isImage = file.raw.type.includes('image');
|
|
|
+ const isLt5M = file.raw.size / 1024 / 1024 < 5;
|
|
|
+
|
|
|
+ if (!isImage) {
|
|
|
+ this.$message.error('只能上传图片文件!');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (!isLt5M) {
|
|
|
+ this.$message.error('图片大小不能超过5MB!');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const formData = new FormData();
|
|
|
+ formData.append('multipartFile', file.raw);
|
|
|
+
|
|
|
+ this.http.uploadFile('/common/uploadFile', formData, res => {
|
|
|
+ if (res.code === "ok") {
|
|
|
+ this.form.contentImage = this.checkAndAddUpload(res.data);
|
|
|
+ this.$message.success('内容图片上传成功');
|
|
|
+ } else {
|
|
|
+ this.$message.error(res.msg || '上传失败');
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ beforeImageUpload(file) {
|
|
|
+ return this.beforeCoverUpload(file);
|
|
|
+ },
|
|
|
+
|
|
|
+ handleVideoChange(file) {
|
|
|
+ const isVideo = file.raw.type.includes('video');
|
|
|
+ const isLt50M = file.raw.size / 1024 / 1024 < 50;
|
|
|
+
|
|
|
+ if (!isVideo) {
|
|
|
+ this.$message.error('只能上传视频文件!');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (!isLt50M) {
|
|
|
+ this.$message.error('视频大小不能超过50MB!');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const formData = new FormData();
|
|
|
+ formData.append('multipartFile', file.raw);
|
|
|
+
|
|
|
+ this.http.uploadFile('/common/uploadFile', formData, res => {
|
|
|
+ if (res.code === "ok") {
|
|
|
+ this.form.contentVideo = this.checkAndAddUpload(res.data);
|
|
|
+ this.$message.success('视频上传成功');
|
|
|
+ } else {
|
|
|
+ this.$message.error(res.msg || '上传失败');
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ beforeVideoUpload(file) {
|
|
|
+ const isVideo = file.type.includes('video');
|
|
|
+ const isLt50M = file.size / 1024 / 1024 < 50;
|
|
|
+
|
|
|
+ if (!isVideo) {
|
|
|
+ this.$message.error('只能上传视频文件!');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (!isLt50M) {
|
|
|
+ this.$message.error('视频大小不能超过50MB!');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ },
|
|
|
+
|
|
|
+ handleContentTypeChange(val) {
|
|
|
+ this.form.contentImage = '';
|
|
|
+ this.form.contentVideo = '';
|
|
|
+ },
|
|
|
+
|
|
|
+ submitForm() {
|
|
|
+ this.$refs.form.validate(valid => {
|
|
|
+ if (valid) {
|
|
|
+ console.log(this.form, '<==== 将要提交的表单')
|
|
|
+ const { id, type, typeName, coverImage, contentImage, contentVideo } = this.form
|
|
|
+ const obj = {
|
|
|
+ typeName,
|
|
|
+ coverImage,
|
|
|
+ type: type == 'video' ? 1 : 0,
|
|
|
+ content: type == 'video' ? contentVideo : contentImage,
|
|
|
+ }
|
|
|
+
|
|
|
+ if(id) {
|
|
|
+ obj.id = id
|
|
|
+ }
|
|
|
+
|
|
|
+ this.submitLoading = true
|
|
|
+ post(`/examination-process/saveOrUpdate`, { ...obj }).then(res => {
|
|
|
+ this.$message({
|
|
|
+ type: 'success',
|
|
|
+ message: res.msg || '保存成功',
|
|
|
+ });
|
|
|
+
|
|
|
+ this.obtainOfflineTrainingCourses()
|
|
|
+ }).finally(() => {
|
|
|
+ this.submitLoading = false
|
|
|
+ })
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ resetForm() {
|
|
|
+ this.$refs.form.resetFields();
|
|
|
+ this.form.contentImage = '';
|
|
|
+ this.form.contentVideo = '';
|
|
|
+ },
|
|
|
+
|
|
|
+ obtainOfflineTrainingCourses() {
|
|
|
+ post(`/examination-process/getDetail`, {}).then((res) => {
|
|
|
+ this.form = {
|
|
|
+ ...res.data,
|
|
|
+ content: checkAndAddUpload(res.data.content),
|
|
|
+ coverImage: checkAndAddUpload(res.data.coverImage),
|
|
|
+ contentImage: res.data.type != 1 ? checkAndAddUpload(res.data.content) : '',
|
|
|
+ contentVideo: res.data.type == 1 ? checkAndAddUpload(res.data.content) : '',
|
|
|
+ type: res.data.type == 1 ? 'video' : 'image'
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ this.obtainOfflineTrainingCourses()
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.offline-training-container {
|
|
|
+ padding: 20px;
|
|
|
+ max-width: 1000px;
|
|
|
+ margin: 0 auto;
|
|
|
+}
|
|
|
+
|
|
|
+.box-card {
|
|
|
+ border-radius: 8px;
|
|
|
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
|
|
+}
|
|
|
+
|
|
|
+.form-section {
|
|
|
+ margin-bottom: 24px;
|
|
|
+}
|
|
|
+
|
|
|
+.upload-area {
|
|
|
+ border: 1px dashed #dcdfe6;
|
|
|
+ border-radius: 6px;
|
|
|
+ padding: 20px;
|
|
|
+ margin-bottom: 20px;
|
|
|
+ background-color: #f5f7fa;
|
|
|
+}
|
|
|
+
|
|
|
+.upload-preview {
|
|
|
+ margin-top: 15px;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+.cover-uploader {
|
|
|
+ border: 1px dashed #d9d9d9;
|
|
|
+ border-radius: 6px;
|
|
|
+ cursor: pointer;
|
|
|
+ position: relative;
|
|
|
+ overflow: hidden;
|
|
|
+ width: 200px;
|
|
|
+ height: 150px;
|
|
|
+ margin: 0 auto;
|
|
|
+}
|
|
|
+
|
|
|
+.cover-uploader:hover {
|
|
|
+ border-color: #409EFF;
|
|
|
+}
|
|
|
+
|
|
|
+.cover-uploader:hover .cover-mask {
|
|
|
+ opacity: 1;
|
|
|
+}
|
|
|
+
|
|
|
+.cover-mask {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ background: rgba(0, 0, 0, 0.5);
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ opacity: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.cover-uploader-icon {
|
|
|
+ font-size: 28px;
|
|
|
+ color: #8c939d;
|
|
|
+ width: 200px;
|
|
|
+ height: 150px;
|
|
|
+ line-height: 150px;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+.cover-preview {
|
|
|
+ width: 200px;
|
|
|
+ height: 150px;
|
|
|
+ object-fit: cover;
|
|
|
+ border-radius: 4px;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+
|
|
|
+.content-preview {
|
|
|
+ max-width: 100%;
|
|
|
+ max-height: 300px;
|
|
|
+ border-radius: 4px;
|
|
|
+ cursor: pointer;
|
|
|
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
|
+}
|
|
|
+
|
|
|
+.video-preview {
|
|
|
+ max-width: 100%;
|
|
|
+ max-height: 300px;
|
|
|
+ border-radius: 4px;
|
|
|
+ background-color: #000;
|
|
|
+}
|
|
|
+
|
|
|
+.upload-tip {
|
|
|
+ color: #909399;
|
|
|
+ font-size: 12px;
|
|
|
+ margin-top: 8px;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+.action-buttons {
|
|
|
+ margin-top: 24px;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+</style>
|