浏览代码

v1.7.2版本接口调试

yuwenjun1997 2 年之前
父节点
当前提交
983290f75c
共有 33 个文件被更改,包括 1595 次插入653 次删除
  1. 11 6
      apis/index.js
  2. 2 1
      layouts/app-ross.vue
  3. 2 1
      layouts/app.vue
  4. 4 1
      middleware/auth.js
  5. 0 41
      middleware/auth1.js
  6. 5 2
      pages/_template/app/approve/club/detail.vue
  7. 20 3
      pages/_template/app/approve/club/index.vue
  8. 13 111
      pages/_template/app/approve/club/star-list.vue
  9. 286 89
      pages/_template/app/approve/device/index.vue
  10. 289 0
      pages/_template/app/approve/device/index1.vue
  11. 2 2
      pages/_template/app/form/club-bind.vue
  12. 4 2
      pages/_template/app/form/club-register.vue
  13. 187 90
      pages/_template/app/form/components/form-club-device.vue
  14. 16 0
      pages/_template/app/form/components/form-club-info.vue
  15. 11 3
      pages/_template/app/record/club/detail.vue
  16. 2 2
      pages/_template/app/record/club/edit.vue
  17. 11 4
      pages/_template/app/record/device/detail.vue
  18. 5 2
      pages/_template/app/record/device/edit.vue
  19. 3 3
      pages/_template/app/record/device/index.vue
  20. 1 1
      pages/_template/app/record/message.vue
  21. 6 1
      pages/_template/ross/approve/club/detail.vue
  22. 37 182
      pages/_template/ross/approve/club/star-list.vue
  23. 279 66
      pages/_template/ross/approve/device/index.vue
  24. 273 0
      pages/_template/ross/approve/device/index1.vue
  25. 3 3
      pages/_template/ross/form/club-register.vue
  26. 74 15
      pages/_template/ross/form/components/form-club-device.vue
  27. 8 4
      pages/_template/ross/form/components/form-club-info.vue
  28. 22 12
      pages/_template/ross/index.vue
  29. 3 3
      pages/_template/ross/record/club/detail.vue
  30. 5 2
      pages/_template/ross/record/device/detail.vue
  31. 3 0
      pages/_template/ross/record/device/edit.vue
  32. 1 1
      pages/_template/ross/record/device/index.vue
  33. 7 0
      utils/index.js

+ 11 - 6
apis/index.js

@@ -50,6 +50,9 @@ export default ($axios) => {
   // 获取已认证机构列表
   const getAuthClubList = (params = {}) =>
     $axios.get('/wx/auth/club/list', { params })
+  // 获取已认证机构列表
+  const getAuthClubStarList = (params = {}) =>
+    $axios.get('/wx/auth/club/star/list', { params })
   // 获取已认证机构详情
   const getAuthClubDetail = (params = {}) =>
     $axios.get('/wx/auth/club/details', { params })
@@ -86,7 +89,7 @@ export default ($axios) => {
     $axios.get('/wx/user/info', { params })
   // 获取品牌列表
   const fetchBrandList = (params = {}) =>
-    $axios.get('/wx/auth/brand/list', { params })
+    $axios.get('/wx/auth/shop/info/list', { params })
   // 获取设备分类列表
   const fetchProductSelectList = (params = {}) =>
     $axios.get('/wx/auth/product/type/select', { params })
@@ -126,14 +129,14 @@ export default ($axios) => {
         queryStringify(params)
     )
   const assistantBaidu = (params = {}) =>
-    fetch(
-      'https://api.map.baidu.com/geoconv/v1' +
-        queryStringify(params)
-    )
+    fetch('https://api.map.baidu.com/geoconv/v1' + queryStringify(params))
 
   // 查询授权商品列表
   const fetchProductDetails = (params = {}) =>
     $axios.get('/wx/auth/product/details', { params })
+  // 查询授权商品列表
+  const fetchDetialBySnCode = (params = {}) =>
+    $axios.get('/wx/auth/product/info', { params })
 
   return {
     customLogin,
@@ -149,6 +152,7 @@ export default ($axios) => {
     getArticleDetail,
     feedback,
     getAuthClubList,
+    getAuthClubStarList,
     getAuthProductCateList,
     getAuthProductList,
     checkToken,
@@ -175,6 +179,7 @@ export default ($axios) => {
     getProductDetails,
     authProducSave,
     fetchProductDetails,
-    assistantBaidu
+    assistantBaidu,
+    fetchDetialBySnCode,
   }
 }

+ 2 - 1
layouts/app-ross.vue

@@ -56,7 +56,7 @@
         <nuxt />
       </div>
       <div class="footer flex justify-center items-center" v-show="showFooter">
-        - 由采美网提供技术支持 -
+        - {{ supplierInfo.shopName }} | 由采美网提供技术支持 -
       </div>
       <SimpleLogin :type="formType" @click="onLoginClick"></SimpleLogin>
     </div>
@@ -93,6 +93,7 @@ export default {
       'isPc',
       'showHeader',
       'showFooter',
+      'supplierInfo',
     ]),
     themeClass() {
       return `theme-${this.themeName}`

+ 2 - 1
layouts/app.vue

@@ -45,7 +45,7 @@
         <nuxt />
       </div>
       <div class="footer flex justify-center items-center" v-show="showFooter">
-        - 由采美网提供技术支持 -
+        - {{ supplierInfo.shopName }} | 由采美网提供技术支持 -
       </div>
       <SimpleLogin :type="formType" @click="onLoginClick"></SimpleLogin>
     </div>
@@ -68,6 +68,7 @@ export default {
       'themeName',
       'showHeader',
       'showFooter',
+      'supplierInfo',
     ]),
     themeClass() {
       return `theme-${this.themeName}`

+ 4 - 1
middleware/auth.js

@@ -95,5 +95,8 @@ function newLinkInit({ route, error, redirect }) {
 }
 
 export default function (context) {
-  return context.route.hash ? oldLinkInit(context) : newLinkInit(context)
+  let hash = context.route.hash
+  const query = getQueryObject(hash)
+  const appId = query.appId
+  return appId ? oldLinkInit(context) : newLinkInit(context)
 }

+ 0 - 41
middleware/auth1.js

@@ -1,41 +0,0 @@
-import modeMap from '~/configs/mode-map'
-import axios from 'axios'
-
-export default async function ({ route, error, redirect }) {
-  const authUserId = parseInt(route.params.template)
-  const auth = modeMap.find((item) => item.authUserId === authUserId)
-  let routePrefix = !auth ? `/${authUserId}/app` : `/${authUserId}/${auth.mode}`
-  const baseURL = process.env.BASE_URL + '/wx/auth/shop/info'
-  return axios
-    .get(baseURL, {
-      params: { authUserId: authUserId },
-    })
-    .then(({ data }) => {
-      if (data.code === -1) {
-        error({
-          statusCode: 404,
-          message: '页面不存在',
-        })
-      } else if (
-        authUserId === 12 &&
-        auth.mode === 'ross' &&
-        route.path.indexOf(`${authUserId}/app`) > -1
-      ) {
-        // console.log(route.fullPath.replace(`${authUserId}/app`, `${authUserId}/ross`))
-        redirect(
-          route.fullPath.replace(`${authUserId}/app`, `${authUserId}/ross`)
-        )
-      } else if (route.path.indexOf(routePrefix) !== 0) {
-        error({
-          statusCode: 404,
-          message: '页面不存在',
-        })
-      }
-    })
-    .catch(() => {
-      error({
-        statusCode: 404,
-        message: '页面不存在',
-      })
-    })
-}

+ 5 - 2
pages/_template/app/approve/club/detail.vue

@@ -20,7 +20,7 @@
         <div class="section flex justify-between items-center">
           <div class="info">
             <div class="name" v-text="clubInfo.authParty"></div>
-            <div class="mobile">{{ clubInfo.mobile | formatEmpty }}</div>
+            <div class="mobile"  @click="callMobile(clubInfo.mobile)">{{ clubInfo.mobile | formatEmpty }}</div>
             <div class="address" v-text="address"></div>
           </div>
           <div class="logo"><img :src="clubInfo.logo" /></div>
@@ -66,6 +66,7 @@
 import { drawLogo } from '@/utils'
 import { mapNavigate } from '@/utils/map-utils'
 import { mapGetters } from 'vuex'
+import { callMobile } from '@/utils'
 export default {
   layout: 'app',
   filters: {
@@ -104,6 +105,7 @@ export default {
     this.$removeStorage(this.routePrefix, 'clubInfo')
   },
   methods: {
+    callMobile,
     // 设备详情
     toDetail(item) {
       window.location.href = `${process.env.CIMEI_LOCAL}/product/auth/product-${item.productId}.html`
@@ -259,6 +261,7 @@ export default {
           }
         }
         .mobile {
+          cursor: pointer;
           &::after {
             @include themify($themes) {
               background-image: themed('pc-icon-mobile');
@@ -490,8 +493,8 @@ export default {
           margin-left: 0.4vw;
           @include themify($themes) {
             background: themed('h5-icon-navigation') no-repeat center;
+            background-size: 3.6vw;
           }
-          background-size: 3.6vw;
         }
       }
       .distance {

+ 20 - 3
pages/_template/app/approve/club/index.vue

@@ -61,6 +61,11 @@
                 </div>
               </div>
             </template>
+            <div
+              class="empty"
+              v-for="i in starEmptyList"
+              :key="'empty-' + i"
+            ></div>
           </div>
         </template>
         <!-- 标题 -->
@@ -129,7 +134,7 @@ export default {
       total: 0,
       cityList: [],
       selectValue: [],
-      // starList: []
+      starList: [],
     }
   },
   computed: {
@@ -137,8 +142,8 @@ export default {
     emptyList() {
       return 3 - (this.list.length % 3)
     },
-    starList() {
-      return this.list.slice(0, 3)
+    starEmptyList() {
+      return 3 - (this.starList.length % 3)
     },
   },
   mounted() {
@@ -150,11 +155,23 @@ export default {
       this.initData()
       this.fetchCityList()
     }
+    this.fetchAuthClubStarList()
   },
   beforeDestroy() {
     this.$toast.clear()
   },
   methods: {
+    // 获取明星机构列表
+    async fetchAuthClubStarList() {
+      try {
+        const res = await this.$http.api.getAuthClubStarList({
+          authUserId: this.authUserId,
+        })
+        this.starList = res.data.slice(0, 3)
+      } catch (error) {
+        console.log(error)
+      }
+    },
     // 绘制logo的方法
     drawLogo,
     // 查看详情

+ 13 - 111
pages/_template/app/approve/club/star-list.vue

@@ -28,11 +28,6 @@
                 <div class="address">
                   {{ formatAddress(item.area, item.address) }}
                 </div>
-                <div
-                  class="distance"
-                  v-text="generateDistance(item.distance)"
-                  v-if="item.distance && item.distance !== 99999"
-                ></div>
               </div>
             </div>
           </template>
@@ -51,30 +46,14 @@
 
 <script>
 import { mapGetters } from 'vuex'
-import { geolocation } from '@/utils/map-utils'
 import { drawLogo, debounce } from '@/utils'
 export default {
   layout: 'app',
   data() {
     return {
-      isLoadingMore: true,
       finished: false,
       isRequest: true,
       list: [],
-      listQuery: {
-        authUserId: '',
-        lngAndLat: '',
-        clubName: '',
-        provinceId: '',
-        cityId: '',
-        townId: '',
-        pageNum: 1,
-        pageSize: 9,
-      },
-      total: 0,
-      cityList: [],
-      selectValue: [],
-      // starList: []
     }
   },
   computed: {
@@ -82,19 +61,12 @@ export default {
     emptyList() {
       return 3 - (this.list.length % 3)
     },
-    starList() {
-      return this.list.slice(0, 3)
+    total() {
+      return this.list.length
     },
   },
   mounted() {
-    const cacheData = this.$getStorage(this.routePrefix, 'club_list_data')
-    if (cacheData) {
-      this.initFromCache(cacheData)
-      this.$removeStorage(this.routePrefix, 'club_list_data')
-    } else {
-      this.initData()
-      this.fetchCityList()
-    }
+    this.initData()
   },
   beforeDestroy() {
     this.$toast.clear()
@@ -104,100 +76,34 @@ export default {
     drawLogo,
     // 查看详情
     toDetail(item) {
-      this.$setStorage(this.routePrefix, 'club_list_data', this.$data, {
-        expiredTime: 5 * 60 * 1000,
-      })
-      this.$setStorage(this.routePrefix, 'clubInfo', item)
       const url = `${this.routePrefix}/approve/club/detail?id=${item.authId}`
       this.$router.push(url)
     },
-    // 从缓存中获取数据
-    initFromCache(cacheData) {
-      this.isLoadingMore = cacheData.isLoadingMore
-      this.finished = cacheData.finished
-      this.isRequest = cacheData.isRequest
-      this.list = cacheData.list
-      this.listQuery = cacheData.listQuery
-      this.total = cacheData.total
-      this.cityList = cacheData.cityList
-      this.selectValue = cacheData.selectValue
-      this.$refs.citySelect.setSelectValue(this.selectValue)
-    },
-
-    generateDistance(value) {
-      return value > 1 ? value + 'km' : value * 1000 + 'm'
-    },
 
     // 初始化页面数据
     async initData() {
-      this.listQuery.authUserId = this.authUserId
-
-      // 自定义加载图标
-      this.$toast.loading({
-        message: '正在获取您附近的机构...',
-        duration: 0,
-      })
-
-      // 获取定位信息 这里使用的是高德地图获取用户具体位置信息
-      try {
-        const resLocation = await geolocation()
-        this.listQuery.lngAndLat = `${resLocation.position.lng},${resLocation.position.lat}`
-      } catch (error) {
-        this.$toast('获取定位信息失败,请确保您开启的定位权限并保存网络畅通')
-        this.isRequest = false
-      }
-
       // 获取机构列表
       this.fetchList()
     },
+
     fetchList: debounce(async function () {
       try {
-        this.isLoadingMore = true
-        const res = await this.$http.api.getAuthClubList(this.listQuery)
-        this.total = res.data.total
-        this.list = [...this.list, ...res.data.list]
-        this.finished = !res.data.hasNextPage
-        this.isLoadingMore = false
-        this.listQuery.pageNum += 1
+        // 自定义加载图标
+        this.$toast.loading({
+          message: '正在获取明星机构...',
+          duration: 0,
+        })
+        const res = await this.$http.api.getAuthClubStarList({
+          authUserId: this.authUserId,
+        })
+        this.list = res.data
       } catch (error) {
         console.log(error)
       } finally {
         this.$toast.clear()
-        this.isRequest = false
       }
     }, 400),
-    // 获取地址列表
-    fetchCityList() {
-      this.$http.api.fetchAllCityList().then((res) => {
-        this.cityList = res.data
-      })
-    },
-    // 城市变化
-    onCityChange(selectValue) {
-      this.listQuery.provinceId = ''
-      this.listQuery.cityId = ''
-      this.listQuery.townId = ''
-      this.selectValue = selectValue
 
-      selectValue.map((item, index) => {
-        if (index === 0) {
-          this.listQuery.provinceId = item.id
-        } else if (index === 1) {
-          this.listQuery.cityId = item.id
-        } else {
-          this.listQuery.townId = item.id
-        }
-      })
-      this.listQuery.pageNum = 1
-      this.list = []
-      this.fetchList()
-    },
-    // 搜索
-    onSearch() {
-      this.listQuery.pageNum = 1
-      this.list = []
-      this.fetchList()
-    },
     // 格式化地址
     formatAddress(a1, a2) {
       let resutl = ''
@@ -209,10 +115,6 @@ export default {
       }
       return resutl || '暂无'
     },
-    // 加载更多
-    onLoadMore() {
-      this.fetchList()
-    },
   },
 }
 </script>

+ 286 - 89
pages/_template/app/approve/device/index.vue

@@ -8,109 +8,211 @@
       @load="onLoadMore"
     >
       <div class="page-top flex flex-col justify-center items-center">
-        <!-- <img class="logo" :src="supplierInfo.logo" /> -->
+        <img class="logo" :src="supplierInfo.logo" />
         <div class="mt-2 name">
-          <span v-text="supplierInfo.shopName"></span>
-          <span>官方授权设备</span>
+          <span v-text="supplierInfo.shopName"></span><span>官方授权设备</span>
         </div>
       </div>
       <div class="page-content">
-        <!-- 搜索区域 -->
-        <div class="search">
-          <SimpleSearch
-            v-model="listQuery.name"
-            @search="onSearch"
-            placeholder="搜索设备"
-          />
-        </div>
-        <!-- 标题 -->
-        <div class="title px-4 pt-12 pb-6">
-          共<span v-text="total"></span>种设备
-        </div>
-        <!-- 列表 -->
-        <div class="list">
-          <div
-            class="section flex items-center mb-4"
-            v-for="item in list"
-            :key="item.productTypeId"
-            @click="toDetail(item)"
+        <div class="search-title">设备种类查询:</div>
+        <div class="search-container">
+          <el-select
+            v-model="listQuery.productTypeId"
+            slot="prepend"
+            placeholder="设备种类"
+            class="select-type"
+          >
+            <template v-for="product in productSelectList">
+              <el-option
+                :label="product.name"
+                :value="product.productTypeId"
+                :key="product.productTypeId"
+              ></el-option>
+            </template>
+          </el-select>
+          <el-input
+            :placeholder="
+              searchQuery.type === 1 ? '请输入SN码' : '请输入机构名'
+            "
+            v-model="searchQuery.keyword"
+            class="input-with-select"
+          >
+            <el-select
+              v-model="searchQuery.type"
+              slot="prepend"
+              placeholder="请选择"
+            >
+              <el-option label="SN码" :value="1"></el-option>
+              <el-option label="机构名" :value="2"></el-option>
+            </el-select>
+            <i slot="prefix" class="el-input__icon el-icon-search"></i>
+          </el-input>
+          <el-button class="submit" type="warning" @click="onSearch"
+            >查询</el-button
           >
-            <img class="cover" :src="item.image" />
-            <div class="name" v-text="item.name"></div>
-          </div>
-          <div class="empty" v-for="i in emptyList" :key="'empty-' + i"></div>
         </div>
-
-        <!-- 列表为空 -->
-        <SimpleEmpty
-          v-if="!total && !isRequest"
-          name="icon-empty-device.png"
-          description="敬请期待~"
-        ></SimpleEmpty>
+        <template v-if="list.length > 0 || searchFlag">
+          <!-- 标题 -->
+          <div class="title px-4 pt-12 pb-6 md:px-0">
+            共<span v-text="total"></span>台设备
+          </div>
+          <!-- 列表 -->
+          <div class="list">
+            <div
+              class="section flex justify-between mb-4"
+              v-for="item in list"
+              :key="item.productId"
+              @click="toDetail(item)"
+            >
+              <img class="cover" :src="item.productImage" />
+              <div class="info">
+                <div class="name" v-text="item.productName"></div>
+                <div class="code">SN码:{{ item.snCode | formatSnCode }}</div>
+                <el-popover placement="right" title="机构列表" trigger="hover">
+                  <template v-for="club in item.clubList">
+                    <div
+                      @click.stop="toClubDetail(club)"
+                      :key="club.authId"
+                      class="club-item"
+                    >
+                      {{ club.authParty }}
+                    </div>
+                  </template>
+                  <div class="club-name" slot="reference">
+                    所属机构:
+                    <template v-for="club in item.clubList">
+                      ,<span :key="club.authId">{{ club.authParty }}</span>
+                    </template>
+                  </div>
+                </el-popover>
+              </div>
+            </div>
+          </div>
+          <!-- 列表为空 -->
+          <SimpleEmpty
+            v-if="!total && !isRequest"
+            name="icon-empty-device.png"
+            description="敬请期待~"
+          ></SimpleEmpty>
+        </template>
       </div>
     </van-list>
   </div>
 </template>
 
 <script>
-import { mapGetters } from 'vuex'
 import { debounce } from '@/utils'
+import { mapGetters } from 'vuex'
 export default {
   layout: 'app',
+  filters: {
+    formatSnCode(code) {
+      if (!code) return ''
+      return code.replace(/^(\w{2})\w+(\w{4})$/, '$1******$2')
+    },
+  },
   data() {
     return {
-      isLoadingMore: true,
+      isLoadingMore: false,
       finished: false,
       isRequest: true,
+      searchQuery: {
+        type: 2,
+        keyword: '测试机构A',
+      },
       listQuery: {
-        authUserId: '',
-        name: '',
+        listType: 1,
+        productTypeId: '',
+        snCode: '',
+        authParty: '测试机构A',
         pageNum: 1,
-        pageSize: 9,
+        pageSize: 10,
       },
       list: [],
       total: 0,
+      productSelectList: [],
+      searchFlag: false,
     }
   },
   computed: {
-    ...mapGetters(['supplierInfo', 'authUserId', 'routePrefix']),
-    emptyList() {
-      return 3 - (this.list.length % 3)
-    },
+    ...mapGetters(['routePrefix', 'supplierInfo', 'authUserId']),
   },
   mounted() {
-    this.fetchList()
+    this.fetchProductSelectList()
   },
   methods: {
-    // 获取设备分类
+    // 获取设备列表
     fetchList: debounce(async function () {
       try {
         this.isLoadingMore = true
-        this.listQuery.authUserId = this.authUserId
-        const res = await this.$http.api.getAuthProductCateList(this.listQuery)
+        const res = await this.$http.api.getAuthProductList(this.listQuery)
         this.list = [...this.list, ...res.data.list]
         this.finished = !res.data.hasNextPage
         this.total = res.data.total
         this.isLoadingMore = false
         this.listQuery.pageNum += 1
+        this.searchFlag = true
       } catch (error) {
         console.log(error)
       } finally {
         this.isRequest = false
+        this.searchFlag = true
       }
     }, 400),
 
-    // 设备详情
-    toDetail(item) {
-      const url = `${this.routePrefix}/approve/device/list?id=${item.productTypeId}`
-      this.$router.push(url)
-    },
     // 搜索
     onSearch() {
-      this.listQuery.pageNum = 1
+      const { productTypeId } = this.listQuery
+      const { type, keyword } = this.searchQuery
+      if (!productTypeId) {
+        return this.$toast('请选择设备分类')
+      }
+      if (!type) {
+        return this.$toast('请选择搜索条件')
+      }
+      if (!keyword) {
+        return this.$toast('搜索内容不能为空')
+      }
+
+      if (type === 1) {
+        this.listQuery.snCode = keyword
+        this.listQuery.authParty = ''
+      } else {
+        this.listQuery.snCode = ''
+        this.listQuery.authParty = keyword
+      }
+
       this.list = []
+      this.listQuery.pageNum = 1
       this.fetchList()
     },
+
+    // 获取设备种类
+    async fetchProductSelectList() {
+      try {
+        const res = await this.$http.api.fetchProductSelectList({
+          authUserId: this.authUserId,
+        })
+        this.productSelectList = res.data
+      } catch (error) {
+        console.log(error)
+      }
+    },
+
+    // 设备详情
+    toDetail(item) {
+      // window.location.href = `${process.env.CIMEI_LOCAL}/product/auth/product-${item.productId}.html`
+      this.$router.push(
+        `${this.routePrefix}/approve/device/detail?id=${item.productId}`
+      )
+    },
+
+    // 机构详情
+    toClubDetail(item) {
+      const url = `${this.routePrefix}/approve/club/detail?id=${item.authId}`
+      this.$router.push(url)
+    },
+
     // 加载更多
     onLoadMore() {
       this.fetchList()
@@ -120,8 +222,26 @@ export default {
 </script>
 
 <style scoped lang="scss">
+.input-with-select {
+  ::v-deep {
+    .el-input-group__prepend {
+      background-color: #fff;
+    }
+  }
+}
+
 // pc 端
 @media screen and (min-width: 768px) {
+  .el-popover {
+    .club-item {
+      line-height: 24px;
+      cursor: pointer;
+      &:hover {
+        color: #f3920d;
+      }
+    }
+  }
+
   .page {
     position: relative;
     min-height: calc(100vh - 80px - 80px);
@@ -145,21 +265,34 @@ export default {
       font-size: 30px;
       color: #fff;
     }
-
-    .logo,
-    .name {
-      transform: translateY(-30px);
-    }
   }
   .page-content {
-    width: 1200px;
+    width: 1000px;
     margin: 0 auto;
 
-    .search {
-      position: absolute;
-      left: 50%;
-      top: 300px;
-      transform: translateX(-50%);
+    .search-title {
+      font-size: 16px;
+      color: #404040;
+      margin: 25px 0;
+    }
+
+    .search-container {
+      display: flex;
+      justify-content: space-between;
+      .input-with-select {
+        margin: 0 15px;
+        .el-select {
+          ::v-deep {
+            .el-input {
+              width: 130px;
+            }
+          }
+        }
+      }
+
+      .submit {
+        width: 295px;
+      }
     }
 
     .title {
@@ -184,32 +317,52 @@ export default {
       }
 
       .section {
-        width: 390px;
-        height: 108px;
+        width: 490px;
+        height: 136px;
         background-color: #f3f5f6;
         border-radius: 4px;
         box-sizing: border-box;
         padding: 16px;
         cursor: pointer;
         transition: all 0.4s;
-
         &:hover {
           box-shadow: 0 0 24px rgba(0, 0, 0, 0.2);
         }
 
         .cover {
           display: block;
-          width: 84px;
-          height: 84px;
+          width: 104px;
+          height: 104px;
         }
-        .name {
-          width: 260px;
-          font-size: 16px;
-          color: #101010;
-          text-overflow: ellipsis;
-          white-space: nowrap;
-          overflow: hidden;
-          margin-left: 16px;
+        .info {
+          width: 336px;
+          position: relative;
+
+          .name {
+            font-size: 18px;
+            color: #101010;
+            font-weight: bold;
+            margin-bottom: 16px;
+            margin-top: 4px;
+            text-overflow: ellipsis;
+            white-space: nowrap;
+            overflow: hidden;
+          }
+          .code,
+          .club-name {
+            position: relative;
+            font-size: 14px;
+            color: #666;
+            line-height: 24px;
+            text-overflow: ellipsis;
+            white-space: nowrap;
+            overflow: hidden;
+            margin-top: 6px;
+
+            span {
+              color: #1890ff;
+            }
+          }
         }
       }
     }
@@ -222,8 +375,9 @@ export default {
     height: 46vw;
     @include themify($themes) {
       background: themed('h5-banner-device');
+      background-size: auto 46vw;
     }
-    background-size: auto 46vw;
+
     .logo {
       display: block;
       width: 14.8vw;
@@ -238,11 +392,34 @@ export default {
   }
   .page-content {
     position: relative;
-    .search {
-      position: absolute;
-      left: 50%;
-      top: 0;
-      transform: translate(-50%, -50%);
+
+    .search-title {
+      font-size: 3.4vw;
+      color: #404040;
+      margin: 3.2vw;
+    }
+
+    .search-container {
+      padding: 0 3.2vw;
+
+      .select-type {
+        width: 100%;
+      }
+
+      .input-with-select {
+        margin: 3.2vw 0;
+        .el-select {
+          ::v-deep {
+            .el-input {
+              width: 130px;
+            }
+          }
+        }
+      }
+
+      .submit {
+        width: 100%;
+      }
     }
 
     .title {
@@ -260,6 +437,7 @@ export default {
       display: flex;
       align-items: center;
       flex-direction: column;
+
       .section {
         width: 93.6vw;
         height: 26vw;
@@ -273,14 +451,33 @@ export default {
           width: 19.6vw;
           height: 19.6vw;
         }
-        .name {
-          width: 66vw;
-          font-size: 4vw;
-          color: #101010;
-          text-overflow: ellipsis;
-          white-space: nowrap;
-          overflow: hidden;
+        .info {
+          position: relative;
           margin-left: 3.2vw;
+          .name {
+            font-size: 4vw;
+            color: #101010;
+            font-weight: bold;
+            margin-bottom: 4vw;
+            text-overflow: ellipsis;
+            white-space: nowrap;
+            overflow: hidden;
+          }
+          .code,
+          .club-name {
+            width: 66vw;
+            position: relative;
+            font-size: 3vw;
+            color: #404040;
+            line-height: 5vw;
+            text-overflow: ellipsis;
+            white-space: nowrap;
+            overflow: hidden;
+
+            span {
+              color: #6d9eff;
+            }
+          }
         }
       }
     }

+ 289 - 0
pages/_template/app/approve/device/index1.vue

@@ -0,0 +1,289 @@
+<template>
+  <div class="page">
+    <van-list
+      v-model="isLoadingMore"
+      :finished="finished"
+      :immediate-check="false"
+      :finished-text="total ? '没有更多了' : ''"
+      @load="onLoadMore"
+    >
+      <div class="page-top flex flex-col justify-center items-center">
+        <!-- <img class="logo" :src="supplierInfo.logo" /> -->
+        <div class="mt-2 name">
+          <span v-text="supplierInfo.shopName"></span>
+          <span>官方授权设备</span>
+        </div>
+      </div>
+      <div class="page-content">
+        <!-- 搜索区域 -->
+        <div class="search">
+          <SimpleSearch
+            v-model="listQuery.name"
+            @search="onSearch"
+            placeholder="搜索设备"
+          />
+        </div>
+        <!-- 标题 -->
+        <div class="title px-4 pt-12 pb-6">
+          共<span v-text="total"></span>种设备
+        </div>
+        <!-- 列表 -->
+        <div class="list">
+          <div
+            class="section flex items-center mb-4"
+            v-for="item in list"
+            :key="item.productTypeId"
+            @click="toDetail(item)"
+          >
+            <img class="cover" :src="item.image" />
+            <div class="name" v-text="item.name"></div>
+          </div>
+          <div class="empty" v-for="i in emptyList" :key="'empty-' + i"></div>
+        </div>
+
+        <!-- 列表为空 -->
+        <SimpleEmpty
+          v-if="!total && !isRequest"
+          name="icon-empty-device.png"
+          description="敬请期待~"
+        ></SimpleEmpty>
+      </div>
+    </van-list>
+  </div>
+</template>
+
+<script>
+import { mapGetters } from 'vuex'
+import { debounce } from '@/utils'
+export default {
+  layout: 'app',
+  data() {
+    return {
+      isLoadingMore: true,
+      finished: false,
+      isRequest: true,
+      listQuery: {
+        authUserId: '',
+        name: '',
+        pageNum: 1,
+        pageSize: 9,
+      },
+      list: [],
+      total: 0,
+    }
+  },
+  computed: {
+    ...mapGetters(['supplierInfo', 'authUserId', 'routePrefix']),
+    emptyList() {
+      return 3 - (this.list.length % 3)
+    },
+  },
+  mounted() {
+    this.fetchList()
+  },
+  methods: {
+    // 获取设备分类
+    fetchList: debounce(async function () {
+      try {
+        this.isLoadingMore = true
+        this.listQuery.authUserId = this.authUserId
+        const res = await this.$http.api.getAuthProductCateList(this.listQuery)
+        this.list = [...this.list, ...res.data.list]
+        this.finished = !res.data.hasNextPage
+        this.total = res.data.total
+        this.isLoadingMore = false
+        this.listQuery.pageNum += 1
+      } catch (error) {
+        console.log(error)
+      } finally {
+        this.isRequest = false
+      }
+    }, 400),
+
+    // 设备详情
+    toDetail(item) {
+      const url = `${this.routePrefix}/approve/device/list?id=${item.productTypeId}`
+      this.$router.push(url)
+    },
+    // 搜索
+    onSearch() {
+      this.listQuery.pageNum = 1
+      this.list = []
+      this.fetchList()
+    },
+    // 加载更多
+    onLoadMore() {
+      this.fetchList()
+    },
+  },
+}
+</script>
+
+<style scoped lang="scss">
+// pc 端
+@media screen and (min-width: 768px) {
+  .page {
+    position: relative;
+    min-height: calc(100vh - 80px - 80px);
+    background-color: #fff;
+  }
+  .page-top {
+    height: 420px;
+    @include themify($themes) {
+      background: themed('pc-banner-device');
+    }
+    background-size: auto 420px;
+
+    .logo {
+      display: block;
+      width: 120px;
+      height: 120px;
+      border-radius: 50%;
+      background: #fff;
+    }
+    .name {
+      font-size: 30px;
+      color: #fff;
+    }
+
+    .logo,
+    .name {
+      transform: translateY(-30px);
+    }
+  }
+  .page-content {
+    width: 1200px;
+    margin: 0 auto;
+
+    .search {
+      position: absolute;
+      left: 50%;
+      top: 300px;
+      transform: translateX(-50%);
+    }
+
+    .title {
+      font-size: 16px;
+      color: #404040;
+
+      span {
+        @include themify($themes) {
+          color: themed('color');
+        }
+      }
+    }
+
+    .list {
+      display: flex;
+      align-items: center;
+      flex-wrap: wrap;
+      justify-content: space-between;
+
+      .empty {
+        width: 390px;
+      }
+
+      .section {
+        width: 390px;
+        height: 108px;
+        background-color: #f3f5f6;
+        border-radius: 4px;
+        box-sizing: border-box;
+        padding: 16px;
+        cursor: pointer;
+        transition: all 0.4s;
+
+        &:hover {
+          box-shadow: 0 0 24px rgba(0, 0, 0, 0.2);
+        }
+
+        .cover {
+          display: block;
+          width: 84px;
+          height: 84px;
+        }
+        .name {
+          width: 260px;
+          font-size: 16px;
+          color: #101010;
+          text-overflow: ellipsis;
+          white-space: nowrap;
+          overflow: hidden;
+          margin-left: 16px;
+        }
+      }
+    }
+  }
+}
+
+// 移动 端
+@media screen and (max-width: 768px) {
+  .page-top {
+    height: 46vw;
+    @include themify($themes) {
+      background: themed('h5-banner-device');
+    }
+    background-size: auto 46vw;
+    .logo {
+      display: block;
+      width: 14.8vw;
+      height: 14.8vw;
+      border-radius: 50%;
+      background: #fff;
+    }
+    .name {
+      font-size: 4vw;
+      color: #fff;
+    }
+  }
+  .page-content {
+    position: relative;
+    .search {
+      position: absolute;
+      left: 50%;
+      top: 0;
+      transform: translate(-50%, -50%);
+    }
+
+    .title {
+      font-size: 3.4vw;
+      color: #404040;
+
+      span {
+        @include themify($themes) {
+          color: themed('color');
+        }
+      }
+    }
+
+    .list {
+      display: flex;
+      align-items: center;
+      flex-direction: column;
+      .section {
+        width: 93.6vw;
+        height: 26vw;
+        background-color: #f3f5f6;
+        border-radius: 4px;
+        box-sizing: border-box;
+        padding: 3.2vw;
+
+        .cover {
+          display: block;
+          width: 19.6vw;
+          height: 19.6vw;
+        }
+        .name {
+          width: 66vw;
+          font-size: 4vw;
+          color: #101010;
+          text-overflow: ellipsis;
+          white-space: nowrap;
+          overflow: hidden;
+          margin-left: 3.2vw;
+        }
+      }
+    }
+  }
+}
+</style>

+ 2 - 2
pages/_template/app/form/club-bind.vue

@@ -2,8 +2,8 @@
   <div class="club-bind">
     <div class="form-container">
       <div class="logo">
-        <!-- <img src="~/assets/theme-images/ross/ross-logo.png" alt="" /> -->
-        <img :src="supplierInfo.logo" :alt="supplierInfo.shopName" />
+        <img src="~/assets/theme-images/ross/ross-logo.png" alt="" />
+        <!-- <img :src="supplierInfo.logo" :alt="supplierInfo.shopName" /> -->
       </div>
       <div class="tip">输入验证码即可完成账号注册及ROSS授权牌匾制作与寄送</div>
       <div class="form">

+ 4 - 2
pages/_template/app/form/club-register.vue

@@ -204,7 +204,7 @@ export default {
       } catch (error) {
         console.log(error)
       }
-      console.log('userfomr', this.clubUserInfo)
+      console.log('userForm', this.clubUserInfo)
     },
     onPrevStep() {
       this.step > 1 && this.step--
@@ -251,7 +251,9 @@ export default {
     toRecord() {
       if (!this.accessToken) {
         this.$toast('请登录后查看')
-        this.$router.push(`${this.routePrefix}`)
+        setTimeout(() => {
+          this.$router.push(`${this.routePrefix}`)
+        }, 1500)
         return
       }
       this.$router.push(`${this.routePrefix}/record/club/detail`)

+ 187 - 90
pages/_template/app/form/components/form-club-device.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="club-device">
-    <template v-for="formItem in formList">
+    <template v-for="(formItem, index) in formList">
       <div :key="formItem.uid" class="device-section">
         <span
           class="remove-btn"
@@ -9,96 +9,136 @@
           >删除这台设备</span
         >
         <el-form :model="formItem" :rules="rules" ref="form">
-          <el-form-item prop="productName" :label="`设备名称${formItem.uuid}:`">
-            <el-select
-              v-model="formItem.productName"
-              filterable
-              allow-create
-              placeholder="请输入新设备名称或选择已有设备"
-              @change="onProductNameChange(formItem, $event)"
+          <el-form-item label="认证方式:">
+            <el-radio-group
+              v-model="formItem.authType"
+              @change="onAuthTypeChange(formItem, index)"
             >
-              <el-option
-                v-for="item in deviceList"
-                :key="item.productTypeId"
-                :label="item.name"
-                :value="item.productTypeId"
-              />
-            </el-select>
-          </el-form-item>
-          <el-form-item prop="productImage" label="设备图片:">
-            <br />
-            <el-input v-show="false" v-model="formItem.productImage"></el-input>
-            <SimpleUploadImage
-              :disabled="Boolean(formItem.productTypeId)"
-              :limit="1"
-              :image-list="formItem.productImageList"
-              :before-upload="beforeProductImageUpload"
-              @success="uploadProductImageSuccess(formItem, $event)"
-              @remove="handleProductImageRemove(formItem, $event)"
-            />
+              <el-radio :label="1">新设备认证</el-radio>
+              <el-radio :label="2">关联已认证设备</el-radio>
+            </el-radio-group>
           </el-form-item>
-          <el-form-item label="所属品牌:" prop="brandId" v-if="editPrams">
-            <el-select v-model="formItem.brandId" placeholder="请选择品牌">
-              <el-option
-                v-for="item in brandList"
-                :key="item.id"
-                :label="item.name"
-                :value="item.id"
+          <template
+            v-if="
+              formItem.authType === 1 ||
+              (formItem.authType === 2 && formItem.snCode)
+            "
+          >
+            <el-form-item
+              prop="productName"
+              :label="`设备名称${formItem.uuid}:`"
+            >
+              <el-select
+                v-model="formItem.productName"
+                filterable
+                allow-create
+                placeholder="请输入新设备名称或选择已有设备"
+                @change="onProductNameChange(formItem, $event)"
+                clearable
+                :disabled="formItem.authType === 2"
+              >
+                <el-option
+                  v-for="item in deviceList"
+                  :key="item.productTypeId"
+                  :label="item.name"
+                  :value="item.productTypeId"
+                />
+              </el-select>
+            </el-form-item>
+            <el-form-item prop="productImage" label="设备图片:">
+              <br />
+              <el-input
+                v-show="false"
+                v-model="formItem.productImage"
+              ></el-input>
+              <SimpleUploadImage
+                :disabled="Boolean(formItem.productTypeId)"
+                :limit="1"
+                :image-list="formItem.productImageList"
+                :before-upload="beforeProductImageUpload"
+                @success="uploadProductImageSuccess(formItem, $event)"
+                @remove="handleProductImageRemove(formItem, $event)"
               />
-            </el-select>
-          </el-form-item>
-          <el-form-item prop="purchaseWay" label="购买渠道:">
-            <el-input
-              placeholder="请输入购买渠道"
-              v-model="formItem.purchaseWay"
-            ></el-input>
-          </el-form-item>
-          <el-form-item prop="invoiceImage" label="发票:">
-            <br />
-            <el-input v-show="false" v-model="formItem.invoiceImage"></el-input>
-            <SimpleUploadImage
-              :limit="1"
-              :image-list="formItem.invoiceImageList"
-              :before-upload="beforeInvoiceImageUpload"
-              @success="uploadInvoiceImageSuccess(formItem, $event)"
-              @remove="handleInvoiceImageRemove(formItem, $event)"
-            />
-          </el-form-item>
-          <el-form-item prop="snCode" label="设备SN码:">
+            </el-form-item>
+            <el-form-item label="所属品牌:" prop="infoId" v-if="editPrams">
+              <el-select
+                v-model="formItem.infoId"
+                placeholder="请选择品牌"
+                :disabled="formItem.authType === 2"
+              >
+                <el-option
+                  v-for="item in brandList"
+                  :key="item.infoId"
+                  :label="item.brandName"
+                  :value="item.infoId"
+                />
+              </el-select>
+            </el-form-item>
+            <el-form-item prop="purchaseWay" label="购买渠道:">
+              <el-input
+                placeholder="请输入购买渠道"
+                v-model="formItem.purchaseWay"
+                :disabled="formItem.authType === 2"
+              ></el-input>
+            </el-form-item>
+            <el-form-item prop="invoiceImage" label="发票:">
+              <br />
+              <el-input
+                v-show="false"
+                v-model="formItem.invoiceImage"
+              ></el-input>
+              <SimpleUploadImage
+                :disabled="formItem.authType === 2"
+                :limit="1"
+                :image-list="formItem.invoiceImageList"
+                :before-upload="beforeInvoiceImageUpload"
+                @success="uploadInvoiceImageSuccess(formItem, $event)"
+                @remove="handleInvoiceImageRemove(formItem, $event)"
+              />
+            </el-form-item>
+          </template>
+          <el-form-item prop="snCode" :label="`设备SN码${formItem.uuid}:`">
             <el-input
-              placeholder="请输入设备SN码"
-              v-model="formItem.snCode"
+              :placeholder="
+                formItem.authType === 1
+                  ? '请输入设备SN码'
+                  : '请输入已认证过的设备SN码'
+              "
+              @blur="onSnCodeBlur(formItem)"
+              v-model.lazy="formItem.snCode"
             ></el-input>
           </el-form-item>
-          <el-form-item prop="paramList" label="设备参数:">
-            <br />
-            <div class="device-param-list">
-              <span class="add-param" @click="insertParam(formItem)"
-                >添加参数</span
-              >
-              <template v-for="(param, index) in formItem.paramList">
-                <div :key="index">
-                  <div class="param flex justify-between mb-4">
-                    <el-input
-                      style="width: 40%"
-                      placeholder="例如:品牌"
-                      class="mr-2"
-                      v-model="param.paramName"
-                    ></el-input>
-                    <el-input
-                      placeholder="请输入参数信息"
-                      v-model="param.paramContent"
-                    ></el-input>
-                    <span
-                      class="remove el-icon-close"
-                      @click="removeParam(formItem, index)"
-                      v-if="formItem.paramList.length > 4"
-                    ></span>
+          <template v-if="formItem.authType === 1">
+            <el-form-item prop="paramList" label="设备参数:" v-if="editPrams">
+              <br />
+              <div class="device-param-list">
+                <span class="add-param" @click="insertParam(formItem)"
+                  >添加参数</span
+                >
+                <template v-for="(param, index) in formItem.paramList">
+                  <div :key="index">
+                    <div class="param flex justify-between mb-4">
+                      <el-input
+                        style="width: 40%"
+                        placeholder="例如:品牌"
+                        class="mr-2"
+                        v-model="param.paramName"
+                      ></el-input>
+                      <el-input
+                        placeholder="请输入参数信息"
+                        v-model="param.paramContent"
+                      ></el-input>
+                      <span
+                        class="remove el-icon-close"
+                        @click="removeParam(formItem, index)"
+                        v-if="formItem.paramList.length > 4"
+                      ></span>
+                    </div>
                   </div>
-                </div>
-              </template>
-            </div>
-          </el-form-item>
+                </template>
+              </div>
+            </el-form-item>
+          </template>
         </el-form>
         <el-divider></el-divider>
       </div>
@@ -168,7 +208,7 @@ export default {
         productImage: [
           { required: true, message: '设备图片不能为空', trigger: ['change'] },
         ],
-        brandId: [
+        infoId: [
           { required: true, message: '所属品牌不能为空', trigger: ['change'] },
         ],
         snCode: [
@@ -193,11 +233,14 @@ export default {
         invoiceImage: [
           { required: true, message: '请上传发票', trigger: ['change'] },
         ],
+        authType: [
+          { required: true, message: '请选择认证方式', trigger: ['change'] },
+        ],
       },
       formList: [],
       brandList: [],
       deviceList: [],
-      editPrams: true
+      editPrams: true,
     }
   },
 
@@ -212,6 +255,47 @@ export default {
   },
 
   methods: {
+    // sn码输入框是去焦点
+    async onSnCodeBlur(formItem) {
+      if (!formItem.authType === 1) return
+      if (!formItem.snCode) return
+      try {
+        const res = await this.$http.api.fetchDetialBySnCode({
+          snCode: formItem.snCode,
+        })
+        formItem.invoiceImage = res.data.invoiceImage
+        formItem.purchaseWay = res.data.purchaseWay
+        formItem.productTypeId = res.data.productTypeId
+        formItem.productName = res.data.productName
+        formItem.infoId = res.data.infoId
+        formItem.productImage = res.data.productImage
+        if (res.data.invoiceImage) {
+          formItem.invoiceImageList = [
+            { name: '发票', url: res.data.invoiceImage },
+          ]
+        }
+        if (res.data.productImage) {
+          formItem.productImageList = [
+            { name: '产品图片', url: res.data.productImage },
+          ]
+        }
+      } catch (error) {
+        console.log(error)
+      }
+    },
+
+    // 认证方式切换
+    onAuthTypeChange(formItem, index) {
+      formItem.purchaseWay = ''
+      formItem.invoiceImage = ''
+      formItem.productName = ''
+      formItem.productTypeId = ''
+      formItem.productImageList = []
+      formItem.invoiceImageList = []
+      formItem.paramList = this.initParams()
+      this.$refs.form[index]?.resetFields()
+    },
+
     // 表单验证
     validate() {
       this.$emit('step', this.formatFormList())
@@ -233,12 +317,13 @@ export default {
         },
       ]
       obj.uuid = ++this.uuid
+      obj.authType = formData.authType
       obj.productImageList = productImageList
       obj.invoiceImageList = invoiceImageList
       obj.productImage = formData.productImage
       obj.productName = formData.productName
       obj.snCode = formData.snCode
-      obj.brandId = formData.brandId
+      obj.infoId = formData.infoId
       obj.productId = formData.productId
       obj.productTypeId = formData.productTypeId
       obj.purchaseWay = formData.purchaseWay
@@ -252,9 +337,10 @@ export default {
       this.formList.forEach((formItem) => {
         const obj = {}
         obj.productImage = formItem.productImage
+        obj.authType = formItem.authType
         obj.productName = formItem.productName
         obj.snCode = formItem.snCode
-        obj.brandId = formItem.brandId
+        obj.infoId = formItem.infoId
         obj.productId = formItem.productId
         obj.source = 2
         obj.productTypeId = formItem.productTypeId
@@ -278,12 +364,13 @@ export default {
         productImage: '', //	设备图片
         productName: '', //	设备名称
         snCode: '', //	设备SN码
-        brandId: '',
+        infoId: '',
         productTypeId: '',
         purchaseWay: '', // 购买渠道
         invoiceImage: '', // 发票
         productImageList: [],
         invoiceImageList: [],
+        authType: 1,
       }
     },
 
@@ -411,10 +498,20 @@ export default {
         border-color: themed('color');
       }
     }
+    .el-radio__input.is-checked + .el-radio__label {
+      @include themify($themes) {
+        color: themed('color');
+      }
+    }
+    .el-radio__input.is-checked .el-radio__inner {
+      @include themify($themes) {
+        background-color: themed('color');
+        border-color: themed('color');
+      }
+    }
   }
 }
 
-
 // pc端
 @media screen and (min-width: 768px) {
   .el-select {

+ 16 - 0
pages/_template/app/form/components/form-club-info.vue

@@ -15,6 +15,18 @@
           v-model="formData.mobile"
         ></el-input>
       </el-form-item>
+      <el-form-item prop="linkMan" label="运营联系人:">
+        <el-input
+          placeholder="请输入运营联系人"
+          v-model="formData.linkMan"
+        ></el-input>
+      </el-form-item>
+      <el-form-item prop="linkMobile" label="运营联系人手机号:">
+        <el-input
+          placeholder="请输入运营联系人手机号"
+          v-model="formData.linkMobile"
+        ></el-input>
+      </el-form-item>
       <el-form-item prop="address" label="所在地区:">
         <br />
         <input type="text" v-model="formData.address" v-show="false" />
@@ -467,6 +479,8 @@ export default {
         firstClubType: this.formData.firstClubType,
         secondClubType: this.formData.secondClubType,
         medicalLicenseImage: this.formData.medicalLicenseImage,
+        linkMan: this.formData.linkMan,
+        linkMobile: this.formData.linkMobile,
         bannerList: this.bannerList.map((item) =>
           item.response ? item.response.data : item.url
         ),
@@ -486,6 +500,8 @@ export default {
       this.formData.secondClubType = formData.secondClubType
       this.formData.medicalLicenseImage = formData.medicalLicenseImage
       this.formData.point = formData.lngAndLat
+      this.formData.linkMan = formData.linkMan
+      this.formData.linkMobile = formData.linkMobile
       this.lnglat = formData.lngAndLat.split(',')
       this.logoList = [{ name: '', url: formData.logo }]
       this.bannerList = formData.bannerList.map((item) => ({

+ 11 - 3
pages/_template/app/record/club/detail.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="page">
     <div class="page-top flex flex-col justify-center items-center">
-      <!-- <img class="logo" :src="supplierInfo.logo" /> -->
+      <img class="logo" :src="supplierInfo.logo" />
       <div class="name mt-2" v-text="supplierInfo.shopName + '认证记录'"></div>
     </div>
     <div class="page-content">
@@ -15,6 +15,14 @@
           <div class="col">联系电话:</div>
           <div class="col">{{ clubInfo.mobile }}</div>
         </div>
+        <div class="row">
+          <div class="col">运营联系人:</div>
+          <div class="col">{{ clubInfo.linkMan }}</div>
+        </div>
+        <div class="row">
+          <div class="col">运营联系人手机号:</div>
+          <div class="col">{{ clubInfo.linkMobile }}</div>
+        </div>
         <div class="row">
           <div class="col">所在地区:</div>
           <div class="col">{{ clubInfo.area }}</div>
@@ -139,7 +147,7 @@
 import SimpleEmpty from '@/components/SimpleEmpty'
 import { mapGetters } from 'vuex'
 export default {
-  layout: 'app',
+  layout: 'app-ross',
   components: {
     SimpleEmpty,
   },
@@ -248,7 +256,7 @@ export default {
       .col {
         &:first-child {
           white-space: nowrap;
-          width: 110px;
+          width: 170px;
           color: #666;
           text-align: right;
           flex-shrink: 0;

+ 2 - 2
pages/_template/app/record/club/edit.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="club-info page">
     <div class="page-top flex flex-col justify-center items-center">
-      <!-- <img class="logo" :src="supplierInfo.logo" /> -->
+      <img class="logo" :src="supplierInfo.logo" />
       <div class="name mt-2" v-text="supplierInfo.shopName + '认证记录'"></div>
     </div>
     <div class="page-content">
@@ -25,7 +25,7 @@ import SimpleRadio from '@/components/SimpleRadio'
 import { mapGetters } from 'vuex'
 import FormClubInfo from '../../form/components/form-club-info.vue'
 export default {
-  layout: 'app',
+  layout: 'app-ross',
   components: {
     SimpleUploadImage,
     SimpleRadio,

+ 11 - 4
pages/_template/app/record/device/detail.vue

@@ -1,11 +1,15 @@
 <template>
   <div class="page">
     <div class="page-top flex flex-col justify-center items-center">
-      <!-- <img class="logo" :src="supplierInfo.logo" /> -->
+      <img class="logo" :src="supplierInfo.logo" />
       <div class="name mt-2" v-text="supplierInfo.shopName + '认证记录'"></div>
     </div>
     <div class="page-content">
       <div class="page-title">设备认证</div>
+      <div class="row">
+        <div class="col">认证方式:</div>
+        <div class="col">新设备认证</div>
+      </div>
       <div class="row">
         <div class="col">设备名称:</div>
         <div class="col">{{ productInfo.productName }}</div>
@@ -42,7 +46,7 @@
       </div>
       <div class="row">
         <div class="col">设备SN码:</div>
-        <div class="col">{{ productInfo.productName }}</div>
+        <div class="col">{{ productInfo.snCode }}</div>
       </div>
       <div class="row">
         <div class="col">设备参数:</div>
@@ -91,9 +95,10 @@
 <script>
 import { mapGetters } from 'vuex'
 export default {
-  layout: 'app',
+  layout: 'app-ross',
   data() {
     return {
+      relationId: '',
       productId: '',
       productInfo: {},
     }
@@ -118,6 +123,7 @@ export default {
   methods: {
     initData() {
       this.productId = this.$route.query.id
+      this.relationId = this.$route.query.relationId
       this.getProductDetails()
     },
     // 获取认证机构信息
@@ -125,6 +131,7 @@ export default {
       try {
         const res = await this.$http.api.getProductDetails({
           productId: this.productId,
+          relationId: this.relationId,
         })
         this.productInfo = { ...this.productInfo, ...res.data }
         console.log('res', this.productInfo)
@@ -143,7 +150,7 @@ export default {
     },
     onEdit() {
       this.$router.push(
-        `${this.routePrefix}/record/device/edit?type=edit&id=${this.productId}`
+        `${this.routePrefix}/record/device/edit?type=edit&id=${this.productId}&relationId=${this.relationId}`
       )
     },
   },

+ 5 - 2
pages/_template/app/record/device/edit.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="club-device page">
     <div class="page-top flex flex-col justify-center items-center">
-      <!-- <img class="logo" :src="supplierInfo.logo" /> -->
+      <img class="logo" :src="supplierInfo.logo" />
       <div class="name mt-2" v-text="supplierInfo.shopName + '认证记录'"></div>
     </div>
     <div class="page-content">
@@ -27,7 +27,7 @@
 import FormClubDevice from '../../form/components/form-club-device.vue'
 import { mapGetters } from 'vuex'
 export default {
-  layout: 'app',
+  layout: 'app-ross',
   components: {
     FormClubDevice,
   },
@@ -36,6 +36,7 @@ export default {
       productInfo: {},
       formData: {},
       productId: 0,
+      relationId: '',
       formType: '',
     }
   },
@@ -66,8 +67,10 @@ export default {
     async getProductDetails() {
       try {
         this.productId = this.$route.query.id
+        this.relationId = this.$route.query.relationId
         const res = await this.$http.api.getProductDetails({
           productId: this.productId,
+          relationId: this.relationId,
         })
         this.productInfo = res.data
         console.log('productInfo', this.productInfo)

+ 3 - 3
pages/_template/app/record/device/index.vue

@@ -8,7 +8,7 @@
       @load="onLoadMore"
     >
       <div class="page-top flex flex-col justify-center items-center">
-        <!-- <img class="logo" :src="supplierInfo.logo" /> -->
+        <img class="logo" :src="supplierInfo.logo" />
         <div
           class="name mt-2"
           v-text="supplierInfo.shopName + '认证记录'"
@@ -51,7 +51,7 @@
 import SimpleEmpty from '@/components/SimpleEmpty'
 import { mapGetters } from 'vuex'
 export default {
-  layout: 'app',
+  layout: 'app-ross',
   components: {
     SimpleEmpty,
   },
@@ -90,7 +90,7 @@ export default {
   methods: {
     toEdit(item) {
       this.$router.push(
-        `${this.routePrefix}/record/device/detail?id=${item.productId}`
+        `${this.routePrefix}/record/device/detail?id=${item.productId}&relationId=${item.relationId}`
       )
     },
     initData() {

+ 1 - 1
pages/_template/app/record/message.vue

@@ -14,7 +14,7 @@
 <script>
 import { mapGetters } from 'vuex'
 export default {
-  layout: 'app',
+  layout: 'app-ross',
   computed: {
     ...mapGetters(['supplierInfo', 'authUserId', 'routePrefix', 'accessToken']),
   },

+ 6 - 1
pages/_template/ross/approve/club/detail.vue

@@ -20,7 +20,9 @@
         <div class="section flex justify-between items-center">
           <div class="info">
             <div class="name" v-text="clubInfo.authParty"></div>
-            <div class="mobile">{{ clubInfo.mobile | formatEmpty }}</div>
+            <div class="mobile" @click="callMobile(clubInfo.mobile)">
+              {{ clubInfo.mobile | formatEmpty }}
+            </div>
             <div class="address" v-text="address"></div>
           </div>
           <div class="logo"><img :src="clubInfo.logo" /></div>
@@ -69,6 +71,7 @@
 <script>
 import { drawLogo } from '@/utils'
 import { convertor, mapNavigate } from '@/utils/map-utils'
+import { callMobile } from '@/utils'
 import { mapGetters } from 'vuex'
 export default {
   layout: 'app-ross',
@@ -108,6 +111,7 @@ export default {
     this.$removeStorage(this.routePrefix, 'clubInfo')
   },
   methods: {
+    callMobile,
     // 设备详情
     toDetail(item) {
       // window.location.href = `${process.env.CIMEI_LOCAL}/product/auth/product-${item.productId}.html`
@@ -282,6 +286,7 @@ export default {
           }
         }
         .mobile {
+          cursor: pointer;
           &::after {
             @include themify($themes) {
               background-image: themed('pc-icon-mobile');

+ 37 - 182
pages/_template/ross/approve/club/star-list.vue

@@ -1,229 +1,88 @@
 <template>
   <div class="page">
-    <van-list
-      v-model="isLoadingMore"
-      :finished="finished"
-      :immediate-check="false"
-      :finished-text="total ? '没有更多了' : ''"
-      @load="onLoadMore"
-    >
-      <!-- <div class="page-top flex flex-col justify-center items-center"></div> -->
-      <div class="page-content">
-        <!-- <div
-          class="navbar flex items-center flex-col"
-          :style="{ top: offsetTop }"
-        >
-          <nuxt-link
-            :to="routePrefix + '/approve/device'"
-            class="link flex items-center flex-col"
-          >
-            <span class="icon icon-device"></span>
-            <span class="text">设备认证</span>
-          </nuxt-link>
-          <nuxt-link
-            :to="routePrefix + '/approve/personnel/operate'"
-            class="link flex items-center flex-col md:mt-6 mt-4"
+    <div class="page-content">
+      <!-- 标题 -->
+      <div class="title flex justify-between px-4 pt-8 pb-6 md:px-0">
+        <div>明星机构</div>
+        <div>共<span v-text="total" class="font-bold"></span>家明星机构</div>
+      </div>
+      <!-- 列表 -->
+      <div class="list">
+        <template v-for="item in list">
+          <div
+            class="section flex justify-between mb-4"
+            :key="item.authId"
+            @click="toDetail(item)"
           >
-            <span class="icon icon-doctor"></span>
-            <span class="text">体疗师认证</span>
-          </nuxt-link>
-        </div>
-
-        <div class="filter">
-          <div class="search">
-            <el-input
-              placeholder="搜索机构"
-              v-model="listQuery.clubName"
-              @change="onSearch"
-            >
-              <i slot="prefix" class="el-input__icon el-icon-search"></i>
-            </el-input>
-          </div>
-          <div class="area">
-            <RossSelectGroup @change="onCityChange" ref="citySelect" />
-          </div>
-        </div> -->
-
-        <!-- 标题 -->
-        <div class="title flex justify-between px-4 pt-8 pb-6 md:px-0">
-          <div>明星机构</div>
-          <div>共<span v-text="total" class="font-bold"></span>家明星机构</div>
-        </div>
-        <!-- 列表 -->
-        <div class="list">
-          <template v-for="item in list">
-            <div
-              class="section flex justify-between mb-4"
-              :key="item.authId"
-              @click="toDetail(item)"
-            >
-              <img class="cover" :src="item.logo || drawLogo(item.clubName)" />
-              <div class="info">
-                <div class="name" v-text="item.clubName"></div>
-                <div class="mobile">{{ item.mobile || '暂无' }}</div>
-                <div class="address">
-                  {{ formatAddress(item.area, item.address) }}
-                </div>
-                <div
-                  class="distance"
-                  v-text="generateDistance(item.distance)"
-                  v-if="item.distance && item.distance !== 99999"
-                ></div>
+            <img class="cover" :src="item.logo || drawLogo(item.authParty)" />
+            <div class="info">
+              <div class="name" v-text="item.authParty"></div>
+              <div class="mobile">{{ item.mobile || '暂无' }}</div>
+              <div class="address">
+                {{ formatAddress(item.area, item.address) }}
               </div>
             </div>
-          </template>
-        </div>
-        <!-- 列表为空 -->
-        <SimpleEmpty
-          v-if="!total && !isRequest"
-          name="icon-empty-club.png"
-          description="敬请期待~"
-        ></SimpleEmpty>
+          </div>
+        </template>
       </div>
-    </van-list>
+    </div>
   </div>
 </template>
 
 <script>
 import { mapGetters } from 'vuex'
-import { geolocation } from '@/utils/map-utils'
 import { drawLogo, debounce } from '@/utils'
 export default {
   layout: 'app-ross',
   data() {
     return {
-      isLoadingMore: true,
       finished: false,
       isRequest: true,
       list: [],
-      listQuery: {
-        authUserId: '',
-        lngAndLat: '',
-        clubName: '',
-        provinceId: '',
-        cityId: '',
-        townId: '',
-        pageNum: 1,
-        pageSize: 10,
-      },
-      total: 0,
-      scrollTop: 0,
-      // starList: []
     }
   },
   computed: {
-    ...mapGetters(['authUserId', 'routePrefix', 'screenWidth', 'isPc']),
-    offsetTop() {
-      if (this.scrollTop <= window.innerHeight / 2) return '240px'
-      return 240 + this.scrollTop - window.innerHeight / 2 + 'px'
-    },
-    starList() {
-      return this.list.slice(0, 2)
+    ...mapGetters(['authUserId', 'routePrefix']),
+    total() {
+      return this.list.length
     },
   },
   mounted() {
-    const cacheData = this.$getStorage(this.routePrefix, 'club_list_data')
-    if (cacheData) {
-      this.initFromCache(cacheData)
-      this.$removeStorage(this.routePrefix, 'club_list_data')
-    } else {
-      this.initData()
-    }
-    window.addEventListener('scroll', () => {
-      this.scrollTop = document.documentElement.scrollTop
-    })
-  },
-  beforeDestroy() {
-    this.$toast.clear()
-    window.removeEventListener('scroll', () => {})
+    this.initData()
   },
   methods: {
     // 绘制logo的方法
     drawLogo,
     // 查看详情
     toDetail(item) {
-      this.$setStorage(this.routePrefix, 'club_list_data', this.$data, {
-        expiredTime: 5 * 60 * 1000,
-      })
-      this.$setStorage(this.routePrefix, 'clubInfo', item)
       const url = `${this.routePrefix}/approve/club/detail?id=${item.authId}`
       this.$router.push(url)
     },
-    // 从缓存中获取数据
-    initFromCache(cacheData) {
-      this.isLoadingMore = cacheData.isLoadingMore
-      this.finished = cacheData.finished
-      this.isRequest = cacheData.isRequest
-      this.list = cacheData.list
-      this.listQuery = cacheData.listQuery
-      this.total = cacheData.total
-      this.$nextTick(() => {
-        this.$refs.citySelect.initSelectValue({
-          provinceId: this.listQuery.provinceId,
-          cityId: this.listQuery.cityId,
-          townId: this.listQuery.townId,
-        })
-      })
-    },
-
-    generateDistance(value) {
-      return value > 1 ? value + 'km' : value * 1000 + 'm'
-    },
 
     // 初始化页面数据
     async initData() {
-      this.listQuery.authUserId = this.authUserId
-
-      // 自定义加载图标
-      // this.$toast.loading({
-      //   message: '正在获取您附近的机构...',
-      //   duration: 0,
-      // })
-
-      // 获取定位信息 这里使用的是高德地图获取用户具体位置信息
-      // try {
-      //   const resLocation = await geolocation()
-      //   this.listQuery.lngAndLat = `${resLocation.position.lng},${resLocation.position.lat}`
-      // } catch (error) {
-      //   this.$toast('获取定位信息失败,请确保您开启的定位权限并保存网络畅通')
-      //   this.isRequest = false
-      // }
       // 获取机构列表
       this.fetchList()
     },
+
     fetchList: debounce(async function () {
       try {
-        this.isLoadingMore = true
-        const res = await this.$http.api.getAuthClubList(this.listQuery)
-        this.total = res.data.total
-        this.list = [...this.list, ...res.data.list]
-        this.finished = !res.data.hasNextPage
-        this.isLoadingMore = false
-        this.listQuery.pageNum += 1
+        // 自定义加载图标
+        this.$toast.loading({
+          message: '正在获取明星机构...',
+          duration: 0,
+        })
+        const res = await this.$http.api.getAuthClubStarList({
+          authUserId: this.authUserId,
+        })
+        this.list = res.data
       } catch (error) {
         console.log(error)
       } finally {
         this.$toast.clear()
-        this.isRequest = false
       }
     }, 400),
-    // 城市变化
-    onCityChange(valueMap) {
-      const { provinceId, cityId, townId } = valueMap
-      this.listQuery.provinceId = provinceId
-      this.listQuery.cityId = cityId
-      this.listQuery.townId = townId
-
-      this.listQuery.pageNum = 1
-      this.list = []
-      this.fetchList()
-    },
-    // 搜索
-    onSearch() {
-      this.listQuery.pageNum = 1
-      this.list = []
-      this.fetchList()
-    },
+
     // 格式化地址
     formatAddress(a1, a2) {
       let resutl = ''
@@ -235,10 +94,6 @@ export default {
       }
       return resutl || '暂无'
     },
-    // 加载更多
-    onLoadMore() {
-      this.fetchList()
-    },
   },
 }
 </script>

+ 279 - 66
pages/_template/ross/approve/device/index.vue

@@ -14,90 +14,205 @@
         </div>
       </div>
       <div class="page-content">
-        <!-- 标题 -->
-        <div class="title px-4 pt-12 pb-6">
-          共<span v-text="total"></span>种设备
-        </div>
-        <!-- 列表 -->
-        <div class="list">
-          <div
-            class="section flex items-center mb-4"
-            v-for="item in list"
-            :key="item.productTypeId"
-            @click="toDetail(item)"
+        <div class="search-title">设备种类查询:</div>
+        <div class="search-container">
+          <el-select
+            v-model="listQuery.productTypeId"
+            slot="prepend"
+            placeholder="设备种类"
+            class="select-type"
+          >
+            <template v-for="product in productSelectList">
+              <el-option
+                :label="product.name"
+                :value="product.productTypeId"
+                :key="product.productTypeId"
+              ></el-option>
+            </template>
+          </el-select>
+          <el-input
+            :placeholder="
+              searchQuery.type === 1 ? '请输入SN码' : '请输入机构名'
+            "
+            v-model="searchQuery.keyword"
+            class="input-with-select"
+          >
+            <el-select
+              v-model="searchQuery.type"
+              slot="prepend"
+              placeholder="请选择"
+            >
+              <el-option label="SN码" :value="1"></el-option>
+              <el-option label="机构名" :value="2"></el-option>
+            </el-select>
+            <i slot="prefix" class="el-input__icon el-icon-search"></i>
+          </el-input>
+          <el-button class="submit" type="warning" @click="onSearch"
+            >查询</el-button
           >
-            <img class="cover" :src="item.image" />
-            <div class="name" v-text="item.name"></div>
-          </div>
         </div>
-
-        <!-- 列表为空 -->
-        <SimpleEmpty
-          v-if="!total && !isRequest"
-          name="icon-empty-device.png"
-          description="敬请期待~"
-        ></SimpleEmpty>
+        <template v-if="list.length > 0 || searchFlag">
+          <!-- 标题 -->
+          <div class="title px-4 pt-12 pb-6 md:px-0">
+            共<span v-text="total"></span>台设备
+          </div>
+          <!-- 列表 -->
+          <div class="list">
+            <div
+              class="section flex justify-between mb-4"
+              v-for="item in list"
+              :key="item.productId"
+              @click="toDetail(item)"
+            >
+              <img class="cover" :src="item.productImage" />
+              <div class="info">
+                <div class="name" v-text="item.productName"></div>
+                <div class="code">SN码:{{ item.snCode | formatSnCode }}</div>
+                <el-popover placement="right" title="机构列表" trigger="hover">
+                  <template v-for="club in item.clubList">
+                    <div
+                      @click.stop="toClubDetail(club)"
+                      :key="club.authId"
+                      class="club-item"
+                    >
+                      {{ club.authParty }}
+                    </div>
+                  </template>
+                  <div class="club-name" slot="reference">
+                    所属机构:
+                    <template v-for="club in item.clubList">
+                      ,<span :key="club.authId">{{ club.authParty }}</span>
+                    </template>
+                  </div>
+                </el-popover>
+              </div>
+            </div>
+          </div>
+          <!-- 列表为空 -->
+          <SimpleEmpty
+            v-if="!total && !isRequest"
+            name="icon-empty-device.png"
+            description="敬请期待~"
+          ></SimpleEmpty>
+        </template>
       </div>
     </van-list>
   </div>
 </template>
 
 <script>
-import { mapGetters } from 'vuex'
 import { debounce } from '@/utils'
+import { mapGetters } from 'vuex'
 export default {
   layout: 'app-ross',
+  filters: {
+    formatSnCode(code) {
+      if (!code) return ''
+      return code.replace(/^(\w{2})\w+(\w{4})$/, '$1******$2')
+    },
+  },
   data() {
     return {
-      isLoadingMore: true,
+      isLoadingMore: false,
       finished: false,
       isRequest: true,
+      searchQuery: {
+        type: 2,
+        keyword: '测试机构A',
+      },
       listQuery: {
-        authUserId: '',
-        name: '',
+        listType: 1,
+        productTypeId: '',
+        snCode: '',
+        authParty: '测试机构A',
         pageNum: 1,
-        pageSize: 9,
+        pageSize: 10,
       },
       list: [],
       total: 0,
+      productSelectList: [],
+      searchFlag: false,
     }
   },
   computed: {
-    ...mapGetters(['supplierInfo', 'authUserId', 'routePrefix']),
+    ...mapGetters(['routePrefix', 'supplierInfo', 'authUserId']),
   },
   mounted() {
-    this.fetchList()
+    this.fetchProductSelectList()
   },
   methods: {
-    // 获取设备分类
+    // 获取设备列表
     fetchList: debounce(async function () {
       try {
         this.isLoadingMore = true
-        this.listQuery.authUserId = this.authUserId
-        const res = await this.$http.api.getAuthProductCateList(this.listQuery)
+        const res = await this.$http.api.getAuthProductList(this.listQuery)
         this.list = [...this.list, ...res.data.list]
         this.finished = !res.data.hasNextPage
         this.total = res.data.total
         this.isLoadingMore = false
         this.listQuery.pageNum += 1
+        this.searchFlag = true
       } catch (error) {
         console.log(error)
       } finally {
         this.isRequest = false
+        this.searchFlag = true
       }
     }, 400),
 
-    // 设备详情
-    toDetail(item) {
-      const url = `${this.routePrefix}/approve/device/search?id=${item.productTypeId}`
-      this.$router.push(url)
-    },
     // 搜索
     onSearch() {
-      this.listQuery.pageNum = 1
+      const { productTypeId } = this.listQuery
+      const { type, keyword } = this.searchQuery
+      if (!productTypeId) {
+        return this.$toast('请选择设备分类')
+      }
+      if (!type) {
+        return this.$toast('请选择搜索条件')
+      }
+      if (!keyword) {
+        return this.$toast('搜索内容不能为空')
+      }
+
+      if (type === 1) {
+        this.listQuery.snCode = keyword
+        this.listQuery.authParty = ''
+      } else {
+        this.listQuery.snCode = ''
+        this.listQuery.authParty = keyword
+      }
+
       this.list = []
+      this.listQuery.pageNum = 1
       this.fetchList()
     },
+
+    // 获取设备种类
+    async fetchProductSelectList() {
+      try {
+        const res = await this.$http.api.fetchProductSelectList({
+          authUserId: this.authUserId,
+        })
+        this.productSelectList = res.data
+      } catch (error) {
+        console.log(error)
+      }
+    },
+
+    // 设备详情
+    toDetail(item) {
+      // window.location.href = `${process.env.CIMEI_LOCAL}/product/auth/product-${item.productId}.html`
+      this.$router.push(
+        `${this.routePrefix}/approve/device/detail?id=${item.productId}`
+      )
+    },
+
+    // 机构详情
+    toClubDetail(item) {
+      const url = `${this.routePrefix}/approve/club/detail?id=${item.authId}`
+      this.$router.push(url)
+    },
+
     // 加载更多
     onLoadMore() {
       this.fetchList()
@@ -107,8 +222,26 @@ export default {
 </script>
 
 <style scoped lang="scss">
+.input-with-select {
+  ::v-deep {
+    .el-input-group__prepend {
+      background-color: #fff;
+    }
+  }
+}
+
 // pc 端
 @media screen and (min-width: 768px) {
+  .el-popover {
+    .club-item {
+      line-height: 24px;
+      cursor: pointer;
+      &:hover {
+        color: #f3920d;
+      }
+    }
+  }
+
   .page {
     position: relative;
     min-height: calc(100vh - 80px - 80px);
@@ -118,8 +251,8 @@ export default {
     height: 420px;
     @include themify($themes) {
       background: themed('pc-banner-device');
-      background-size: auto 420px;
     }
+    background-size: auto 420px;
 
     .logo {
       display: block;
@@ -137,11 +270,29 @@ export default {
     width: 1000px;
     margin: 0 auto;
 
-    .search {
-      position: absolute;
-      left: 50%;
-      top: 300px;
-      transform: translateX(-50%);
+    .search-title {
+      font-size: 16px;
+      color: #404040;
+      margin: 25px 0;
+    }
+
+    .search-container {
+      display: flex;
+      justify-content: space-between;
+      .input-with-select {
+        margin: 0 15px;
+        .el-select {
+          ::v-deep {
+            .el-input {
+              width: 130px;
+            }
+          }
+        }
+      }
+
+      .submit {
+        width: 295px;
+      }
     }
 
     .title {
@@ -174,7 +325,6 @@ export default {
         padding: 16px;
         cursor: pointer;
         transition: all 0.4s;
-
         &:hover {
           box-shadow: 0 0 24px rgba(0, 0, 0, 0.2);
         }
@@ -184,15 +334,35 @@ export default {
           width: 104px;
           height: 104px;
         }
-        .name {
-          width: 260px;
-          font-size: 18px;
-          color: #101010;
-          text-overflow: ellipsis;
-          white-space: nowrap;
-          overflow: hidden;
-          margin-left: 16px;
-          font-weight: bold;
+        .info {
+          width: 336px;
+          position: relative;
+
+          .name {
+            font-size: 18px;
+            color: #101010;
+            font-weight: bold;
+            margin-bottom: 16px;
+            margin-top: 4px;
+            text-overflow: ellipsis;
+            white-space: nowrap;
+            overflow: hidden;
+          }
+          .code,
+          .club-name {
+            position: relative;
+            font-size: 14px;
+            color: #666;
+            line-height: 24px;
+            text-overflow: ellipsis;
+            white-space: nowrap;
+            overflow: hidden;
+            margin-top: 6px;
+
+            span {
+              color: #1890ff;
+            }
+          }
         }
       }
     }
@@ -207,7 +377,7 @@ export default {
       background: themed('h5-banner-device');
       background-size: auto 46vw;
     }
-    
+
     .logo {
       display: block;
       width: 14.8vw;
@@ -222,11 +392,34 @@ export default {
   }
   .page-content {
     position: relative;
-    .search {
-      position: absolute;
-      left: 50%;
-      top: 0;
-      transform: translate(-50%, -50%);
+
+    .search-title {
+      font-size: 3.4vw;
+      color: #404040;
+      margin: 3.2vw;
+    }
+
+    .search-container {
+      padding: 0 3.2vw;
+
+      .select-type {
+        width: 100%;
+      }
+
+      .input-with-select {
+        margin: 3.2vw 0;
+        .el-select {
+          ::v-deep {
+            .el-input {
+              width: 130px;
+            }
+          }
+        }
+      }
+
+      .submit {
+        width: 100%;
+      }
     }
 
     .title {
@@ -244,6 +437,7 @@ export default {
       display: flex;
       align-items: center;
       flex-direction: column;
+
       .section {
         width: 93.6vw;
         height: 26vw;
@@ -257,14 +451,33 @@ export default {
           width: 19.6vw;
           height: 19.6vw;
         }
-        .name {
-          width: 66vw;
-          font-size: 4vw;
-          color: #101010;
-          text-overflow: ellipsis;
-          white-space: nowrap;
-          overflow: hidden;
+        .info {
+          position: relative;
           margin-left: 3.2vw;
+          .name {
+            font-size: 4vw;
+            color: #101010;
+            font-weight: bold;
+            margin-bottom: 4vw;
+            text-overflow: ellipsis;
+            white-space: nowrap;
+            overflow: hidden;
+          }
+          .code,
+          .club-name {
+            width: 66vw;
+            position: relative;
+            font-size: 3vw;
+            color: #404040;
+            line-height: 5vw;
+            text-overflow: ellipsis;
+            white-space: nowrap;
+            overflow: hidden;
+
+            span {
+              color: #6d9eff;
+            }
+          }
         }
       }
     }

+ 273 - 0
pages/_template/ross/approve/device/index1.vue

@@ -0,0 +1,273 @@
+<template>
+  <div class="page">
+    <van-list
+      v-model="isLoadingMore"
+      :finished="finished"
+      :immediate-check="false"
+      :finished-text="total ? '没有更多了' : ''"
+      @load="onLoadMore"
+    >
+      <div class="page-top flex flex-col justify-center items-center">
+        <img class="logo" :src="supplierInfo.logo" />
+        <div class="mt-2 name">
+          <span v-text="supplierInfo.shopName"></span><span>官方授权设备</span>
+        </div>
+      </div>
+      <div class="page-content">
+        <!-- 标题 -->
+        <div class="title px-4 pt-12 pb-6">
+          共<span v-text="total"></span>种设备
+        </div>
+        <!-- 列表 -->
+        <div class="list">
+          <div
+            class="section flex items-center mb-4"
+            v-for="item in list"
+            :key="item.productTypeId"
+            @click="toDetail(item)"
+          >
+            <img class="cover" :src="item.image" />
+            <div class="name" v-text="item.name"></div>
+          </div>
+        </div>
+
+        <!-- 列表为空 -->
+        <SimpleEmpty
+          v-if="!total && !isRequest"
+          name="icon-empty-device.png"
+          description="敬请期待~"
+        ></SimpleEmpty>
+      </div>
+    </van-list>
+  </div>
+</template>
+
+<script>
+import { mapGetters } from 'vuex'
+import { debounce } from '@/utils'
+export default {
+  layout: 'app-ross',
+  data() {
+    return {
+      isLoadingMore: true,
+      finished: false,
+      isRequest: true,
+      listQuery: {
+        authUserId: '',
+        name: '',
+        pageNum: 1,
+        pageSize: 9,
+      },
+      list: [],
+      total: 0,
+    }
+  },
+  computed: {
+    ...mapGetters(['supplierInfo', 'authUserId', 'routePrefix']),
+  },
+  mounted() {
+    this.fetchList()
+  },
+  methods: {
+    // 获取设备分类
+    fetchList: debounce(async function () {
+      try {
+        this.isLoadingMore = true
+        this.listQuery.authUserId = this.authUserId
+        const res = await this.$http.api.getAuthProductCateList(this.listQuery)
+        this.list = [...this.list, ...res.data.list]
+        this.finished = !res.data.hasNextPage
+        this.total = res.data.total
+        this.isLoadingMore = false
+        this.listQuery.pageNum += 1
+      } catch (error) {
+        console.log(error)
+      } finally {
+        this.isRequest = false
+      }
+    }, 400),
+
+    // 设备详情
+    toDetail(item) {
+      const url = `${this.routePrefix}/approve/device/search?id=${item.productTypeId}`
+      this.$router.push(url)
+    },
+    // 搜索
+    onSearch() {
+      this.listQuery.pageNum = 1
+      this.list = []
+      this.fetchList()
+    },
+    // 加载更多
+    onLoadMore() {
+      this.fetchList()
+    },
+  },
+}
+</script>
+
+<style scoped lang="scss">
+// pc 端
+@media screen and (min-width: 768px) {
+  .page {
+    position: relative;
+    min-height: calc(100vh - 80px - 80px);
+    background-color: #fff;
+  }
+  .page-top {
+    height: 420px;
+    @include themify($themes) {
+      background: themed('pc-banner-device');
+      background-size: auto 420px;
+    }
+
+    .logo {
+      display: block;
+      width: 120px;
+      height: 120px;
+      border-radius: 50%;
+      background: #fff;
+    }
+    .name {
+      font-size: 30px;
+      color: #fff;
+    }
+  }
+  .page-content {
+    width: 1000px;
+    margin: 0 auto;
+
+    .search {
+      position: absolute;
+      left: 50%;
+      top: 300px;
+      transform: translateX(-50%);
+    }
+
+    .title {
+      font-size: 16px;
+      color: #404040;
+
+      span {
+        @include themify($themes) {
+          color: themed('color');
+        }
+      }
+    }
+
+    .list {
+      display: flex;
+      align-items: center;
+      flex-wrap: wrap;
+      justify-content: space-between;
+
+      .empty {
+        width: 390px;
+      }
+
+      .section {
+        width: 490px;
+        height: 136px;
+        background-color: #f3f5f6;
+        border-radius: 4px;
+        box-sizing: border-box;
+        padding: 16px;
+        cursor: pointer;
+        transition: all 0.4s;
+
+        &:hover {
+          box-shadow: 0 0 24px rgba(0, 0, 0, 0.2);
+        }
+
+        .cover {
+          display: block;
+          width: 104px;
+          height: 104px;
+        }
+        .name {
+          width: 260px;
+          font-size: 18px;
+          color: #101010;
+          text-overflow: ellipsis;
+          white-space: nowrap;
+          overflow: hidden;
+          margin-left: 16px;
+          font-weight: bold;
+        }
+      }
+    }
+  }
+}
+
+// 移动 端
+@media screen and (max-width: 768px) {
+  .page-top {
+    height: 46vw;
+    @include themify($themes) {
+      background: themed('h5-banner-device');
+      background-size: auto 46vw;
+    }
+    
+    .logo {
+      display: block;
+      width: 14.8vw;
+      height: 14.8vw;
+      border-radius: 50%;
+      background: #fff;
+    }
+    .name {
+      font-size: 4vw;
+      color: #fff;
+    }
+  }
+  .page-content {
+    position: relative;
+    .search {
+      position: absolute;
+      left: 50%;
+      top: 0;
+      transform: translate(-50%, -50%);
+    }
+
+    .title {
+      font-size: 3.4vw;
+      color: #404040;
+
+      span {
+        @include themify($themes) {
+          color: themed('color');
+        }
+      }
+    }
+
+    .list {
+      display: flex;
+      align-items: center;
+      flex-direction: column;
+      .section {
+        width: 93.6vw;
+        height: 26vw;
+        background-color: #f3f5f6;
+        border-radius: 4px;
+        box-sizing: border-box;
+        padding: 3.2vw;
+
+        .cover {
+          display: block;
+          width: 19.6vw;
+          height: 19.6vw;
+        }
+        .name {
+          width: 66vw;
+          font-size: 4vw;
+          color: #101010;
+          text-overflow: ellipsis;
+          white-space: nowrap;
+          overflow: hidden;
+          margin-left: 3.2vw;
+        }
+      }
+    }
+  }
+}
+</style>

+ 3 - 3
pages/_template/ross/form/club-register.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="page">
     <div class="page-top flex flex-col justify-center items-center">
-      <img class="logo" :src="supplierInfo.logo" />
+      <!-- <img class="logo" :src="supplierInfo.logo" /> -->
       <div
         class="name mt-2"
         v-text="supplierInfo.shopName + '正品授权申请'"
@@ -100,7 +100,7 @@ export default {
       isRequest: true,
       active: false,
       registerType: [3],
-      step: 3,
+      step: 1,
       stepList: [
         {
           label: '账号注册',
@@ -204,7 +204,7 @@ export default {
       } catch (error) {
         console.log(error)
       }
-      console.log('userfomr', this.clubUserInfo)
+      console.log('userForm', this.clubUserInfo)
     },
     onPrevStep() {
       this.step > 1 && this.step--

+ 74 - 15
pages/_template/ross/form/components/form-club-device.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="club-device">
-    <template v-for="formItem in formList">
+    <template v-for="(formItem, index) in formList">
       <div :key="formItem.uid" class="device-section">
         <span
           class="remove-btn"
@@ -9,13 +9,21 @@
           >删除这台设备</span
         >
         <el-form :model="formItem" :rules="rules" ref="form">
-          <el-form-item label="认证方式:" prop="authType">
-            <el-radio-group v-model="formItem.authType">
+          <el-form-item label="认证方式:">
+            <el-radio-group
+              v-model="formItem.authType"
+              @change="onAuthTypeChange(formItem, index)"
+            >
               <el-radio :label="1">新设备认证</el-radio>
               <el-radio :label="2">关联已认证设备</el-radio>
             </el-radio-group>
           </el-form-item>
-          <template v-if="formItem.authType === 1">
+          <template
+            v-if="
+              formItem.authType === 1 ||
+              (formItem.authType === 2 && formItem.snCode)
+            "
+          >
             <el-form-item
               prop="productName"
               :label="`设备名称${formItem.uuid}:`"
@@ -27,6 +35,7 @@
                 placeholder="请输入新设备名称或选择已有设备"
                 @change="onProductNameChange(formItem, $event)"
                 clearable
+                :disabled="formItem.authType === 2"
               >
                 <el-option
                   v-for="item in deviceList"
@@ -51,13 +60,17 @@
                 @remove="handleProductImageRemove(formItem, $event)"
               />
             </el-form-item>
-            <el-form-item label="所属品牌:" prop="brandId" v-if="editPrams">
-              <el-select v-model="formItem.brandId" placeholder="请选择品牌">
+            <el-form-item label="所属品牌:" prop="infoId" v-if="editPrams">
+              <el-select
+                v-model="formItem.infoId"
+                placeholder="请选择品牌"
+                :disabled="formItem.authType === 2"
+              >
                 <el-option
                   v-for="item in brandList"
-                  :key="item.id"
-                  :label="item.name"
-                  :value="item.id"
+                  :key="item.infoId"
+                  :label="item.brandName"
+                  :value="item.infoId"
                 />
               </el-select>
             </el-form-item>
@@ -65,6 +78,7 @@
               <el-input
                 placeholder="请输入购买渠道"
                 v-model="formItem.purchaseWay"
+                :disabled="formItem.authType === 2"
               ></el-input>
             </el-form-item>
             <el-form-item prop="invoiceImage" label="发票:">
@@ -74,6 +88,7 @@
                 v-model="formItem.invoiceImage"
               ></el-input>
               <SimpleUploadImage
+                :disabled="formItem.authType === 2"
                 :limit="1"
                 :image-list="formItem.invoiceImageList"
                 :before-upload="beforeInvoiceImageUpload"
@@ -82,14 +97,15 @@
               />
             </el-form-item>
           </template>
-          <el-form-item prop="snCode" label="设备SN码:">
+          <el-form-item prop="snCode" :label="`设备SN码${formItem.uuid}:`">
             <el-input
               :placeholder="
                 formItem.authType === 1
                   ? '请输入设备SN码'
                   : '请输入已认证过的设备SN码'
               "
-              v-model="formItem.snCode"
+              @blur="onSnCodeBlur(formItem)"
+              v-model.lazy="formItem.snCode"
             ></el-input>
           </el-form-item>
           <template v-if="formItem.authType === 1">
@@ -192,7 +208,7 @@ export default {
         productImage: [
           { required: true, message: '设备图片不能为空', trigger: ['change'] },
         ],
-        brandId: [
+        infoId: [
           { required: true, message: '所属品牌不能为空', trigger: ['change'] },
         ],
         snCode: [
@@ -239,6 +255,47 @@ export default {
   },
 
   methods: {
+    // sn码输入框是去焦点
+    async onSnCodeBlur(formItem) {
+      if (!formItem.authType === 1) return
+      if (!formItem.snCode) return
+      try {
+        const res = await this.$http.api.fetchDetialBySnCode({
+          snCode: formItem.snCode,
+        })
+        formItem.invoiceImage = res.data.invoiceImage
+        formItem.purchaseWay = res.data.purchaseWay
+        formItem.productTypeId = res.data.productTypeId
+        formItem.productName = res.data.productName
+        formItem.infoId = res.data.infoId
+        formItem.productImage = res.data.productImage
+        if (res.data.invoiceImage) {
+          formItem.invoiceImageList = [
+            { name: '发票', url: res.data.invoiceImage },
+          ]
+        }
+        if (res.data.productImage) {
+          formItem.productImageList = [
+            { name: '产品图片', url: res.data.productImage },
+          ]
+        }
+      } catch (error) {
+        console.log(error)
+      }
+    },
+
+    // 认证方式切换
+    onAuthTypeChange(formItem, index) {
+      formItem.purchaseWay = ''
+      formItem.invoiceImage = ''
+      formItem.productName = ''
+      formItem.productTypeId = ''
+      formItem.productImageList = []
+      formItem.invoiceImageList = []
+      formItem.paramList = this.initParams()
+      this.$refs.form[index]?.resetFields()
+    },
+
     // 表单验证
     validate() {
       this.$emit('step', this.formatFormList())
@@ -260,12 +317,13 @@ export default {
         },
       ]
       obj.uuid = ++this.uuid
+      obj.authType = formData.authType
       obj.productImageList = productImageList
       obj.invoiceImageList = invoiceImageList
       obj.productImage = formData.productImage
       obj.productName = formData.productName
       obj.snCode = formData.snCode
-      obj.brandId = formData.brandId
+      obj.infoId = formData.infoId
       obj.productId = formData.productId
       obj.productTypeId = formData.productTypeId
       obj.purchaseWay = formData.purchaseWay
@@ -279,9 +337,10 @@ export default {
       this.formList.forEach((formItem) => {
         const obj = {}
         obj.productImage = formItem.productImage
+        obj.authType = formItem.authType
         obj.productName = formItem.productName
         obj.snCode = formItem.snCode
-        obj.brandId = formItem.brandId
+        obj.infoId = formItem.infoId
         obj.productId = formItem.productId
         obj.source = 2
         obj.productTypeId = formItem.productTypeId
@@ -305,7 +364,7 @@ export default {
         productImage: '', //	设备图片
         productName: '', //	设备名称
         snCode: '', //	设备SN码
-        brandId: '',
+        infoId: '',
         productTypeId: '',
         purchaseWay: '', // 购买渠道
         invoiceImage: '', // 发票

+ 8 - 4
pages/_template/ross/form/components/form-club-info.vue

@@ -15,16 +15,16 @@
           v-model="formData.mobile"
         ></el-input>
       </el-form-item>
-      <el-form-item prop="mobile" label="运营联系人:">
+      <el-form-item prop="linkMan" label="运营联系人:">
         <el-input
           placeholder="请输入运营联系人"
-          v-model="formData.mobile"
+          v-model="formData.linkMan"
         ></el-input>
       </el-form-item>
-      <el-form-item prop="mobile" label="运营联系人手机号:">
+      <el-form-item prop="linkMobile" label="运营联系人手机号:">
         <el-input
           placeholder="请输入运营联系人手机号"
-          v-model="formData.mobile"
+          v-model="formData.linkMobile"
         ></el-input>
       </el-form-item>
       <el-form-item prop="address" label="所在地区:">
@@ -479,6 +479,8 @@ export default {
         firstClubType: this.formData.firstClubType,
         secondClubType: this.formData.secondClubType,
         medicalLicenseImage: this.formData.medicalLicenseImage,
+        linkMan: this.formData.linkMan,
+        linkMobile: this.formData.linkMobile,
         bannerList: this.bannerList.map((item) =>
           item.response ? item.response.data : item.url
         ),
@@ -498,6 +500,8 @@ export default {
       this.formData.secondClubType = formData.secondClubType
       this.formData.medicalLicenseImage = formData.medicalLicenseImage
       this.formData.point = formData.lngAndLat
+      this.formData.linkMan = formData.linkMan
+      this.formData.linkMobile = formData.linkMobile
       this.lnglat = formData.lngAndLat.split(',')
       this.logoList = [{ name: '', url: formData.logo }]
       this.bannerList = formData.bannerList.map((item) => ({

+ 22 - 12
pages/_template/ross/index.vue

@@ -33,7 +33,7 @@
           <div class="search">
             <el-input
               placeholder="搜索机构"
-              v-model="listQuery.clubName"
+              v-model="listQuery.authParty"
               @change="onSearch"
             >
               <i slot="prefix" class="el-input__icon el-icon-search"></i>
@@ -62,19 +62,19 @@
               >
                 <img
                   class="cover"
-                  :src="item.logo || drawLogo(item.clubName)"
+                  :src="item.logo || drawLogo(item.authParty)"
                 />
                 <div class="info">
-                  <div class="name" v-text="item.clubName"></div>
+                  <div class="name" v-text="item.authParty"></div>
                   <div class="mobile">{{ item.mobile || '暂无' }}</div>
                   <div class="address">
                     {{ formatAddress(item.area, item.address) }}
                   </div>
-                  <div
+                  <!-- <div
                     class="distance"
                     v-text="generateDistance(item.distance)"
                     v-if="item.distance && item.distance !== 99999"
-                  ></div>
+                  ></div> -->
                 </div>
               </div>
             </template>
@@ -94,9 +94,9 @@
               :key="item.authId"
               @click="toDetail(item)"
             >
-              <img class="cover" :src="item.logo || drawLogo(item.clubName)" />
+              <img class="cover" :src="item.logo || drawLogo(item.authParty)" />
               <div class="info">
-                <div class="name" v-text="item.clubName"></div>
+                <div class="name" v-text="item.authParty"></div>
                 <div class="mobile">{{ item.mobile || '暂无' }}</div>
                 <div class="address">
                   {{ formatAddress(item.area, item.address) }}
@@ -136,7 +136,7 @@ export default {
       listQuery: {
         authUserId: '',
         lngAndLat: '',
-        clubName: '',
+        authParty: '',
         provinceId: '',
         cityId: '',
         townId: '',
@@ -145,7 +145,7 @@ export default {
       },
       total: 0,
       scrollTop: 0,
-      // starList: []
+      starList: [],
     }
   },
   computed: {
@@ -154,9 +154,6 @@ export default {
       if (this.scrollTop <= window.innerHeight / 2) return '240px'
       return 240 + this.scrollTop - window.innerHeight / 2 + 'px'
     },
-    starList() {
-      return this.list.slice(0, 2)
-    },
   },
   mounted() {
     const cacheData = this.$getStorage(this.routePrefix, 'club_list_data')
@@ -169,12 +166,25 @@ export default {
     window.addEventListener('scroll', () => {
       this.scrollTop = document.documentElement.scrollTop
     })
+    this.fetchAuthClubStarList()
   },
   beforeDestroy() {
     this.$toast.clear()
     window.removeEventListener('scroll', () => {})
   },
   methods: {
+    // 获取明星机构列表
+    async fetchAuthClubStarList() {
+      try {
+        const res = await this.$http.api.getAuthClubStarList({
+          authUserId: this.authUserId,
+        })
+        this.starList = res.data.slice(0, 2)
+      } catch (error) {
+        console.log(error)
+      }
+    },
+
     // 绘制logo的方法
     drawLogo,
     // 查看详情

+ 3 - 3
pages/_template/ross/record/club/detail.vue

@@ -17,11 +17,11 @@
         </div>
         <div class="row">
           <div class="col">运营联系人:</div>
-          <div class="col">{{ clubInfo.mobile }}</div>
+          <div class="col">{{ clubInfo.linkMan }}</div>
         </div>
         <div class="row">
           <div class="col">运营联系人手机号:</div>
-          <div class="col">{{ clubInfo.mobile }}</div>
+          <div class="col">{{ clubInfo.linkMobile }}</div>
         </div>
         <div class="row">
           <div class="col">所在地区:</div>
@@ -256,7 +256,7 @@ export default {
       .col {
         &:first-child {
           white-space: nowrap;
-          width: 110px;
+          width: 170px;
           color: #666;
           text-align: right;
           flex-shrink: 0;

+ 5 - 2
pages/_template/ross/record/device/detail.vue

@@ -46,7 +46,7 @@
       </div>
       <div class="row">
         <div class="col">设备SN码:</div>
-        <div class="col">{{ productInfo.productName }}</div>
+        <div class="col">{{ productInfo.snCode }}</div>
       </div>
       <div class="row">
         <div class="col">设备参数:</div>
@@ -98,6 +98,7 @@ export default {
   layout: 'app-ross',
   data() {
     return {
+      relationId: '',
       productId: '',
       productInfo: {},
     }
@@ -122,6 +123,7 @@ export default {
   methods: {
     initData() {
       this.productId = this.$route.query.id
+      this.relationId = this.$route.query.relationId
       this.getProductDetails()
     },
     // 获取认证机构信息
@@ -129,6 +131,7 @@ export default {
       try {
         const res = await this.$http.api.getProductDetails({
           productId: this.productId,
+          relationId: this.relationId,
         })
         this.productInfo = { ...this.productInfo, ...res.data }
         console.log('res', this.productInfo)
@@ -147,7 +150,7 @@ export default {
     },
     onEdit() {
       this.$router.push(
-        `${this.routePrefix}/record/device/edit?type=edit&id=${this.productId}`
+        `${this.routePrefix}/record/device/edit?type=edit&id=${this.productId}&relationId=${this.relationId}`
       )
     },
   },

+ 3 - 0
pages/_template/ross/record/device/edit.vue

@@ -36,6 +36,7 @@ export default {
       productInfo: {},
       formData: {},
       productId: 0,
+      relationId: '',
       formType: '',
     }
   },
@@ -66,8 +67,10 @@ export default {
     async getProductDetails() {
       try {
         this.productId = this.$route.query.id
+        this.relationId = this.$route.query.relationId
         const res = await this.$http.api.getProductDetails({
           productId: this.productId,
+          relationId: this.relationId,
         })
         this.productInfo = res.data
         console.log('productInfo', this.productInfo)

+ 1 - 1
pages/_template/ross/record/device/index.vue

@@ -90,7 +90,7 @@ export default {
   methods: {
     toEdit(item) {
       this.$router.push(
-        `${this.routePrefix}/record/device/detail?id=${item.productId}`
+        `${this.routePrefix}/record/device/detail?id=${item.productId}&relationId=${item.relationId}`
       )
     },
     initData() {

+ 7 - 0
utils/index.js

@@ -155,3 +155,10 @@ export async function downloadWithUrl(downUrl, fileName, self) {
     notification.close()
   }
 }
+
+export function callMobile(mobile) {
+  if (!mobile) return
+  const a = document.createElement('a')
+  a.href = 'tel:' + mobile
+  a.click()
+}