喻文俊 %!s(int64=3) %!d(string=hai) anos
pai
achega
5f75b5a27a
Modificáronse 49 ficheiros con 9645 adicións e 216 borrados
  1. 178 0
      src/views/admin/supplier/audit/club/device/index.vue
  2. 140 0
      src/views/admin/supplier/audit/club/device/review.vue
  3. 180 0
      src/views/admin/supplier/audit/club/index.vue
  4. 280 0
      src/views/admin/supplier/audit/club/list.vue
  5. 158 0
      src/views/admin/supplier/audit/club/review.vue
  6. 180 0
      src/views/admin/supplier/audit/doctor/index.vue
  7. 195 0
      src/views/admin/supplier/audit/doctor/list.vue
  8. 199 0
      src/views/admin/supplier/audit/doctor/review.vue
  9. 190 0
      src/views/admin/supplier/audit/material/article/index.vue
  10. 108 0
      src/views/admin/supplier/audit/material/article/review.vue
  11. 279 0
      src/views/admin/supplier/audit/material/file/index.vue
  12. 0 0
      src/views/admin/supplier/audit/material/file/review.vue
  13. 179 0
      src/views/admin/supplier/audit/material/image/index.vue
  14. 107 0
      src/views/admin/supplier/audit/material/image/review.vue
  15. 199 0
      src/views/admin/supplier/audit/material/index.vue
  16. 0 0
      src/views/admin/supplier/audit/material/review.vue
  17. 270 0
      src/views/admin/supplier/audit/material/video/index.vue
  18. 0 0
      src/views/admin/supplier/audit/material/video/review.vue
  19. 299 0
      src/views/admin/supplier/club/detail.vue
  20. 273 0
      src/views/admin/supplier/club/device/detail.vue
  21. 216 0
      src/views/admin/supplier/club/device/index.vue
  22. 355 0
      src/views/admin/supplier/club/index.vue
  23. 729 0
      src/views/admin/supplier/edit.vue
  24. 254 0
      src/views/admin/supplier/index.vue
  25. 0 0
      src/views/common/helper/file/index.vue
  26. 0 0
      src/views/common/helper/video/index.vue
  27. 102 0
      src/views/common/password/index.vue
  28. 0 13
      src/views/error-log/components/ErrorTestA.vue
  29. 0 11
      src/views/error-log/components/ErrorTestB.vue
  30. 0 32
      src/views/error-log/index.vue
  31. 0 0
      src/views/icons/element-icons.js
  32. 0 101
      src/views/icons/index.vue
  33. 0 10
      src/views/icons/svg-icons.js
  34. 350 0
      src/views/normal/club/device/edit.vue
  35. 298 0
      src/views/normal/club/device/index.vue
  36. 580 0
      src/views/normal/club/edit.vue
  37. 580 0
      src/views/normal/club/index.vue
  38. 219 0
      src/views/normal/club/user/index.vue
  39. 206 0
      src/views/normal/doctor/edit.vue
  40. 224 0
      src/views/normal/doctor/index.vue
  41. 90 0
      src/views/normal/feedback/detail.vue
  42. 217 0
      src/views/normal/feedback/index.vue
  43. 142 0
      src/views/normal/material/article/edit.vue
  44. 279 0
      src/views/normal/material/article/index.vue
  45. 488 0
      src/views/normal/material/file/index.vue
  46. 172 0
      src/views/normal/material/image/edit.vue
  47. 250 0
      src/views/normal/material/image/index.vue
  48. 480 0
      src/views/normal/material/video/index.vue
  49. 0 49
      src/views/normal/password.vue

+ 178 - 0
src/views/admin/supplier/audit/club/device/index.vue

@@ -0,0 +1,178 @@
+<template>
+  <div class="app-container">
+    <!-- 搜索区域 -->
+    <div class="filter-container">
+      <span>设备名称:</span>
+      <el-input
+        v-model="listQuery.productName"
+        placeholder="请输入设备名称"
+        style="width: 200px"
+        class="filter-item"
+        @keyup.enter.native="getList"
+      />
+      <span>设备SN码:</span>
+      <el-input
+        v-model="listQuery.snCode"
+        placeholder="请输入设备SN码"
+        style="width: 200px"
+        class="filter-item"
+        @keyup.enter.native="getList"
+      />
+      <span>审核状态:</span>
+      <el-select
+        v-model="listQuery.reviewStatus"
+        placeholder="供应商类型"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="所有类型" value="" />
+        <el-option label="待审核" :value="1" />
+        <el-option label="审核通过" :value="2" />
+        <el-option label="审核未通过" :value="0" />
+      </el-select>
+      <el-button type="primary" icon="el-icon-search" @click="getList">查询</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 :index="indexMethod" label="序号" type="index" width="80" align="center" />
+      <el-table-column prop="productName" label="设备名称" align="center" />
+      <el-table-column prop="snCode" label="设备SN码" align="center" />
+      <el-table-column label="审核状态" width="220px" align="center">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.auditStatus === 2" size="small" type="warning">待审核</el-tag>
+          <el-tag v-if="row.auditStatus === 1" size="small" type="success">审核通过</el-tag>
+          <!-- 未通过原因展示 -->
+          <template v-if="row.auditStatus === 0">
+            <!-- <span class="status danger">审核未通过&nbsp;</span> -->
+            <el-popover
+              placement="top-start"
+              title="审核说明"
+              width="400"
+              trigger="hover"
+              :content="row.invalidReason"
+            >
+              <el-tag slot="reference" size="small" type="danger" class="reason">
+                <span>审核未通过</span>
+                <span class="el-icon-question status danger " />
+              </el-tag>
+            </el-popover>
+            <!-- 未通过原因展示END -->
+          </template>
+        </template>
+      </el-table-column>
+      <el-table-column label="审核时间" width="250px" align="center">
+        <template slot-scope="{row}">
+          <span v-if="row.auditStatus!==2">{{ row.auditTime | formatTime }}</span>
+          <span v-else>—</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="审核人" align="center">
+        <template slot-scope="{row}">
+          <span v-if="row.auditStatus!==2">{{ row.auditBy }}</span>
+          <span v-else>—</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" width="240px" align="center">
+        <template slot-scope="{row}">
+          <el-button v-if="row.auditStatus !== 1" type="primary" icon="el-icon-s-check" size="mini" @click="$_navigationTo(`auth-shop-detail?id=${row.productId}&authId=${listQuery.authId}`)">审核</el-button>
+          <span v-else class="status success el-icon-check">&nbsp;已审核</span>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 表格区域END -->
+    <!-- 页码 -->
+    <pagination v-show="total>0" :total="total" :page.sync="listQuery.pageNum" :limit.sync="listQuery.pageSize" @pagination="getList" />
+  </div>
+</template>
+
+<script>
+import Pagination from '@/components/Pagination'
+import { getProdList } from '@/api/product'
+import { formatDate } from '@/utils'
+export default {
+  components: { Pagination },
+  filters: {
+    formatTime(time) {
+      if (!time) {
+        return ''
+      }
+      return formatDate(time, 'yyyy-MM-DD HH:mm:ss')
+    }
+  },
+
+  data() {
+    return {
+      listLoading: false,
+      listQuery: {
+        listType: 2,
+        authId: '',
+        productName: '',
+        reviewStatus: '',
+        snCode: '',
+        pageNum: 1,
+        pageSize: 10
+      },
+      total: 0,
+      list: []
+    }
+  },
+  created() {
+    this.listQuery.authId = this.$route.query.authId
+    this.getList()
+  },
+  methods: {
+    // 过滤列表
+    handleFilter() {},
+    // 获取列表信息
+    getList() {
+      this.listLoading = true
+      getProdList(this.listQuery).then(res => {
+        if (res.code !== 0) return
+        this.total = res.data.total
+        this.list = res.data.list
+      }).finally(() => {
+        this.listLoading = false
+      })
+    },
+    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;
+}
+
+</style>

+ 140 - 0
src/views/admin/supplier/audit/club/device/review.vue

@@ -0,0 +1,140 @@
+<template>
+  <div v-loading="isLoading" class="shop-detail">
+    <el-form v-if="product!==null" ref="formRef" :model="formData" :rules="formRules" label-width="120px">
+      <el-form-item label="设备名称:">
+        <span>{{ product.productName }}</span>
+      </el-form-item>
+      <el-form-item label="设备SN码:">
+        <span>{{ product.snCode }}</span>
+      </el-form-item>
+      <el-form-item label="设备图片:">
+        <el-image
+          style="width: 140px; height: 140px"
+          :src="product.productImage"
+          :preview-src-list="imgList"
+        />
+      </el-form-item>
+      <el-form-item label="授权牌:">
+        <el-image
+          style="width: 140px; height: 140px"
+          :src="product.certificateImage"
+          :preview-src-list="imgList"
+        />
+      </el-form-item>
+      <template v-if="product.paramList.length>0">
+        <el-form-item label="相关参数:">
+          <table>
+            <tr v-for="(params,index) in product.paramList" :key="index">
+              <td>{{ params.paramName }}:</td>
+              <td>{{ params.paramContent }}</td>
+            </tr>
+          </table>
+        </el-form-item>
+      </template>
+
+      <el-form-item label="审核状态:">
+        <el-radio-group v-model="formData.auditStatus">
+          <el-radio :label="1">通过</el-radio>
+          <el-radio :label="0">不通过</el-radio>
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item v-if="formData.auditStatus!==1" prop="invalidReason" label="原因:">
+        <el-input v-model="formData.invalidReason" type="textarea" placeholder="请说明原因" />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="info" @click="$_back">返回</el-button>
+        <el-button type="primary" @click="submit">提交</el-button>
+      </el-form-item>
+    </el-form>
+  </div>
+</template>
+
+<script>
+import { getProductById, auditProduct } from '@/api/product'
+import { mapGetters, mapMutations } from 'vuex'
+export default {
+  data() {
+    return {
+      authId: '', // 当前产品所属授权机构id
+      isLoading: false,
+      formData: {
+        auditBy: '', // 审核人id
+        productId: '', // 商品id
+        auditStatus: 1, // 商品审核状态
+        invalidReason: '' // 审核信息
+      },
+      formRules: {
+        invalidReason: { required: true, message: '不通过原因不能为空', tigger: 'blur' }
+      },
+      imgList: [], // 图片列表
+      product: null // 商品信息
+    }
+  },
+  computed: {
+    ...mapGetters(['authUserId'])
+  },
+  created() {
+    this.formData.productId = this.$route.query.id
+    this.authId = this.$route.query.authId
+    this.getDetail()
+  },
+  methods: {
+    ...mapMutations({ setMessageState: 'webSocket/SET_MESSAGE_STATE' }),
+    // 获取商品详情
+    getDetail() {
+      this.isLoading = true
+      getProductById({ productId: this.formData.productId })
+        .then(res => {
+          if (res.code !== 0) return
+          this.product = res.data
+          this.imgList = [this.product.productImage, this.product.certificateImage]
+        }).finally(() => {
+          this.isLoading = false
+        })
+    },
+    // 提交审核信息
+    submit() {
+      this.$refs.formRef.validate(valid => {
+        if (valid) {
+          this.isLoading = true
+          // 指定审核人
+          this.formData.auditBy = this.authUserId
+          // 提交审核信息
+          auditProduct(this.formData).then(res => {
+            if (res.code !== 0) return
+            this.$message.success(res.data)
+            this.$store.dispatch('tagsView/delView', this.$route)
+            this.$router.back()
+            // this.setMessageState({ id: parseInt(this.formData.productId), type: 2 })
+          }).finally(() => {
+            this.isLoading = false
+          })
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.shop-detail{
+  margin-bottom: 80px;
+  font-size: 14px;
+  color: #444;
+  .params-list{
+    margin: 0;
+    padding: 0;
+    list-style: none;
+    li{
+      margin-bottom: 15px;
+    }
+  }
+  .el-form {
+    width: 800px;
+    margin: 25px auto 0;
+    .el-button{
+      width: 120px;
+    }
+  }
+}
+</style>

+ 180 - 0
src/views/admin/supplier/audit/club/index.vue

@@ -0,0 +1,180 @@
+<template>
+  <div class="app-container">
+    <!-- 搜索区域 -->
+    <div class="filter-container">
+      <span>供应商名称:</span>
+      <el-input
+        v-model="listQuery.shopName"
+        placeholder="供应商名称"
+        style="width: 200px"
+        class="filter-item"
+        @keyup.enter.native="getList"
+      />
+      <span>供应商类型:</span>
+      <el-select
+        v-model="listQuery.shopType"
+        placeholder="供应商类型"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="所有类型" value="" />
+        <el-option label="代理商" :value="2" />
+        <el-option label="品牌方" :value="1" />
+      </el-select>
+      <span>手机号:</span>
+      <el-input
+        v-model="listQuery.mobile"
+        placeholder="手机号"
+        style="width: 200px"
+        class="filter-item"
+        @keyup.enter.native="getList"
+      />
+      <span>审核状态:</span>
+      <el-select
+        v-model="listQuery.lowerAuditStatus"
+        placeholder="审核状态"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="全部" value="" />
+        <el-option label="已完成审核" :value="1" />
+        <el-option label="未完成审核" :value="0" />
+      </el-select>
+      <span>联系人:</span>
+      <el-input
+        v-model="listQuery.linkMan"
+        placeholder="联系人"
+        style="width: 200px"
+        class="filter-item"
+        @keyup.enter.native="getList"
+      />
+      <el-button type="primary" icon="el-icon-search" @click="getList">查询</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 :index="indexMethod" label="序号" type="index" width="80" align="center" />
+      <el-table-column prop="name" label="供应商名称" align="center" />
+      <el-table-column label="供应商类型" width="150px" align="center">
+        <template slot-scope="{ row }">
+          <span v-if="row.shopType === 1">品牌方</span>
+          <span v-if="row.shopType === 2">代理商</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="mobile" label="手机号" width="200px" align="center" />
+      <el-table-column prop="linkMan" label="联系人" width="200px" align="center" />
+      <el-table-column label="审核状态" width="220px" align="center">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.lowerAuditStatus === 0" size="small" type="danger">未完成审核</el-tag>
+          <el-tag v-if="row.lowerAuditStatus === 1" size="small" type="success">已完成审核</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" width="240px" align="center">
+        <template slot-scope="{ row }">
+          <el-badge :hidden="row.lowerAuditStatus === 1" :value="row.waitAuditNum" :max="99">
+            <el-button
+              type="primary"
+              icon="el-icon-s-check"
+              size="mini"
+              @click="$_navigationTo(`auth-list?authUserId=${row.authUserId}`)"
+            >机构认证审核</el-button>
+          </el-badge>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 表格区域END -->
+    <!-- 页码 -->
+    <pagination
+      v-show="total > 0"
+      :total="total"
+      :page.sync="listQuery.pageNum"
+      :limit.sync="listQuery.pageSize"
+      @pagination="getList(listQuery)"
+    />
+  </div>
+</template>
+
+<script>
+import { fetchSupplierList } from '@/api/supplier'
+import Pagination from '@/components/Pagination'
+export default {
+  components: { Pagination },
+  data() {
+    return {
+      listQuery: {
+        listType: 2,
+        brandId: '', // 品牌id
+        linkMan: '', // 联系人
+        mobile: '', // 手机号
+        pageNum: 0, // 页码
+        pageSize: 10, // 分页大小
+        shopName: '', // 供应商名称
+        shopType: '', // 供应商类型
+        lowerAuditStatus: ''
+      },
+      listLoading: false,
+      list: [],
+      total: 0
+    }
+  },
+  created() {
+    this.getList()
+  },
+  methods: {
+    // 过滤列表
+    handleFilter() {},
+    // 获取供应商列表
+    getList() {
+      this.listLoading = true
+      fetchSupplierList(this.listQuery)
+        .then(res => {
+          if (res.code !== 0) return
+          this.list = res.data.list
+          this.total = res.data.total
+        })
+        .finally(() => {
+          this.listLoading = false
+        })
+    },
+    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;
+}
+</style>

+ 280 - 0
src/views/admin/supplier/audit/club/list.vue

@@ -0,0 +1,280 @@
+<template>
+  <div class="app-container">
+    <!-- 搜索区域 -->
+    <div class="filter-container">
+      <span>机构名称:</span>
+      <el-input
+        v-model="listQuery.authParty"
+        placeholder="机构名称"
+        style="width: 200px"
+        class="filter-item"
+        @keyup.enter.native="getList"
+      />
+      <span>审核状态:</span>
+      <el-select
+        v-model="listQuery.auditStatus"
+        placeholder="审核状态"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="全部" value="" />
+        <el-option label="待审核" :value="2" />
+        <el-option label="审核通过" :value="1" />
+        <el-option label="审核未通过" :value="0" />
+      </el-select>
+      <span>设备认证审核状态:</span>
+      <el-select
+        v-model="listQuery.lowerAuditStatus"
+        placeholder="供应商类型"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="全部" value="" />
+        <el-option label="已完成审核" :value="1" />
+        <el-option label="未完成审核" :value="0" />
+      </el-select>
+      <el-button type="primary" icon="el-icon-search" @click="getList">查询</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 label="序号" :index="indexMethod" type="index" width="80" align="center" />
+      <el-table-column prop="authParty" label="机构名称" align="center" />
+      <el-table-column label="审核状态" width="220px" align="center">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.auditStatus === 2" size="small" type="warning">待审核</el-tag>
+          <el-tag v-if="row.auditStatus === 1" size="small" type="success">审核通过</el-tag>
+          <!-- 未通过原因展示 -->
+          <template v-if="row.auditStatus === 0">
+            <!-- <span class="status danger">审核未通过&nbsp;</span> -->
+            <el-popover
+              placement="top-start"
+              title="审核说明"
+              width="400"
+              trigger="hover"
+              :content="row.invalidReason"
+            >
+              <el-tag slot="reference" size="small" type="danger" class="reason">
+                <span>审核未通过</span>
+                <span class="el-icon-question status danger " />
+              </el-tag>
+            </el-popover>
+            <!-- 未通过原因展示END -->
+          </template>
+        </template>
+      </el-table-column>
+      <el-table-column label="商品信息审核状态" width="220px" align="center">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.lowerAuditStatus === 0" size="small" type="danger">未完成审核</el-tag>
+          <el-tag v-if="row.lowerAuditStatus === 1" size="small" type="success">已完成审核</el-tag>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="审核时间" width="250px" align="center">
+        <template slot-scope="{row}">
+          <span v-if="row.auditStatus!==2">{{ row.auditTime | formatTime }}</span>
+          <span v-else>—</span>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="审核人" align="center" width="200px">
+        <template slot-scope="{row}">
+          <span v-if="row.auditStatus!==2">{{ row.auditBy }}</span>
+          <span v-else>—</span>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="操作" width="240px" align="center">
+        <template slot-scope="{ row }">
+          <el-button
+            v-if="row.auditStatus !== 1"
+            type="warning"
+            size="mini"
+            style="margin-right:5px"
+            icon="el-icon-s-check"
+            @click="$_navigationTo(`auth-detail?authId=${row.authId}`)"
+          >审核</el-button>
+          <el-badge :hidden="row.lowerAuditStatus === 1" :value="row.waitAuditNum" :max="99">
+            <el-button icon="el-icon-s-shop" type="primary" size="mini" @click="$_navigationTo(`auth-shop-list?authId=${row.authId}`)">设备认证审核</el-button>
+          </el-badge>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 表格区域END -->
+    <!-- 页码 -->
+    <pagination v-show="total>0" :total="total" :page.sync="listQuery.pageNum" :limit.sync="listQuery.pageSize" @pagination="getList" />
+    <!-- 审核弹窗 -->
+    <el-dialog title="授权机构审核" :visible.sync="dialogVisible" width="450px" @close="dialogClosed">
+      <div class="auth-info">
+        <div class="auth-name">
+          <i>授权机构:</i>
+          <b>{{ dialogData.authParty }}</b>
+        </div>
+        <el-form ref="formRef" :model="dialogData" label-width="85px" :rules="dialogFormRules">
+          <el-form-item label="审核状态:">
+            <el-radio-group v-model="dialogData.auditStatus">
+              <el-radio :label="1">通过</el-radio>
+              <el-radio :label="0">不通过</el-radio>
+            </el-radio-group>
+          </el-form-item>
+          <el-form-item v-if="dialogData.auditStatus === 0" label="原因:" prop="invalidReason">
+            <el-input v-model="dialogData.invalidReason" type="textarea" placeholder="请说明原因" />
+          </el-form-item>
+        </el-form>
+      </div>
+      <div slot="footer">
+        <el-button @click="dialogVisible = false">取 消</el-button>
+        <el-button type="primary" @click="auditStatusHandle">确 定</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import Pagination from '@/components/Pagination'
+import { fecthAuthList, auditAuth } from '@/api/auth'
+import { formatDate } from '@/utils'
+import { mapGetters, mapMutations } from 'vuex'
+export default {
+  components: { Pagination },
+  filters: {
+    formatTime(time) {
+      if (!time) {
+        return ''
+      }
+      return formatDate(time, 'yyyy-MM-DD HH:mm:ss')
+    }
+  },
+  data() {
+    return {
+      // 是否显示dialog
+      dialogVisible: false,
+      listLoading: false,
+      // 查询参数
+      listQuery: {
+        listType: 2,
+        authParty: '', // 授权机构
+        authUserId: '', // 供应商用户id
+        pageNum: 1, // 页码
+        pageSize: 10, // 分页
+        auditStatus: '', // 审核状态
+        lowerAuditStatus: '' // 下属内容审核状态
+      },
+      total: 0,
+      dialogData: {
+        auditBy: '', // 审核人
+        authId: '', // 授权机构id
+        authParty: '', // 授权机构名称
+        auditStatus: 1, // 审核状态
+        invalidReason: '' // 审核信息
+      },
+      dialogFormRules: {
+        invalidReason: {
+          required: true,
+          message: '不通过原因不能为空',
+          tigger: 'blur'
+        }
+      },
+      // 机构信息审核列表
+      list: []
+    }
+  },
+  computed: {
+    ...mapGetters(['authUserId'])
+  },
+  created() {
+    this.listQuery.authUserId = this.$route.query.authUserId
+    this.getList()
+  },
+  methods: {
+    ...mapMutations({ setMessageState: 'webSocket/SET_MESSAGE_STATE' }),
+    // 获取授权列表
+    getList() {
+      this.listLoading = true
+      fecthAuthList(this.listQuery).then(response => {
+        if (response.code !== 0) return
+        const { list, total } = response.data
+        this.list = list
+        this.total = total
+      }).finally(() => {
+        this.listLoading = false
+      })
+    },
+    // 审核
+    auditStatusHandle() {
+      this.$refs.formRef.validate(valid => {
+        if (valid) {
+          // 指定审核人
+          this.dialogData.auditBy = this.authUserId
+          // 提交审核信息
+          auditAuth(this.dialogData).then(res => {
+            if (res.code !== 0) return
+            this.$message.success(res.data)
+            this.setMessageState({ id: this.dialogData.authId, type: 1 })
+          }).finally(() => {
+            this.dialogVisible = false
+            this.getList()
+          })
+        }
+      })
+    },
+    // 审核对话框
+    handleShowDialog(item) {
+      console.log(item)
+      this.dialogData.authParty = item.authParty
+      this.dialogData.authId = item.authId
+      this.dialogVisible = true
+    },
+    // 审核对话框关闭
+    dialogClosed() {
+      this.dialogData.authParty = ''
+      this.dialogData.reviewStatus = 1
+    },
+    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;
+  }
+}
+
+.auth-info {
+  .auth-name {
+    font-size: 16px;
+    padding-bottom: 25px;
+    border-bottom: 1px solid #ddd;
+    margin-bottom: 25px;
+  }
+}
+</style>

+ 158 - 0
src/views/admin/supplier/audit/club/review.vue

@@ -0,0 +1,158 @@
+<template>
+  <div v-if="!isLoading" class="club-edit">
+    <el-form ref="formRef" class="club-edit-form" label-width="120px" :model="formData" :rules="formRules">
+      <el-form-item label="机构名称:">
+        <span>{{ authInfo.authParty }}</span>
+      </el-form-item>
+      <el-form-item label="所在地区:">
+        <span>{{ authInfo.area }}</span>
+      </el-form-item>
+      <el-form-item label="详细地址:">
+        <span>{{ authInfo.address }}</span>
+      </el-form-item>
+      <el-form-item label="经纬度:">
+        <span>{{ authInfo.lngAndLat }}</span>
+      </el-form-item>
+      <el-form-item label="联系方式:" prop="mobile">
+        <span>{{ authInfo.mobile }}</span>
+      </el-form-item>
+      <el-form-item label="机构logo:">
+        <el-image
+          style="width: 140px; height: 140px"
+          :src="authInfo.logo"
+        />
+      </el-form-item>
+      <el-form-item label="轮播图:">
+        <el-image
+          v-for="(image,index) in authInfo.bannerList"
+          :key="index"
+          style="width: 140px; height: 140px;margin-right: 16px;"
+          :src="image"
+          :preview-src-list="imgList"
+        />
+      </el-form-item>
+
+      <!-- 审核表单 -->
+      <el-form-item label="审核状态:">
+        <el-radio-group v-model="formData.auditStatus">
+          <el-radio :label="1">通过</el-radio>
+          <el-radio :label="0">不通过</el-radio>
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item v-if="formData.auditStatus!==1" prop="invalidReason" label="原因:">
+        <el-input v-model="formData.invalidReason" type="textarea" placeholder="请说明原因" />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="info" @click="$_back">返回</el-button>
+        <el-button type="primary" @click="submit">提交</el-button>
+      </el-form-item>
+    </el-form>
+  </div>
+</template>
+
+<script>
+// import Location from '@/components/location'
+import { getAuthFormData, auditAuth } from '@/api/auth'
+import { mapGetters } from 'vuex'
+
+export default {
+
+  data() {
+    return {
+      isLoading: false,
+
+      authId: '',
+
+      formData: {
+        auditBy: '', // 审核人id
+        authId: '', // 机构id
+        auditStatus: 1, // 审核状态
+        invalidReason: '' // 审核信息
+      },
+
+      formRules: {
+        invalidReason: { required: true, message: '不通过原因不能为空', tigger: 'blur' }
+      },
+
+      authInfo: {
+        address: '',
+        area: '',
+        authId: '',
+        authParty: '',
+        bannerList: '',
+        cityId: '',
+        lngAndLat: '',
+        logo: '',
+        mobile: '',
+        provinceId: '',
+        townId: ''
+      },
+
+      // 预览图片
+      imgList: []
+    }
+  },
+  computed: {
+    ...mapGetters(['authUserId'])
+  },
+  created() {
+    this.authId = this.formData.authId = this.$route.query.authId
+    this.getDetail()
+  },
+  methods: {
+    // 数据回显
+    getDetail() {
+      getAuthFormData({ authId: this.authId }).then(res => {
+        this.authInfo.address = res.data.address
+        this.authInfo.area = res.data.area
+        this.authInfo.authId = res.data.authId
+        this.authInfo.authParty = res.data.authParty
+        this.authInfo.bannerList = this.imgList = res.data.bannerList
+        this.authInfo.cityId = res.data.cityId
+        this.authInfo.lngAndLat = res.data.lngAndLat
+        this.authInfo.logo = res.data.logo
+        this.authInfo.mobile = res.data.mobile
+        this.authInfo.provinceId = res.data.provinceId
+        this.authInfo.townId = res.data.townId
+      })
+    },
+    // 提交审核信息
+    submit() {
+      this.$refs.formRef.validate(valid => {
+        if (valid) {
+          this.isLoading = true
+          // 指定审核人
+          this.formData.auditBy = this.authUserId
+          // 提交审核信息
+          auditAuth(this.formData).then(res => {
+            if (res.code !== 0) return
+            this.$message.success(res.data)
+            this.$store.dispatch('tagsView/delView', this.$route)
+            this.$router.back()
+          }).finally(() => {
+            this.isLoading = false
+          })
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.club-edit {
+  margin-bottom: 80px;
+}
+
+.club-edit-form {
+  width: 600px;
+  margin: 0 auto;
+  margin-top: 80px;
+}
+.submit-btn {
+  text-align: center;
+  .el-button {
+    width: 140px;
+  }
+}
+</style>

+ 180 - 0
src/views/admin/supplier/audit/doctor/index.vue

@@ -0,0 +1,180 @@
+<template>
+  <div class="app-container">
+    <!-- 搜索区域 -->
+    <div class="filter-container">
+      <span>供应商名称:</span>
+      <el-input
+        v-model="listQuery.shopName"
+        placeholder="供应商名称"
+        style="width: 200px"
+        class="filter-item"
+        @keyup.enter.native="getList"
+      />
+      <span>供应商类型:</span>
+      <el-select
+        v-model="listQuery.shopType"
+        placeholder="供应商类型"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="所有类型" value="" />
+        <el-option label="代理商" :value="2" />
+        <el-option label="品牌方" :value="1" />
+      </el-select>
+      <span>手机号:</span>
+      <el-input
+        v-model="listQuery.mobile"
+        placeholder="手机号"
+        style="width: 200px"
+        class="filter-item"
+        @keyup.enter.native="getList"
+      />
+      <span>审核状态:</span>
+      <el-select
+        v-model="listQuery.lowerAuditStatus"
+        placeholder="审核状态"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="全部" value="" />
+        <el-option label="已完成审核" :value="1" />
+        <el-option label="未完成审核" :value="0" />
+      </el-select>
+      <span>联系人:</span>
+      <el-input
+        v-model="listQuery.linkMan"
+        placeholder="联系人"
+        style="width: 200px"
+        class="filter-item"
+        @keyup.enter.native="getList"
+      />
+      <el-button type="primary" icon="el-icon-search" @click="getList">查询</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 :index="indexMethod" label="序号" type="index" width="80" align="center" />
+      <el-table-column prop="name" label="供应商名称" align="center" />
+      <el-table-column label="供应商类型" width="150px" align="center">
+        <template slot-scope="{ row }">
+          <span v-if="row.shopType === 1">品牌方</span>
+          <span v-if="row.shopType === 2">代理商</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="mobile" label="手机号" width="200px" align="center" />
+      <el-table-column prop="linkMan" label="联系人" width="200px" align="center" />
+      <el-table-column label="审核状态" width="220px" align="center">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.lowerAuditStatus === 0" size="small" type="danger">未完成审核</el-tag>
+          <el-tag v-if="row.lowerAuditStatus === 1" size="small" type="success">已完成审核</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" width="240px" align="center">
+        <template slot-scope="{ row }">
+          <el-badge :hidden="row.lowerAuditStatus === 1" :value="row.doctorWaitNum" :max="99">
+            <el-button
+              type="primary"
+              icon="el-icon-s-check"
+              size="mini"
+              @click="$_navigationTo(`doctor-list?authUserId=${row.authUserId}`)"
+            >医师认证审核</el-button>
+          </el-badge>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 表格区域END -->
+    <!-- 页码 -->
+    <pagination
+      v-show="total > 0"
+      :total="total"
+      :page.sync="listQuery.pageNum"
+      :limit.sync="listQuery.pageSize"
+      @pagination="getList(listQuery)"
+    />
+  </div>
+</template>
+
+<script>
+import { fetchSupplierList } from '@/api/supplier'
+import Pagination from '@/components/Pagination'
+export default {
+  components: { Pagination },
+  data() {
+    return {
+      listQuery: {
+        listType: 4,
+        brandId: '', // 品牌id
+        linkMan: '', // 联系人
+        mobile: '', // 手机号
+        pageNum: 0, // 页码
+        pageSize: 10, // 分页大小
+        shopName: '', // 供应商名称
+        shopType: '', // 供应商类型
+        lowerAuditStatus: ''
+      },
+      listLoading: false,
+      list: [],
+      total: 0
+    }
+  },
+  created() {
+    this.getList()
+  },
+  methods: {
+    // 过滤列表
+    handleFilter() {},
+    // 获取供应商列表
+    getList() {
+      this.listLoading = true
+      fetchSupplierList(this.listQuery)
+        .then(res => {
+          if (res.code !== 0) return
+          this.list = res.data.list
+          this.total = res.data.total
+        })
+        .finally(() => {
+          this.listLoading = false
+        })
+    },
+    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;
+}
+</style>

+ 195 - 0
src/views/admin/supplier/audit/doctor/list.vue

@@ -0,0 +1,195 @@
+<template>
+  <div class="app-container">
+    <div class="filter-container">
+      <span>医师姓名:</span>
+      <el-input v-model="listQuery.doctorName" placeholder="医师姓名" style="width: 200px;" class="filter-item" @keyup.enter.native="handleFilter" />
+      <span>从业资格证编号:</span>
+      <el-input v-model="listQuery.certificateNo" placeholder="从业资格证编号" style="width: 200px;" class="filter-item" @keyup.enter.native="handleFilter" />
+      <span>审核状态:</span>
+      <el-select
+        v-model="listQuery.auditStatus"
+        placeholder="审核状态"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="全部" value="" />
+        <el-option label="待审核" :value="2" />
+        <el-option label="审核通过" :value="1" />
+        <el-option label="审核未通过" :value="0" />
+      </el-select>
+      <el-button type="primary" icon="el-icon-search" @click="getList">查询</el-button>
+    </div>
+    <!-- 表格区域 -->
+    <el-table
+      :key="tableKey"
+      v-loading="listLoading"
+      :data="list"
+      border
+      fit
+      highlight-current-row
+      style="width: 100%;"
+      header-row-class-name="tableHeader"
+    >
+      <el-table-column label="序号" :index="indexMethod" type="index" align="center" width="80" />
+      <el-table-column label="医生姓名" align="center" prop="doctorName" />
+      <el-table-column label="从业资格证编号" align="center" prop="certificateNo" />
+
+      <el-table-column label="审核状态" width="220px" align="center">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.auditStatus === 2" size="small" type="warning">待审核</el-tag>
+          <el-tag v-if="row.auditStatus === 1" size="small" type="success">审核通过</el-tag>
+          <!-- 未通过原因展示 -->
+          <template v-if="row.auditStatus === 0">
+            <!-- <span class="status danger">审核未通过&nbsp;</span> -->
+            <el-popover
+              placement="top-start"
+              title="审核说明"
+              width="400"
+              trigger="hover"
+              :content="row.invalidReason"
+            >
+              <el-tag slot="reference" size="small" type="danger" class="reason">
+                <span>审核未通过</span>
+                <span class="el-icon-question status danger " />
+              </el-tag>
+            </el-popover>
+            <!-- 未通过原因展示END -->
+          </template>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="审核时间" width="250px" align="center">
+        <template slot-scope="{row}">
+          <span v-if="row.auditStatus!==2">{{ row.auditTime | formatTime }}</span>
+          <span v-else>—</span>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="审核人" align="center">
+        <template slot-scope="{row}">
+          <span v-if="row.auditStatus!==2">{{ row.auditBy }}</span>
+          <span v-else>—</span>
+        </template>
+      </el-table-column>
+
+      <!-- <el-table-column v-if="false" label="创建人" width="180px" align="center" prop="createBy" /> -->
+      <el-table-column label="操作" align="center" width="240px" class-name="small-padding fixed-width">
+        <template slot-scope="{ row }">
+          <el-button v-if="row.auditStatus !== 1" type="primary" size="mini" @click="$_navigationTo(`doctor-detail?id=${row.doctorId}`)">
+            审核
+          </el-button>
+          <span v-else class="status success el-icon-check">&nbsp;已审核</span>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 页码 -->
+    <pagination v-show="total>0" :total="total" :page.sync="listQuery.pageNum" :limit.sync="listQuery.pageSize" @pagination="getList" />
+  </div>
+</template>
+
+<script>
+import Pagination from '@/components/Pagination' // secondary package based on el-pagination
+import { mapGetters } from 'vuex'
+import { formatDate } from '@/utils'
+import { fetchDoctorList, removeDoctor, doctorStatusChange } from '@/api/doctor'
+
+export default {
+  components: { Pagination },
+  filters: {
+    formatTime(time) {
+      if (!time) {
+        return ''
+      }
+      return formatDate(time, 'yyyy-MM-DD HH:mm:ss')
+    }
+  },
+  data() {
+    return {
+      listLoading: false,
+      tableKey: 0,
+      total: 0,
+      listQuery: {
+        authUserId: '',
+        listType: 2,
+        doctorName: '',
+        auditStatus: '',
+        certificateNo: '',
+        status: '',
+        pageNum: 1,
+        pageSize: 10
+      },
+      list: []
+    }
+  },
+  computed: {
+    ...mapGetters(['authUserId', 'proxyInfo'])
+  },
+  created() {
+    this.getList()
+  },
+  methods: {
+    // 获取列表
+    getList() {
+      this.listQuery.authUserId = this.$route.query.authUserId
+
+      console.log(this.listQuery.authUserId)
+      fetchDoctorList(this.listQuery).then(res => {
+        console.log(res)
+        this.list = res.data.list
+        this.total = res.data.total
+      })
+    },
+    // 修改状态
+    handleChangeStatus(row) {
+      const status = row.status === 1 ? 0 : 1
+
+      doctorStatusChange({ doctorId: row.doctorId, status }).then(res => {
+        this.$message.success('状态修改成功')
+        this.getList()
+      })
+    },
+    // 删除
+    async handleRemoveDoctor(row) {
+      const text = await this.$confirm('确认删除该医师信息吗?删除后不可恢复', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).catch(() => {
+        this.$message.info('已取消操作')
+      })
+      if (text !== 'confirm') return
+
+      removeDoctor({ doctorId: row.doctorId }).then(res => {
+        this.$message.success('删除成功')
+        this.getList()
+      })
+    },
+    // 表格索引
+    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;
+  }
+}
+</style>

+ 199 - 0
src/views/admin/supplier/audit/doctor/review.vue

@@ -0,0 +1,199 @@
+<template>
+  <div class="doctor-edit">
+    <el-form ref="formRef" class="doctor-edit-form" label-width="140px" :model="formData" :rules="formRules">
+      <el-form-item label="医师姓名:">
+        <span>{{ doctorInfo.doctorName }}</span>
+      </el-form-item>
+      <el-form-item label="从业资格证编号:">
+        <span>{{ doctorInfo.certificateNo }}</span>
+      </el-form-item>
+      <el-form-item label="所在机构:" prop="clubName">
+        <span>{{ doctorInfo.clubName }}</span>
+      </el-form-item>
+      <el-form-item label="医师照片:" prop="doctorImage">
+        <el-image
+          style="width: 140px; height: 140px"
+          :src="doctorInfo.doctorImage"
+          :preview-src-list="doctorImgList"
+        />
+      </el-form-item>
+      <el-form-item label="轮播图:" prop="banner">
+        <el-image
+          v-for="(image,index) in doctorInfo.bannerList"
+          :key="index"
+          style="width: 140px; height: 140px"
+          :src="image"
+          :preview-src-list="bannerImgList"
+        />
+      </el-form-item>
+
+      <el-form-item label="具备操作资格设备:" prop="equipment">
+        <div class="device-section">
+          <div v-for="(equipment, index) in doctorInfo.equipmentList" :key="index" class="section">
+            <el-form label-width="90px">
+              <el-form-item label="设备名称:">
+                <span>{{ equipment.equipmentName }}</span>
+              </el-form-item>
+              <el-form-item label="所属品牌:">
+                <span>{{ equipment.brand }}</span>
+              </el-form-item>
+              <el-form-item label="设备图片:">
+                <el-image
+                  style="width: 140px; height: 140px"
+                  :src="equipment.image"
+                  :preview-src-list="equipmentImgList"
+                />
+              </el-form-item>
+            </el-form>
+          </div>
+        </div>
+      </el-form-item>
+
+      <!-- 审核表单 -->
+      <el-form-item v-if="type === 'audit'" label="审核状态:">
+        <el-radio-group v-model="formData.auditStatus">
+          <el-radio :label="1">通过</el-radio>
+          <el-radio :label="0">不通过</el-radio>
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item v-if="formData.auditStatus!==1" prop="invalidReason" label="原因:">
+        <el-input v-model="formData.invalidReason" type="textarea" placeholder="请说明原因" />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="info" @click="$_back">返回</el-button>
+        <el-button type="primary" @click="submit">提交</el-button>
+      </el-form-item>
+    </el-form>
+  </div>
+</template>
+
+<script>
+import { mapGetters } from 'vuex'
+import { doctorFormData, doctorAudit } from '@/api/doctor'
+
+export default {
+  data() {
+    return {
+      isRequest: true,
+      doctorId: '',
+      point: {},
+      disabled: false,
+      doctorInfo: {
+        doctorName: '',
+        certificateNo: '',
+        clubName: '',
+        bannerList: '',
+        doctorImage: '',
+        equipmentList: ''
+      },
+      formData: {
+        auditBy: '', // 审核人id
+        doctorId: '', // 商品id
+        auditStatus: 1, // 商品审核状态
+        invalidReason: '' // 审核信息
+      },
+      formRules: {
+        invalidReason: { required: true, message: '不通过原因不能为空', tigger: 'blur' }
+      },
+      type: 'audit',
+      doctorImgList: [],
+      bannerImgList: [],
+      equipmentImgList: []
+    }
+  },
+  computed: {
+    ...mapGetters(['authUserId'])
+  },
+  created() {
+    this.doctorId = this.formData.doctorId = parseInt(this.$route.query.id)
+    this.type = this.$route.query.type
+    this.initFormData()
+  },
+  methods: {
+    // 表单数据回显
+    initFormData() {
+      doctorFormData({ doctorId: this.doctorId }).then(res => {
+        this.setFormData(res.data)
+      })
+    },
+    // 设置表单数据
+    setFormData(data) {
+      this.doctorInfo.doctorName = data.doctorName
+      this.doctorInfo.certificateNo = data.certificateNo
+      this.doctorInfo.clubName = data.clubName
+      this.doctorInfo.bannerList = data.bannerList
+      this.doctorInfo.doctorImage = data.doctorImage
+      this.doctorInfo.equipmentList = data.equipmentList
+
+      this.doctorImgList = [data.doctorImage]
+      this.bannerImgList = data.bannerList
+      this.equipmentImgList = data.equipmentList.map(item => item.image)
+    },
+
+    // 提交审核信息
+    submit() {
+      this.$refs.formRef.validate(valid => {
+        if (valid) {
+          this.isLoading = true
+          // 指定审核人
+          this.formData.auditBy = this.authUserId
+          // 提交审核信息
+          doctorAudit(this.formData).then(res => {
+            if (res.code !== 0) return
+            this.$message.success(res.data)
+            this.$store.dispatch('tagsView/delView', this.$route)
+            this.$router.back()
+          }).finally(() => {
+            this.isLoading = false
+          })
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.doctor-edit{
+  margin-bottom: 80px;
+}
+
+.doctor-edit-form {
+  width: 650px;
+  margin: 0 auto;
+  margin-top: 80px;
+}
+.submit-btn {
+  text-align: center;
+  .el-button {
+    width: 140px;
+  }
+}
+
+.device-section {
+  .section {
+    position: relative;
+    border: 1px solid #eee;
+    padding: 25px 25px 0 16px;
+    margin-bottom: 16px;
+    .remove {
+      position: absolute;
+      right: 6px;
+      top: 6px;
+      font-size: 14px;
+      cursor: pointer;
+      background: #f56c6c;
+      color: #fff;
+      padding: 2px;
+      border-radius: 50%;
+      transition: all 0.2s;
+      &:hover {
+        background: red;
+      }
+    }
+  }
+  .el-form-item {
+    padding-bottom: 25px;
+  }
+}
+</style>

+ 190 - 0
src/views/admin/supplier/audit/material/article/index.vue

@@ -0,0 +1,190 @@
+<template>
+  <div class="app-container">
+    <!-- 搜索区域 -->
+    <div class="filter-container">
+      <span>文章标题:</span>
+      <el-input
+        v-model="listQuery.articleTitle"
+        placeholder="文章标题"
+        style="width: 200px"
+        class="filter-item"
+        @keyup.enter.native="getList"
+      />
+      <span>审核状态:</span>
+      <el-select
+        v-model="listQuery.auditStatus"
+        placeholder="审核状态"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="全部" value="" />
+        <el-option label="待审核" :value="2" />
+        <el-option label="审核通过" :value="1" />
+        <el-option label="审核未通过" :value="0" />
+      </el-select>
+      <el-button type="primary" icon="el-icon-search" @click="getList">查询</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 label="序号" :index="indexMethod" type="index" width="80" align="center" />
+      <el-table-column label="文章标题" prop="articleTitle" align="center" />
+      <el-table-column label="文章头图" width="200" align="center">
+        <template slot-scope="{ row }">
+          <el-image
+            style="width: 50px; height: 50px"
+            :src="row.articleImage"
+          /></template>
+      </el-table-column>
+      <el-table-column label="审核状态" width="150px" align="center">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.auditStatus === 2" size="small" type="warning">待审核</el-tag>
+          <el-tag v-if="row.auditStatus === 1" size="small" type="success">审核通过</el-tag>
+          <!-- 未通过原因展示 -->
+          <template v-if="row.auditStatus === 0">
+            <!-- <span class="status danger">审核未通过&nbsp;</span> -->
+            <el-popover
+              placement="top-start"
+              title="审核说明"
+              width="400"
+              trigger="hover"
+              :content="row.invalidReason"
+            >
+              <el-tag slot="reference" size="small" type="danger" class="reason">
+                <span>审核未通过</span>
+                <span class="el-icon-question status danger " />
+              </el-tag>
+            </el-popover>
+            <!-- 未通过原因展示END -->
+          </template>
+        </template>
+      </el-table-column>
+      <el-table-column label="审核时间" width="250px" align="center">
+        <template slot-scope="{row}">
+          <span v-if="row.auditStatus!==2">{{ row.auditTime | formatTime }}</span>
+          <span v-else>—</span>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="审核人" align="center" width="200px">
+        <template slot-scope="{row}">
+          <span v-if="row.auditStatus!==2">{{ row.auditBy }}</span>
+          <span v-else>—</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" width="150px" align="center">
+        <template slot-scope="{row}">
+          <el-button
+            v-if="row.auditStatus !== 1"
+            type="primary"
+            size="mini"
+            style="margin-right:5px"
+            icon="el-icon-s-check"
+            @click="$_navigationTo(`doc-article-detail?articleId=${row.articleId}`)"
+          >审核</el-button>
+          <span v-else class="status success el-icon-check">&nbsp;已审核</span>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 表格区域END -->
+    <!-- 页码 -->
+    <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'
+import { formatDate } from '@/utils'
+import { getArticleList } from '@/api/doc'
+export default {
+  components: { Pagination },
+  filters: {
+    formatTime(time) {
+      if (!time) {
+        return ''
+      }
+      return formatDate(time, 'yyyy-MM-DD HH:mm:ss')
+    }
+  },
+  data() {
+    return {
+      listLoading: false,
+      total: 0, // 列表数据条数
+      listQuery: {
+        authUserId: '', // 机构id
+        auditStatus: '', // 审核状态
+        articleTitle: '', // 文章标题
+        listType: 2, // 列表类型:1文章列表,2文章审核列表
+        pageNum: 1, // 页码
+        pageSize: 10, // 分页大小
+        status: '' // 文章状态:0已下线,1已上线,2待上线
+      },
+      list: []
+    }
+  },
+  created() {
+    this.listQuery.authUserId = this.$route.query.authUserId
+    this.getList()
+  },
+  methods: {
+    // 获取列表数据
+    getList() {
+      this.listLoading = true
+      getArticleList(this.listQuery)
+        .then(res => {
+          if (res.code !== 0) return
+          this.list = res.data.list
+          this.total = res.data.total
+          console.log(res)
+        })
+        .finally(() => {
+          this.listLoading = false
+        })
+    },
+    // 初始化预览图片列表
+    initPreviewList(list) {
+      list.forEach(item => this.srcList.push(item.articleCover))
+    },
+    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;
+}
+</style>

+ 108 - 0
src/views/admin/supplier/audit/material/article/review.vue

@@ -0,0 +1,108 @@
+<template>
+  <div class="app-container">
+    <el-form ref="formRef" :model="formData" :rules="formRules" class="detail" label-width="100px">
+      <el-form-item label="文章标题:">{{ articleTitle }}</el-form-item>
+      <el-form-item label="文章封面:">
+        <el-image style="width:200px;height:200px" :src="articleImage" :preview-src-list="srcList" />
+      </el-form-item>
+      <el-form-item label="文章内容:">
+        <div class="iframe" v-html="articleContent" />
+        <!-- <iframe width="375" height="667" :src="previewSrc" frameborder="1" /> -->
+      </el-form-item>
+      <el-form-item label="审核状态:">
+        <el-radio-group v-model="formData.auditStatus">
+          <el-radio :label="1">通过</el-radio>
+          <el-radio :label="0">不通过</el-radio>
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item v-if="formData.auditStatus!==1" prop="invalidReason" label="原因:">
+        <el-input v-model="formData.invalidReason" type="textarea" placeholder="请说明原因" />
+      </el-form-item>
+      <el-form-item label="">
+        <el-button type="info" @click="$_back">返回</el-button>
+        <el-button type="primary" @click="submit">提交</el-button>
+      </el-form-item>
+    </el-form>
+  </div>
+</template>
+
+<script>
+import { getArticleDeatil } from '@/api/doc'
+import { auditArticle } from '@/api/docReview'
+import { mapGetters } from 'vuex'
+export default {
+  data() {
+    return {
+      articleContent: '', // 文章内容
+      articleTitle: '', // 文章标题
+      articleImage: '', // 文章封面图
+      srcList: [], // 文章封面图片回显
+      previewSrc: '', // 预览图片列表
+      formData: {
+        articleId: '', // 文章id
+        auditStatus: 1, // 审核状态
+        invalidReason: '', // 不同过原因
+        auditBy: '' // 审核人
+      },
+      formRules: {
+        invalidReason: { required: true, message: '不通过原因不能为空', tigger: 'blur' }
+      }
+    }
+  },
+  computed: {
+    ...mapGetters(['authUserId'])
+  },
+  created() {
+    this.formData.articleId = this.$route.query.articleId
+    this.getDetail()
+  },
+  methods: {
+    // 获取文章数据
+    getDetail() {
+      getArticleDeatil({ articleId: this.formData.articleId })
+        .then(res => {
+          console.log(res)
+          if (res.code !== 0) return
+          this.articleContent = res.data.articleContent
+          this.articleTitle = res.data.articleTitle
+          this.articleImage = res.data.articleImage
+          this.srcList.push(this.articleImage)
+        })
+    },
+    // 审核操作
+    submit() {
+      this.$refs.formRef.validate(valide => {
+        if (!valide) return
+        this.formData.auditBy = this.authUserId
+        auditArticle(this.formData)
+          .then(res => {
+            console.log(res)
+            if (res.code !== 0) return
+            this.$message({
+              message: res.data,
+              type: 'success',
+              duration: 1000
+            })
+            this.$store.dispatch('tagsView/delView', this.$route)
+            this.$router.back()
+          })
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.iframe{
+  height: 600px;
+  overflow: scroll;
+  border: 1px solid #999;
+}
+.detail{
+  width: 1000px;
+  margin: 30px auto;
+}
+.el-button{
+  width: 120px;
+}
+</style>

+ 279 - 0
src/views/admin/supplier/audit/material/file/index.vue

@@ -0,0 +1,279 @@
+<template>
+  <div class="app-container review-box">
+    <!-- 搜索区域 -->
+    <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-select
+        v-model="listQuery.auditStatus"
+        placeholder="审核状态"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="全部" value="" />
+        <el-option label="待审核" :value="2" />
+        <el-option label="审核通过" :value="1" />
+        <el-option label="审核未通过" :value="0" />
+      </el-select>
+      <el-button type="primary" icon="el-icon-search" @click="getList">查询</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 label="序号" :index="indexMethod" type="index" width="80" align="center" />
+      <el-table-column label="文件名称" prop="fileTitle" align="center" />
+      <el-table-column label="审核状态" width="150px" align="center">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.auditStatus === 2" size="small" type="warning">待审核</el-tag>
+          <el-tag v-if="row.auditStatus === 1" size="small" type="success">审核通过</el-tag>
+          <!-- 未通过原因展示 -->
+          <template v-if="row.auditStatus === 0">
+            <!-- <span class="status danger">审核未通过&nbsp;</span> -->
+            <el-popover
+              placement="top-start"
+              title="审核说明"
+              width="400"
+              trigger="hover"
+              :content="row.invalidReason"
+            >
+              <el-tag slot="reference" size="small" type="danger" class="reason">
+                <span>审核未通过</span>
+                <span class="el-icon-question status danger " />
+              </el-tag>
+            </el-popover>
+            <!-- 未通过原因展示END -->
+          </template>
+        </template>
+      </el-table-column>
+      <el-table-column label="审核时间" width="250px" align="center">
+        <template slot-scope="{row}">
+          <span v-if="row.auditStatus!==2">{{ row.auditTime | formatTime }}</span>
+          <span v-else>—</span>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="审核人" align="center" width="200px">
+        <template slot-scope="{row}">
+          <span v-if="row.auditStatus!==2">{{ row.auditBy }}</span>
+          <span v-else>—</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" width="150px" align="center">
+        <template slot-scope="{row}">
+          <el-button
+            v-if="row.auditStatus===2"
+            type="primary"
+            size="mini"
+            style="margin-right:5px"
+            icon="el-icon-s-check"
+            @click="handleShowDialog(row)"
+          >审核</el-button>
+          <span v-else class="status success el-icon-check">&nbsp;已审核</span>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 表格区域END -->
+    <!-- 页码 -->
+    <pagination v-show="total > 0" :total="total" :page.sync="listQuery.pageNum" :limit.sync="listQuery.pageSize" @pagination="getList(listQuery)" />
+    <!-- 视频预览对话框 -->
+    <el-dialog
+      title="视频审核"
+      :visible.sync="dialogVisible"
+      width="40%"
+      @closed="dialogColosed"
+    >
+      <el-form ref="formRef" :model="dialogData" label-width="65px" :rules="dialogFormRules">
+        <el-form-item label="标题:">
+          {{ current.fileTitle }}
+        </el-form-item>
+        <el-form-item label="文件:">
+          <img src="@/assets/img/pdf_cover.png" alt="文件封面" width="60" height="60">
+          <span class="preview" @click.prevent="handlePreviewFile">预览</span>
+        </el-form-item>
+        <el-form-item label="审核:">
+          <el-radio-group v-model="dialogData.auditStatus">
+            <el-radio :label="1">通过</el-radio>
+            <el-radio :label="0">不通过</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item v-if="dialogData.auditStatus === 0" label="原因:" prop="invalidReason">
+          <el-input v-model="dialogData.invalidReason" type="textarea" placeholder="请说明原因" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="dialogVisible = false">取 消</el-button>
+        <el-button type="primary" @click="handleAuditStatus">提 交</el-button>
+      </div>
+    </el-dialog>
+    <!-- 视频预览对话框END -->
+  </div>
+</template>
+
+<script>
+import Pagination from '@/components/Pagination'
+import openWindow from '@/utils/open-window'
+import { formatDate } from '@/utils'
+import { getFileList } from '@/api/doc'
+import { auditfile } from '@/api/docReview'
+import { mapGetters } from 'vuex'
+export default {
+  components: { Pagination },
+  filters: {
+    formatTime(time) {
+      if (!time) {
+        return ''
+      }
+      return formatDate(time, 'yyyy-MM-DD HH:mm:ss')
+    }
+  },
+  data() {
+    return {
+      dialogVisible: false, // 文件审核dialog是否显示
+      listLoading: false, // 列表加载
+      total: 0, // 列表数据条数
+      listQuery: {
+        authUserId: '', // 机构id
+        auditStatus: '', // 审核状态
+        fileTitle: '', // 文件标题
+        listType: 2, // 列表类型
+        pageNum: 1, // 页码
+        pageSize: 10, // 分页大小
+        status: '' // 文章状态:0已下线,1已上线,2待上线
+      },
+      list: [],
+      // 当前审核选中的文件数据,需要传给预览窗口的数据
+      current: {
+        currentfileUrl: '',
+        fileTitle: ''
+      },
+      // 审核提交数据
+      dialogData: {
+        fileId: '', // 文章id
+        auditStatus: 1, // 审核状态
+        invalidReason: '', // 不同过原因
+        auditBy: '' // 审核人
+      },
+      dialogFormRules: {
+        invalidReason: { required: true, message: '不通过原因不能为空', tigger: 'blur' }
+      }
+    }
+  },
+  computed: {
+    ...mapGetters(['authUserId'])
+  },
+  created() {
+    this.listQuery.authUserId = this.$route.query.authUserId
+    this.getList()
+  },
+  methods: {
+    // 获取列表数据
+    getList() {
+      this.listLoading = true
+      getFileList(this.listQuery)
+        .then(res => {
+          if (res.code !== 0) return
+          this.list = res.data.list
+          this.total = res.data.total
+          console.log(res)
+        })
+        .finally(() => {
+          this.listLoading = false
+        })
+    },
+    // 显示审核dialog对话框
+    handleShowDialog(row) {
+      console.log('------')
+      console.log(row)
+      this.current.currentfileUrl = row.filePreviewUrl
+      this.current.fileTitle = row.fileTitle
+      this.dialogData.fileId = row.fileId
+      this.dialogVisible = true
+    },
+    // dialog关闭后的回调
+    dialogColosed() {
+      this.currentfileUrl = ''
+      this.current.currentfileUrl = ''
+      this.current.fileTitle = ''
+      this.dialogData.auditStatus = 1
+      this.dialogData.fileId = ''
+    },
+    // 审核操作
+    handleAuditStatus() {
+      this.$refs.formRef.validate(valid => {
+        if (valid) {
+          this.dialogData.auditBy = this.authUserId
+          auditfile(this.dialogData)
+            .then(res => {
+              console.log(res)
+              if (res.code !== 0) return
+              this.$message({
+                message: res.data,
+                type: 'success',
+                duration: 1000
+              })
+              this.dialogVisible = false
+              this.getList()
+            })
+        }
+      })
+    },
+    // 小窗口浏览pdf文件
+    handlePreviewFile() {
+      openWindow(this.current.currentfileUrl, this.current.fileTitle, this.current.fileTitle, 1200, 600)
+    },
+    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;
+}
+.preview{
+  cursor: pointer;
+  margin-left: 5px;
+  color: #0eaae7;
+}
+</style>

+ 0 - 0
src/views/admin/supplier/audit/material/file/review.vue


+ 179 - 0
src/views/admin/supplier/audit/material/image/index.vue

@@ -0,0 +1,179 @@
+<template>
+  <div class="app-container">
+    <!-- 搜索区域 -->
+    <div class="filter-container">
+      <span>图片标题:</span>
+      <el-input
+        v-model="listQuery.imageTitle"
+        placeholder="图片标题"
+        style="width: 200px"
+        class="filter-item"
+        @keyup.enter.native="getList"
+      />
+      <span>审核状态:</span>
+      <el-select
+        v-model="listQuery.auditStatus"
+        placeholder="审核状态"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="全部" value="" />
+        <el-option label="待审核" :value="2" />
+        <el-option label="审核通过" :value="1" />
+        <el-option label="审核未通过" :value="0" />
+      </el-select>
+      <el-button type="primary" icon="el-icon-search" @click="getList">查询</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 label="序号" type="index" :index="indexMethod" width="80" align="center" />
+      <el-table-column label="图片标题" prop="imageTitle" align="center" />
+      <el-table-column label="审核状态" width="150px" align="center">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.auditStatus === 2" size="small" type="warning">待审核</el-tag>
+          <el-tag v-if="row.auditStatus === 1" size="small" type="success">审核通过</el-tag>
+          <!-- 未通过原因展示 -->
+          <template v-if="row.auditStatus === 0">
+            <!-- <span class="status danger">审核未通过&nbsp;</span> -->
+            <el-popover
+              placement="top-start"
+              title="审核说明"
+              width="400"
+              trigger="hover"
+              :content="row.invalidReason"
+            >
+              <el-tag slot="reference" size="small" type="danger" class="reason">
+                <span>审核未通过</span>
+                <span class="el-icon-question status danger " />
+              </el-tag>
+            </el-popover>
+            <!-- 未通过原因展示END -->
+          </template>
+        </template>
+      </el-table-column>
+      <el-table-column label="审核时间" width="250px" align="center">
+        <template slot-scope="{row}">
+          <span v-if="row.auditStatus!==2">{{ row.auditTime | formatTime }}</span>
+          <span v-else>—</span>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="审核人" align="center" width="200px">
+        <template slot-scope="{row}">
+          <span v-if="row.auditStatus!==2">{{ row.auditBy }}</span>
+          <span v-else>—</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" width="150px" align="center">
+        <template slot-scope="{row}">
+          <el-button
+            v-if="row.auditStatus !== 1"
+            type="primary"
+            size="mini"
+            style="margin-right:5px"
+            icon="el-icon-s-check"
+            @click="$_navigationTo(`doc-image-detail?imageId=${row.imageId}`)"
+          >审核</el-button>
+          <span v-else class="status success el-icon-check">&nbsp;已审核</span>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 表格区域END -->
+    <!-- 页码 -->
+    <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'
+import { formatDate } from '@/utils'
+import { getImageList } from '@/api/doc'
+export default {
+  components: { Pagination },
+  filters: {
+    formatTime(time) {
+      if (!time) {
+        return ''
+      }
+      return formatDate(time, 'yyyy-MM-DD HH:mm:ss')
+    }
+  },
+  data() {
+    return {
+      listLoading: false, // 列表加载
+      total: 0, // 图片总条数
+      listQuery: {
+        authUserId: '', // 机构id
+        auditStatus: '', // 审核状态
+        imageTitle: '', // 图片标题
+        listType: 2, // 列表类型
+        pageNum: 1, // 页码
+        pageSize: 10, // 分页大小
+        status: '' // 文章状态:0已下线,1已上线,2待上线
+      },
+      list: []
+    }
+  },
+  created() {
+    this.listQuery.authUserId = this.$route.query.authUserId
+    this.getList()
+  },
+  methods: {
+    // 获取列表数据
+    getList() {
+      this.listLoading = true
+      getImageList(this.listQuery)
+        .then(res => {
+          if (res.code !== 0) return
+          this.list = res.data.list
+          this.total = res.data.total
+          console.log(res)
+        })
+        .finally(() => {
+          this.listLoading = false
+        })
+    },
+    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;
+}
+</style>

+ 107 - 0
src/views/admin/supplier/audit/material/image/review.vue

@@ -0,0 +1,107 @@
+<template>
+  <div class="app-container">
+    <div class="detail">
+      <el-form ref="formRef" label-width="120px" :model="formData" :rules="formRules">
+        <el-form-item label="标题:">
+          {{ imageTitle }}
+        </el-form-item>
+        <el-form-item label="图片:">
+          <template v-for="(item,index) in imageList">
+            <el-image :key="index" style="width: 150px; height: 150px" :src="item" :preview-src-list="imageList" />
+          </template>
+        </el-form-item>
+        <el-form-item label="审核状态:">
+          <el-radio-group v-model="formData.auditStatus">
+            <el-radio :label="1">通过</el-radio>
+            <el-radio :label="0">不通过</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item v-if="formData.auditStatus!==1" prop="invalidReason" label="原因:">
+          <el-input v-model="formData.invalidReason" type="textarea" placeholder="请说明原因" />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="info" @click="$_back">返回</el-button>
+          <el-button type="primary" @click="submit">提交</el-button>
+        </el-form-item>
+      </el-form>
+    </div>
+  </div>
+</template>
+
+<script>
+import { getImageDetail } from '@/api/doc'
+import { auditImage } from '@/api/docReview'
+import { mapGetters } from 'vuex'
+export default {
+  data() {
+    return {
+      imageList: [], // 上传的图片列表
+      imageTitle: '', // 图片标题
+      formData: {
+        imageId: '', // 文章id
+        auditStatus: 1, // 审核状态
+        invalidReason: '', // 不同过原因
+        auditBy: '' // 审核人
+      },
+      formRules: {
+        invalidReason: { required: true, message: '不通过原因不能为空', tigger: 'blur' }
+      }
+    }
+  },
+  computed: {
+    ...mapGetters(['authUserId'])
+  },
+  created() {
+    this.formData.imageId = this.$route.query.imageId
+    this.getDetail()
+  },
+  methods: {
+    // 审核
+    submit() {
+      this.$refs.formRef.validate(valide => {
+        if (!valide) return
+        this.formData.auditBy = this.authUserId
+        auditImage(this.formData)
+          .then(res => {
+            console.log(res)
+            if (res.code !== 0) return
+            this.$message({
+              message: res.data,
+              type: 'success',
+              duration: 1000
+            })
+            // 如果保存文章成功就要关闭当前页面
+            this.$store.dispatch('tagsView/delView', this.$route)
+            this.$router.back()
+          })
+      })
+    },
+    // 获取图片数据详情
+    getDetail() {
+      getImageDetail({ imageId: this.formData.imageId })
+        .then(res => {
+          console.log(res)
+          if (res.code !== 0) return
+          this.imageList = res.data.imageList
+          this.imageTitle = res.data.imageTitle
+        })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.detail{
+  width: 800px;
+  margin: 25px auto;
+  .el-image{
+    margin-right: 12px;
+    &:nth-child(4n){
+      margin-right: 0;
+    }
+  }
+  .el-button{
+    width: 120px;
+  }
+}
+</style>

+ 199 - 0
src/views/admin/supplier/audit/material/index.vue

@@ -0,0 +1,199 @@
+<template>
+  <div class="app-container">
+    <!-- 搜索区域 -->
+    <div class="filter-container">
+      <span>供应商名称:</span>
+      <el-input
+        v-model="listQuery.shopName"
+        placeholder="供应商名称"
+        style="width: 200px"
+        class="filter-item"
+        @keyup.enter.native="getList"
+      />
+      <span>供应商类型:</span>
+      <el-select
+        v-model="listQuery.shopType"
+        placeholder="供应商类型"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="所有类型" value="" />
+        <el-option label="代理商" :value="2" />
+        <el-option label="品牌方" :value="1" />
+      </el-select>
+      <span>手机号:</span>
+      <el-input
+        v-model="listQuery.mobile"
+        placeholder="手机号"
+        style="width: 200px"
+        class="filter-item"
+        @keyup.enter.native="getList"
+      />
+      <span>审核状态:</span>
+      <el-select
+        v-model="listQuery.lowerAuditStatus"
+        placeholder="供应商类型"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="全部" value="" />
+        <el-option label="已完成审核" :value="1" />
+        <el-option label="未完成审核" :value="0" />
+      </el-select>
+      <span>联系人:</span>
+      <el-input
+        v-model="listQuery.linkMan"
+        placeholder="联系人"
+        style="width: 200px"
+        class="filter-item"
+        @keyup.enter.native="getList"
+      />
+      <el-button type="primary" icon="el-icon-search" @click="getList">查询</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 label="序号" :index="indexMethod" type="index" width="80" align="center" />
+      <el-table-column prop="name" label="供应商名称" align="center" />
+      <el-table-column label="供应商类型" width="150px" align="center">
+        <template slot-scope="{ row }">
+          <span v-if="row.shopType === 1">品牌方</span>
+          <span v-if="row.shopType === 2">代理商</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="mobile" label="手机号" width="200px" align="center" />
+      <el-table-column prop="linkMan" label="联系人" width="200px" align="center" />
+      <el-table-column label="审核状态" width="150px" align="center">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.lowerAuditStatus === 0" size="small" type="danger">未完成审核</el-tag>
+          <el-tag v-if="row.lowerAuditStatus === 1" size="small" type="success">已完成审核</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="待审核" width="460px" align="center">
+        <template slot-scope="{ row }">
+          <el-badge :hidden="row.articleWaitNum === 0" :value="row.articleWaitNum" :max="99">
+            <el-button
+              type="primary"
+              icon="el-icon-tickets"
+              size="mini"
+              @click="$_navigationTo(`doc-article-list?authUserId=${row.authUserId}`)"
+            >文章</el-button>
+          </el-badge>
+          <el-badge :hidden="row.imageWaitNum === 0" :value="row.imageWaitNum" :max="99">
+            <el-button
+              type="primary"
+              icon="el-icon-picture-outline"
+              size="mini"
+              @click="$_navigationTo(`doc-image-list?authUserId=${row.authUserId}`)"
+            >图片</el-button>
+          </el-badge>
+          <el-badge :hidden="row.videoWaitNum === 0" :value="row.videoWaitNum" :max="99">
+            <el-button
+              type="primary"
+              icon="el-icon-video-camera"
+              size="mini"
+              @click="$_navigationTo(`doc-video-list?authUserId=${row.authUserId}`)"
+            >视频</el-button>
+          </el-badge>
+          <el-badge :hidden="row.fileWaitNum === 0" :value="row.fileWaitNum" :max="99">
+            <el-button
+              type="primary"
+              icon="el-icon-document-copy"
+              size="mini"
+              @click="$_navigationTo(`doc-file-list?authUserId=${row.authUserId}`)"
+            >文件</el-button>
+          </el-badge>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 表格区域END -->
+    <!-- 页码 -->
+    <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'
+import { fetchSupplierList } from '@/api/supplier'
+export default {
+  components: { Pagination },
+  data() {
+    return {
+      listLoading: false,
+      total: 0,
+      listQuery: {
+        listType: 3,
+        brandId: '', // 品牌id
+        linkMan: '', // 联系人
+        mobile: '', // 手机号
+        pageNum: 1, // 页码
+        pageSize: 10, // 分页大小
+        shopName: '', // 供应商名称
+        shopType: '', // 供应商类型
+        lowerAuditStatus: ''
+      },
+      list: []
+    }
+  },
+  created() {
+    this.getList()
+  },
+  methods: {
+    // 获取供应商待审核列表数据
+    getList() {
+      this.listLoading = true
+      fetchSupplierList(this.listQuery)
+        .then(res => {
+          if (res.code !== 0) return
+          this.list = res.data.list
+          this.total = res.data.total
+        })
+        .finally(() => {
+          this.listLoading = false
+        })
+    },
+    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;
+}
+</style>

+ 0 - 0
src/views/admin/supplier/audit/material/review.vue


+ 270 - 0
src/views/admin/supplier/audit/material/video/index.vue

@@ -0,0 +1,270 @@
+<template>
+  <div class="app-container review-box">
+    <!-- 搜索区域 -->
+    <div class="filter-container">
+      <span>视频名称:</span>
+      <el-input
+        v-model="listQuery.videoTitle"
+        placeholder="视频名称"
+        style="width: 200px"
+        class="filter-item"
+        @keyup.enter.native="getList"
+      />
+      <span>审核状态:</span>
+      <el-select
+        v-model="listQuery.auditStatus"
+        placeholder="审核状态"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="全部" value="" />
+        <el-option label="待审核" :value="2" />
+        <el-option label="审核通过" :value="1" />
+        <el-option label="审核未通过" :value="0" />
+      </el-select>
+      <el-button type="primary" icon="el-icon-search" @click="getList">查询</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 label="序号" type="index" :index="indexMethod" width="80" align="center" />
+      <el-table-column label="视频名称" prop="videoTitle" align="center" />
+      <el-table-column label="审核状态" width="150px" align="center">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.auditStatus === 2" size="small" type="warning">待审核</el-tag>
+          <el-tag v-if="row.auditStatus === 1" size="small" type="success">审核通过</el-tag>
+          <!-- 未通过原因展示 -->
+          <template v-if="row.auditStatus === 0">
+            <!-- <span class="status danger">审核未通过&nbsp;</span> -->
+            <el-popover
+              placement="top-start"
+              title="审核说明"
+              width="400"
+              trigger="hover"
+              :content="row.invalidReason"
+            >
+              <el-tag slot="reference" size="small" type="danger" class="reason">
+                <span>审核未通过</span>
+                <span class="el-icon-question status danger " />
+              </el-tag>
+            </el-popover>
+            <!-- 未通过原因展示END -->
+          </template>
+        </template>
+      </el-table-column>
+      <el-table-column label="审核时间" width="250px" align="center">
+        <template slot-scope="{row}">
+          <span v-if="row.auditStatus!==2">{{ row.auditTime | formatTime }}</span>
+          <span v-else>—</span>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="审核人" align="center" width="200px">
+        <template slot-scope="{row}">
+          <span v-if="row.auditStatus!==2">{{ row.auditBy }}</span>
+          <span v-else>—</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" width="150px" align="center">
+        <template slot-scope="{row}">
+          <el-button
+            v-if="row.auditStatus !== 1"
+            type="primary"
+            size="mini"
+            style="margin-right:5px"
+            icon="el-icon-s-check"
+            @click="handleShowDialog(row)"
+          >审核</el-button>
+          <span v-else class="status success el-icon-check">&nbsp;已审核</span>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 表格区域END -->
+    <!-- 页码 -->
+    <pagination v-show="total > 0" :total="total" :page.sync="listQuery.pageNum" :limit.sync="listQuery.pageSize" @pagination="getList(listQuery)" />
+    <!-- 视频预览对话框 -->
+    <el-dialog
+      title="视频审核"
+      :visible.sync="dialogVisible"
+      width="40%"
+      @closed="dialogColosed"
+    >
+      <el-form ref="formRef" :model="dialogData" label-width="65px" :rules="dialogFormRules">
+        <el-form-item label="标题:">
+          {{ current.videoTitle }}
+        </el-form-item>
+        <el-form-item label="视频:">
+          <video :src="current.currentVideoUrl" controls="controls" width="100%">
+            您的浏览器不支持播放该视频
+          </video>
+        </el-form-item>
+        <el-form-item label="审核:">
+          <el-radio-group v-model="dialogData.auditStatus">
+            <el-radio :label="1">通过</el-radio>
+            <el-radio :label="0">不通过</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item v-if="dialogData.auditStatus === 0" label="原因:" prop="invalidReason">
+          <el-input v-model="dialogData.invalidReason" type="textarea" placeholder="请说明原因" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="dialogVisible = false">取 消</el-button>
+        <el-button type="primary" @click="handleAuditStatus">提 交</el-button>
+      </div>
+    </el-dialog>
+    <!-- 视频预览对话框END -->
+  </div>
+</template>
+
+<script>
+import Pagination from '@/components/Pagination'
+import { formatDate } from '@/utils'
+import { getVideoList } from '@/api/doc'
+import { auditVideo } from '@/api/docReview'
+import { mapGetters } from 'vuex'
+export default {
+  components: { Pagination },
+  filters: {
+    formatTime(time) {
+      if (!time) {
+        return ''
+      }
+      return formatDate(time, 'yyyy-MM-DD HH:mm:ss')
+    }
+  },
+  data() {
+    return {
+      dialogVisible: false, // 视频审核dialog是否显示
+      listLoading: false, // 列表加载
+      total: 0, // 列表总数据条数
+      listQuery: {
+        authUserId: '', // 机构id
+        auditStatus: '', // 审核状态
+        videoTitle: '', // 视频标题
+        listType: 2, // 列表类型
+        pageNum: 1, // 页码
+        pageSize: 10, // 分页大小
+        status: '' // 文章状态:0已下线,1已上线,2待上线
+      },
+      list: [],
+      current: {
+        currentVideoUrl: '', // 当前选中的视频url,预览url
+        videoTitle: ''
+      },
+      dialogData: {
+        videoId: '', // 文章id
+        auditStatus: 1, // 审核状态
+        invalidReason: '', // 不同过原因
+        auditBy: '' // 审核人
+      },
+      dialogFormRules: {
+        invalidReason: {
+          required: true,
+          message: '不通过原因不能为空',
+          tigger: 'blur'
+        }
+      }
+    }
+  },
+  computed: {
+    ...mapGetters(['authUserId'])
+  },
+  created() {
+    this.listQuery.authUserId = this.$route.query.authUserId
+    this.getList()
+  },
+  methods: {
+    // 获取列表数据
+    getList() {
+      this.listLoading = true
+      getVideoList(this.listQuery)
+        .then(res => {
+          if (res.code !== 0) return
+          this.list = res.data.list
+          this.total = res.data.total
+          console.log(res)
+        })
+        .finally(() => {
+          this.listLoading = false
+        })
+    },
+    // 显示审核对话框
+    handleShowDialog(row) {
+      console.log(row)
+      this.current.currentVideoUrl = row.videoPreviewUrl
+      this.current.videoTitle = row.videoTitle
+      this.dialogData.videoId = row.videoId
+      this.dialogVisible = true
+    },
+    // 审核框关闭事件
+    dialogColosed() {
+      this.currentVideoUrl = ''
+      this.dialogData.auditStatus = 1
+      this.dialogData.videoId = ''
+      this.$refs.formRef.clearValidate()
+    },
+    // 审核
+    handleAuditStatus() {
+      this.$refs.formRef.validate(valid => {
+        if (valid) {
+          console.log(valid)
+          this.dialogData.auditBy = this.authUserId
+          auditVideo(this.dialogData)
+            .then(res => {
+              console.log(res)
+              if (res.code !== 0) return
+              this.$message({
+                message: res.data,
+                type: 'success',
+                duration: 1000
+              })
+              this.dialogVisible = false
+              this.getList()
+            })
+        }
+      })
+    },
+    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;
+}
+</style>

+ 0 - 0
src/views/admin/supplier/audit/material/video/review.vue


+ 299 - 0
src/views/admin/supplier/club/detail.vue

@@ -0,0 +1,299 @@
+<template>
+  <div class="club-edit">
+    <el-form ref="submitForm" class="club-edit-form" label-width="120px" :model="formData" :rules="rules">
+      <el-form-item label="机构名称:" prop="name">
+        <el-input v-model="formData.name" placeholder="请输入机构名称" disabled />
+      </el-form-item>
+      <el-form-item label="所在地区:" prop="address">
+        <el-cascader
+          ref="cascader"
+          v-model="formData.address"
+          disabled
+          :class="{ display: cascaderDisplay }"
+          clearable
+          :props="cascaderProps"
+          style="width: 100%"
+          :placeholder="cascaderPlaceholder"
+          @change="handleChange"
+        />
+      </el-form-item>
+      <el-form-item label="详细地址:" prop="fullAddress">
+        <el-input v-model="formData.fullAddress" placeholder="请输入详细地址" disabled />
+      </el-form-item>
+      <el-form-item label="经纬度:" prop="point">
+        <el-input v-model="formData.point" placeholder="请输入经纬度 (格式:纬度,经度,可通过右侧地图小按钮获取)" disabled>
+          <el-button slot="append" icon="el-icon-map-location" />
+        </el-input>
+      </el-form-item>
+      <el-form-item label="联系方式:" prop="mobile">
+        <el-input v-model="formData.mobile" placeholder="请输入联系方式" disabled />
+      </el-form-item>
+      <el-form-item label="机构logo:" prop="logoImage">
+        <el-input v-show="false" v-model="formData.logoImage" disabled />
+        <upload-image
+          tip="建议尺寸:242px * 242px"
+          :image-list="logoList"
+          :before-upload="beforeLogoUpload"
+          @success="uploadLogoSuccess"
+          @remove="handleLogoRemove"
+        />
+      </el-form-item>
+      <el-form-item label="轮播图:" prop="banner">
+        <el-input v-show="false" v-model="formData.banner" disabled />
+        <upload-image
+          tip="至少上传一张,最多6张;建议尺寸:542px * 542px"
+          :image-list="bannerList"
+          :before-upload="beforeBannerUpload"
+          :limit="1"
+          @success="uploadBannerSuccess"
+          @remove="handleBannerRemove"
+        />
+      </el-form-item>
+    </el-form>
+  </div>
+</template>
+
+<script>
+// import Location from '@/components/location'
+import AMapUI from '@/components/AMapUI'
+import UploadImage from '@/components/UploadImage'
+import { mapGetters } from 'vuex'
+import { saveBrandAuth, getAuthFormData } from '@/api/auth'
+import { getAddress } from '@/api/common'
+import { isPoint } from '@/utils/validate'
+
+export default {
+  components: {
+    // Location
+    [AMapUI.name]: AMapUI,
+    UploadImage
+  },
+  data() {
+    var validatePoint = (rule, value, callback) => {
+      if (value === '') {
+        callback(new Error('经纬度坐标不能为空'))
+      } else {
+        if (isPoint(value)) {
+          this.$refs.ruleForm.validateField('point')
+        } else {
+          callback('经纬度坐标格式不正确,(例如:114.095294,22.536004)')
+        }
+        callback()
+      }
+    }
+
+    return {
+      dialogMapVisible: false,
+      point: {},
+      value: [],
+      options: [],
+
+      authId: '',
+      disabled: false,
+
+      area: '',
+      formData: {
+        name: '',
+        address: [],
+        fullAddress: '',
+        point: '',
+        mobile: '',
+        logoImage: '',
+        banner: ''
+      },
+      rules: {
+        name: [{ required: true, message: '机构名称不能为空', trigger: ['blur', 'change'] }],
+        address: [{ required: true, message: '地址不能为空', trigger: 'change', type: 'array' }],
+        fullAddress: [{ required: true, message: '详细不能为空', trigger: ['blur', 'change'] }],
+        point: [{ validator: validatePoint, trigger: ['blur', 'change'] }],
+        mobile: [{ required: true, message: '联系方式不能为空', trigger: ['blur', 'change'] }],
+        logoImage: [{ required: true, message: '请上传机构logo', trigger: 'change' }],
+        banner: [{ required: true, message: '请至少上传一张banner图片', trigger: 'change' }]
+      },
+      // logo图片列表
+      logoList: [],
+      // banner图片列表
+      bannerList: [],
+      // 级联选择的地址
+      address: ''
+    }
+  },
+  computed: {
+    ...mapGetters(['authUserId', 'proxyInfo']),
+    // 级联选择器
+    cascaderProps() {
+      return {
+        lazy: true,
+        lazyLoad: async(node, resolve) => {
+          const { level, value = 0 } = node
+          const result = await getAddress({ parentId: value, type: level })
+          const nodes = result.data.map(item => ({ value: item.id, label: item.name, leaf: level >= 2 }))
+          resolve(nodes)
+        }
+      }
+    },
+    cascaderDisplay() {
+      return this.formData.address.length > 0
+    },
+    cascaderPlaceholder() {
+      return this.cascaderDisplay ? this.area : '请选择所在区域'
+    },
+    // 定位使用的地址
+    locationAddress() {
+      return this.address + this.formData.fullAddress
+    }
+  },
+  created() {
+    this.authId = this.$route.query.id
+    this.initFormData()
+  },
+  methods: {
+    // 获取地址
+    initAddress() {
+      return getAddress({
+        parentId: 19,
+        type: 1
+      })
+    },
+
+    // 地图标记变化
+    markerChange(point) {
+      this.formData.point = `${point.lng},${point.lat}`
+    },
+
+    // 数据回显
+    initFormData() {
+      getAuthFormData({ authId: this.authId }).then(res => {
+        console.log(res)
+        this.formData.name = res.data.authParty
+
+        this.formData.fullAddress = res.data.address
+        this.formData.point = res.data.lngAndLat
+        this.formData.mobile = res.data.mobile
+        this.formData.logoImage = res.data.logo
+        this.formData.banner = res.data.bannerList.length || ''
+
+        this.logoList = [{ name: '', url: res.data.logo }]
+        this.bannerList = res.data.bannerList.map(item => ({ name: '', url: item }))
+
+        this.formData.address = [res.data.provinceId, res.data.cityId, res.data.townId]
+        // this.formData.address = '广东省/深圳市/福田区'
+        this.area = res.data.area
+      })
+    },
+
+    // 表单提交保存
+    submit() {
+      this.$refs.submitForm.validate(valide => {
+        if (!valide) return
+
+        console.log(this.formData)
+        const {
+          name: authParty,
+          address: [provinceId, cityId, townId],
+          mobile,
+          logoImage: logo,
+          point: lngAndLat
+        } = this.formData
+
+        const authUserId = this.proxyInfo?.authUserId || this.authUserId
+
+        const data = {
+          authId: parseInt(this.authId),
+          authParty,
+          authUserId,
+          createBy: authUserId,
+          provinceId,
+          cityId,
+          townId,
+          address: this.formData.fullAddress,
+          mobile,
+          logo,
+          lngAndLat
+        }
+
+        data.bannerList = this.bannerList.map(item => item.response ? item.response.data : item.url)
+
+        console.log(data)
+        saveBrandAuth(data)
+          .then(res => {
+            const h = this.$createElement
+            this.$notify.success({
+              title: `修改授权机构`,
+              message: h('i', { style: 'color: #333' }, `已修改授权机构:"${this.formData.name}"`),
+              duration: 3000
+            })
+            this.$refs.submitForm.resetFields()
+            this.$store.dispatch('tagsView/delView', this.$route)
+            this.$router.push('/auth/list')
+          })
+          .catch(err => {
+            this.$message.danger(err.msg)
+          })
+      })
+    },
+    handleChange(e) {
+      const node = this.$refs.cascader.getCheckedNodes()
+      if (node.length <= 0) return
+      this.address = node[0].pathLabels.join()
+    },
+    // logo上传
+    uploadLogoSuccess({ response, file, fileList }) {
+      this.logoList = fileList
+      this.formData.logoImage = fileList[0].response.data
+    },
+    handleLogoRemove({ file, fileList }) {
+      this.logoList = fileList
+      this.formData.logoImage = ''
+    },
+    beforeLogoUpload(file) {
+      const flag = file.size / 1024 < 500
+      if (!flag) {
+        this.$message.error('上传logo图片大小不能超过 500kb!')
+      }
+      return flag
+    },
+
+    // banner上传
+    uploadBannerSuccess({ response, file, fileList }) {
+      this.bannerList = fileList
+      console.log(this.bannerList)
+      this.formData.banner = fileList.length > 0 ? fileList.length : ''
+    },
+    handleBannerRemove({ file, fileList }) {
+      this.bannerList = fileList
+      this.formData.banner = fileList.length > 0 ? fileList.length : ''
+    },
+    beforeBannerUpload(file) {
+      const flag = file.size / 1024 / 1024 < 1
+      if (!flag) {
+        this.$message.error('上传banner图片大小不能超过 1MB!')
+      }
+      return flag
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+#allmap {
+  width: 100%;
+  height: 600px;
+}
+
+.club-edit {
+  margin-bottom: 80px;
+}
+
+.club-edit-form {
+  width: 600px;
+  margin: 0 auto;
+  margin-top: 80px;
+}
+.submit-btn {
+  text-align: center;
+  .el-button {
+    width: 140px;
+  }
+}
+</style>

+ 273 - 0
src/views/admin/supplier/club/device/detail.vue

@@ -0,0 +1,273 @@
+<template>
+  <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="请输入设备名称" disabled />
+      </el-form-item>
+
+      <el-form-item label="设备SN码:" prop="snCode">
+        <el-input v-model="formData.snCode" placeholder="请输入设备SN码" disabled />
+      </el-form-item>
+
+      <el-form-item v-if="shopType === 2" label="所属品牌:" prop="brandId">
+        <el-select v-model="formData.brandId" placeholder="请选择品牌" style="width: 100%" filterable disabled>
+          <el-option v-for="item in brandList" :key="item.id" :label="item.name" :value="item.id" />
+        </el-select>
+      </el-form-item>
+
+      <el-form-item label="设备图片:" prop="productImage">
+        <upload-image ref="uploadImageRef2" :file-list="fileList1" disabled @success="imageUploadSuccess1" />
+        <el-input v-model="formData.productImage" class="hiddenInput" />
+      </el-form-item>
+      <el-form-item label="授权牌:" prop="certificateImage">
+        <upload-image ref="uploadImageRef2" :file-list="fileList2" disabled @success="imageUploadSuccess2" />
+        <el-input v-model="formData.certificateImage" class="hiddenInput" />
+      </el-form-item>
+      <el-form-item label="相关参数:" prop="paramList">
+        <div v-for="(item, index) in paramList" :key="index" class="form-group paramsItem">
+          <el-input v-model="item.paramName" class="param-title" placeholder="参数名称" maxlength="10" disabled />
+          <el-input v-model="item.paramContent" class="param-info" placeholder="请输入参数信息" maxlength="50" disabled />
+          <span v-if="paramsCount > 4" class="closed el-icon-close" @click="handleRemoveParam(index)" />
+        </div>
+        <!-- <el-button type="primary" size="mini" @click="handleAddParam">添加参数</el-button> -->
+      </el-form-item>
+      <!-- <el-form-item 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" @click="submit">保存</el-button>
+      <el-button type="warning" @click="$_back()">返回</el-button>
+    </div> -->
+  </div>
+</template>
+
+<script>
+import UploadImage from '../../components/uploadImage'
+import { saveProduct, getProductById } from '@/api/product'
+import { fetchBrandList } from '@/api/brand'
+import { mapGetters } from 'vuex'
+export default {
+  components: { UploadImage },
+  data() {
+    return {
+      isLoading: false,
+      paramsCount: 4,
+      formData: {
+        authUserId: '',
+        authId: '', //	授权id
+        certificateImage: '', //	授权牌照
+        createBy: '', //	创建人id
+        // 	设备参数列表
+        paramList: [],
+        productId: '', //	授权设备id
+        productImage: '', //	设备图片
+        productName: '', //	设备名称
+        snCode: '', //	设备SN码
+        brandId: ''
+      },
+      paramList: [],
+      brandList: [],
+      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', 'proxyInfo', 'shopType', 'brandId'])
+  },
+  watch: {
+    paramList: {
+      deep: true,
+      handler: function() {
+        this.formData.paramList = this.setParamToFormData()
+      }
+    }
+  },
+  created() {
+    this.formData.productId = parseInt(this.$route.query.id)
+    this.formData.authUserId = this.proxyInfo?.authUserId || this.authUserId
+    this.initFormData()
+    if (this.shopType === 2) {
+      this.getBrandList()
+    }
+    // 如果供应商类型为品牌方,则自动设置品牌id
+    if (this.shopType === 1) {
+      this.formData.brandId = this.proxyInfo?.brandId || this.brandId || ''
+    }
+  },
+  methods: {
+    // 提交
+    submit() {
+      this.formData.paramList = this.setParamToFormData()
+      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)) {
+            if (key !== 'paramList') {
+              this.formData[key] = res.data[key]
+            }
+          }
+        }
+        // 初始化参数
+        this.paramList = res.data.paramList
+        this.paramsCount = this.paramList.length
+        if (this.paramsCount < 4) {
+          this.initParamList(4 - this.paramsCount)
+        }
+        this.initImageList()
+        this.isLoading = false
+      })
+    },
+    // 获取品牌信息
+    getBrandList() {
+      fetchBrandList({ type: 3, authUserId: this.formData.authUserId }).then(res => {
+        console.log(res)
+        this.brandList = res.data
+      })
+    },
+    // 初始化上传图片列表
+    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.proxyInfo?.authUserId || this.authUserId
+      this.formData.authUserId = this.proxyInfo?.authUserId || this.authUserId
+      saveProduct(this.formData)
+        .then(res => {
+          if (res.code !== 0) return
+          const h = this.$createElement
+          this.$notify.success({
+            title: '修改设备',
+            message: h('i', { style: 'color: #333' }, `已修改设备:"${this.formData.productName}"`),
+            duration: 2000
+          })
+          this.$store.dispatch('tagsView/delView', this.$route)
+          this.$router.back()
+        })
+        .finally(() => {
+          this.isLoading = false
+        })
+    },
+    // 保存参数到formdata
+    setParamToFormData() {
+      return this.paramList.filter(item => item.paramContent !== '' && item.paramName !== '')
+    },
+    // 添加一栏参数
+    handleAddParam() {
+      this.paramsCount += 1
+      this.paramList.push({
+        paramContent: '',
+        paramName: ''
+      })
+    },
+    // 删除一栏参数
+    handleRemoveParam(index) {
+      this.paramsCount -= 1
+      this.paramList.splice(index, 1)
+    },
+    // 图片上传成功 产品图片
+    imageUploadSuccess1(data) {
+      this.formData.productImage = data.data
+    },
+    // 图片上传成功 授权牌照
+    imageUploadSuccess2(data) {
+      this.formData.certificateImage = data.data
+    },
+    setParamList(data) {
+      this.paramList = data.paramList
+    },
+    // 初始化参数列表
+    initParamList(count) {
+      for (let i = 0; i < count; i++) {
+        this.paramList.push({
+          paramContent: '',
+          paramName: ''
+        })
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.addProduct {
+  margin-bottom: 80px;
+  .form-group {
+    margin-bottom: 2%;
+    .param-title {
+      width: 30%;
+    }
+    .param-info {
+      width: 68%;
+      margin-left: 2%;
+    }
+  }
+}
+.addForm {
+  width: 500px;
+  margin: 0 auto;
+  margin-top: 80px;
+}
+.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>

+ 216 - 0
src/views/admin/supplier/club/device/index.vue

@@ -0,0 +1,216 @@
+<template>
+  <div class="app-container">
+    <div class="filter-container">
+      <span>设备名称:</span>
+      <el-input v-model="listQuery.productName" placeholder="商品名称" style="width: 200px;" class="filter-item" @keyup.enter.native="handleFilter" />
+      <span>设备SN码:</span>
+      <el-input v-model="listQuery.snCode" placeholder="商品SN码" style="width: 200px;" class="filter-item" @keyup.enter.native="handleFilter" />
+      <span>审核状态:</span>
+      <el-select
+        v-model="listQuery.auditStatus"
+        placeholder="审核状态"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="全部" value="" />
+        <el-option label="待审核" :value="2" />
+        <el-option label="审核通过" :value="1" />
+        <el-option label="审核未通过" :value="0" />
+      </el-select>
+      <span>上线状态:</span>
+      <el-select
+        v-model="listQuery.status"
+        placeholder="上线状态"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="全部" value="" />
+        <el-option label="已上线" :value="1" />
+        <el-option label="待上线" :value="2" />
+        <el-option label="未上线" :value="0" />
+      </el-select>
+      <el-button type="primary" icon="el-icon-search" @click="handleFilter">查询</el-button>
+    </div>
+    <!-- 表格区域 -->
+    <el-table
+      :key="tableKey"
+      v-loading="listLoading"
+      :data="list"
+      border
+      fit
+      highlight-current-row
+      style="width: 100%;"
+      header-row-class-name="tableHeader"
+    >
+      <el-table-column label="序号" :index="indexMethod" type="index" align="center" width="80" />
+      <el-table-column label="设备名称" align="center" prop="productName" />
+      <el-table-column label="设备SN码" align="center" prop="snCode" />
+
+      <el-table-column label="审核状态" width="220px" align="center">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.auditStatus === 2" size="small" type="warning">待审核</el-tag>
+          <el-tag v-if="row.auditStatus === 1" size="small" type="success">审核通过</el-tag>
+          <!-- 未通过原因展示 -->
+          <template v-if="row.auditStatus === 0">
+            <!-- <span class="status danger">审核未通过&nbsp;</span> -->
+            <el-popover
+              placement="top-start"
+              title="审核说明"
+              width="400"
+              trigger="hover"
+              :content="row.invalidReason"
+            >
+              <el-tag slot="reference" size="small" type="danger" class="reason">
+                <span>审核未通过</span>
+                <span class="el-icon-question status danger " />
+              </el-tag>
+            </el-popover>
+            <!-- 未通过原因展示END -->
+          </template>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="上线状态" width="140px" align="center">
+        <template slot-scope="{row}">
+          <!-- 只有审核通过了才能操作上下线 auditStatus :审核状态 -->
+          <template v-if="row.auditStatus === 1">
+            <template v-if="row.status === 0">
+              <span style="margin-right:10px;" class="status danger">已下线</span>
+              <el-button v-if="userIdentity===2 || proxyInfo !== null" type="primary" size="mini" @click="handleChangeStatus(row)">上线</el-button>
+            </template>
+            <template v-else>
+              <span style="margin-right:10px;" class="status success ">已上线</span>
+              <el-button v-if="userIdentity===2 || proxyInfo !== null" type="info" size="mini" plain @click="handleChangeStatus(row)">下线</el-button>
+            </template>
+          </template>
+          <template v-else>
+            <!-- <el-tag type="warning">待上线</el-tag> -->
+            <span style="margin-right:10px;" class="status warning">待上线</span>
+          </template>
+        </template>
+      </el-table-column>
+      <el-table-column label="创建时间" class-name="status-col" width="300px" align="center">
+        <template slot-scope="{row}">
+          <span>{{ row.createTime | formatTime }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" width="240px" class-name="small-padding fixed-width">
+        <template slot-scope="{row}">
+          <el-button type="primary" size="mini" @click="$_navigationTo(`auth-product-detail?id=${row.productId}`)">查看</el-button>
+          <el-button type="primary" size="mini" :disabled="row.auditStatus !== 1" @click="handleShowQRcode(row)">
+            二维码
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 页码 -->
+    <pagination v-show="total>0" :total="total" :page.sync="listQuery.pageNum" :limit.sync="listQuery.pageSize" @pagination="getList" />
+
+    <!-- 二维码 -->
+    <transition name="fade">
+      <qrcode v-if="showQRcode" :product-info="productInfo" @close="showQRcode = false" />
+    </transition>
+  </div>
+</template>
+
+<script>
+import { getProdList } 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, Qrcode },
+  filters: {
+    formatTime(time) {
+      if (!time) {
+        return ''
+      }
+      return formatDate(time, 'yyyy-MM-DD HH:mm:ss')
+    }
+  },
+
+  data() {
+    return {
+      authParty: '',
+      tableKey: 0,
+      list: null,
+      total: 0,
+      listLoading: true,
+      listQuery: {
+        status: '',
+        auditStatus: '',
+        authId: '',
+        productName: '',
+        snCode: '',
+        pageNum: 1,
+        pageSize: 10
+      },
+      showQRcode: false,
+      productInfo: {}
+    }
+  },
+  computed: {
+    ...mapGetters(['userIdentity', 'proxyInfo'])
+  },
+  created() {
+    this.listQuery.authId = this.$route.query.id
+    this.authParty = this.$route.query.authParty
+    this.getList()
+  },
+
+  methods: {
+    // 获取列表信息
+    getList() {
+      getProdList(this.listQuery).then(res => {
+        const { total, list } = res.data
+        this.total = total
+        this.list = list
+        // this.checkAuditFailedList(list)
+      }).finally(() => {
+        this.listLoading = false
+      })
+    },
+    // 过滤列表
+    handleFilter() {
+      this.listQuery.page = 1
+      this.getList()
+    },
+    // 显示二维码
+    handleShowQRcode(item) {
+      this.productInfo = item
+      this.productInfo.authParty = this.authParty
+      this.showQRcode = true
+    },
+    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;
+  }
+}
+</style>

+ 355 - 0
src/views/admin/supplier/club/index.vue

@@ -0,0 +1,355 @@
+<template>
+  <div class="app-container">
+    <div class="filter-container">
+      <span>机构名称:</span>
+      <el-input v-model="listQuery.authParty" placeholder="授权机构" style="width: 280px;" class="filter-item" @keyup.enter.native="handleFilter" />
+      <span>审核状态:</span>
+      <el-select
+        v-model="listQuery.auditStatus"
+        placeholder="审核状态"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="全部" value="" />
+        <el-option label="待审核" :value="2" />
+        <el-option label="审核通过" :value="1" />
+        <el-option label="审核未通过" :value="0" />
+      </el-select>
+      <span>上线状态:</span>
+      <el-select
+        v-model="listQuery.status"
+        placeholder="上线状态"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="全部" value="" />
+        <el-option label="已上线" :value="1" />
+        <el-option label="待上线" :value="2" />
+        <el-option label="未上线" :value="0" />
+      </el-select>
+      <el-button icon="el-icon-search" type="primary" @click="getList">查询</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
+      :key="tableKey"
+      v-loading="listLoading"
+      :data="list"
+      border
+      fit
+      highlight-current-row
+      style="width: 100%;"
+      header-row-class-name="tableHeader"
+    >
+      <el-table-column label="序号" :index="indexMethod" align="center" width="80" type="index" />
+
+      <el-table-column label="机构名称" align="center" prop="authParty" />
+
+      <el-table-column label="审核状态" width="220px" align="center">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.auditStatus === 2" size="small" type="warning">待审核</el-tag>
+          <el-tag v-if="row.auditStatus === 1" size="small" type="success">审核通过</el-tag>
+          <!-- 未通过原因展示 -->
+          <template v-if="row.auditStatus === 0">
+            <!-- <span class="status danger">审核未通过&nbsp;</span> -->
+            <el-popover
+              placement="top-start"
+              title="审核说明"
+              width="400"
+              trigger="hover"
+              :content="row.invalidReason"
+            >
+              <el-tag slot="reference" size="small" type="danger" class="reason">
+                <span>审核未通过</span>
+                <span class="el-icon-question status danger " />
+              </el-tag>
+            </el-popover>
+            <!-- 未通过原因展示END -->
+          </template>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="上线状态" width="140px" align="center">
+        <template slot-scope="{row}">
+          <!-- 只有审核通过了才能操作上下线 auditStatus :审核状态 -->
+          <template v-if="row.auditStatus === 1">
+            <template v-if="row.status === 0">
+              <span style="margin-right:10px;" class="status danger">已下线</span>
+            </template>
+            <template v-else>
+              <span style="margin-right:10px;" class="status success ">已上线</span>
+            </template>
+          </template>
+          <template v-else>
+            <!-- <el-tag type="warning">待上线</el-tag> -->
+            <span style="margin-right:10px;" class="status warning">待上线</span>
+          </template>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="创建时间" class-name="status-col" width="360px">
+        <template slot-scope="{row}">
+          <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" class-name="small-padding fixed-width">
+        <template slot-scope="{row}">
+          <el-button type="primary" size="mini" @click="$_navigationTo(`/supplier/auth-detail?id=${row.authId}&authParty=${row.authParty}`)">
+            查看
+          </el-button>
+          <el-button type="primary" size="mini" @click="$_navigationTo(`/supplier/auth-product-list?id=${row.authId}&authParty=${row.authParty}`)">
+            查看设备认证
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 页码 -->
+    <pagination v-show="total>0" :total="total" :page.sync="listQuery.pageNum" :limit.sync="listQuery.pageSize" @pagination="getList" />
+
+    <!-- 导入对话框 -->
+    <!-- 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 FileUpload from '@/components/FileUpload'
+import { fecthAuthList, 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, FileUpload },
+  filters: {
+    formatTime(time) {
+      if (!time) {
+        return ''
+      }
+      return formatDate(time, 'yyyy-MM-DD HH:mm:ss')
+    }
+  },
+  data() {
+    return {
+      tableKey: 0,
+      list: null,
+      total: 0,
+      listLoading: true,
+      // 查询参数
+      listQuery: {
+        authParty: '', // 授权机构
+        authUserId: '', // 供应商用户id
+        pageNum: 1, // 页码
+        pageSize: 10, // 分页
+        status: ''
+      },
+      disabled: false,
+
+      // ------------------
+      improtDialogVisible: false,
+      requestLoading: false,
+      uploadFileList: [],
+      improtDialogFormData: {
+        fileUrl: ''
+      },
+      improtDialogFormRules: {
+        fileUrl: [
+          {
+            required: true,
+            message: '请选择文件', trigger: 'change'
+          }
+        ]
+      },
+      chooseFile: ''
+    }
+  },
+  computed: {
+    ...mapGetters(['authUserId', 'userIdentity', 'proxyInfo', 'copyUserInfo']),
+    saveBtnClickable() {
+      return this.uploadFileList.length > 0
+    }
+  },
+  created() {
+    this.listQuery.authUserId = this.$route.query.id || this.proxyInfo?.authUserId || this.authUserId
+    const type = this.$route.query.type
+    // 如果是通过路由参数传递的type,则需要同步到store
+    if (type) {
+      this.$store.commit('user/SET_SHOP_TYPE', parseInt(type))
+    }
+    this.getList()
+  },
+  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
+      fecthAuthList(this.listQuery).then(response => {
+        if (response.code !== 0) {
+          return this.$message.error('授权列表信息获取失败')
+        }
+        const { list, total } = response.data
+        this.list = list
+        this.total = total
+      }).catch(err => {
+        console.log(err)
+        return this.$message.error('授权列表信息获取失败')
+      }).finally(() => {
+        this.listLoading = false
+      })
+    },
+    // 格式化列表数据
+    formatList(list = []) {
+      list.forEach(i => {
+        i.status = i.status === 1
+      })
+    },
+    // 过滤列表
+    handleFilter() {
+      this.listQuery.page = 1
+      this.getList()
+    },
+
+    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;
+  }
+}
+</style>

+ 729 - 0
src/views/admin/supplier/edit.vue

@@ -0,0 +1,729 @@
+<template>
+  <div v-loading="isLoading" class="addSupplier">
+    <el-form ref="formData1Ref" :model="formData1" :rules="formDataRules" label-width="120px" class="addForm">
+      <el-form-item label="供应商类型:" prop="shopType">
+        <el-select
+          v-model="formData1.shopType"
+          placeholder="请选择供应商类型"
+          style="width: 100%"
+          @change="handleTypeChange"
+        >
+          <el-option label="品牌方" :value="1" />
+          <el-option label="代理商" :value="2" />
+        </el-select>
+      </el-form-item>
+
+      <!-- 供应商名称 -->
+      <el-form-item v-if="formData1.shopType === 2" label="供应商名称:" prop="shopName">
+        <el-input v-model="formData1.shopName" placeholder="请输入供应商名称" maxlength="50" show-word-limit />
+      </el-form-item>
+
+      <el-form-item v-if="formData1.shopType === 1" clearable label="供应商名称:" prop="brandId">
+        <el-select
+          v-model="formData1.brandId"
+          placeholder="请选择品牌"
+          style="width: 100%"
+          filterable
+          @change="handleBrandChange"
+        >
+          <el-option v-for="item in brandList" :key="item.id" :label="item.name" :value="item.id" />
+        </el-select>
+      </el-form-item>
+      <!-- 供应商名称END -->
+
+      <el-form-item label="手机号:" prop="mobile">
+        <el-input v-model="formData1.mobile" placeholder="请输入手机号" maxlength="11" show-word-limit @input="handleInput" />
+      </el-form-item>
+
+      <el-form-item label="联系人:" prop="linkMan">
+        <el-input v-model="formData1.linkMan" placeholder="请输入联系人" />
+      </el-form-item>
+
+      <!-- 代理商logo -->
+      <transition name="fade">
+        <el-form-item v-if="formData1.shopType === 2" label="代理商logo:" prop="logo">
+          <el-input v-show="false" v-model="formData1.logo" />
+          <upload-image-t
+            tip="建议尺寸:200px * 200px"
+            :image-list="logoList"
+            :before-upload="beforeLogoImageUpload"
+            @success="uploadLogoImageSuccess"
+            @remove="handleLogoImageRemove"
+          />
+        </el-form-item>
+      </transition>
+      <transition name="fade">
+        <el-form-item v-if="formData1.shopType === 2" label="代理品牌:" prop="shopInfo" class="brand-list">
+          <template v-if="supplierBrands !== []">
+            <el-tag v-for="(brand , index) in supplierBrands" :key="index" closable type="success" @close="handleRemove(index)" @click="handleShowInfo(index)">{{ brand.brandName }}</el-tag>
+          </template>
+          <el-tag type="primary" @click="handleShowDialog">添加品牌<span class="el-icon-plus" /></el-tag>
+          <!-- <el-input v-model="formData1.shopInfo" class="hiddenInput" /> -->
+        </el-form-item>
+      </transition>
+
+      <template v-if="formData1.shopType === 1">
+        <el-form-item label="产地:" prop="countryId">
+          <el-select v-model="formData1.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
+            ref="uploadImageRef1"
+            :file-list="fileList1"
+            @success="imageUploadSuccess1"
+            @error="imageUploadFaild1"
+            @remove="imageRemove1"
+          />
+          <el-input v-model="formData1.brandAuthLogo" type="hidden" class="hiddenInput" />
+        </el-form-item>
+
+        <el-form-item label="官网认证链接:">
+          <el-input v-model="formData1.securityLink" placeholder="请输入官网认证链接" />
+        </el-form-item>
+      </template>
+
+      <!-- 公众号信息 -->
+      <el-form-item label="微信公众号:">
+        <el-select v-model="formData1.wxAccountType" placeholder="请选择微信公众号类型" style="width: 100%">
+          <el-option label="服务号" :value="2" />
+          <el-option label="订阅号" :value="1" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="appID:">
+        <el-input v-model="formData1.appId" placeholder="微信公众号appID,没有就不填" />
+      </el-form-item>
+      <el-form-item label="appSecret:">
+        <el-input v-model="formData1.appSecret" placeholder="微信公众号appsecret,没有就不填" />
+      </el-form-item>
+      <el-form-item label="公众号二维码:" prop="qrCodeImage">
+        <upload-image
+          ref="uploadImageRef1"
+          :file-list="ewmUrl"
+          tip-title="128px*128px"
+          @success="wxImageUploadSuccess"
+          @error="wxImageUploadFaild"
+          @remove="wxImageUploadRemove"
+        />
+        <el-input v-model="formData1.qrCodeImage" type="hidden" class="hiddenInput" />
+      </el-form-item>
+      <!-- 公众号信息END -->
+      <el-form-item label="供应商状态:">
+        <el-select v-model="formData1.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" @click="submit">保存</el-button>
+      <el-button type="warning" @click="$_back()">返回</el-button>
+    </div>
+
+    <!-- 供应商添加品牌的对话框 -->
+    <el-dialog :title="dialogTitleText" :visible.sync="showDialog" width="width" @closed="dialogClosed">
+      <el-form ref="formData2Ref" :model="formData2" label-width="120px" :rules="formDataRules">
+
+        <el-form-item label="选择品牌:" prop="brandId">
+          <el-select
+            v-model="formData2.brandId"
+            placeholder="请选择品牌"
+            style="width: 100%"
+            filterable
+            @change="handleBrandChange"
+          >
+            <el-option v-for="item in brandListCopy" :key="item.id" :label="item.name" :value="item.id" />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="产地:" prop="countryId">
+          <el-select v-model="formData2.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
+            ref="uploadImageRef2"
+            :file-list="fileList2"
+            @success="imageUploadSuccess2"
+            @error="imageUploadFaild2"
+            @remove="imageRemove2"
+          />
+          <el-input v-model="formData2.brandAuthLogo" type="hidden" class="hiddenInput" />
+        </el-form-item>
+
+        <el-form-item label="代理声明:">
+          <el-radio-group v-model="formData2.statementType" @change="handleStatementChange">
+            <el-radio :label="1">弹窗</el-radio>
+            <el-radio :label="2">链接</el-radio>
+            <el-radio :label="3">图片</el-radio>
+            <el-radio :label="4">文件</el-radio>
+          </el-radio-group>
+        </el-form-item>
+
+        <el-form-item v-if="formData2.statementType === 1" ref="statement1" label="弹窗:" prop="statementContent">
+          <el-input
+            v-if="formData2.statementType === 1"
+            v-model="formData2.statementContent"
+            type="textarea"
+          />
+        </el-form-item>
+
+        <el-form-item v-else-if="formData2.statementType === 2" ref="statement2" label="链接:" prop="statementLink">
+          <el-input v-if="formData2.statementType === 2" v-model="formData2.statementLink" />
+        </el-form-item>
+
+        <el-form-item
+          v-else-if="formData2.statementType === 3"
+          ref="statement3"
+          label="图片:"
+          class="no-input"
+          prop="statementImage"
+        >
+          <upload-image
+            v-if="formData2.statementType === 3"
+            ref="uploadImageRef3"
+            :file-list="fileList3"
+            tip-title="宽:760px"
+            @success="imageUploadSuccess3"
+            @error="imageUploadFaild3"
+            @remove="imageRemove3"
+          />
+          <el-input v-model="formData2.statementImage" type="hidden" class="hiddenInput" />
+        </el-form-item>
+
+        <el-form-item v-else ref="statementFileRef" label="文件:" prop="statementFileId">
+          <upload-file
+            v-if="formData2.statementType === 4"
+            ref="uploadFileRef"
+            :auth-user-id="formData2.authUserId"
+            :brand-id="formData2.brandId"
+            :file-list="fileList4"
+            @success="fileUploadSuccess"
+            @error="fileUploadFaild"
+            @remove="fileRemove"
+            @change="fileChange"
+          />
+          <el-input v-model="formData2.statementFileId" type="hidden" class="hiddenInput" />
+        </el-form-item>
+
+        <el-form-item label="官网认证链接:">
+          <el-input v-model="formData2.securityLink" placeholder="请输入官网认证链接" />
+        </el-form-item>
+
+      </el-form>
+
+      <div slot="footer">
+        <el-button @click="showDialog = false">取 消</el-button>
+        <el-button type="primary" :loading="dialogLoading" @click="handleAddBrand">确 定</el-button>
+      </div>
+    </el-dialog>
+
+  </div>
+</template>
+
+<script>
+import UploadImage from '../components/uploadImage'
+import UploadFile from '../components/uploadFile'
+import UploadImageT from '@/components/UploadImage'
+import { mapGetters } from 'vuex'
+import { isMobile } from '@/utils/validate'
+import { fetchBrandList } from '@/api/brand'
+import { addSupplier } from '@/api/supplier'
+
+export default {
+  components: { UploadImage, UploadFile, UploadImageT },
+  data() {
+    const validMobile = (rule, value, callback) => {
+      if (!isMobile(value)) {
+        return callback(new Error('手机号格式不正确'))
+      }
+      return callback()
+    }
+    return {
+      isCheckout: true,
+      isLoading: false,
+      dialogLoading: false,
+      showDialog: false,
+      excludeBrandList: [], // 已经选择的品牌,需要被排除在外的
+      selectedShopType: 1,
+      currentIndex: '',
+      prevBrandId: '',
+      dialogTitle: '添加',
+      // 表单1
+      formData1: {
+        shopType: 1, // 供应商类型
+        shopName: '', // 供应商名称
+        brandId: '', // 品牌id
+        mobile: '', // 手机号
+        linkMan: '', // 联系人
+        countryId: 1, // 产地id
+        brandAuthLogo: '', // 品牌logo
+        securityLink: '', // 官网认证链接
+        shopStatus: 1, // 供应商状态,
+        shopInfo: '',
+        wxAccountType: 2,
+        appId: '',
+        appSecret: '',
+        qrCodeImage: '', // 微信公众号二维码
+        logo: '' // 代理商logo
+      },
+      // 表单2
+      formData2: {
+        index: '',
+        isNew: true,
+        brandName: '',
+        brandId: '', // 品牌id
+        countryId: 1, // 产地id
+        brandAuthLogo: '', // 品牌logo
+        securityLink: '', // 官网认证链接
+        statementType: 1, // 代理声明类型
+        statementContent: '', // 声明内容
+        statementFileId: null, // 声明文件id
+        statementImage: '', // 声明图片
+        statementLink: '', // 声明链接
+        statementFileName: '' // 上传图片的名称
+      },
+      supplierBrands: [],
+      brandList: [],
+      // 表单数据校验
+      formDataRules: {
+        shopType: { required: true, message: '供应商类型不能为空', tigger: 'change', type: 'number' },
+        shopName: { required: true, message: '供应名称不能为空', tigger: 'change' },
+        mobile: [{ required: true, message: '手机号不能为空', tigger: 'change' }, { validator: validMobile, tigger: 'change' }],
+        linkMan: { required: true, message: '联系人不能为空', tigger: 'blur' },
+        countryId: { required: true, message: '产地不能为空', tigger: 'change', type: 'number' },
+        brandAuthLogo: { required: true, message: '品牌logo不能为空', tigger: 'change' },
+        shopInfo: { required: true, message: '代理品牌不能为空', tigger: 'change', type: 'string' },
+        brandId: { required: true, message: '品牌不能为空', tigger: 'change', type: 'number' },
+        statementContent: { required: true, message: '声明内容不能为空', tigger: 'change' }, // 声明内容
+        statementFileId: { required: true, message: '声明文件不能为空', tigger: 'change', type: 'number' }, // 声明文件id
+        statementImage: { required: true, message: '声明图片不能为空', tigger: 'change' }, // 声明图片
+        statementLink: { required: true, message: '声明链接不能为空', tigger: 'change' }, // 声明链接,
+        logo: { required: true, message: '代理商logo不能为空', tigger: 'change' }
+        // ewmUrl: { required: true, message: '微信公众号二维码不能为空', tigger: 'change' }
+      },
+      // 上传的文件列表
+      fileList1: [],
+      fileList2: [],
+      fileList3: [],
+      fileList4: [], // 文件
+      logoList: [],
+      ewmUrl: []
+    }
+  },
+  computed: {
+    ...mapGetters(['countryList', 'authUserId']),
+    brandListCopy() {
+      return this.brandList.filter(item => {
+        return !this.excludeBrandList.includes(item.id)
+      })
+    },
+    dialogTitleText() {
+      return `${this.dialogTitle}代理品牌`
+    }
+  },
+  watch: {
+    supplierBrands() {
+      if (this.supplierBrands.length > 0) {
+        this.formData1.shopInfo = '1'
+      } else {
+        this.formData1.shopInfo = ''
+      }
+    }
+  },
+  created() {
+    this.getBrandList(1)
+  },
+  methods: {
+    // 提交保存
+    submit() {
+      this.$refs.formData1Ref.validate(valid => {
+        if (!valid) return
+        this.isLoading = true
+        addSupplier(this.setAddParams()).then(res => {
+          if (res.code !== 0) {
+            return
+          }
+          const h = this.$createElement
+          this.$notify.success({
+            title: '添加供应商',
+            message: h('i', { style: 'color: #333' }, `已添加供应商:"${this.formData1.shopName}"`),
+            duration: 3000
+          })
+          this.$store.dispatch('tagsView/delView', this.$route)
+          this.$router.push('/supplier')
+        }).finally(() => {
+          this.isLoading = false
+        })
+      })
+    },
+    // 封装请求参数
+    setAddParams() {
+      // 品牌方的参数列表
+      const result = {
+        authUserId: '',
+        createBy: '',
+        linkMan: '',
+        mobile: '',
+        shopName: '',
+        shopStatus: '',
+        shopType: '',
+        shopInfo: [],
+        qrCodeImage: '',
+        appId: '',
+        appSecret: '',
+        wxAccountType: ''
+      }
+      // 品牌方
+      if (this.selectedShopType === 1) {
+        for (const key in result) {
+          if (Object.hasOwnProperty.call(result, key)) {
+            if (key !== 'shopInfo') {
+              result[key] = this.formData1[key]
+            }
+          }
+        }
+        result.shopInfo.push({
+          brandId: this.formData1.brandId,
+          countryId: this.formData1.countryId,
+          brandAuthLogo: this.formData1.brandAuthLogo,
+          securityLink: this.formData1.securityLink,
+          statementType: 1,
+          statementContent: '',
+          statementFileId: null,
+          statementImage: '',
+          statementLink: ''
+        })
+      }
+
+      // 代理商
+      if (this.selectedShopType === 2) {
+        for (const key in result) {
+          if (Object.hasOwnProperty.call(result, key)) {
+            if (key !== 'shopInfo') {
+              result[key] = this.formData1[key]
+            }
+          }
+        }
+        result.shopInfo = this.supplierBrands
+        result.logo = this.formData1.logo
+      }
+      result.createBy = this.authUserId
+      console.log(result)
+      return result
+    },
+
+    // 获取品牌列表
+    getBrandList(type) {
+      fetchBrandList({ type }).then(res => {
+        if (res.code !== 0) {
+          return
+        }
+        this.brandList = res.data
+      })
+    },
+    // 品牌改变事件
+    handleBrandChange(id) {
+      const selectBrand = this.brandList.filter(item => item.id === id)[0]
+      // 选择品牌方
+      if (this.formData1.shopType === 1) {
+        this.fileList1 = []
+        this.formData1.shopName = selectBrand.name
+        this.formData1.brandAuthLogo = selectBrand.authLogo
+        this.formData1.brandId = selectBrand.id
+        if (selectBrand.authLogo) {
+          this.fileList1 = [{ name: selectBrand.name, url: selectBrand.authLogo }]
+        }
+      }
+      // 如果选择代理应商
+      if (this.formData1.shopType === 2) {
+        this.formData2.brandAuthLogo = selectBrand.authLogo
+        this.formData2.brandName = selectBrand.name
+        this.formData2.brandId = selectBrand.id
+        if (selectBrand.authLogo) {
+          this.fileList2 = [{ name: selectBrand.name, url: selectBrand.authLogo }]
+        }
+      }
+    },
+    // 添加品牌对话框
+    handleShowDialog() {
+      this.dialogTitle = '新增'
+      this.showDialog = true
+      this.resetFormData2()
+    },
+    // 添加品牌
+    handleAddBrand() {
+      this.dialogLoading = true
+      // 如果声明类型为4,并且文件id为空或null,则需要先上传文件再保存
+      if (this.formData2.statementType === 4 && (this.formData2.statementFileId === '' || this.formData2.statementFileId === null)) {
+        this.$refs.uploadFileRef.$refs.upload.submit()
+      } else {
+        this.saveShopInfo()
+      }
+    },
+    saveShopInfo() {
+      this.dialogLoading = false
+      this.$refs.formData2Ref.validate(valid => {
+        if (!valid) {
+          return
+        }
+        // 如果是新增的
+        const shopInfo = this.clone(this.formData2)
+        if (shopInfo.isNew) {
+          this.supplierBrands.push(shopInfo)
+        } else {
+        // 修改的
+          this.supplierBrands.splice(this.currentIndex, 1, shopInfo)
+        }
+        this.addExcludeBrand(shopInfo.brandId)
+        shopInfo.isNew = false
+        this.prevBrandId = ''
+        this.showDialog = false
+        const h = this.$createElement
+        this.$notify.success({
+          title: `${this.dialogTitle}品牌`,
+          message: h('i', { style: 'color: #333' }, `${this.dialogTitle}品牌:"${shopInfo.brandName}"`),
+          duration: 2000
+        })
+      })
+    },
+    // 移除品牌
+    handleRemove(index) {
+      const pop = this.supplierBrands.splice(index, 1)[0]
+      this.removeExcludeBrand(pop.brandId)
+      const h = this.$createElement
+      this.$notify.success({
+        title: '移除品牌',
+        message: h('i', { style: 'color: #333' }, `已移除品牌:"${pop.brandName}"`),
+        duration: 2000
+      })
+    },
+    // 修改品牌
+    handleShowInfo(index) {
+      this.dialogTitle = '修改'
+      this.currentIndex = index
+      this.formData2 = this.clone(this.supplierBrands[index])
+      this.prevBrandId = this.supplierBrands[index].brandId // 保存当前的品牌id
+      this.fileList2 = [{ name: '', url: this.formData2.brandAuthLogo }]
+      this.fileList3 = [{ name: '', url: this.formData2.statementImage }]
+      this.fileList4 = [{ name: this.formData2.statementFileName, url: '' }]
+      this.removeExcludeBrand(this.supplierBrands[index].brandId)
+      this.showDialog = true
+    },
+    // 添加品牌对话框关闭
+    dialogClosed() {
+      if (this.prevBrandId) {
+        this.addExcludeBrand(this.prevBrandId)
+        this.prevBrandId = ''
+      }
+      this.resetFormData2()
+    },
+    // 声明类型切换
+    handleStatementChange() {},
+    // 供应商类型改变事件
+    handleTypeChange(shopType) {
+      this.selectedShopType = shopType
+      this.getBrandList(shopType)
+      this.resetFormData1(shopType)
+    },
+    // 添加排除品牌
+    addExcludeBrand(id) {
+      this.excludeBrandList.push(id)
+    },
+    // 移除排除品牌
+    removeExcludeBrand(id) {
+      const index = this.excludeBrandList.indexOf(id)
+      this.excludeBrandList.splice(index, 1)
+    },
+    // 输入框输入时
+    handleInput() {
+      this.formData1.mobile = this.formData1.mobile.replace(/[^\w\.\/]/ig, '')
+    },
+
+    // 文件上传成功
+    fileUploadSuccess(data) {
+      this.formData2.statementFileName = data.data.fileName
+      this.formData2.statementFileId = data.data.fileId
+      if (data.code === 0) {
+        this.saveShopInfo()
+      }
+    },
+    fileUploadFaild(err, file, fileList) {
+      this.$message.error('文件上传失败')
+      console.log(err)
+    },
+    fileRemove() {
+      this.formData2.statementFileId = null
+      console.log('删除文件')
+    },
+    fileChange() {
+      console.log('文件改变')
+      this.$refs.statementFileRef.clearValidate()
+    },
+
+    // 图片上传成功 品牌logo  1
+    imageUploadSuccess1(data) {
+      this.formData1.brandAuthLogo = data.data
+    },
+    imageUploadFaild1(err, file, fileList) {
+      this.$message.error('图片上传失败')
+      console.log(err)
+    },
+    imageRemove1() {
+      this.formData1.brandAuthLogo = ''
+      console.log('删除图片')
+    },
+    // 图片上传成功 品牌logo 2
+    imageUploadSuccess2(data) {
+      this.formData2.brandAuthLogo = data.data
+    },
+    imageUploadFaild2(err, file, fileList) {
+      this.$message.error('图片上传失败')
+      console.log(err)
+    },
+    imageRemove2() {
+      this.formData2.brandAuthLogo = ''
+      console.log('删除图片')
+    },
+    // 图片上传成功 声明图片  3
+    imageUploadSuccess3(data) {
+      this.formData2.statementImage = data.data
+    },
+    imageUploadFaild3(err, file, fileList) {
+      this.$message.error('图片上传失败')
+      console.log(err)
+    },
+    imageRemove3() {
+      this.formData2.statementImage = ''
+      console.log('删除图片')
+    },
+    // 微信二维码上传
+    wxImageUploadSuccess(data) {
+      this.formData1.qrCodeImage = data.data
+    },
+    wxImageUploadFaild(err) {
+      this.$message.error('图片上传失败')
+      console.log(err)
+    },
+    wxImageUploadRemove() {
+      this.formData1.qrCodeImage = ''
+    },
+
+    // 代理商logo上传
+    beforeLogoImageUpload(file) {
+      const flag = file.size / 1024 / 1024 < 1
+      if (!flag) {
+        this.$message.error('上传医师照片大小不能超过 1MB!')
+      }
+      return flag
+    },
+    uploadLogoImageSuccess({ response, file, fileList }) {
+      this.logoList = fileList
+      this.formData1.logo = response.data
+    },
+    handleLogoImageRemove({ file, fileList }) {
+      this.logoList = fileList
+      this.formData1.logo = ''
+    },
+
+    // 重置表单1
+    resetFormData1(shopType) {
+      this.formData1 = {
+        shopType: shopType, // 供应商类型
+        shopName: '', // 供应商名称
+        brandId: '', // 品牌id
+        mobile: '', // 手机号
+        linkMan: '', // 联系人
+        countryId: '', // 产地id
+        brandAuthLogo: '', // 品牌logo
+        securityLink: '', // 官网认证链接
+        shopStatus: 1, // 供应商状态,
+        shopInfo: [],
+        qrCodeImage: '',
+        logo: ''
+      }
+      this.fileList1 = []
+      this.fileList2 = []
+      this.fileList3 = []
+      this.fileList4 = []
+      this.ewmUrl = []
+      this.$refs.formData1Ref.clearValidate()
+    },
+    // 重置表单2
+    resetFormData2() {
+      this.formData2 = {
+        index: '',
+        isNew: true,
+        brandName: '',
+        brandId: '', // 品牌id
+        countryId: 1, // 产地id
+        brandAuthLogo: '', // 品牌logo
+        securityLink: '', // 官网认证链接
+        statementType: 1, // 代理声明类型
+        statementContent: '', // 声明内容
+        statementFileId: null, // 声明文件id
+        statementImage: '', // 声明图片
+        statementLink: '', // 声明链接
+        statementFileName: ''
+      }
+      this.fileList1 = []
+      this.fileList2 = []
+      this.fileList3 = []
+      this.fileList4 = []
+      setTimeout(() => {
+        this.$refs.formData2Ref.clearValidate()
+      }, 200)
+    },
+    // 克隆
+    clone(data) {
+      const result = {}
+      for (const key in data) {
+        if (Object.hasOwnProperty.call(data, key)) {
+          result[key] = data[key]
+        }
+      }
+      return result
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.addSupplier {
+    margin-bottom: 80px;
+}
+.addForm {
+    width: 500px;
+    margin: 0 auto;
+    margin-top: 80px;
+    .brand-list{
+      .el-tag{
+        margin-right: 5px;
+        cursor: pointer;
+      }
+    }
+}
+.submit-btn {
+    text-align: center;
+    .el-button {
+        width: 140px;
+    }
+}
+.hiddenInput {
+    display: none;
+}
+</style>

+ 254 - 0
src/views/admin/supplier/index.vue

@@ -0,0 +1,254 @@
+<template>
+  <div class="app-container">
+    <div class="filter-container">
+      <span>供应商名称:</span>
+      <el-input v-model="listQuery.shopName" placeholder="供应商名称" style="width: 200px;" class="filter-item" @keyup.enter.native="handleFilter" />
+      <span>供应商类型:</span>
+      <el-select v-model="listQuery.shopType" placeholder="供应商类型" clearable style="width: 200px" class="filter-item" @change="getList()">
+        <el-option label="所有类型" value="" />
+        <el-option label="代理商" :value="2" />
+        <el-option label="品牌方" :value="1" />
+      </el-select>
+      <span>所属品牌:</span>
+      <el-select v-model="listQuery.brandId" placeholder="所属品牌" clearable class="filter-item" style="width: 200px" filterable @change="getList()">
+        <el-option label="所有品牌" value="" />
+        <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" icon="el-icon-search" @click="getList(listQuery)">查询</el-button>
+      <el-button type="primary" icon="el-icon-edit" @click="$_navigationTo('add')">添加供应商</el-button>
+    </div>
+    <!-- 表格区域 -->
+    <el-table
+      :key="tableKey"
+      v-loading="listLoading"
+      :data="list"
+      border
+      fit
+      highlight-current-row
+      style="width: 100%;"
+      header-row-class-name="tableHeader"
+    >
+      <el-table-column label="序号" :index="indexMethod" 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 v-slot="{row}">
+          <span v-if="row.shopType === 1">品牌方</span>
+          <span v-if="row.shopType === 2">代理商</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="手机号" width="120px" align="center" prop="mobile" />
+      <el-table-column label="联系人" width="100px" align="center" prop="linkMan" />
+      <el-table-column label="供应商状态" align="center" width="140px">
+        <template v-slot="{row}">
+          <el-switch v-model="row.shopStatus" @change="handleChangeStatus(row)" />
+        </template>
+      </el-table-column>
+      <el-table-column label="创建时间" class-name="status-col" width="200px">
+        <template slot-scope="{row}">
+          <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 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(row)">
+            代他操作
+          </el-button>
+          <el-button size="mini" type="primary" @click="$_navigationTo(`/supplier/auth-list?id=${row.authUserId}`)">
+            查看机构认证
+          </el-button>
+          <el-button size="mini" type="primary" @click="handleResetPwd(row)">
+            重置密码
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 页码 -->
+    <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, 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')
+    }
+  },
+  // mixins: [scrollTo],
+  data() {
+    return {
+      slider: 1,
+      listLoading: true,
+      tableKey: '',
+      total: 0, // 条数统计
+      listQuery: {
+        brandId: '', // 品牌id
+        linkMan: '', // 联系人
+        mobile: '', // 手机号
+        pageNum: 0, // 页码
+        pageSize: 10, // 分页大小
+        shopName: '', // 供应商名称
+        shopType: ''// 供应商类型
+      },
+      list: [],
+      brandList: [], // 品牌列表
+      prevData: ''
+    }
+  },
+  created() {
+    this.getList()
+    this.getBrandList()
+  },
+  methods: {
+    // 获取列表数据
+    getList() {
+      this.listLoading = true
+      fetchSupplierList(this.listQuery).then(res => {
+        if (res.code !== 0) {
+          return this.$message.error('获取数据失败~')
+        }
+        const { total, list } = res.data
+        this.total = total
+        this.formatList(list)
+        this.list = list
+        console.log(this.list)
+      }).catch(err => { console.log(err) }).finally(() => {
+        this.listLoading = false
+      })
+    },
+    // 格式化数组
+    formatList(list = []) {
+      list.forEach(i => {
+        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 = {
+        status: item.shopStatus ? 1 : 0,
+        authUserId: item.authUserId
+      }
+      supplierStatusChange(params)
+        .then(res => {
+          if (res.code === 0) {
+            this.getList()
+            this.$message({
+              message: '操作成功',
+              duration: 500,
+              type: 'success'
+            })
+          }
+        }).catch(() => {
+          this.getList()
+          this.$message({
+            message: '操作失败',
+            duration: 500,
+            type: 'danger'
+          })
+        })
+    },
+    // 重置密码
+    async handleResetPwd(item) {
+      const text = await this.$confirm('此操作将重置该供应商的密码, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).catch(() => {
+        this.$message.info('已取消操作')
+      })
+      if (text !== 'confirm') return
+      // 要执行的操作
+      resetPassword({ authUserId: item.authUserId }).then(res => {
+        if (res.code !== 0) return
+        const h = this.$createElement
+        this.$notify.success({
+          title: '重置密码',
+          message: h('i', { style: 'color: #333' }, `已重置供应商"${item.name}"的密码`),
+          duration: 2000
+        })
+      })
+    },
+    // 代他操作
+    async handleProxy(item) {
+      const text = await this.$confirm('此操作将临时登录该供应商账号, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).catch(() => {
+        this.$message.info('已取消操作')
+      })
+      if (text !== 'confirm') return
+      // 要执行的操作
+      console.log(item)
+      // this.$store.commit('user/SET_PROXY_INFO', item)
+      this.$store.commit('proxy/OPEN_PROXY', item)
+      // this.$router.push(`/auth/list?type=${item.shopType}`)
+      this.$router.push(`/proxy`)
+    },
+    // 过滤列表
+    handleFilter() {
+      this.listQuery.page = 1
+      this.getList()
+    },
+    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;
+  }
+}
+
+</style>

+ 0 - 0
src/views/common/helper/file/index.vue


+ 0 - 0
src/views/common/helper/video/index.vue


+ 102 - 0
src/views/common/password/index.vue

@@ -0,0 +1,102 @@
+<template>
+  <div>
+    <el-form ref="form" :model="formData" :rules="formRules" label-width="80px" class="form">
+      <el-form-item label="旧密码" prop="oldPassword">
+        <el-input v-model="formData.oldPassword" type="password" placeholder="请输入旧密码" />
+      </el-form-item>
+      <el-form-item label="新密码" prop="newPassword">
+        <el-input v-model="formData.newPassword" type="password" placeholder="请输入新密码" />
+      </el-form-item>
+      <el-form-item label="确认密码" prop="confirmPwd">
+        <el-input v-model="formData.confirmPwd" type="password" placeholder="请再次输入密码" />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" @click="submit()">确认</el-button>
+        <el-button type="warning" @click="$_back()">返回</el-button>
+      </el-form-item>
+    </el-form>
+  </div>
+</template>
+
+<script>
+import { modifyPassword } from '@/api/user'
+import { validPassword } from '@/utils/validate'
+export default {
+  data() {
+    var confirmPassword = (rule, value, callback) => {
+      if (value === '') {
+        callback(new Error('请再次输入密码'))
+      } else if (value !== this.formData.newPassword) {
+        callback(new Error('两次输入密码不一致!'))
+      } else {
+        callback()
+      }
+    }
+    var validPwd = (rule, value, callback) => {
+      if (this.formData.oldPassword === value) {
+        callback(new Error('新密码与旧密码相同'))
+      } else if (!validPassword(value)) {
+        callback(new Error('请输入字母与数字组合的8-12位密码'))
+      } else {
+        callback()
+      }
+    }
+    return {
+      formData: {
+        oldPassword: '',
+        newPassword: '',
+        confirmPwd: ''
+      },
+      formRules: {
+        oldPassword: [
+          { required: true, message: '请输入原来的密码', trigger: 'blur' }
+        ],
+        newPassword: [
+          { required: true, trigger: ['change', 'blur'], validator: validPwd }
+        ],
+        confirmPwd: [
+          { required: true, message: '请再次输入密码' },
+          { validator: confirmPassword, trigger: 'change' }
+        ]
+      }
+    }
+  },
+  methods: {
+    submit() {
+      const that = this
+      this.$refs.form.validate(valide => {
+        if (!valide) return
+        const authUserId = this.$store.getters.authUserId
+        modifyPassword({ authUserId, ...that.formData }).then(res => {
+          if (res.code === 0) {
+            this.$refs.form.resetFields()
+            this.$message.success('密码修改成功,请重新登录')
+            this.logout()
+          }
+        }).catch(err => {
+          console.log(err)
+        })
+      })
+    },
+    async logout() {
+      setTimeout(() => {
+        // 退出登录重置用户信息
+        this.$store.dispatch('user/logout')
+        // 重置相关state
+        this.$store.dispatch('resetState')
+        this.$router.replace('/login')
+      }, 500)
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+  .form{
+    width: 600px;
+    margin: 80px auto;
+    .el-button{
+      width: 120px;
+    }
+  }
+</style>

+ 0 - 13
src/views/error-log/components/ErrorTestA.vue

@@ -1,13 +0,0 @@
-<template>
-  <div>
-    <!--error code-->
-    {{ a.a }}
-    <!--error code-->
-  </div>
-</template>
-
-<script>
-export default {
-  name: 'ErrorTestA'
-}
-</script>

+ 0 - 11
src/views/error-log/components/ErrorTestB.vue

@@ -1,11 +0,0 @@
-<template>
-  <div />
-</template>
-
-<script>
-export default {
-  created() {
-    this.b = b // eslint-disable-line
-  }
-}
-</script>

+ 0 - 32
src/views/error-log/index.vue

@@ -1,32 +0,0 @@
-<template>
-  <div class="errPage-container">
-    <ErrorA />
-    <ErrorB />
-    <h3>Please click the bug icon in the upper right corner</h3>
-    <aside>
-      Now the management system are basically the form of the spa, it enhances the user experience, but it also increases the possibility of page problems, a small negligence may lead to the entire page deadlock. Fortunately Vue provides a way to catch handling exceptions, where you can handle errors or report exceptions.
-      <a target="_blank" class="link-type" href="https://panjiachen.github.io/vue-element-admin-site/guide/advanced/error.html">
-        Document introduction
-      </a>
-    </aside>
-    <a href="#">
-      <img src="https://wpimg.wallstcn.com/360e4842-4db5-42d0-b078-f9a84a825546.gif">
-    </a>
-  </div>
-</template>
-
-<script>
-import ErrorA from './components/ErrorTestA'
-import ErrorB from './components/ErrorTestB'
-
-export default {
-  name: 'ErrorLog',
-  components: { ErrorA, ErrorB }
-}
-</script>
-
-<style scoped>
-  .errPage-container {
-    padding: 30px;
-  }
-</style>

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
src/views/icons/element-icons.js


+ 0 - 101
src/views/icons/index.vue

@@ -1,101 +0,0 @@
-<template>
-  <div class="icons-container">
-    <aside>
-      <a href="https://panjiachen.github.io/vue-element-admin-site/guide/advanced/icon.html" target="_blank">Add and use
-      </a>
-    </aside>
-    <el-tabs type="border-card">
-      <el-tab-pane label="Icons">
-        <div class="grid">
-          <div v-for="item of svgIcons" :key="item" @click="handleClipboard(generateIconCode(item),$event)">
-            <el-tooltip placement="top">
-              <div slot="content">
-                {{ generateIconCode(item) }}
-              </div>
-              <div class="icon-item">
-                <svg-icon :icon-class="item" class-name="disabled" />
-                <span>{{ item }}</span>
-              </div>
-            </el-tooltip>
-          </div>
-        </div>
-      </el-tab-pane>
-      <el-tab-pane label="Element-UI Icons">
-        <div class="grid">
-          <div v-for="item of elementIcons" :key="item" @click="handleClipboard(generateElementIconCode(item),$event)">
-            <el-tooltip placement="top">
-              <div slot="content">
-                {{ generateElementIconCode(item) }}
-              </div>
-              <div class="icon-item">
-                <i :class="'el-icon-' + item" />
-                <span>{{ item }}</span>
-              </div>
-            </el-tooltip>
-          </div>
-        </div>
-      </el-tab-pane>
-    </el-tabs>
-  </div>
-</template>
-
-<script>
-import clipboard from '@/utils/clipboard'
-import svgIcons from './svg-icons'
-import elementIcons from './element-icons'
-
-export default {
-  name: 'Icons',
-  data() {
-    return {
-      svgIcons,
-      elementIcons
-    }
-  },
-  methods: {
-    generateIconCode(symbol) {
-      return `<svg-icon icon-class="${symbol}" />`
-    },
-    generateElementIconCode(symbol) {
-      return `<i class="el-icon-${symbol}" />`
-    },
-    handleClipboard(text, event) {
-      clipboard(text, event)
-    }
-  }
-}
-</script>
-
-<style lang="scss" scoped>
-.icons-container {
-  margin: 10px 20px 0;
-  overflow: hidden;
-
-  .grid {
-    position: relative;
-    display: grid;
-    grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
-  }
-
-  .icon-item {
-    margin: 20px;
-    height: 85px;
-    text-align: center;
-    width: 100px;
-    float: left;
-    font-size: 30px;
-    color: #24292e;
-    cursor: pointer;
-  }
-
-  span {
-    display: block;
-    font-size: 16px;
-    margin-top: 10px;
-  }
-
-  .disabled {
-    pointer-events: none;
-  }
-}
-</style>

+ 0 - 10
src/views/icons/svg-icons.js

@@ -1,10 +0,0 @@
-const req = require.context('../../icons/svg', false, /\.svg$/)
-const requireAll = requireContext => requireContext.keys()
-
-const re = /\.\/(.*)\.svg/
-
-const svgIcons = requireAll(req).map(i => {
-  return i.match(re)[1]
-})
-
-export default svgIcons

+ 350 - 0
src/views/normal/club/device/edit.vue

@@ -0,0 +1,350 @@
+<template>
+  <div v-loading="isLoading" class="addProduct">
+    <el-form ref="addFormRef" label-width="130px" class="addForm" :model="formData" :rules="rules">
+      <el-form-item label="设备名称:" prop="productName">
+        <el-input v-model="formData.productName" placeholder="建议输入30个字符效果最佳" />
+      </el-form-item>
+
+      <el-form-item label="设备SN码:" prop="snCode">
+        <el-input v-model="formData.snCode" placeholder="请输入设备SN码" />
+      </el-form-item>
+
+      <el-form-item v-if="shopType === 2" label="所属品牌:" prop="brandId">
+        <el-select
+          v-model="formData.brandId"
+          placeholder="请选择品牌"
+          style="width: 100%"
+          filterable
+          @change="handleChange"
+        >
+          <el-option v-for="item in brandList" :key="item.id" :label="item.name" :value="item.id" />
+        </el-select>
+      </el-form-item>
+
+      <el-form-item label="设备图片:" prop="productImage">
+        <upload-image
+          tip="建议尺寸:542px * 542px"
+          :image-list="productImageList"
+          :before-upload="beforeProductImageUpload"
+          @success="uploadProductImageSuccess"
+          @remove="handleProductImageRemove"
+        />
+        <el-input v-model="formData.productImage" class="hiddenInput" />
+      </el-form-item>
+      <el-form-item label="授权牌:" prop="certificateImage">
+        <upload-image
+          tip="建议尺寸:150px * 112px"
+          :image-list="certificateImageList"
+          :before-upload="beforeCertificateImageUpload"
+          @success="uploadCertificateImageSuccess"
+          @remove="handleCertificateImageRemove"
+        />
+        <el-input v-model="formData.certificateImage" class="hiddenInput" />
+      </el-form-item>
+      <!-- 是否生成二维码授权牌 -->
+      <el-form-item label="生成二维码授权牌:">
+        <el-radio-group v-model="formData.addQrCodeFlag" size="mini" @change="handleRadioChange">
+          <el-radio :label="0" border>否</el-radio>
+          <el-radio :label="1" border :disabled="certificateImageList.length <= 0">是</el-radio>
+        </el-radio-group>
+      </el-form-item>
+      <!-- 二维码授权牌模板 -->
+      <el-form-item v-if="formData.addQrCodeFlag===1" label="选择模板:">
+        <auth-card-template v-model="formData.addTemplateType" :image-list="certificateImageList" />
+      </el-form-item>
+
+      <el-form-item label="相关参数:" prop="paramList">
+        <div v-for="(item, index) in paramList" :key="index" class="form-group paramsItem">
+          <el-input v-model="item.paramName" class="param-title" :placeholder="item.tip.first" 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>
+        <el-button type="primary" size="mini" @click="handleAddParam">添加参数</el-button>
+      </el-form-item>
+      <!-- <el-form-item 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" @click="submit">保存</el-button>
+      <el-button type="warning" @click="$_back()">返回</el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+import UploadImage from '@/components/UploadImage'
+import { saveProduct } from '@/api/product'
+import { fetchBrandList } from '@/api/brand'
+import { mapGetters } from 'vuex'
+import { isSnCode } from '@/utils/validate'
+import AuthCardTemplate from '../components/authCardTemplate.vue'
+export default {
+  components: { UploadImage, AuthCardTemplate },
+  data() {
+    const valideSNcode = (rules, value, callback) => {
+      if (!isSnCode(value)) {
+        return callback(new Error('只能是字母+数字组合'))
+      }
+      callback()
+    }
+    const valideBrandId = (rules, value, callback) => {
+      if (!value) {
+        return callback(new Error('所属品牌不能为空'))
+      }
+      callback()
+    }
+    return {
+      isLoading: false,
+      paramsCount: 4,
+      brandList: [],
+      formData: {
+        authUserId: '',
+        authId: '', //	授权id
+        certificateImage: '', //	授权牌照
+        createBy: '', //	创建人id
+        // 	设备参数列表
+        paramList: [],
+        productId: '', //	授权设备id
+        productImage: '', //	设备图片
+        productName: '', //	设备名称
+        snCode: '', //	设备SN码
+        status: 2, //	上架状态:0下线,1上线 2待审核
+        brandId: '',
+        addQrCodeFlag: 0,
+        addTemplateType: 1
+      },
+      paramList: [], // 参数列表
+      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字符以内' }
+        ],
+        brandId: [{ required: true, validator: valideBrandId, tigger: 'change' }]
+      },
+      // 参数框的提示语
+      tipList: ['例如:品牌', '例如:尺寸', '例如:功率', '例如:重量'],
+
+      // 商品图片列表
+      productImageList: [],
+      // 授权牌照图片列表
+      certificateImageList: []
+    }
+  },
+  computed: {
+    ...mapGetters(['authUserId', 'proxyInfo', 'shopType', 'brandId'])
+  },
+  watch: {
+    paramList: {
+      deep: true,
+      handler: function() {
+        this.formData.paramList = this.setParamToFormData()
+      }
+    }
+  },
+  created() {
+    this.formData.authId = this.$route.query.id
+    this.formData.authUserId = this.proxyInfo?.authUserId || this.authUserId
+    this.initParamList()
+    // 如果供应商类型为代理商  则需要获取它代理的品牌列表
+    if (this.shopType === 2) {
+      this.getBrandList()
+    }
+    // 如果供应商类型为品牌方,则自动设置品牌id
+    if (this.shopType === 1) {
+      this.formData.brandId = this.proxyInfo?.brandId || this.brandId || ''
+    }
+  },
+  methods: {
+
+    authCardChange(current) {
+      console.log(current)
+      this.formData.addTemplateType = current
+    },
+
+    handleChange() {
+      console.log(this.formData)
+    },
+
+    handleRadioChange(index) {
+      if (index === 1 && this.certificateImageList.length <= 0) {
+        this.$message.warning('请先上传授权牌')
+        this.formData.addQrCodeFlag = 0
+        return
+      }
+    },
+
+    // 提交
+    submit() {
+      this.formData.paramList = this.setParamToFormData()
+      this.$refs.addFormRef.validate(valide => {
+        if (valide) {
+          this.save()
+        }
+      })
+    },
+    // 保存表单数据
+    save() {
+      this.isLoading = true
+      // createBy先判断是否为代理操作,是就从代理数据中获取,否则直接获取当前登录用户的信息
+      this.formData.createBy = this.proxyInfo?.authUserId || this.authUserId
+      this.formData.authUserId = this.proxyInfo?.authUserId || this.authUserId
+      saveProduct(this.formData)
+        .then(res => {
+          if (res.code !== 0) return
+          const h = this.$createElement
+          this.$notify.success({
+            title: '新增设备',
+            message: h('i', { style: 'color: #333' }, `已添加设备:"${this.formData.productName}"`),
+            duration: 2000
+          })
+          this.$refs.addFormRef.resetFields()
+          this.clearFormData()
+          this.$store.dispatch('tagsView/delView', this.$route)
+          this.$router.push(`/product/list?id=${this.formData.authId}`)
+        })
+        .finally(() => {
+          this.isLoading = false
+        })
+    },
+    // 保存参数到formdata
+    setParamToFormData() {
+      return this.paramList.filter(item => item.paramContent !== '' && item.paramName !== '')
+    },
+    // 初始化参数列表
+    initParamList() {
+      for (let i = 0; i < this.paramsCount; i++) {
+        this.paramList.push({
+          paramContent: '',
+          paramName: '',
+          tip: {
+            first: this.tipList[i],
+            second: '请输入参数信息'
+          }
+        })
+      }
+    },
+    // 获取品牌信息
+    getBrandList() {
+      fetchBrandList({ type: 3, authUserId: this.formData.authUserId }).then(res => {
+        console.log(res)
+
+        this.brandList = res.data
+      })
+    },
+    // 添加一栏参数
+    handleAddParam() {
+      this.paramsCount += 1
+      this.paramList.push({
+        paramContent: '',
+        paramName: '',
+        tip: {
+          first: '参数名称',
+          second: '请输入参数信息'
+        }
+      })
+    },
+    // 删除一栏参数
+    handleRemoveParam(index) {
+      this.paramsCount -= 1
+      this.paramList.splice(index, 1)
+    },
+
+    // 产品图片上传
+    beforeProductImageUpload(file) {
+      const flag = file.size / 1024 / 1024 < 1
+      if (!flag) {
+        this.$message.error('上传产品图片大小不能超过 1MB!')
+      }
+      return flag
+    },
+    uploadProductImageSuccess({ response, file, fileList }) {
+      this.productImageList = fileList
+      this.formData.productImage = response.data
+    },
+    handleProductImageRemove({ file, fileList }) {
+      this.productImageList = fileList
+      this.formData.productImage = ''
+    },
+    // 授权牌照上传
+    beforeCertificateImageUpload(file) {
+      const flag = file.size / 1024 / 1024 < 1
+      if (!flag) {
+        this.$message.error('上传授权牌图片大小不能超过 1MB!')
+      }
+      return flag
+    },
+    uploadCertificateImageSuccess({ response, file, fileList }) {
+      this.certificateImageList = fileList
+      this.formData.certificateImage = response.data
+    },
+    handleCertificateImageRemove({ file, fileList }) {
+      this.certificateImageList = fileList
+      this.formData.certificateImage = ''
+      this.formData.addQrCodeFlag = 0
+    },
+
+    clearFormData() {
+      this.paramList = []
+      this.paramsCount = 4
+      this.initParamList()
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.addProduct {
+  margin-bottom: 80px;
+  .form-group {
+    margin-bottom: 2%;
+    .param-title {
+      width: 30%;
+    }
+    .param-info {
+      width: 68%;
+      margin-left: 2%;
+    }
+  }
+}
+.addForm {
+  width: 800px;
+  margin: 0 auto;
+  margin-top: 80px;
+}
+.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>

+ 298 - 0
src/views/normal/club/device/index.vue

@@ -0,0 +1,298 @@
+<template>
+  <div class="app-container">
+    <div class="filter-container">
+      <span>设备名称:</span>
+      <el-input v-model="listQuery.productName" placeholder="设备名称" style="width: 200px;" class="filter-item" @keyup.enter.native="handleFilter" />
+      <span>设备SN码:</span>
+      <el-input v-model="listQuery.snCode" placeholder="设备SN码" style="width: 200px;" class="filter-item" @keyup.enter.native="handleFilter" />
+      <span>审核状态:</span>
+      <el-select
+        v-model="listQuery.auditStatus"
+        placeholder="审核状态"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="全部" value="" />
+        <el-option label="待审核" :value="2" />
+        <el-option label="审核通过" :value="1" />
+        <el-option label="审核未通过" :value="0" />
+      </el-select>
+      <span>上线状态:</span>
+      <el-select
+        v-model="listQuery.status"
+        placeholder="上线状态"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="全部" value="" />
+        <el-option label="已上线" :value="1" />
+        <el-option label="待上线" :value="2" />
+        <el-option label="未上线" :value="0" />
+      </el-select>
+      <el-button type="primary" icon="el-icon-search" @click="handleFilter">查询</el-button>
+      <el-button v-if="isProxy" icon="el-icon-edit" type="primary" @click="$_navigationTo(`add?id=${listQuery.authId}`)">添加</el-button>
+    </div>
+    <!-- 表格区域 -->
+    <el-table
+      :key="tableKey"
+      v-loading="listLoading"
+      :data="list"
+      border
+      fit
+      highlight-current-row
+      style="width: 100%;"
+      header-row-class-name="tableHeader"
+    >
+      <el-table-column label="序号" :index="indexMethod" type="index" align="center" width="80" />
+      <el-table-column label="设备名称" align="center" prop="productName" />
+      <el-table-column label="设备SN码" align="center" prop="snCode" />
+
+      <el-table-column label="审核状态" width="220px" align="center">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.auditStatus === 2" size="small" type="warning">待审核</el-tag>
+          <el-tag v-if="row.auditStatus === 1" size="small" type="success">审核通过</el-tag>
+          <!-- 未通过原因展示 -->
+          <template v-if="row.auditStatus === 0">
+            <!-- <span class="status danger">审核未通过&nbsp;</span> -->
+            <el-popover
+              placement="top-start"
+              title="审核说明"
+              width="400"
+              trigger="hover"
+              :content="row.invalidReason"
+            >
+              <el-tag slot="reference" size="small" type="danger" class="reason">
+                <span>审核未通过</span>
+                <span class="el-icon-question status danger " />
+              </el-tag>
+            </el-popover>
+            <!-- 未通过原因展示END -->
+          </template>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="上线状态" width="140px" align="center">
+        <template slot-scope="{row}">
+          <!-- 只有审核通过了才能操作上下线 auditStatus :审核状态 -->
+          <template v-if="row.auditStatus === 1">
+            <template v-if="row.status === 0">
+              <span style="margin-right:10px;" class="status danger">已下线</span>
+              <el-button v-if="isProxy" type="primary" size="mini" @click="handleChangeStatus(row)">上线</el-button>
+            </template>
+            <template v-else>
+              <span style="margin-right:10px;" class="status success ">已上线</span>
+              <el-button v-if="isProxy" type="info" size="mini" @click="handleChangeStatus(row)">下线</el-button>
+            </template>
+          </template>
+          <template v-else>
+            <!-- <el-tag type="warning">待上线</el-tag> -->
+            <span style="margin-right:10px;" class="status warning">待上线</span>
+          </template>
+        </template>
+      </el-table-column>
+      <el-table-column label="创建时间" class-name="status-col" width="300px" align="center">
+        <template slot-scope="{row}">
+          <span>{{ row.createTime | formatTime }}</span>
+        </template>
+      </el-table-column>
+      <!-- <el-table-column v-if="false" label="创建人" width="180px" align="center" prop="createBy" /> -->
+      <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="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 v-if="row.auditStatus === 1" type="primary" size="mini" @click="handleShowQRcode(row)">
+            二维码
+          </el-button>
+          <el-button v-else type="info" size="mini" disabled>
+            二维码
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 页码 -->
+    <pagination v-show="total>0" :total="total" :page.sync="listQuery.pageNum" :limit.sync="listQuery.pageSize" @pagination="getList" />
+
+    <!-- 二维码 -->
+    <transition name="fade">
+      <qrcode v-if="showQRcode" :product-info="productInfo" @close="showQRcode = false" />
+    </transition>
+  </div>
+</template>
+
+<script>
+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, Qrcode },
+  filters: {
+    formatTime(time) {
+      if (!time) {
+        return ''
+      }
+      return formatDate(time, 'yyyy-MM-DD HH:mm:ss')
+    }
+  },
+
+  data() {
+    return {
+      authParty: '',
+      tableKey: 0,
+      list: null,
+      total: 0,
+      listLoading: true,
+      listQuery: {
+        status: '',
+        auditStatus: '',
+        authId: '',
+        productName: '',
+        snCode: '',
+        pageNum: 1,
+        pageSize: 10
+      },
+      showQRcode: false,
+      productInfo: {},
+      // 审核未通过
+      auditFailedList: [],
+      auditNoticeFlag: true
+    }
+  },
+  computed: {
+    ...mapGetters(['userIdentity', 'proxyInfo']),
+    isProxy() {
+      return this.proxyInfo || this.userIdentity !== 1
+    }
+  },
+  created() {
+    this.listQuery.authId = this.$route.query.id
+    this.authParty = this.$route.query.authParty
+    this.getList()
+  },
+
+  methods: {
+
+    // 添加
+    handleAddPro() {
+      this.$router.push('add')
+    },
+    // 修改
+    handleEditPro() {
+      this.$router.push('edit')
+    },
+    // 获取列表信息
+    getList() {
+      getProdList(this.listQuery).then(res => {
+        const { total, list } = res.data
+        this.total = total
+        this.list = list
+        // this.checkAuditFailedList(list)
+      }).finally(() => {
+        this.listLoading = false
+      })
+    },
+    // 过滤列表
+    handleFilter() {
+      this.listQuery.page = 1
+      this.getList()
+    },
+    // 改变启用状态
+    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.$message({
+            message: '操作成功',
+            duration: 500,
+            type: 'success'
+          })
+          this.listLoading = false
+        }).finally(() => {
+          this.getList()
+        })
+      }
+    },
+    // 删除商品
+    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 => {
+        const h = this.$createElement
+        this.$notify.success({
+          title: '删除商品',
+          message: h('i', { style: 'color: #333' }, `已删除商品:"${item.productName}"`),
+          duration: 2000
+        })
+      }).finally(() => {
+        this.getList()
+      })
+    },
+    // 显示二维码
+    handleShowQRcode(item) {
+      this.productInfo = item
+      this.productInfo.authParty = this.authParty
+      this.showQRcode = true
+    },
+    // 获取审核未通过条数
+    // Audit failed 审核未通过
+    checkAuditFailedList(data) {
+      this.auditFailedList = data.filter(item => item.auditStatus === 0)
+      if (this.auditFailedList.length > 0 && this.auditNoticeFlag && (this.userIdentity !== 1 || this.proxyInfo !== null)) {
+        this.$notify.info({
+          title: '消息通知',
+          dangerouslyUseHTMLString: true,
+          message: `共有<b style="color:red">${this.auditFailedList.length}</b>件商品未能通过审核,请查看原因并及时修改!`,
+          duration: 3000
+        })
+        this.auditNoticeFlag = false
+      }
+    },
+    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;
+  }
+}
+</style>

+ 580 - 0
src/views/normal/club/edit.vue

@@ -0,0 +1,580 @@
+<template>
+  <div class="app-container">
+    <div class="filter-container">
+      <span>机构名称:</span>
+      <el-input v-model="listQuery.authParty" placeholder="机构名称" style="width: 280px;" class="filter-item" @keyup.enter.native="handleFilter" />
+      <span>审核状态:</span>
+      <el-select
+        v-model="listQuery.auditStatus"
+        placeholder="审核状态"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="全部" value="" />
+        <el-option label="待审核" :value="2" />
+        <el-option label="审核通过" :value="1" />
+        <el-option label="审核未通过" :value="0" />
+      </el-select>
+      <span>上线状态:</span>
+      <el-select
+        v-model="listQuery.status"
+        placeholder="上线状态"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="全部" value="" />
+        <el-option label="已上线" :value="1" />
+        <el-option label="待上线" :value="2" />
+        <el-option label="未上线" :value="0" />
+      </el-select>
+
+      <el-button icon="el-icon-search" type="primary" @click="getList">查询</el-button>
+      <!-- <el-button v-if="isProxy" icon="el-icon-edit" type="primary" @click="handleShowEditDialog('添加品牌授权')">添加品牌授权</el-button> -->
+      <el-button v-if="isProxy" icon="el-icon-edit" type="primary" @click="$_navigationTo('/auth/auth-add')">添加</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>
+      <el-button type="primary" icon="el-icon-download" @click="handleExport(1)">一键下载授权牌</el-button>
+      <el-button type="primary" icon="el-icon-download" @click="handleExport(2)">一键下载二维码</el-button>
+    </div>
+    <!-- 表格区域 -->
+    <el-table
+      :key="tableKey"
+      v-loading="listLoading"
+      :data="list"
+      border
+      fit
+      highlight-current-row
+      style="width: 100%;"
+      header-row-class-name="tableHeader"
+    >
+      <el-table-column label="序号" :index="indexMethod" align="center" width="80" type="index" />
+
+      <el-table-column label="机构名称" align="center" prop="authParty" />
+
+      <el-table-column label="审核状态" width="160px" align="center">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.auditStatus === 2" size="small" type="warning">待审核</el-tag>
+          <el-tag v-if="row.auditStatus === 1" size="small" type="success">审核通过</el-tag>
+          <!-- 未通过原因展示 -->
+          <template v-if="row.auditStatus === 0">
+            <!-- <span class="status danger">审核未通过&nbsp;</span> -->
+            <el-popover
+              placement="top-start"
+              title="审核说明"
+              width="400"
+              trigger="hover"
+              :content="row.invalidReason"
+            >
+              <el-tag slot="reference" size="small" type="danger" class="reason">
+                <span>审核未通过</span>
+                <span class="el-icon-question status danger " />
+              </el-tag>
+            </el-popover>
+            <!-- 未通过原因展示END -->
+          </template>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="上线状态" width="260px" align="center">
+        <template slot-scope="{row}">
+          <!-- 只有审核通过了才能操作上下线 auditStatus :审核状态 -->
+          <template v-if="row.auditStatus === 1">
+            <template v-if="row.status === 0">
+              <span style="margin-right:10px;" class="status danger">已下线</span>
+              <el-button v-if="isProxy" type="primary" size="mini" @click="handleChangeStatus(row)">上线</el-button>
+            </template>
+            <template v-else>
+              <span style="margin-right:10px;" class="status success ">已上线</span>
+              <el-button v-if="isProxy" type="info" size="mini" @click="handleChangeStatus(row)">下线</el-button>
+            </template>
+          </template>
+          <template v-else>
+            <!-- <el-tag type="warning">待上线</el-tag> -->
+            <span style="margin-right:10px;" class="status warning">待上线</span>
+          </template>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="创建时间" class-name="status-col" width="200px">
+        <template slot-scope="{row}">
+          <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="400px" class-name="small-padding fixed-width">
+        <template slot-scope="{row}">
+          <template v-if="isProxy">
+            <el-button type="primary" size="mini" @click="$_navigationTo(`/auth/auth-edit?id=${row.authId}&authParty=${row.authParty}`)">
+              编辑
+            </el-button>
+            <el-button type="primary" size="mini" @click="$_navigationTo(`/auth/user-list?id=${row.authId}&authParty=${row.authParty}`)">
+              登录用户
+            </el-button>
+          </template>
+          <template v-if="!isProxy">
+            <el-button type="primary" size="mini" @click="$_navigationTo(`/product?id=${row.authId}&authParty=${row.authParty}`)">
+              查看
+            </el-button>
+          </template>
+          <el-button type="primary" size="mini" @click="$_navigationTo(`/product?id=${row.authId}&authParty=${row.authParty}`)">
+            查看设备认证
+          </el-button>
+          <el-button v-if="isProxy" type="danger" size="mini" @click="handleRemoveAuth(row)">
+            删除
+          </el-button>
+
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 页码 -->
+    <pagination v-show="total>0" :total="total" :page.sync="listQuery.pageNum" :limit.sync="listQuery.pageSize" @pagination="getList" />
+
+    <!-- 对话框区域 -->
+    <el-dialog
+      :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="authParty">
+          <el-input v-model="addAuthFormData.authParty" placeholder="请输入授权机构名称" />
+        </el-form-item>
+        <!-- <el-form-item label="上线状态:">
+          <el-select v-model="addAuthFormData.status">
+            <el-option label="上线" :value="1" />
+            <el-option label="下线" :value="0" />
+          </el-select>
+        </el-form-item> -->
+      </el-form>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="showAddAuthDialog = false">取 消</el-button>
+        <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 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, FileUpload },
+  filters: {
+    formatTime(time) {
+      if (!time) {
+        return ''
+      }
+      return formatDate(time, 'yyyy-MM-DD HH:mm:ss')
+    }
+  },
+  data() {
+    return {
+      noticeTitle: '添加',
+      dialogFlag: true, // 对话框状态
+      tableKey: 0,
+      list: null,
+      total: 0,
+      listLoading: true,
+      // 查询参数
+      listQuery: {
+        authParty: '', // 授权机构
+        authUserId: '', // 供应商用户id
+        pageNum: 1, // 页码
+        pageSize: 10, // 分页
+        status: ''
+      },
+      // 添加品牌授权
+      showAddAuthDialog: false, // 显示添加供应商对话框
+      dialogTitle: '',
+      addAuthFormData: {
+        authId: '', // 授权id
+        authUserId: '', // 供应商用户id
+        authParty: '', // 授权机构
+        createBy: '', // 创建人id
+        status: 2 // 授权状态 0下线,1上线  2待审核
+      },
+      addAuthFormRules: {
+        authParty: [
+          { required: true, message: '请输入授权机构名称', trigger: 'blur' }
+        ]
+      },
+      disabled: false,
+      // 审核未通过
+      auditFailedList: [],
+      auditNoticeFlag: true,
+      // ------------------
+      improtDialogVisible: false,
+      requestLoading: false,
+      uploadFileList: [],
+      improtDialogFormData: {
+        fileUrl: ''
+      },
+      improtDialogFormRules: {
+        fileUrl: [
+          {
+            required: true,
+            message: '请选择文件', trigger: 'change'
+          }
+        ]
+      },
+      chooseFile: ''
+    }
+  },
+  computed: {
+    ...mapGetters(['authUserId', 'userIdentity', 'proxyInfo', 'copyUserInfo']),
+    saveBtnClickable() {
+      return this.uploadFileList.length > 0
+    },
+    isProxy() {
+      return this.proxyInfo || this.userIdentity !== 1
+    }
+  },
+  created() {
+    this.listQuery.authUserId = this.$route.query.id || this.proxyInfo?.authUserId || this.authUserId
+    const type = this.$route.query.type
+    // 如果是通过路由参数传递的type,则需要同步到store
+    if (type) {
+      this.$store.commit('user/SET_SHOP_TYPE', parseInt(type))
+    }
+    this.getList()
+  },
+  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)
+      }
+    },
+
+    // 导出下载授权牌 || 二维码
+    async handleExport(type) {
+      const confirmText = type === 1 ? '授权牌' : '二维码'
+
+      const text = await this.$confirm(`确认下载所有${confirmText}?`, '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).catch(() => {
+        this.$message.info('已取消操作')
+      })
+      if (text !== 'confirm') return
+      // 使用a链接下载
+      downLoadWithATag(`${process.env.VUE_APP_BASE_API}/download/shop/image?authUserId=${this.authUserId}&type=${type}`)
+    },
+
+    // 下载模板
+    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
+      fecthAuthList(this.listQuery).then(response => {
+        if (response.code !== 0) {
+          return this.$message.error('授权列表信息获取失败')
+        }
+        const { list, total } = response.data
+        // this.formatList(list)
+        this.list = list
+        this.total = total
+        // 获取审核未通过的列表
+        // this.checkAuditFailedList(list)
+      }).catch(err => {
+        console.log(err)
+        return this.$message.error('授权列表信息获取失败')
+      }).finally(() => {
+        this.listLoading = false
+      })
+    },
+    // 获取审核未通过条数
+    // Audit failed 审核未通过
+    checkAuditFailedList(data) {
+      this.auditFailedList = data.filter(item => item.auditStatus === 0)
+      if (this.auditFailedList.length > 0 && this.auditNoticeFlag && (this.userIdentity !== 1 || this.proxyInfo !== null)) {
+        this.$notify.info({
+          title: '消息通知',
+          dangerouslyUseHTMLString: true,
+          message: `共有<b style="color:red">${this.auditFailedList.length}</b>个授权机构未能通过审核,请查看原因并及时修改!`,
+          duration: 3000
+        })
+        this.auditNoticeFlag = false
+      }
+    },
+    // 检查机构名是否存在 true:存在  false:不存在
+    handleCheckAuthName(name) {
+      const flag = this.list.some(item => item.authParty === name)
+      console.log(flag)
+      return flag
+    },
+    // 添加授权
+    handleUpdateBrandAuth() {
+      if (this.handleCheckAuthName(this.addAuthFormData.authParty) && this.dialogFlag) {
+        this.$message({
+          message: '该授权机构已存在',
+          duration: 1000,
+          type: 'warning'
+        })
+        return
+      }
+      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 => {
+            if (res.code !== 0) {
+              return
+            }
+            this.getList()
+            const h = this.$createElement
+            this.$notify.success({
+              title: `${this.noticeTitle}授权机构`,
+              message: h('i', { style: 'color: #333' }, `已${this.noticeTitle}授权机构:"${this.addAuthFormData.authParty}"`),
+              duration: 3000
+            })
+            this.$refs.addAuthForm.resetFields()
+          }).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 => {
+        if (res.code !== 0) return
+        const h = this.$createElement
+        this.$notify.success({
+          title: '移除授权机构',
+          message: h('i', { style: 'color: #333' }, `移除授权机构:"${item.authParty}"`),
+          duration: 3000
+        })
+      }).catch(err => {
+        console.log(err)
+      }).finally(() => {
+        this.listLoading = false
+        this.getList()
+      })
+    },
+    // 格式化列表数据
+    formatList(list = []) {
+      list.forEach(i => {
+        i.status = i.status === 1
+      })
+    },
+    // 供应商状态改变
+    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 = {
+        authId: item.authId,
+        status: item.status === 1 ? 0 : 1
+      }
+      changeAuthStatus(params).then(res => {
+        // this.$message.success(res.data)
+        this.$message({
+          message: res.data,
+          duration: 500,
+          type: 'success'
+        })
+        this.getList()
+      }).catch(err => {
+        console.log(err)
+      }).finally(() => {
+        this.listLoading = false
+      })
+    },
+    // 过滤列表
+    handleFilter() {
+      this.listQuery.page = 1
+      this.getList()
+    },
+    // 添加供应商
+    handleAddAuth() {
+      console.log('添加供应商')
+    },
+    // 对话框关闭事件
+    dialogClosed() {
+      console.log('dialog is closed')
+      this.addAuthFormData.authParty = ''
+      this.addAuthFormData.authId = ''
+      this.addAuthFormData.status = 1
+      this.noticeTitle = '添加'
+      this.$refs.addAuthForm.resetFields()
+    },
+    handleShowEditDialog(title, data) {
+      this.dialogTitle = title
+      if (data) {
+        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.noticeTitle = '修改'
+        this.dialogFlag = false
+      } else {
+        this.dialogFlag = true
+      }
+      this.showAddAuthDialog = true
+    },
+    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;
+  }
+}
+</style>

+ 580 - 0
src/views/normal/club/index.vue

@@ -0,0 +1,580 @@
+<template>
+  <div class="app-container">
+    <div class="filter-container">
+      <span>机构名称:</span>
+      <el-input v-model="listQuery.authParty" placeholder="机构名称" style="width: 280px;" class="filter-item" @keyup.enter.native="handleFilter" />
+      <span>审核状态:</span>
+      <el-select
+        v-model="listQuery.auditStatus"
+        placeholder="审核状态"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="全部" value="" />
+        <el-option label="待审核" :value="2" />
+        <el-option label="审核通过" :value="1" />
+        <el-option label="审核未通过" :value="0" />
+      </el-select>
+      <span>上线状态:</span>
+      <el-select
+        v-model="listQuery.status"
+        placeholder="上线状态"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="全部" value="" />
+        <el-option label="已上线" :value="1" />
+        <el-option label="待上线" :value="2" />
+        <el-option label="未上线" :value="0" />
+      </el-select>
+
+      <el-button icon="el-icon-search" type="primary" @click="getList">查询</el-button>
+      <!-- <el-button v-if="isProxy" icon="el-icon-edit" type="primary" @click="handleShowEditDialog('添加品牌授权')">添加品牌授权</el-button> -->
+      <el-button v-if="isProxy" icon="el-icon-edit" type="primary" @click="$_navigationTo('/auth/auth-add')">添加</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>
+      <el-button type="primary" icon="el-icon-download" @click="handleExport(1)">一键下载授权牌</el-button>
+      <el-button type="primary" icon="el-icon-download" @click="handleExport(2)">一键下载二维码</el-button>
+    </div>
+    <!-- 表格区域 -->
+    <el-table
+      :key="tableKey"
+      v-loading="listLoading"
+      :data="list"
+      border
+      fit
+      highlight-current-row
+      style="width: 100%;"
+      header-row-class-name="tableHeader"
+    >
+      <el-table-column label="序号" :index="indexMethod" align="center" width="80" type="index" />
+
+      <el-table-column label="机构名称" align="center" prop="authParty" />
+
+      <el-table-column label="审核状态" width="160px" align="center">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.auditStatus === 2" size="small" type="warning">待审核</el-tag>
+          <el-tag v-if="row.auditStatus === 1" size="small" type="success">审核通过</el-tag>
+          <!-- 未通过原因展示 -->
+          <template v-if="row.auditStatus === 0">
+            <!-- <span class="status danger">审核未通过&nbsp;</span> -->
+            <el-popover
+              placement="top-start"
+              title="审核说明"
+              width="400"
+              trigger="hover"
+              :content="row.invalidReason"
+            >
+              <el-tag slot="reference" size="small" type="danger" class="reason">
+                <span>审核未通过</span>
+                <span class="el-icon-question status danger " />
+              </el-tag>
+            </el-popover>
+            <!-- 未通过原因展示END -->
+          </template>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="上线状态" width="260px" align="center">
+        <template slot-scope="{row}">
+          <!-- 只有审核通过了才能操作上下线 auditStatus :审核状态 -->
+          <template v-if="row.auditStatus === 1">
+            <template v-if="row.status === 0">
+              <span style="margin-right:10px;" class="status danger">已下线</span>
+              <el-button v-if="isProxy" type="primary" size="mini" @click="handleChangeStatus(row)">上线</el-button>
+            </template>
+            <template v-else>
+              <span style="margin-right:10px;" class="status success ">已上线</span>
+              <el-button v-if="isProxy" type="info" size="mini" @click="handleChangeStatus(row)">下线</el-button>
+            </template>
+          </template>
+          <template v-else>
+            <!-- <el-tag type="warning">待上线</el-tag> -->
+            <span style="margin-right:10px;" class="status warning">待上线</span>
+          </template>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="创建时间" class-name="status-col" width="200px">
+        <template slot-scope="{row}">
+          <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="400px" class-name="small-padding fixed-width">
+        <template slot-scope="{row}">
+          <template v-if="isProxy">
+            <el-button type="primary" size="mini" @click="$_navigationTo(`/auth/auth-edit?id=${row.authId}&authParty=${row.authParty}`)">
+              编辑
+            </el-button>
+            <el-button type="primary" size="mini" @click="$_navigationTo(`/auth/user-list?id=${row.authId}&authParty=${row.authParty}`)">
+              登录用户
+            </el-button>
+          </template>
+          <template v-if="!isProxy">
+            <el-button type="primary" size="mini" @click="$_navigationTo(`/product?id=${row.authId}&authParty=${row.authParty}`)">
+              查看
+            </el-button>
+          </template>
+          <el-button type="primary" size="mini" @click="$_navigationTo(`/product?id=${row.authId}&authParty=${row.authParty}`)">
+            查看设备认证
+          </el-button>
+          <el-button v-if="isProxy" type="danger" size="mini" @click="handleRemoveAuth(row)">
+            删除
+          </el-button>
+
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 页码 -->
+    <pagination v-show="total>0" :total="total" :page.sync="listQuery.pageNum" :limit.sync="listQuery.pageSize" @pagination="getList" />
+
+    <!-- 对话框区域 -->
+    <el-dialog
+      :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="authParty">
+          <el-input v-model="addAuthFormData.authParty" placeholder="请输入授权机构名称" />
+        </el-form-item>
+        <!-- <el-form-item label="上线状态:">
+          <el-select v-model="addAuthFormData.status">
+            <el-option label="上线" :value="1" />
+            <el-option label="下线" :value="0" />
+          </el-select>
+        </el-form-item> -->
+      </el-form>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="showAddAuthDialog = false">取 消</el-button>
+        <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 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, FileUpload },
+  filters: {
+    formatTime(time) {
+      if (!time) {
+        return ''
+      }
+      return formatDate(time, 'yyyy-MM-DD HH:mm:ss')
+    }
+  },
+  data() {
+    return {
+      noticeTitle: '添加',
+      dialogFlag: true, // 对话框状态
+      tableKey: 0,
+      list: null,
+      total: 0,
+      listLoading: true,
+      // 查询参数
+      listQuery: {
+        authParty: '', // 授权机构
+        authUserId: '', // 供应商用户id
+        pageNum: 1, // 页码
+        pageSize: 10, // 分页
+        status: ''
+      },
+      // 添加品牌授权
+      showAddAuthDialog: false, // 显示添加供应商对话框
+      dialogTitle: '',
+      addAuthFormData: {
+        authId: '', // 授权id
+        authUserId: '', // 供应商用户id
+        authParty: '', // 授权机构
+        createBy: '', // 创建人id
+        status: 2 // 授权状态 0下线,1上线  2待审核
+      },
+      addAuthFormRules: {
+        authParty: [
+          { required: true, message: '请输入授权机构名称', trigger: 'blur' }
+        ]
+      },
+      disabled: false,
+      // 审核未通过
+      auditFailedList: [],
+      auditNoticeFlag: true,
+      // ------------------
+      improtDialogVisible: false,
+      requestLoading: false,
+      uploadFileList: [],
+      improtDialogFormData: {
+        fileUrl: ''
+      },
+      improtDialogFormRules: {
+        fileUrl: [
+          {
+            required: true,
+            message: '请选择文件', trigger: 'change'
+          }
+        ]
+      },
+      chooseFile: ''
+    }
+  },
+  computed: {
+    ...mapGetters(['authUserId', 'userIdentity', 'proxyInfo', 'copyUserInfo']),
+    saveBtnClickable() {
+      return this.uploadFileList.length > 0
+    },
+    isProxy() {
+      return this.proxyInfo || this.userIdentity !== 1
+    }
+  },
+  created() {
+    this.listQuery.authUserId = this.$route.query.id || this.proxyInfo?.authUserId || this.authUserId
+    const type = this.$route.query.type
+    // 如果是通过路由参数传递的type,则需要同步到store
+    if (type) {
+      this.$store.commit('user/SET_SHOP_TYPE', parseInt(type))
+    }
+    this.getList()
+  },
+  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)
+      }
+    },
+
+    // 导出下载授权牌 || 二维码
+    async handleExport(type) {
+      const confirmText = type === 1 ? '授权牌' : '二维码'
+
+      const text = await this.$confirm(`确认下载所有${confirmText}?`, '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).catch(() => {
+        this.$message.info('已取消操作')
+      })
+      if (text !== 'confirm') return
+      // 使用a链接下载
+      downLoadWithATag(`${process.env.VUE_APP_BASE_API}/download/shop/image?authUserId=${this.authUserId}&type=${type}`)
+    },
+
+    // 下载模板
+    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
+      fecthAuthList(this.listQuery).then(response => {
+        if (response.code !== 0) {
+          return this.$message.error('授权列表信息获取失败')
+        }
+        const { list, total } = response.data
+        // this.formatList(list)
+        this.list = list
+        this.total = total
+        // 获取审核未通过的列表
+        // this.checkAuditFailedList(list)
+      }).catch(err => {
+        console.log(err)
+        return this.$message.error('授权列表信息获取失败')
+      }).finally(() => {
+        this.listLoading = false
+      })
+    },
+    // 获取审核未通过条数
+    // Audit failed 审核未通过
+    checkAuditFailedList(data) {
+      this.auditFailedList = data.filter(item => item.auditStatus === 0)
+      if (this.auditFailedList.length > 0 && this.auditNoticeFlag && (this.userIdentity !== 1 || this.proxyInfo !== null)) {
+        this.$notify.info({
+          title: '消息通知',
+          dangerouslyUseHTMLString: true,
+          message: `共有<b style="color:red">${this.auditFailedList.length}</b>个授权机构未能通过审核,请查看原因并及时修改!`,
+          duration: 3000
+        })
+        this.auditNoticeFlag = false
+      }
+    },
+    // 检查机构名是否存在 true:存在  false:不存在
+    handleCheckAuthName(name) {
+      const flag = this.list.some(item => item.authParty === name)
+      console.log(flag)
+      return flag
+    },
+    // 添加授权
+    handleUpdateBrandAuth() {
+      if (this.handleCheckAuthName(this.addAuthFormData.authParty) && this.dialogFlag) {
+        this.$message({
+          message: '该授权机构已存在',
+          duration: 1000,
+          type: 'warning'
+        })
+        return
+      }
+      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 => {
+            if (res.code !== 0) {
+              return
+            }
+            this.getList()
+            const h = this.$createElement
+            this.$notify.success({
+              title: `${this.noticeTitle}授权机构`,
+              message: h('i', { style: 'color: #333' }, `已${this.noticeTitle}授权机构:"${this.addAuthFormData.authParty}"`),
+              duration: 3000
+            })
+            this.$refs.addAuthForm.resetFields()
+          }).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 => {
+        if (res.code !== 0) return
+        const h = this.$createElement
+        this.$notify.success({
+          title: '移除授权机构',
+          message: h('i', { style: 'color: #333' }, `移除授权机构:"${item.authParty}"`),
+          duration: 3000
+        })
+      }).catch(err => {
+        console.log(err)
+      }).finally(() => {
+        this.listLoading = false
+        this.getList()
+      })
+    },
+    // 格式化列表数据
+    formatList(list = []) {
+      list.forEach(i => {
+        i.status = i.status === 1
+      })
+    },
+    // 供应商状态改变
+    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 = {
+        authId: item.authId,
+        status: item.status === 1 ? 0 : 1
+      }
+      changeAuthStatus(params).then(res => {
+        // this.$message.success(res.data)
+        this.$message({
+          message: res.data,
+          duration: 500,
+          type: 'success'
+        })
+        this.getList()
+      }).catch(err => {
+        console.log(err)
+      }).finally(() => {
+        this.listLoading = false
+      })
+    },
+    // 过滤列表
+    handleFilter() {
+      this.listQuery.page = 1
+      this.getList()
+    },
+    // 添加供应商
+    handleAddAuth() {
+      console.log('添加供应商')
+    },
+    // 对话框关闭事件
+    dialogClosed() {
+      console.log('dialog is closed')
+      this.addAuthFormData.authParty = ''
+      this.addAuthFormData.authId = ''
+      this.addAuthFormData.status = 1
+      this.noticeTitle = '添加'
+      this.$refs.addAuthForm.resetFields()
+    },
+    handleShowEditDialog(title, data) {
+      this.dialogTitle = title
+      if (data) {
+        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.noticeTitle = '修改'
+        this.dialogFlag = false
+      } else {
+        this.dialogFlag = true
+      }
+      this.showAddAuthDialog = true
+    },
+    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;
+  }
+}
+</style>

+ 219 - 0
src/views/normal/club/user/index.vue

@@ -0,0 +1,219 @@
+<template>
+  <div class="app-container">
+    <!-- 搜索区域 -->
+    <div class="filter-container">
+      <span>手机号:</span>
+      <el-input
+        v-model="listQuery.mobile"
+        placeholder="手机号"
+        style="width: 200px"
+        class="filter-item"
+        @keyup.enter.native="getList"
+      />
+      <span>状态:</span>
+      <el-select
+        v-model="listQuery.status"
+        placeholder="邀请码状态"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="全部" value="" />
+        <el-option label="已绑定" :value="1" />
+        <el-option label="未绑定" :value="0" />
+        <el-option label="已过期" :value="2" />
+      </el-select>
+      <el-button type="primary" icon="el-icon-search" @click="getList">查询</el-button>
+      <el-button icon="el-icon-thumb" type="primary" @click="handleMakeGenerate">生成邀请码</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 label="序号" :index="indexMethod" type="index" width="80px" align="center" />
+      <el-table-column label="邀请码" prop="invitationCode" width="100px" align="center" />
+      <el-table-column label="状态" width="100px" align="center">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.status === 0" size="small" type="warning">未绑定</el-tag>
+          <el-tag v-if="row.status === 1" size="small" type="success">已绑定</el-tag>
+          <el-tag v-if="row.status === 2" size="small" type="danger">已过期</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="添加时间" width="200px" align="center">
+        <template slot-scope="{row}">
+          <span>{{ row.addTime | formatTime }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="微信昵称" align="center">
+        <template slot-scope="{row}">
+          <span v-if="row.nickName">{{ row.nickName }}</span>
+          <span v-else>—</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="手机号" width="140" align="center">
+        <template slot-scope="{row}">
+          <span v-if="row.mobile">{{ row.mobile }}</span>
+          <span v-else>—</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="openID" width="280" align="center">
+        <template slot-scope="{row}">
+          <span v-if="row.openId">{{ row.openId }}</span>
+          <span v-else>—</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="绑定时间" width="200px" align="center">
+        <template slot-scope="{row}">
+          <span v-if="row.bindTime">{{ row.bindTime | formatTime }}</span>
+          <span v-else>—</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" width="200px" align="center">
+        <template slot-scope="{row}">
+          <el-button v-if="row.status === 1" type="danger" size="mini" style="margin-right:5px" @click="handleUnbindGenerate(row)">解绑邀请码</el-button>
+          <el-button v-else type="primary" size="mini" style="margin-right:5px" @click="handleUpdateGenerate(row)">更新邀请码</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 表格区域END -->
+    <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 { formatDate } from '@/utils'
+import { mapGetters } from 'vuex'
+import { getAuthUserList, makeGenerate, unbindGenerate, updateGenerate } from '@/api/auth'
+export default {
+  components: { Pagination },
+  filters: {
+    formatTime(time) {
+      if (!time) {
+        return ''
+      }
+      return formatDate(time, 'yyyy-MM-DD HH:mm:ss')
+    }
+  },
+  data() {
+    return {
+      total: 0,
+      authId: '', // 机构id
+      listLoading: false,
+      listQuery: {
+        authId: '', // 机构id
+        mobile: '', // 手机号
+        status: '', // 邀请码状态
+        pageNum: 0, // 页码
+        pageSize: 10 // 分页大小
+      },
+      list: [],
+      srcList: []
+    }
+  },
+  computed: {
+    ...mapGetters(['authUserId'])
+  },
+  created() {
+    this.authId = this.$route.query.id
+    this.getList()
+  },
+  methods: {
+    // 获取列表数据
+    getList() {
+      this.listLoading = true
+      this.listQuery.authId = this.authId
+      getAuthUserList(this.listQuery)
+        .then(res => {
+          if (res.code !== 0) return
+          this.list = res.data.list
+          this.total = res.data.total
+          console.log(res)
+        })
+        .finally(() => {
+          this.listLoading = false
+        })
+    },
+    // 生成邀请码
+    handleMakeGenerate() {
+      makeGenerate({ authId: this.authId })
+        .then(res => {
+          console.log(res)
+          if (res.code !== 0) return
+          this.$message({
+            type: 'success',
+            message: res.data,
+            duration: 500
+          })
+          this.getList()
+        })
+    },
+    // 更新邀请码
+    handleUpdateGenerate(row) {
+      updateGenerate({ clubUserId: row.clubUserId })
+        .then(res => {
+          if (res.code !== 0) return
+          console.log(res)
+          this.$message({
+            type: 'success',
+            message: res.data,
+            duration: 500
+          })
+          this.getList()
+        })
+    },
+    // 解绑邀请码
+    handleUnbindGenerate(row) {
+      unbindGenerate({ clubUserId: row.clubUserId })
+        .then(res => {
+          if (res.code !== 0) return
+          console.log(res)
+          this.$message({
+            type: 'success',
+            message: res.data,
+            duration: 500
+          })
+          this.getList()
+        })
+    },
+    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;
+}
+</style>

+ 206 - 0
src/views/normal/doctor/edit.vue

@@ -0,0 +1,206 @@
+<template>
+  <div class="doctor-edit">
+    <el-form ref="submitForm" class="doctor-edit-form" label-width="140px" :model="formData" :rules="rules">
+      <el-form-item label="医师姓名:" prop="doctorName">
+        <el-input v-model="formData.doctorName" type="text" placeholder="请输入医师姓名" :maxlength="30" />
+      </el-form-item>
+      <el-form-item label="从业资格证编号:" prop="certificateNo">
+        <el-input v-model="formData.certificateNo" placeholder="请输入从业资格证编号" />
+      </el-form-item>
+      <el-form-item label="所在机构:" prop="clubName">
+        <el-input v-model="formData.clubName" placeholder="请输入机构名称" />
+      </el-form-item>
+      <el-form-item label="医师照片:" prop="doctorImage">
+        <el-input v-show="false" v-model="formData.doctorImage" />
+        <upload-image
+          tip="提示:上传医师个人照片,建议尺寸:200px * 200px"
+          :image-list="doctorImageList"
+          :before-upload="beforeDoctorImageUpload"
+          @success="uploadDoctorImageSuccess"
+          @remove="handleDoctorImageRemove"
+        />
+      </el-form-item>
+      <el-form-item label="轮播图:" prop="banner">
+        <el-input v-show="false" v-model="formData.banner" />
+        <upload-image
+          tip="至少上传一张机构门店图,最多上传6张;建议尺寸:542px * 542px"
+          :image-list="bannerList"
+          :limit="6"
+          :before-upload="beforeBannerUpload"
+          @success="uploadBannerSuccess"
+          @remove="handleBannerRemove"
+        />
+      </el-form-item>
+
+      <el-form-item label="具备操作资格设备:" prop="equipment">
+        <el-input v-show="false" v-model="formData.equipment" />
+        <device-section ref="subForm" :list="deviceList" @change="deviceListDataChange" />
+      </el-form-item>
+
+    </el-form>
+    <div class="submit-btn">
+      <el-button type="primary" @click="submit">保存</el-button>
+      <el-button type="warning" @click="$_back()">返回</el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+import { Promise } from 'jszip/lib/external'
+import { mapGetters } from 'vuex'
+import DeviceSection from '../components/deviceSection.vue'
+import UploadImage from '@/components/UploadImage'
+import { doctorSave } from '@/api/doctor'
+
+export default {
+  components: { DeviceSection, UploadImage },
+  data() {
+    var validateCertificateNo = (rule, value, callback) => {
+      if (value === '') {
+        callback(new Error('从业资格证编号不能为空'))
+      } else {
+        if (/^[a-z|A-Z|0-9]{1,}$/.test(value)) {
+          this.$refs.ruleForm.validateField('point')
+        } else {
+          callback('从业资格证编号格式不正确')
+        }
+        callback()
+      }
+    }
+
+    return {
+      point: {},
+      disabled: false,
+      formData: {
+        doctorName: '',
+        certificateNo: '',
+        clubName: '',
+        banner: '',
+        doctorImage: '',
+        equipment: ''
+      },
+      rules: {
+        doctorName: [{ required: true, message: '医师姓名不能为空', trigger: ['blur', 'change'] }],
+        certificateNo: [{ required: true, validator: validateCertificateNo, trigger: ['blur', 'change'] }],
+        clubName: [{ required: true, message: '所在机构不能为空', trigger: ['blur', 'change'] }],
+        doctorImage: [{ required: true, message: '请上传医师照片', trigger: 'change' }],
+        banner: [{ required: true, message: '请上传至少一张轮播图', trigger: 'change' }],
+        equipment: [{ required: true, message: '具备操作资格设备不能为空', trigger: 'change' }]
+      },
+      // logo图片列表
+      doctorImageList: [],
+      // banner图片列表
+      bannerList: [],
+      // 资格仪器列表
+      deviceList: []
+    }
+  },
+  computed: {
+    ...mapGetters(['token', 'authUserId', 'proxyInfo']),
+    // 图片上传
+    action() {
+      return process.env.VUE_APP_UPLOAD_API + '/upload/image'
+    },
+    headers() {
+      return {
+        'X-Token': this.token
+      }
+    }
+  },
+  created() {
+
+  },
+  methods: {
+    // 具备操作资格设备列表数据变化
+    deviceListDataChange(list) {
+      this.deviceList = list
+      this.formData.equipment = list.length || ''
+    },
+
+    // 提交表单验证
+    submit() {
+      Promise.all([this.$refs.subForm.valideAllForm(), this.$refs.submitForm.validate()]).then(res => {
+        this.save()
+      })
+    },
+
+    // 保存
+    save() {
+      const authUserId = this.proxyInfo?.authUserId || this.authUserId
+
+      const data = {
+        authUserId,
+        createBy: authUserId,
+        doctorId: '',
+        doctorName: this.formData.doctorName,
+        certificateNo: this.formData.certificateNo,
+        clubName: this.formData.clubName,
+        doctorImage: this.formData.doctorImage
+      }
+
+      console.log(this.formData)
+
+      data.bannerList = this.bannerList.map(item => item.response ? item.response.data : item.url)
+      data.equipmentList = this.deviceList.map(item => ({ equipmentName: item.equipmentName, brand: item.brand, image: item.image }))
+      doctorSave(data).then(res => {
+        this.$message.success('保存成功')
+        this.$store.dispatch('tagsView/delView', this.$route)
+        this.$router.push('/doctor/list')
+      })
+    },
+
+    // 医师照片上传
+    uploadDoctorImageSuccess({ response, file, fileList }) {
+      this.doctorImageList = fileList
+      this.formData.doctorImage = response.data
+    },
+    handleDoctorImageRemove({ file, fileList }) {
+      this.doctorImageList = fileList
+      this.formData.doctorImage = ''
+    },
+    beforeDoctorImageUpload(file) {
+      const flag = file.size / 1024 / 1024 < 1
+      if (!flag) {
+        this.$message.error('上传医师照片大小不能超过 1MB!')
+      }
+      return flag
+    },
+
+    // banner上传
+    uploadBannerSuccess({ response, file, fileList }) {
+      this.bannerList = fileList
+      this.formData.banner = fileList.length || ''
+    },
+    handleBannerRemove({ file, fileList }) {
+      this.bannerList = fileList
+      this.formData.banner = fileList.length || ''
+    },
+    beforeBannerUpload(file) {
+      const flag = file.size / 1024 / 1024 < 1
+      if (!flag) {
+        this.$message.error('上传banner图片大小不能超过 1MB!')
+      }
+      return flag
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.doctor-edit{
+  margin-bottom: 80px;
+}
+
+.doctor-edit-form {
+  width: 650px;
+  margin: 0 auto;
+  margin-top: 80px;
+}
+.submit-btn {
+  text-align: center;
+  .el-button {
+    width: 140px;
+  }
+}
+
+</style>

+ 224 - 0
src/views/normal/doctor/index.vue

@@ -0,0 +1,224 @@
+<template>
+  <div class="app-container">
+    <div class="filter-container">
+      <span>医师姓名:</span>
+      <el-input v-model="listQuery.doctorName" placeholder="医师姓名" style="width: 200px;" class="filter-item" @keyup.enter.native="handleFilter" />
+      <span>审核状态:</span>
+      <el-select
+        v-model="listQuery.auditStatus"
+        placeholder="审核状态"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="全部" value="" />
+        <el-option label="待审核" :value="2" />
+        <el-option label="审核通过" :value="1" />
+        <el-option label="审核未通过" :value="0" />
+      </el-select>
+      <span>上线状态:</span>
+      <el-select
+        v-model="listQuery.status"
+        placeholder="上线状态"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="全部" value="" />
+        <el-option label="已上线" :value="1" />
+        <el-option label="待上线" :value="2" />
+        <el-option label="未上线" :value="0" />
+      </el-select>
+      <el-button type="primary" icon="el-icon-search" @click="getList">查询</el-button>
+      <el-button type="primary" icon="el-icon-edit" @click="$_navigationTo('/doctor/add')">添加</el-button>
+    </div>
+    <!-- 表格区域 -->
+    <el-table
+      :key="tableKey"
+      v-loading="listLoading"
+      :data="list"
+      border
+      fit
+      highlight-current-row
+      style="width: 100%;"
+      header-row-class-name="tableHeader"
+    >
+      <el-table-column label="序号" :index="indexMethod" type="index" align="center" width="80" />
+      <el-table-column label="医生姓名" align="center" prop="doctorName" />
+      <el-table-column label="从业资格证编号" align="center" prop="certificateNo" />
+
+      <el-table-column label="审核状态" width="220px" align="center">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.auditStatus === 2" size="small" type="warning">待审核</el-tag>
+          <el-tag v-if="row.auditStatus === 1" size="small" type="success">审核通过</el-tag>
+          <!-- 未通过原因展示 -->
+          <template v-if="row.auditStatus === 0">
+            <!-- <span class="status danger">审核未通过&nbsp;</span> -->
+            <el-popover
+              placement="top-start"
+              title="审核说明"
+              width="400"
+              trigger="hover"
+              :content="row.invalidReason"
+            >
+              <el-tag slot="reference" size="small" type="danger" class="reason">
+                <span>审核未通过</span>
+                <span class="el-icon-question status danger " />
+              </el-tag>
+            </el-popover>
+            <!-- 未通过原因展示END -->
+          </template>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="上线状态" width="140px" align="center">
+        <template slot-scope="{row}">
+          <!-- 只有审核通过了才能操作上下线 auditStatus :审核状态 -->
+          <template v-if="row.auditStatus === 1">
+            <template v-if="row.status === 0">
+              <span style="margin-right:10px;" class="status danger">已下线</span>
+              <el-button v-if="isProxy" type="primary" size="mini" @click="handleChangeStatus(row)">上线</el-button>
+            </template>
+            <template v-else>
+              <span style="margin-right:10px;" class="status success ">已上线</span>
+              <el-button v-if="isProxy" type="info" size="mini" @click="handleChangeStatus(row)">下线</el-button>
+            </template>
+          </template>
+          <template v-else-if="row.auditStatus === 2">
+            <!-- <el-tag type="warning">待上线</el-tag> -->
+            <span style="margin-right:10px;" class="status warning">待上线</span>
+          </template>
+          <template v-else>
+            <!-- <el-tag type="warning">待上线</el-tag> -->
+            <span style="margin-right:10px;" class="status danger">已下线</span>
+          </template>
+        </template>
+      </el-table-column>
+      <el-table-column label="创建时间" class-name="status-col" width="300px" align="center">
+        <template slot-scope="{row}">
+          <span>{{ row.createTime | formatTime }}</span>
+        </template>
+      </el-table-column>
+
+      <!-- <el-table-column v-if="false" label="创建人" width="180px" align="center" prop="createBy" /> -->
+      <el-table-column label="操作" align="center" width="240px" class-name="small-padding fixed-width">
+        <template slot-scope="{row}">
+          <el-button type="primary" size="mini" @click="$_navigationTo(`edit?id=${row.doctorId}`)">
+            编辑
+          </el-button>
+          <el-button type="danger" size="mini" @click="handleRemoveDoctor(row)">
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 页码 -->
+    <pagination v-show="total>0" :total="total" :page.sync="listQuery.pageNum" :limit.sync="listQuery.pageSize" @pagination="getList" />
+  </div>
+</template>
+
+<script>
+import Pagination from '@/components/Pagination' // secondary package based on el-pagination
+import { mapGetters } from 'vuex'
+import { formatDate } from '@/utils'
+import { fetchDoctorList, removeDoctor, doctorStatusChange } from '@/api/doctor'
+
+export default {
+  components: { Pagination },
+  filters: {
+    formatTime(time) {
+      if (!time) {
+        return ''
+      }
+      return formatDate(time, 'yyyy-MM-DD HH:mm:ss')
+    }
+  },
+  data() {
+    return {
+      listLoading: false,
+      tableKey: 0,
+      total: 0,
+      listQuery: {
+        listType: 1,
+        doctorName: '',
+        auditStatus: '',
+        status: '',
+        pageNum: 1,
+        pageSize: 10
+      },
+      list: []
+    }
+  },
+  computed: {
+    ...mapGetters(['authUserId', 'proxyInfo']),
+    isProxy() {
+      return this.proxyInfo || this.userIdentity !== 1
+    }
+  },
+  created() {
+    this.getList()
+  },
+  methods: {
+    // 获取列表
+    getList() {
+      this.listQuery.authUserId = this.proxyInfo?.authUserId || this.authUserId
+      fetchDoctorList(this.listQuery).then(res => {
+        console.log(res)
+        this.list = res.data.list
+        this.total = res.data.total
+      })
+    },
+    // 修改状态
+    handleChangeStatus(row) {
+      const status = row.status === 1 ? 0 : 1
+
+      doctorStatusChange({ doctorId: row.doctorId, status }).then(res => {
+        this.$message.success('状态修改成功')
+        this.getList()
+      })
+    },
+    // 删除
+    async handleRemoveDoctor(row) {
+      const text = await this.$confirm('确认删除该医师信息吗?删除后不可恢复', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).catch(() => {
+        this.$message.info('已取消操作')
+      })
+      if (text !== 'confirm') return
+
+      removeDoctor({ doctorId: row.doctorId }).then(res => {
+        this.$message.success('删除成功')
+        this.getList()
+      })
+    },
+    // 表格索引
+    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;
+  }
+}
+</style>

+ 90 - 0
src/views/normal/feedback/detail.vue

@@ -0,0 +1,90 @@
+<template>
+  <div class="app-container">
+    <div class="form">
+      <h2>反馈处理</h2>
+      <el-form ref="formRef" label-width="100px" :rules="formRules" :model="formData">
+        <el-form-item label="机构名称:">
+          {{ feedbackData.clubName }}
+        </el-form-item>
+        <el-form-item label="手机号:">{{ feedbackData.mobile }}</el-form-item>
+        <el-form-item label="反馈内容:">
+          <div style="overflow-wrap:anywhere;text-align:justify">{{ feedbackData.content }}</div>
+        </el-form-item>
+        <el-form-item label="处理状态:">
+          <span v-if="feedbackData.handleStatus===0" class="status danger">未处理</span>
+          <span v-if="feedbackData.handleStatus===1" class="status success">已处理</span>
+        </el-form-item>
+        <el-form-item label="处理结果:" prop="handleResult">
+          <el-input v-model="formData.handleResult" type="textarea" placeholder="请添加处理结果" />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="info" @click="$_back">返回</el-button>
+          <el-button type="primary" @click="submit">提交</el-button>
+        </el-form-item>
+      </el-form>
+    </div>
+  </div>
+</template>
+
+<script>
+import { getFeedbackDetail, handleFeedback } from '@/api/auth'
+export default {
+  data() {
+    return {
+      feedbackId: '',
+      formData: {
+        handleResult: ''
+      },
+      formRules: {
+        handleResult: { required: true, message: '处理结果不能为空', tigger: 'blur' }
+      },
+      feedbackData: {}
+    }
+  },
+  created() {
+    this.feedbackId = this.$route.query.feedbackId
+    this.getDetail()
+  },
+  methods: {
+    // 提交处理信息
+    submit() {
+      this.$refs.formRef.validate(valid => {
+        if (!valid) return
+        handleFeedback({ feedbackId: this.feedbackId, handleResult: this.formData.handleResult })
+          .then(res => {
+            if (res.code !== 0) return
+            this.$message({
+              message: res.data,
+              duration: 500,
+              type: 'success'
+            })
+            this.$store.dispatch('tagsView/delView', this.$route)
+            this.$router.back()
+          })
+      })
+    },
+    // 获取反馈信息
+    getDetail() {
+      getFeedbackDetail({ feedbackId: this.feedbackId }).then(res => {
+        console.log(res)
+        this.feedbackData = res.data
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.form{
+  width: 800px;
+  margin: 30px auto;
+  .el-button{
+    width: 120px;
+  }
+  h2{
+    text-align: center;
+    margin-bottom: 45px;
+    color: #444;
+  }
+}
+</style>

+ 217 - 0
src/views/normal/feedback/index.vue

@@ -0,0 +1,217 @@
+<template>
+  <div class="app-container">
+    <!-- 搜索区域 -->
+    <div class="filter-container">
+      <span>机构名称:</span>
+      <el-input
+        v-model="listQuery.clubName"
+        placeholder="机构名称"
+        style="width: 200px"
+        class="filter-item"
+        @keyup.enter.native="getList"
+      />
+      <span>手机号:</span>
+      <el-input v-model="listQuery.mobile" placeholder="手机号" style="width: 200px;" class="filter-item" @keyup.enter.native="handleFilter" />
+      <span>处理状态:</span>
+      <el-select
+        v-model="listQuery.handleStatus"
+        placeholder="处理状态"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="全部" value="" />
+        <el-option label="已处理" :value="1" />
+        <el-option label="未处理" :value="0" />
+      </el-select>
+      <el-button type="primary" icon="el-icon-search" @click="getList">查询</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 label="序号" :index="indexMethod" type="index" width="80" align="center" />
+      <el-table-column type="expand" width="50">
+        <template slot-scope="{row}">
+          <el-form label-position="left" class="table-expand" label-width="110px">
+            <el-form-item label="机构名称:">
+              <span>{{ row.clubName }}</span>
+            </el-form-item>
+            <el-form-item label="手机号:">
+              <span>{{ row.mobile }}</span>
+            </el-form-item>
+            <el-form-item label="提交时间:">
+              <span>{{ row.commitTime | formatTime }}</span>
+            </el-form-item>
+            <el-form-item label="处理状态:">
+              <span>
+                <el-tag v-if="row.handleStatus === 0" size="small" type="danger">未处理</el-tag>
+                <el-tag v-if="row.handleStatus === 1" size="small" type="success">已处理</el-tag>
+              </span>
+            </el-form-item>
+            <el-form-item label="反馈内容:">
+              <span style="overflow-wrap:anywhere;text-align:justify">{{ row.content }}</span>
+            </el-form-item>
+            <el-form-item label="处理结果:">
+              <span>{{ row.handleResult }}</span>
+            </el-form-item>
+          </el-form>
+        </template>
+      </el-table-column>
+      <el-table-column label="机构名称" prop="clubName" align="center" />
+      <el-table-column label="手机号" prop="mobile" width="120" align="center" />
+      <el-table-column label="反馈内容" prop="content" align="center">
+        <template slot-scope="{row}">
+          <span class="content">{{ row.content }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="提交时间" width="180px" align="center">
+        <template slot-scope="{row}">
+          <span v-if="row.auditStatus!==2">{{ row.commitTime | formatTime }}</span>
+          <span v-else>—</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="处理状态" width="100px" align="center">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.handleStatus === 0" size="small" type="danger">未处理</el-tag>
+          <el-tag v-if="row.handleStatus === 1" size="small" type="success">已处理</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="处理结果" prop="handleResult" align="center">
+        <template slot-scope="{row}">
+          <span v-if="row.handleStatus === 1" class="content">{{ row.handleResult }}</span>
+          <span v-else>—</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="处理时间" width="180px" align="center">
+        <template slot-scope="{row}">
+          <span v-if="row.handleStatus === 1">{{ row.handleTime | formatTime }}</span>
+          <span v-else>—</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" width="120px" align="center">
+        <template slot-scope="{row}">
+          <el-button type="primary" size="mini" style="margin-right:5px" icon="el-icon-edit" @click="$_navigationTo(`/feedback/detail?feedbackId=${row.feedbackId}`)">处理</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 表格区域END -->
+    <!-- 页码 -->
+    <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'
+import { formatDate } from '@/utils'
+import { mapGetters } from 'vuex'
+import { getFeedbackList } from '@/api/auth'
+export default {
+  components: { Pagination },
+  filters: {
+    formatTime(time) {
+      if (!time) {
+        return ''
+      }
+      return formatDate(time, 'yyyy-MM-DD HH:mm:ss')
+    }
+  },
+  data() {
+    return {
+      listLoading: false,
+      listQuery: {
+        authUserId: '',
+        clubName: '',
+        handleStatus: '',
+        mobile: '',
+        pageNum: 1, // 页码
+        pageSize: 10 // 分页大小
+      },
+      total: 0,
+      list: []
+    }
+  },
+  computed: {
+    ...mapGetters(['authUserId', 'userIdentity', 'proxyInfo'])
+  },
+  created() {
+    this.getList()
+  },
+  methods: {
+    // 获取列表数据
+    getList() {
+      this.listQuery.authUserId = this.authUserId
+      console.log(this.listQuery)
+      getFeedbackList(this.listQuery).then(res => {
+        console.log(res)
+        if (res.code !== 0) return
+        this.list = res.data.list
+        this.total = res.data.total
+      }).catch(err => {
+        console.log(err)
+      })
+    },
+    // 初始化预览图片列表
+    initPreviewList(list) {
+      list.forEach(item => this.srcList.push(item.articleCover))
+    },
+    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;
+  }
+}
+.content{
+  display: block;
+  overflow: hidden !important;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+}
+.el-table .cell {
+  overflow: visible;
+}
+.el-badge{
+  margin: 0 6px;
+}
+// .table-expand {
+//     font-size: 0;
+//     padding-left: 130px;
+//   }
+//   .table-expand label {
+//     width: 90px;
+//     color: #99a9bf;
+//   }
+//   .table-expand .el-form-item {
+//     margin-right: 0;
+//     margin-bottom: 0;
+//     width: 30%;
+//   }
+</style>

+ 142 - 0
src/views/normal/material/article/edit.vue

@@ -0,0 +1,142 @@
+<template>
+  <div v-loading="isLoading" class="app-container">
+    <div class="form">
+      <el-form ref="formRef" label-width="120px" :model="formData" :rules="formRules">
+        <el-form-item label="标题:" prop="articleTitle">
+          <el-input v-model="formData.articleTitle" placeholder="请输入文章标题" maxlength="50" show-word-limit />
+        </el-form-item>
+        <el-form-item label="头图:" prop="articleImage">
+          <upload-image tip-title="128px * 128px" :file-list="imagelist" @success="handleSussces" @error="handleError" />
+          <el-input v-model="formData.articleImage" class="hiddenInput" />
+        </el-form-item>
+        <el-form-item label="文章内容:" prop="articleContent">
+          <tinymce v-model="formData.articleContent" :token="token" :action="action" :height="300" />
+          <el-input v-model="formData.articleContent" class="hiddenInput" />
+        </el-form-item>
+      </el-form>
+    </div>
+    <div class="submit-btn">
+      <el-button type="primary" @click="submit">保存</el-button>
+      <el-button type="warning" @click="$_back()">返回</el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+import { mapGetters } from 'vuex'
+import UploadImage from '../components/uploadImage'
+import Tinymce from '@/components/Tinymce'
+import { getToken } from '@/utils/auth'
+import { saveArticle, getArticleDeatil } from '@/api/doc'
+export default {
+  components: { UploadImage, Tinymce },
+  data() {
+    return {
+      editType: 0, // 编辑模式 1:添加文章  2:修改文章
+      formData: {
+        articleId: '', // 文章id
+        authUserId: '', // 用户id
+        articleTitle: '', // 文章标题
+        articleImage: '', // 文章封面
+        articleContent: '' // 文章内容
+      },
+      // 表单验证规则
+      formRules: {
+        articleTitle: [
+          { required: true, message: '文章标题不能为空', trigger: 'blur' },
+          { min: 1, max: 50, message: '长度在 1 到 50 个字符', trigger: 'blur' }
+        ],
+        articleImage: [{ required: true, message: '文章必须上传封面', trigger: 'change' }],
+        articleContent: [{ required: true, message: '文章内容不能为空', trigger: 'change' }]
+      },
+      // 表单是否处于加载状态
+      isLoading: true,
+      // 当前用户登录的token
+      token: '',
+      // 富文本框上传图片的接口
+      action: process.env.VUE_APP_UPLOAD_API + '/upload/image',
+      // 封面图片列表
+      imagelist: []
+    }
+  },
+  computed: {
+    ...mapGetters(['authUserId'])
+  },
+  created() {
+    this.token = getToken()
+    this.formData.articleId = this.$route.query.articleId || ''
+    this.editType = this.formData.articleId ? 2 : 1
+    this.initFormData()
+  },
+  mounted() {
+    setTimeout(() => {
+      this.isLoading = false
+    }, 500)
+  },
+  methods: {
+    // 保存文章
+    submit() {
+      this.formData.authUserId = this.authUserId
+      this.$refs.formRef.validate(valid => {
+        if (!valid) return
+        this.isLoading = true
+        saveArticle(this.formData).then(res => {
+          console.log(res)
+          if (res.code !== 0) return
+          this.$message.success(res.data)
+          // 如果保存文章成功就要关闭当前页面
+          this.$store.dispatch('tagsView/delView', this.$route)
+          this.$router.back()
+        }).finally(() => {
+          this.isLoading = false
+        })
+      })
+    },
+    // 初始化表单回显数据
+    initFormData() {
+      if (!this.formData.articleId) return
+      getArticleDeatil({ articleId: this.formData.articleId }).then(res => {
+        for (const key in this.formData) {
+          if (Object.hasOwnProperty.call(this.formData, key)) {
+            this.formData[key] = res.data[key]
+          }
+        }
+        this.imagelist = [{ name: '文章封面', url: this.formData.articleImage }]
+        console.log(res)
+      })
+    },
+    // 封面图片上传成功
+    handleSussces(res) {
+      console.log(res)
+      if (!res.data) {
+        this.imagelist = []
+        return
+      }
+      this.formData.articleImage = res.data
+    },
+    // 封面图片上传失败
+    handleError() {
+      this.imagelist = []
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.app-container{
+  .form{
+    width: 1000px;
+    margin: 30px auto;
+  }
+}
+.hiddenInput{
+  height: 0;
+  display: none;
+}
+.submit-btn {
+  text-align: center;
+  .el-button {
+    width: 140px;
+  }
+}
+</style>

+ 279 - 0
src/views/normal/material/article/index.vue

@@ -0,0 +1,279 @@
+<template>
+  <div class="app-container">
+    <!-- 搜索区域 -->
+    <div class="filter-container">
+      <span>文章标题:</span>
+      <el-input
+        v-model="listQuery.articleTitle"
+        placeholder="文章标题"
+        style="width: 200px"
+        class="filter-item"
+        @keyup.enter.native="getList"
+      />
+      <span>审核状态:</span>
+      <el-select
+        v-model="listQuery.auditStatus"
+        placeholder="审核状态"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="全部" value="" />
+        <el-option label="待审核" :value="2" />
+        <el-option label="审核通过" :value="1" />
+        <el-option label="审核未通过" :value="0" />
+      </el-select>
+      <span>上线状态:</span>
+      <el-select
+        v-model="listQuery.status"
+        placeholder="上线状态"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="全部" value="" />
+        <el-option label="已上线" :value="1" />
+        <el-option label="待上线" :value="2" />
+        <el-option label="未上线" :value="0" />
+      </el-select>
+      <el-button type="primary" icon="el-icon-search" @click="getList">查询</el-button>
+      <el-button
+        v-if="userIdentity === 2 || proxyInfo !== null"
+        icon="el-icon-edit"
+        type="primary"
+        @click="$_navigationTo(`/doc/article-edit`)"
+      >添加文章</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 label="序号" :index="indexMethod" type="index" width="80" align="center" />
+      <el-table-column label="文章标题" prop="articleTitle" align="center" />
+      <el-table-column label="文章头图" width="200" align="center">
+        <template slot-scope="{ row }">
+          <el-image
+            style="width: 50px; height: 50px"
+            :src="row.articleImage"
+          /></template>
+      </el-table-column>
+      <el-table-column label="审核状态" width="180px" align="center">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.auditStatus === 2" size="small" type="warning">待审核</el-tag>
+          <el-tag v-if="row.auditStatus === 1" size="small" type="success">审核通过</el-tag>
+          <!-- 未通过原因展示 -->
+          <template v-if="row.auditStatus === 0">
+            <!-- <span class="status danger">审核未通过&nbsp;</span> -->
+            <el-popover
+              placement="top-start"
+              title="审核说明"
+              width="400"
+              trigger="hover"
+              :content="row.invalidReason"
+            >
+              <el-tag slot="reference" size="small" type="danger" class="reason">
+                <span>审核未通过</span>
+                <span class="el-icon-question status danger " />
+              </el-tag>
+            </el-popover>
+            <!-- 未通过原因展示END -->
+          </template>
+        </template>
+      </el-table-column>
+      <el-table-column label="上线状态" width="180px" align="center">
+        <template slot-scope="{ row }">
+          <!-- 只有审核通过了才能操作上下线 auditStatus :审核状态 -->
+          <template v-if="row.auditStatus === 1">
+            <template v-if="row.status === 0">
+              <span style="margin-right:10px;" class="status danger">已下线</span>
+              <el-button
+                v-if="userIdentity === 2 || proxyInfo !== null"
+                type="primary"
+                size="mini"
+                @click="handleChangeStatus(row)"
+              >上线</el-button>
+            </template>
+            <template v-else>
+              <span style="margin-right:10px;" class="status success ">已上线</span>
+              <el-button
+                v-if="userIdentity === 2 || proxyInfo !== null"
+                type="info"
+                size="mini"
+                plain
+                @click="handleChangeStatus(row)"
+              >下线</el-button>
+            </template>
+          </template>
+          <template v-else>
+            <!-- <el-tag type="warning">待上线</el-tag> -->
+            <span style="margin-right:10px;" class="status warning">待上线</span>
+          </template>
+        </template>
+      </el-table-column>
+      <el-table-column label="创建时间" width="240px" align="center">
+        <template slot-scope="{ row }">
+          {{ row.createTime | formatTime }}
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" width="240px" align="center">
+        <template slot-scope="{ row }">
+          <el-button
+            type="primary"
+            size="mini"
+            style="margin-right:5px"
+            icon="el-icon-edit"
+            @click="$_navigationTo(`/doc/article-edit?articleId=${row.articleId}`)"
+          >编辑</el-button>
+          <el-button
+            type="danger"
+            size="mini"
+            style="margin-right:5px"
+            icon="el-icon-s-check"
+            @click="handleRemoveArticle(row)"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 表格区域END -->
+    <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 { formatDate } from '@/utils'
+import { mapGetters } from 'vuex'
+import { changeArticleStatus, getArticleList, removeArticle } from '@/api/doc'
+export default {
+  components: { Pagination },
+  filters: {
+    formatTime(time) {
+      if (!time) {
+        return ''
+      }
+      return formatDate(time, 'yyyy-MM-DD HH:mm:ss')
+    }
+  },
+  data() {
+    return {
+      listLoading: false,
+      total: 0,
+      listQuery: {
+        authUserId: '', // 机构id
+        auditStatus: '', // 审核状态
+        articleTitle: '', // 文章标题
+        listType: 1, // 列表类型:1文章列表,2文章审核列表
+        pageNum: 1, // 页码
+        pageSize: 10, // 分页大小
+        status: '' // 文章状态:0已下线,1已上线,2待上线
+      },
+      list: []
+    }
+  },
+  computed: {
+    ...mapGetters(['authUserId', 'userIdentity', 'proxyInfo'])
+  },
+  created() {
+    this.getList()
+  },
+  methods: {
+    // 获取列表数据
+    getList() {
+      this.listLoading = true
+      this.listQuery.authUserId = this.authUserId
+      getArticleList(this.listQuery)
+        .then(res => {
+          if (res.code !== 0) return
+          this.list = res.data.list
+          console.log(res)
+          this.total = res.data.total
+        })
+        .finally(() => {
+          this.listLoading = false
+        })
+    },
+    // 删除文章
+    async handleRemoveArticle(row) {
+      const text = await this.$confirm('确认删除该文章吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).catch(() => {
+        this.$message.info('已取消操作')
+      })
+      if (text !== 'confirm') return
+      removeArticle({ articleId: row.articleId })
+        .then(res => {
+          if (res.code !== 0) return
+          this.$message.success(res.data)
+          this.getList(this.listQuery)
+        })
+    },
+    // 状态改变
+    handleChangeStatus(item) {
+      this.listLoading = true
+      // const params = {
+      //   authId: item.authId,
+      //   status: item.status ? 1 : 0
+      // }
+      console.log(item)
+      const params = {
+        articleId: item.articleId,
+        status: item.status === 1 ? 0 : 1
+      }
+      changeArticleStatus(params).then(res => {
+        // this.$message.success(res.data)
+        this.$message({
+          message: res.data,
+          duration: 500,
+          type: 'success'
+        })
+        this.getList()
+      }).catch(err => {
+        console.log(err)
+      }).finally(() => {
+        this.listLoading = false
+      })
+    },
+    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;
+}
+</style>

+ 488 - 0
src/views/normal/material/file/index.vue

@@ -0,0 +1,488 @@
+<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-select
+        v-model="listQuery.auditStatus"
+        placeholder="审核状态"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="全部" value="" />
+        <el-option label="待审核" :value="2" />
+        <el-option label="审核通过" :value="1" />
+        <el-option label="审核未通过" :value="0" />
+      </el-select>
+      <span>上线状态:</span>
+      <el-select
+        v-model="listQuery.status"
+        placeholder="上线状态"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="全部" value="" />
+        <el-option label="已上线" :value="1" />
+        <el-option label="待上线" :value="2" />
+        <el-option label="未上线" :value="0" />
+      </el-select>
+      <el-button type="primary" icon="el-icon-search" @click="getList">查询</el-button>
+      <el-button
+        v-if="userIdentity === 2 || proxyInfo !== null"
+        icon="el-icon-edit"
+        type="primary"
+        @click="handleShowDialog('add')"
+      >添加文件</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 label="序号" :index="indexMethod" type="index" width="80" align="center" />
+      <el-table-column label="文件标题" prop="fileTitle" align="center" />
+      <el-table-column label="审核状态" width="180px" align="center">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.auditStatus === 2" size="small" type="warning">待审核</el-tag>
+          <el-tag v-if="row.auditStatus === 1" size="small" type="success">审核通过</el-tag>
+          <!-- 未通过原因展示 -->
+          <template v-if="row.auditStatus === 0">
+            <!-- <span class="status danger">审核未通过&nbsp;</span> -->
+            <el-popover placement="top-start" title="审核说明" width="400" trigger="hover" :content="row.invalidReason">
+              <el-tag slot="reference" size="small" type="danger" class="reason">
+                <span>审核未通过</span>
+                <span class="el-icon-question status danger " />
+              </el-tag>
+            </el-popover>
+            <!-- 未通过原因展示END -->
+          </template>
+        </template>
+      </el-table-column>
+      <el-table-column label="上线状态" width="180px" align="center">
+        <template slot-scope="{ row }">
+          <!-- 只有审核通过了才能操作上下线 auditStatus :审核状态 -->
+          <template v-if="row.auditStatus === 1">
+            <template v-if="row.status === 0">
+              <span style="margin-right:10px;" class="status danger">已下线</span>
+              <el-button
+                v-if="userIdentity === 2 || proxyInfo !== null"
+                type="primary"
+                size="mini"
+                @click="handleChangeStatus(row)"
+              >上线</el-button>
+            </template>
+            <template v-else>
+              <span style="margin-right:10px;" class="status success ">已上线</span>
+              <el-button
+                v-if="userIdentity === 2 || proxyInfo !== null"
+                type="info"
+                size="mini"
+                plain
+                @click="handleChangeStatus(row)"
+              >下线</el-button>
+            </template>
+          </template>
+          <template v-else>
+            <!-- <el-tag type="warning">待上线</el-tag> -->
+            <span style="margin-right:10px;" class="status warning">待上线</span>
+          </template>
+        </template>
+      </el-table-column>
+      <el-table-column label="创建时间" width="240px" align="center">
+        <template slot-scope="{ row }">
+          {{ row.createTime | formatTime }}
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" width="280px" align="center">
+        <template slot-scope="{ row }">
+          <el-button
+            type="primary"
+            size="mini"
+            style="margin-right:5px"
+            icon="el-icon-view"
+            @click="handlePreviewFile(row)"
+          >预览</el-button>
+          <el-button
+            type="primary"
+            size="mini"
+            style="margin-right:5px"
+            icon="el-icon-edit"
+            @click="handleShowDialog('edit', row)"
+          >编辑</el-button>
+          <el-button
+            type="danger"
+            size="mini"
+            style="margin-right:5px"
+            icon="el-icon-s-check"
+            @click="handleRemoveFile(row)"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 表格区域END -->
+    <pagination
+      v-show="total > 0"
+      :total="total"
+      :page.sync="listQuery.pageNum"
+      :limit.sync="listQuery.pageSize"
+      @pagination="getList(listQuery)"
+    />
+    <!-- 视频预览对话框 -->
+    <el-dialog
+      :title="dialogTitle"
+      :visible.sync="dialogVisible"
+      width="40%"
+      :close-on-click-modal="false"
+      :close-on-press-escape="false"
+      @closed="dialogColosed"
+      @close="beforeDialogClose"
+    >
+      <el-form ref="formRef" :model="dialogData" label-width="110px" :rules="dialogFormRules">
+        <el-form-item label="标题:" prop="fileTitle">
+          <el-input v-model="dialogData.fileTitle" maxlength="50" show-word-limit />
+        </el-form-item>
+        <el-form-item label="上传文件:" prop="filePreviewUrl" style="margin-bottom:0">
+          <div class="file-upload-box">
+            <!-- 上传文件组件 -->
+            <el-upload
+              ref="uploadFileRef"
+              accept=".pdf"
+              :class="{ hidden: hasFile }"
+              :auto-upload="false"
+              :headers="headers"
+              :action="action"
+              :on-success="fileUploadSuccess"
+              :on-change="fileUploadChange"
+              :on-remove="fileUploadRemove"
+              :before-upload="beforeUpload"
+              :file-list="fileList"
+            >
+              <el-button size="mini" type="primary" style="width:100%">上传文件</el-button>
+            </el-upload>
+            <el-input v-model="dialogData.filePreviewUrl" type="hidden" class="hiddenInput" />
+          </div>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="dialogVisible = false">取 消</el-button>
+        <el-button type="primary" :loading="submitLoading" @click="handleSave">提 交</el-button>
+      </div>
+    </el-dialog>
+    <!-- 视频预览对话框END -->
+  </div>
+</template>
+
+<script>
+import Pagination from '@/components/Pagination' // secondary package based on el-pagination
+import { formatDate } from '@/utils'
+import { mapGetters } from 'vuex'
+import { getToken } from '@/utils/auth'
+import { changeFileStatus, getFileList, removeFile, saveFile } from '@/api/doc'
+import openWindow from '@/utils/open-window'
+export default {
+  components: { Pagination },
+  filters: {
+    formatTime(time) {
+      if (!time) {
+        return ''
+      }
+      return formatDate(time, 'yyyy-MM-DD HH:mm:ss')
+    }
+  },
+  data() {
+    return {
+      listLoading: false, // 列表加载
+      submitLoading: false, // 按钮加载
+      total: 0, // 列表条数
+      dialogVisible: false, // 是否显示dialog
+      dialogTitle: '添加文件', // dialog标题
+      hasFile: false, // 是否上传了文件
+      previewUrl: '', // 上传文件成功后的url
+      downloadUrl: '',
+      chooseNewFile: false, // 是否选择了新的图片上传
+      listQuery: {
+        authUserId: '', // 供应商用户id
+        listType: 1, // 列表类型:1视频列表,2视频审核列表
+        fileTitle: '', // 文件标题
+        auditStatus: '', // 审核状态:0审核未通过,1审核通过,2待审核
+        status: '', // 视频状态:0已下线,1已上线,2待上线
+        pageNum: 1, // 页码
+        pageSize: 10 // 分页大小
+      },
+      fileList: [],
+      // dialog表单中的数据
+      dialogData: {
+        authUserId: '',
+        fileTitle: '',
+        fileId: '',
+        // fileUrl: '',
+        fileName: '',
+        filePreviewUrl: '',
+        fileDownloadUrl: ''
+      },
+      // dialog表单数据校验规则
+      dialogFormRules: {
+        fileTitle: [{ required: true, message: '标题不能为空', trigger: 'blur' }],
+        filePreviewUrl: [{ required: true, message: '文件不能为空', trigger: 'change' }]
+      },
+      list: []
+    }
+  },
+  computed: {
+    ...mapGetters(['authUserId', 'userIdentity', 'proxyInfo']),
+    headers() {
+      return {
+        'X-Token': getToken()
+      }
+    },
+    action() {
+      return `${process.env.VUE_APP_UPLOAD_API}/upload/file`
+    }
+  },
+  created() {
+    this.getList()
+  },
+  methods: {
+
+    // 小窗口浏览pdf文件
+    handlePreviewFile(row) {
+      console.log(row)
+      openWindow(row.filePreviewUrl, row.fileTitle, row.fileTitle, 1200, 600)
+    },
+
+    // 获取列表数据
+    getList() {
+      this.listLoading = true
+      this.listQuery.authUserId = this.authUserId
+      getFileList(this.listQuery)
+        .then(res => {
+          if (res.code !== 0) return
+          this.list = res.data.list
+          this.total = res.data.total
+          console.log(res)
+        })
+        .finally(() => {
+          this.listLoading = false
+        })
+    },
+    // 点击保存按钮
+    handleSave() {
+      if (!this.dialogData.fileTitle || !this.dialogData.filePreviewUrl) {
+        this.$refs.formRef.validateField('fileTitle')
+        this.$refs.formRef.validateField('filePreviewUrl')
+        return
+      }
+      // 对标题字段进行规则校验
+      console.log(this.dialogData)
+      this.$refs.formRef.validateField('fileTitle', error => {
+        if (!error) {
+          this.submitLoading = true
+          this.hasFile && !this.chooseNewFile ? this.save() : this.$refs.uploadFileRef.submit()
+        }
+      })
+    },
+    // 调用保存数据接口
+    save() {
+      this.$refs.formRef.validate(valide => {
+        if (!valide) return
+        this.dialogData.authUserId = this.authUserId
+        if (this.previewUrl && this.downloadUrl) {
+          this.dialogData.filePreviewUrl = this.previewUrl
+          this.dialogData.fileDownloadUrl = this.downloadUrl
+        }
+        console.log(this.dialogData)
+        console.log('保存')
+        saveFile(this.dialogData)
+          .then(res => {
+            console.log(res)
+            if (res.code !== 0) return
+            this.dialogVisible = false
+            this.getList()
+            this.$message({
+              type: 'success',
+              message: res.data,
+              duration: 500
+            })
+          })
+          .finally(() => {
+            this.submitLoading = false
+          })
+      })
+    },
+    // 删除视频
+    async handleRemoveFile(row) {
+      const text = await this.$confirm('视频删除后不可恢复,确认删除该视频吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).catch(() => {
+        this.$message.info('已取消操作')
+      })
+      if (text !== 'confirm') return
+      removeFile({ fileId: row.fileId }).then(res => {
+        if (res.code !== 0) return
+        this.$message.success(res.data)
+        this.getList()
+      })
+    },
+    // 显示dialog对话框
+    handleShowDialog(type, row) {
+      this.dialogTitle = type === 'add' ? '添加文件' : '修改文件'
+      this.$refs?.formRef?.resetFields()
+      this.dialogVisible = true
+      if (type !== 'add') {
+        this.setDialogData(row)
+      }
+    },
+    // 设置表单初始值
+    setDialogData(row) {
+      console.log(row)
+      if (!row) return
+      for (const key in this.dialogData) {
+        if (Object.hasOwnProperty.call(this.dialogData, key)) {
+          this.dialogData[key] = row[key]
+        }
+      }
+      if (this.dialogData.filePreviewUrl) {
+        this.fileList = [{ name: row.fileName, url: row.filePreviewUrl }]
+        this.hasFile = true
+      }
+    },
+    // dialog对话框关闭时的回调
+    dialogColosed() {
+      this.dialogData.authUserId = ''
+      this.dialogData.fileTitle = ''
+      this.dialogData.fileId = ''
+      this.dialogData.filePreviewUrl = ''
+      this.dialogData.fileDownloadUrl = ''
+      this.dialogData.fileName = ''
+      this.previewUrl = ''
+      this.downloadUrl = ''
+      this.chooseNewFile = false
+      this.hasFile = false
+      this.fileList = []
+      this.submitLoading = false
+      console.log(this.dialogData)
+    },
+    // 对话框关闭前的回调
+    beforeDialogClose() {
+      console.log('对话框关闭')
+      // this.$refs.formRef.clearValidate()
+      // 停止上传文件
+      this.$refs.formRef.resetFields()
+      this.$refs.uploadFileRef.abort()
+    },
+    // 上传文件成功
+    fileUploadSuccess(response) {
+      // this.dialogData.fileUrl = response.fileUrl
+      this.previewUrl = response.previewUrl
+      this.downloadUrl = response.downloadUrl
+      this.dialogData.fileName = response.fileName
+      this.save()
+      console.log(response)
+    },
+    // 上传文件成功,选择文件,上传文件失败的回调
+    fileUploadChange(file, fileList) {
+      this.hasFile = fileList.length > 0
+      this.dialogData.filePreviewUrl = '-'
+      this.dialogData.fileDownloadUrl = '-'
+      this.chooseNewFile = true
+    },
+    // 移除文件
+    fileUploadRemove(file, fileList) {
+      this.dialogData.filePreviewUrl = ''
+      this.dialogData.fileDownloadUrl = ''
+      this.hasFile = fileList.length > 0
+    },
+    beforeUpload(file, fileList) {
+      const flag = file.size <= 100 * 1024 * 1204
+      if (!flag) {
+        this.$message({
+          message: '文件大小超过100MB,请重新选择!',
+          duration: 1000,
+          type: 'warning'
+        })
+        this.fileList = []
+      }
+      return flag
+    },
+    // 状态改变
+    handleChangeStatus(item) {
+      this.listLoading = true
+      // const params = {
+      //   authId: item.authId,
+      //   status: item.status ? 1 : 0
+      // }
+      console.log(item)
+      const params = {
+        fileId: item.fileId,
+        status: item.status === 1 ? 0 : 1
+      }
+      changeFileStatus(params)
+        .then(res => {
+          // this.$message.success(res.data)
+          this.$message({
+            message: res.data,
+            duration: 500,
+            type: 'success'
+          })
+          this.getList()
+        })
+        .catch(err => {
+          console.log(err)
+        })
+        .finally(() => {
+          this.listLoading = false
+        })
+    },
+    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;
+}
+</style>

+ 172 - 0
src/views/normal/material/image/edit.vue

@@ -0,0 +1,172 @@
+<template>
+  <div class="app-container">
+    <div class="form">
+      <el-form ref="formRef" :model="formData" :rules="formRules" label-width="70px">
+        <el-form-item label="标题:" prop="imageTitle">
+          <el-input v-model="formData.imageTitle" placeholder="图片列表标题" maxlength="50" show-word-limit />
+        </el-form-item>
+        <el-form-item label="图片:" prop="imageFlag">
+          <el-upload
+            class="upload-control"
+            :class="{hidden:count === 8}"
+            list-type="picture-card"
+            accept=".png,.jpg,.gif"
+            :action="action"
+            :headers="headers"
+            :multiple="true"
+            :limit="8"
+            :file-list="imageList"
+            :on-remove="handleRemove"
+            :on-success="handleUploadSuccess"
+            :before-upload="beforeUpload"
+          >
+            <i class="el-icon-picture-outline" />
+            <div slot="tip" class="el-upload__tip" style="color:#999"><span style="color:red">*</span>最多只能上传8张图片</div>
+          </el-upload>
+          <el-input v-model="formData.imageFlag" class="hiddenInput" />
+        </el-form-item>
+      </el-form>
+      <div class="submit-btn">
+        <el-button type="primary" @click="submit">保存</el-button>
+        <el-button type="warning" @click="$_back()">返回</el-button>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { getToken } from '@/utils/auth'
+import { mapGetters } from 'vuex'
+import { getImageDetail, saveImage } from '@/api/doc'
+export default {
+  data() {
+    return {
+      count: 0, // 图片个数
+      imageId: '', // 图片列表id
+      imageList: [], // 回显图片列表
+      imageArr: [], // 上传的图片列表
+      formData: {
+        imageTitle: '', // 图片标题
+        imageFlag: '' // 是否上传图片的标识 不为空则代表上传过图片
+      },
+      formRules: {
+        imageTitle: [
+          { required: true, message: '标题不能为空', trigger: 'blur' },
+          { max: 50, message: '标题不能超过50个字符', trigger: 'blur' }
+        ],
+        imageFlag: [
+          { required: true, message: '图片列表不能为空', trigger: 'change' }
+        ]
+      }
+    }
+  },
+  computed: {
+    ...mapGetters(['authUserId']),
+    headers() {
+      return {
+        'X-Token': getToken()
+      }
+    },
+    action() {
+      return `${process.env.VUE_APP_UPLOAD_API}/upload/image`
+    }
+  },
+  watch: {
+    count(nVal, oVal) {
+      this.formData.imageFlag = (nVal > 0 ? 'has image' : '')
+    }
+  },
+  created() {
+    this.imageId = this.$route.query.imageId || ''
+    this.initFormData()
+  },
+  methods: {
+    submit() {
+      // 请求参数
+      const params = {
+        imageId: this.imageId,
+        authUserId: this.authUserId,
+        imageTitle: this.formData.imageTitle,
+        imageArr: this.imageArr
+      }
+      // 校验表单数据
+      this.$refs.formRef.validate(valid => {
+        if (!valid) return
+        this.isLoading = true
+        // 保存
+        saveImage(params).then(res => {
+          console.log(res)
+          if (res.code !== 0) return
+          this.$message.success(res.data)
+          // 如果保存文章成功就要关闭当前页面
+          this.$store.dispatch('tagsView/delView', this.$route)
+          this.$router.back()
+        }).finally(() => {
+          this.isLoading = false
+        })
+      })
+    },
+    // 初始化表单数据
+    initFormData() {
+      if (!this.imageId) return
+      getImageDetail({ imageId: this.imageId }).then(res => {
+        console.log(res)
+        const { imageTitle, imageList } = res.data
+        this.formData.imageTitle = imageTitle
+        this.imageArr = imageList
+        this.count = imageList.length
+        for (let i = 0; i < this.count; i++) {
+          this.imageList.push({ name: '', url: imageList[i] })
+        }
+        console.log(this.imageList)
+      })
+    },
+    // 图片上传成功的回调
+    handleUploadSuccess(response, file, fileList) {
+      this.count = fileList.length
+      this.imageArr.push(response.data)
+    },
+    // 移除图片的回调
+    handleRemove(file, fileList) {
+      const removeUrl = this.searchFileUrl(this.imageList, file)
+      const pop = this.imageArr.indexOf(removeUrl)
+      this.imageArr.splice(pop, 1)
+      this.count = fileList.length
+    },
+    beforeUpload(file, fileList) {
+      const flag = file.size <= 5 * 1024 * 1204
+      if (!flag) {
+        this.$message({
+          message: '文件大小超过5MB,请重新选择!',
+          duration: 1000,
+          type: 'warning'
+        })
+        this.fileList = []
+      }
+      return flag
+    },
+    // 根据图片id获取图片
+    searchFileUrl(fileList = [], file) {
+      return fileList.filter(v => v.uid === file.uid)[0]?.url
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.form{
+  width: 700px;
+  margin: 30px auto;
+  .submit-btn {
+    text-align: left;
+    padding-left: 70px;
+    .el-button {
+      width: 140px;
+    }
+  }
+}
+.hiddenInput{
+  height: 0;
+  display: none;
+}
+</style>

+ 250 - 0
src/views/normal/material/image/index.vue

@@ -0,0 +1,250 @@
+<template>
+  <div class="app-container">
+    <!-- 搜索区域 -->
+    <div class="filter-container">
+      <span>图片标题:</span>
+      <el-input
+        v-model="listQuery.imageTitle"
+        placeholder="图片标题"
+        style="width: 200px"
+        class="filter-item"
+        @keyup.enter.native="getList"
+      />
+      <span>审核状态:</span>
+      <el-select
+        v-model="listQuery.auditStatus"
+        placeholder="审核状态"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="全部" value="" />
+        <el-option label="待审核" :value="2" />
+        <el-option label="审核通过" :value="1" />
+        <el-option label="审核未通过" :value="0" />
+      </el-select>
+      <span>上线状态:</span>
+      <el-select
+        v-model="listQuery.status"
+        placeholder="上线状态"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="全部" value="" />
+        <el-option label="已上线" :value="1" />
+        <el-option label="待上线" :value="2" />
+        <el-option label="未上线" :value="0" />
+      </el-select>
+      <el-button type="primary" icon="el-icon-search" @click="getList">查询</el-button>
+      <el-button
+        v-if="userIdentity === 2 || proxyInfo!==null"
+        icon="el-icon-edit"
+        type="primary"
+        @click="$_navigationTo(`/doc/image-edit`)"
+      >添加图片</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 label="序号" :index="indexMethod" type="index" width="80" align="center" />
+      <el-table-column label="图片标题" prop="imageTitle" align="center" />
+      <el-table-column label="审核状态" width="180px" align="center">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.auditStatus === 2" size="small" type="warning">待审核</el-tag>
+          <el-tag v-if="row.auditStatus === 1" size="small" type="success">审核通过</el-tag>
+          <!-- 未通过原因展示 -->
+          <template v-if="row.auditStatus === 0">
+            <!-- <span class="status danger">审核未通过&nbsp;</span> -->
+            <el-popover
+              placement="top-start"
+              title="审核说明"
+              width="400"
+              trigger="hover"
+              :content="row.invalidReason"
+            >
+              <el-tag slot="reference" size="small" type="danger" class="reason">
+                <span>审核未通过</span>
+                <span class="el-icon-question status danger " />
+              </el-tag>
+            </el-popover>
+            <!-- 未通过原因展示END -->
+          </template>
+        </template>
+      </el-table-column>
+      <el-table-column label="上线状态" width="180px" align="center">
+        <template slot-scope="{row}">
+          <!-- 只有审核通过了才能操作上下线 auditStatus :审核状态 -->
+          <template v-if="row.auditStatus === 1">
+            <template v-if="row.status === 0">
+              <span style="margin-right:10px;" class="status danger">已下线</span>
+              <el-button v-if="userIdentity===2 || proxyInfo!==null" type="primary" size="mini" @click="handleChangeStatus(row)">上线</el-button>
+            </template>
+            <template v-else>
+              <span style="margin-right:10px;" class="status success ">已上线</span>
+              <el-button v-if="userIdentity===2 || proxyInfo!==null" type="info" size="mini" plain @click="handleChangeStatus(row)">下线</el-button>
+            </template>
+          </template>
+          <template v-else>
+            <!-- <el-tag type="warning">待上线</el-tag> -->
+            <span style="margin-right:10px;" class="status warning">待上线</span>
+          </template>
+        </template>
+      </el-table-column>
+      <el-table-column label="创建时间" width="240px" align="center">
+        <template slot-scope="{row}">
+          {{ row.createTime | formatTime }}
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" width="240px" align="center">
+        <template slot-scope="{row}">
+          <el-button type="primary" size="mini" style="margin-right:5px" icon="el-icon-edit" @click="$_navigationTo(`/doc/image-edit?imageId=${row.imageId}`)">编辑</el-button>
+          <el-button type="danger" size="mini" style="margin-right:5px" icon="el-icon-s-check" @click="handleRemoveImage(row)">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <pagination v-show="total>0" :total="total" :page.sync="listQuery.pageNum" :limit.sync="listQuery.pageSize" @pagination="getList(listQuery)" />
+    <!-- 表格区域END -->
+  </div>
+</template>
+
+<script>
+import Pagination from '@/components/Pagination' // secondary package based on el-pagination
+import { formatDate } from '@/utils'
+import { mapGetters } from 'vuex'
+import { changeImageStatus, getImageList, removeImage } from '@/api/doc'
+export default {
+  components: { Pagination },
+  filters: {
+    formatTime(time) {
+      if (!time) {
+        return ''
+      }
+      return formatDate(time, 'yyyy-MM-DD HH:mm:ss')
+    }
+  },
+  data() {
+    return {
+      listLoading: false,
+      total: 0,
+      listQuery: {
+        authUserId: '', // 机构id
+        auditStatus: '', // 审核状态
+        imageTitle: '', // 文章标题
+        listType: 1, // 列表类型:1文章列表,2文章审核列表
+        pageNum: 1, // 页码
+        pageSize: 10, // 分页大小
+        status: '' // 文章状态:0已下线,1已上线,2待上线
+      },
+      list: []
+    }
+  },
+  computed: {
+    ...mapGetters(['authUserId', 'userIdentity', 'proxyInfo'])
+  },
+  created() {
+    this.getList()
+  },
+  methods: {
+    // 获取列表数据
+    getList() {
+      this.listLoading = true
+      this.listQuery.authUserId = this.authUserId
+      getImageList(this.listQuery)
+        .then(res => {
+          console.log(res)
+          if (res.code !== 0) return
+          this.list = res.data.list
+          this.total = res.data.total
+        })
+        .finally(() => {
+          this.listLoading = false
+        })
+    },
+
+    // 删除图片
+    async handleRemoveImage(row) {
+      const text = await this.$confirm('确认删除该图片吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).catch(() => {
+        this.$message.info('已取消操作')
+      })
+      if (text !== 'confirm') return
+      removeImage({ imageId: row.imageId })
+        .then(res => {
+          if (res.code !== 0) return
+          this.$message.success(res.data)
+          this.getList(this.listQuery)
+        })
+    },
+    // 状态改变
+    handleChangeStatus(item) {
+      this.listLoading = true
+      // const params = {
+      //   authId: item.authId,
+      //   status: item.status ? 1 : 0
+      // }
+      console.log(item)
+      const params = {
+        imageId: item.imageId,
+        status: item.status === 1 ? 0 : 1
+      }
+      changeImageStatus(params).then(res => {
+        // this.$message.success(res.data)
+        this.$message({
+          message: res.data,
+          duration: 500,
+          type: 'success'
+        })
+        this.getList()
+      }).catch(err => {
+        console.log(err)
+      }).finally(() => {
+        this.listLoading = false
+      })
+    },
+    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;
+}
+</style>

+ 480 - 0
src/views/normal/material/video/index.vue

@@ -0,0 +1,480 @@
+<template>
+  <div class="app-container">
+    <!-- 搜索区域 -->
+    <div class="filter-container">
+      <span>视频标题:</span>
+      <el-input
+        v-model="listQuery.videoTitle"
+        placeholder="视频标题"
+        style="width: 200px"
+        class="filter-item"
+        @keyup.enter.native="getList"
+      />
+      <span>审核状态:</span>
+      <el-select
+        v-model="listQuery.auditStatus"
+        placeholder="审核状态"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="全部" value="" />
+        <el-option label="待审核" :value="2" />
+        <el-option label="审核通过" :value="1" />
+        <el-option label="审核未通过" :value="0" />
+      </el-select>
+      <span>上线状态:</span>
+      <el-select
+        v-model="listQuery.status"
+        placeholder="上线状态"
+        clearable
+        style="width: 200px"
+        class="filter-item"
+        @change="getList"
+      >
+        <el-option label="全部" value="" />
+        <el-option label="已上线" :value="1" />
+        <el-option label="待上线" :value="2" />
+        <el-option label="未上线" :value="0" />
+      </el-select>
+      <el-button type="primary" icon="el-icon-search" @click="getList">查询</el-button>
+      <el-button v-if="userIdentity === 2 || proxyInfo!==null" icon="el-icon-edit" type="primary" @click="handleShowDialog('add')">添加视频</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 label="序号" :index="indexMethod" type="index" width="80" align="center" />
+      <el-table-column label="视频标题" prop="videoTitle" align="center" />
+      <el-table-column label="审核状态" width="180px" align="center">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.auditStatus === 2" size="small" type="warning">待审核</el-tag>
+          <el-tag v-if="row.auditStatus === 1" size="small" type="success">审核通过</el-tag>
+          <!-- 未通过原因展示 -->
+          <template v-if="row.auditStatus === 0">
+            <!-- <span class="status danger">审核未通过&nbsp;</span> -->
+            <el-popover
+              placement="top-start"
+              title="审核说明"
+              width="400"
+              trigger="hover"
+              :content="row.invalidReason"
+            >
+              <el-tag slot="reference" size="small" type="danger" class="reason">
+                <span>审核未通过</span>
+                <span class="el-icon-question status danger " />
+              </el-tag>
+            </el-popover>
+            <!-- 未通过原因展示END -->
+          </template>
+        </template>
+      </el-table-column>
+      <el-table-column label="上线状态" width="180px" align="center">
+        <template slot-scope="{row}">
+          <!-- 只有审核通过了才能操作上下线 auditStatus :审核状态 -->
+          <template v-if="row.auditStatus === 1">
+            <template v-if="row.status === 0">
+              <span style="margin-right:10px;" class="status danger">已下线</span>
+              <el-button v-if="userIdentity===2 || proxyInfo!==null" type="primary" size="mini" @click="handleChangeStatus(row)">上线</el-button>
+            </template>
+            <template v-else>
+              <span style="margin-right:10px;" class="status success ">已上线</span>
+              <el-button v-if="userIdentity===2 || proxyInfo!==null" type="info" size="mini" plain @click="handleChangeStatus(row)">下线</el-button>
+            </template>
+          </template>
+          <template v-else>
+            <!-- <el-tag type="warning">待上线</el-tag> -->
+            <span style="margin-right:10px;" class="status warning">待上线</span>
+          </template>
+        </template>
+      </el-table-column>
+      <el-table-column label="创建时间" width="240px" align="center">
+        <template slot-scope="{row}">
+          {{ row.createTime | formatTime }}
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" width="280px" align="center">
+        <template slot-scope="{row}">
+          <el-button type="primary" size="mini" style="margin-right:5px" icon="el-icon-video-play" @click="handlePlayer(row)">播放</el-button>
+          <el-button type="primary" size="mini" style="margin-right:5px" icon="el-icon-edit" @click="handleShowDialog('edit',row)">编辑</el-button>
+          <el-button type="danger" size="mini" style="margin-right:5px" icon="el-icon-s-check" @click="handleRemoveVideo(row)">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 表格区域END -->
+    <pagination v-show="total>0" :total="total" :page.sync="listQuery.pageNum" :limit.sync="listQuery.pageSize" @pagination="getList(listQuery)" />
+    <!-- 视频预览对话框 -->
+    <el-dialog
+      :title="dialogTitle"
+      :visible.sync="dialogVisible"
+      width="40%"
+      :close-on-click-modal="false"
+      :close-on-press-escape="false"
+      @close="beforeDialogClose"
+      @closed="dialogColosed"
+    >
+      <el-form ref="formRef" :model="dialogData" label-width="110px" :rules="dialogFormRules">
+        <el-form-item label="标题:" prop="videoTitle">
+          <el-input v-model="dialogData.videoTitle" maxlength="50" show-word-limit />
+        </el-form-item>
+        <el-form-item ref="formVideoUrlRef" label="上传视频:" prop="videoPreviewUrl">
+
+          <div class="file-upload-box" style="height:40px;">
+            <!-- 上传文件组件 -->
+            <el-upload
+              ref="uploadRef"
+              accept=".mp4"
+              :class="{hidden:hasVideo}"
+              :auto-upload="false"
+              :headers="headers"
+              :action="action"
+              :on-success="handleUploadSuccess"
+              :on-change="handleUploadChange"
+              :on-remove="handleFileRemove"
+              :before-upload="beforeUpload"
+              :file-list="fileList"
+            >
+              <el-button size="mini" type="primary" style="width:100%">上传视频</el-button>
+            </el-upload>
+            <el-input v-model="dialogData.videoPreviewUrl" type="hidden" class="hiddenInput" />
+          </div>
+          <span style="color:#999;font-size:12px">视频大小不能超过<i style="color:red">*50MB*</i></span>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="dialogVisible = false">取 消</el-button>
+        <el-button type="primary" :loading="submitLoading" @click="handleSubmit">提 交</el-button>
+      </div>
+    </el-dialog>
+    <!-- 视频预览对话框END -->
+
+    <!-- 视频预览对话框 -->
+    <el-dialog
+      title="视频预览"
+      :visible.sync="dialogPreviewVisible"
+      width="60%"
+      @closed="dialogPreviewColosed"
+    >
+      <video :src="videoPreviewUrl" controls="controls" width="100%">
+        您的浏览器不支持播放该视频
+      </video>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="dialogPreviewVisible = false">关闭</el-button>
+      </div>
+    </el-dialog>
+    <!-- 视频预览对话框END -->
+
+  </div>
+</template>
+
+<script>
+import Pagination from '@/components/Pagination' // secondary package based on el-pagination
+import { formatDate } from '@/utils'
+import { mapGetters } from 'vuex'
+import { getToken } from '@/utils/auth'
+import { changeVideoStatus, getVideoList, removeVideo, saveVideo } from '@/api/doc'
+export default {
+  components: { Pagination },
+  filters: {
+    formatTime(time) {
+      if (!time) {
+        return ''
+      }
+      return formatDate(time, 'yyyy-MM-DD HH:mm:ss')
+    }
+  },
+  data() {
+    return {
+      dialogPreviewVisible: false,
+      listLoading: false, // 列表加载
+      submitLoading: false, // 按钮加载
+      dialogVisible: false, // 是否显示dialog
+      dialogTitle: '添加视频', // dialog标题
+      total: 0, // 数据条数
+      hasVideo: false, // 是否上传了视频
+      chooseNewVideo: false, // 是否重新选择了视频
+      fileList: [], // 上传的视频列表
+      previewUrl: '', // 上传视频成功的url
+      downloadUrl: '',
+      listQuery: {
+        authUserId: '', // 供应商用户id
+        listType: 1, // 列表类型:1视频列表,2视频审核列表
+        videoTitle: '', // 供应商类型
+        auditStatus: '', // 审核状态:0审核未通过,1审核通过,2待审核
+        status: '', // 视频状态:0已下线,1已上线,2待上线
+        pageNum: 1, // 页码
+        pageSize: 10 // 分页大小
+      },
+      // dialog中表单的数据
+      dialogData: {
+        videoId: '',
+        authUserId: '',
+        videoName: '',
+        videoTitle: '',
+        // videoUrl: '',
+        videoPreviewUrl: '',
+        videoDownloadUrl: ''
+      },
+      // dialog中表单字段校验规则
+      dialogFormRules: {
+        videoTitle: [{ required: true, message: '标题不能为空', trigger: 'blur' }],
+        videoPreviewUrl: [{ required: true, message: '链接不能为空', trigger: ['change', 'blur'] }]
+      },
+      list: [],
+      videoPreviewUrl: ''
+    }
+  },
+  computed: {
+    ...mapGetters(['authUserId', 'userIdentity', 'proxyInfo']),
+    headers() {
+      return {
+        'X-Token': getToken()
+      }
+    },
+    action() {
+      return `${process.env.VUE_APP_UPLOAD_API}/upload/file`
+    }
+  },
+  created() {
+    this.getList()
+  },
+  methods: {
+
+    // 播放视频
+    handlePlayer(row) {
+      this.currentVideoUrl = row.videoPreviewUrl
+      this.dialogPreviewVisible = true
+    },
+
+    dialogPreviewColosed() {
+      this.currentVideoUrl = ''
+    },
+
+    // 获取列表数据
+    getList() {
+      this.listLoading = true
+      this.listQuery.authUserId = this.authUserId
+      getVideoList(this.listQuery)
+        .then(res => {
+          if (res.code !== 0) return
+          this.list = res.data.list
+          this.total = res.data.total
+          console.log(res)
+        })
+        .finally(() => {
+          this.listLoading = false
+        })
+    },
+    // 提交
+    handleSubmit() {
+      if (!this.dialogData.videoPreviewUrl) {
+        this.$refs.formRef.validateField('videoTitle')
+        this.$refs.formRef.validateField('videoPreviewUrl')
+        return
+      }
+      // 对标题字段进行规则校验
+      this.$refs.formRef.validateField('videoTitle', (error) => {
+        if (!error) {
+          /**
+           * 新增视频和修改视频
+           * 表单有两种提交方式
+           * 1、直接提交保存,不上传视频
+           * 2、上传视频成功后再保存
+           * 要针对这两种上传方式做响应的判断
+           * 组合:1.新增时,填写视频地址,不上传视频  --直接提交
+           *      2.新增时,填写视频地址,再选择上传视频  --上传的视频优先级高
+           *      3.新增时,不填写视频地址,选择上传视频  --上传视频后再提交
+           *      4.修改时,只修改视频标题,已经有了视频地址  --直接提交
+           *      5.修改时,重新选择了视频  --上传视频后再提交
+           */
+          this.submitLoading = true;
+          (this.dialogData.videoPreviewUrl && (!this.hasVideo || (this.hasVideo && !this.chooseNewVideo))) ? this.save() : this.$refs.uploadRef.submit()
+        }
+      })
+    },
+    // 保存视频
+    save() {
+      this.$refs.formRef.validate(valide => {
+        if (!valide) return
+        this.dialogData.authUserId = this.authUserId
+        // uploadVideoUrl不为空,就代表重新上传了视频,需要为表单中的videoUrl重新赋值,新增时该值也不为空
+        if (this.previewUrl && this.downloadUrl) {
+          this.dialogData.videoPreviewUrl = this.previewUrl
+          this.dialogData.videoDownloadUrl = this.downloadUrl
+        }
+        saveVideo(this.dialogData)
+          .then(res => {
+            console.log(res)
+            if (res.code !== 0) return
+            this.dialogVisible = false
+            this.getList()
+            this.$message({
+              type: 'success',
+              message: res.data,
+              duration: 500
+            })
+          }).finally(() => {
+            this.submitLoading = false
+          })
+      })
+    },
+    // 设置表单初始值
+    setDialogData(row) {
+      if (!row) return
+      console.log(row)
+      for (const key in this.dialogData) {
+        if (Object.hasOwnProperty.call(this.dialogData, key)) {
+          this.dialogData[key] = row[key]
+        }
+      }
+      if (this.dialogData.videoPreviewUrl) {
+        this.fileList.push({ name: row.videoName, url: row.videoPreviewUrl })
+        this.hasVideo = true
+      }
+    },
+    // 删除视频
+    async handleRemoveVideo(row) {
+      const text = await this.$confirm('视频删除后不可恢复,确认删除该视频吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).catch(() => {
+        this.$message.info('已取消操作')
+      })
+      if (text !== 'confirm') return
+      removeVideo({ videoId: row.videoId })
+        .then(res => {
+          if (res.code !== 0) return
+          this.$message.success(res.data)
+          this.getList()
+        })
+    },
+    // 显示对话框
+    handleShowDialog(type, row) {
+      this.dialogTitle = type === 'add' ? '添加视频' : '修改视频'
+      this.setDialogData(row)
+      this.dialogVisible = true
+    },
+    // 对话框关闭的回调
+    dialogColosed() {
+      this.fileList = []
+      this.hasVideo = false
+      this.dialogData.videoId = ''
+      this.dialogData.authUserId = ''
+      this.dialogData.videoTitle = ''
+      this.dialogData.videoPreviewUrl = ''
+      this.dialogData.videoDownloadUrl = ''
+      this.chooseNewVideo = false
+      this.downloadUrl = ''
+      this.previewUrl = ''
+      this.submitLoading = false
+    },
+    // 对话框关闭前的回调
+    beforeDialogClose() {
+      this.$refs.formRef.resetFields()
+      // 停止上传文件
+      this.$refs.uploadRef.abort()
+    },
+    // 视频上传成功
+    handleUploadSuccess(response, file, fileList) {
+      console.log(response)
+      // this.dialogData.videoUrl = response.fileUrl
+      this.previewUrl = response.previewUrl
+      this.downloadUrl = response.downloadUrl
+      this.dialogData.videoName = response.fileName
+      this.save()
+    },
+    // 选添加文件、上传成功和上传失败时都会被调用
+    handleUploadChange(file, fileList) {
+      console.log(file)
+      this.chooseNewVideo = true
+      this.hasVideo = fileList.length > 0
+      this.dialogData.videoPreviewUrl = '-'
+      this.dialogData.videoDownloadUrl = '-'
+    },
+    // 移除视频
+    handleFileRemove(file, fileList) {
+      this.hasVideo = fileList.length > 0
+      this.dialogData.videoPreviewUrl = ''
+      this.dialogData.videoDownloadUrl = ''
+      this.submitLoading = false
+    },
+    // 上传视频前判断文件大小
+    beforeUpload(file, fileList) {
+      const flag = file.size <= 100 * 1024 * 1204
+      if (!flag) {
+        this.$message({
+          message: '文件大小超过100MB,请重新选择!',
+          duration: 1000,
+          type: 'warning'
+        })
+        this.fileList = []
+      }
+      return flag
+    },
+    // 状态改变
+    handleChangeStatus(item) {
+      this.listLoading = true
+      console.log(item)
+      const params = {
+        videoId: item.videoId,
+        status: item.status === 1 ? 0 : 1
+      }
+      changeVideoStatus(params).then(res => {
+        // this.$message.success(res.data)
+        this.$message({
+          message: res.data,
+          duration: 500,
+          type: 'success'
+        })
+        this.getList()
+      }).catch(err => {
+        console.log(err)
+      }).finally(() => {
+        this.listLoading = false
+      })
+    },
+    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;
+}
+.hasBottom{
+  padding-bottom: 40px;
+}
+</style>

+ 0 - 49
src/views/normal/password.vue

@@ -1,49 +0,0 @@
-<template>
-  <div class="password">
-    <el-form ref="form" :model="formData" label-width="80px" class="form">
-      <el-form-item label="旧密码:">
-        <el-input v-model="formData.oldPwd" placeholder="请输入旧密码" />
-      </el-form-item>
-      <el-form-item label="新密码:">
-        <el-input v-model="formData.newPwd" placeholder="请输入新密码" />
-      </el-form-item>
-      <el-form-item label="确认密码:">
-        <el-input v-model="formData.confirmPwd" placeholder="请再次输入密码" />
-      </el-form-item>
-      <el-form-item class="submit">
-        <el-button type="primary">确认</el-button>
-        <el-button type="warning" @click="$_back">取消</el-button>
-      </el-form-item>
-    </el-form>
-  </div>
-</template>
-
-<script>
-export default {
-  data() {
-    return {
-      formData: {
-        oldPwd: '',
-        newPwd: '',
-        confirmPwd: ''
-      }
-    }
-  },
-  methods: {
-    // back() {
-    //   this.$router.go(-1)
-    // }
-  }
-}
-</script>
-
-<style lang="scss" scoped>
-.form{
-  width: 600px;
-  margin: 80px auto;
-
-  .el-button{
-    width: 120px;
-  }
-}
-</style>

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio