浏览代码

AI素材搜索&热词管理

lushixing 4 月之前
父节点
当前提交
897b3a2c35

+ 11 - 0
src/api/AIAssetSearch.js

@@ -0,0 +1,11 @@
+import request from '@/utils/request'
+
+//列表
+export function shopConfigInfoList(data) {
+  return request({
+    url: '/productAndVideo/page',
+    method: 'post',
+    data,
+    customApi: 'api'
+  })
+}

+ 2 - 1
src/api/api.js

@@ -1,3 +1,4 @@
 export const api = {
-  fileUrl: process.env.VUE_APP_API + 'file/viUpload'
+  fileUrl: process.env.VUE_APP_API + 'file/viUpload',
+  importExcel: process.env.VUE_APP_API + 'product/importExcel'
 }

+ 38 - 0
src/api/trendingWordsList.js

@@ -0,0 +1,38 @@
+import request from '@/utils/request'
+
+//列表
+export function hotWordList(params) {
+  return request({
+    url: '/hotWord/page',
+    method: 'get',
+    params,
+    customApi: 'api'
+  })
+}
+// 删除
+export function deteleHotWord(data) {
+  return request({
+    url: '/hotWord/delete',
+    method: 'post',
+    data,
+    customApi: 'api'
+  })
+}
+// add
+export function addHotWord(data) {
+  return request({
+    url: '/hotWord/add',
+    method: 'post',
+    data,
+    customApi: 'api'
+  })
+}
+// 编辑
+export function editHotWord(data) {
+  return request({
+    url: '/hotWord/edit',
+    method: 'post',
+    data,
+    customApi: 'api'
+  })
+}

+ 14 - 7
src/components/ExcelImport/index.vue

@@ -12,8 +12,8 @@
       :show-file-list="false"
       accept=".xlsx,.xls"
     >
-      <el-button type="primary">
-        <i class="el-icon-upload2" /><slot name="upload-text"> 上传Excel文件</slot>
+      <el-button type="primary" :loading="loading">
+        <i class="el-icon-upload2" /><slot name="upload-text">上传Excel文件</slot>
       </el-button>
       <div class="el-upload__tip" slot="tip">只能上传 xlsx/xls 文件,且不超过10MB</div>
     </el-upload>
@@ -50,6 +50,7 @@ export default {
   },
   data() {
     return {
+      loading: false,
       uploadProgress: 0,
       uploadStatus: null
     }
@@ -70,6 +71,7 @@ export default {
       
       this.uploadProgress = 0
       this.uploadStatus = null
+      this.loading = true;
       return true
     },
     
@@ -78,14 +80,16 @@ export default {
     },
     
     handleUploadSuccess(response) {
-      this.uploadStatus = 'success'
-      this.$emit('on-success', response)
+      this.uploadStatus = 'success';
+      this.loading = false;
+      this.$emit('on-success', response);
       setTimeout(() => {
         this.uploadProgress = 0
       }, 2000)
     },
     
     handleUploadError() {
+      this.loading = false;
       this.uploadStatus = 'exception'
       this.$message.error('文件上传失败')
     }
@@ -94,13 +98,16 @@ export default {
 </script>
 
 <style scoped>
-.excel-import {
- text-align: right;
+.excel-uploader {
+  display: flex;
+  align-items: center;
+  gap: 10px;
 }
 
+
 .el-upload__tip {
-  margin-top: 10px;
   color: #909399;
   font-size: 12px;
+  margin: 0;
 }
 </style>

+ 5 - 1
src/permission.js

@@ -55,7 +55,11 @@ router.beforeEach(async (to, from, next) => {
             { routerPath: "/faceSwapVideo/faceSwapVideoIndex" },
             { routerPath: "/faceSwapVideo/faceSwapVideoTool" },
             { routerPath: "/oralVideo" },
-            { routerPath: "/oralVideo/oralVideoIndex" }]
+            { routerPath: "/oralVideo/oralVideoIndex" },
+            { routerPath: "/AIAssetSearch" },
+            { routerPath: "/AIAssetSearch/AIAssetSearchIndex" },
+            { routerPath: "/trendingTermList" },
+            { routerPath: "/trendingTermList/trendingTermListIndex" }]
          
           const accessRoutes = await store.dispatch('permission/generateRoutes', data);
           router.addRoutes(accessRoutes);

+ 5 - 1
src/router/index.js

@@ -39,12 +39,16 @@ import videoCoverManagerRouter from "./modules/videoCoverManager";
 import musicLibraryManager from "./modules/musicLibraryManager";
 import catwalkVideoRouter from "./modules/catwalkVideo";
 import faceSwapVideoRouter from "./modules/faceSwapVideo";
+import AIAssetSearchRouter from "./modules/AIAssetSearch";
+import trendingTermListRouter from "./modules/trendingTermList";
 export const asyncRoutes = [
   oralVideoRouter,
   catwalkVideoRouter,
   faceSwapVideoRouter,
   videoCoverManagerRouter,
-  musicLibraryManager
+  musicLibraryManager,
+  AIAssetSearchRouter,
+  trendingTermListRouter
   // userAuthRouter,
 ];
 

+ 20 - 0
src/router/modules/AIAssetSearch.js

@@ -0,0 +1,20 @@
+/** When your routing table is too long, you can split it into small modules **/
+
+import Layout from "@/layout";
+
+const AIAssetSearchRouter = {
+  path: "/AIAssetSearch",
+  component: Layout,
+  redirect: "/AIAssetSearch/AIAssetSearchIndex",
+  name: "AIAssetSearch",
+  meta: { title: "AI素材搜索管理", icon: "el-icon-s-shop" },
+  children: [
+    {
+      path: "AIAssetSearchIndex",
+      component: () => import("@/views/ai-asset-finder/index"),
+      name: "AIAssetSearchIndex",
+      meta: { title: "AI素材搜索" }
+    }
+  ]
+};
+export default AIAssetSearchRouter;

+ 1 - 1
src/router/modules/catwalkVideo.js

@@ -6,7 +6,7 @@ const catwalkVideoRouter = {
   path: "/catwalkVideo",
   component: Layout,
   redirect: "/catwalkVideo/catwalkVideoIndex",
-  name: "走秀视频管理",
+  name: "catwalkVideo",
   meta: { title: "走秀视频管理", icon: "el-icon-camera-solid" },
   children: [
     {

+ 3 - 3
src/router/modules/faceSwapVideo.js

@@ -6,19 +6,19 @@ const faceSwapVideoRouter = {
   path: "/faceSwapVideo",
   component: Layout,
   redirect: "/face-swap-video/faceSwapVideoIndex",
-  name: "视频换脸管理",
+  name: "faceSwapVideo",
   meta: { title: "视频换脸管理", icon: "el-icon-s-cooperation" },
   children: [
     {
       path: "faceSwapVideoIndex",
       component: () => import("@/views/face-swap-video/index"),
-      name: "视频换脸列表",
+      name: "faceSwapVideoIndex",
       meta: { title: "视频换脸列表" }
     },
     {
       path: "faceSwapVideoTool",
       component: () => import("@/views/face-swap-video/faceSwapVideo"),
-      name: "AI视频换脸",
+      name: "faceSwapVideoTool",
       meta: { title: "AI视频换脸" }
     },
   ]

+ 1 - 1
src/router/modules/musicLibraryManager.js

@@ -6,7 +6,7 @@ const musicLibraryManagerRouter = {
   path: "/musicLibraryManager",
   component: Layout,
   redirect: "/musicLibraryManager/musicLibraryIndex",
-  name: "音乐库管理",
+  name: "musicLibraryManager",
   meta: { title: "音乐库管理", icon: "el-icon-s-claim" },
   children: [
     {

+ 3 - 3
src/router/modules/oralVideo.js

@@ -6,19 +6,19 @@ const oralVideoRouter = {
   path: "/oralVideo",
   component: Layout,
   redirect: "/oralVideo/oralVideoIndex",
-  name: "口播视频管理",
+  name: "oralVideo",
   meta: { title: "口播视频管理", icon: "el-icon-video-camera-solid" },
   children: [
     {
       path: "oralVideoIndex",
       component: () => import("@/views/oral-video/index.vue"),
-      name: "口播视频列表",
+      name: "oralVideoIndex",
       meta: { title: "口播视频列表" }
     },
     {
       path: "product",
       component: () => import("@/views/product/product.vue"),
-      name: "商品列表",
+      name: "oralVideoProduct",
       meta: { title: "商品列表" }
     }
   ]

+ 20 - 0
src/router/modules/trendingTermList.js

@@ -0,0 +1,20 @@
+/** When your routing table is too long, you can split it into small modules **/
+
+import Layout from "@/layout";
+
+const trendingTermListRouter = {
+  path: "/trendingTermList",
+  component: Layout,
+  redirect: "/trendingTermList/trendingTermListIndex",
+  name: "trendingTermList",
+  meta: { title: "热词管理", icon: "el-icon-s-shop" },
+  children: [
+    {
+      path: "trendingTermListIndex",
+      component: () => import("@/views/trending-words-list/index"),
+      name: "trendingTermListIndex",
+      meta: { title: "热词管理列表" }
+    }
+  ]
+};
+export default trendingTermListRouter;

+ 2 - 2
src/router/modules/videoCoverManager.js

@@ -6,12 +6,12 @@ const videoCoverManagerRouter = {
   path: "/videoCoverManager",
   component: Layout,
   redirect: "/videoCoverManager/videoCoverIndex",
-  name: "店铺信息管理",
+  name: "videoCoverManager",
   meta: { title: "店铺信息管理", icon: "el-icon-s-shop" },
   children: [
     {
       path: "videoCoverIndex",
-      component: () => import("@/views/video-cover-manager/index"),
+      component: () => import("@/views/trending-words-list/index"),
       name: "videoCoverIndex",
       meta: { title: "店铺信息列表" }
     }

+ 349 - 0
src/views/ai-asset-finder/index.vue

@@ -0,0 +1,349 @@
+<template>
+  <div class="app-container">
+    <div class="filter-container">
+      <div class="filter-container-lt">
+        <el-form :inline="true" label-position="left" :model="listQuery">
+          <el-form-item>
+            <el-input clearable v-model="listQuery.sku" placeholder="搜索SKU"
+            ></el-input>
+          </el-form-item>
+          <el-form-item>
+            <el-select v-model="listQuery.type" clearable filterable placeholder="全部类型">
+              <el-option
+                v-for="item in typesOptions"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value">
+              </el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" @click="getList()">搜索</el-button>
+          </el-form-item>
+          <el-form-item>
+            <excel-import :upload-url="action" 
+              :headers="{
+                'Authorization': 'Bearer ' + token
+              }"
+              :upload-data="{ type: 'import' }" @on-success="handleImportSuccess">
+              <template slot="upload-text">
+                导入
+              </template>
+            </excel-import>
+          </el-form-item>
+        </el-form>
+      </div>
+    </div>
+    <div class="table-container">
+      <el-table  style="width: 100%" v-loading="listLoading" :key="tableKey" :data="list" row-key="id"
+        stripe border fit highlight-current-row>
+        <el-table-column label="序号" type="index" width="60" align="center" />
+        <el-table-column label="SKU" min-width="100" align="center" prop="sku" />
+        <el-table-column label="商品图" min-width="130" align="center">
+          <template slot-scope="scope">
+            <div class="image-black">
+              <el-image 
+                class="video-img"
+                style="width: 80px;aspect-ratio: 3 / 4;"
+                :src="scope.row.productUrl" 
+                :preview-src-list="[scope.row.productUrl]">
+              </el-image>
+              <i class="el-icon-zoom-in" />
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="商品名" min-width="100" align="center" prop="name" />
+        <el-table-column label="商品分类" min-width="100" align="center" prop="category" />
+        <el-table-column label="商品ID" min-width="100" align="center" prop="productId" />
+        <!-- <el-table-column label="天猫热词" min-width="100" align="center" prop="hotWords" /> -->
+        <el-table-column label="视频" width="350" align="center">
+          <template slot-scope="scope" v-if="scope.row.aiVideoInfoVOList && scope.row.aiVideoInfoVOList.length">
+            <div class="video-black">
+              <ul>
+                <li v-for="(acc, idx) in scope.row.aiVideoInfoVOList" :key="idx">
+                  <div v-if="isVideoFormat(acc.videoUrl)" class="video"
+                    @click="handlePlay(acc.videoUrl)">
+                    <img :src="acc.videoCoverImageUrl" class="video-img" />
+                    <i class="el-icon-video-play" />
+                  </div>
+                  <div class="video" v-else>
+                    <el-image class="video-last-img video" :src="acc.videoUrl"
+                      :preview-src-list="[acc.videoUrl]" :lazy="true"/>
+                    <i class="el-icon-zoom-in" />
+                  </div>
+                  <span class="tags" v-if="acc.type == 1">口播</span>
+                  <span class="tags" v-if="acc.type == 2">走秀</span>
+                  <span class="tags" v-if="acc.type == 3">换脸</span>
+                </li>
+              </ul>
+            </div>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+
+    <!-- 分页 -->
+    <swPage v-if="total > 0" key="2" :listQuery="listQuery" :total="total" pos="btmRight" @retPage="retPage" />
+    <!-- 视频播放 -->
+    <video-player ref="videoPlayer" :video-url="currentVideoUrl" :video-title="currentVideoTitle"
+      @close="handlePlayerClose" />
+    <el-image ref="elImage" style="width: 0; height: 0;" :src="imageUrl" :preview-src-list="[imageUrl]">
+    </el-image>
+  </div>
+</template>
+
+<script>
+import { api } from "@/api/api";
+import waves from "@/directive/waves";
+import swPage from "@/views/common/swPage";
+import { getToken } from '@/utils/auth'
+import { auditStatus } from "@/constants/index";
+import { getValueByKey } from "@/utils/index";
+import { shopConfigInfoList } from "@/api/AIAssetSearch";
+import permission from "@/directive/permission";
+import VideoPlayer from "@/components/VideoPlayer";
+import ExcelImport from "@/components/ExcelImport";
+
+export default {
+  name: "AIAssetSearch",
+  directives: {
+    waves,
+    permission
+  },
+  components: {
+    swPage,
+    VideoPlayer,
+    ExcelImport
+  },
+  data() {
+    return {
+      action: api.importExcel,
+      auditStatus,
+      tableKey: 0,
+      list: [],
+      total: 0,
+      listLoading: false,
+      downloadingRows: {},
+      listQuery: {
+        currentPage: 1,
+        pageSize: 10,
+        sku: null,
+        type: null 
+      },
+      currentVideoUrl: null,
+      currentVideoTitle: null,
+      currentVideo: {},
+      imageUrl: null
+    };
+  },
+  //页面创建的时候执行
+  created() {
+    this.getList();
+  },
+  computed: {
+    token() {
+      return getToken();
+    },
+    typesOptions() {
+      return [
+        {value: 1, label: 'AI口播视频'},
+        {value: 2, label: 'AI走秀视频'},
+        {value: 3, label: 'AI换脸视频'}
+      ]
+    }
+  },
+  methods: {
+    getValueByKey,
+    isVideoFormat(url) {
+      if (!url) return false;
+      const extension = url
+        .toLowerCase()
+        .split(".")
+        .pop();
+      return["mp4", "mov",].includes(extension);
+    },
+    handlePlay(url) {
+      if (!url) {
+        this.$message.error("媒体地址不存在");
+        return;
+      }
+
+      if (this.isVideoFormat(url)) {
+        // 视频播放逻辑
+        this.currentVideoUrl = url;
+        this.currentVideoTitle =  url.split("/").pop();
+        this.$refs.videoPlayer.show();
+      } else if (this.isImageFormat(url)) {
+        // 新增图片格式判断
+        this.$nextTick(() => {
+          this.imageUrl = url;
+          this.$refs.elImage.clickHandler();
+        });
+      } else {
+        this.$message.error("不支持的文件格式");
+      }
+    },
+    handlePlayerClose() {
+      this.currentVideoUrl = "";
+      this.currentVideoTitle = "";
+    },
+    getList() {
+      this.listLoading = true;
+      const params = {}
+      for (const key in this.listQuery) {
+        const value = this.listQuery[key]
+        if (value !== null && value !== '' && value !== undefined) {
+          params[key] = value
+        }
+      }
+      shopConfigInfoList(params).then(res => {
+        if (200 == res.code) {
+          this.total = res.data.total;
+          this.list = res.data.rows;
+        }
+        this.listLoading = false;
+      });
+    },
+    retPage() {
+      //分页
+      this.getList();
+    },
+    handleFilter() {
+      this.listQuery.page = 1;
+      this.getList();
+    },
+    handleImportSuccess(response) {
+      if (response.code == 200) {
+        this.getList();
+      }
+    }
+  }
+};
+</script>
+
+<style rel="stylesheet/scss" lang="scss" scoped>
+@import "@/styles/layout.scss";
+
+.button {
+  .el-button {
+    margin-bottom: 10px;
+
+    &:last-child {
+      margin-bottom: 0;
+    }
+  }
+}
+.video-black {
+  display: flex;
+  justify-content: center;
+  ul {
+    margin: 0;
+    padding: 0;
+    display: flex;
+    gap: 10px;
+  }
+  li {
+    position: relative;
+    list-style: none;
+    width: 80px;
+    aspect-ratio: 3 / 4;
+    height: 100%;
+  }
+  .video {
+    position: relative;
+    display: flex;
+    align-content: center;
+    justify-content: center;
+    cursor: pointer;
+    width: 80px;
+    aspect-ratio: 3/4;
+
+    &:hover {
+      i {
+        opacity: 1;
+        pointer-events: none;
+      }
+
+      .video-img {
+        opacity: 0.6;
+      }
+    }
+
+    &-img {
+      width: 80px;
+      border: 1px solid #eee;
+      object-fit: cover;
+      object-position: top;
+      cursor: pointer;
+    }
+
+    i {
+      position: absolute;
+      top: 50%;
+      left: 50%;
+      transform: translate(-50%,-50%);
+      width: 20px;
+      height: 20px;
+      font-size: 20px;
+      font-weight: bold;
+      color: #fff;
+      opacity: 0;
+      cursor: pointer;
+    }
+  }
+  .tags {
+    position: absolute;
+    bottom: 0;
+    left: 0;
+    width: 100%;
+    background: #ae8877;
+    font-size: 12px;
+    color: #fff;
+    height: auto;
+    display: block;
+  }
+}
+.image-black {
+  position: relative;
+  display: flex;
+  align-content: center;
+  justify-content: center;
+  cursor: pointer;
+
+  &:hover {
+    i {
+      opacity: 1;
+      pointer-events: none;
+    }
+
+    .video-img {
+      opacity: 0.6;
+    }
+  }
+
+  &-img {
+    width: 80px;
+    border: 1px solid #eee;
+    object-fit: cover;
+    object-position: top;
+    cursor: pointer;
+  }
+
+  i {
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%,-50%);
+    width: 20px;
+    height: 20px;
+    font-size: 20px;
+    font-weight: bold;
+    color: #fff;
+    opacity: 0;
+    cursor: pointer;
+  }
+  .tags {
+
+  }
+}
+</style>

+ 4 - 0
src/views/catwalk-video/brandVideoEditor.vue

@@ -518,6 +518,10 @@ export default {
             border: 1px solid #CBD0DC;
             padding: 0 30px;
             color: #54575C;
+
+            &:hover {
+              background: #f8f8f8;
+            }
           }
         }
       }

+ 15 - 3
src/views/catwalk-video/index.vue

@@ -3,6 +3,10 @@
     <div class="filter-container">
       <div class="filter-container-lt">
         <el-form :inline="true" label-position="left" :model="listQuery">
+          <el-form-item>
+            <el-input clearable v-model="listQuery.sku" placeholder="搜索SKU"
+            ></el-input>
+          </el-form-item>
           <el-form-item>
             <el-input clearable v-model="listQuery.videoTitle" placeholder="视频标题"
             ></el-input>
@@ -17,7 +21,7 @@
               </el-option>
             </el-select>
           </el-form-item>
-          <el-button type="primary" @click="getList()">搜索</el-button>
+          <el-button type="primary" @click="handleFilter">搜索</el-button>
         </el-form>
       </div>
     </div>
@@ -212,7 +216,8 @@ export default {
         pageSize: 10,
         videoTitle: null,
         type:2,
-        processStatus: null
+        processStatus: null,
+        sku: ''
       },
       currentVideoUrl: null,
       currentVideoTitle: null,
@@ -230,7 +235,14 @@ export default {
     getValueByKey,
     getList(notLoading) {
       !notLoading && (this.listLoading = true);
-      fetchOralVideoList(this.listQuery).then(res => {
+      const params = {}
+      for (const key in this.listQuery) {
+        const value = this.listQuery[key]
+        if (value !== null && value !== '' && value !== undefined) {
+          params[key] = value
+        }
+      }
+      fetchOralVideoList(params).then(res => {
         if (200 == res.code) {
           this.total = res.data.total;
           this.list = res.data.rows;

+ 21 - 13
src/views/face-swap-video/index.vue

@@ -2,16 +2,17 @@
   <div class="app-container">
     <div class="filter-container">
       <div class="filter-container-lt">
-        <el-input placeholder="视频标题" class="filter-item" style="width: 200px;" clearable
-          v-model="listQuery.videoTitle" />
-        <!-- <el-input
-          placeholder="SKU"
-          class="filter-item"
-          style="width: 200px;"
-          clearable
-          v-model="listQuery.sku"
-        /> -->
-        <el-button v-waves class="filter-btn" type="primary" icon="el-icon-search" @click="handleFilter">搜索</el-button>
+        <el-form :inline="true" label-position="left" :model="listQuery">
+          <el-form-item>
+            <el-input clearable v-model="listQuery.sku" placeholder="搜索SKU"
+            ></el-input>
+          </el-form-item>
+          <el-form-item>
+            <el-input clearable v-model="listQuery.videoTitle" placeholder="视频标题"
+            ></el-input>
+          </el-form-item>
+          <el-button type="primary" @click="handleFilter">搜索</el-button>
+        </el-form>
       </div>
       <!-- <div class="filter-container-rt">
         <excel-import :upload-url="'/api/upload-excel'" :headers="{ token: 'your-token' }"
@@ -189,8 +190,8 @@ export default {
         currentPage: 1,
         pageSize: 10,
         videoTitle: null,
-        type: 3
-        // sku: null,
+        type: 3,
+        sku: null
       },
       currentVideoUrl: null,
       currentVideoTitle: null,
@@ -223,7 +224,14 @@ export default {
     },
     getList() {
       this.listLoading = true;
-      fetchOralVideoList(this.listQuery).then(res => {
+      const params = {}
+      for (const key in this.listQuery) {
+        const value = this.listQuery[key]
+        if (value !== null && value !== '' && value !== undefined) {
+          params[key] = value
+        }
+      }
+      fetchOralVideoList(params).then(res => {
         if (200 == res.code) {
           this.total = res.data.total;
           this.list = res.data.rows;

+ 4 - 0
src/views/music-library-manager/musicLibraryUpdater.vue

@@ -425,6 +425,10 @@ export default {
             border: 1px solid #CBD0DC;
             padding: 0 30px;
             color: #54575C;
+
+            &:hover {
+              background: #f8f8f8;
+            }
           }
         }
       }

+ 21 - 7
src/views/oral-video/index.vue

@@ -2,10 +2,17 @@
   <div class="app-container">
     <div class="filter-container">
       <div class="filter-container-lt">
-        <el-input placeholder="视频标题" class="filter-item" style="width: 200px;" clearable
-          v-model="listQuery.videoTitle" />
-        <!-- <el-input placeholder="SKU" class="filter-item" style="width: 200px;" clearable v-model="listQuery.sku" /> -->
-        <el-button v-waves class="filter-btn" type="primary" icon="el-icon-search" @click="handleFilter">搜索</el-button>
+        <el-form :inline="true" label-position="left" :model="listQuery">
+          <el-form-item>
+            <el-input clearable v-model="listQuery.sku" placeholder="搜索SKU"
+            ></el-input>
+          </el-form-item>
+          <el-form-item>
+            <el-input clearable v-model="listQuery.videoTitle" placeholder="视频标题"
+            ></el-input>
+          </el-form-item>
+          <el-button type="primary" @click="handleFilter">搜索</el-button>
+        </el-form>
       </div>
       <!-- <div class="filter-container-rt">
         <excel-import :upload-url="'/api/upload-excel'" :headers="{ token: 'your-token' }"
@@ -196,8 +203,8 @@ export default {
         currentPage: 1,
         pageSize: 10,
         videoTitle: null,
-        type:1
-        // sku:null
+        type: 1,
+        sku:null
       },
       currentVideoUrl: null,
       currentVideoTitle: null,
@@ -212,7 +219,14 @@ export default {
     getValueByKey,
     getList() {
       this.listLoading = true;
-      fetchOralVideoList(this.listQuery).then(res => {
+      const params = {}
+      for (const key in this.listQuery) {
+        const value = this.listQuery[key]
+        if (value !== null && value !== '' && value !== undefined) {
+          params[key] = value
+        }
+      }
+      fetchOralVideoList(params).then(res => {
         if (200 == res.code) {
           this.total = res.data.total;
           this.list = res.data.rows;

+ 115 - 0
src/views/trending-words-list/components/trendingTermListFormModal.vue

@@ -0,0 +1,115 @@
+<template>
+  <el-dialog :title="(modelType == 'add' ? '添加' : '编辑') + '热词'" width="800px" :visible.sync="dialogVisible">
+    <el-form :model="form" :rules="rules" ref="TrendingTermListForm" label-width="100px">
+      <el-form-item prop="title" label="热词标题:">
+        <el-input placeholder="请输入热词标题" v-model="form.title"></el-input>
+      </el-form-item>
+    </el-form>
+
+    <span slot="footer" class="dialog-footer">
+      <el-button @click="dialogVisible = false">取消</el-button>
+      <el-button type="primary" :loading="comfirmLoading" @click="handleConfirm">确定</el-button>
+    </span>
+  </el-dialog>
+</template>
+
+<script>
+import { addHotWord, editHotWord } from "@/api/trendingWordsList";
+export default {
+  name: "TrendingTermListFormModal",
+  props: {
+  },
+  data() {
+    return {
+      form: {
+        title: ''
+      },
+      modelType: 'add',
+      dialogVisible: false,
+      comfirmLoading: false,
+      editId: '',
+      platformName: '',
+      rules: {
+        title: [
+          { required: true, message: "请输入热词标题", trigger: "blur" }
+        ],
+        platformName: [
+          { required: true, message: "请输入平台名称", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  computed: {
+  },
+  watch: {
+    dialogVisible(val) {
+      if (!val) {
+        this.form = {
+          title: ''
+        }
+        this.modelType =  'add';
+        this.comfirmLoading = false;
+        this.editId = '';
+        this.platformName = '';
+      }
+    }
+  },
+  methods: {
+    show(rows, type) {
+      this.dialogVisible = true;
+      this.comfirmLoading = false;
+      this.modelType = type;
+      if (type == 'edit') {
+        this.editId = rows.id;
+        this.platformName = rows.platformName;
+      }
+      this.$nextTick(() => {
+        this.form = type == 'edit' ? {
+          title: rows.title
+        } : {
+          title: ''
+        }
+        this.$refs.TrendingTermListForm.resetFields()
+      })
+    },
+    handleConfirm() {
+      this.$refs.TrendingTermListForm.validate(valid => {
+        if (valid) {
+          this.comfirmLoading = true;
+          const params = this.form;
+          if (this.modelType == 'add') {
+            addHotWord(params).then(res =>{
+              this.dialogVisible = false;
+              if(res.code == 200){
+                this.$message.success(res.msg || "操作成功");
+                this.$emit("confirm");
+              }
+            }).finally(()=>{
+              this.comfirmLoading = false;
+            })
+          } else {
+            params.id = this.editId;
+            params.platformName = this.platformName;
+            editHotWord(params).then(res =>{
+              this.dialogVisible = false;
+              if(res.code == 200){
+                this.$message.success(res.msg || "操作成功");
+                this.$emit("confirm");
+              }
+            }).finally(()=>{
+              this.comfirmLoading = false;
+            })
+          }
+          
+        } else {
+          return false;
+        }
+      });
+    }
+  }
+};
+</script>
+<style lang="scss">
+</style>
+
+

+ 171 - 0
src/views/trending-words-list/index.vue

@@ -0,0 +1,171 @@
+<template>
+  <div class="app-container">
+    <div class="filter-container">
+      <div class="filter-container-lt">
+        <el-form :inline="true" label-position="left" :model="listQuery">
+          <el-form-item>
+            <el-input clearable v-model="listQuery.title" placeholder="标题"
+            ></el-input>
+          </el-form-item>
+          <el-form-item>
+            <el-select v-model="listQuery.platformName" clearable filterable placeholder="平台名称">
+              <el-option
+                v-for="item in platformNames"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value">
+              </el-option>
+            </el-select>
+          </el-form-item>
+          <el-button type="primary" @click="getList()">搜索</el-button >
+          <el-button type="primary" @click="add()">新增</el-button >
+        </el-form>
+      </div>
+    </div>
+    <div class="table-container">
+      <el-table  style="width: 100%" v-loading="listLoading" :key="tableKey" :data="list" row-key="id"
+        stripe border fit highlight-current-row>
+        <el-table-column label="序号" type="index" width="60" align="center" />
+        <el-table-column label="标题" min-width="100" align="center" prop="title" />
+        <el-table-column label="平台名称" min-width="100" align="center" prop="platformName" />
+        <el-table-column label="操作人" min-width="100" align="center" prop="creator" />
+        <el-table-column label="创建时间" min-width="100" align="center" prop="createTime" />
+        <el-table-column label="更新时间" min-width="100" align="center" prop="updateTime" />
+        <el-table-column label="操作" align="center" width="160">
+          <template slot-scope="scope">
+            <el-tooltip class="item" effect="dark" content="编辑" placement="top">
+              <el-button type="success" size="mini" icon="el-icon-edit" circle @click="handleEdit(scope.row)" />
+            </el-tooltip>
+            <el-tooltip class="more" effect="dark" content="删除" placement="top">
+              <el-button type="danger" size="mini" icon="el-icon-delete-solid" circle
+                @click="handleDelete(scope.row)" />
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+
+    <!-- 分页 -->
+    <swPage v-if="total > 0" key="2" :listQuery="listQuery" :total="total" pos="btmRight" @retPage="retPage" />
+    <trendingTermListFormModal ref="TrendingTermListFormModal" @confirm="retPage"></trendingTermListFormModal>
+  </div>
+</template>
+
+<script>
+import waves from "@/directive/waves";
+import swPage from "@/views/common/swPage";
+import { auditStatus } from "@/constants/index";
+import { getValueByKey } from "@/utils/index";
+import { hotWordList, deteleHotWord } from "@/api/trendingWordsList";
+import permission from "@/directive/permission";
+import trendingTermListFormModal from "./components/trendingTermListFormModal";
+
+
+export default {
+  name: "TrendingTermList",
+  directives: {
+    waves,
+    permission
+  },
+  components: {
+    swPage,
+    trendingTermListFormModal
+  },
+  computed: {
+    platformNames() {
+      return [
+        {value: '天猫', label: '天猫'},
+        {value: '自研', label: '自研'}
+      ]
+    }
+  },
+  data() {
+    return {
+      auditStatus,
+      tableKey: 0,
+      list: [],
+      total: 0,
+      listLoading: false,
+      downloadingRows: {},
+      listQuery: {
+        currentPage: 1,
+        pageSize: 10,
+        title: null,
+        platformName: null 
+      }
+    };
+  },
+  //页面创建的时候执行
+  created() {
+    this.getList();
+  },
+  methods: {
+    getValueByKey,
+    getList() {
+      this.listLoading = true;
+      const params = {}
+      for (const key in this.listQuery) {
+        const value = this.listQuery[key]
+        if (value !== null && value !== '' && value !== undefined) {
+          params[key] = value
+        }
+      }
+      hotWordList(params).then(res => {
+        if (200 == res.code) {
+          this.total = res.data.total;
+          this.list = res.data.rows;
+        }
+        this.listLoading = false;
+      });
+    },
+    retPage() {
+      //分页
+      this.getList();
+    },
+    handleFilter() {
+      this.listQuery.page = 1;
+      this.getList();
+    },
+    handleEdit(row) {
+      this.$refs.TrendingTermListFormModal.show(row, 'edit');
+    },
+    add() {
+      this.$refs.TrendingTermListFormModal.show(null, 'add');
+    },
+    handleDelete(row) {
+      //删除
+      this.$confirm("确定要删除吗?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        const { id } = row;
+        deteleHotWord([id]).then(() => {
+          this.$notify({
+            title: "成功",
+            message: "删除成功",
+            type: "success",
+            duration: 3000
+          });
+          const index = this.list.indexOf(row);
+          this.list.splice(index, 1);
+        });
+      });
+    }
+  }
+};
+</script>
+
+<style rel="stylesheet/scss" lang="scss" scoped>
+@import "@/styles/layout.scss";
+
+.button {
+  .el-button {
+    margin-bottom: 10px;
+
+    &:last-child {
+      margin-bottom: 0;
+    }
+  }
+}
+</style>

+ 8 - 1
src/views/video-cover-manager/index.vue

@@ -118,7 +118,14 @@ export default {
     getValueByKey,
     getList() {
       this.listLoading = true;
-      shopConfigInfoList(this.listQuery).then(res => {
+      const params = {}
+      for (const key in this.listQuery) {
+        const value = this.listQuery[key]
+        if (value !== null && value !== '' && value !== undefined) {
+          params[key] = value
+        }
+      }
+      shopConfigInfoList(params).then(res => {
         if (200 == res.code) {
           this.total = res.data.total;
           this.list = res.data.rows;