yuwenjun il y a 4 ans
Parent
commit
c76db1ce48
47 fichiers modifiés avec 1640 ajouts et 527 suppressions
  1. 3 0
      .env.development
  2. 2 0
      .env.production
  3. 31 31
      mock/auth.js
  4. 13 13
      mock/supplier.js
  5. 16 16
      mock/user.js
  6. 2 0
      package.json
  7. 0 41
      src/api/article.js
  8. 28 0
      src/api/auth.js
  9. 10 0
      src/api/brand.js
  10. 9 0
      src/api/common.js
  11. 46 0
      src/api/product.js
  12. 0 8
      src/api/qiniu.js
  13. 0 17
      src/api/remote-search.js
  14. 0 38
      src/api/role.js
  15. 19 1
      src/api/supplier.js
  16. 8 0
      src/api/user.js
  17. BIN
      src/assets/img/qrcode-bg-down.jpg
  18. BIN
      src/assets/img/qrcode-bg-show.png
  19. 226 0
      src/components/qrcode/index.vue
  20. 7 3
      src/layout/components/Navbar.vue
  21. 2 2
      src/main.js
  22. 3 2
      src/mixin/base.js
  23. 11 5
      src/permission.js
  24. 10 5
      src/router/index.js
  25. 4 1
      src/store/getters.js
  26. 18 1
      src/store/modules/app.js
  27. 12 4
      src/store/modules/permission.js
  28. 9 3
      src/store/modules/user.js
  29. 4 0
      src/styles/index.css
  30. 0 0
      src/styles/index.min.css
  31. 7 0
      src/styles/index.scss
  32. 11 0
      src/utils/index.js
  33. 10 3
      src/utils/request.js
  34. 19 0
      src/utils/validate.js
  35. 5 5
      src/views/error-page/404.vue
  36. 7 4
      src/views/login/index.vue
  37. 12 4
      src/views/password/index.vue
  38. 129 25
      src/views/supplier/auth/index.vue
  39. 21 10
      src/views/supplier/components/uploadFile.vue
  40. 15 20
      src/views/supplier/components/uploadImage.vue
  41. 174 41
      src/views/supplier/product/add.vue
  42. 194 41
      src/views/supplier/product/edit.vue
  43. 91 65
      src/views/supplier/product/index.vue
  44. 126 49
      src/views/supplier/user/add.vue
  45. 258 45
      src/views/supplier/user/edit.vue
  46. 66 22
      src/views/supplier/user/index.vue
  47. 2 2
      vue.config.js

+ 3 - 0
.env.development

@@ -3,3 +3,6 @@ ENV = 'development'
 
 # base api
 VUE_APP_BASE_API = 'http://192.168.2.68:8012'
+
+# 文件上传
+VUE_APP_UPLOAD_API='https://zplma-b.caimei365.com'

+ 2 - 0
.env.production

@@ -4,3 +4,5 @@ ENV = 'production'
 # base api
 VUE_APP_BASE_API = '/prod-api'
 
+# 文件上传
+VUE_APP_UPLOAD_API='https://zplma-b.caimei365.com'

+ 31 - 31
mock/auth.js

@@ -15,37 +15,37 @@ for (let i = 0; i < count; i++) {
 }
 
 module.exports = [
-  {
-    url: '/auth/list',
-    type: 'get',
-    response: config => {
-      return {
-        code: 0,
-        data: {
-          list: authList,
-          total: authList.length,
-          endRow: 0,
-          firstPage: 0,
-          hasNextPage: true,
-          hasPreviousPage: true,
-          isFirstPage: true,
-          isLastPage: true,
-          lastPage: 0,
-          navigateFirstPage: 0,
-          navigateLastPage: 0,
-          navigatePages: 0,
-          navigatepageNums: [],
-          nextPage: 0,
-          pageNum: 0,
-          pageSize: 0,
-          pages: 0,
-          prePage: 0,
-          size: 0,
-          startRow: 0
-        }
-      }
-    }
-  }
+  // {
+  //   url: '/auth/list',
+  //   type: 'get',
+  //   response: config => {
+  //     return {
+  //       code: 0,
+  //       data: {
+  //         list: authList,
+  //         total: authList.length,
+  //         endRow: 0,
+  //         firstPage: 0,
+  //         hasNextPage: true,
+  //         hasPreviousPage: true,
+  //         isFirstPage: true,
+  //         isLastPage: true,
+  //         lastPage: 0,
+  //         navigateFirstPage: 0,
+  //         navigateLastPage: 0,
+  //         navigatePages: 0,
+  //         navigatepageNums: [],
+  //         nextPage: 0,
+  //         pageNum: 0,
+  //         pageSize: 0,
+  //         pages: 0,
+  //         prePage: 0,
+  //         size: 0,
+  //         startRow: 0
+  //       }
+  //     }
+  //   }
+  // }
 ]
 
 // {

+ 13 - 13
mock/supplier.js

@@ -22,18 +22,18 @@ for (let i = 0; i < count; i++) {
 }
 
 module.exports = [
-  {
-    url: '/shop/list',
-    type: 'get',
-    response: config => {
-      return {
-        code: 0,
-        data: {
-          list: supplierList,
-          total: supplierList.length
-        }
-      }
-    }
-  }
+  // {
+  //   url: '/shop/list',
+  //   type: 'get',
+  //   response: config => {
+  //     return {
+  //       code: 0,
+  //       data: {
+  //         list: supplierList,
+  //         total: supplierList.length
+  //       }
+  //     }
+  //   }
+  // }
 ]
 

+ 16 - 16
mock/user.js

@@ -24,22 +24,22 @@ const users = {
 }
 
 module.exports = [
-  {
-    url: '/user/login/password',
-    type: 'post',
-    response: config => {
-      return {
-        code: 0,
-        data: {
-          shopStatus: 1,
-          authUserId: 1,
-          userIdentity: 1,
-          token: 'abc-token',
-          name: '用户'
-        }
-      }
-    }
-  },
+  // {
+  //   url: '/user/login/password',
+  //   type: 'post',
+  //   response: config => {
+  //     return {
+  //       code: 0,
+  //       data: {
+  //         shopStatus: 1,
+  //         authUserId: 1,
+  //         userIdentity: 1,
+  //         token: 'abc-token',
+  //         name: '用户'
+  //       }
+  //     }
+  //   }
+  // },
   // user login
   // {
   //   url: '/vue-element-admin/user/login',

+ 2 - 0
package.json

@@ -28,9 +28,11 @@
     "js-cookie": "2.2.0",
     "jsonlint": "1.6.3",
     "jszip": "3.2.1",
+    "moment": "^2.29.1",
     "normalize.css": "7.0.0",
     "nprogress": "0.2.0",
     "path-to-regexp": "2.4.0",
+    "qrcode": "^1.4.4",
     "screenfull": "4.2.0",
     "script-loader": "0.7.2",
     "sortablejs": "1.8.4",

+ 0 - 41
src/api/article.js

@@ -1,41 +0,0 @@
-import request from '@/utils/request'
-
-export function fetchList(query) {
-  return request({
-    url: '/vue-element-admin/article/list',
-    method: 'get',
-    params: query
-  })
-}
-
-export function fetchArticle(id) {
-  return request({
-    url: '/vue-element-admin/article/detail',
-    method: 'get',
-    params: { id }
-  })
-}
-
-export function fetchPv(pv) {
-  return request({
-    url: '/vue-element-admin/article/pv',
-    method: 'get',
-    params: { pv }
-  })
-}
-
-export function createArticle(data) {
-  return request({
-    url: '/vue-element-admin/article/create',
-    method: 'post',
-    data
-  })
-}
-
-export function updateArticle(data) {
-  return request({
-    url: '/vue-element-admin/article/update',
-    method: 'post',
-    data
-  })
-}

+ 28 - 0
src/api/auth.js

@@ -1,5 +1,6 @@
 import request from '@/utils/request'
 
+// 授权列表
 export function fecthAuthList(params) {
   return request({
     url: '/auth/list',
@@ -7,3 +8,30 @@ export function fecthAuthList(params) {
     params
   })
 }
+
+// 添加品牌授权
+export function saveBrandAuth(data) {
+  return request({
+    url: '/auth/save',
+    method: 'post',
+    data
+  })
+}
+
+// 修改授权状态
+export function changeAuthStatus(data) {
+  return request({
+    url: '/auth/update/status',
+    method: 'post',
+    data
+  })
+}
+
+// 删除授权
+export function removeAuth(data) {
+  return request({
+    url: '/auth/delete',
+    method: 'post',
+    data
+  })
+}

+ 10 - 0
src/api/brand.js

@@ -0,0 +1,10 @@
+import request from '@/utils/request'
+
+// 品牌列表
+export function fetchBrandList(params) {
+  return request({
+    url: '/shop/brand/list',
+    method: 'get',
+    params
+  })
+}

+ 9 - 0
src/api/common.js

@@ -0,0 +1,9 @@
+import request from '@/utils/request'
+
+// 获取地址
+export function getCountry(params) {
+  return request({
+    url: '/shop/country/list',
+    method: 'get'
+  })
+}

+ 46 - 0
src/api/product.js

@@ -0,0 +1,46 @@
+import request from '@/utils/request'
+
+// 获取商品列表
+export function getProdList(params) {
+  return request({
+    url: '/auth/product/list',
+    method: 'get',
+    params
+  })
+}
+
+// 添加商品
+export function saveProduct(data) {
+  return request({
+    url: '/auth/product/save',
+    method: 'post',
+    data
+  })
+}
+
+// 根据id获取商品信息
+export function getProductById(params) {
+  return request({
+    url: '/auth/product/form/data',
+    method: 'get',
+    params
+  })
+}
+
+// 修改商品状态
+export function setProductStatus(data) {
+  return request({
+    url: '/auth/product/update/status',
+    method: 'post',
+    data
+  })
+}
+
+// 删除商品
+export function removeProduct(data) {
+  return request({
+    url: '/auth/product/delete',
+    method: 'post',
+    data
+  })
+}

+ 0 - 8
src/api/qiniu.js

@@ -1,8 +0,0 @@
-import request from '@/utils/request'
-
-export function getToken() {
-  return request({
-    url: '/qiniu/upload/token', // 假地址 自行替换
-    method: 'get'
-  })
-}

+ 0 - 17
src/api/remote-search.js

@@ -1,17 +0,0 @@
-import request from '@/utils/request'
-
-export function searchUser(name) {
-  return request({
-    url: '/vue-element-admin/search/user',
-    method: 'get',
-    params: { name }
-  })
-}
-
-export function transactionList(query) {
-  return request({
-    url: '/vue-element-admin/transaction/list',
-    method: 'get',
-    params: query
-  })
-}

+ 0 - 38
src/api/role.js

@@ -1,38 +0,0 @@
-import request from '@/utils/request'
-
-export function getRoutes() {
-  return request({
-    url: '/vue-element-admin/routes',
-    method: 'get'
-  })
-}
-
-export function getRoles() {
-  return request({
-    url: '/vue-element-admin/roles',
-    method: 'get'
-  })
-}
-
-export function addRole(data) {
-  return request({
-    url: '/vue-element-admin/role',
-    method: 'post',
-    data
-  })
-}
-
-export function updateRole(id, data) {
-  return request({
-    url: `/vue-element-admin/role/${id}`,
-    method: 'put',
-    data
-  })
-}
-
-export function deleteRole(id) {
-  return request({
-    url: `/vue-element-admin/role/${id}`,
-    method: 'delete'
-  })
-}

+ 19 - 1
src/api/supplier.js

@@ -10,10 +10,28 @@ export function fetchSupplierList(params) {
 }
 
 // 供应商状态
-export function supplierStatusChange(params) {
+export function supplierStatusChange(data) {
   return request({
     url: '/shop/update/status',
     method: 'post',
+    data
+  })
+}
+
+// 添加供应商
+export function addSupplier(data) {
+  return request({
+    url: '/shop/save',
+    method: 'post',
+    data
+  })
+}
+
+// 根据id获取供应商
+export function getSupplierById(params) {
+  return request({
+    url: '/shop/form/data',
+    method: 'get',
     params
   })
 }

+ 8 - 0
src/api/user.js

@@ -16,6 +16,14 @@ export function modifyPassword(data) {
   })
 }
 
+export function resetPassword(data) {
+  return request({
+    url: '/shop/reset/password',
+    method: 'post',
+    data
+  })
+}
+
 // export function getInfo(token) {
 //   return request({
 //     url: '/vue-element-admin/user/info',

BIN
src/assets/img/qrcode-bg-down.jpg


BIN
src/assets/img/qrcode-bg-show.png


+ 226 - 0
src/components/qrcode/index.vue

@@ -0,0 +1,226 @@
+<template>
+  <div class="code-container">
+    <transition name="fade">
+      <div v-if="isVisible" class="qrcode">
+        <div class="title">{{ productInfo.productName }}</div>
+        <div class="sncode"><span>仪器SN码:</span>{{ hanldeSNcode(productInfo.snCode) }}</div>
+        <div class="content">
+          <img :src="imgUrl" alt="">
+        </div>
+        <div class="btn down-btn" @click="handleDown">下载二维码</div>
+        <div class="btn close-btn" @click="handleClose">关闭</div>
+      </div>
+    </transition>
+    <canvas id="canvas" style="display:none" />
+    <div v-if="isVisible" class="mask" @click="handleClose" />
+    <a id="downloadLink" href="#" style="display:none" />
+  </div>
+</template>
+
+<script>
+import QRCode from 'qrcode'
+import downImage from '@/assets/img/qrcode-bg-down.jpg'
+export default {
+  name: 'Qrcode',
+  filters: {
+
+  },
+  props: {
+    productInfo: {
+      type: Object,
+      default: () => {}
+    },
+    isVisible: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data() {
+    return {
+      imgUrl: '',
+      wwwServer: process.env.VUE_APP_BASE_API,
+      qrcodePath: ''
+    }
+  },
+  created() {
+    this.qrcodePath = `${this.wwwServer}/product/auth/product-${this.productInfo?.productId}.html`
+    this.initQrcode()
+  },
+  methods: {
+    // 关闭二维码
+    handleClose() {
+      this.$emit('close')
+    },
+    // 下载二维码
+    handleDown() {
+      this.createDownFile((downCanvas) => {
+        // 构造url
+        var url = downCanvas.toDataURL('image/jpg')
+        // 构造a标签并模拟点击
+        var downloadLink = document.getElementById('downloadLink')
+        downloadLink.setAttribute('href', url)
+        downloadLink.setAttribute('download', '二维码.jpg')
+        downloadLink.click()
+      })
+    },
+    // 初始化二维码
+    async initQrcode() {
+      // 二维码配置
+      const options = {
+        width: 192,
+        height: 192,
+        margin: 1
+      }
+      try {
+        this.imgUrl = await QRCode.toDataURL(this.qrcodePath, options)
+      } catch (err) {
+        console.error(err)
+      }
+    },
+    // 生成下载的文件
+    async createDownFile(callback) {
+      const strHeader = this.productInfo.productName
+      const strFooter1 = '仪器SN码:'
+      const strFooter2 = this.hanldeSNcode(this.productInfo.snCode)
+      // 生成二维码参数信息
+      const options = {
+        width: 720,
+        height: 720,
+        margin: 1
+      }
+      // 生成二维码dataURL
+      const downDataURL = await QRCode.toDataURL(this.qrcodePath, options)
+
+      // 设置下载二维码
+      const downCanvas = document.getElementById('canvas')
+      const downImg = new Image()
+      const downBgImg = new Image()
+      downImg.src = downDataURL
+      downBgImg.src = downImage
+      downBgImg.onload = function() {
+        // 重新绘制画布
+        const w = this.width
+        const h = this.height
+        downCanvas.width = w
+        downCanvas.height = h
+        const ctx = downCanvas.getContext('2d')
+        // 设置画布背景
+        ctx.fillStyle = '#ffffff'
+        ctx.fillRect(0, 0, downCanvas.width, downCanvas.height)
+        // 设置文字样式
+        ctx.fillStyle = '#ffffff'
+        ctx.font = 'bold 52px MicrosoftYaHei'
+        ctx.textAlign = 'center'
+        // 绘制背景
+        ctx.drawImage(this, 0, 0)
+        // 绘制二维码
+        ctx.drawImage(downImg, 185, 372)
+        // 绘制顶部文字描述
+        const chr = strHeader.split('')
+        let temp = ''
+        const row = []
+        for (let a = 0; a < chr.length; a++) {
+          if (ctx.measureText(temp).width >= (w - 290)) {
+            row.push(temp)
+            temp = ''
+          }
+          temp += chr[a]
+        }
+        row.push(temp)
+        if (row.length === 1) {
+          ctx.fillText(row[0], w / 2, 122)
+        } else {
+          for (var b = 0; b < row.length; b++) {
+            ctx.fillText(row[b], w / 2, 160 - (row.length - b - 1) * 65)
+          }
+        }
+        // 绘制底部文字
+        ctx.fillStyle = '#42aaff'
+        ctx.font = 'bold 33px MicrosoftYaHei'
+        ctx.textAlign = 'center'
+        ctx.fillText(strFooter1 + strFooter2, w / 2, 238)
+        // 绘制完成后的回调
+        callback(downCanvas)
+      }
+    },
+    hanldeSNcode(code) {
+      const start = code.slice(0, 2)
+      const end = code.slice(code.length - 5, code.length - 1)
+      return start + '*'.repeat(6) + end
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.mask{
+  position: fixed;
+  top: 0;
+  left: 0;
+  z-index: 9998;
+  width: 100vw;
+  height: 100vh;
+  background: rgba(0,0,0,.5);
+}
+.qrcode{
+  z-index: 9999;
+  position: fixed;
+  left: 50%;
+  top: 20%;
+  transform: translateX(-50%);
+  width: 300px;
+  height: 400px;
+  background: url(../../assets/img/qrcode-bg-show.png) no-repeat center;
+  .content{
+    width: 192px;
+    height: 192px;
+    position: absolute;
+    left: 54px;
+    bottom: 46px;
+  }
+  .down-btn{
+    left: 0;
+  }
+  .close-btn{
+    right: 0;
+  }
+  .title{
+    position: absolute;
+    top: 32px;
+    left: 50%;
+    transform: translateX(-50%);
+    width:256px;
+    text-align: center;
+    font-size: 16px;
+    color: #fff;
+    font-weight: bold;
+  }
+  .sncode{
+    position: absolute;
+    top: 78px;
+    left: 50%;
+    transform: translateX(-50%);
+    text-align: center;
+    width: 192px;
+    color: #0e9ef0;
+    font-size: 14px;
+    span{
+      font-weight: bold;
+    }
+  }
+
+}
+.btn  {
+  position: absolute;
+  bottom: -60px;
+	width: 108px;
+	height: 32px;
+	background-image: linear-gradient(-90deg,	#50c0ff 0%,#0e90dc 100%);
+	border-radius: 4px;
+  text-align: center;
+  line-height: 32px;
+  color: #fff;
+  font-size: 14px;
+  cursor: pointer;
+}
+</style>

+ 7 - 3
src/layout/components/Navbar.vue

@@ -17,7 +17,7 @@
       <el-dropdown class="avatar-container right-menu-item hover-effect" trigger="click">
         <div class="avatar-wrapper">
           <img src="https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif" class="user-avatar">
-          <span>{{ name }}</span>
+          <span>{{ userName }}</span>
           <i class="el-icon-caret-bottom" />
         </div>
         <el-dropdown-menu slot="dropdown">
@@ -53,8 +53,12 @@ export default {
     ...mapGetters([
       'sidebar',
       'device',
-      'name'
-    ])
+      'name',
+      'proxyInfo'
+    ]),
+    userName() {
+      return this.proxyInfo?.name || this.name
+    }
   },
   methods: {
     toggleSideBar() {

+ 2 - 2
src/main.js

@@ -31,8 +31,8 @@ import './mixin/base' // 公共方法
  * please remove it before going online ! ! !
  */
 // if (process.env.NODE_ENV === 'production') {
-const { mockXHR } = require('../mock')
-mockXHR()
+//   const { mockXHR } = require('../mock')
+//   mockXHR()
 // }
 
 Vue.use(Element, {

+ 3 - 2
src/mixin/base.js

@@ -7,10 +7,11 @@ const option = {
       this.$router.go(-1)
     },
     // 跳转
-    $_navigationTo(url) {
-      this.$router.push(url)
+    $_navigationTo(url, params) {
+      this.$router.push({ path: url, params })
     }
   }
+
 }
 
 Vue.mixin(option)

+ 11 - 5
src/permission.js

@@ -9,6 +9,7 @@ import getPageTitle from '@/utils/get-page-title'
 NProgress.configure({ showSpinner: false }) // NProgress Configuration
 
 const whiteList = ['/login', '/auth-redirect'] // no redirect whitelist
+const toSupplier = ['/supplier/list', '/supplier', '/supplier/add', '/supplier/edit']
 
 router.beforeEach(async(to, from, next) => {
   // start progress bar
@@ -19,17 +20,22 @@ router.beforeEach(async(to, from, next) => {
 
   // determine whether the user has logged in
   const hasToken = getToken()
-
   if (hasToken) {
+    if (toSupplier.includes(to.path)) {
+      store.dispatch('tagsView/delAllViews')
+      store.commit('user/SET_PROXY_INFO', null)
+      next()
+    }
     if (to.path === '/login') {
       // if is logged in, redirect to the home page
-      next({ path: '/' })
+      next()
       NProgress.done() // hack: https://github.com/PanJiaChen/vue-element-admin/pull/2939
     } else {
       // determine whether the user has obtained his permission roles through getInfo
       // const hasRoles = store.getters.roles && store.getters.roles.length > 0
+      // 加载国家列表
+      store.dispatch('app/setCountry')
       const hasInitRouter = store.getters.initRouter
-      console.log(store.getters.roles)
       if (hasInitRouter) {
         next()
       } else {
@@ -39,7 +45,6 @@ router.beforeEach(async(to, from, next) => {
           store.commit('permission/SET_INITROUTER', true)
           // generate accessible routes map based on roles
           const accessRoutes = await store.dispatch('permission/generateRoutes', store.getters.roles)
-          console.log(accessRoutes)
           // dynamically add accessible routes
           router.addRoutes(accessRoutes)
 
@@ -63,7 +68,8 @@ router.beforeEach(async(to, from, next) => {
       next()
     } else {
       // other pages that do not have permission to access are redirected to the login page.
-      next(`/login?redirect=${to.path}`)
+      next(`/login`)
+      Message.error('登录失效,请重新登录!')
       NProgress.done()
     }
   }

+ 10 - 5
src/router/index.js

@@ -75,6 +75,7 @@ export const constantRoutes = [
   {
     component: Layout,
     path: '/password',
+    name: 'Password',
     redirect: 'edit',
     hidden: true,
     meta: { title: '密码管理' },
@@ -82,6 +83,7 @@ export const constantRoutes = [
       {
         path: 'edit',
         component: () => import('@/views/password/index'),
+        name: 'Edit',
         meta: { title: '修改密码' }
       }
     ]
@@ -132,14 +134,16 @@ export const asyncRoutes = [
     component: Layout,
     alwaysShow: true,
     redirect: '/auth/list',
+    // hidden: 'true',
+    // hidden: store.getters.userIdentity === 1 ? 'true' : 'false',
     name: 'Auth',
-    meta: { title: '授权管理', icon: 'el-icon-s-promotion', roles: ['normal'], noCache: true },
+    meta: { title: '授权管理', icon: 'el-icon-s-promotion', roles: ['admin', 'normal'], noCache: true },
     children: [
       {
         path: 'list',
         component: () => import('@/views/supplier/auth/index'),
         name: 'AuthList',
-        meta: { title: '授权列表', icon: 'el-icon-menu', roles: ['normal'], noCache: true }
+        meta: { title: '授权列表', icon: 'el-icon-menu', roles: ['admin', 'normal'], noCache: true, affix: true }
       }
     ]
   },
@@ -149,11 +153,12 @@ export const asyncRoutes = [
     component: Layout,
     alwaysShow: true,
     redirect: '/product/list',
-    // hidden: true,
+    hidden: true,
     name: 'Auth',
     meta: { title: '商品管理', icon: 'el-icon-s-shop', roles: ['admin', 'normal'], noCache: true },
     children: [
       {
+        hidden: true,
         path: 'list',
         component: () => import('@/views/supplier/product/index'),
         name: 'Product',
@@ -164,14 +169,14 @@ export const asyncRoutes = [
         path: 'add',
         component: () => import('@/views/supplier/product/add'),
         name: 'AddProduct',
-        meta: { title: '添加商品', icon: 'el-icon-menu', roles: ['admin', 'normal'], noCache: true }
+        meta: { title: '添加商品', icon: 'el-icon-menu', roles: ['admin', 'normal'], noCache: false }
       },
       {
         hidden: true,
         path: 'edit',
         component: () => import('@/views/supplier/product/edit'),
         name: 'EditProduct',
-        meta: { title: '修改商品', icon: 'el-icon-menu', roles: ['admin', 'normal'], noCache: true }
+        meta: { title: '修改商品', icon: 'el-icon-menu', roles: ['admin', 'normal'], noCache: false }
       }
     ]
   },

+ 4 - 1
src/store/getters.js

@@ -1,7 +1,9 @@
 const getters = {
   sidebar: state => state.app.sidebar,
   size: state => state.app.size,
+  countryList: state => state.app.countryList,
   device: state => state.app.device,
+  isRefresh: state => state.app.isRefresh,
   visitedViews: state => state.tagsView.visitedViews,
   cachedViews: state => state.tagsView.cachedViews,
   token: state => state.user.token,
@@ -11,6 +13,7 @@ const getters = {
   userIdentity: state => state.user.userIdentity,
   permission_routes: state => state.permission.routes,
   errorLogs: state => state.errorLog.logs,
-  initRouter: state => state.permission.initRouter
+  initRouter: state => state.permission.initRouter,
+  proxyInfo: state => state.user.proxyInfo
 }
 export default getters

+ 18 - 1
src/store/modules/app.js

@@ -1,4 +1,5 @@
 import Cookies from 'js-cookie'
+import { getCountry } from '@/api/common'
 
 const state = {
   sidebar: {
@@ -6,7 +7,9 @@ const state = {
     withoutAnimation: false
   },
   device: 'desktop',
-  size: Cookies.get('size') || 'medium'
+  size: Cookies.get('size') || 'medium',
+  countryList: [],
+  isRefresh: true
 }
 
 const mutations = {
@@ -30,6 +33,13 @@ const mutations = {
   SET_SIZE: (state, size) => {
     state.size = size
     Cookies.set('size', size)
+  },
+  // 获取国家列表
+  SET_COUNTRY: (state, list) => {
+    state.countryList = list
+  },
+  SET_IS_REFRESH: (state, flag) => {
+    state.isRefresh = flag
   }
 }
 
@@ -45,6 +55,13 @@ const actions = {
   },
   setSize({ commit }, size) {
     commit('SET_SIZE', size)
+  },
+  setCountry({ commit }) {
+    getCountry().then(res => {
+      if (res.code === 0) {
+        commit('SET_COUNTRY', res.data)
+      }
+    })
   }
 }
 

+ 12 - 4
src/store/modules/permission.js

@@ -55,12 +55,20 @@ const actions = {
     return new Promise(resolve => {
       let accessedRoutes = []
       // 开启后admin可以访问所有的路由
+      // if (roles.includes('admin')) {
+      //   accessedRoutes = asyncRoutes || []
+      // } else {
+      //   accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
+      // }
+      accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
       if (roles.includes('admin')) {
-        accessedRoutes = asyncRoutes || []
-      } else {
-        accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
+        accessedRoutes.forEach((item, index) => {
+          if (item.name === 'Auth') {
+            item.hidden = 'true'
+            item.children[0].meta.affix = false
+          }
+        })
       }
-      // accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
       commit('SET_ROUTES', accessedRoutes)
       resolve(accessedRoutes)
     })

+ 9 - 3
src/store/modules/user.js

@@ -1,7 +1,6 @@
 import { login } from '@/api/user'
 import { getToken, setToken, removeToken, setUser, getUser, removeUser } from '@/utils/auth'
 import { resetRouter } from '@/router'
-// console.log(getUser())
 const userInfo = getUser() && JSON.parse(getUser())
 
 function formatRoles(userIdentity) {
@@ -23,7 +22,8 @@ const state = {
   roles: formatRoles(userInfo?.userIdentity),
   shopStatus: userInfo?.shopStatus || '',
   authUserId: userInfo?.authUserId || '',
-  userIdentity: userInfo?.userIdentity || ''
+  userIdentity: userInfo?.userIdentity || '',
+  proxyInfo: null
 }
 
 const mutations = {
@@ -40,6 +40,9 @@ const mutations = {
     state.shopStatus = userInfo.shopStatus
     state.authUserId = userInfo.authUserId
     state.userIdentity = userInfo.userIdentity
+  },
+  SET_PROXY_INFO: (state, proxyInfo) => {
+    state.proxyInfo = proxyInfo
   }
 }
 
@@ -49,15 +52,16 @@ const actions = {
     const { username, password } = userInfo
     return new Promise((resolve, reject) => {
       login({ mobileOrName: username.trim(), password: password }).then(response => {
-        console.log(response)
         const { shopStatus, token, authUserId, userIdentity, name } = response.data
         const roles = formatRoles(userIdentity)
         commit('SET_TOKEN', token) // 保存token
         commit('SET_USERINFO', { shopStatus, authUserId, userIdentity }) // 保存用户信息
         commit('SET_ROLES', roles) // 根据用户类型生成角色列表
         commit('SET_NAME', name) // 保存用户名称
+        // commit('app/SET_IS_REFRESH', false)
         setToken(token) // cokies保存token
         setUser(response.data) // cokies保存当前用户信息
+        console.log(response)
         resolve()
       }).catch(error => {
         reject(error)
@@ -69,6 +73,8 @@ const actions = {
   logout({ commit, state, dispatch }) {
     commit('SET_TOKEN', '') // 重置token
     commit('SET_ROLES', []) // 重置角色权限表
+    commit('SET_PROXY_INFO', null)
+    commit('SET_NAME', '')
     removeToken() // 从cokies中移除token
     resetRouter() // 重置路由
     removeUser() // 从cokies中移除用户信息

+ 4 - 0
src/styles/index.css

@@ -659,3 +659,7 @@ aside a:hover {
 .status.danger {
   color: #F56C6C;
 }
+
+.hidden .el-upload {
+  display: none !important;
+}

Fichier diff supprimé car celui-ci est trop grand
+ 0 - 0
src/styles/index.min.css


+ 7 - 0
src/styles/index.scss

@@ -200,3 +200,10 @@ aside {
     color: #F56C6C;
   }
 }
+
+
+.hidden {
+  .el-upload {
+    display: none !important;
+  }
+}

+ 11 - 0
src/utils/index.js

@@ -1,7 +1,18 @@
+import moment from 'moment'
 /**
  * Created by PanJiaChen on 16/11/18.
  */
 
+/**
+ * Parse the time to string
+ * @param {(Object|string|number)} time
+ * @param {string} cFormat
+ * @returns {string | null}
+ */
+export function formatDate(time, cFormat) {
+  return moment(time).format(cFormat)
+}
+
 /**
  * Parse the time to string
  * @param {(Object|string|number)} time

+ 10 - 3
src/utils/request.js

@@ -2,6 +2,7 @@ import axios from 'axios'
 import { Message } from 'element-ui'
 import store from '@/store'
 import { getToken } from '@/utils/auth'
+import router from '@/router'
 
 // create an axios instance
 const service = axios.create({
@@ -14,8 +15,8 @@ const service = axios.create({
 service.interceptors.request.use(
   config => {
     // do something before request is sent
-    // config.headers['Content-Type'] = 'application/json'
-    // config.data = JSON.stringify(config.data)
+    config.headers['Content-Type'] = 'application/json'
+    config.data = JSON.stringify(config.data)
     if (store.getters.token) {
       // let each request carry token
       // ['X-Token'] is a custom headers key
@@ -46,7 +47,13 @@ service.interceptors.response.use(
   response => {
     const res = response.data
 
-    // if the custom code is not 20000, it is judged as an error.
+    // token失效时
+    if (res.code === -99) {
+      Message({ message: '登录失效,请重新登录!' })
+      router.replace('/login')
+    }
+
+    // 返回不成功
     if (res.code !== 0) {
       Message({
         message: res.msg || 'Error',

+ 19 - 0
src/utils/validate.js

@@ -55,6 +55,15 @@ export function validEmail(email) {
   return reg.test(email)
 }
 
+/**
+ * @param {String} arg
+ * @returns {Boolean}
+ */
+export function validPassword(password) {
+  const reg = /^[a-z|A-Z|0-9]{8,12}$/
+  return reg.test(password)
+}
+
 /**
  * @param {string} str
  * @returns {Boolean}
@@ -85,3 +94,13 @@ export function isMobile(arg) {
   const reg = /^(13[0-9]|14[5|7]|15[0|1|2|3|4|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$/
   return reg.test(arg)
 }
+
+/**
+ * @param {String} arg
+ * @returns {Boolean}
+ */
+export function isSnCode(arg) {
+  const reg = /^[a-z|A-Z|0-9]+$/
+  return reg.test(arg)
+}
+

+ 5 - 5
src/views/error-page/404.vue

@@ -8,13 +8,13 @@
         <img class="pic-404__child right" src="@/assets/404_images/404_cloud.png" alt="404">
       </div>
       <div class="bullshit">
-        <div class="bullshit__oops">OOPS!</div>
-        <div class="bullshit__info">All rights reserved
+        <div class="bullshit__oops">NO RIGHTS!</div>
+        <!-- <div class="bullshit__info">All rights reserved
           <a style="color:#20a0ff" href="https://wallstreetcn.com" target="_blank">wallstreetcn</a>
-        </div>
+        </div> -->
         <div class="bullshit__headline">{{ message }}</div>
         <div class="bullshit__info">Please check that the URL you entered is correct, or click the button below to return to the homepage.</div>
-        <a href="javascript:void(0)" class="bullshit__return-home" @click="$_back()">Back to home</a>
+        <a href="javascript:void(0)" class="bullshit__return-home" @click="$_back()">返回首页</a>
       </div>
     </div>
   </div>
@@ -26,7 +26,7 @@ export default {
   name: 'Page404',
   computed: {
     message() {
-      return 'The webmaster said that you can not enter this page...'
+      return '您无权访问该页面...'
     }
   }
 }

+ 7 - 4
src/views/login/index.vue

@@ -86,6 +86,10 @@ export default {
   },
   created() {
     // window.addEventListener('storage', this.afterQRScan)
+    const isRefresh = this.$store.getters.isRefresh
+    if (!isRefresh) {
+      window.location.reload()
+    }
   },
   mounted() {
     if (this.loginForm.username === '') {
@@ -114,21 +118,20 @@ export default {
     },
     handleLogin() {
       this.$refs.loginForm.validate(valid => {
-        console.log(valid)
         if (valid) {
           this.loading = true
           this.$store.dispatch('user/login', this.loginForm)
             .then(() => {
-              // this.$router.push({ path: this.redirect || '/', query: this.otherQuery })
-              this.$router.push('/')
+              const isAdmin = this.$store.getters.userIdentity === 1
+              isAdmin ? this.$router.push('/supplier/list') : this.$router.push('/auth/list')
               this.loading = false
               this.$message.success('登录成功')
+              this.$store.commit('app/SET_IS_REFRESH', false)
             })
             .catch(() => {
               this.loading = false
             })
         } else {
-          console.log('字段校验未通过')
           return false
         }
       })

+ 12 - 4
src/views/password/index.vue

@@ -20,9 +20,10 @@
 
 <script>
 import { modifyPassword } from '@/api/user'
+import { validPassword } from '@/utils/validate'
 export default {
   data() {
-    var validatePass = (rule, value, callback) => {
+    var confirmPassword = (rule, value, callback) => {
       if (value === '') {
         callback(new Error('请再次输入密码'))
       } else if (value !== this.formData.newPassword) {
@@ -31,6 +32,13 @@ export default {
         callback()
       }
     }
+    var validPwd = (rule, value, callback) => {
+      if (!validPassword(value)) {
+        callback(new Error('请输入字母与数字组合的8-12位密码'))
+      } else {
+        callback()
+      }
+    }
     return {
       formData: {
         oldPassword: '',
@@ -39,13 +47,13 @@ export default {
       },
       formRules: {
         oldPassword: [
-          { required: true, message: '请输入原来的密码', trigger: 'blur' }
+          { required: true, message: '请输入原来的密码', trigger: 'change' }
         ],
         newPassword: [
-          { required: true, message: '请输入新密码', trigger: 'blur' }
+          { required: true, trigger: 'change', validator: validPwd }
         ],
         confirmPwd: [
-          { validator: validatePass, trigger: 'blur' }
+          { validator: confirmPassword, trigger: 'change' }
         ]
       }
     }

+ 129 - 25
src/views/supplier/auth/index.vue

@@ -3,8 +3,8 @@
     <div class="filter-container">
       <span>授权机构:</span>
       <el-input v-model="listQuery.authParty" placeholder="授权机构" style="width: 280px;" class="filter-item" @keyup.enter.native="handleFilter" />
-      <el-button type="primary">查询</el-button>
-      <el-button type="primary" @click="showAddAuthDialog = true">添加品牌授权</el-button>
+      <el-button type="primary" @click="getList">查询</el-button>
+      <el-button v-if="userIdentity === 2 || proxyInfo!==null" type="primary" @click="handleShowEditDialog('添加品牌授权')">添加品牌授权</el-button>
     </div>
     <!-- 表格区域 -->
     <el-table
@@ -24,23 +24,35 @@
 
       <el-table-column label="授权机构" align="center" prop="authParty" />
 
-      <el-table-column label="授权状态" width="140px" align="center" prop="status">
-        <template v-slot="{row}">
-          <el-switch v-model="row.status" @change="handleChangeStatus(row)" />
+      <el-table-column v-if="userIdentity===2 || proxyInfo!==null" label="上线状态" width="140px" align="center">
+        <template slot-scope="{row}">
+          <i v-if="row.status === 1" class="el-icon-circle-check status success" @click="handleChangeStatus(row)" />
+          <i v-if="row.status === 0" class="el-icon-circle-close status danger" @click="handleChangeStatus(row)" />
         </template>
+        <!-- <template v-slot="{row}">
+          <el-switch v-model="row.status" @change="handleChangeStatus(row)" />
+        </template> -->
       </el-table-column>
 
       <el-table-column label="创建时间" class-name="status-col" width="360px">
         <template slot-scope="{row}">
-          <span>{{ row.createTime | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
+          <span>{{ row.createTime | formatTime }}</span>
         </template>
       </el-table-column>
 
       <el-table-column label="创建人" class-name="status-col" width="160px" prop="createBy" />
 
-      <el-table-column label="操作" align="center" width="160px" class-name="small-padding fixed-width">
-        <template>
-          <el-button type="primary" size="mini" @click="$_navigationTo('/product')">
+      <el-table-column label="操作" align="center" width="240px" class-name="small-padding fixed-width">
+        <template slot-scope="{row}">
+          <template v-if="userIdentity === 2|| proxyInfo!==null">
+            <el-button type="info" size="mini" @click="handleShowEditDialog('添加品牌授权',row)">
+              编辑
+            </el-button>
+            <el-button type="danger" size="mini" @click="handleRemoveAuth(row)">
+              删除
+            </el-button>
+          </template>
+          <el-button type="primary" size="mini" @click="$_navigationTo(`/product?id=${row.authId}`)">
             商品列表
           </el-button>
         </template>
@@ -52,17 +64,17 @@
 
     <!-- 对话框区域 -->
     <el-dialog
-      title="添加品牌授权"
+      :title="dialogTitle"
       :visible.sync="showAddAuthDialog"
       width="30%"
       @close="dialogClosed"
     >
       <el-form ref="addAuthForm" :rules="addAuthFormRules" :model="addAuthFormData" label-width="100px">
-        <el-form-item label="授权机构:" prop="name">
-          <el-input v-model="addAuthFormData.name" placeholder="请输入授权机构名称" />
+        <el-form-item label="授权机构:" prop="authParty">
+          <el-input v-model="addAuthFormData.authParty" placeholder="请输入授权机构名称" />
         </el-form-item>
         <el-form-item label="上架状态:">
-          <el-select v-model="addAuthFormData.state">
+          <el-select v-model="addAuthFormData.status">
             <el-option label="上架" :value="1" />
             <el-option label="下架" :value="0" />
           </el-select>
@@ -70,19 +82,28 @@
       </el-form>
       <span slot="footer" class="dialog-footer">
         <el-button @click="showAddAuthDialog = false">取 消</el-button>
-        <el-button type="primary" @click="showAddAuthDialog = false">确 定</el-button>
+        <el-button type="primary" :disabled="disabled" @click="handleUpdateBrandAuth">确 定</el-button>
       </span>
     </el-dialog>
   </div>
 </template>
 
 <script>
-import { fecthAuthList } from '@/api/auth'
+import { fecthAuthList, saveBrandAuth, changeAuthStatus, removeAuth } from '@/api/auth'
 import Pagination from '@/components/Pagination' // secondary package based on el-pagination
-
+import { mapGetters } from 'vuex'
+import { formatDate } from '@/utils'
 export default {
   name: 'ComplexTable',
   components: { Pagination },
+  filters: {
+    formatTime(time) {
+      if (!time) {
+        return ''
+      }
+      return formatDate(time, 'yyyy-MM-DD hh:mm:ss')
+    }
+  },
   data() {
     return {
       tableKey: 0,
@@ -98,18 +119,27 @@ export default {
       },
       // 添加品牌授权
       showAddAuthDialog: false, // 显示添加供应商对话框
+      dialogTitle: '',
       addAuthFormData: {
-        name: '',
-        state: 1
+        authId: '', // 授权id
+        authUserId: '', // 供应商用户id
+        authParty: '', // 授权机构
+        createBy: '', // 创建人id
+        status: 1 // 授权状态 0下架,1上架
       },
       addAuthFormRules: {
-        name: [
+        authParty: [
           { required: true, message: '请输入授权机构名称', trigger: 'blur' }
         ]
-      }
+      },
+      disabled: false
     }
   },
+  computed: {
+    ...mapGetters(['authUserId', 'userIdentity', 'proxyInfo'])
+  },
   created() {
+    this.listQuery.authUserId = this.$route.query.id || this.proxyInfo?.authUserId || this.authUserId
     this.getList()
   },
   methods: {
@@ -120,9 +150,8 @@ export default {
         if (response.code !== 0) {
           return this.$message.error('授权列表信息获取失败')
         }
-        console.log(response)
         const { list, total } = response.data
-        this.formatList(list)
+        // this.formatList(list)
         this.list = list
         this.total = total
       }).catch(err => {
@@ -132,6 +161,51 @@ export default {
         this.listLoading = false
       })
     },
+    // 添加授权
+    handleUpdateBrandAuth() {
+      this.$refs.addAuthForm.validate(valide => {
+        if (valide) {
+          this.disabled = true
+          this.listLoading = true
+          // authUserId先判断是否为代理操作,是就从代理数据中获取,否则直接获取当前登录用户的信息
+          this.addAuthFormData.authUserId = this.$route.query.id || this.proxyInfo?.authUserId || this.authUserId
+          this.addAuthFormData.createBy = this.addAuthFormData.authUserId
+          saveBrandAuth(this.addAuthFormData).then(res => {
+            this.getList()
+            this.$message.success(res.data)
+          }).catch(err => {
+            console.log(err)
+            this.$message.danger('操作失败')
+          }).finally(() => {
+            this.showAddAuthDialog = false
+            this.listLoading = false
+            this.disabled = false
+          })
+        }
+      })
+    },
+    // 删除品牌授权
+    async handleRemoveAuth(item) {
+      const text = await this.$confirm('此操作将删除该授权机构, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).catch(() => {
+        this.$message.info('已取消操作')
+      })
+      if (text !== 'confirm') return
+      // 要执行的操作
+      this.listLoading = true
+      removeAuth({	authId: item.authId }).then(res => {
+        this.$message.success(res.data)
+      }).catch(err => {
+        this.$message.danger('删除失败')
+        console.log(err)
+      }).finally(() => {
+        this.listLoading = false
+        this.getList()
+      })
+    },
     // 格式化列表数据
     formatList(list = []) {
       list.forEach(i => {
@@ -140,11 +214,24 @@ export default {
     },
     // 供应商状态改变
     handleChangeStatus(item) {
+      if (this.userIdentity !== 2 && this.proxyInfo === null) return
+      this.listLoading = true
+      // const params = {
+      //   authId: item.authId,
+      //   status: item.status ? 1 : 0
+      // }
       const params = {
-        shopStatus: item.shopStatus ? 1 : 0,
-        authUserId: item.authUserId
+        authId: item.authId,
+        status: item.status === 1 ? 0 : 1
       }
-      console.log(params)
+      changeAuthStatus(params).then(res => {
+        this.$message.success(res.data)
+        this.getList()
+      }).catch(err => {
+        console.log(err)
+      }).finally(() => {
+        this.listLoading = false
+      })
     },
     // 过滤列表
     handleFilter() {
@@ -157,7 +244,24 @@ export default {
     },
     // 对话框关闭事件
     dialogClosed() {
+      this.addAuthFormData.authId = ''
       this.$refs.addAuthForm.resetFields()
+    },
+    handleShowEditDialog(title, data) {
+      this.dialogTitle = title
+      if (data) {
+        // authId: '', // 授权id
+        // authUserId: '', // 供应商用户id
+        // authParty: '', // 授权机构
+        // createBy: '', // 创建人id
+        // status: 1
+        this.addAuthFormData.authId = data.authId
+        this.addAuthFormData.authUserId = data.authUserId
+        this.addAuthFormData.authParty = data.authParty
+        this.addAuthFormData.createBy = data.createBy
+        this.status = data.status
+      }
+      this.showAddAuthDialog = true
     }
   }
 }

+ 21 - 10
src/views/supplier/components/uploadFile.vue

@@ -1,18 +1,19 @@
 <template>
   <div>
     <el-upload
-      ref="uploadFile"
+      ref="upload"
       class="upload-demo"
-      drag
-      :action="action"
-      multiple
       :limit="1"
       :data="params"
+      :action="action"
+      :file-list="fileList"
+      :auto-upload="false"
       :on-success="success"
+      :accept="accept"
     >
-      <i class="el-icon-upload" />
-      <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
-      <!-- <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div> -->
+      <el-button slot="trigger" size="mini" type="primary">选取文件</el-button>
+      <el-button style="margin-left: 10px;" size="mini" type="success" @click="uploadFile">上传</el-button>
+      <div slot="tip" class="el-upload__tip">只能上传.doc/.ppt/.pdf文件,且不超过1MB</div>
     </el-upload>
   </div>
 </template>
@@ -20,10 +21,17 @@
 <script>
 
 export default {
+  props: {
+    fileList: {
+      type: Array,
+      default: () => []
+    }
+  },
   data() {
     return {
       // 图片上传接口
-      action: process.env.VUE_APP_BASE_API + '/shop/upload/file',
+      action: process.env.VUE_APP_UPLOAD_API + '/shop/upload/file',
+      accept: '.doc,.ppt,.pdf',
       // 请求参数
       params: {
         authUserId: this.$store.getters.authUserId
@@ -31,11 +39,14 @@ export default {
     }
   },
   methods: {
-    success(response, file, fileList) {
-      this.$emit('success', response, file, fileList)
+    success(response) {
+      this.$emit('success', response)
     },
     error(err, file, fileList) {
       this.$emit('error', err, file, fileList)
+    },
+    uploadFile() {
+      this.$refs.upload.submit()
     }
   }
 }

+ 15 - 20
src/views/supplier/components/uploadImage.vue

@@ -5,12 +5,12 @@
       :action="action"
       list-type="picture-card"
       :on-preview="handlePictureCardPreview"
-      :on-remove="handleRemove"
       :before-upload="beforeUpload"
       :limit="1"
       :accept="accept"
-      :class="{hidden:isChooesed}"
       :auto-upload="true"
+      :on-success="success"
+      :file-list="fileList"
     >
       <i class="el-icon-plus" />
     </el-upload>
@@ -23,35 +23,39 @@
 <script>
 // import { uploadImage } from '@/api/upload'
 export default {
+  props: {
+    fileList: {
+      type: Array,
+      default: () => []
+    }
+  },
   data() {
     return {
-      isChooesed: false, // 是否上选择了图片
       dialogImageUrl: '',
       dialogVisible: false,
       // 文件上传请求接口
-      action: process.env.VUE_APP_BASE_API + '/upload/image',
-      // action: 'https://d1fd53a1-a1f9-41a8-90e0-e9e54a0e00ba.bspapp.com/http/upload',
+      action: process.env.VUE_APP_UPLOAD_API + '/upload/image',
       accept: '.jpg,.png,.gif'
     }
   },
   methods: {
-    handleRemove(file, fileList) {
-      console.log(file, fileList)
-    },
+    // 预览图片
     handlePictureCardPreview(file) {
       this.dialogImageUrl = file.url
       this.dialogVisible = true
     },
+    // 图片上传成功
     success(response, file, fileList) {
-      this.$emit('success', response, file, fileList)
-      this.isChooesed = true
+      this.$emit('success', response)
     },
+    // 图片上传失败
     error(err, file, fileList) {
       this.$emit('error', err, file, fileList)
     },
+    // 图片上传之前的钩子
     beforeUpload(file) {
       const size = file.size
-      if (size > 1024) {
+      if (size > 1024 * 1000) {
         this.$message.warning('文件上传大小超出限制(≤1MB)')
         return false
       }
@@ -59,12 +63,3 @@ export default {
   }
 }
 </script>
-
-<style lang="scss" scoped>
-.hidden {
-  .el-upload {
-    display: none !important;
-  }
-}
-</style>
-

+ 174 - 41
src/views/supplier/product/add.vue

@@ -1,46 +1,65 @@
 <template>
-  <div class="addProduct">
-    <el-form ref="addFormRef" label-width="120px" class="addForm">
-      <el-form-item label="商品名称:">
-        <el-input placeholder="请输入商品名称" />
+  <div v-loading="isLoading" class="addProduct">
+    <el-form
+      ref="addFormRef"
+      label-width="120px"
+      class="addForm"
+      :model="formData"
+      :rules="rules"
+    >
+      <el-form-item label="商品名称:" prop="productName">
+        <el-input v-model="formData.productName" placeholder="请输入商品名称" />
       </el-form-item>
-      <el-form-item label="商品SN码:">
-        <el-input placeholder="请输入商品SN码" />
+      <el-form-item label="商品SN码:" prop="snCode">
+        <el-input v-model="formData.snCode" placeholder="请输入商品SN码" />
       </el-form-item>
-      <el-form-item label="商品图片:">
-        <upload-image />
+      <el-form-item label="商品图片:" prop="productImage">
+        <upload-image ref="uploadImageRef2" @success="imageUploadSuccess1" />
+        <el-input v-model="formData.productImage" class="hiddenInput" />
       </el-form-item>
-      <el-form-item label="授权牌:">
-        <upload-image />
+      <el-form-item label="授权牌:" prop="certificateImage">
+        <upload-image ref="uploadImageRef2" @success="imageUploadSuccess2" />
+        <el-input v-model="formData.certificateImage" class="hiddenInput" />
       </el-form-item>
-      <el-form-item label="相关参数:">
-        <div class="form-group">
-          <el-input class="param-title" placeholder="例如:品牌" />
-          <el-input class="param-info" placeholder="请输入参数信息" />
+      <el-form-item label="相关参数:" prop="paramList">
+        <div
+          v-for="(item, index) in formData.paramList"
+          :key="index"
+          class="form-group paramsItem"
+        >
+          <el-input
+            v-model="item.paramName"
+            class="param-title"
+            placeholder="例如:品牌"
+            maxlength="10"
+          />
+          <el-input
+            v-model="item.paramContent"
+            class="param-info"
+            placeholder="请输入参数信息"
+            maxlength="50"
+          />
+          <span v-if="paramsCount>4" class="closed el-icon-close" @click="handleRemoveParam(index)" />
         </div>
-        <div class="form-group">
-          <el-input class="param-title" placeholder="例如:尺寸" />
-          <el-input class="param-info" placeholder="请输入参数信息" />
-        </div>
-        <div class="form-group">
-          <el-input class="param-title" placeholder="例如:功率" />
-          <el-input class="param-info" placeholder="请输入参数信息" />
-        </div>
-        <div class="form-group">
-          <el-input class="param-title" placeholder="例如:型号" />
-          <el-input class="param-info" placeholder="请输入参数信息" />
-        </div>
-        <el-button type="primary" size="mini">添加参数</el-button>
+        <el-button
+          type="primary"
+          size="mini"
+          @click="handleAddParam"
+        >添加参数</el-button>
       </el-form-item>
       <el-form-item label="上架状态:">
-        <el-select placeholder="产地" style="width:100%">
-          <el-option label="上架" />
-          <el-option label="下架" />
+        <el-select
+          v-model="formData.status"
+          placeholder="上架状态"
+          style="width: 100%"
+        >
+          <el-option label="上架" :value="1" />
+          <el-option label="下架" :value="0" />
         </el-select>
       </el-form-item>
     </el-form>
     <div class="submit-btn">
-      <el-button type="primary">保存</el-button>
+      <el-button type="primary" @click="submit">保存</el-button>
       <el-button type="warning" @click="$_back()">返回</el-button>
     </div>
   </div>
@@ -48,39 +67,153 @@
 
 <script>
 import UploadImage from '../components/uploadImage'
+import { saveProduct } from '@/api/product'
+import { mapGetters } from 'vuex'
+import { isSnCode } from '@/utils/validate'
 export default {
   components: { UploadImage },
   data() {
+    const valideSNcode = (rules, value, callback) => {
+      if (!isSnCode(value)) {
+        return callback(new Error('只能是字母+数字组合'))
+      }
+      callback()
+    }
     return {
-      statement: 1
+      isLoading: false,
+      paramsCount: 4,
+      formData: {
+        authId: '', //	授权id
+        certificateImage: '', //	授权牌照
+        createBy: '', //	创建人id
+        // 	商品参数列表
+        paramList: [],
+        productId: '', //	授权商品id
+        productImage: '', //	商品图片
+        productName: '', //	商品名称
+        snCode: '', //	商品SN码
+        status: 1 //	上架状态:0下架,1上架
+      },
+      rules: {
+        certificateImage: [{ required: true, message: '授权牌照不能为空' }],
+        paramList: [{ required: true, message: '参数不能为空' }],
+        productImage: [{ required: true, message: '商品图片不能为空' }],
+        snCode: [{ required: true, message: 'SN码不能为空' }, { validator: valideSNcode }],
+        productName: [{ required: true, message: '商品名称不能为空' }, { max: 50, message: '字数在50字符以内' }]
+      }
+    }
+  },
+  computed: {
+    ...mapGetters(['authUserId', 'proxyInfo'])
+  },
+  created() {
+    this.formData.authId = this.$route.query.id
+    this.initParamList()
+  },
+  methods: {
+    // 提交
+    submit() {
+      this.$refs.addFormRef.validate(valide => {
+        if (valide) {
+          this.save()
+        }
+      })
+    },
+    // 保存表单数据
+    save() {
+      this.isLoading = true
+      // createBy先判断是否为代理操作,是就从代理数据中获取,否则直接获取当前登录用户的信息
+      this.formData.createBy = this.proxyInfo?.authUserId || this.authUserId
+      saveProduct(this.formData).then(res => {
+        this.$message.success(res.data)
+        this.$refs.addFormRef.resetFields()
+        this.clearFormData()
+      }).finally(() => {
+        this.isLoading = false
+      })
+    },
+    // 初始化参数列表
+    initParamList() {
+      for (let i = 0; i < this.paramsCount; i++) {
+        this.formData.paramList.push({
+          paramContent: '',
+          paramName: ''
+        })
+      }
+    },
+    // 添加一栏参数
+    handleAddParam() {
+      this.paramsCount += 1
+      this.formData.paramList.push({
+        paramContent: '',
+        paramName: ''
+      })
+    },
+    // 删除一栏参数
+    handleRemoveParam(index) {
+      this.paramsCount -= 1
+      this.formData.paramList.splice(index, 1)
+    },
+    // 图片上传成功 产品图片
+    imageUploadSuccess1(data) {
+      this.formData.productImage = data.data
+    },
+    // 图片上传成功 授权牌照
+    imageUploadSuccess2(data) {
+      this.formData.certificateImage = data.data
+    },
+    clearFormData() {
+      this.formData.paramList = []
+      this.paramsCount = 4
+      this.initParamList()
     }
   }
 }
 </script>
 
 <style lang="scss" scoped>
-.addProduct{
+.addProduct {
   margin-bottom: 80px;
-  .form-group{
+  .form-group {
     margin-bottom: 2%;
-    .param-title{
+    .param-title {
       width: 30%;
     }
-    .param-info{
+    .param-info {
       width: 68%;
       margin-left: 2%;
     }
   }
 }
-.addForm{
+.addForm {
   width: 500px;
   margin: 0 auto;
   margin-top: 80px;
 }
-.submit-btn{
-    text-align: center;
-    .el-button{
-      width:140px;
+.submit-btn {
+  text-align: center;
+  .el-button {
+    width: 140px;
+  }
+}
+.paramsItem{
+  position: relative;
+  .closed{
+    position: absolute;
+    top: 50%;
+    transform: translateY(-50%);
+    right: -20px;
+    cursor: pointer;
+    color: #ddd;
+    &:hover{
+      color: #333;
     }
   }
+
+}
+ .hiddenInput{
+    height: 0;
+    display: none;
+  }
+
 </style>

+ 194 - 41
src/views/supplier/product/edit.vue

@@ -1,46 +1,65 @@
 <template>
-  <div class="addProduct">
-    <el-form ref="addFormRef" label-width="120px" class="addForm">
-      <el-form-item label="商品名称:">
-        <el-input placeholder="请输入商品名称" />
+  <div v-loading="isLoading" class="addProduct">
+    <el-form
+      ref="addFormRef"
+      label-width="120px"
+      class="addForm"
+      :model="formData"
+      :rules="rules"
+    >
+      <el-form-item label="商品名称:" prop="productName">
+        <el-input v-model="formData.productName" placeholder="请输入商品名称" />
       </el-form-item>
-      <el-form-item label="商品SN码:">
-        <el-input placeholder="请输入商品SN码" />
+      <el-form-item label="商品SN码:" prop="snCode">
+        <el-input v-model="formData.snCode" placeholder="请输入商品SN码" />
       </el-form-item>
-      <el-form-item label="商品图片:">
-        <upload-image />
+      <el-form-item label="商品图片:" prop="productImage">
+        <upload-image ref="uploadImageRef2" :file-list="fileList1" @success="imageUploadSuccess1" />
+        <el-input v-model="formData.productImage" class="hiddenInput" />
       </el-form-item>
-      <el-form-item label="授权牌:">
-        <upload-image />
+      <el-form-item label="授权牌:" prop="certificateImage">
+        <upload-image ref="uploadImageRef2" :file-list="fileList2" @success="imageUploadSuccess2" />
+        <el-input v-model="formData.certificateImage" class="hiddenInput" />
       </el-form-item>
-      <el-form-item label="相关参数:">
-        <div class="form-group">
-          <el-input class="param-title" placeholder="例如:品牌" />
-          <el-input class="param-info" placeholder="请输入参数信息" />
+      <el-form-item label="相关参数:" prop="paramList">
+        <div
+          v-for="(item, index) in formData.paramList"
+          :key="index"
+          class="form-group paramsItem"
+        >
+          <el-input
+            v-model="item.paramName"
+            class="param-title"
+            placeholder="例如:品牌"
+            maxlength="10"
+          />
+          <el-input
+            v-model="item.paramContent"
+            class="param-info"
+            placeholder="请输入参数信息"
+            maxlength="50"
+          />
+          <span v-if="paramsCount>4" class="closed el-icon-close" @click="handleRemoveParam(index)" />
         </div>
-        <div class="form-group">
-          <el-input class="param-title" placeholder="例如:尺寸" />
-          <el-input class="param-info" placeholder="请输入参数信息" />
-        </div>
-        <div class="form-group">
-          <el-input class="param-title" placeholder="例如:功率" />
-          <el-input class="param-info" placeholder="请输入参数信息" />
-        </div>
-        <div class="form-group">
-          <el-input class="param-title" placeholder="例如:型号" />
-          <el-input class="param-info" placeholder="请输入参数信息" />
-        </div>
-        <el-button type="primary" size="mini">添加参数</el-button>
+        <el-button
+          type="primary"
+          size="mini"
+          @click="handleAddParam"
+        >添加参数</el-button>
       </el-form-item>
       <el-form-item label="上架状态:">
-        <el-select placeholder="产地" style="width:100%">
-          <el-option label="上架" />
-          <el-option label="下架" />
+        <el-select
+          v-model="formData.status"
+          placeholder="上架状态"
+          style="width: 100%"
+        >
+          <el-option label="上架" :value="1" />
+          <el-option label="下架" :value="0" />
         </el-select>
       </el-form-item>
     </el-form>
     <div class="submit-btn">
-      <el-button type="primary">保存</el-button>
+      <el-button type="primary" @click="submit">保存</el-button>
       <el-button type="warning" @click="$_back()">返回</el-button>
     </div>
   </div>
@@ -48,39 +67,173 @@
 
 <script>
 import UploadImage from '../components/uploadImage'
+import { saveProduct, getProductById } from '@/api/product'
+import { mapGetters } from 'vuex'
 export default {
   components: { UploadImage },
   data() {
     return {
-      statement: 1
+      isLoading: false,
+      paramsCount: 4,
+      formData: {
+        authId: '', //	授权id
+        certificateImage: '', //	授权牌照
+        createBy: '', //	创建人id
+        // 	商品参数列表
+        paramList: [],
+        productId: '', //	授权商品id
+        productImage: '', //	商品图片
+        productName: '', //	商品名称
+        snCode: '', //	商品SN码
+        status: 1 //	上架状态:0下架,1上架
+      },
+      rules: {
+        certificateImage: [{ required: true, message: '授权牌照不能为空' }],
+        paramList: [{ required: true, message: '参数不能为空' }],
+        productImage: [{ required: true, message: '商品图片不能为空' }],
+        snCode: [{ required: true, message: 'SN码不能为空' }],
+        productName: [{ required: true, message: '商品名称不能为空' }, { max: 50, message: '字数在50字符以内' }]
+      },
+      fileList1: [],
+      fileList2: []
+    }
+  },
+  computed: {
+    ...mapGetters(['authUserId'])
+  },
+  created() {
+    this.formData.productId = this.$route.query.id
+    this.initFormData()
+  },
+  methods: {
+    // 提交
+    submit() {
+      this.$refs.addFormRef.validate(valide => {
+        if (valide) {
+          this.save()
+        }
+      })
+    },
+    // 初始化表单数据
+    initFormData() {
+      this.isLoading = true
+      getProductById({ productId: this.formData.productId }).then(res => {
+        console.log(res)
+        // const { authId, certificateImage, paramList, productId, productImage, productName, snCode, status } = res.data
+        for (const key in res.data) {
+          if (Object.hasOwnProperty.call(res.data, key)) {
+            this.formData[key] = res.data[key]
+          }
+        }
+        this.paramsCount = this.formData.paramList.length
+        if (this.paramsCount < 4) {
+          this.initParamList(4 - this.paramsCount)
+        }
+        this.initImageList()
+        this.isLoading = false
+      })
+    },
+    // 初始化上传图片列表
+    initImageList() {
+      setTimeout(() => {
+        const productImage = this.formData.productImage
+        const certificateImage = this.formData.certificateImage
+        if (productImage) {
+          this.fileList1.push({ name: 'productImage', url: productImage })
+        }
+        if (certificateImage) {
+          this.fileList2.push({ name: 'certificateImage', url: certificateImage })
+        }
+      }, 200)
+    },
+    // 保存表单数据
+    save() {
+      this.isLoading = true
+      this.formData.createBy = this.authUserId
+      saveProduct(this.formData).then(res => {
+        console.log(res)
+        this.$message.success(res.data)
+      }).finally(() => {
+        this.isLoading = false
+      })
+    },
+    // 添加一栏参数
+    handleAddParam() {
+      this.paramsCount += 1
+      this.formData.paramList.push({
+        paramContent: '',
+        paramName: ''
+      })
+    },
+    // 删除一栏参数
+    handleRemoveParam(index) {
+      this.paramsCount -= 1
+      this.formData.paramList.splice(index, 1)
+    },
+    // 图片上传成功 产品图片
+    imageUploadSuccess1(data) {
+      this.formData.productImage = data.data
+    },
+    // 图片上传成功 授权牌照
+    imageUploadSuccess2(data) {
+      this.formData.certificateImage = data.data
+    },
+    // 初始化参数列表
+    initParamList(count) {
+      for (let i = 0; i < count; i++) {
+        this.formData.paramList.push({
+          paramContent: '',
+          paramName: ''
+        })
+      }
     }
   }
 }
 </script>
 
 <style lang="scss" scoped>
-.addProduct{
+.addProduct {
   margin-bottom: 80px;
-  .form-group{
+  .form-group {
     margin-bottom: 2%;
-    .param-title{
+    .param-title {
       width: 30%;
     }
-    .param-info{
+    .param-info {
       width: 68%;
       margin-left: 2%;
     }
   }
 }
-.addForm{
+.addForm {
   width: 500px;
   margin: 0 auto;
   margin-top: 80px;
 }
-.submit-btn{
-    text-align: center;
-    .el-button{
-      width:140px;
+.submit-btn {
+  text-align: center;
+  .el-button {
+    width: 140px;
+  }
+}
+.paramsItem{
+  position: relative;
+  .closed{
+    position: absolute;
+    top: 50%;
+    transform: translateY(-50%);
+    right: -20px;
+    cursor: pointer;
+    color: #ddd;
+    &:hover{
+      color: #333;
     }
   }
+
+}
+ .hiddenInput{
+    height: 0;
+    display: none;
+  }
+
 </style>

+ 91 - 65
src/views/supplier/product/index.vue

@@ -3,8 +3,10 @@
     <div class="filter-container">
       <span>授权机构:</span>
       <el-input v-model="listQuery.title" placeholder="授权机构" style="width: 200px;" class="filter-item" @keyup.enter.native="handleFilter" />
-      <el-button type="primary">查询</el-button>
-      <el-button type="primary" @click="$_navigationTo('add')">添加商品</el-button>
+      <span>商品SN码:</span>
+      <el-input v-model="listQuery.snCode" placeholder="商品SN码" style="width: 200px;" class="filter-item" @keyup.enter.native="handleFilter" />
+      <el-button type="primary" @click="handleFilter">查询</el-button>
+      <el-button v-if="userIdentity === 2 || proxyInfo !== null" type="primary" @click="$_navigationTo(`add?id=${listQuery.authId}`)">添加商品</el-button>
     </div>
     <!-- 表格区域 -->
     <el-table
@@ -15,47 +17,37 @@
       fit
       highlight-current-row
       style="width: 100%;"
-      @sort-change="sortChange"
     >
-      <el-table-column label="序号" prop="id" sortable="custom" align="center" width="80" :class-name="getSortClass('id')">
+      <el-table-column label="序号" prop="id" sortable="custom" align="center" width="80">
         <template>
           <span>1</span>
         </template>
       </el-table-column>
-      <el-table-column label="商品名称" align="center">
-        <template>
-          <span>商品名称</span>
-        </template>
-      </el-table-column>
-      <el-table-column label="商品SN码" align="center">
-        <template>
-          <span>类型</span>
-        </template>
-      </el-table-column>
-      <el-table-column label="上架状态" width="140px" align="center">
-        <template>
-          <i class="el-icon-circle-check status success" />
+      <el-table-column label="商品名称" align="center" prop="productName" />
+      <el-table-column label="商品SN码" align="center" prop="snCode" />
+      <el-table-column v-if="userIdentity===2 || proxyInfo !== null" label="上架状态" width="140px" align="center">
+        <template slot-scope="{row}">
+          <i v-if="row.status === 1" class="el-icon-circle-check status success" @click="handleChangeStatus(row)" />
+          <i v-if="row.status === 0" class="el-icon-circle-close status danger" @click="handleChangeStatus(row)" />
         </template>
       </el-table-column>
       <el-table-column label="创建时间" class-name="status-col" width="300px" align="center">
         <template slot-scope="{row}">
-          <span>{{ row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
-        </template>
-      </el-table-column>
-      <el-table-column label="创建人" width="180px" align="center">
-        <template>
-          <span>创建人</span>
+          <span>{{ row.createTime | formatTime }}</span>
         </template>
       </el-table-column>
+      <el-table-column label="创建人" width="180px" align="center" prop="createBy" />
       <el-table-column label="操作" align="center" width="240px" class-name="small-padding fixed-width">
-        <template>
-          <el-button type="default" size="mini" @click="$_navigationTo('edit')">
-            编辑
-          </el-button>
-          <el-button type="danger" size="mini">
-            删除
-          </el-button>
-          <el-button type="primary" size="mini">
+        <template slot-scope="{row}">
+          <template v-if="userIdentity === 2|| proxyInfo !== null">
+            <el-button type="default" size="mini" @click="$_navigationTo(`edit?id=${row.productId}`)">
+              编辑
+            </el-button>
+            <el-button type="danger" size="mini" @click="handleRemoveProduct(row)">
+              删除
+            </el-button>
+          </template>
+          <el-button type="primary" size="mini" @click="handleShowQRcode(row)">
             二维码
           </el-button>
         </template>
@@ -63,17 +55,31 @@
     </el-table>
 
     <!-- 页码 -->
-    <pagination v-show="total>0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.limit" @pagination="getList" />
+    <pagination v-show="total>0" :total="total" :page.sync="listQuery.pageNum" :limit.sync="listQuery.pageSize" @pagination="getList" />
+
+    <!-- 二维码 -->
+    <qrcode :is-visible="showQRcode" :product-info="productInfo" @close="showQRcode = false" />
   </div>
 </template>
 
 <script>
-import { fetchList } from '@/api/article'
+import { getProdList, setProductStatus, removeProduct } from '@/api/product'
 import Pagination from '@/components/Pagination' // secondary package based on el-pagination
-
+import Qrcode from '@/components/qrcode'
+import { formatDate } from '@/utils'
+import { mapGetters } from 'vuex'
 export default {
   name: 'ComplexTable',
-  components: { Pagination },
+  components: { Pagination, Qrcode },
+  filters: {
+    formatTime(time) {
+      if (!time) {
+        return ''
+      }
+      return formatDate(time, 'yyyy-MM-DD hh:mm:ss')
+    }
+  },
+
   data() {
     return {
       tableKey: 0,
@@ -81,18 +87,24 @@ export default {
       total: 0,
       listLoading: true,
       listQuery: {
-        page: 1,
-        limit: 20,
-        importance: undefined,
-        title: undefined,
-        type: undefined,
-        sort: '+id'
-      }
+        authId: '',
+        productName: '',
+        snCode: '',
+        pageNum: 1,
+        pageSize: 10
+      },
+      showQRcode: false,
+      productInfo: {}
     }
   },
+  computed: {
+    ...mapGetters(['userIdentity', 'proxyInfo'])
+  },
   created() {
+    this.listQuery.authId = this.$route.query.id
     this.getList()
   },
+
   methods: {
     // 添加
     handleAddPro() {
@@ -104,14 +116,11 @@ export default {
     },
     // 获取列表信息
     getList() {
-      fetchList(this.listQuery).then(response => {
-        this.list = response.data.items
-        this.total = response.data.total
-
-        // Just to simulate the time of the request
-        setTimeout(() => {
-          this.listLoading = false
-        }, 1.5 * 1000)
+      getProdList(this.listQuery).then(res => {
+        this.total = res.data.total
+        this.list = res.data.list
+      }).finally(() => {
+        this.listLoading = false
       })
     },
     // 过滤列表
@@ -119,24 +128,41 @@ export default {
       this.listQuery.page = 1
       this.getList()
     },
-
-    sortChange(data) {
-      const { prop, order } = data
-      if (prop === 'id') {
-        this.sortByID(order)
+    // 改变启用状态
+    handleChangeStatus(item) {
+      if (this.userIdentity === 2 || this.proxyInfo !== null) {
+        this.listLoading = true
+        const { status,	productId } = item
+        const newStatus = status === 0 ? 1 : 0
+        setProductStatus({ status: newStatus, productId }).then(res => {
+          this.$message.success(res.data)
+          this.listLoading = false
+        }).finally(() => {
+          this.getList()
+        })
       }
     },
-    sortByID(order) {
-      if (order === 'ascending') {
-        this.listQuery.sort = '+id'
-      } else {
-        this.listQuery.sort = '-id'
-      }
-      this.handleFilter()
+    // 删除商品
+    async handleRemoveProduct(item) {
+      const text = await this.$confirm('此操作将删除该授权机构, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).catch(() => {
+        this.$message.info('已取消操作')
+      })
+      if (text !== 'confirm') return
+
+      removeProduct({ productId: item.productId }).then(res => {
+        this.$message.success(res.data)
+      }).finally(() => {
+        this.getList()
+      })
     },
-    getSortClass: function(key) {
-      const sort = this.listQuery.sort
-      return sort === `+${key}` ? 'ascending' : 'descending'
+    // 显示二维码
+    handleShowQRcode(item) {
+      this.showQRcode = true
+      this.productInfo = item
     }
   }
 }

+ 126 - 49
src/views/supplier/user/add.vue

@@ -1,22 +1,26 @@
 <template>
-  <div class="addSupplier">
+  <div v-loading="isLoading" class="addSupplier">
     <el-form ref="addFormRef" :model="addData" :rules="rules" label-width="120px" class="addForm">
       <el-form-item label="供应商类型:" prop="shopType">
-        <el-select v-model="addData.shopType" placeholder="请选择供应商类型" style="width: 100%">
-          <el-option label="代理商" :value="1" />
-          <el-option label="品牌方" :value="2" />
+        <el-select v-model="addData.shopType" placeholder="请选择供应商类型" style="width: 100%" @change="getBrandList">
+          <el-option label="品牌方" :value="1" />
+          <el-option label="代理商" :value="2" />
         </el-select>
       </el-form-item>
 
       <!-- 供应商名称 -->
-      <el-form-item v-if="addData.shopType===1" label="供应商名称:" prop="shopName">
+      <el-form-item v-if="addData.shopType===2" label="供应商名称:" prop="shopName">
         <el-input v-model="addData.shopName" placeholder="请输入供应商名称" />
       </el-form-item>
 
-      <el-form-item v-if="addData.shopType===2" label="供应商名称:" prop="shopName">
-        <el-select v-model="addData.shopName" placeholder="请选择供应商类型" style="width: 100%">
-          <el-option label="供应商名称1" value="1" />
-          <el-option label="供应商名称2" value="2" />
+      <el-form-item v-if="addData.shopType===1" label="供应商名称:" prop="shopName">
+        <el-select v-model="selectedBrandIndex" placeholder="请选择品牌" style="width: 100%" filterable @change="setShopName">
+          <el-option
+            v-for="(item,index) in brandList"
+            :key="item.id"
+            :label="item.name"
+            :value="index"
+          />
         </el-select>
       </el-form-item>
       <!-- 供应商名称END -->
@@ -27,30 +31,34 @@
       <el-form-item label="联系人:" prop="linkMan">
         <el-input v-model="addData.linkMan" placeholder="请输入联系人" />
       </el-form-item>
-      <el-form-item label="所属品牌:" prop="brandId">
-        <el-select v-model="addData.brandId" placeholder="请选择所属品牌" style="width: 100%">
+      <el-form-item v-if="addData.shopType===2" label="所属品牌:" prop="brandId">
+        <el-select v-model="addData.brandId" placeholder="请选择所属品牌" style="width: 100%" filterable @change="setShopName">
           <el-option
-            v-for="item in brand"
+            v-for="item in brandList"
             :key="item.id"
-            :label="item.label"
+            :label="item.name"
             :value="item.id"
           />
         </el-select>
       </el-form-item>
       <el-form-item label="产地:" prop="countryId">
-        <el-select v-model="addData.countryId" placeholder="产地" style="width: 100%">
-          <el-option label="中国" value="1" />
-          <el-option label="法国" value="2" />
+        <el-select v-model="addData.countryId" placeholder="产地" style="width: 100%" filterable>
+          <el-option
+            v-for="item in countryList"
+            :key="item.countryId"
+            :label="item.countryName"
+            :value="item.countryId"
+          />
         </el-select>
       </el-form-item>
       <el-form-item label="品牌logo:" class="no-input" prop="brandAuthLogo">
-        <upload-image @success="imageUploadSuccess" @error="imageUploadFaild" />
-        <el-input v-model="addData.brandAuthLogo" type="hidden" />
+        <upload-image ref="uploadImageRef1" :file-list="fileList1" @success="imageUploadSuccess1" @error="imageUploadFaild1" />
+        <el-input v-model="addData.brandAuthLogo" type="hidden" class="hiddenInput" />
       </el-form-item>
       <el-form-item label="官网认证链接:">
         <el-input v-model="addData.securityLink" placeholder="请输入官网认证链接" />
       </el-form-item>
-      <template v-if="addData.shopType===1">
+      <template v-if="addData.shopType===2">
         <el-form-item label="代理声明:">
           <el-radio v-model="addData.statementType" :label="1">弹窗</el-radio>
           <el-radio v-model="addData.statementType" :label="2">链接</el-radio>
@@ -65,12 +73,12 @@
           <el-input v-if="addData.statementType === 2" v-model="addData.statementLink" />
         </el-form-item>
         <el-form-item v-else-if="addData.statementType === 3" label="图片:" class="no-input" prop="statementImage">
-          <upload-image v-if="addData.statementType === 3" />
-          <el-input v-model="addData.statementImage" type="statementFileId" />
+          <upload-image v-if="addData.statementType === 3" ref="uploadImageRef2" @success="imageUploadSuccess2" @error="imageUploadFaild2" />
+          <el-input v-model="addData.statementImage" type="hidden" class="hiddenInput" />
         </el-form-item>
-        <el-form-item v-else label="文件:" prop="statementImage">
-          <upload-file v-if="addData.statementType === 4" @success="fileUploadSuccess" @error="fileUploadFaild" />
-          <el-input v-model="addData.statementFileId" type="hidden" />
+        <el-form-item v-else label="文件:" prop="statementFileId">
+          <upload-file v-if="addData.statementType === 4" ref="uploadFileRef" @success="fileUploadSuccess" @error="fileUploadFaild" />
+          <el-input v-model="addData.statementFileId" type="hidden" class="hiddenInput" />
         </el-form-item>
 
       </template>
@@ -93,40 +101,42 @@ import UploadImage from '../components/uploadImage'
 import UploadFile from '../components/uploadFile'
 import { mapGetters } from 'vuex'
 import { isMobile } from '@/utils/validate'
+import { fetchBrandList } from '@/api/brand'
+import { addSupplier } from '@/api/supplier'
+
 export default {
   components: { UploadImage, UploadFile },
   data() {
     var valideMobile = (rule, value, callback) => {
       if (!isMobile(value)) {
-        console.log(isMobile(value))
         callback(new Error('手机号格式不正确'))
       } else {
         callback()
       }
     }
     return {
+      isLoading: false,
+
       addData: {
         authUserId: '', // 供应商id
-        brandAuthLogo: 'brandAuthLogo.png', //	品牌授权logo
+        brandAuthLogo: '', //	品牌授权logo
         brandId: '', // 品牌id
-        countryId: '', // 产地国家id
+        countryId: 1, // 产地国家id
         createBy: '', // 创建人用户id
         linkMan: '', // 联系人
         mobile: '', // 手机号
         securityLink: '', // 官网认证链接
         shopName: '', // 供应商名称
         shopStatus: 1, // 供应商状态:0停用 1启用
-        shopType: 2, //	供应商类型:1代理商,2品牌方
+        shopType: 1, //	供应商类型:1品牌方,2代理商
         statementContent: '', // 声明弹窗内容
         statementLink: '', // 声明链接
         statementFileId: '', //	声明文件id
-        statementImage: 'statement.png', // 声明图片
+        statementImage: '', // 声明图片
         statementType: 1 // 代理声明类型:1弹窗 2链接 3图片 4文件(.doc .ppt .pdf)
       },
-      brand: [
-        { id: 1, label: '品牌1' },
-        { id: 2, label: '品牌2' }
-      ],
+      selectedBrandIndex: '',
+      brandList: [], // 品牌列表
       rules: {
         shopType: [{ required: true, message: '供应商类型不能为空', trigger: 'change' }],
         shopName: [{ required: true, message: '供应商名称不能为空', trigger: ['blur', 'change'] }],
@@ -136,34 +146,102 @@ export default {
         ], // 手机号格式校验
         linkMan: [{ required: true, message: '联系人不能为空', trigger: 'blur' }],
         countryId: [{ required: true, message: '产地不能为空', trigger: 'change' }],
-        brandAuthLogo: [{ required: true }],
+        brandAuthLogo: [{ required: true, message: '品牌logo不能为空' }],
         brandId: [{ required: true, message: '所属品牌不能为空', trigger: 'change' }],
         statementContent: [{ required: true, message: '声明不能为空', trigger: 'blur' }],
         statementLink: [{ required: true, message: '声明链接不能为空', trigger: 'blur' }],
-        statementImage: [{ required: true }],
-        statementFileId: [{ required: true }]
-      }
+        statementImage: [{ required: true, message: '声明图片不能为空' }],
+        statementFileId: [{ required: true, message: '声明文件不能为空' }]
+      },
+      fileList1: [], // 已上传的图片列表 品牌logo
+      fileList2: [], // 已上传的图片列表 声明图片
+      fileList3: [] // 已上传的图片列表 声明文件
+      // countryList: []
     }
   },
   computed: {
-    ...mapGetters(['userIdentity', 'authUserId'])
+    ...mapGetters(['userIdentity', 'name', 'countryList', 'authUserId'])
+  },
+  created() {
+    this.initAddForm()
   },
   methods: {
-    // 保存
-    save() {
-      this.$refs.addFormRef.validate(valide => {
-        console.log(valide)
+    // 初始添加供应商时的表单数据
+    initAddForm() {
+      // this.addData.authUserId = this.authUserId
+      this.getBrandList()
+    },
+    // 获取品牌列表
+    getBrandList() {
+      // 获取品牌列表
+      fetchBrandList({ type: this.addData.shopType }).then(res => {
+        console.log(res)
+        if (res.code === 0) {
+          this.brandList = res.data
+        }
+      }).catch(err => console.log(err))
+    },
+    // 保存表单数据
+    async save() {
+      this.isLoading = true
+      this.addData.createBy = this.authUserId
+      const that = this
+      // this.uploadFile()
+      await this.$refs.addFormRef.validate(valide => {
+        if (!valide) {
+          this.isLoading = false
+          return
+        }
+        addSupplier(that.addData).then(res => {
+          console.log(res)
+          this.$message.success('添加成功')
+          // this.$refs.addFormRef.resetFields()
+        }).finally(() => {
+          this.isLoading = false
+          this.$refs.addFormRef.resetFields()
+          this.addData.securityLink = ''
+        })
       })
     },
+    // 设置品牌名称
+    setShopName(index) {
+      const fileList = []
+      if (this.addData.shopType === 1) {
+        this.addData.shopName = this.brandList[index]?.name
+      }
+      this.addData.brandAuthLogo = this.brandList[index]?.authLogo || ''
+      if (this.brandList[index]?.authLogo) {
+        fileList.push({ name: this.addData.shopName, url: this.brandList[index]?.authLogo || '' })
+      }
+      this.fileList1 = fileList
+    },
+    // 手动提交上传图片
+    // uploadFile() {
+    //   this.$refs.uploadImageRef1?.$refs.upload.submit()
+    //   this.$refs.uploadImageRef2?.$refs.upload.submit()
+    //   this.$refs.uploadfileRef?.$refs.upload.submit()
+    // },
     // 文件上传成功
-    fileUploadSuccess(response, file, fileList) {},
+    fileUploadSuccess(data) {
+      this.addData.statementFileId = data.data
+    },
     fileUploadFaild(err, file, fileList) {
       console.log(err)
     },
 
-    // 图片上传成功
-    imageUploadSuccess(response, file, fileList) {},
-    imageUploadFaild(err, file, fileList) {
+    // 图片上传成功 品牌logo
+    imageUploadSuccess1(data) {
+      this.addData.brandAuthLogo = data.data
+    },
+    imageUploadFaild1(err, file, fileList) {
+      console.log(err)
+    },
+
+    // 图片上传成功 声明图片
+    imageUploadSuccess2(data) {
+      this.addData.statementImage = data.data
+    },
+    imageUploadFaild2(err, file, fileList) {
       console.log(err)
     }
   }
@@ -185,8 +263,7 @@ export default {
     width: 140px;
   }
 }
-.no-input{
-  height: 148px !important;
-  overflow: hidden;
+.hiddenInput{
+  display: none;
 }
 </style>

+ 258 - 45
src/views/supplier/user/edit.vue

@@ -1,57 +1,96 @@
 <template>
-  <div class="addSupplier">
-    <el-form ref="addFormRef" label-width="120px" class="addForm">
-      <el-form-item label="供应商类型:">
-        <el-select placeholder="供应商类型" style="width:100%">
-          <el-option label="供应商类型1" />
-          <el-option label="供应商类型2" />
+  <div v-loading="isLoading" class="addSupplier">
+    <el-form ref="addFormRef" :model="addData" :rules="rules" label-width="120px" class="addForm">
+      <el-form-item label="供应商类型:" prop="shopType">
+        <el-select v-model="addData.shopType" placeholder="请选择供应商类型" style="width: 100%" @change="getBrandList">
+          <el-option label="品牌方" :value="1" />
+          <el-option label="代理商" :value="2" />
         </el-select>
       </el-form-item>
-      <el-form-item label="供应商名称:">
-        <el-input placeholder="供应商名称" />
+
+      <!-- 供应商名称 -->
+      <el-form-item v-if="addData.shopType===2" label="供应商名称:" prop="shopName">
+        <el-input v-model="addData.shopName" placeholder="请输入供应商名称" />
       </el-form-item>
-      <el-form-item label="手机号:">
-        <el-input placeholder="手机号" />
+
+      <el-form-item v-if="addData.shopType===1" label="供应商名称:" prop="shopName">
+        <el-select v-model="selectedBrandIndex" placeholder="请选择品牌" style="width: 100%" filterable @change="setShopName">
+          <el-option
+            v-for="(item,index) in brandList"
+            :key="item.id"
+            :label="item.name"
+            :value="index"
+          />
+        </el-select>
+      </el-form-item>
+      <!-- 供应商名称END -->
+
+      <el-form-item label="手机号:" prop="mobile">
+        <el-input v-model="addData.mobile" placeholder="请输入手机号" />
       </el-form-item>
-      <el-form-item label="联系人:">
-        <el-input placeholder="联系人" />
+      <el-form-item label="联系人:" prop="linkMan">
+        <el-input v-model="addData.linkMan" placeholder="请输入联系人" />
       </el-form-item>
-      <el-form-item label="所属品牌:">
-        <el-select placeholder="所属品牌" style="width:100%">
-          <el-option label="品牌1" />
-          <el-option label="品牌2" />
+      <el-form-item v-if="addData.shopType===2" label="所属品牌:" prop="brandId">
+        <el-select v-model="addData.brandId" placeholder="请选择所属品牌" style="width: 100%" filterable @change="setShopName">
+          <el-option
+            v-for="(item,index) in brandList"
+            :key="item.id"
+            :label="item.name"
+            :value="index"
+          />
         </el-select>
       </el-form-item>
-      <el-form-item label="产地:">
-        <el-select placeholder="产地" style="width:100%">
-          <el-option label="中国" />
-          <el-option label="法国" />
+      <el-form-item label="产地:" prop="countryId">
+        <el-select v-model="addData.countryId" placeholder="产地" style="width: 100%" filterable>
+          <el-option
+            v-for="item in countryList"
+            :key="item.countryId"
+            :label="item.countryName"
+            :value="item.countryId"
+          />
         </el-select>
       </el-form-item>
-      <el-form-item label="品牌logo:">
-        <upload-image />
+      <el-form-item label="品牌logo:" class="no-input" prop="brandAuthLogo">
+        <upload-image ref="uploadImageRef1" :file-list="fileList1" @success="imageUploadSuccess1" @error="imageUploadFaild1" />
+        <el-input v-model="addData.brandAuthLogo" type="hidden" class="hiddenInput" />
       </el-form-item>
       <el-form-item label="官网认证链接:">
-        <el-input />
-      </el-form-item>
-      <el-form-item label="代理声明:">
-        <el-radio v-model="statement" :label="1">弹窗</el-radio>
-        <el-radio v-model="statement" :label="2">链接</el-radio>
-        <el-radio v-model="statement" :label="3">图片</el-radio>
-        <el-radio v-model="statement" :label="4">文件</el-radio>
-      </el-form-item>
-      <el-form-item label="弹窗内容:">
-        <el-input v-if="statement === 1" type="textarea" />
-        <el-input v-if="statement === 2" />
-        <upload-image v-if="statement === 3" />
-        <upload-file v-if="statement === 4" />
+        <el-input v-model="addData.securityLink" placeholder="请输入官网认证链接" />
       </el-form-item>
+      <template v-if="addData.shopType===2">
+        <el-form-item label="代理声明:">
+          <el-radio v-model="addData.statementType" :label="1">弹窗</el-radio>
+          <el-radio v-model="addData.statementType" :label="2">链接</el-radio>
+          <el-radio v-model="addData.statementType" :label="3">图片</el-radio>
+          <el-radio v-model="addData.statementType" :label="4">文件</el-radio>
+        </el-form-item>
+
+        <el-form-item v-if="addData.statementType === 1" label="弹窗:" prop="statementContent">
+          <el-input v-if="addData.statementType === 1" v-model="addData.statementContent" type="textarea" />
+        </el-form-item>
+        <el-form-item v-else-if="addData.statementType === 2" label="链接:" prop="statementLink">
+          <el-input v-if="addData.statementType === 2" v-model="addData.statementLink" />
+        </el-form-item>
+        <el-form-item v-else-if="addData.statementType === 3" label="图片:" class="no-input" prop="statementImage">
+          <upload-image v-if="addData.statementType === 3" ref="uploadImageRef2" :file-list="fileList2" @success="imageUploadSuccess2" @error="imageUploadFaild2" />
+          <el-input v-model="addData.statementImage" type="hidden" class="hiddenInput" />
+        </el-form-item>
+        <el-form-item v-else label="文件:" prop="statementFileId">
+          <upload-file v-if="addData.statementType === 4" ref="uploadFileRef" :file-list="fileList3" @success="fileUploadSuccess" @error="fileUploadFaild" />
+          <el-input v-model="addData.statementFileId" type="hidden" class="hiddenInput" />
+        </el-form-item>
+
+      </template>
       <el-form-item label="供应商状态:">
-        <el-input />
+        <el-select v-model="addData.shopStatus" placeholder="请选择供应商状态" style="width: 100%">
+          <el-option label="启用" :value="1" />
+          <el-option label="禁用" :value="0" />
+        </el-select>
       </el-form-item>
     </el-form>
     <div class="submit-btn">
-      <el-button type="primary">保存</el-button>
+      <el-button type="primary" @click="save">保存</el-button>
       <el-button type="warning" @click="$_back()">返回</el-button>
     </div>
   </div>
@@ -60,29 +99,203 @@
 <script>
 import UploadImage from '../components/uploadImage'
 import UploadFile from '../components/uploadFile'
+import { mapGetters } from 'vuex'
+import { isMobile } from '@/utils/validate'
+import { fetchBrandList } from '@/api/brand'
+import { addSupplier, getSupplierById } from '@/api/supplier'
+
 export default {
   components: { UploadImage, UploadFile },
   data() {
+    var valideMobile = (rule, value, callback) => {
+      if (!isMobile(value)) {
+        callback(new Error('手机号格式不正确'))
+      } else {
+        callback()
+      }
+    }
     return {
-      statement: 1
+      isLoading: false,
+
+      addData: {
+        authUserId: '', // 供应商id
+        brandAuthLogo: '', //	品牌授权logo
+        brandId: '', // 品牌id
+        countryId: 1, // 产地国家id
+        createBy: '', // 创建人用户id
+        linkMan: '', // 联系人
+        mobile: '', // 手机号
+        securityLink: '', // 官网认证链接
+        shopName: '', // 供应商名称
+        shopStatus: 1, // 供应商状态:0停用 1启用
+        shopType: 1, //	供应商类型:1品牌方,2代理商
+        statementContent: '', // 声明弹窗内容
+        statementLink: '', // 声明链接
+        statementFileId: 'no file', //	声明文件id
+        statementImage: '', // 声明图片
+        statementType: 1 // 代理声明类型:1弹窗 2链接 3图片 4文件(.doc .ppt .pdf)
+      },
+      selectedBrandIndex: '',
+      brandList: [], // 品牌列表
+      // 表单校验规则
+      rules: {
+        shopType: [{ required: true, message: '供应商类型不能为空', trigger: 'change' }],
+        shopName: [{ required: true, message: '供应商名称不能为空', trigger: ['blur', 'change'] }],
+        mobile: [
+          { required: true, message: '手机号不能为空', trigger: 'blur' },
+          { validator: valideMobile, trigger: 'blur' }
+        ], // 手机号格式校验
+        linkMan: [{ required: true, message: '联系人不能为空', trigger: 'blur' }],
+        countryId: [{ required: true, message: '产地不能为空', trigger: 'change' }],
+        brandAuthLogo: [{ required: true, message: '品牌logo不能为空' }],
+        brandId: [{ required: true, message: '所属品牌不能为空', trigger: 'change' }],
+        statementContent: [{ required: true, message: '声明不能为空', trigger: 'blur' }],
+        statementLink: [{ required: true, message: '声明链接不能为空', trigger: 'blur' }],
+        statementImage: [{ required: true, message: '声明图片不能为空' }],
+        statementFileId: [{ required: true, message: '声明文件不能为空' }]
+      },
+      fileList1: [], // 已上传的图片列表 品牌logo
+      fileList2: [], // 已上传的图片列表 声明图片
+      fileList3: [] // 已上传的图片列表 声明文件
+      // countryList: []
+    }
+  },
+  computed: {
+    ...mapGetters(['userIdentity', 'name', 'countryList', 'authUserId'])
+  },
+  created() {
+    // 获取供应商id
+    this.addData.authUserId = this.$route.query.id
+    this.getInfoById(this.addData.authUserId)
+  },
+  methods: {
+    // 初始添加供应商时的表单数据
+    initAddForm(data) {
+      this.setFormData(data)
+      this.getBrandList(data.type)
+    },
+    // 查询供应商信息
+    getInfoById(id) {
+      this.isLoading = true
+      getSupplierById({ authUserId: id })
+        .then(res => {
+          if (res.code === 0) {
+            this.initAddForm(res.data)
+          }
+        })
+        .catch(err => { console.log(err) })
+        .finally(() => {
+          this.isLoading = false
+        })
+    },
+    // 为表单设置数据
+    setFormData(data) {
+      for (const key in this.addData) {
+        if (Object.hasOwnProperty.call(data, key)) {
+          this.addData[key] = data[key] || ''
+        }
+      }
+      if (this.addData.brandAuthLogo) {
+        this.fileList1.push({ name: 'authLogo', url: this.addData.brandAuthLogo })
+      }
+      if (this.addData.statementImage) {
+        this.fileList2.push({ name: '声明图片', url: this.addData.statementImage })
+      }
+      if (data.statementFileName) {
+        // this.fileList3.push({ name: '您已上传文件,不支持预览,可删除后重新上传', url: '' })
+        this.fileList3.push({ name: data.statementFileName, url: '' })
+      }
+    },
+    // 获取品牌列表
+    getBrandList(type) {
+      fetchBrandList({ type }).then(res => {
+        if (res.code === 0) {
+          this.brandList = res.data
+        }
+      }).catch(err => console.log(err))
+    },
+
+    // 保存表单数据
+    async save() {
+      this.isLoading = true
+      this.addData.createBy = this.authUserId
+      // this.uploadFile()
+      await this.$refs.addFormRef.validate(valide => {
+        if (!valide) {
+          this.isLoading = false
+          return
+        }
+        if (this.addData.statementFileId === 'no file') {
+          this.addData.statementFileId = null
+        }
+        addSupplier(this.addData).then(res => {
+          this.$message.success('修改成功')
+          // this.$refs.addFormRef.resetFields()
+        }).catch(err => {
+          console.log(err)
+          this.$message.danger('修改失败')
+        }).finally(() => {
+          this.isLoading = false
+          this.$refs.addFormRef.resetFields()
+          this.addData.securityLink = ''
+        })
+      })
+    },
+    // 设置品牌名称
+    setShopName(index) {
+      const fileList = []
+      if (this.addData.shopType === 1) {
+        this.addData.shopName = this.brandList[index]?.name
+      }
+      this.addData.brandAuthLogo = this.brandList[index]?.authLogo || ''
+      if (this.brandList[index]?.authLogo) {
+        fileList.push({ name: this.addData.shopName, url: this.brandList[index]?.authLogo || '' })
+      }
+      this.fileList1 = fileList
+    },
+    // 文件上传成功
+    fileUploadSuccess(data) {
+      this.addData.statementFileId = data.data
+    },
+    fileUploadFaild(err, file, fileList) {
+      console.log(err)
+    },
+
+    // 图片上传成功 品牌logo
+    imageUploadSuccess1(data) {
+      this.addData.brandAuthLogo = data.data
+    },
+    imageUploadFaild1(err, file, fileList) {
+      console.log(err)
+    },
+
+    // 图片上传成功 声明图片
+    imageUploadSuccess2(data) {
+      this.addData.statementImage = data.data
+    },
+    imageUploadFaild2(err, file, fileList) {
+      console.log(err)
     }
   }
 }
 </script>
 
 <style lang="scss" scoped>
-.addSupplier{
+.addSupplier {
   margin-bottom: 80px;
 }
-.addForm{
+.addForm {
   width: 500px;
   margin: 0 auto;
   margin-top: 80px;
 }
-.submit-btn{
-    text-align: center;
-    .el-button{
-      width:140px;
-    }
+.submit-btn {
+  text-align: center;
+  .el-button {
+    width: 140px;
   }
+}
+.hiddenInput{
+  display: none;
+}
 </style>

+ 66 - 22
src/views/supplier/user/index.vue

@@ -10,14 +10,18 @@
       </el-select>
       <span>所属品牌:</span>
       <el-select v-model="listQuery.brandId" placeholder="所属品牌" clearable class="filter-item" style="width: 200px">
-        <el-option label="品牌1" :value="1" />
-        <el-option label="品牌2" :value="2" />
+        <el-option
+          v-for="item in brandList"
+          :key="item.id"
+          :label="item.name"
+          :value="item.id"
+        />
       </el-select>
       <span>手机号:</span>
       <el-input v-model="listQuery.mobile" placeholder="手机号" style="width: 200px;" class="filter-item" @keyup.enter.native="handleFilter" />
       <span>联系人:</span>
       <el-input v-model="listQuery.linkMan" placeholder="联系人" style="width: 200px;" class="filter-item" @keyup.enter.native="handleFilter" />
-      <el-button type="primary" @click="getList()">查询</el-button>
+      <el-button type="primary" @click="getList(listQuery)">查询</el-button>
       <el-button type="primary" @click="$_navigationTo('add')">添加供应商</el-button>
     </div>
     <!-- 表格区域 -->
@@ -33,8 +37,9 @@
       <el-table-column label="序号" type="index" sortable="custom" align="center" width="80" />
       <el-table-column label="供应商名称" align="center" prop="name" />
       <el-table-column label="供应商类型" width="150px" align="center">
-        <template>
-          <span>类型</span>
+        <template v-slot="{row}">
+          <span v-if="row.type === 1">品牌方</span>
+          <span v-if="row.type === 2">供应商</span>
         </template>
       </el-table-column>
       <el-table-column label="所属品牌" width="150px" align="center" prop="brandName" />
@@ -47,22 +52,22 @@
       </el-table-column>
       <el-table-column label="创建时间" class-name="status-col" width="200px">
         <template slot-scope="{row}">
-          <span>{{ row.createTime | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
+          <span>{{ row.createTime | formatTime }}</span>
         </template>
       </el-table-column>
       <el-table-column label="创建人" class-name="status-col" width="100px" prop="createBy" />
       <el-table-column label="操作" align="center" width="360" class-name="small-padding fixed-width">
-        <template>
-          <el-button type="info" size="mini" @click="$_navigationTo('edit')">
+        <template slot-scope="{row}">
+          <el-button size="mini" type="primary" @click="$_navigationTo(`edit?id=${row.authUserId}`)">
             编辑
           </el-button>
-          <el-button size="mini" type="primary" @click="handleProxy">
+          <el-button size="mini" type="primary" @click="handleProxy(row)">
             代他操作
           </el-button>
-          <el-button size="mini" type="success" @click="$_navigationTo('/auth/list')">
+          <el-button size="mini" type="primary" @click="$_navigationTo(`/auth/list?id=${row.authUserId}`)">
             授权信息
           </el-button>
-          <el-button size="mini" type="danger" @click="handleResetPwd">
+          <el-button size="mini" type="primary" @click="handleResetPwd(row)">
             重置密码
           </el-button>
         </template>
@@ -70,17 +75,28 @@
     </el-table>
 
     <!-- 页码 -->
-    <pagination v-show="total>0" :total="total" :page.sync="listQuery.pageNum" :limit.sync="listQuery.pageSize" @pagination="getList" />
+    <pagination v-show="total>0" :total="total" :page.sync="listQuery.pageNum" :limit.sync="listQuery.pageSize" @pagination="getList(listQuery)" />
 
   </div>
 </template>
 
 <script>
 import Pagination from '@/components/Pagination' // secondary package based on el-pagination
-import { fetchSupplierList } from '@/api/supplier'
+import { fetchSupplierList, supplierStatusChange } from '@/api/supplier'
+import { resetPassword } from '@/api/user'
+import { fetchBrandList } from '@/api/brand'
+import { formatDate } from '@/utils'
 export default {
   name: 'ComplexTable',
   components: { Pagination },
+  filters: {
+    formatTime(time) {
+      if (!time) {
+        return ''
+      }
+      return formatDate(time, 'yyyy-MM-DD hh:mm:ss')
+    }
+  },
   data() {
     return {
       slider: 1,
@@ -96,21 +112,22 @@ export default {
         shopName: '', // 供应商名称
         shopType: ''// 供应商类型
       },
-      list: []
+      list: [],
+      brandList: [] // 品牌列表
     }
   },
   created() {
-    this.getList(this.listQuery)
+    this.getList()
+    this.getBrandList()
   },
   methods: {
     // 获取列表数据
-    getList(listQuery) {
+    getList() {
       this.listLoading = true
-      fetchSupplierList().then(res => {
+      fetchSupplierList(this.listQuery).then(res => {
         if (res.code !== 0) {
           return this.$message.error('获取数据失败~')
         }
-        console.log(res)
         const { total, list } = res.data
         this.total = total
         this.formatList(list)
@@ -125,16 +142,32 @@ export default {
         i.shopStatus = i.shopStatus === 1
       })
     },
+    // 获取品牌列表
+    getBrandList() {
+      // 获取品牌列表
+      fetchBrandList().then(res => {
+        if (res.code === 0) {
+          this.brandList = res.data
+        }
+      }).catch(err => console.log(err))
+    },
     // 供应商状态改变
     handleChangeStatus(item) {
       const params = {
-        shopStatus: item.shopStatus ? 1 : 0,
+        status: item.shopStatus ? 1 : 0,
         authUserId: item.authUserId
       }
-      console.log(params)
+      supplierStatusChange(params)
+        .then(res => {
+          if (res.code === 0) {
+            this.$message.success('操作成功')
+          }
+        }).catch(() => {
+          this.$message.danger('操作失败')
+        })
     },
     // 重置密码
-    async handleResetPwd() {
+    async handleResetPwd(item) {
       const text = await this.$confirm('此操作将重置该供应商的密码, 是否继续?', '提示', {
         confirmButtonText: '确定',
         cancelButtonText: '取消',
@@ -144,9 +177,12 @@ export default {
       })
       if (text !== 'confirm') return
       // 要执行的操作
+      resetPassword({ authUserId: item.authUserId }).then(res => {
+        this.$message.success(res.data)
+      })
     },
     // 代他操作
-    async handleProxy() {
+    async handleProxy(item) {
       const text = await this.$confirm('此操作将临时登录该供应商账号, 是否继续?', '提示', {
         confirmButtonText: '确定',
         cancelButtonText: '取消',
@@ -156,6 +192,14 @@ export default {
       })
       if (text !== 'confirm') return
       // 要执行的操作
+      console.log(item)
+      this.$store.commit('user/SET_PROXY_INFO', item)
+      this.$router.push(`/auth/list`)
+    },
+    // 过滤列表
+    handleFilter() {
+      this.listQuery.page = 1
+      this.getList()
     }
   }
 }

+ 2 - 2
vue.config.js

@@ -35,8 +35,8 @@ module.exports = {
     overlay: {
       warnings: false,
       errors: true
-    },
-    before: require('./mock/mock-server.js')
+    }
+    // before: require('./mock/mock-server.js')
   },
   configureWebpack: {
     // provide the app's title in webpack's name field, so that

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff