瀏覽代碼

Merge branch 'developerA' into developer

喻文俊 3 年之前
父節點
當前提交
9d00ce715e

+ 19 - 0
src/api/auth.js

@@ -1,5 +1,24 @@
 import request from '@/utils/request'
 
+// Excel表格导入
+export function authImportExcel(data) {
+  return request({
+    url: '/auth/import/excel',
+    method: 'post',
+    data,
+    headers: { 'Content-Type': 'multipart/form-data;charset=UTF-8' }
+  })
+}
+
+// Excel表格导出
+export function authExportExcel(params) {
+  return request({
+    url: '/auth/export/excel',
+    method: 'get',
+    params
+  })
+}
+
 // 授权列表
 export function fecthAuthList(params) {
   return request({

+ 43 - 0
src/api/helper.js

@@ -0,0 +1,43 @@
+import request from '@/utils/request'
+
+/**
+ * 获取帮助列表
+ * @param {*} fileType  文件类型:1视频,2文档
+ * @param {*} fileTitle 文件标题
+ * @param {*} fileModule 文件模块:1品牌授权-授权列表,2机构管理-机构列表
+ * @param {*} pageNum 第几页
+ * @param {*} pageSize 一页多少条
+ */
+export function fetchCourseList(params) {
+  return request({
+    url: '/data/file/course/list',
+    method: 'get',
+    params
+  })
+}
+
+/**
+ * 保存记录
+ * @param {*} fileId  文件id;
+ * @param {*} fileTitle 文件标题;
+ * @param {*} fileName 文件名称;
+ * @param {*} ossName oss名称;
+ * @param {*} fileType 文件类型:1视频,2文档;
+ * @param {*} fileModule 文件模块:1品牌授权-授权列表,2机构管理-机构列表
+ */
+export function saveCourse(data) {
+  return request({
+    url: '/data/file/course/save',
+    method: 'post',
+    data
+  })
+}
+
+// 删除记录
+export function removeCourse(data) {
+  return request({
+    url: '/data/file/course/delete',
+    method: 'post',
+    data
+  })
+}

+ 137 - 0
src/components/FileUpload/index.vue

@@ -0,0 +1,137 @@
+<template>
+  <div class="file-upload">
+    <el-upload
+      ref="upload"
+      :class="{'hide-upload':hideUpload}"
+      :action="action"
+      :multiple="multiple"
+      :limit="limit"
+      :on-preview="handlePreview"
+      :on-remove="handleRemove"
+      :before-remove="beforeRemove"
+      :on-success="onSuccess"
+      :on-error="onError"
+      :on-exceed="handleExceed"
+      :on-change="handleChange"
+      :file-list="uploadList"
+      :auto-upload="autoUpload"
+      :accept="acceptType"
+    >
+      <el-button size="small" type="primary">点击上传</el-button>
+      <div v-if="uploadTip" slot="tip" class="el-upload__tip">{{ uploadTip }}</div>
+    </el-upload>
+  </div>
+</template>
+
+<script>
+export default {
+  props: {
+    uploadTip: {
+      type: String,
+      default: ''
+    },
+    limit: {
+      type: Number,
+      default: 9
+    },
+    fileList: {
+      type: Array,
+      default: () => []
+    },
+    multiple: {
+      type: Boolean,
+      default: false
+    },
+    autoUpload: {
+      type: Boolean,
+      default: false
+    },
+    acceptType: {
+      type: String,
+      default: ''
+    }
+  },
+  data() {
+    return {
+      action: '',
+      uploadList: []
+    }
+  },
+  computed: {
+    hideUpload() {
+      if (this.multiple) {
+        return this.uploadList.length === this.limit
+      } else {
+        return this.uploadList.length === 1
+      }
+    }
+  },
+  watch: {
+    fileList(nVal) {
+      console.log(nVal)
+      this.uploadList = nVal
+    }
+  },
+  created() {
+    console.log(this.$props)
+    this.action = process.env.VUE_APP_UPLOAD_API + '/upload/file'
+    this.uploadList = this.fileList
+  },
+  methods: {
+    handleRemove(file, fileList) {
+      this.uploadList = fileList
+      this.$emit('change', fileList)
+    },
+    beforeRemove(file, fileList) {
+      this.uploadList = fileList
+      return this.$confirm(`确定移除 ${file.name}?`)
+    },
+    handlePreview(file) {
+      console.log(file)
+    },
+    handleExceed(files, fileList) {
+      this.uploadList = fileList
+      this.$message.warning(`当前限制选择 ${this.limit} 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`)
+    },
+    onSuccess(response, file, fileList) {
+      this.uploadList = fileList
+      this.$emit('change', fileList)
+    },
+    onError(err, file, fileList) {
+      console.log(err)
+      this.uploadList = fileList
+    },
+    handleChange(file, fileList) {
+      this.uploadList = fileList
+      this.$emit('change', fileList)
+    },
+    submit() {
+      console.log('手动上传')
+      this.$refs.upload.submit()
+    },
+    clearAllFiles() {
+      this.uploadList = []
+    }
+  }
+}
+</script>
+
+<style lang="scss">
+.hide-upload{
+.el-upload{
+  display: none;
+}
+.el-upload-list__item:first-child{
+    margin-top: 6px;
+}
+
+}
+.file-upload{
+  position: relative;
+  .upload-btn{
+    position: absolute;
+    top: 2px;
+    left: 0;
+  }
+}
+</style>

+ 5 - 3
src/router/index.js

@@ -10,6 +10,7 @@ import supplierRoutes from './modules/supplier'
 import authRoutes from './modules/auth'
 import productRoutes from './modules/product'
 import reviewRoutes from './modules/review'
+import heloperRoutes from './modules/helper'
 // import proxyRoutes from './modules/proxy'
 import docRoutes from './modules/doc'
 import feedbackRoutes from './modules/feedback'
@@ -48,7 +49,7 @@ export const constantRoutes = [
   },
   {
     path: '/login',
-    component: () => import('@/views/login/index'),
+    component: () => import(/* webpackChunkName: "login" */ '@/views/login/index'),
     hidden: true
   },
   {
@@ -78,13 +79,13 @@ export const constantRoutes = [
     name: 'Password',
     redirect: 'edit',
     hidden: true,
-    meta: { title: '密码管理' },
+    meta: { title: '密码管理', id: 40 },
     children: [
       {
         path: 'edit',
         component: () => import('@/views/password/index'),
         name: 'Edit',
-        meta: { title: '修改密码' }
+        meta: { title: '修改密码', id: 2 }
       }
     ]
   }
@@ -100,6 +101,7 @@ export const asyncRoutes = [
   // ...proxyRoutes,
   ...docRoutes,
   ...feedbackRoutes,
+  ...heloperRoutes,
 
   // 404页面 放在最后面
   { path: '*', redirect: '/404', hidden: true }

+ 17 - 2
src/router/modules/auth.js

@@ -9,13 +9,28 @@ const authRoutes = [
     alwaysShow: true,
     redirect: '/auth/list',
     name: 'Auth',
-    meta: { title: '授权管理', icon: 'el-icon-s-promotion', roles: ['admin', 'normal'], noCache: true, proxy: true },
+    meta: {
+      title: '授权管理',
+      icon: 'el-icon-s-promotion',
+      roles: ['admin', 'normal'],
+      noCache: true,
+      proxy: true,
+      id: 1
+    },
     children: [
       {
         path: 'list',
         component: () => import('@/views/authentic/auth/index'),
         name: 'AuthList',
-        meta: { title: '授权列表', icon: 'el-icon-menu', roles: ['admin', 'normal'], affix: true, noCache: true, proxy: true }
+        meta: {
+          title: '授权列表',
+          icon: 'el-icon-menu',
+          roles: ['admin', 'normal'],
+          affix: true,
+          noCache: true,
+          proxy: true,
+          id: 2
+        }
       }
     ]
   }

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

@@ -9,20 +9,20 @@ const clubRoutes = [
     alwaysShow: true,
     redirect: '/club/list',
     name: 'Club',
-    meta: { title: '机构管理', icon: 'el-icon-user-solid', roles: ['normal'], noCache: true, proxy: true },
+    meta: { title: '机构管理', icon: 'el-icon-user-solid', roles: ['normal'], noCache: true, proxy: true, id: 3 },
     children: [
       {
         path: 'list',
         component: () => import('@/views/authentic/authuser/index'),
         name: 'ClubList',
-        meta: { title: '机构列表', icon: 'el-icon-menu', roles: ['normal'], noCache: true, proxy: true }
+        meta: { title: '机构列表', icon: 'el-icon-menu', roles: ['normal'], noCache: true, proxy: true, id: 4 }
       },
       {
         path: 'user-list',
         component: () => import('@/views/authentic/authuser/userList'),
         name: 'ClubUserList',
         hidden: true,
-        meta: { title: '用户列表', icon: 'el-icon-menu', roles: ['normal'], noCache: true, proxy: true }
+        meta: { title: '用户列表', icon: 'el-icon-menu', roles: ['normal'], noCache: true, proxy: true, id: 5 }
       }
     ]
   }

+ 14 - 7
src/router/modules/doc.js

@@ -9,45 +9,52 @@ const docRoutes = [
     alwaysShow: true,
     redirect: '/doc/article-list',
     name: 'Doc',
-    meta: { title: '资料管理', icon: 'el-icon-s-management', roles: ['normal'], noCache: true, proxy: true },
+    meta: { title: '资料管理', icon: 'el-icon-s-management', roles: ['normal'], noCache: true, proxy: true, id: 6 },
     children: [
       {
         path: 'article-list',
         component: () => import('@/views/authentic/doc/articleList'),
         name: 'ArticleList',
-        meta: { title: '文章列表', icon: 'el-icon-tickets', roles: ['normal'], noCache: true, proxy: true }
+        meta: { title: '文章列表', icon: 'el-icon-tickets', roles: ['normal'], noCache: true, proxy: true, id: 7 }
       },
       {
         path: 'article-edit',
         component: () => import('@/views/authentic/doc/articleEdit'),
         hidden: true,
         name: 'ArticleEdit',
-        meta: { title: '编辑文章', icon: 'el-icon-menu', roles: ['normal'], noCache: true, proxy: true }
+        meta: { title: '编辑文章', icon: 'el-icon-menu', roles: ['normal'], noCache: true, proxy: true, id: 8 }
       },
       {
         path: 'image-list',
         component: () => import('@/views/authentic/doc/imageList'),
         name: 'ImageList',
-        meta: { title: '图片列表', icon: 'el-icon-picture-outline', roles: ['normal'], noCache: true, proxy: true }
+        meta: {
+          title: '图片列表',
+          icon: 'el-icon-picture-outline',
+          roles: ['normal'],
+          noCache: true,
+          proxy: true,
+          id: 9
+        }
       },
       {
         path: 'image-edit',
         component: () => import('@/views/authentic/doc/imageEdit'),
         hidden: true,
         name: 'ImageEdit',
-        meta: { title: '编辑图片', icon: 'el-icon-menu', roles: ['normal'], noCache: true, proxy: true }
+        meta: { title: '编辑图片', icon: 'el-icon-menu', roles: ['normal'], noCache: true, proxy: true, id: 10 }
       },
       {
         path: 'video-list',
         component: () => import('@/views/authentic/doc/videoList'),
         name: 'VideoList',
-        meta: { title: '视频列表', icon: 'el-icon-video-camera', roles: ['normal'], noCache: true, proxy: true }
+        meta: { title: '视频列表', icon: 'el-icon-video-camera', roles: ['normal'], noCache: true, proxy: true, id: 11 }
       },
       {
         path: 'file-list',
         component: () => import('@/views/authentic/doc/fileList'),
         name: 'FileList',
-        meta: { title: '文件列表', icon: 'el-icon-receiving', roles: ['normal'], noCache: true, proxy: true }
+        meta: { title: '文件列表', icon: 'el-icon-receiving', roles: ['normal'], noCache: true, proxy: true, id: 12 }
       }
     ]
   }

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

@@ -9,20 +9,20 @@ const feedbackRoutes = [
     alwaysShow: true,
     redirect: '/feedback/list',
     name: 'Feedback',
-    meta: { title: '用户反馈', icon: 'el-icon-s-comment', roles: ['normal'], noCache: true },
+    meta: { title: '用户反馈', icon: 'el-icon-s-comment', roles: ['normal'], noCache: true, id: 13 },
     children: [
       {
         path: 'list',
         component: () => import('@/views/authentic/feedback/index'),
         name: 'FeedbackList',
-        meta: { title: '反馈列表', icon: 'el-icon-menu', roles: ['normal'], noCache: true }
+        meta: { title: '反馈列表', icon: 'el-icon-menu', roles: ['normal'], noCache: true, id: 14 }
       },
       {
         path: 'detail',
         component: () => import('@/views/authentic/feedback/detail'),
         name: 'FeedbackDetail',
         hidden: true,
-        meta: { title: '反馈处理', icon: 'el-icon-menu', roles: ['normal'], noCache: true }
+        meta: { title: '反馈处理', icon: 'el-icon-menu', roles: ['normal'], noCache: true, id: 15 }
       }
     ]
   }

+ 53 - 0
src/router/modules/helper.js

@@ -0,0 +1,53 @@
+/* Layout */
+import Layout from '@/layout'
+
+// 授权管理页面
+const heloperRoutes = [
+  {
+    path: '/helper',
+    component: Layout,
+    alwaysShow: true,
+    redirect: '/helper/video',
+    name: 'Helper',
+    meta: {
+      title: '新手帮助',
+      icon: 'el-icon-s-promotion',
+      roles: ['admin', 'normal'],
+      noCache: true,
+      proxy: true,
+      id: 16
+    },
+    children: [
+      {
+        path: 'video',
+        component: () => import('@/views/authentic/helper/video'),
+        name: 'HelperVideo',
+        meta: {
+          title: '视频教程',
+          icon: 'el-icon-menu',
+          roles: ['admin', 'normal'],
+          affix: false,
+          noCache: true,
+          proxy: false,
+          id: 17
+        }
+      },
+      {
+        path: 'document',
+        component: () => import('@/views/authentic/helper/document'),
+        name: 'HelperDocument',
+        meta: {
+          title: '文档教程',
+          icon: 'el-icon-menu',
+          roles: ['admin', 'normal'],
+          affix: false,
+          noCache: true,
+          proxy: false,
+          id: 18
+        }
+      }
+    ]
+  }
+]
+
+export default heloperRoutes

+ 4 - 4
src/router/modules/product.js

@@ -10,28 +10,28 @@ const productRoutes = [
     redirect: '/product/list',
     hidden: true,
     name: 'Product',
-    meta: { title: '商品管理', icon: 'el-icon-s-shop', roles: ['admin', 'normal'], noCache: true },
+    meta: { title: '商品管理', icon: 'el-icon-s-shop', roles: ['admin', 'normal'], noCache: true, id: 19 },
     children: [
       {
         hidden: true,
         path: 'list',
         component: () => import('@/views/authentic/product/index'),
         name: 'ProductList',
-        meta: { title: '商品列表', icon: 'el-icon-menu', roles: ['admin', 'normal'], noCache: true }
+        meta: { title: '商品列表', icon: 'el-icon-menu', roles: ['admin', 'normal'], noCache: true, id: 20 }
       },
       {
         hidden: true,
         path: 'add',
         component: () => import('@/views/authentic/product/add'),
         name: 'AddProduct',
-        meta: { title: '添加商品', icon: 'el-icon-menu', roles: ['normal'], noCache: true, proxy: true }
+        meta: { title: '添加商品', icon: 'el-icon-menu', roles: ['normal'], noCache: true, proxy: true, id: 21 }
       },
       {
         hidden: true,
         path: 'edit',
         component: () => import('@/views/authentic/product/edit'),
         name: 'EditProduct',
-        meta: { title: '修改商品', icon: 'el-icon-menu', roles: ['normal'], noCache: true, proxy: true }
+        meta: { title: '修改商品', icon: 'el-icon-menu', roles: ['normal'], noCache: true, proxy: true, id: 22 }
       }
     ]
   }

+ 13 - 13
src/router/modules/review.js

@@ -10,34 +10,34 @@ const reviewRoutes = [
     alwaysShow: true,
     name: 'ReviewAuth',
     redirect: '/review/auth/list',
-    meta: { title: '品牌授权审核', icon: 'el-icon-s-check', roles: ['admin'], noCache: true },
+    meta: { title: '品牌授权审核', icon: 'el-icon-s-check', roles: ['admin'], noCache: true, id: 23 },
     children: [
       {
         path: 'list',
         component: () => import('@/views/authentic/review/auth/index'),
         name: 'ReviewList',
-        meta: { title: '审核列表', icon: 'el-icon-menu', roles: ['admin'], noCache: true }
+        meta: { title: '审核列表', icon: 'el-icon-menu', roles: ['admin'], noCache: true, id: 24 }
       },
       {
         path: 'auth-list',
         hidden: true,
         component: () => import('@/views/authentic/review/auth/authList'),
         name: 'ReviewAuthList',
-        meta: { title: '授权机构审核列表', icon: 'el-icon-menu', roles: ['admin'], noCache: true }
+        meta: { title: '授权机构审核列表', icon: 'el-icon-menu', roles: ['admin'], noCache: true, id: 25 }
       },
       {
         path: 'shop-list',
         hidden: true,
         component: () => import('@/views/authentic/review/auth/shopList'),
         name: 'ShopList',
-        meta: { title: '商品审核列表', icon: 'el-icon-menu', roles: ['admin'], noCache: true }
+        meta: { title: '商品审核列表', icon: 'el-icon-menu', roles: ['admin'], noCache: true, id: 26 }
       },
       {
         path: 'shop-detail',
         hidden: true,
         component: () => import('@/views/authentic/review/auth/shopDetail'),
         name: 'ShopDetail',
-        meta: { title: '商品审核详情', icon: 'el-icon-menu', roles: ['admin'], noCache: true }
+        meta: { title: '商品审核详情', icon: 'el-icon-menu', roles: ['admin'], noCache: true, id: 27 }
       }
     ]
   },
@@ -48,55 +48,55 @@ const reviewRoutes = [
     alwaysShow: true,
     name: 'ReviewDoc',
     redirect: '/review/doc/list',
-    meta: { title: '资料审核管理', icon: 'el-icon-s-check', roles: ['admin'], noCache: true },
+    meta: { title: '资料审核管理', icon: 'el-icon-s-check', roles: ['admin'], noCache: true, id: 28 },
     children: [
       {
         path: 'list',
         component: () => import('@/views/authentic/review/doc/index'),
         name: 'ReviewDocList',
-        meta: { title: '审核列表', icon: 'el-icon-menu', roles: ['admin'], noCache: true }
+        meta: { title: '审核列表', icon: 'el-icon-menu', roles: ['admin'], noCache: true, id: 29 }
       },
       {
         path: 'article',
         component: () => import('@/views/authentic/review/doc/articleList'),
         name: 'ReviewDocArticle',
         hidden: true,
-        meta: { title: '文章审核列表', icon: 'el-icon-menu', roles: ['admin'], noCache: true }
+        meta: { title: '文章审核列表', icon: 'el-icon-menu', roles: ['admin'], noCache: true, id: 30 }
       },
       {
         path: 'article/detail',
         component: () => import('@/views/authentic/review/doc/articleDetail'),
         name: 'ReviewDocArticleDetail',
         hidden: true,
-        meta: { title: '审核文章', icon: 'el-icon-menu', roles: ['admin'], noCache: true }
+        meta: { title: '审核文章', icon: 'el-icon-menu', roles: ['admin'], noCache: true, id: 31 }
       },
       {
         path: 'image',
         component: () => import('@/views/authentic/review/doc/imageList'),
         name: 'ReviewDocImage',
         hidden: true,
-        meta: { title: '图片审核列表', icon: 'el-icon-menu', roles: ['admin'], noCache: true }
+        meta: { title: '图片审核列表', icon: 'el-icon-menu', roles: ['admin'], noCache: true, id: 32 }
       },
       {
         path: 'image/detail',
         component: () => import('@/views/authentic/review/doc/imageDetail'),
         name: 'ReviewDocImageDetail',
         hidden: true,
-        meta: { title: '审核图片', icon: 'el-icon-menu', roles: ['admin'], noCache: true }
+        meta: { title: '审核图片', icon: 'el-icon-menu', roles: ['admin'], noCache: true, id: 33 }
       },
       {
         path: 'video',
         component: () => import('@/views/authentic/review/doc/videoList'),
         name: 'ReviewDocVideo',
         hidden: true,
-        meta: { title: '视频审核列表', icon: 'el-icon-menu', roles: ['admin'], noCache: true }
+        meta: { title: '视频审核列表', icon: 'el-icon-menu', roles: ['admin'], noCache: true, id: 34 }
       },
       {
         path: 'file',
         component: () => import('@/views/authentic/review/doc/fileList'),
         name: 'ReviewDocFile',
         hidden: true,
-        meta: { title: '文件审核列表', icon: 'el-icon-menu', roles: ['admin'], noCache: true }
+        meta: { title: '文件审核列表', icon: 'el-icon-menu', roles: ['admin'], noCache: true, id: 35 }
       }
     ]
   }

+ 4 - 4
src/router/modules/supplier.js

@@ -9,27 +9,27 @@ const supplierRoutes = [
     alwaysShow: true,
     name: 'Supplier',
     redirect: '/supplier/list',
-    meta: { title: '供应商管理', icon: 'el-icon-s-custom', roles: ['admin'], noCache: true },
+    meta: { title: '供应商管理', icon: 'el-icon-s-custom', roles: ['admin'], noCache: true, id: 36 },
     children: [
       {
         path: 'list',
         component: () => import('@/views/authentic/supplier/index'),
         name: 'SupplierList',
-        meta: { title: '供应商列表', icon: 'el-icon-menu', affix: true, roles: ['admin'], noCache: true }
+        meta: { title: '供应商列表', icon: 'el-icon-menu', affix: true, roles: ['admin'], noCache: true, id: 37 }
       },
       {
         hidden: true,
         path: 'add',
         component: () => import('@/views/authentic/supplier/add'),
         name: 'SupplierAdd',
-        meta: { title: '添加供应商', icon: 'el-icon-menu', roles: ['admin'], noCache: true }
+        meta: { title: '添加供应商', icon: 'el-icon-menu', roles: ['admin'], noCache: true, id: 38 }
       },
       {
         hidden: true,
         path: 'edit',
         component: () => import('@/views/authentic/supplier/edit'),
         name: 'SupplierEdit',
-        meta: { title: '修改供应商', icon: 'el-icon-menu', roles: ['admin'], noCache: true }
+        meta: { title: '修改供应商', icon: 'el-icon-menu', roles: ['admin'], noCache: true, id: 39 }
       }
     ]
   }

+ 2 - 0
src/store/getters.js

@@ -11,9 +11,11 @@ const getters = {
   roles: state => state.user.roles,
   authUserId: state => state.user.authUserId,
   userIdentity: state => state.user.userIdentity,
+  copyUserInfo: state => state.user.copyUserInfo,
   permission_routes: state => state.permission.routes,
   errorLogs: state => state.errorLog.logs,
   initRouter: state => state.permission.initRouter,
+  routes: state => state.permission.routes,
   proxyInfo: state => state.proxy.proxyInfo,
   proxyState: state => state.proxy.proxyState,
   isChangeProxy: state => state.proxy.isChangeProxy,

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

@@ -3,7 +3,7 @@ import { getToken, setToken, removeToken, setUser, getUser, removeUser } from '@
 import { resetRouter } from '@/router'
 const userInfo = getUser() && JSON.parse(getUser())
 
-const formatRoles = (userIdentity) => {
+const formatRoles = userIdentity => {
   let roles = []
   switch (userIdentity) {
     case 1:
@@ -28,7 +28,8 @@ const state = {
   userIdentity: userInfo?.userIdentity || '',
   proxyInfo: null,
   shopType: userInfo?.shopType || '',
-  brandId: userInfo?.brandId || ''
+  brandId: userInfo?.brandId || '',
+  copyUserInfo: userInfo // 原始登录用户信息
 }
 
 const mutations = {
@@ -61,7 +62,7 @@ const mutations = {
     state.shopType = shopType
   },
   // 重置用户状态
-  RESET_STATE: (state) => {
+  RESET_STATE: state => {
     state.token = getToken()
     state.name = userInfo?.name || ''
     state.roles = formatRoles(userInfo?.userIdentity)

+ 52 - 0
src/utils/formatRoutesToModule.js

@@ -0,0 +1,52 @@
+import { constantRoutes, asyncRoutes } from '@/router/index'
+import store from '@/store'
+
+let routesTree = []
+let routes = []
+
+function getRoutes() {
+  const roles = store.getters.roles
+  routes = [...constantRoutes, ...asyncRoutes].filter(item => item.meta)
+  if (!roles.includes('admin')) {
+    routes = routes.filter(route => !route.meta.roles || route.meta.roles.includes('normal'))
+  }
+  return routes
+}
+
+function formatRoutesToModule() {
+  routes = getRoutes()
+  routesTree = []
+  routes.forEach(first => {
+    const obj = {
+      label: first.meta.title,
+      value: first.meta.id
+    }
+    if (first.children) {
+      obj.children = []
+      first.children.forEach(second => {
+        obj.children.push({
+          label: second.meta.title,
+          value: second.meta.id
+        })
+      })
+    }
+    routesTree.push(obj)
+  })
+
+  return routesTree
+}
+
+export function getToutesTree() {
+  return formatRoutesToModule()
+}
+
+// 根据id获取栏目
+export function getModuleType(ids) {
+  ids = ids.split('-')
+  const parent = routes.find(item => item.meta.id === parseInt(ids[0]))
+  const children = parent && parent.children.find(item => item.meta.id === parseInt(ids[1]))
+  if (!parent || !children) {
+    return ''
+  }
+  return `${parent.meta.title}/${children.meta.title}`
+}

+ 21 - 3
src/utils/open-window.js

@@ -1,9 +1,10 @@
 /**
  *Created by PanJiaChen on 16/11/29.
  * @param {Sting} url 子窗口需要打开的页面url
+ * @param {Sting} strWindowName 子窗口名称
  * @param {Sting} title 页面标题
  */
-export default function openWindow(url, title, w, h) {
+export default function openWindow(url, strWindowName, title, w, h) {
   // Fixes dual-screen position                            Most browsers       Firefox
   // const dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : screen.left
   // const dualScreenTop = window.screenTop !== undefined ? window.screenTop : screen.top
@@ -19,10 +20,27 @@ export default function openWindow(url, title, w, h) {
   const left = (screen.availWidth - width) / 2
   const top = (screen.availHeight - height) / 2
 
-  const newWindow = window.open(url, title, 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=yes, copyhistory=no, width=' + width + ', height=' + height + ', top=' + top + ', left=' + left)
+  const newWindow = window.open(
+    url,
+    strWindowName,
+    title,
+    'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=yes, copyhistory=no, width=' +
+      width +
+      ', height=' +
+      height +
+      ', top=' +
+      top +
+      ', left=' +
+      left
+  )
   // Puts focus on the newWindow
   if (window.focus) {
     newWindow.focus()
   }
-}
+  // 修改窗口标题
+  newWindow.onload = function() {
+    newWindow.document.title = title
+  }
 
+  console.log()
+}

+ 10 - 5
src/utils/request.js

@@ -12,15 +12,20 @@ NProgress.configure({ showSpinner: false }) // NProgress Configuration
 const service = axios.create({
   baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
   // withCredentials: true, // send cookies when cross-domain requests
-  timeout: 6000 // request timeout
+  timeout: 60000 // request timeout
 })
 
 // 请求拦截
 service.interceptors.request.use(
   config => {
     NProgress.start()
-    config.headers['Content-Type'] = 'application/json'
-    config.data = JSON.stringify(config.data)
+    // 默认以application/json 格式传递参数
+    config.headers['Content-Type'] = config.headers['Content-Type'] || 'application/json'
+    // 只有以当 Content-Type === application/json 是对参数序列化
+    if (config.headers['Content-Type'] === 'application/json') {
+      config.data = JSON.stringify(config.data)
+    }
+
     const token = getToken()
     if (token) {
       config.headers['X-Token'] = token
@@ -38,7 +43,7 @@ service.interceptors.response.use(
   /**
    * If you want to get http information such as headers or status
    * Please return  response => response
-  */
+   */
 
   /**
    * Determine the request status by custom code
@@ -57,7 +62,7 @@ service.interceptors.response.use(
       }, 500)
       NProgress.done()
       return
-    // 返回不成功
+      // 返回不成功
     } else if (res.code !== 0) {
       Message({
         message: res.msg || '操作失败了,请重试!',

+ 50 - 2
src/utils/tools.js

@@ -52,8 +52,47 @@ export function debounce(func, wait, immediate = false) {
  * @returns hash字符串
  */
 export function createHash(hashLength) {
-  if (!hashLength || typeof (Number(hashLength)) !== 'number') { return }
-  var ar = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
+  if (!hashLength || typeof Number(hashLength) !== 'number') {
+    return
+  }
+  var ar = [
+    '1',
+    '2',
+    '3',
+    '4',
+    '5',
+    '6',
+    '7',
+    '8',
+    '9',
+    '0',
+    'a',
+    'b',
+    'c',
+    'd',
+    'e',
+    'f',
+    'g',
+    'h',
+    'i',
+    'j',
+    'k',
+    'l',
+    'm',
+    'n',
+    'o',
+    'p',
+    'q',
+    'r',
+    's',
+    't',
+    'u',
+    'v',
+    'w',
+    'x',
+    'y',
+    'z'
+  ]
   var hs = []
   var hl = Number(hashLength)
   var al = ar.length
@@ -62,3 +101,12 @@ export function createHash(hashLength) {
   }
   return hs.join('')
 }
+
+// 通过a标签下载文件
+export function downLoadWithATag(href) {
+  const downLink = document.createElement('a')
+  downLink.href = href
+  downLink.style.display = 'none'
+  downLink.setAttribute('download', true)
+  downLink.click()
+}

+ 141 - 8
src/views/authentic/auth/index.vue

@@ -33,6 +33,9 @@
       </el-select>
       <el-button icon="el-icon-search" type="primary" @click="getList">查询</el-button>
       <el-button v-if="userIdentity === 2 || proxyInfo!==null" icon="el-icon-edit" type="primary" @click="handleShowEditDialog('添加品牌授权')">添加品牌授权</el-button>
+      <el-button icon="el-icon-upload" type="primary" @click="improtDialogVisible = true">导入</el-button>
+      <el-button icon="el-icon-document" type="primary" @click="handleExportExcel">导出</el-button>
+      <el-button icon="el-icon-document-copy" type="primary" @click="downLoadExportExcel">获取导入模板</el-button>
     </div>
     <!-- 表格区域 -->
     <el-table
@@ -144,17 +147,39 @@
         <el-button type="primary" :disabled="disabled" @click="handleUpdateBrandAuth">确 定</el-button>
       </span>
     </el-dialog>
+    <!-- 导入对话框 -->
+    <!-- dialog Start -->
+    <el-dialog
+      title="导入"
+      :visible.sync="improtDialogVisible"
+      width="30%"
+      @close="improtDialogClose"
+    >
+      <el-form ref="dialogForm" :model="improtDialogFormData" label-width="86px" :rules="improtDialogFormRules">
+        <el-form-item label="文件路径:" prop="fileUrl">
+          <file-upload ref="fileUpload" :file-list="uploadFileList" @change="fileUploadChange" />
+          <el-input v-show="false" v-model="improtDialogFormData.fileUrl" />
+        </el-form-item>
+      </el-form>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="improtDialogVisible = false">取 消</el-button>
+        <el-button type="primary" :disabled="!saveBtnClickable" :loading="requestLoading" @click="submitUpload">确 定</el-button>
+      </span>
+    </el-dialog>
+    <!-- dialog END -->
   </div>
 </template>
 
 <script>
-import { fecthAuthList, saveBrandAuth, changeAuthStatus, removeAuth } from '@/api/auth'
+import FileUpload from '@/components/FileUpload'
+import { fecthAuthList, saveBrandAuth, changeAuthStatus, removeAuth, authImportExcel } from '@/api/auth'
 import Pagination from '@/components/Pagination' // secondary package based on el-pagination
 import { mapGetters } from 'vuex'
 import { formatDate } from '@/utils'
+import { debounce, downLoadWithATag } from '@/utils/tools'
 export default {
   name: 'ComplexTable',
-  components: { Pagination },
+  components: { Pagination, FileUpload },
   filters: {
     formatTime(time) {
       if (!time) {
@@ -197,11 +222,31 @@ export default {
       disabled: false,
       // 审核未通过
       auditFailedList: [],
-      auditNoticeFlag: true
+      auditNoticeFlag: true,
+      // ------------------
+      improtDialogVisible: false,
+      requestLoading: false,
+      uploadFileList: [],
+      improtDialogFormData: {
+        fileUrl: ''
+      },
+      improtDialogFormRules: {
+        fileUrl: [
+          {
+            required: true,
+            message: '请选择文件', trigger: 'change'
+          }
+        ]
+      },
+      chooseFile: ''
     }
   },
   computed: {
-    ...mapGetters(['authUserId', 'userIdentity', 'proxyInfo'])
+    ...mapGetters(['authUserId', 'userIdentity', 'proxyInfo', 'copyUserInfo']),
+    saveBtnClickable() {
+      return this.uploadFileList.length > 0
+    }
+
   },
   created() {
     this.listQuery.authUserId = this.$route.query.id || this.proxyInfo?.authUserId || this.authUserId
@@ -212,11 +257,99 @@ export default {
     }
     this.getList()
   },
-  destroyed() {
-    // 页面关闭时清空代理数据
-    // this.$store.commit('user/SET_PROXY_INFO', null)
-  },
   methods: {
+    // 上传文件
+    submitUpload() {
+      this.$refs.dialogForm.validate(valid => {
+        console.log(valid)
+        if (!valid) return
+        this.requestLoading = true // 上传文件
+        // this.$refs.fileUpload.submit()
+        this.handleSave()
+      })
+    },
+    // 监听上传文件的状态变化
+    async fileUploadChange(fileList) {
+      this.uploadFileList = fileList
+      try {
+        await this.handleFileUploadStatus(fileList)
+        this.handleSave.apply(this)
+      } catch (error) {
+        console.log(error)
+      }
+    },
+
+    // 下载模板
+    downLoadExportExcel() {
+      downLoadWithATag(`${process.env.VUE_APP_BASE_API}/download/file?ossName=%E6%AD%A3%E5%93%81%E8%81%94%E7%9B%9F%E6%9C%BA%E6%9E%84%E3%80%81%E5%95%86%E5%93%81%E5%AF%BC%E5%85%A5%E6%A8%A1%E6%9D%BF.xlsx&fileName=%E6%AD%A3%E5%93%81%E8%81%94%E7%9B%9F%E6%9C%BA%E6%9E%84%E3%80%81%E5%95%86%E5%93%81%E5%AF%BC%E5%85%A5%E6%A8%A1%E6%9D%BF.xlsx`)
+    },
+
+    // 导出为Excel
+    async handleExportExcel() {
+      const text = await this.$confirm('确认导出所有授权机构的数据吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).catch(() => {
+        this.$message.info('已取消操作')
+      })
+      if (text !== 'confirm') return
+      // 使用a链接下载
+      downLoadWithATag(`${process.env.VUE_APP_BASE_API}/auth/export/excel?authUserId=${this.authUserId}`)
+    },
+
+    // 导入Excel 并提交
+    handleSave: debounce(function() {
+      console.log('保存')
+      console.log(this.improtDialogFormData)
+      console.log(this.proxyInfo, this.authUserId)
+      // 上传文件使用 multipart/form-data
+      const formData = new FormData()
+
+      formData.append('authUserId', this.authUserId)
+      formData.append('createBy', this.copyUserInfo.authUserId)
+      formData.append('file', this.chooseFile)
+
+      authImportExcel(formData)
+        .then(res => {
+          this.$message.success(res.data)
+          this.improtDialogVisible = false
+          this.getList()
+        })
+        .catch(err => { console.log(err) })
+        .finally(() => {
+          this.requestLoading = false
+        })
+    }, 200),
+
+    // 处理文件上传状态
+    handleFileUploadStatus(fileList) {
+      console.log(fileList)
+      this.chooseFile = fileList[0].raw
+      // 文件列表为空
+      if (fileList.length <= 0) {
+        this.improtDialogFormData.fileUrl = ''
+        return Promise.reject('faild')
+      }
+      // 取第一个文件
+      const { response, status } = fileList[0]
+      // 文件已选择但未上传
+      if (status === 'ready') {
+        this.improtDialogFormData.fileUrl = status
+        return Promise.reject('faild')
+      }
+      // 文件已上传
+      if (status === 'success') {
+        this.improtDialogFormData.fileUrl = response.previewUrl
+        return Promise.resolve('success')
+      }
+    },
+    improtDialogClose() {
+      console.log(123)
+      // this.uploadFileList = []
+      this.$refs.fileUpload.clearAllFiles()
+      this.$refs.dialogForm.resetFields()
+    },
     // 获取授权列表
     getList() {
       this.listLoading = true

+ 400 - 0
src/views/authentic/helper/document.vue

@@ -0,0 +1,400 @@
+<template>
+  <div class="app-container">
+    <!-- 搜索区域 -->
+    <div class="filter-container">
+      <span>标题:</span>
+      <el-input
+        v-model="listQuery.fileTitle"
+        placeholder="标题"
+        style="width: 200px"
+        class="filter-item"
+        @keyup.enter.native="getList"
+      />
+      <span>所属模块:</span>
+
+      <el-cascader
+        v-model="listQuery.fileModule"
+        :options="modules"
+        class="filter-item"
+        placeholder="所属模块"
+        style="margin-rigth: 15px"
+        clearable
+        @change="getList"
+      />
+      <el-button type="primary" icon="el-icon-search" @click="getList">查询</el-button>
+      <el-button
+        v-if="userIdentity === 1"
+        icon="el-icon-edit"
+        type="primary"
+        @click="dialogVisible = true"
+      >添加</el-button>
+    </div>
+    <!-- 搜索区域END -->
+    <!-- 表格区域 -->
+    <el-table
+      v-loading="listLoading"
+      :data="list"
+      style="width: 100%"
+      border
+      fit
+      highlight-current-row
+      cell-class-name="table-cell"
+    >
+      <el-table-column
+        v-loading="listLoading"
+        :data="list"
+        style="width: 100%"
+        border
+        fit
+        highlight-current-row
+        cell-class-name="table-cell"
+      >
+        <el-table-column label="序号" :index="indexMethod" type="index" width="80" align="center" />
+        <el-table-column label="标题" prop="fileTitle" align="center" />
+        <el-table-column label="所属模块" align="center" prop="fileModuleType" />
+        <el-table-column label="创建时间" width="240px" align="center">
+          <template slot-scope="{ row }">
+            {{ row.createTime | formatTime }}
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" align="center">
+          <template slot-scope="{ row }">
+            <el-button
+              v-if="userIdentity === 1"
+              type="primary"
+              size="mini"
+              style="margin-right:5px"
+              icon="el-icon-edit"
+              @click="handleEditFile(row)"
+            >编辑</el-button>
+
+            <el-button
+              type="success"
+              size="mini"
+              style="margin-right:5px"
+              icon="el-icon-document"
+              @click="handlePreview(row)"
+            >查看</el-button>
+
+            <el-button
+              v-if="userIdentity === 1"
+              type="danger"
+              size="mini"
+              style="margin-right:5px"
+              icon="el-icon-s-check"
+              @click="handleRemove(row)"
+            >删除</el-button>
+
+          </template>
+        </el-table-column>
+      </el-table-column></el-table>
+    <!-- 表格区域END -->
+    <pagination v-show="total>0" :total="total" :page.sync="listQuery.pageNum" :limit.sync="listQuery.pageSize" @pagination="getList(listQuery)" />
+
+    <!-- 文档编辑dialog -->
+    <el-dialog
+      title="添加文档"
+      :visible="dialogVisible"
+      width="30%"
+      @close="dialogClose"
+    >
+
+      <el-form ref="dialogForm" :model="dialogFormData" label-width="86px" :rules="rules">
+        <el-form-item label="标题:" prop="fileTitle">
+          <el-input v-model="dialogFormData.fileTitle" placeholder="请输入标题" />
+        </el-form-item>
+        <el-form-item label="文档路径:" prop="fileUrl">
+          <file-upload ref="fileUpload" :file-list="uploadFileList" accept-type=".doc,.docx" @change="fileUploadChange" />
+          <el-input v-show="false" v-model="dialogFormData.fileUrl" />
+        </el-form-item>
+        <el-form-item label="所属模块:" prop="fileModule">
+          <el-cascader
+            v-if="dialogVisible"
+            v-model="dialogFormData.fileModule"
+            :options="modules"
+            placeholder="所属模块"
+            clearable
+          />
+        </el-form-item>
+      </el-form>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="dialogVisible = false">取 消</el-button>
+        <el-button type="primary" :disabled="!saveBtnClickable" :loading="requestLoading" @click="submitUpload">确 定</el-button>
+      </span>
+    </el-dialog>
+    <!-- 文档编辑dialog END -->
+  </div>
+</template>
+
+<script>
+import FileUpload from '@/components/FileUpload'
+import Pagination from '@/components/Pagination' // secondary package based on el-pagination
+import openWindow from '@/utils/open-window'
+import { formatDate } from '@/utils'
+import { mapGetters } from 'vuex'
+import { fetchCourseList, saveCourse, removeCourse } from '@/api/helper'
+import { getToutesTree, getModuleType } from '@/utils/formatRoutesToModule'
+import { debounce } from '@/utils/tools'
+export default {
+  components: { Pagination, FileUpload },
+  filters: {
+    formatTime(time) {
+      if (!time) {
+        return ''
+      }
+      return formatDate(time, 'yyyy-MM-DD HH:mm:ss')
+    }
+  },
+
+  data() {
+    return {
+      listLoading: false,
+      dialogVisible: false,
+      requestLoading: false,
+      total: 0,
+      listQuery: {
+        fileType: 2, // 文件类型:1视频,2文档
+        fileTitle: '', // 文件标题
+        fileModule: [], // 文件模块:1品牌授权-授权列表,2机构管理-机构列表
+        pageNum: 1,
+        pageSize: 10
+      },
+      modules: [],
+      list: [],
+      uploadFileList: [],
+      dialogFormData: {},
+      rules: {
+        fileTitle: [{
+          required: true,
+          message: '请输入标题', trigger: ['change', 'blur']
+        }],
+        fileUrl: [
+          {
+            required: true,
+            message: '请选择文件', trigger: 'change'
+          }
+        ],
+        fileModule: [{
+          required: true,
+          message: '请选择所属模块', trigger: 'change'
+        }]
+      }
+    }
+  },
+  computed: {
+    ...mapGetters(['authUserId', 'userIdentity', 'proxyInfo', 'routes']),
+    saveBtnClickable() {
+      return this.uploadFileList.length > 0
+    }
+  },
+  created() {
+    this.dialogFormData = this.resetDialogFormData()
+    this.modules = getToutesTree(this.routes)
+    this.getList()
+  },
+  methods: {
+    // 初始化dialog formdata
+    resetDialogFormData() {
+      return {
+        fileTitle: '',
+        fileUrl: '',
+        fileId: '',
+        fileName: '',
+        fileType: 2,
+        fileModule: []
+      }
+    },
+
+    // 上传文件
+    submitUpload() {
+      if (this.userIdentity !== 1) return
+      this.$refs.dialogForm.validate(valid => {
+        console.log(valid)
+        if (!valid) return
+        this.requestLoading = true // 上传文件 保存 loading
+
+        const uploadFile = this.uploadFileList[0]
+        // 文件如果已上传 直接保存
+        if (uploadFile && uploadFile.status === 'success') {
+          this.handleSave()
+        } else {
+          // 上传文件
+          this.$refs.fileUpload.submit()
+        }
+        console.log(this.uploadFileList)
+      })
+    },
+    // 监听上传文件的状态变化
+    async fileUploadChange(fileList) {
+      this.uploadFileList = fileList
+      try {
+        await this.handleFileUploadStatus(fileList)
+        this.handleSave.apply(this)
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 保存 TODO
+    handleSave: debounce(function() {
+      if (this.userIdentity !== 1) return
+      const params = {
+        fileId: this.dialogFormData.fileId || '',
+        fileTitle: this.dialogFormData.fileTitle,
+        fileName: this.dialogFormData.fileName,
+        ossName: this.dialogFormData.fileUrl,
+        fileType: this.dialogFormData.fileType,
+        fileModule: this.dialogFormData.fileModule.join('-')
+      }
+      saveCourse(params).then(res => {
+        this.$message.success(res.data)
+        this.dialogVisible = false
+        this.getList()
+      }).catch(err => {
+        console.log(err)
+      }).finally(() => {
+        this.requestLoading = false
+      })
+    }, 200),
+
+    // 处理文件上传状态
+    handleFileUploadStatus(fileList) {
+      // 文件列表为空
+      if (fileList.length <= 0) {
+        this.dialogFormData.fileUrl = ''
+        return Promise.reject('faild')
+      }
+      // 取第一个文件
+      const { response, status } = fileList[0]
+      // 文件已选择但未上传
+      if (status === 'ready') {
+        this.dialogFormData.fileUrl = status
+        return Promise.reject('faild')
+      }
+      // 文件已上传
+      if (status === 'success') {
+        this.dialogFormData.fileUrl = response.downloadUrl
+        this.dialogFormData.fileName = response.fileName
+        return Promise.resolve('success')
+      }
+      console.log(response)
+    },
+
+    // 数据回显 修改
+    handleEditFile(row) {
+      if (this.userIdentity !== 1) return
+      const fileModule = row.fileModule.split('-')
+      const i = parseInt(fileModule[0])
+      const j = parseInt(fileModule[1])
+      // dialog 表单数据
+      this.dialogFormData.fileTitle = row.fileTitle
+      this.dialogFormData.fileUrl = row.ossName
+      this.dialogFormData.fileId = row.fileId
+      this.dialogFormData.fileName = row.fileName
+      this.dialogFormData.fileType = 2
+      this.dialogFormData.fileModule = [i, j]
+      // 文件回显列表
+      this.uploadFileList = [{ url: row.fileUrl, name: row.fileName }]
+      this.dialogVisible = true
+    },
+
+    // 获取列表数据
+    getList() {
+      this.listLoading = true
+      const params = {
+        ...this.listQuery,
+        authUserId: this.authUserId,
+        fileModule: this.listQuery.fileModule.join('-')
+      }
+      fetchCourseList(params)
+        .then(res => {
+          if (res.code !== 0) return
+          this.list = this.formatFileModuleType(res.data.list)
+          this.total = res.data.total
+        })
+        .finally(() => {
+          this.listLoading = false
+        })
+    },
+    // 删除
+    async handleRemove(row) {
+      if (this.userIdentity !== 1) return
+      const text = await this.$confirm('确认删除该帮助文档吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).catch(() => {
+        this.$message.info('已取消操作')
+      })
+      if (text !== 'confirm') return
+      removeCourse({ fileId: row.fileId })
+        .then(res => {
+          if (res.code !== 0) return
+          this.$message.success(res.data)
+          this.getList(this.listQuery)
+        })
+    },
+
+    // 预览
+    handlePreview(row) {
+      const url = `https://view.officeapps.live.com/op/view.aspx?src=${encodeURIComponent(row.fileUrl)}`
+      openWindow(url, '', `${row.fileModuleType}-教程`, 800, 460)
+    },
+
+    // 关闭添加对话框
+    dialogClose() {
+      this.uploadFileList = []
+      this.$refs.fileUpload.clearAllFiles()
+      this.$refs.dialogForm.resetFields()
+
+      this.dialogFormData = this.resetDialogFormData()
+      this.dialogVisible = false
+    },
+    // 获取模块文本
+    formatFileModuleType(list) {
+      return list.filter(item => {
+        item.fileModuleType = getModuleType(item.fileModule)
+        return item.fileModuleType !== ''
+      })
+    },
+    // 表格索引
+    indexMethod(index) {
+      return index + this.listQuery.pageSize * (this.listQuery.pageNum - 1) + 1
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.filter-container {
+  span {
+    display: inline-block;
+    margin-bottom: 10px;
+    vertical-align: middle;
+    font-size: 14px;
+  }
+  .el-button {
+    display: inline-block;
+    margin-bottom: 10px;
+    vertical-align: middle;
+  }
+  .el-input,
+  .el-select {
+    margin-right: 10px;
+    margin-left: 10px;
+  }
+}
+.el-table .cell {
+  overflow: visible;
+}
+.el-badge {
+  margin: 0 6px;
+}
+
+.el-cascader{
+&.filter-item{
+margin: 0 15px 10px;
+}
+
+}
+
+</style>

+ 400 - 0
src/views/authentic/helper/video.vue

@@ -0,0 +1,400 @@
+<template>
+  <div class="app-container">
+    <!-- 搜索区域 -->
+    <div class="filter-container">
+      <span>标题:</span>
+      <el-input
+        v-model="listQuery.fileTitle"
+        placeholder="标题"
+        style="width: 200px"
+        class="filter-item"
+        @keyup.enter.native="getList"
+      />
+      <span>所属模块:</span>
+
+      <el-cascader
+        v-model="listQuery.fileModule"
+        :options="modules"
+        class="filter-item"
+        placeholder="所属模块"
+        style="margin-rigth: 15px"
+        clearable
+        @change="getList"
+      />
+      <el-button type="primary" icon="el-icon-search" @click="getList">查询</el-button>
+      <el-button
+        v-if="userIdentity === 1"
+        icon="el-icon-edit"
+        type="primary"
+        @click="dialogVisible = true"
+      >添加</el-button>
+    </div>
+    <!-- 搜索区域END -->
+    <!-- 表格区域 -->
+    <el-table
+      v-loading="listLoading"
+      :data="list"
+      style="width: 100%"
+      border
+      fit
+      highlight-current-row
+      cell-class-name="table-cell"
+    >
+      <el-table-column
+        v-loading="listLoading"
+        :data="list"
+        style="width: 100%"
+        border
+        fit
+        highlight-current-row
+        cell-class-name="table-cell"
+      >
+        <el-table-column label="序号" :index="indexMethod" type="index" width="80" align="center" />
+        <el-table-column label="标题" prop="fileTitle" align="center" />
+        <el-table-column label="所属模块" align="center" prop="fileModuleType" />
+        <el-table-column label="创建时间" width="240px" align="center">
+          <template slot-scope="{ row }">
+            {{ row.createTime | formatTime }}
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" align="center">
+          <template slot-scope="{ row }">
+            <el-button
+              v-if="userIdentity === 1"
+              type="primary"
+              size="mini"
+              style="margin-right:5px"
+              icon="el-icon-edit"
+              @click="handleEditFile(row)"
+            >编辑</el-button>
+
+            <el-button
+              type="success"
+              size="mini"
+              style="margin-right:5px"
+              icon="el-icon-film"
+              @click="handlePreview(row)"
+            >播放</el-button>
+
+            <el-button
+              v-if="userIdentity === 1"
+              type="danger"
+              size="mini"
+              style="margin-right:5px"
+              icon="el-icon-s-check"
+              @click="handleRemove(row)"
+            >删除</el-button>
+
+          </template>
+        </el-table-column>
+      </el-table-column></el-table>
+    <!-- 表格区域END -->
+    <pagination v-show="total>0" :total="total" :page.sync="listQuery.pageNum" :limit.sync="listQuery.pageSize" @pagination="getList(listQuery)" />
+
+    <!-- 视频编辑dialog -->
+    <el-dialog
+      title="添加视频"
+      :visible="dialogVisible"
+      width="30%"
+      @close="dialogClose"
+    >
+
+      <el-form ref="dialogForm" :model="dialogFormData" label-width="86px" :rules="rules">
+        <el-form-item label="标题:" prop="fileTitle">
+          <el-input v-model="dialogFormData.fileTitle" placeholder="请输入标题" />
+        </el-form-item>
+        <el-form-item label="视频路径:" prop="fileUrl">
+          <file-upload ref="fileUpload" :file-list="uploadFileList" accept-type="video/*" @change="fileUploadChange" />
+          <el-input v-show="false" v-model="dialogFormData.fileUrl" />
+        </el-form-item>
+        <el-form-item label="所属模块:" prop="fileModule">
+          <el-cascader
+            v-if="dialogVisible"
+            v-model="dialogFormData.fileModule"
+            :options="modules"
+            placeholder="所属模块"
+            clearable
+          />
+        </el-form-item>
+      </el-form>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="dialogVisible = false">取 消</el-button>
+        <el-button type="primary" :disabled="!saveBtnClickable" :loading="requestLoading" @click="submitUpload">确 定</el-button>
+      </span>
+    </el-dialog>
+    <!-- 视频编辑dialog END -->
+  </div>
+</template>
+
+<script>
+import FileUpload from '@/components/FileUpload'
+import Pagination from '@/components/Pagination' // secondary package based on el-pagination
+import openWindow from '@/utils/open-window'
+import { formatDate } from '@/utils'
+import { mapGetters } from 'vuex'
+import { fetchCourseList, saveCourse, removeCourse } from '@/api/helper'
+import { getToutesTree, getModuleType } from '@/utils/formatRoutesToModule'
+import { debounce } from '@/utils/tools'
+export default {
+  components: { Pagination, FileUpload },
+  filters: {
+    formatTime(time) {
+      if (!time) {
+        return ''
+      }
+      return formatDate(time, 'yyyy-MM-DD HH:mm:ss')
+    }
+  },
+
+  data() {
+    return {
+      listLoading: false,
+      dialogVisible: false,
+      requestLoading: false,
+      total: 0,
+      listQuery: {
+        fileType: 1, // 文件类型:1视频,2文档
+        fileTitle: '', // 文件标题
+        fileModule: [], // 文件模块:1品牌授权-授权列表,2机构管理-机构列表
+        pageNum: 1,
+        pageSize: 10
+      },
+      modules: [],
+      list: [],
+      uploadFileList: [],
+      dialogFormData: {},
+      rules: {
+        fileTitle: [{
+          required: true,
+          message: '请输入标题', trigger: ['change', 'blur']
+        }],
+        fileUrl: [
+          {
+            required: true,
+            message: '请选择文件', trigger: 'change'
+          }
+        ],
+        fileModule: [{
+          required: true,
+          message: '请选择所属模块', trigger: 'change'
+        }]
+      }
+    }
+  },
+  computed: {
+    ...mapGetters(['authUserId', 'userIdentity', 'proxyInfo', 'routes']),
+    saveBtnClickable() {
+      return this.uploadFileList.length > 0
+    }
+  },
+  created() {
+    this.dialogFormData = this.resetDialogFormData()
+    this.modules = getToutesTree(this.routes)
+    this.getList()
+    console.log(this.authUserId)
+  },
+  methods: {
+    // 初始化dialog formdata
+    resetDialogFormData() {
+      return {
+        fileTitle: '',
+        fileUrl: '',
+        fileId: '',
+        fileName: '',
+        fileType: 1,
+        fileModule: []
+      }
+    },
+
+    // 上传文件
+    submitUpload() {
+      if (this.userIdentity !== 1) return
+      this.$refs.dialogForm.validate(valid => {
+        console.log(valid)
+        if (!valid) return
+        this.requestLoading = true // 上传文件 保存 loading
+
+        const uploadFile = this.uploadFileList[0]
+        // 文件如果已上传 直接保存
+        if (uploadFile && uploadFile.status === 'success') {
+          this.handleSave()
+        } else {
+          // 上传文件
+          this.$refs.fileUpload.submit()
+        }
+        console.log(this.uploadFileList)
+      })
+    },
+    // 监听上传文件的状态变化
+    async fileUploadChange(fileList) {
+      this.uploadFileList = fileList
+      try {
+        await this.handleFileUploadStatus(fileList)
+        this.handleSave.apply(this)
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 保存 TODO
+    handleSave: debounce(function() {
+      if (this.userIdentity !== 1) return
+      const params = {
+        fileId: this.dialogFormData.fileId || '',
+        fileTitle: this.dialogFormData.fileTitle,
+        fileName: this.dialogFormData.fileName,
+        ossName: this.dialogFormData.fileUrl,
+        fileType: this.dialogFormData.fileType,
+        fileModule: this.dialogFormData.fileModule.join('-')
+      }
+      saveCourse(params).then(res => {
+        this.$message.success(res.data)
+        this.dialogVisible = false
+        this.getList()
+      }).catch(err => {
+        console.log(err)
+      }).finally(() => {
+        this.requestLoading = false
+      })
+    }, 200),
+
+    // 处理文件上传状态
+    handleFileUploadStatus(fileList) {
+      // 文件列表为空
+      if (fileList.length <= 0) {
+        this.dialogFormData.fileUrl = ''
+        return Promise.reject('faild')
+      }
+      // 取第一个文件
+      const { response, status } = fileList[0]
+      // 文件已选择但未上传
+      if (status === 'ready') {
+        this.dialogFormData.fileUrl = status
+        return Promise.reject('faild')
+      }
+      // 文件已上传
+      if (status === 'success') {
+        this.dialogFormData.fileUrl = response.downloadUrl
+        this.dialogFormData.fileName = response.fileName
+        return Promise.resolve('success')
+      }
+      console.log(response)
+    },
+
+    // 数据回显 修改
+    handleEditFile(row) {
+      if (this.userIdentity !== 1) return
+      const fileModule = row.fileModule.split('-')
+      const i = parseInt(fileModule[0])
+      const j = parseInt(fileModule[1])
+      // dialog 表单数据
+      this.dialogFormData.fileTitle = row.fileTitle
+      this.dialogFormData.fileUrl = row.ossName
+      this.dialogFormData.fileId = row.fileId
+      this.dialogFormData.fileName = row.fileName
+      this.dialogFormData.fileType = 1
+      this.dialogFormData.fileModule = [i, j]
+      // 文件回显列表
+      this.uploadFileList = [{ url: row.fileUrl, name: row.fileName }]
+      this.dialogVisible = true
+    },
+
+    // 获取列表数据
+    getList() {
+      this.listLoading = true
+      const params = {
+        ...this.listQuery,
+        authUserId: this.authUserId,
+        fileModule: this.listQuery.fileModule.join('-')
+      }
+      fetchCourseList(params)
+        .then(res => {
+          if (res.code !== 0) return
+          this.list = this.formatFileModuleType(res.data.list)
+          this.total = res.data.total
+        })
+        .finally(() => {
+          this.listLoading = false
+        })
+    },
+    // 删除
+    async handleRemove(row) {
+      if (this.userIdentity !== 1) return
+      const text = await this.$confirm('确认删除该帮助视频吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).catch(() => {
+        this.$message.info('已取消操作')
+      })
+      if (text !== 'confirm') return
+      removeCourse({ fileId: row.fileId })
+        .then(res => {
+          if (res.code !== 0) return
+          this.$message.success(res.data)
+          this.getList(this.listQuery)
+        })
+    },
+
+    // 预览
+    handlePreview(row) {
+      openWindow(row.fileUrl, '', `${row.fileModuleType}-教程`, 800, 460)
+    },
+
+    // 关闭添加对话框
+    dialogClose() {
+      this.uploadFileList = []
+      this.$refs.fileUpload.clearAllFiles()
+      this.$refs.dialogForm.resetFields()
+
+      this.dialogFormData = this.resetDialogFormData()
+      this.dialogVisible = false
+    },
+    // 获取模块文本
+    formatFileModuleType(list) {
+      return list.filter(item => {
+        item.fileModuleType = getModuleType(item.fileModule)
+        return item.fileModuleType !== ''
+      })
+    },
+    // 表格索引
+    indexMethod(index) {
+      return index + this.listQuery.pageSize * (this.listQuery.pageNum - 1) + 1
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.filter-container {
+  span {
+    display: inline-block;
+    margin-bottom: 10px;
+    vertical-align: middle;
+    font-size: 14px;
+  }
+  .el-button {
+    display: inline-block;
+    margin-bottom: 10px;
+    vertical-align: middle;
+  }
+  .el-input,
+  .el-select {
+    margin-right: 10px;
+    margin-left: 10px;
+  }
+}
+.el-table .cell {
+  overflow: visible;
+}
+.el-badge {
+  margin: 0 6px;
+}
+
+.el-cascader{
+&.filter-item{
+margin: 0 15px 10px;
+}
+
+}
+
+</style>

+ 1 - 1
src/views/authentic/supplier/add.vue

@@ -460,7 +460,7 @@ export default {
           this.supplierBrands.push(shopInfo)
         } else {
         // 修改的
-          this.supplierBrands.splice(this.currentIndex, shopInfo)
+          this.supplierBrands.splice(this.currentIndex, 1, shopInfo)
         }
         this.addExcludeBrand(shopInfo.brandId)
         shopInfo.isNew = false

+ 3 - 1
src/views/authentic/supplier/edit.vue

@@ -499,6 +499,7 @@ export default {
     },
     // 添加品牌
     handleAddBrand() {
+      console.log(this.formData2)
       this.dialogLoading = true
       // 如果声明类型为4,并且文件id为空或null,则需要先上传文件再保存
       if (this.formData2.statementType === 4 && (this.formData2.statementFileId === '' || this.formData2.statementFileId === null)) {
@@ -514,13 +515,14 @@ export default {
         if (!valid) {
           return
         }
+
         // 如果是新增的
         const shopInfo = this.clone(this.formData2)
         if (shopInfo.isNew) {
           this.supplierBrands.push(shopInfo)
         } else {
         // 修改的
-          this.supplierBrands.splice(this.currentIndex, shopInfo)
+          this.supplierBrands.splice(this.currentIndex, 1, shopInfo)
         }
         this.addExcludeBrand(shopInfo.brandId)
         shopInfo.isNew = false