peng
3 天以前 1421a6bd5595378c8266f1ff383a61ecfe5d848f
后台视频发布
4个文件已修改
610 ■■■■■ 已修改文件
manager/src/api/video.js 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
manager/src/api/videoTag.js 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
manager/src/views/video/VideoList.vue 581 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
seller/src/views/goods/goods-seller/goodsOperationSec.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
manager/src/api/video.js
@@ -102,3 +102,12 @@
    method: "POST"
  })
}
// 发布视频
export const publish = (params) => {
  return service({
    url: "/lmk/video/publish",
    method: "POST",
    data: params
  })
}
manager/src/api/videoTag.js
@@ -60,3 +60,19 @@
        data: params
    })
}
// 获取推荐标签
export const recommend = (params) => {
  return service({
    url: "/lmk/video-tag/recommend",
    method: "GET",
    params: params
  })
}
// 查询商品
export const videoGoodsEsPage = (params) => {
  return service({
    url: "/lmk/video-tag/video/es",
    method: "GET",
    params: params
  })
}
manager/src/views/video/VideoList.vue
@@ -29,7 +29,7 @@
            @on-change="handleSearch"
            style="width: 160px"
          >
            <Option v-for="tag in tagList" :key="tag.id" :value="tag.id">{{tag.tagName}}</Option>
            <Option v-for="tag in tagList" :key="tag.id" :value="tag.id">{{ tag.tagName }}</Option>
          </Select>
        </Form-item>
        <Form-item label="视频状态" prop="status">
@@ -51,14 +51,194 @@
          type="primary"
          icon="ios-search"
          class="search-btn"
        >搜索</Button
        >搜索
        </Button
        >
      </Form>
      <Row class="operation padding-row">
        <Button @click="recreateEsIndex" type="primary">重新构建es索引</Button>
        <Button @click="openUploadVideo" type="primary" icon="md-arrow-up"> 上传视频</Button>
      </Row>
      <Modal
        v-model="upLoadVideoShow"
        :title="uploadVideoForm.id?'编辑主页视频':'上传主页视频'"
        width="800"
        :mask-closable="false"
      >
        <Form
          ref="searchForm"
          @keydown.enter.native="handleSearch"
          :model="uploadVideoForm"
          inline
        >
          <Row :gutter="24" class="operation padding-row" style="width: 100%;">
            <Col span="12">
              <FormItem label="标题:" :label-width="80">
                <Input v-model="uploadVideoForm.title" placeholder="请输入标题"></Input>
              </FormItem>
            </Col>
            <Col span="12">
              <FormItem label="上传类型:" :label-width="80" prpo="videoContentType">
                <Select v-model="uploadVideoForm.videoContentType" style="width:200px">
                  <Option value="img">图片</Option>
                  <Option value="video">视频</Option>
                </Select>
              </FormItem>
            </Col>
          </Row>
          <Row>
            <Col span="12" v-if="!uploadVideoForm.videoFileKey&&showVideoFlag">
              <FormItem :label-width="80" label="上传视频" prop="videoFileKey">
                <Upload
                  :multiple="true"
                  :before-upload="upLoadVideo"
                  accept="video/*"
                  action=""
                >
                  <Button icon="ios-cloud-upload-outline">选择视频</Button>
                </Upload>
                <Progress :percent="videoProgress" v-if="showVideoProgress" status="active"/>
              </FormItem>
            </Col>
            <Col span="12" v-else-if="uploadVideoForm.videoFileKey">
              <FormItem :labelWidth="80" label="视频">
                <video style="width: 150px;height: 150px"
                       controls
                       @loadedmetadata="getVideoDuration"
                       :poster="uploadVideoForm.showCoverUrl"
                       :autoplay="false"
                       id="remoteVideo" :src="uploadVideoForm.showVideoUrl"
                       ref="videoInfo"
                ></video>
              </FormItem>
            </Col>
          </Row>
          <Row :gutter="24">
            <Col span="12" v-if="uploadVideoForm.videoFileKey">
              <FormItem :labelWidth="80">
                <Button @click="reloadVideo" type="primary">重新上传视频</Button>
              </FormItem>
            </Col>
          </Row>
          <Row :gutter="24" v-if="uploadVideoForm.videoImgs&&showImgFlag">
            <Col span="12">
              <FormItem :labelWidth="80" label="上传图片">
                <template>
                  <div class="demo-upload-list" v-for="item in uploadVideoForm.showListImages" :key="item">
                    <template>
                      <img :src="item">
                      <div class="demo-upload-list-cover">
                        <Icon type="ios-eye-outline" @click.native="handleView(item)"></Icon>
                        <Icon type="ios-trash-outline" @click.native="handleRemove(item)"></Icon>
                      </div>
                    </template>
                    <!--                    <template v-else>-->
                    <!--                      <Progress v-if="item.showProgress" :percent="item.percentage" hide-info></Progress>-->
                    <!--                    </template>-->
                  </div>
                  <Upload
                    ref="upload"
                    :show-upload-list="false"
                    :format="['jpg','jpeg','png']"
                    :max-size="2048"
                    :before-upload="upLoadImg"
                    multiple
                    type="drag"
                    action="-"
                    style="display: inline-block;width:58px;">
                    <div style="width: 58px;height:58px;line-height: 58px;">
                      <Icon type="ios-camera" size="20"></Icon>
                    </div>
                  </Upload>
                  <Modal title="图片预览" v-model="visible">
                    <img :src="imgName" v-if="visible" style="width: 100%">
                  </Modal>
                </template>
              </FormItem>
            </Col>
          </Row>
          <Row :gutter="24">
            <Col span="24">
              <FormItem label="标签" :label-width="80" style="width: 100%">
                <Select v-model="chooseTag" filterable multiple allow-create @on-create="createVideoTag">
                  <Option v-for="item in videoTagList" :value="item.tagName" :key="item.id">{{ item.tagName }}</Option>
                </Select>
              </FormItem>
            </Col>
          </Row>
          <Row :gutter="24">
            <Col span="24">
              <FormItem label="选中商品" :label-width="80">
              </FormItem>
            </Col>
          </Row>
          <Row :gutter="24">
            <Col span="12">
              <FormItem label="商品列表" :label-width="80">
                <Input v-model="searchGoodsForm.keyword" style="width:200px" @on-change="searchGoodsList"></Input>
                <div style="height: 400px;overflow: auto;">
                  <div v-for="item in goodsData" :key="item.id" style="display: flex;
                          align-items: center;justify-content: flex-start;border: 1px solid gray;margin-top: 10px;
                          padding: 10px;border-radius: 20px" @click="chooseGoods(item.id)">
                    <div>
                      <img :src="endpoint+'/'+item.thumbnail" style="width: 80px;height: 80px">
                    </div>
                    <div style="display: flex;flex-direction: column;margin-left: 20px">
                      <div style="font-size: 1.5em;font-weight: bold">{{ item.goodsName }}</div>
                      <div style="color: #ff6f6f">
                        ¥{{ item.price }}
                      </div>
                    </div>
                  </div>
                </div>
                <Page
                  :current="searchGoodsForm.pageNumber"
                  :total="goodsTotal"
                  :page-size="searchGoodsForm.pageSize"
                  @on-change="goodsChangePage"
                  @on-page-size-change="goodsChangePageSize"
                  :page-size-opts="[10, 20, 50]"
                  size="small"
                  show-total
                  show-elevator
                  show-sizer
                ></Page>
              </FormItem>
            </Col>
            <Col span="12">
              <FormItem label="选中商品" :label-width="80">
                <div style="height: 400px;overflow: auto;">
                  <div v-for="(item,index) in uploadVideoForm.goodsList" :key="item.id" style="display: flex;
                          align-items: center;justify-content: flex-start;border: 1px solid gray;margin-top: 10px;
                          padding: 10px;border-radius: 20px">
                    <div>
                      <img :src="endpoint+'/'+item.thumbnail" style="width: 80px;height: 80px">
                    </div>
                    <div style="display: flex;flex-direction: column;margin-left: 20px">
                      <div style="font-size: 1.5em;font-weight: bold">{{ item.goodsName }}</div>
                      <div style="color: #ff6f6f;display: flex;align-content: center;justify-content: flex-start">
                        <div> ¥{{ item.price }}</div>
                        <div style="margin-left: 10px">
                          <InputNumber v-model="item.goodsNum" :min="0" :max="99" controls-outside @on-change="changeGoodsNum(item.goodsSkuId,index,item.goodsNum)"
                                       style="vertical-align: center;width: 100px"></InputNumber>
                        </div>
                      </div>
                    </div>
                  </div>
                </div>
              </FormItem>
            </Col>
          </Row>
        </Form>
        <div slot="footer">
          <Button type="text" @click="closeVideoUpload">关闭</Button>
          <Button type="primary" @click="submitVideoUpload">确认</Button>
        </div>
      </Modal>
      <Modal
        v-model="playVideoShow"
        :title="playVideoTitle"
@@ -88,20 +268,20 @@
          :rules="auditingRule"
        >
          <Form-item label="标题:">
            <div>{{detail.title}}</div>
            <div>{{ detail.title }}</div>
          </Form-item>
          <Form-item label="标签:">
            <div style="display: flex;flex-wrap: wrap">
              <div v-for="(tag, index) in detail.tagList" :key="'tag' + index" style="margin-right: 5px">
                <Tag color="red">{{tag.tagName}}</Tag>
                <Tag color="red">{{ tag.tagName }}</Tag>
              </div>
            </div>
          </Form-item>
          <Form-item v-if="detail.videoContentType === 'video'" label="视频时长:" :label-width="72">
            <div>{{formatSeconds(detail.videoDuration)}}</div>
            <div>{{ formatSeconds(detail.videoDuration) }}</div>
          </Form-item>
          <Form-item v-if="detail.videoContentType === 'img'" label="图片张数:" :label-width="72">
            <div>{{detail.imgs.length}}</div>
            <div>{{ detail.imgs.length }}</div>
          </Form-item>
          <Form-item v-if="detail.videoContentType === 'video'" class="video-warp" :label-width="0">
            <Row>
@@ -182,7 +362,7 @@
      >
        <Form :model="videoDownForm" :rules="videoDownRule" ref="videoDownForm">
          <FormItem label="下架原因:" :labelWidth="100" prop="reason">
            <editor ref="editor" @input="getReason" />
            <editor ref="editor" @input="getReason"/>
          </FormItem>
        </Form>
        <div slot="footer">
@@ -203,25 +383,33 @@
      >
        <template slot-scope="{ row, index }" slot="tagList">
          <div v-for="(tag, index) in row.tagList" :key="'tag' + index" style="margin-top: 5px">
            <Tag color="red">{{tag.tagName}}</Tag>
            <Tag color="red">{{ tag.tagName }}</Tag>
          </div>
        </template>
        <template slot-scope="{ row, index }" slot="videoFileKey">
          <div v-if="row.videoContentType === 'video'" class="play-text" @click="playVideo(row.videoFileKey, row.title)">点击播放</div>
          <div v-if="row.videoContentType === 'video'" class="play-text"
               @click="playVideo(row.videoFileKey, row.title)">点击播放
          </div>
        </template>
        <template slot-scope="{ row, index }" slot="videoDuration">
          <div>{{formatSeconds(row.videoDuration)}}</div>
          <div>{{ formatSeconds(row.videoDuration) }}</div>
        </template>
        <template slot-scope="{ row, index }" slot="recommend">
          <i-switch v-model="row.recommend" :before-change="() => handleBeforeChange(row)" true-color="#13ce66"/>
        </template>
        <template slot-scope="{ row, index }" slot="status">
          {{transStatus(row.status)}}
          {{ transStatus(row.status) }}
        </template>
        <template slot-scope="{ row, index }" slot="action">
          <Button type="primary" size="small" style="margin-right: 5px" v-if="row.status === '99'" @click="openAuditing(row)">审核</Button>
          <Button type="error" size="small" style="margin-right: 5px" v-if="row.status === '1'" @click="openVideoDown(row)">下架</Button>
          <Button type="success" size="small" style="margin-right: 5px" v-else-if="row.status === '0'" @click="videoUp(row)">上架</Button>
          <Button type="primary" size="small" style="margin-right: 5px" v-if="row.status === '99'"
                  @click="openAuditing(row)">审核
          </Button>
          <Button type="error" size="small" style="margin-right: 5px" v-if="row.status === '1'"
                  @click="openVideoDown(row)">下架
          </Button>
          <Button type="success" size="small" style="margin-right: 5px" v-else-if="row.status === '0'"
                  @click="videoUp(row)">上架
          </Button>
        </template>
      </Table>
@@ -244,16 +432,81 @@
</template>
<script>
import {getVideos, recommendSet, getVideoById, auditingVideo, up, down, recreateIndex} from "@/api/video";
import {getVideoTagList} from "@/api/videoTag";
import {getFilePreview} from "@/api/file";
import {getVideos, recommendSet, getVideoById, auditingVideo, up, down, recreateIndex,publish} from "@/api/video";
import {getVideoTagList, recommend, videoGoodsEsPage} from "@/api/videoTag";
import {getFilePreview, getSts} from "@/api/file";
import Editor from '@/components/editor/index.vue'
import GoodsExpandRow from '@/views/video/GoodsExpandRow'
import COS from "cos-js-sdk-v5";
import {getFileKey} from "@/utils/file";
import vuedraggable from "vuedraggable";
export default {
  name: "VideoList",
  components: {Editor,GoodsExpandRow},
  components: {vuedraggable, Editor, GoodsExpandRow},
  watch: {
    'uploadVideoForm.videoContentType'(newValue, oldValue) {
      if (newValue === 'video') {
        this.showVideoFlag = true;
        this.showImgFlag = false;
        this.uploadVideoForm.videoImgs = []
        this.uploadVideoForm.showListImages = []
      } else {
        this.uploadVideoForm.videoFileKey = '';
        this.showVideoFlag = false;
        this.showImgFlag = true;
        this.videoProgress = 0;
      }
    },
    chooseTag(newValue, oldValue) {
      this.uploadVideoForm.tags = newValue.map(item => {
        const findTag = this.videoTagList.find(tagItem => {
          return tagItem.tagName === item
        })
        if (findTag) {
          return {
            id: findTag.id,
            tagName: findTag.tagName
          }
        } else {
          return {
            id: "",
            tagName: item,
          }
        }
      })
      console.log('------------------------------this.uploadVideoForm.tags>', this.uploadVideoForm.tags)
    }
  },
  data() {
    return {
      endpoint: '',
      searchGoods: '',
      videoTagList: [],
      chooseTag: '',
      videoTag: '',
      visible: false,
      imgName: '',
      showVideoFlag: true,
      showImgFlag: false,
      showVideoProgress: false,
      videoProgress: 0,
      upLoadVideoShow: false,
      uploadVideoForm: {
        id: '',
        title: '',
        cover: "",
        videoFileKey: "",
        videoDuration: 0,
        videoFit: "cover",
        videoContentType: 'video',
        videoImgs: [],
        showListImages: [],
        tags: [],
        fileInfo: {},
        goodsList: []
      },
      videoDownForm: {
        id: '',
        reason: ''
@@ -313,6 +566,13 @@
        title: '', // 标题
        tagList: [], // 标签
        status: '99'
      },
      searchGoodsForm: {
        // 搜索框初始化对象
        pageNumber: 1, // 当前页数
        pageSize: 10, // 页面大小
        keyword: '',
        searchFromSelfStore: false
      },
      tagList: [], // 标签列表
      columns: [
@@ -408,8 +668,10 @@
          width: 200,
        },
      ],
      goodsData: [],
      data: [], // 表单数据
      total: 0, // 表单数据总数
      goodsTotal: 0, // 表单数据总数
      selectCount: 0, // 已选数量
      selectList: [], // 已选数据列表
    }
@@ -419,6 +681,213 @@
    this.getTags('')
  },
  methods: {
    //todo 保留后续可能会使用
    changeGoodsNum(id,index,goodsNum){
      console.log('-------------------->',id,index,goodsNum)
    },
    chooseGoods(id) {
      const goods = this.goodsData.find(item => {
        return item.id === id;
      })
      const existingItem = this.uploadVideoForm.goodsList.find(item => item.goodsSkuId === id);
      if (existingItem) {
        existingItem.goodsNum = existingItem.goodsNum + 1;
      } else {
        this.uploadVideoForm.goodsList.push({
          goodsId: goods.goodsId,
          goodsSkuId: goods.id,
          goodsNum: 1,
          goodsName: goods.goodsName,
          thumbnail: goods.thumbnail,
          price: goods.price,
        })
      }
      // this.uploadVideoForm.goodsList.forEach(item => {
      //   if (item.goodsSkuId === id) {
      //     item.goodsNum = item.goodsNum+1;
      //   }
      // })
      console.log('------------------------>', this.uploadVideoForm.goodsList)
    },
    searchGoodsList() {
      this.searchGoodsForm.pageNumber = 1;
      this.getGoodsDataList();
    },
    closeVideoUpload() {
      this.upLoadVideoShow = false;
    },
    submitVideoUpload() {
      this.uploadVideoForm.goodsList =  this.uploadVideoForm.goodsList.filter(item => {
        return item.goodsNum >0;
      })
      publish(this.uploadVideoForm).then(response => {
        if (response.code == 200) {
          this.$Message.success("视频发布成功");
          this.upLoadVideoShow = false;
          this.getDataList();
        }
      }).then(error=>{
        this.$Message.success(error);
      })
    },
    //todo 后续可能会使用预留
    createVideoTag(e) {
    },
    handleRemove(file) {
      const fileList2 = this.uploadVideoForm.showListImages;
      this.uploadVideoForm.videoImgs.splice(fileList2.indexOf(file), 1);
      this.uploadVideoForm.showListImages.splice(fileList2.indexOf(file), 1);
    },
    handleView(name) {
      this.imgName = name;
      this.visible = true;
    },
    async upLoadImg(file) {
      if (this.uploadVideoForm.videoImgs >= 5) {
        this.$Message.error("图片上传不能超过5个");
        return;
      }
      try {
        // this.upLoadVideoLoading = true;
        // 获取文件上传临时密钥
        const sts = await getSts();
        const cos = new COS({
          getAuthorization: async function (options, callback) {
            callback({
              TmpSecretId: sts.data.tmpSecretId,
              TmpSecretKey: sts.data.tmpSecretKey,
              SecurityToken: sts.data.sessionToken,
              // 建议返回服务器时间作为签名的开始时间,避免客户端本地时间偏差过大导致签名错误
              StartTime: sts.data.stsStartTime, // 时间戳,单位秒,如:1580000000
              ExpiredTime: sts.data.stsEndTime,// 时间戳,单位秒,如:1580000000
              ScopeLimit: true, // 细粒度控制权限需要设为 true,会限制密钥只在相同请求时重复使用
            });
          }
        })
        const fileKey = getFileKey(file.name)
        const upData = await cos.uploadFile({
          Bucket: sts.data.bucket,
          Region: sts.data.region,
          Key: fileKey,
          Body: file, // 要上传的文件对象。
          SliceSize: 1024 * 1024 * 5,
          onProgress: function (progressData) {
            console.log('上传进度:', progressData);
          },
        });
        console.log("上传成功", upData)
        this.$nextTick(() => {
          this.uploadVideoForm.videoImgs.push(fileKey);
          this.uploadVideoForm.showListImages.push(sts.data.endpoint + "/" + fileKey);
        })
      } catch (e) {
        console.log("上传失败", upData)
        return false;
      } finally {
        // this.upLoadVideoLoading = false;
      }
      return false;
    },
    reloadVideo() {
      this.uploadVideoForm.videoFileKey = '';
      this.uploadVideoForm.showVideoUrl = '';
    },
    calculateVideoFit(width, height) {
      const videoRatio = width / height;
      // 规则2:竖屏视频(如9:16)
      if (videoRatio < 0.8) return 'cover';
      return 'contain';
    },
    getVideoDuration(e) {
      const duration = this.$refs.videoInfo.duration;
      const videoWidth = this.$refs.videoInfo.videoWidth;
      const videoHeight = this.$refs.videoInfo.videoHeight;
      // 根据宽高比选择视频填充模式
      const fitType = this.calculateVideoFit(videoWidth, videoHeight)
      this.uploadVideoForm.videoFit = fitType
      console.log('------视频信息3------------>', videoWidth, videoHeight, fitType)
      this.uploadVideoForm.videoDuration = Math.floor(duration);
    },
    async upLoadVideo(file) {
      try {
        this.$nextTick(() => {
          this.showVideoProgress = true;
        })
        // 获取文件上传临时密钥
        const sts = await getSts();
        const cos = new COS({
          getAuthorization: async function (options, callback) {
            callback({
              TmpSecretId: sts.data.tmpSecretId,
              TmpSecretKey: sts.data.tmpSecretKey,
              SecurityToken: sts.data.sessionToken,
              // 建议返回服务器时间作为签名的开始时间,避免客户端本地时间偏差过大导致签名错误
              StartTime: sts.data.stsStartTime, // 时间戳,单位秒,如:1580000000
              ExpiredTime: sts.data.stsEndTime,// 时间戳,单位秒,如:1580000000
              ScopeLimit: true, // 细粒度控制权限需要设为 true,会限制密钥只在相同请求时重复使用
            });
          }
        })
        const fileKey = getFileKey(file.name)
        const upData = await cos.uploadFile({
          Bucket: sts.data.bucket,
          Region: sts.data.region,
          Key: fileKey,
          Body: file, // 要上传的文件对象。
          SliceSize: 1024 * 1024 * 5,
          onProgress: (progressData) => {
            console.log('上传进度:', progressData);
            this.videoProgress = Math.floor(progressData.percent * 100);
          },
        });
        console.log(this.uploadVideoForm)
        this.$nextTick(() => {
          this.uploadVideoForm.videoFileKey = fileKey;
          this.uploadVideoForm.showVideoUrl = sts.data.endpoint + "/" + fileKey;
        })
        console.log("上传成功", upData)
        const duration = this.$refs.healthVideoInfo.duration;
        console.log('-测试获取时间信息---------------->', duration);
      } catch (e) {
        console.log("上传失败", upData)
      } finally {
        this.$nextTick(() => {
          this.showVideoProgress = false;
        })
      }
      return false;
    },
    openUploadVideo() {
      this.upLoadVideoShow = true;
      this.videoTagList = []
      this.uploadVideoForm = {
        id: '',
        title: '',
        cover: "",
        videoFileKey: "",
        videoDuration: 0,
        videoFit: "cover",
        videoContentType: 'video',
        videoImgs: [],
        showListImages: [],
        tags: [],
        fileInfo: {},
        goodsList: []
      }
      recommend({
        searchType: "HOT"
      }).then(res => {
        this.videoTagList = res.data;
      })
      this.searchGoodsList();
    },
    recreateEsIndex() {
      recreateIndex().then(res => {
        this.$Message.success(res.msg)
@@ -587,6 +1056,25 @@
      this.getDataList();
    },
    // 获取列表数据
    getGoodsDataList() {
      let search = this.searchGoodsForm;
      if (search.pageNumber > 0) {
        search.pageNumber = search.pageNumber - 1;
      }
      videoGoodsEsPage(search).then((res) => {
        console.log(res)
        this.loading = false;
        if (res.code == 200) {
          this.goodsData = res.data;
          getSts().then(res => {
            this.endpoint = res.data.endpoint
          })
          this.goodsTotal = res.total;
        }
      });
      this.total = this.data.length;
    },
    // 获取列表数据
    getDataList() {
      this.loading = true;
      getVideos(this.searchForm).then((res) => {
@@ -624,6 +1112,17 @@
      this.searchForm.pageSize = v;
      this.getDataList();
    },
    // 分页 改变页码
    goodsChangePage(v) {
      this.searchForm.pageNumber = v;
      this.getGoodsDataList();
    },
    // 分页 改变页数
    goodsChangePageSize(v) {
      this.searchForm.pageNumber = 1;
      this.searchForm.pageSize = v;
      this.getGoodsDataList();
    },
  }
}
</script>
@@ -634,22 +1133,68 @@
  text-align: center;
  color: #2d8cf0;
}
.play-text:hover {
  cursor: pointer;
}
.video-warp {
  width: 100%;
  height: 440px;
}
.data-item {
  display: flex;
  align-items: center;
}
.img-warp {
  padding: 10px;
}
.image {
  width: 150px;
  height: 200px;
}
.demo-upload-list {
  display: inline-block;
  width: 60px;
  height: 60px;
  text-align: center;
  line-height: 60px;
  border: 1px solid transparent;
  border-radius: 4px;
  overflow: hidden;
  background: #fff;
  position: relative;
  box-shadow: 0 1px 1px rgba(0, 0, 0, .2);
  margin-right: 4px;
}
.demo-upload-list img {
  width: 100%;
  height: 100%;
}
.demo-upload-list-cover {
  display: none;
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  background: rgba(0, 0, 0, .6);
}
.demo-upload-list:hover .demo-upload-list-cover {
  display: block;
}
.demo-upload-list-cover i {
  color: #fff;
  font-size: 20px;
  cursor: pointer;
  margin: 0 2px;
}
</style>
seller/src/views/goods/goods-seller/goodsOperationSec.vue
@@ -401,7 +401,7 @@
            </div>
            <FormItem class="form-item-view-el" label="PC商品描述" prop="intro" style="width: 100%">
              <editor
                :show-upload="false"
                :show-upload="true"
                ref="editor"
                v-model="baseInfoForm.intro"
                height="800px"
@@ -415,7 +415,7 @@
            <FormItem class="form-item-view-el" label="移动端描述" prop="skuList" style="width: 100%">
              <editor
                :show-upload="false"
                :show-upload="true"
                ref="introEditor"
                v-model="baseInfoForm.mobileIntro"
                height="800px"