فهرست منبع

接入商品图库

lushixing 3 هفته پیش
والد
کامیت
dccc5ff535

+ 19 - 0
src/api/productRepo.js

@@ -0,0 +1,19 @@
+import request from '@/utils/request'
+
+//列表
+export function galleryProduct(params) {
+  return request({
+    url: '/galleryProduct/page',
+    method: 'get',
+    params
+  })
+}
+
+//同步产品数据
+export function pullGalleryProduct(params) {
+  return request({
+    url: '/pullGalleryProduct',
+    method: 'get',
+    params
+  })
+}

+ 3 - 1
src/permission.js

@@ -76,7 +76,9 @@ router.beforeEach(async (to, from, next) => {
             { routerPath: "/AIAssetSearch" },
             { routerPath: "/AIAssetSearch/AIAssetSearchIndex" },
             { routerPath: "/trendingTermList" },
-            { routerPath: "/trendingTermList/trendingTermListIndex" }]
+            { routerPath: "/trendingTermList/trendingTermListIndex" },
+            { routerPath: "/productRepo" },
+            { routerPath: "/productRepo/productRepoIndex" }]
          
           const accessRoutes = await store.dispatch('permission/generateRoutes', data);
           router.addRoutes(accessRoutes);

+ 3 - 1
src/router/index.js

@@ -42,6 +42,7 @@ import catwalkVideoRouter from "./modules/catwalkVideo";
 import faceSwapVideoRouter from "./modules/faceSwapVideo";
 import AIAssetSearchRouter from "./modules/AIAssetSearch";
 import trendingTermListRouter from "./modules/trendingTermList";
+import productRepoRouter from "./modules/productRepo";
 export const asyncRoutes = [
   oralVideoRouter,
   catwalkVideoRouter,
@@ -50,7 +51,8 @@ export const asyncRoutes = [
   videoCoverManagerRouter,
   musicLibraryManager,
   AIAssetSearchRouter,
-  trendingTermListRouter
+  trendingTermListRouter,
+  productRepoRouter
   // userAuthRouter,
 ];
 

+ 19 - 0
src/router/modules/productRepo.js

@@ -0,0 +1,19 @@
+/** When your routing table is too long, you can split it into small modules **/
+
+import Layout from "@/layout";
+
+const productRepoRouter = {
+  path: "/productRepo",
+  component: Layout,
+  redirect: "/productRepo/productRepoIndex",
+  meta: { title: "产品库", icon: "el-icon-s-shop" },
+  children: [
+    {
+      path: "productRepoIndex",
+      component: () => import("@/views/product-repo/index"),
+      name: "productRepoIndex",
+      meta: { title: "产品库列表" }
+    }
+  ]
+};
+export default productRepoRouter;

+ 333 - 0
src/views/design-agent/components/productRepoModal.vue

@@ -0,0 +1,333 @@
+<template>
+  <el-dialog  width="1270px" custom-class="product-repo-modal" :visible.sync="dialogVisible" show-close>
+    <div class="app-container-block">
+      <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.productCode" placeholder="请输入SPU"
+                ></el-input>
+              </el-form-item>
+              <el-button type="primary" @click="getList()">搜索</el-button >
+            </el-form>
+          </div>
+        </div>
+        <div class="exhibition-area" v-show="showImageList">
+          <div class="image-list">
+            <div class="image" v-for="(acc, index) in currentImageList" :key="acc.url + '_' + index">
+              <img :src="acc.url" alt="">
+              <el-checkbox v-model="acc.checked" @change="changeImageList(acc.checked, index)"></el-checkbox>
+            </div>
+          </div>
+          <div class="return">
+            <el-button icon="el-icon-back" @click="backTable">返回</el-button>
+          </div>
+        </div>
+        <div class="" v-show="!showImageList">
+          <div class="table-container">
+            <el-table  style="width: 100%" v-loading="listLoading" :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="商品SPU" min-width="100" align="center">
+                <template slot-scope="scope">
+                  <p style="margin: 0; padding: 0; cursor: pointer;" @click="handleImageList(scope.row)">{{ scope.row.productCode }}</p>
+                </template>
+              </el-table-column>
+              <el-table-column label="商品ID" min-width="100" align="center" prop="productId" />
+              <el-table-column label="商品图片" min-width="100" align="center">
+                <template slot-scope="scope">
+                  <p style="margin: 0; padding: 0; cursor: pointer;" v-if="scope.row.productImageUrls && scope.row.productImageUrls.length" @click="handleImageList(scope.row)">
+                    <img style="max-width: 100px;" :src="scope.row.productImageUrls[0]"  alt="">
+                  </p>
+                </template>
+              </el-table-column>
+              <el-table-column label="商品名称" min-width="100" align="center" prop="productTitle" />
+              <!-- <el-table-column label="价格" min-width="100" align="center" prop="createTime" /> -->
+              <el-table-column label="更新时间" min-width="100" align="center" prop="updateTime" />
+            </el-table>
+          </div>
+          <!-- 分页 -->
+          <swPage v-if="total > 0" key="2" :listQuery="listQuery" :total="total" pos="btmRight" @retPage="retPage" />
+        </div>
+      </div>
+      <div class="have-chosen-block">
+        <div class="have-chosen-box">
+          <div class="have-chosen">
+            <div class="have-chosen-title">已选图片</div>
+            <div class="have-chosen-image-list">
+              <div class="have-chosen-image" v-for="(acc, index) in chooseImageList" :key="acc + '-' + index">
+                <div class="delete" @click="delImage(acc, index)"><span>X</span></div>
+                <img :src="acc">
+              </div>
+            </div>
+          </div>
+          <span slot="footer" class="dialog-footer">
+            <el-button @click="dialogVisible = false" size="small">取消</el-button>
+            <el-button type="primary" @click="handleConfirm" size="small">确定</el-button>
+          </span>
+        </div>
+      </div>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+import swPage from "@/views/common/swPage";
+import { galleryProduct } from "@/api/productRepo";
+export default {
+  name: "productRepoModal",
+  components: {
+    swPage
+  },
+  props: {
+  },
+  data() {
+    return {
+      showImageList: false,
+      dialogVisible: false,
+      currentImageList: [],
+      chooseImageList: [],
+      delArr: [],
+      list: [],
+      total: 0,
+      listLoading: false,
+      listQuery: {
+        currentPage: 1,
+        pageSize: 10,
+        productCode: null
+      }
+    };
+  },
+  computed: {
+    
+  },
+  watch: {
+    dialogVisible(val) {
+      if (!val) {
+        this.showImageList = false;
+      }
+    }
+  },
+  methods: {
+    show(row) {
+      this.dialogVisible = true;
+      this.delArr = [];
+      this.chooseImageList = JSON.parse(JSON.stringify(row));
+      this.getList();
+    },
+    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
+        }
+      }
+      galleryProduct(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();
+    },
+    handleConfirm() {
+      this.$emit('setImageList', this.chooseImageList, this.delArr);
+      this.dialogVisible = false;
+    },
+    handleImageList(row) {
+      if (row.productImageUrls && row.productImageUrls.length) {
+        this.showImageList = true;
+        this.currentImageList = row.productImageUrls.map(acc => {
+          const isChecked = this.chooseImageList.filter(item => item == acc)
+          return {
+            url: acc,
+            checked: isChecked.length ? true : false
+          }
+        });
+      }
+    },
+    changeImageList(checked, index) {
+      if (checked) {
+        if (this.chooseImageList.length >= 5) {
+          this.$set(this.currentImageList[index], 'checked', false)
+          this.$message.error("最多只能添加5张图片哦!");
+        } else {
+          this.chooseImageList.push(this.currentImageList[index].url)
+        }
+      } else {
+        // 取消选中
+        this.chooseImageList.forEach((acc, i) => {
+          if (acc == this.currentImageList[index].url) {
+            this.chooseImageList.splice(i, 1)
+          }
+        })
+        this.delArr.push(this.currentImageList[index].url)
+      }
+    },
+    delImage(row, index) {
+      //删除
+      this.$confirm("确定要删除吗?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.chooseImageList.splice(index, 1);
+        this.delArr.push(row);
+        this.currentImageList.forEach(acc => {
+          if (acc.url == row) {
+            this.$set(acc, 'checked', false);
+          }
+        })
+      });
+    },
+    backTable() {
+      this.showImageList = false;
+    }
+  }
+};
+</script>
+<style lang="scss" scoped>
+  .app-container-block {
+    .have-chosen-block {
+      padding-top: 60px;
+    }
+    .have-chosen-box {
+      display: flex;
+      flex-direction: column;
+      justify-content: space-between;
+      width: 250px;
+      flex: 0 0 250px;
+      border-radius: 5px;
+      background-color: #f2f2f2;
+      height: 100%;
+    }
+    .have-chosen-title {
+      font-size: 18px;
+      line-height: 28px;
+      color: #232323;
+    }
+    .have-chosen {
+      box-sizing: border-box;
+      padding: 20px;
+      width: 100%;
+      color: #000;
+      font-weight: 700;
+      overflow: auto;
+    }
+    .have-chosen-image-list {
+      display: flex;
+      flex-direction: column;
+      .have-chosen-image {
+        width: 100%;
+        height: 280px;
+        background-color: #ccc;
+        margin-top: 20px;
+        overflow: hidden;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        position: relative;
+
+        .delete {
+          position: absolute;
+          top: 10px;
+          right: 10px;
+          background: rgba(0, 0, 0, .6);
+          color: #fff;
+          width: 30px;
+          height: 30px;
+          text-align: center;
+          line-height: 30px;
+          border-radius: 100px;
+          font-size: 15px;
+          cursor: pointer;
+        }
+        img {
+          height: 100%;
+        }
+      }
+    }
+  }
+</style>
+<style lang="scss">
+  .el-dialog.product-repo-modal {
+    margin-top: 30px !important;
+    height: calc(100% - 60px);
+    .el-dialog__header {
+      padding: 0;
+    }
+    .el-dialog__body {
+      height: 100%;
+    }
+    .app-container-block {
+      display: flex;
+      gap: 20px;
+      height: 100%;
+    }
+    .app-container {
+      width: 100%;
+      padding: 0;
+    }
+    .dialog-footer {
+      display: flex;
+      justify-content: center;
+      padding: 10px;
+    }
+    .exhibition-area {
+      box-sizing: border-box;
+      padding: 20px;
+      border-radius: 5px;
+      border: 2px solid #f2f2f2;
+      position: relative;
+      display: flex;
+      flex-direction: column-reverse;
+      height: calc(100% - 72px);
+      .image-list {
+        width: 100%;
+        height: 100%;
+        overflow: auto;
+        box-sizing: border-box;
+        display: flex;
+        gap: 18px;
+        flex-wrap: wrap;
+        margin-top: 20px;
+
+        .image {
+          position: relative;
+          width: 200px;
+          display: flex;
+          justify-content: center;
+          align-items: center;
+          background-color: #ccc;
+          position: relative;
+          overflow: hidden;
+          cursor: pointer;
+
+          img {
+            display: block;
+            width: 100%;
+          }
+        }
+      }
+
+      .el-checkbox {
+        position: absolute;
+        top: 10px;
+        right: 10px;
+      }
+    }
+  }
+</style>
+
+

+ 56 - 2
src/views/design-agent/feature-mod-index.vue

@@ -107,11 +107,17 @@
                         :before-upload="beforeUploadVideo"
                       >
                         <div v-loading="uploading">
-                          <i class="el-icon-plus" v-if="ruleForm.imageList.length"></i>
+                          <template v-if="ruleForm.imageList.length">
+                            <i class="el-icon-plus"></i>
+                            <el-button type="primary" size="mini" @click.stop="handleProductRepo">产品库</el-button>
+                          </template>
                           <div class="el-upload__info" v-else>
-                            <i class="el-icon-upload"></i>
+                            <i class="el-icon-upload" style="margin: 0;"></i>
                             <div class="el-upload__text">点击或将图片拖拽到这里上传,最多上传 5 张图片</div>
                             <div class="el-upload__tip" slot="tip">图片要求:支持JPG、PNG和WEBP,最大为20M</div>
+                            <div class="el-upload__btn">
+                              <el-button type="primary" size="small" @click.stop="handleProductRepo">从产品库选择</el-button>
+                            </div>
                           </div>
                         </div>
                       </el-upload>
@@ -359,6 +365,7 @@
         </div>
       </div>
     </div>
+    <product-repo-modal ref="productRepoModal" @setImageList="setImageList"></product-repo-modal>
   </div>
 </template>
 
@@ -369,11 +376,13 @@ import { getToken } from '@/utils/auth'
 import downloadUtil from "@/utils/downloadUtil";
 import { genCidHex16, fetchStreamText } from '@/utils/index'
 import request from '@/utils/request'
+import productRepoModal from './components/productRepoModal'
 // 引入 Swiper 及样式
 import Swiper from 'swiper'
 import 'swiper/dist/css/swiper.min.css'
 export default {
   components: {
+    productRepoModal
   },
   data() {
     return {
@@ -816,6 +825,51 @@ export default {
       }).finally(() => {
         this.viewLoading = false
       })
+    },
+    setImageList(row, dels) {
+      row.forEach(acc => {
+        if (!this.ruleForm.imageList.includes(acc)) {
+          this.ruleForm.imageList.push(acc);
+        }
+      })
+      if (dels && dels.length) {
+        var diff = dels.filter(function(item){
+          return row.indexOf(item) === -1;
+        });
+        if (diff.length) {
+          this.ruleForm.imageList.forEach((acc, index) => {
+            if (diff.includes(acc)) {
+              this.ruleForm.imageList.splice(index, 1);
+            }
+          })
+        }
+      }
+      this.$nextTick(() => {
+        if (this.swiper) {
+          this.swiper.update()
+        } else {
+          this.initSwiper()
+        }
+      })
+    },
+    delImageList(url) {
+      if (this.ruleForm.imageList.includes(url)) {
+        this.ruleForm.imageList.forEach((acc, index) => {
+          if (url == acc) {
+            this.ruleForm.imageList.splice(index, 1);
+          }
+        })
+        this.$nextTick(() => {
+          if (this.swiper) {
+            this.swiper.update()
+          } else {
+            this.initSwiper()
+          }
+        })
+      }
+    },
+    handleProductRepo() {
+      this.$refs.productRepoModal && this.$refs.productRepoModal.show(this.ruleForm.imageList);
     }
   }
 };

+ 139 - 0
src/views/product-repo/index.vue

@@ -0,0 +1,139 @@
+<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.productCode" placeholder="请输入SPU"
+            ></el-input>
+          </el-form-item>
+          <el-button type="primary" @click="getList()">搜索</el-button >
+          <el-button type="primary" @click="productsSync()" icon="el-icon-refresh" :loading="productsSyncLoading">同步商品</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="商品SPU" min-width="100" align="center" prop="productCode" />
+        <el-table-column label="商品ID" min-width="100" align="center" prop="productId" />
+        <el-table-column label="商品图片" min-width="100" align="center">
+          <template slot-scope="scope">
+            <el-image 
+              v-if="scope.row.productImageUrls && scope.row.productImageUrls.length"
+              style="width: 100px; height: 100px"
+              :src="scope.row.productImageUrls[0]" 
+              :preview-src-list="scope.row.productImageUrls">
+            </el-image>
+          </template>
+        </el-table-column>
+        <el-table-column label="商品名称" min-width="100" align="center" prop="productTitle" />
+        <!-- <el-table-column label="价格" min-width="100" align="center" prop="createTime" /> -->
+        <el-table-column label="更新时间" min-width="100" align="center" prop="updateTime" />
+      </el-table>
+    </div>
+    <!-- 分页 -->
+    <swPage v-if="total > 0" key="2" :listQuery="listQuery" :total="total" pos="btmRight" @retPage="retPage" />
+  </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 { galleryProduct, pullGalleryProduct } from "@/api/productRepo";
+import permission from "@/directive/permission";
+
+
+export default {
+  name: "TrendingTermList",
+  directives: {
+    waves,
+    permission
+  },
+  components: {
+    swPage
+  },
+  computed: {
+  },
+  data() {
+    return {
+      auditStatus,
+      tableKey: 0,
+      list: [],
+      total: 0,
+      listLoading: false,
+      productsSyncLoading: false,
+      listQuery: {
+        currentPage: 1,
+        pageSize: 10,
+        productCode: 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
+        }
+      }
+      galleryProduct(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();
+    },
+    productsSync() {
+      const params = this.listQuery ? { productCode: this.listQuery.productCode } : {}
+      if (!this.listQuery.productCode) {
+        this.$message.error("产品款号不能为空!");
+        return;
+      }
+      this.productsSyncLoading = true;
+      pullGalleryProduct(params).then(res => {
+        if (200 == res.code) {
+          this.$message.success(res.msg || "操作成功");
+        }
+        this.productsSyncLoading = false;
+      }).finally(() => {
+        this.productsSyncLoading = false;
+      })
+    }
+  }
+};
+</script>
+
+<style rel="stylesheet/scss" lang="scss" scoped>
+@import "@/styles/layout.scss";
+
+.button {
+  .el-button {
+    margin-bottom: 10px;
+
+    &:last-child {
+      margin-bottom: 0;
+    }
+  }
+}
+</style>