Browse Source

视频列表,添加编辑视频页面

cxmo 1 year ago
parent
commit
a66bf48c13

+ 63 - 0
src/api/modules/trainingApi.js

@@ -87,4 +87,67 @@ export const ClassifyInterface = {
     deleteClassify:(params)=>{
         return http.post('/eta_training_video/classify/remove',params)
     }
+}
+
+//视频管理
+export const VideoInterface = {
+    /**
+     * 获取视频列表
+     * @param {Object} params 
+     * @param {Number} params.PageSize
+     * @param {Number} params.CurrentIndex 
+     * @param {String} params.Keyword
+     * @param {String} params.StartTime
+     * @param {String} params.EndTime
+     * @param {Number} params.ClassifyId
+     * @param {String} params.TagIds 标签IDs, 英文逗号拼接
+     * @param {Number} params.PublishState 发布状态:1-未发布;2-已发布
+     * @returns 
+     */
+    getVideoList:(params)=>{
+        return http.get('/eta_training_video/page_list',params)
+    },
+    /**
+     * 新增视频
+     * @param {Object} params 
+     * @param {String} params.Title
+     * @param {String} params.Introduce
+     * @param {String} params.CoverImg
+     * @param {String} params.VideoUrl
+     * @param {Number} params.ClassifyId
+     * @param {Array} params.TagIds
+     * @returns 
+     */
+    addVideo:(params)=>{
+        return http.post('/eta_training_video/add',params)
+    },
+    /**
+     * 编辑视频
+     * @param {Object} params 
+     * @param {Number} params.VideoId
+     * 其他同上
+     * @returns 
+     */
+    editVideo:(params)=>{
+        return http.post('/eta_training_video/edit',params)
+    },
+    /**
+     * 发布/取消发布视频
+     * @param {Object} params
+     * @param {Number} params.VideoId
+     * @param {Number} params.PublishState 发布状态:0-取消发布;1-发布
+     * @returns 
+     */
+    publishVideo:(params)=>{
+        return http.post('/eta_training_video/publish',params)
+    },
+    /**
+     * 删除视频
+     * @param {Object} params
+     * @param {Number} params.VideoId
+     * @returns 
+     */
+    deleteVideo:(params)=>{
+        return http.post('/eta_training_video/remove',params)
+    },
 }

+ 5 - 0
src/routes/modules/trainingRoutes.js

@@ -23,6 +23,11 @@ export default[
                 name: "分类管理",
                 component: () => import('@/views/training_manage/classifyManage.vue')
             },
+            {
+                path:'modifyVideo',
+                name:'编辑视频',
+                component:()=> import('@/views/training_manage/modifyVideoPage.vue')
+            }
         ]
     }
 ]

+ 28 - 0
src/views/training_manage/config/tableColumn.js

@@ -12,3 +12,31 @@ export const labelTableColumn = [
         minWidth:'200px',
     }
 ]
+
+
+export const videoTableColumn = [
+    {
+        label:'视频封面',
+        key:'CoverImg',
+        Width:'300px',
+    },{
+        label:'视频名称',
+        key:'Title',
+        minWidth:'200px'
+    },{
+        label:'分类',
+        key:'Classify',
+        Width:'200px',
+    },{
+        label:'标签',
+        key:'Tags',
+        minWidth:'200px',
+    },{
+        label:'状态',
+        key:'PublishState',
+    },{
+        label:'创建时间',
+        key:'CreateTime',
+        Width:'200px',
+    }
+]

+ 1 - 1
src/views/training_manage/labelManage.vue

@@ -29,7 +29,7 @@
                 :page-size="pageSize" 
                 :total="total"
                 style="text-align:right;margin-top:30px;">
-        </el-pagination>
+            </el-pagination>
         </div>
         <!-- 添加标签弹窗 -->
         <el-dialog

+ 37 - 0
src/views/training_manage/mixins/videoMixins.js

@@ -0,0 +1,37 @@
+import {TagInterface,ClassifyInterface} from '@/api/modules/trainingApi'
+export default{
+    data() {
+        return {
+            tagList:[],
+            classifyList:[],
+        }
+    },
+    methods: {
+        //获取分类列表
+        getClassifyList(){
+            ClassifyInterface.getClassifyList({}).then(res=>{
+                if(res.Ret!==200) return 
+                this.classifyList = res.Data&&res.Data.List||[]
+                this.filterNodes(this.classifyList)
+            })
+        },
+        filterNodes(arr) {
+            arr.length && arr.forEach(item => {
+                item.Children && item.Children.length && this.filterNodes(item.Children)
+                if(item.Children && !item.Children.length) {
+                    delete item.Children
+                }
+            })
+        },
+        //获取标签列表
+        getTagList(){
+            TagInterface.getTagList({
+                PageSize:1000,
+                CurrentIndex:1
+            }).then(res=>{
+                if(res.Ret!==200) return 
+                this.tagList = res.Data&&res.Data.List||[]
+            })
+        }
+    }
+}

+ 170 - 18
src/views/training_manage/modifyVideoPage.vue

@@ -1,40 +1,192 @@
 <template>
-    <div class="modify-video-page-wrap traing-manage">
-        <div class="top-wrap">
-            
-            <el-input v-model="searchText" clearable 
-                prefix-icon="el-icon-search" placeholder="请输入视频名称" @input="handleCurrentChange(1)" 
-                style="width:240px;"></el-input>
-        </div>
-        <div class="table-wrap">
-            <el-button type="primary" @click="handleModifyLabel({})">新增视频</el-button>
+    <!-- 新增编辑视频 -->
+    <div class="modify-video-page-wrap">
+        <el-form :model="form">
+            <el-form-item label="所属分类" prop="ClassifyId">
+                <el-select v-model="form.ClassifyId"></el-select>
+            </el-form-item>
+            <el-form-item label="视频名称" prop="Title">
+                <el-input v-model="form.Title"></el-input>
+            </el-form-item>
+            <el-form-item label="视频简介" prop="Introduce">
+                <el-input v-model="form.ClassifyId" type="textarea" maxlength="50" show-word-limit :rows="5"></el-input>
+            </el-form-item>
+            <el-form-item label="上传封面" prop="CoverImg">
+                <el-upload action="" accept="image/*" 
+                    :http-request="handleUploadImg" :show-file-list="false">
+                    <el-button type="primary">点击上传</el-button>
+                    <span style="color:#999999;margin-left: 5px;" @click.stop>建议尺寸比例3:2,支持png、jpg、gif、jpeg格式</span>
+                </el-upload>
+                <div class="img-box">
+                    <img :src="form.CoverImg" v-if="form.CoverImg">
+                    <span v-else>请上传封面图</span>
+                </div>
+            </el-form-item>
+            <el-form-item label="上传视频" prop="VideoUrl">
+                <el-upload action="" accept=".mp4" 
+                    :http-request="handleUploadVideo" :show-file-list="false">
+                    <el-button type="primary">点击上传</el-button>
+                    <span style="color:#999999;margin-left: 5px;" @click.stop>仅支持mp4格式</span>
+                </el-upload>
+                <div class="img-box">
+                    <span v-if="form.VideoUrl">时长</span>
+                    <img :src="form.CoverImg" v-if="form.VideoUrl">
+                    
+                    <span v-else>请上传视频</span>
+                </div>
+            </el-form-item>
+            <el-form-item label="视频标签" prop="TagIds">
+                <el-button type="text">选择标签</el-button>
+                <div class="tag-list">
+                    <span class="tag-item" v-for="tag in TagIds">
+                        <span>{{tag.TagName}}</span>
+                        <span @click.stop="removeTag(tag)"><i class="el-icon-close"></i></span>
+                    </span>
+                </div>
+            </el-form-item>
+        </el-form>
+        <div class="btn-box">
+            <el-button type="primary" plain>取消</el-button>
+            <el-button type="primary">保存</el-button>
+            <el-button type="primary">发布</el-button>
         </div>
+        <!-- 选择标签弹窗 -->
     </div>
 </template>
 
 <script>
+import {bannerupload} from '@/api/api.js'
+import {VideoInterface} from '@/api/modules/trainingApi'
+import mixin from './mixins/videoMixins'
 export default {
+    mixins:[mixin],
+    props:{
+        VideoList:{
+            type:Array,
+            default:[]
+        }
+    },
     data() {
         return {
-            searchText:'',
-            tableData: [],
-            tableLoading: false,
+            form:{},
 
-            currentPage: 1,
-            pageSize: 10,
-            total: 0,
+            isImageUploading:false,
+            isVideoUploading:false
 
 
         };
     },
     methods: {
-        handleCurrentChange(page){
+        handleUploadImg(file){
+            //检查图片是否合法
+            console.log('hhh',file)
 
+            isImageUploading = true
+        },
+        uploadImg(file){
+            let form = new FormData();
+            form.append('file',file.file);
+            bannerupload(form).then(res=>{
+                this.isImageUploading = false
+                if(res.Ret!==200) return 
+                this.form.CoverImg = res.Data.ResourceUrl
+            })
+        },
+        handleUploadVideo(file){
+            //检查视频是否合法,并获取视频时长
+            this.isVideoUploading = true
+        },
+        uploadVideo(file,OSSInfo){
+            this.isVideoUploading = false
+        },
+        removeTag(tag){
+            const index = this.form.TagIds.findIndex(i=>i.TagId===tag.TagId)
+            index!==-1&&(this.form.TagIds.splice(index,1))
+        },
+        //获取视频信息
+        getVideoDetail(){
+            const {VideoId} = this.$route.query
+            const videoInfo = _.cloneDeep(this.VideoList.find(i=>i.VideoId==VideoId)||null)
+            if(videoInfo){
+                const {Classify} = videoInfo
+                const classifyArr = this.getDataClassify(Classify)
+                videoInfo.ClassifyId = classifyArr[classifyArr.length-1]
+                delete videoInfo.Classify
+            }
+            this.form = videoInfo||{}
+        },
+        //获取视频分类路径
+        getDataClassify(classify,classifyArr=[]){
+            classifyArr.push(classify.ClassifyId)
+            if(classify.Children&&classify.Children.length){
+                return this.getDataClassify(classify.Children[0],classifyArr)
+            }
+            return classifyArr
+        },
+        //添加/编辑视频
+        async modifyVideo(type){
+            let res  = null
+            let params = {...this.form,...{TagIds:this.form.TagIds.map(t=>t.TagId)}}
+            if(type==='add'){
+                res = await VideoInterface.addVideo(params)
+            }else{
+                res = await VideoInterface.editVideo(params)
+            }
+            if(res.Ret!==200) return 
+            this.$message.success(`${type==='add'?'添加':'编辑'}成功`)
+            this.$router.push('/trainingVideo')
         }
     },
+    mounted(){
+        this.getClassifyList()
+        this.getTagList()
+        this.getVideoDetail()
+    }
 };
 </script>
-
+<style lang="scss">
+.modify-video-page-wrap{
+    .el-textarea__inner{
+        resize: none;
+    }
+    .el-form-item{
+            .el-form-item__content{
+                display: flex;
+                flex-direction: column;
+                align-items:flex-start;
+            }
+        }
+}
+</style>
 <style scoped lang="scss">
-
+.modify-video-page-wrap{
+    box-sizing: border-box;
+    padding:40px;
+    background-color: #fff;
+    border-radius: 4px;
+    .el-form{
+        .el-input,.el-select,.el-textarea{
+            width:500px;
+        }
+        .img-box{
+            background-color: #D9D9D9;
+            width:150px;
+            height:100px;
+            text-align: center;
+            margin-top: 10px;
+            img{
+                width:100%;
+                height:100%;
+            }
+        }
+    }
+    .btn-box{
+        text-align: center;
+        .el-button{
+            margin-right: 50px;
+            width:120px;
+            text-align: center;
+        }
+    }
+}
 </style>

+ 218 - 4
src/views/training_manage/videoManage.vue

@@ -1,22 +1,236 @@
 <template>
-    <div class="video-manage-wrap">
-
+    <div class="video-manage-wrap traing-manage">
+        <div class="top-wrap">
+            <div class="select-box">
+                <el-date-picker
+                    v-model="datePick"
+                    type="daterange"
+                    value-format="yyyy-MM-dd"
+                    range-separator="至"
+                    start-placeholder="开始日期"
+                    end-placeholder="结束日期"
+                    clearable
+                    @change="handleCurrentChange(1)">
+                </el-date-picker>
+                <el-cascader placeholder="选择分类" 
+                    v-model="ClassifyId"
+                    :options="classifyList"
+                    clearable
+                    :show-all-levels="false"
+                    :props="{emitPath:false,
+                            checkStrictly:true,
+                            label:'ClassifyName',
+                            value:'ClassifyId',
+                            children:'Children'}"
+                    @change="handleCurrentChange(1)">
+                </el-cascader>
+                <el-select placeholder="选择标签" 
+                    v-model="TagIds" multiple clearable
+                    @change="handleCurrentChange(1)">
+                    <el-option
+                        v-for="item in tagList"
+                        :key="item.TagId"
+                        :label="item.TagName"
+                        :value="item.TagId">
+                    </el-option>
+                </el-select>
+                <el-select placeholder="选择状态" 
+                    v-model="PublishState" clearable
+                    @change="handleCurrentChange(1)">
+                    <el-option label="未发布" :value="1"/>
+                    <el-option label="已发布" :value="2"/>
+                </el-select>
+            </div>
+            <el-input v-model="searchText" clearable 
+                prefix-icon="el-icon-search" placeholder="请输入视频名称" @input="handleCurrentChange(1)" 
+                style="width:240px;"></el-input>
+        </div>
+        <div class="table-wrap">
+            <el-button type="primary" @click="handleModifyVideo(0)">新增视频</el-button>
+            <el-table border :data="tableData">
+                <el-table-column v-for="column in tableColumn" :key="column.key" 
+                    :label="column.label" align="center"
+                    :prop="column.key"
+                    :width="column.Width"
+                    :min-width="column.minWidth">
+                    <template slot-scope="{row}">
+                        <!-- 视频封面 -->
+                        <div class="img-box" v-if="column.key==='CoverImg'">
+                            <img :src="row.CoverImg" >
+                        </div>
+                        <!-- 分类 -->
+                        <span v-else-if="column.key==='Classify'">
+                            {{getDataClassify(row.Classify).join('/')}}
+                        </span>
+                        <!-- 标签 -->
+                        <div class="label-box" v-else-if="column.key==='Tags'">
+                            <span class="label-item" v-for="tag in row.Tags" :key="tag.TagId">{{tag.TagName}}</span>
+                        </div>
+                        <!-- 发布状态 -->
+                        <span v-else-if="column.key==='PublishState'">{{row.PublishState===0?'未发布':'已发布'}}</span>
+                        <span v-else>{{row[column.key]}}</span>
+                    </template>
+                </el-table-column>
+                <el-table-column label="操作" align="center">
+                    <template slot-scope="{row}">
+                        <el-button type="text" @click="handleModifyVideo(row.VideoId)">编辑</el-button>
+                        <el-button type="text" @click="publishVideo(row)">{{row.PublishState===0?'发布':'取消发布'}}</el-button>
+                        <el-button type="text" @click="deleteVideo(row)">删除</el-button>
+                    </template>
+                </el-table-column>
+            </el-table>
+            <el-pagination
+                layout="total,prev,pager,next,jumper" 
+                background
+                :current-page="currentPage"
+                @current-change="handleCurrentChange"
+                :page-size="pageSize" 
+                :total="total"
+                style="text-align:right;margin-top:30px;">
+            </el-pagination>
+        </div>
     </div>
 </template>
 
 <script>
+import {videoTableColumn} from './config/tableColumn'
+import {VideoInterface} from '@/api/modules/trainingApi'
+import mixin from './mixins/videoMixins'
 export default {
+    mixins:[mixin],
     data() {
         return {
+            /* search options */
+            searchText:'',
+            datePick:[],
+            ClassifyId:'',
+            TagIds:[],
+            PublishState:'',
+
+            tableData: [],
+            tableColumn:videoTableColumn,
+            tableLoading: false,
+
+            currentPage: 1,
+            pageSize: 10,
+            total: 0,
+
 
         };
     },
     methods: {
-
+        //获取视频分类路径
+        getDataClassify(classify,classifyArr=[]){
+            classifyArr.push(classify.ClassifyName)
+            if(classify.Children&&classify.Children.length){
+                return this.getDataClassify(classify.Children[0],classifyArr)
+            }
+            return classifyArr
+        },
+        //获取视频列表
+        getTableData(){
+            VideoInterface.getVideoList({
+                PageSize:this.pageSize,
+                CurrentIndex:this.currentPage,
+                Keyword:this.searchText,
+                StartTime:this.datePick[0],
+                EndTime:this.datePick[1],
+                ClassifyId:Number(this.ClassifyId),
+                TagIds:this.TagIds.join(','),
+                PublishState:Number(this.PublishState)
+            }).then(res=>{
+                if(res.Ret!==200) return 
+                if(!res.Data){
+                    this.tableData = []
+                    this.total = 0
+                    return
+                } 
+                this.tableData = res.Data.List||[]
+                this.total = res.Data.Paging.Totals
+            })
+        },
+        handleModifyVideo(VideoId){
+            this.$router.push({path:'/modifyVideo',query:{VideoId}})
+        },
+        deleteVideo(data){
+            const hint = data.PublishState===0?'删除后不可恢复,是否确认删除?':'该视频已发布,删除后取消发布并删除,是否确认删除?'
+            this.$confirm(
+                    hint,'提示',
+                    {
+                        confirmButtonText: '确定',
+                        cancelButtonText: '取消',
+                        type: 'warning',  
+                    }
+            ).then(()=>{
+                VideoInterface.deleteVideo({
+                    VideoId:data.VideoId,
+                }).then(res=>{
+                    if(res.Ret!==200) return 
+                    this.$message.success("删除成功")
+                    this.getTableData()
+                })
+            })
+        },
+        publishVideo(data){
+            const hint = data.PublishState===0?'是否确认发布':'是否取消发布'
+            this.$confirm(
+                    hint,'提示',
+                    {
+                        confirmButtonText: '确定',
+                        cancelButtonText: '取消',
+                        type: 'warning',  
+                    }
+            ).then(()=>{
+                VideoInterface.publishVideo({
+                    VideoId:data.VideoId,
+                    PublishState:data.PublishState===0?1:0
+                }).then(res=>{
+                    if(res.Ret!==200) return 
+                    this.$message.success(`${data.PublishState?'取消发布':'发布'}成功`)
+                    this.getTableData()
+                })
+            })
+        },
+        handleCurrentChange(page){
+            this.currentPage = page
+            this.getTableData()
+        }
     },
+    mounted(){
+        this.getClassifyList()
+        this.getTagList()
+        this.getTableData()
+    }
 };
 </script>
 
 <style scoped lang="scss">
-
+@import "./css/manage.scss";
+.video-manage-wrap{
+    .table-wrap{
+        .el-table{
+            margin-top:20px;
+            .img-box{
+                text-align: center;
+                img{
+                    width:150px;
+                    height:100px;
+                }
+            }
+            .label-box{
+                display: flex;
+                justify-content: center;
+                gap:8px;
+                .label-item{
+                    padding:6px 12px;
+                    border: 1px solid #409EFF;
+                    color: #409EFF;
+                    background-color: #EAF3FE;
+                    box-sizing: border-box;
+                    border-radius: 4px;
+                }
+            }
+        }
+    }
+}
 </style>