ソースを参照

添加视频和相册管理页面及接口

reghao 2 年 前
コミット
ac218b598b

+ 5 - 0
src/api/image.js

@@ -3,6 +3,7 @@ import { get, post } from '@/utils/request'
 const imageApi = {
   userAlbumApi: '/api/content/image/album',
   userAlbumApi1: '/api/content/image/album',
+  albumSubmitApi: '/api/content/image/album/submit',
 }
 
 // 视频推荐接口
@@ -13,3 +14,7 @@ export function getUserAlbums(userId) {
 export function getUserAlbum(albumId) {
   return get(imageApi.userAlbumApi1 + '/' + albumId)
 }
+
+export function submitAlbum(album) {
+  return post(imageApi.albumSubmitApi, album)
+}

+ 21 - 1
src/api/video.js

@@ -50,7 +50,7 @@ export function videoUrl(videoId) {
   return get(videoApi.videoUrlApi + '/' + videoId)
 }
 
-// 视频 URL 接口
+// 视频分类接口
 export function videoCategory() {
   return get(videoApi.videoCategoryApi)
 }
@@ -59,6 +59,26 @@ export function submitVideo(video) {
   return post(videoApi.videoSubmitApi, video)
 }
 
+// 更新视频信息
+export function updateVideoInfo(data) {
+  return post(videoApi.videoSubmitApi, data)
+}
+
+// 更新视频可见范围
+export function updateVideoScope(data) {
+  return post(videoApi.videoSubmitApi, data)
+}
+
+// 更新视频封面
+export function updateVideoCover(data) {
+  return post(videoApi.videoSubmitApi, data)
+}
+
+// 更新视频文件
+export function updateVideoFile(data) {
+  return post(videoApi.videoSubmitApi, data)
+}
+
 // 播放记录
 export function submitPlayRecord(playerRecord) {
   return post(videoApi.playerRecordApi, playerRecord)

+ 308 - 0
src/components/upload/EditImage.vue

@@ -0,0 +1,308 @@
+<template>
+  <div>
+    <el-row class="movie-list">
+      <el-card class="box-card">
+        <div class="text item">
+          <el-button style="float: left; padding: 3px 0" type="text" @click="onReturnAlbum">返回相册列表</el-button>
+        </div>
+      </el-card>
+    </el-row>
+    <el-row class="movie-list">
+      <el-col :md="8">
+        <el-card class="box-card">
+          <div slot="header" class="clearfix">
+            <span>添加图片</span>
+            <el-button style="float: right; padding: 3px 0" type="text" @click="onAddImages">更新</el-button>
+          </div>
+          <div class="text item">
+            <file-pond
+              ref="pond"
+              name="file"
+              label-idle="选择图片或拖动图片到此处"
+              label-file-processing="图片正在上传,请稍后"
+              label-file-processing-aborted="图片上传被取消"
+              label-tap-to-retry="尝试重试"
+              label-file-processing-complete="图片上传成功!"
+              label-max-file-size="上传的图片大小不能超过 100MB"
+              label-max-file-size-exceeded="上传的图片大小不能超过 100MB"
+              allow-file-size-validation="true"
+              max-file-size="100MB"
+              accepted-file-types="image/png, image/jpeg, image/jpg, image/gif"
+              :allow-multiple="true"
+              :max-files="100"
+              :server="server"
+              :instant-upload="true"
+              @init="handleFilePondInit"
+              @processfile="handleFilePondSuccess"
+              @removefile="handleFilePondRemove"
+            />
+          </div>
+        </el-card>
+      </el-col>
+      <el-col :md="8">
+        <el-card class="box-card">
+          <div slot="header" class="clearfix">
+            <span>修改相册名</span>
+            <el-button style="float: right; padding: 3px 0" type="text" @click="onUpdateAlbumName">更新</el-button>
+          </div>
+          <div class="text item">
+            <el-form ref="form" :model="form" label-width="80px">
+              <el-form-item label="相册名">
+                <el-input v-model="form.albumName" style="width: 70%; padding-right: 2px" placeholder="相册名不能超过 50 个字符" />
+              </el-form-item>
+            </el-form>
+          </div>
+        </el-card>
+      </el-col>
+      <el-col :md="8">
+        <el-card class="box-card">
+          <div slot="header" class="clearfix">
+            <span>修改相册可见范围</span>
+            <el-button style="float: right; padding: 3px 0" type="text" @click="onUpdateAlbumScope">更新</el-button>
+          </div>
+          <div class="text item">
+            <el-form ref="form" :model="form" label-width="80px">
+              <el-form-item label="相册名">
+                <el-input v-model="form.albumName" style="width: 70%; padding-right: 2px" placeholder="相册名不能超过 50 个字符" />
+              </el-form-item>
+            </el-form>
+          </div>
+        </el-card>
+      </el-col>
+    </el-row>
+    <el-row>
+      <el-col :md="24" class="movie-list">
+        <div>
+          <el-col v-for="(image, index) in data.imageUrls"
+                  :key="image.thumbnailUrl"
+                  :md="6" :sm="12" :xs="12"
+                  style="padding-right: 5px; padding-left: 5px; padding-bottom: 5px">
+            <el-card :body-style="{ padding: '0px' }" class="card">
+              <div class="imgs">
+                <el-image
+                  lazy
+                  fit="cover"
+                  class="coverImg"
+                  :src="image.thumbnailUrl"
+                  @click="showImages(index)">
+                </el-image>
+              </div>
+              <div style="padding: 14px;">
+                <el-button
+                  size="mini"
+                  type="danger"
+                  class="el-icon-delete"
+                  @click="onDeleteImage"></el-button>
+<!--                <span>
+                  <i class="el-icon-delete" style="color: blue" @click="onDeleteImage(image.imageFileId)"/>
+                </span>-->
+              </div>
+            </el-card>
+          </el-col>
+        </div>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import VueFilePond from 'vue-filepond'
+import 'filepond/dist/filepond.min.css'
+import FilePondPluginImagePreview from 'filepond-plugin-image-preview'
+import 'filepond-plugin-image-preview/dist/filepond-plugin-image-preview.min.css'
+import FilePondPluginFileValidateType from 'filepond-plugin-file-validate-type'
+import FilePondPluginFileValidateSize from 'filepond-plugin-file-validate-size'
+
+const FilePond = VueFilePond(
+  FilePondPluginFileValidateType,
+  FilePondPluginImagePreview,
+  FilePondPluginFileValidateSize
+)
+var imgFileIds = []
+
+import { getUserAlbums, getUserAlbum, submitAlbum } from "@/api/image";
+
+export default {
+  name: 'EditImage',
+  data() {
+    return {
+      // 屏幕宽度, 为了控制分页条的大小
+      screenWidth: document.body.clientWidth,
+      currentPage: 1,
+      viewerOptions:{
+        movable: true,
+        fullscreen: false,
+        keyboard: true
+      },
+      user: null,
+      data: null,
+      followButton: {
+        icon: 'el-icon-plus',
+        text: '关注'
+      },
+      collected: false,
+      server: {
+        url: '//oss.reghao.cn/',
+        revert: null,
+        process: {
+          headers: {
+            Authorization: '1234567890'
+          },
+          ondata(formData) {
+            formData.append('channelId', 5)
+            return formData
+          },
+          onload(response) {
+            const resp = JSON.parse(response)
+            if (resp.code === 0) {
+              const uploadId = resp.data.uploadId
+              imgFileIds.push(uploadId)
+            } else {
+              if (resp.msg != null) {
+                this.message = '上传文件出现异常,请重新上传!' + resp.msg
+              } else {
+                this.message = '上传文件出现异常,请重新上传!'
+              }
+              this.showMessage = true
+            }
+          }
+        }
+      },
+      imageList: [],
+      form: {
+        albumName: null,
+        scope: 0
+      }
+    }
+  },
+  created() {
+    document.title = '编辑相册'
+
+    const albumId = this.$route.params.albumId
+    getUserAlbum(albumId).then(res => {
+      if (res.code === 0) {
+        const resData = res.data
+        this.data = resData
+        this.form.albumName = resData.albumName
+        // this.form.scope = resData.scope
+      }
+    })
+  },
+  mounted() {
+    // 当窗口宽度改变时获取屏幕宽度
+    window.onresize = () => {
+      return () => {
+        window.screenWidth = document.body.clientWidth
+        this.screenWidth = window.screenWidth
+      }
+    }
+  },
+  methods: {
+    showImages(index) {
+      const imageUrls = []
+      for (const i of this.data.imageUrls) {
+        imageUrls.push(i.originalUrl)
+      }
+
+      this.$viewerApi({
+        images: imageUrls,
+        options: {
+          initialViewIndex: index,
+          movable: true,
+          fullscreen: false,
+          keyboard: true
+        }
+      })
+    },
+    /***********************************************************************/
+    handleFilePondInit() {
+      // FilePond instance methods are available on `this.$refs.pond`
+    },
+    handleFilePondSuccess(error, metadata) {
+      if (error === null) {
+        return
+      }
+      console.log('图片已上传')
+      console.log(metadata)
+    },
+    handleFilePondRemove(error, metadata) {
+      console.log('删除已上传的图片')
+      /*if (error === null) {
+        const file = metadata.file
+        const uploadId = this.imgMap[file.name]
+        fetch('//oss.reghao.cn/' + uploadId, {
+          headers: {
+            'Authorization': this.$store.getters.token
+          },
+          method: 'DELETE'
+        }).then(response => response.json())
+          .then(json => {
+            console.log('删除 this.statusPost.imageFileIds 中相应的图片')
+          })
+          .catch(e => {
+            return null
+          })
+      }*/
+    },
+    /***********************************************************************/
+    onUpdateAlbumName() {
+      console.log('修改相册名')
+    },
+    onUpdateAlbumScope() {
+      console.log('修改相册可见范围')
+    },
+    onDeleteImage(imageFileId) {
+      console.log('删除图片 ' + imageFileId)
+    },
+    onReturnAlbum() {
+      this.$router.push('/post/image')
+    },
+    onAddImages() {
+      console.log('添加图片')
+      /*this.form.imageFileIds = imgFileIds
+      submitAlbum(this.form).then(res => {
+        if (res.code === 0) {
+          this.$router.push('/post/image')
+        } else {
+        }
+      })*/
+    }
+  }
+}
+</script>
+
+<style scoped>
+.movie-list {
+  padding-top: 15px;
+  padding-left: 6%;
+  padding-right: 6%;
+}
+
+/*处于手机屏幕时*/
+@media screen and (max-width: 768px){
+  .movie-list {
+    padding-top: 8px;
+    padding-left: 0.5%;
+    padding-right: 0.5%;
+  }
+
+  .coverImg {
+    height: 120px !important;
+  }
+}
+
+.coverImg {
+  width: 100%;
+  height: 320px;
+  display: block;
+}
+
+.card {
+  margin-bottom: 20px;
+  transition: all 0.6s; /*所有属性变化在0.6秒内执行动画*/
+}
+
+.imgs {
+  position: relative;
+}
+</style>

+ 491 - 0
src/components/upload/EditVideo.vue

@@ -0,0 +1,491 @@
+<template>
+  <div>
+    <el-row class="movie-list">
+      <el-card class="box-card">
+        <div class="text item">
+          <el-button style="float: left; padding: 3px 0" type="text" @click="onReturnVideo">返回视频列表</el-button>
+        </div>
+      </el-card>
+    </el-row>
+    <el-row class="movie-list">
+      <el-col :md="8">
+        <el-card class="box-card">
+          <div slot="header" class="clearfix">
+            <span>更新视频文件</span>
+            <el-button style="float: right; padding: 3px 0" type="text" @click="onUpdateVideoFile">更新</el-button>
+          </div>
+          <div class="text item">
+            <uploader
+              class="uploader-example"
+              :options="options"
+              :auto-start="true"
+              @file-added="onFileAdded"
+              @file-success="onFileSuccess"
+              @file-progress="onFileProgress"
+              @file-error="onFileError"
+            >
+              <uploader-unsupport />
+              <uploader-drop>
+                <p>拖动视频文件到此处或</p>
+                <uploader-btn :attrs="attrs">选择视频文件</uploader-btn>
+              </uploader-drop>
+              <uploader-list />
+            </uploader>
+          </div>
+        </el-card>
+      </el-col>
+      <el-col :md="8">
+        <el-card class="box-card">
+          <div slot="header" class="clearfix">
+            <span>更新视频封面</span>
+            <el-button style="float: right; padding: 3px 0" type="text" @click="onUpdateVideoCover">更新</el-button>
+          </div>
+          <div class="text item">
+            <el-upload
+              class="avatar-uploader"
+              action="//oss.reghao.cn/"
+              :headers="imgHeaders"
+              :data="imgData"
+              :show-file-list="false"
+              :before-upload="beforeAvatarUpload"
+              :on-success="handleAvatarSuccess"
+            >
+              <img v-if="imageUrl" :src="imageUrl" class="avatar">
+              <i v-else class="el-icon-plus avatar-uploader-icon" />
+            </el-upload>
+          </div>
+        </el-card>
+      </el-col>
+    </el-row>
+    <el-row class="movie-list">
+      <el-col :md="8">
+        <el-card class="box-card">
+          <div slot="header" class="clearfix">
+            <span>更新视频信息</span>
+            <el-button style="float: right; padding: 3px 0" type="text" @click="onUpdateVideoInfo">更新</el-button>
+          </div>
+          <div class="text item">
+            <el-form ref="form" :model="form" label-width="80px">
+              <el-form-item label="标题">
+                <el-input v-model="form.title" style="width: 70%; padding-right: 2px" placeholder="标题不能超过 50 个字符" />
+              </el-form-item>
+              <el-form-item label="描述">
+                <el-input v-model="form.description" type="textarea" style="width: 70%; padding-right: 2px" />
+              </el-form-item>
+              <el-form-item label="分区">
+                <el-select v-model="category" placeholder="请选择分区">
+                  <el-option label="新闻" value="shanghai" />
+                  <el-option label="教育" value="beijing" />
+                </el-select>
+                <el-select v-model="childCategory" placeholder="请选择子分区">
+                  <el-option label="历史" value="shanghai" />
+                  <el-option label="计算机" value="beijing" />
+                </el-select>
+              </el-form-item>
+              <el-form-item label="标签">
+                <el-input v-model="tagsStr" style="width: 70%; padding-right: 2px" placeholder="多个标签之间使用英文逗号分隔" />
+              </el-form-item>
+            </el-form>
+          </div>
+        </el-card>
+      </el-col>
+      <el-col :md="8">
+        <el-card class="box-card">
+          <div slot="header" class="clearfix">
+            <span>更新视频可见范围</span>
+            <el-button style="float: right; padding: 3px 0" type="text" @click="onUpdateVideoScope">更新</el-button>
+          </div>
+          <div class="text item">
+            <el-form ref="form" :model="form" label-width="80px">
+              <el-form-item label="可见范围">
+                <el-select v-model="form.scope" placeholder="选择可见范围">
+                  <el-option label="所有人可见" value="1" />
+                  <el-option label="验证码可见" value="2" />
+                  <el-option label="VIP 可见" value="3" />
+                  <el-option label="仅自己可见" value="4" />
+                </el-select>
+              </el-form-item>
+            </el-form>
+          </div>
+        </el-card>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { videoCategory, submitVideo, videoInfo, updateVideoInfo, updateVideoScope, updateVideoCover, updateVideoFile } from '@/api/video'
+
+export default {
+  name: 'EditVideo',
+  data() {
+    return {
+      /***********************************************************************/
+      options: {
+        target: '//oss.reghao.cn/',
+        chunkSize: 1024 * 1024 * 1024 * 5, // 5GiB
+        fileParameterName: 'file',
+        testChunks: false,
+        query: (file, chunk) => {
+          return {
+            channelId: 2
+          }
+        },
+        headers: {
+          Authorization: '1234567890'
+        }
+      },
+      attrs: {
+        accept: 'video/*'
+      },
+      imgHeaders: {
+        Authorization: '1234567890'
+      },
+      imgData: {
+        channelId: 3
+      },
+      /***********************************************************************/
+      coverUrl: null,
+      categoryMap: {
+        Set: function(key, value) { this[key] = value },
+        Get: function(key) { return this[key] },
+        Contains: function(key) { return this.Get(key) !== null },
+        Remove: function(key) { delete this[key] }
+      },
+      category: [],
+      childCategory: [],
+      coverFile: null,
+      imageList: [],
+      imageUrl: '',
+      // 提交给后端的数据
+      tagsStr: null,
+      form: {
+        videoFileId: null,
+        coverUrl: null,
+        title: null,
+        description: null,
+        categoryId: 0,
+        tags: [],
+        scope: null,
+        width: 0,
+        height: 0,
+        duration: 0
+      },
+      videoInfo: null
+    }
+  },
+  created() {
+    document.title = '编辑视频'
+
+    const videoId = this.$route.params.videoId
+    videoInfo(videoId).then(res => {
+      if (res.code === 0) {
+        const videoInfo = res.data
+        this.imageUrl = videoInfo.coverUrl
+        this.form.title = videoInfo.title
+        this.form.description = videoInfo.description
+        this.form.scope = videoInfo.scope
+      } else {
+
+      }
+    })
+    //this.getVideoCategory()
+  },
+  methods: {
+    /***********************************************************************/
+    onFileAdded(file) {
+      if (file.file.size > 1024*1024*1024*5) {
+        file.cancel()
+        this.$notify(
+          {
+            title: '提示',
+            message: '视频文件应小于 5GiB',
+            type: 'warning',
+            duration: 3000
+          }
+        )
+        return
+      }
+      this.setTitle(file.file.name)
+      this.processVideo(file.file)
+    },
+    onFileProgress(rootFile, file, chunk) {
+    },
+    onFileSuccess(rootFile, file, response, chunk) {
+      const res = JSON.parse(response)
+      if (res.code === 0) {
+        const resData = res.data
+        this.form.videoFileId = resData.uploadId
+
+        this.$notify(
+          {
+            title: '提示',
+            message: '视频已上传',
+            type: 'warning',
+            duration: 3000
+          }
+        )
+      }
+    },
+    onFileError(rootFile, file, response, chunk) {
+      this.$notify(
+        {
+          title: '提示',
+          message: '文件上传错误',
+          type: 'warning',
+          duration: 3000
+        }
+      )
+    },
+    /***********************************************************************/
+    beforeAvatarUpload(file) {
+      const isJPG = file.type === 'image/jpeg'
+      const isLt2M = file.size / 1024 / 1024 < 2
+      if (!isJPG) {
+        this.$message.error('上传头像图片只能是 JPG 格式!')
+      }
+      if (!isLt2M) {
+        this.$message.error('上传头像图片大小不能超过 2MB!')
+      }
+      return isJPG && isLt2M
+    },
+    handleAvatarSuccess(res, file) {
+      this.imageList.push(file)
+      this.imageUrl = URL.createObjectURL(file.raw)
+      if (res.code === 0) {
+        const resData = res.data
+        const uploadId = resData.uploadId
+        const url = resData.url
+      } else {
+
+      }
+    },
+    /***********************************************************************/
+    // 选择视频后获取视频的分辨率和时长, 并截取第一秒的内容作为封面
+    processVideo(file) {
+      return new Promise((resolve, reject) => {
+        const canvas = document.createElement('canvas')
+        const canvasCtx = canvas.getContext('2d')
+
+        const videoElem = document.createElement('video')
+        const dataUrl = window.URL.createObjectURL(file)
+        // 当前帧的数据是可用的
+        videoElem.onloadeddata = function() {
+          resolve(videoElem)
+        }
+        videoElem.onerror = function() {
+          reject('video 后台加载失败')
+        }
+        // 设置 auto 预加载数据, 否则会出现截图为黑色图片的情况
+        videoElem.setAttribute('preload', 'auto')
+        videoElem.src = dataUrl
+        // 预加载完成后才会获取到视频的宽高和时长数据
+        videoElem.addEventListener('canplay', this.onCanPlay(videoElem, canvas, canvasCtx))
+      })
+    },
+    onCanPlay(videoElem, canvas, canvasCtx) {
+      setTimeout(() => {
+        // 视频视频分辨率
+        const videoWidth = videoElem.videoWidth
+        const videoHeight = videoElem.videoHeight
+        this.form.width = videoWidth
+        this.form.height = videoHeight
+        this.form.duration = videoElem.duration
+
+        videoElem.pause()
+        // 设置画布尺寸
+        canvas.width = videoWidth
+        canvas.height = videoHeight
+        canvasCtx.drawImage(videoElem, 0, 0, canvas.width, canvas.height)
+        // 把图标base64编码后变成一段url字符串
+        const urlData = canvas.toDataURL('image/jpeg')
+        if (typeof urlData !== 'string') {
+          alert('urlData不是字符串')
+          return
+        }
+
+        var arr = urlData.split(',')
+        var bstr = atob(arr[1])
+        var n = bstr.length
+        var u8arr = new Uint8Array(n)
+        while (n--) {
+          u8arr[n] = bstr.charCodeAt(n)
+        }
+
+        const coverFile = new File([u8arr], 'cover.jpg', { type: 'image/jpeg' })
+        if (coverFile instanceof File) {
+          const formData = new FormData()
+          formData.append('file', coverFile)
+          formData.append('channelId', 3)
+          fetch(`//oss.reghao.cn/`, {
+            headers: {
+              Authorization: '1234567890'
+            },
+            method: 'POST',
+            credentials: 'include',
+            body: formData
+          }).then(response => response.json())
+            .then(json => {
+              if (json.code === 0) {
+                const resData = json.data
+                this.form.coverUrl = resData.url
+                this.imageUrl = resData.url
+              } else {
+                this.$notify(
+                  {
+                    title: '提示',
+                    message: '视频封面上传失败,请重试!' + json.msg,
+                    type: 'warning',
+                    duration: 3000
+                  }
+                )
+              }
+            })
+            .catch(e => {
+              return null
+            })
+        }
+      }, 1000) // 1000毫秒,就是截取第一秒,2000毫秒就是截取第2秒,视频1秒通常24帧,也可以换算成截取第几帧。
+      // 防止拖动进度条的时候重复触发
+      // videoElem.removeEventListener('canplay', arguments.callee)
+    },
+    /***********************************************************************/
+    setTitle(title) {
+      if (title.length > 50) {
+        this.form.title = title.substring(0, 50)
+        this.form.description = title
+      } else {
+        this.form.title = title
+      }
+    },
+    getVideoCategory() {
+      videoCategory()
+        .then(res => {
+          if (res.code === 0) {
+            for (let i = 0; i < res.data.length; i++) {
+              const name = res.data[i].name
+              //this.category.push(name)
+              this.categoryMap.Set(name, res.data[i])
+            }
+          } else {
+            this.$notify(
+              {
+                title: '提示',
+                message: res.msg,
+                type: 'warning',
+                duration: 3000
+              }
+            )
+          }
+        }).catch(error => {
+          this.$notify(
+            {
+              title: '提示',
+              message: error.message,
+              type: 'error',
+              duration: 3000
+            }
+          )
+        })
+    },
+    getCategory(name) {
+      // 重置子分区,清除前一次选择分区时留下的缓存
+      this.childCategory = []
+      this.currentCategory = this.categoryMap.Get(name)
+      this.form.categoryId = this.currentCategory.id
+
+      const c = this.currentCategory.children
+      if (c) {
+        for (let i = 0; i < c.length; i++) {
+          this.childCategory.push(c[i].name)
+        }
+      }
+    },
+    getChildCategory(name) {
+      const c = this.currentCategory.children
+      for (let i = 0; i < c.length; i++) {
+        if (c[i].name === name) {
+          this.form.categoryId = c[i].id
+        }
+      }
+    },
+    onReturnVideo() {
+      this.$router.push('/post/video')
+    },
+    onUpdateVideoFile() {
+      console.log('更新视频文件')
+    },
+    onUpdateVideoCover() {
+      console.log('更新视频封面')
+    },
+    onUpdateVideoInfo() {
+      console.log('更新视频信息')
+    },
+    onUpdateVideoScope() {
+      console.log('更新视频作用域')
+    }
+  }
+}
+</script>
+
+<style>
+/*处于手机屏幕时*/
+@media screen and (max-width: 768px){
+  .movie-list {
+    padding-top: 8px;
+    padding-left: 0.5%;
+    padding-right: 0.5%;
+  }
+
+  .coverImg {
+    height: 120px !important;
+  }
+}
+
+.movie-list {
+  padding-top: 15px;
+  padding-left: 6%;
+  padding-right: 6%;
+}
+
+.uploader-example {
+  width: 500px;
+  padding: 15px;
+  margin: 40px auto 0;
+  font-size: 12px;
+  box-shadow: 0 0 10px rgba(0, 0, 0, .4);
+}
+.uploader-example .uploader-btn {
+  margin-right: 4px;
+}
+.uploader-example .uploader-list {
+  max-height: 440px;
+  overflow: auto;
+  overflow-x: hidden;
+  overflow-y: auto;
+}
+
+.avatar-uploader .el-upload {
+  border: 1px dashed #d9d9d9;
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+}
+.avatar-uploader .el-upload:hover {
+  border-color: #409EFF;
+}
+.avatar-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 320px;
+  height: 240px;
+  line-height: 178px;
+  text-align: center;
+}
+.avatar {
+  width: 320px;
+  height: 240px;
+  display: block;
+}
+</style>

+ 13 - 7
src/components/upload/PublishImage.vue

@@ -27,8 +27,8 @@
           />
         </el-row>
         <el-form ref="form" :model="form" label-width="80px">
-          <el-form-item label="标题">
-            <el-input v-model="form.title" style="width: 70%; padding-right: 2px" placeholder="标题不能超过 50 个字符" />
+          <el-form-item label="相册名">
+            <el-input v-model="form.albumName" style="width: 70%; padding-right: 2px" placeholder="相册名不能超过 50 个字符" />
           </el-form-item>
           <el-form-item label="相册">
             <el-select v-model="form.album" placeholder="选择相册">
@@ -54,6 +54,8 @@ import 'filepond-plugin-image-preview/dist/filepond-plugin-image-preview.min.css
 import FilePondPluginFileValidateType from 'filepond-plugin-file-validate-type'
 import FilePondPluginFileValidateSize from 'filepond-plugin-file-validate-size'
 
+import { submitAlbum } from '@/api/image'
+
 const FilePond = VueFilePond(
   FilePondPluginFileValidateType,
   FilePondPluginImagePreview,
@@ -95,9 +97,7 @@ export default {
       },
       imageList: [],
       form: {
-        title: null,
-        album: null,
-        imageIds: [],
+        albumName: null
       }
     }
   },
@@ -134,8 +134,14 @@ export default {
       }*/
     },
     onSubmit() {
-      console.log(this.form)
-      console.log(imgFileIds)
+      this.form.imageFileIds = imgFileIds
+      submitAlbum(this.form).then(res => {
+        if (res.code === 0) {
+          this.$router.push('/post/image')
+        } else {
+
+        }
+      })
     }
   }
 }

+ 31 - 36
src/components/upload/PublishVideo.vue

@@ -58,7 +58,7 @@
           </el-select>
         </el-form-item>
         <el-form-item label="标签">
-          <el-input v-model="form.tags" style="width: 70%; padding-right: 2px" placeholder="多个标签之间使用英文逗号分隔" />
+          <el-input v-model="tagsStr" style="width: 70%; padding-right: 2px" placeholder="多个标签之间使用英文逗号分隔" />
         </el-form-item>
         <el-form-item label="可见范围">
           <el-select v-model="form.scope" placeholder="选择可见范围">
@@ -122,14 +122,14 @@ export default {
       imageList: [],
       imageUrl: '',
       // 提交给后端的数据
+      tagsStr: null,
       form: {
-        videoObjectName: null,
         videoFileId: null,
-        coverFileId: null,
+        coverUrl: null,
         title: null,
         description: null,
         categoryId: 0,
-        tags: null,
+        tags: [],
         scope: null,
         width: 0,
         height: 0,
@@ -276,7 +276,7 @@ export default {
             .then(json => {
               if (json.code === 0) {
                 const resData = json.data
-                this.form.coverFileId = resData.uploadId
+                this.form.coverUrl = resData.url
                 this.imageUrl = resData.url
               } else {
                 this.$notify(
@@ -369,7 +369,7 @@ export default {
         return
       }
 
-      if (!this.form.coverFileId) {
+      if (!this.form.coverUrl) {
         this.$notify(
           {
             title: '提示',
@@ -405,7 +405,8 @@ export default {
         return
       }
 
-      /*if (this.form.tags.length === 0 || this.videoPost.tags.length > 10) {
+       this.form.tags = this.tagsStr.split(",")
+      if (this.form.tags.length === 0 || this.form.tags.length > 10) {
         this.$notify(
           {
             title: '提示',
@@ -415,39 +416,33 @@ export default {
           }
         )
         return
-      }*/
-      submitVideo(this.form)
-        .then(res => {
-          if (res.code === 0) {
-            this.$notify(
-              {
-                title: '提示',
-                message: '投稿成功,等待审核通过后其他人就可以看到你的视频了',
-                type: 'warning',
-                duration: 3000
-              }
-            )
-            this.$router.push('/post/list')
-          } else {
-            this.$notify(
-              {
-                title: '提示',
-                message: res.msg,
-                type: 'warning',
-                duration: 3000
-              }
-            )
-          }
-        }).catch(error => {
-        this.$notify(
-          {
+      }
+
+      submitVideo(this.form).then(res => {
+        if (res.code === 0) {
+          this.$notify({
+            title: '提示',
+            message: '投稿成功,等待审核通过后其他人就可以看到你的视频了',
+            type: 'warning',
+            duration: 3000
+          })
+          this.$router.push('/post/list')
+        } else {
+          this.$notify({
+              title: '提示',
+              message: res.msg,
+              type: 'warning',
+              duration: 3000
+          })
+        }
+      }).catch(error => {
+          this.$notify({
             title: '提示',
             message: error.message,
             type: 'warning',
             duration: 3000
-          }
-        )
-        })
+          })
+      })
     }
   }
 }

+ 12 - 0
src/router/index.js

@@ -23,6 +23,8 @@ const CollectionIndex = () => import('views/user/Collection')
 const HistoryIndex = () => import('views/user/History')
 const PostPublish = () => import('views/post/PostPublish')
 const PostPublishVideo = () => import('views/post/PostPublish')
+const PostEditVideo = () => import('components/upload/EditVideo')
+const PostEditAlbum = () => import('components/upload/EditImage')
 const PostPublishAudio = () => import('views/post/PostPublish')
 const PostPublishImage = () => import('views/post/PostPublish')
 const PostPublishArticle = () => import('views/post/PostPublish')
@@ -193,6 +195,16 @@ const routes = [
     name: 'PostPublishVideo',
     component: PostPublishVideo
   },
+  {
+    path: '/post/edit/video/:videoId',
+    name: 'PostEditVideo',
+    component: PostEditVideo
+  },
+  {
+    path: '/post/edit/album/:albumId',
+    name: 'PostEditAlbum',
+    component: PostEditAlbum
+  },
   {
     path: '/post/publish/audio',
     name: 'PostPublishAudio',

+ 73 - 2
src/views/post/PostAnalysis.vue

@@ -14,13 +14,67 @@
         </el-menu>
       </el-col>
       <el-col :md="20">
-        <span>稿件数据分析</span>
+        <el-table
+          :data="dataList"
+          style="width: 100%"
+        >
+          <el-table-column
+            type="index">
+          </el-table-column>
+          <el-table-column
+            prop="coverUrl"
+            label="视频封面"
+            width="150">
+            <template   slot-scope="scope">
+              <el-image :src="scope.row.coverUrl" min-width="40" height="30" />
+            </template>
+          </el-table-column>
+          <el-table-column
+            prop="pubDate"
+            label="发布时间">
+          </el-table-column>
+          <el-table-column
+            prop="videoId"
+            label="视频 ID"
+            width="180">
+          </el-table-column>
+          <el-table-column
+            prop="title"
+            label="标题"
+            width="180">
+          </el-table-column>
+          <el-table-column
+            prop="viewCount"
+            label="播放量">
+          </el-table-column>
+          <el-table-column
+            prop="commentCount"
+            label="评论量">
+          </el-table-column>
+          <el-table-column
+            prop="commentCount"
+            label="收藏量">
+          </el-table-column>
+          <el-table-column label="操作">
+            <template slot-scope="scope">
+              <el-button
+                size="mini"
+                @click="handleEdit(scope.$index, scope.row)">编辑</el-button>
+              <el-button
+                size="mini"
+                type="danger"
+                @click="handleDelete(scope.$index, scope.row)">删除</el-button>
+            </template>
+          </el-table-column>
+        </el-table>
       </el-col>
     </el-row>
   </div>
 </template>
 
 <script>
+import { userVideoList } from "@/api/video";
+
 export default {
   name: 'PostAnalysis',
   data() {
@@ -29,10 +83,27 @@ export default {
         { path: '/post/publish', name: '发布', icon: 'el-icon-upload' },
         { path: '/post/list', name: '稿件', icon: 'el-icon-files' },
         { path: '/post/analysis', name: '数据', icon: 'el-icon-data-analysis' }
-      ]
+      ],
+      userId: 10001,
+      dataList: []
     }
   },
   created() {
+    document.title = "数据分析"
+
+    userVideoList(1, this.userId, 1).then(res => {
+      if (res.code === 0) {
+        const resData = res.data.list
+        if (resData.length !== 0) {
+          this.showEmpty = false
+          for (const item of resData) {
+            this.dataList.push(item)
+          }
+        } else {
+          this.showEmpty = true
+        }
+      }
+    })
   },
   watch: {
     $route(){

+ 215 - 12
src/views/post/PostList.vue

@@ -16,20 +16,161 @@
       <el-col :md="20">
         <el-tabs v-model="activeName" @tab-click='tabClick'>
           <el-tab-pane label="视频" name="video">
-            <span>
-              <h4>视频稿件</h4>
-            </span>
+            <el-row :md="6" :sm="12" :xs="12">
+              <el-table
+                :data="dataList"
+                style="width: 100%"
+              >
+                <el-table-column
+                  type="index">
+                </el-table-column>
+                <el-table-column
+                  prop="coverUrl"
+                  label="视频封面"
+                  width="150">
+                  <template   slot-scope="scope">
+                    <el-image :src="scope.row.coverUrl" min-width="40" height="30" />
+                  </template>
+                </el-table-column>
+                <el-table-column
+                  prop="pubDate"
+                  label="发布时间">
+                </el-table-column>
+                <el-table-column
+                  prop="horizontal"
+                  label="横屏">
+                  <template slot-scope="scope">
+                    <el-tag v-if="scope.row.horizontal" :type="'success'" disable-transitions>
+                      横屏
+                    </el-tag>
+                    <el-tag v-else :type="'warning'" disable-transitions>
+                      竖屏
+                    </el-tag>
+                  </template>
+                </el-table-column>
+                <el-table-column
+                  prop="title"
+                  label="标题"
+                  width="180">
+                </el-table-column>
+                <el-table-column
+                  prop="description"
+                  label="描述">
+                </el-table-column>
+                <el-table-column
+                  prop="scope"
+                  label="审核状态">
+                  <template slot-scope="scope">
+                    <el-tag v-if="scope.row.viewCount === 1" :type="'success'" disable-transitions>
+                      {{scope.row.viewCount}}
+                    </el-tag>
+                    <el-tag v-else-if="scope.row.viewCount === 2" :type="'warning'" disable-transitions>
+                      {{scope.row.viewCount}}
+                    </el-tag>
+                    <el-tag v-else :type="'danger'" disable-transitions>
+                      {{scope.row.viewCount}}
+                    </el-tag>
+                  </template>
+                </el-table-column>
+                <el-table-column
+                  prop="scope"
+                  label="可见范围">
+                  <template slot-scope="scope">
+                    <el-tag v-if="scope.row.viewCount === 1" disable-transitions>
+                      全部可见
+                    </el-tag>
+                    <el-tag v-else-if="scope.row.viewCount === 2" :type="'success'" disable-transitions>
+                      VIP 可见
+                    </el-tag>
+                    <el-tag v-else-if="scope.row.viewCount === 3" :type="'warning'" disable-transitions>
+                      验证码可见
+                    </el-tag>
+                    <el-tag v-else :type="'danger'" disable-transitions>
+                      本人可见
+                    </el-tag>
+                  </template>
+                </el-table-column>
+                <el-table-column label="操作">
+                  <template slot-scope="scope">
+                    <el-button
+                      size="mini"
+                      @click="handleEdit(scope.$index, scope.row)">编辑</el-button>
+                    <el-button
+                      size="mini"
+                      type="danger"
+                      @click="handleDelete(scope.$index, scope.row)">删除</el-button>
+                  </template>
+                </el-table-column>
+              </el-table>
+            </el-row>
+          </el-tab-pane>
+          <el-tab-pane label="图片" name="image">
+            <el-row :md="6" :sm="12" :xs="12">
+              <el-table
+                :data="dataList"
+                style="width: 100%"
+              >
+                <el-table-column
+                  type="index">
+                </el-table-column>
+                <el-table-column
+                  prop="coverUrl"
+                  label="相册封面"
+                  width="150">
+                  <template   slot-scope="scope">
+                    <el-image :src="scope.row.coverUrl" min-width="40" height="30" />
+                  </template>
+                </el-table-column>
+                <el-table-column
+                  prop="pubDate"
+                  label="发布时间">
+                </el-table-column>
+                <el-table-column
+                  prop="albumName"
+                  label="相册名字"
+                  width="180">
+                </el-table-column>
+                <el-table-column
+                  prop="total"
+                  label="图片数量">
+                </el-table-column>
+                <el-table-column
+                  prop="scope"
+                  label="可见范围">
+                  <template slot-scope="scope">
+                    <el-tag v-if="scope.row.viewCount === 1" disable-transitions>
+                      全部可见
+                    </el-tag>
+                    <el-tag v-else-if="scope.row.viewCount === 2" :type="'success'" disable-transitions>
+                      VIP 可见
+                    </el-tag>
+                    <el-tag v-else-if="scope.row.viewCount === 3" :type="'warning'" disable-transitions>
+                      验证码可见
+                    </el-tag>
+                    <el-tag v-else :type="'danger'" disable-transitions>
+                      本人可见
+                    </el-tag>
+                  </template>
+                </el-table-column>
+                <el-table-column label="操作">
+                  <template slot-scope="scope">
+                    <el-button
+                      size="mini"
+                      @click="handleEditImage(scope.$index, scope.row)">编辑</el-button>
+                    <el-button
+                      size="mini"
+                      type="danger"
+                      @click="handleDeleteImage(scope.$index, scope.row)">删除</el-button>
+                  </template>
+                </el-table-column>
+              </el-table>
+            </el-row>
           </el-tab-pane>
           <el-tab-pane label="音频" name="audio">
             <span>
               <h4>音频稿件</h4>
             </span>
           </el-tab-pane>
-          <el-tab-pane label="图片" name="image">
-            <span>
-              <h4>图片稿件</h4>
-            </span>
-          </el-tab-pane>
           <el-tab-pane label="文章" name="article">
             <span>
               <h4>文章稿件</h4>
@@ -42,11 +183,14 @@
 </template>
 
 <script>
-import PublishVideo from '@/components/upload/PublishVideo'
+import ImageAlbumCard from '@/components/card/ImageAlbumCard'
+
+import {getUserAlbums} from "@/api/image";
+import { userVideoList } from "@/api/video";
 
 export default {
-  name: 'Publish',
-  components: { PublishVideo},
+  name: 'PostList',
+  components: { ImageAlbumCard },
   data() {
     return {
       navList: [
@@ -54,10 +198,14 @@ export default {
         { path: '/post/list', name: '稿件', icon: 'el-icon-files' },
         { path: '/post/analysis', name: '数据', icon: 'el-icon-data-analysis' }
       ],
-      activeName: 'video'
+      activeName: 'video',
+      userId: 10001,
+      dataList: []
     }
   },
   created() {
+    document.title = "稿件列表"
+
     const path = this.$route.path
     if (path.endsWith("video")) {
       this.activeName = 'video'
@@ -72,6 +220,8 @@ export default {
       this.activeName = 'article'
       document.title = '文章稿件'
     }
+
+    this.getData()
   },
   watch: {
     $route(){
@@ -79,6 +229,22 @@ export default {
     }
   },
   methods: {
+    handleEdit(index, row) {
+      console.log(row.videoId);
+      const path = '/post/edit/video/' + row.videoId
+      this.$router.push(path)
+    },
+    handleDelete(index, row) {
+      console.log(row.videoId);
+    },
+    handleEditImage(index, row) {
+      console.log(row.videoId);
+      const path = '/post/edit/album/' + row.albumId
+      this.$router.push(path)
+    },
+    handleDeleteImage(index, row) {
+      console.log(row.videoId);
+    },
     tabClick(tab) {
       this.activeName = tab.name
       if (this.activeName === 'video') {
@@ -99,6 +265,43 @@ export default {
       }
       this.$router.push(path)
     },
+    getData() {
+      if (this.activeName === 'video') {
+        userVideoList(1, this.userId, 1).then(res => {
+          if (res.code === 0) {
+            const resData = res.data.list
+            if (resData.length !== 0) {
+              this.showEmpty = false
+              for (const item of resData) {
+                this.dataList.push(item)
+              }
+            } else {
+              this.showEmpty = true
+            }
+          }
+        })
+      } else if (this.activeName === 'image') {
+        getUserAlbums(this.userId).then(res => {
+          if (res.code === 0) {
+            const resData = res.data
+            if (resData.length !== 0) {
+              this.showEmpty = false
+              for (const item of resData) {
+                this.dataList.push(item)
+              }
+            } else {
+              this.showEmpty = true
+            }
+          }
+        })
+      } else if (this.activeName === 'audio') {
+        this.currentPage = 1
+        this.lastId = 0
+      } else if (this.activeName === 'article') {
+        this.currentPage = 1
+        this.lastId = 0
+      }
+    },
   }
 }
 </script>

+ 4 - 4
src/views/post/PostPublish.vue

@@ -66,10 +66,7 @@ export default {
   },
   created() {
     const path = this.$route.path
-    if (path.endsWith("video")) {
-      this.activeName = 'video'
-      document.title = '发布视频'
-    } else if (path.endsWith("image")) {
+    if (path.endsWith("image")) {
       this.activeName = 'image'
       document.title = '发布图片'
     } else if (path.endsWith("audio")) {
@@ -78,6 +75,9 @@ export default {
     } else if (path.endsWith("article")) {
       this.activeName = 'article'
       document.title = '发布文章'
+    } else {
+      this.activeName = 'video'
+      document.title = '发布视频'
     }
   },
   watch: {