Kaynağa Gözat

用户咨询记录

zhengjinyi 1 yıl önce
ebeveyn
işleme
22acc612d0
37 değiştirilmiş dosya ile 7237 ekleme ve 82 silme
  1. 12 0
      .eslintrc.js
  2. 96 0
      src/api/library/keyword.js
  3. 215 0
      src/api/user/consult/consult.js
  4. 393 0
      src/api/user/customer/customer.js
  5. 13 1
      src/router/modules/keywordLibrary.js
  6. 110 1
      src/router/modules/user.js
  7. 8 0
      src/styles/index.scss
  8. 52 0
      src/utils/time-picker.js
  9. 159 0
      src/views/library/tag/components/label-dialog.vue
  10. 50 45
      src/views/library/tag/list.vue
  11. 296 0
      src/views/library/tag/priority-list.vue
  12. 375 0
      src/views/library/tag/static-list.vue
  13. 25 28
      src/views/member/product/list.vue
  14. 8 7
      src/views/sys/login/index.vue
  15. 177 0
      src/views/user/consult/components/datePicker.vue
  16. 516 0
      src/views/user/consult/detail.vue
  17. 237 0
      src/views/user/consult/genre-list.vue
  18. 599 0
      src/views/user/consult/list.vue
  19. 292 0
      src/views/user/consult/report-list.vue
  20. 469 0
      src/views/user/consult/unreg-detail.vue
  21. 168 0
      src/views/user/consult/unreg-list.vue
  22. 300 0
      src/views/user/customer/advertis-edit.vue
  23. 262 0
      src/views/user/customer/advertis-list.vue
  24. 151 0
      src/views/user/customer/components/article-dialog.vue
  25. 174 0
      src/views/user/customer/components/article.vue
  26. 188 0
      src/views/user/customer/components/product.vue
  27. 124 0
      src/views/user/customer/components/search-dialog.vue
  28. 158 0
      src/views/user/customer/components/search.vue
  29. 139 0
      src/views/user/customer/components/shop-advertis-dialog.vue
  30. 150 0
      src/views/user/customer/components/shop-dialog.vue
  31. 162 0
      src/views/user/customer/components/shop.vue
  32. 248 0
      src/views/user/customer/customer-article-list.vue
  33. 58 0
      src/views/user/customer/customer-page-list.vue
  34. 207 0
      src/views/user/customer/customer-popup-edit.vue
  35. 225 0
      src/views/user/customer/customer-search-list.vue
  36. 174 0
      src/views/user/customer/customer-stat-list.vue
  37. 247 0
      src/views/user/customer/list.vue

+ 12 - 0
.eslintrc.js

@@ -26,6 +26,18 @@ module.exports = {
         }
       }
     ],
+    'vue/html-self-closing': [
+      'error',
+      {
+        html: {
+          void: 'always',
+          normal: 'never',
+          component: 'always'
+        },
+        svg: 'always',
+        math: 'always'
+      }
+    ],
     'vue/singleline-html-element-content-newline': 'off',
     'vue/multiline-html-element-content-newline': 'off',
     'vue/name-property-casing': ['error', 'PascalCase'],

+ 96 - 0
src/api/library/keyword.js

@@ -67,3 +67,99 @@ export function findLinkageStatus(params) {
     params
   })
 }
+/**
+ * 协销列表
+ * @returns
+ */
+export function getServiceList(params) {
+  return request({
+    url: '/keyword/getServiceList',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 静态标签列表
+ * @param {*} keyword 标签
+ * @param {*} beginTime 统计开始时间
+ * @param {*} endTime 统计结束时间
+ * @param {*} serviceProviderId 协销Id
+ * @param {*} pageNum 页码
+ * @param {*} pageSize 条数
+ * @returns
+ */
+export function getStatekeywordList(params) {
+  return request({
+    url: '/keyword/statekeyword/list',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 保存静态标签
+ * @param {*} keyword 标签
+ * @returns
+ */
+export function saveLabelByState(params) {
+  return request({
+    url: '/keyword/saveLabelByState',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 优先展示标签列表
+ * @param {*} keyword 标签
+ * @param {*} fromSearch 来源
+ * @param {*} dynamicStatus 0 为动态标签 1 静态标签
+ * @param {*} pageNum 页码
+ * @param {*} pageSize 条数
+ * @returns
+ */
+export function getPriorKeywordList(params) {
+  return request({
+    url: '/keyword/getPriorKeywordList',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 选择标签弹窗列表
+ * @param {*} keyword 标签
+ * @param {*} fromSearch 来源
+ * @param {*} dynamicStatus 0 为动态标签 1 静态标签
+ * @param {*} pageNum 页码
+ * @param {*} pageSize 条数
+ * @returns
+ */
+export function getPickKeyword(params) {
+  return request({
+    url: '/keyword/getPickKeyword',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 保存优先展示标签
+ * @param {*} searchIds 标签
+ * @returns
+ */
+export function savePriorKeyword(params) {
+  return request({
+    url: '/keyword/savePriorKeyword',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 删除优先展示标签
+ * @param {*} id 标签Id
+ * @returns
+ */
+export function delPriorKeyword(params) {
+  return request({
+    url: '/keyword/delPriorKeyword',
+    method: 'get',
+    params: params
+  })
+}

+ 215 - 0
src/api/user/consult/consult.js

@@ -0,0 +1,215 @@
+import request from '@/utils/request'
+
+/**
+ * 用户咨询记录汇总
+ * @param {*} remarks 标签词
+ * @param {*} consult 咨询类别
+ * @param {*} clubName 机构名称
+ * @param {*} newDeal 新分配机构状态 0 全部 1 是  2否
+ * @param {*} isRegister 是否注册 0 全部 1 未注册 2已注册
+ * @param {*} todayTime 时间
+ * @param {*} serviceProviderId 协销Id
+ * @param {*} pageNum,
+ * @param {*} pageSize
+ * @returns
+ */
+export function getRemarksRegistList(params) {
+  return request({
+    url: '/user/remarks/registList',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 获取咨询类别
+ * @returns
+ */
+export function getClassName(params) {
+  return request({
+    url: '/user/remarks/getClassName',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 获取当天协销咨询记录信息
+ * @param {*} accessDate 时间
+ * @returns
+ */
+export function getServiceList(params) {
+  return request({
+    url: '/user/remarks/getServiceList',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 咨询记录类别列表
+ * @param {*} className 类别名称
+ * @param {*} status 状态
+ * @param {*} pageNum 页码
+ * @param {*} pageSize 条数
+ * @returns
+ */
+export function getConsultList(params) {
+  return request({
+    url: '/user/remarks/getConsultList',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 添加保存咨询记录类别
+ * @param {*} className 类别名称
+ * @param {*} sortNumber 类别排序
+ * @returns
+ */
+export function saveConsult(data) {
+  return request({
+    url: '/user/remarks/saveConsult',
+    method: 'post',
+    data: data
+  })
+}
+/**
+ * 删除类别
+ * @param {*} id 类别Id
+ * @returns
+ */
+export function deleteConsult(id) {
+  return request({
+    url: '/user/remarks/deleteConsult/' + id,
+    method: 'get'
+  })
+}
+
+/**
+ * 设置类别排序
+ * @param {*} id 类别Id
+ * @param {*} sortNumber 类别排序
+ * @returns
+ */
+export function consultSort(params) {
+  return request({
+    url: '/user/remarks/sort',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 获取报备列表
+ * @param {*} reportId 报备Id
+ * @param {*} productName 咨询商品名称
+ * @param {*} clubName 机构名称
+ * @param {*} reportName 报备人
+ * @param {*} status 状态 1.已审核 2.待审核 3.审核未通过
+ * @param {*} startAddTime 提交开始时间
+ * @param {*} endAddTime 提交结束时间
+ * @param {*} pageNum 页码
+ * @param {*} pageSize 条数
+ * @returns
+ */
+export function getReportList(params) {
+  return request({
+    url: '/user/remarks/ReportList',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 审核报备
+ * @param {*} auditText 审核备注
+ * @param {*} status 报备状态
+ */
+export function reportCount(params) {
+  return request({
+    url: '/user/remarks/reportCount',
+    method: 'get',
+    params
+  })
+}
+
+/**
+ * 删除报备
+ * @param {*} reportId 报备Id
+ * @returns
+ */
+export function deleteReport(id) {
+  return request({
+    url: '/user/remarks/deleteReport/' + id,
+    method: 'get'
+  })
+}
+
+/**
+ * 报备详情
+ * @param {*} reportId 报备
+ * @returns
+ */
+export function cmRegistReportList(params) {
+  return request({
+    url: '/user/remarks/cmRegistReportList',
+    method: 'get',
+    params
+  })
+}
+
+/**
+ * 取消报备关联
+ * @param {*}  remarksId 供应商Id
+ * @param {*} type 关键词
+ * @returns
+ */
+export function getAudit(params) {
+  return request({
+    url: '/user/remarks/audit',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 未注册咨询记录
+ * @param {*} questionMan 咨询人
+ * @param {*} serviceProviderId 协销Id
+ * @param {*} concat 是否同步
+ * @param {*} pageNum 页码
+ * @param {*} pageSize 条数
+ * @returns
+ */
+export function visitRemarkList(params) {
+  return request({
+    url: '/user/remarks/visitRemarkList',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 未注册用户已同步数据详情
+ * @param {*} clubId 机构Id
+ * @param {*} questionManId 咨询人Id
+ * @param {*} remarks 标签词
+ * @param {*} consult 类别
+ * @param {*} startAddTime 开始时间
+ * @param {*} endAddTime 结束时间
+ * @param {*} pageNum 页码
+ * @param {*} pageSize 条数
+ */
+export function remarksList(params) {
+  return request({
+    url: '/user/remarks/remarksList',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 文件下载
+ * @param {*} fileName 文件名称
+ * @param {*} ossName 阿里云oss名称
+ */
+export function remarksFileDownload(data) {
+  return request({
+    url: '/user/remarks/remarks/download',
+    method: 'post',
+    data: data
+  })
+}

+ 393 - 0
src/api/user/customer/customer.js

@@ -0,0 +1,393 @@
+import request from '@/utils/request'
+
+/**
+ * 潜客搜集供应商列表
+ * @param {*} shopName
+ * @param {*} status
+ * @param {*} pageNum,
+ * @param {*} pageSize
+ * @returns
+ */
+export function getCustomerShopList(params) {
+  return request({
+    url: '/user/customer/getCustomerShopList',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 选择已上线供应商列表
+ * @param {*} shopName
+ * @param {*} pageNum,
+ * @param {*} pageSize
+ * @returns
+ */
+export function getShopList(params) {
+  return request({
+    url: '/user/customer/getShopList',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 保存添加统计供应商
+ * @param {*} shopIds
+ * @returns
+ */
+export function saveCustomerShop(params) {
+  return request({
+    url: '/user/customer/saveCustomerShop',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 设置供应商统计状态
+ * @param {*} id 统计供应商表的ID
+ * @param {*} status 统计状态
+ * @returns
+ */
+export function renewCustomerShop(params) {
+  return request({
+    url: '/user/customer/renewCustomerShop',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 供应商相关游客统计列表
+ * @param {*} shopId 供应商Id
+ * @param {*} consultName 咨询人姓名
+ * @param {*} consultMobile 咨询手机号
+ * @param {*} pageNum 咨询手机号
+ * @param {*} pageSize 咨询手机号
+ * @returns
+ */
+export function getCmInformationList(params) {
+  return request({
+    url: '/user/customer/getCmInformationList',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 设置潜客跟进状态
+ * @param {*} id 潜客列表ID
+ * @param {*} followUpStatus 跟进状态
+ * @returns
+ */
+export function renewFollowUpStatus(params) {
+  return request({
+    url: '/user/customer/renewFollowUpStatus',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 供应商相关文章列表
+ * @param {*} shopId 供应商Id
+ * @param {*} infoId 列表文章Id
+ * @param {*} title 标题
+ * @param {*} status  统计状态
+ * @param {*} pageNum 页码
+ * @param {*} pageSize 条数
+ * @returns
+ */
+export function getShopInfoList(params) {
+  return request({
+    url: '/user/customer/getShopInfoList',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 供应商选择文章列表
+ * @param {*} id 文章Id
+ * @param {*} title 标题
+ * @param {*} pageNum 页码
+ * @param {*} pageSize 条数
+ * @returns
+ */
+export function getInfoList(params) {
+  return request({
+    url: '/user/customer/getInfoList',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 添加文章
+ * @param {*} shopId 供应商Id
+ * @param {*} infoIds 文章Id合集
+ */
+export function saveShopInfo(params) {
+  return request({
+    url: '/user/customer/saveShopInfo',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 设置文章统计状态
+ * @param {*} id 文章统计Id
+ * @param {*} status 统计状态
+ * @returns
+ */
+export function renewShopInfo(params) {
+  return request({
+    url: '/user/customer/renewShopInfo',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 删除文章
+ * @param {*} id 文章统计Id
+ * @returns
+ */
+export function delShopInfo(id) {
+  return request({
+    url: '/user/customer/delShopInfo/' + id,
+    method: 'get'
+  })
+}
+/**
+ * 供应商相关搜索词列表
+ * @param {*} shopId 供应商Id
+ * @param {*} keyword 关键词
+ * @param {*} status  统计状态
+ * @param {*} pageNum 页码
+ * @param {*} pageSize 条数
+ * @returns
+ */
+export function getShopKeywordList(params) {
+  return request({
+    url: '/user/customer/getShopKeywordList',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 供应商选择文搜索词列表
+ * @param {*} keyword 标题
+ * @param {*} pageNum 页码
+ * @param {*} pageSize 条数
+ * @returns
+ */
+export function getSearchFrequencyList(params) {
+  return request({
+    url: '/user/customer/getSearchFrequencyList',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 添加关键词
+ * @param {*} shopId 供应商Id
+ * @param {*} keyWordIds 文章Id合集
+ */
+export function saveShopKeyword(params) {
+  return request({
+    url: '/user/customer/saveShopKeyword',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 设置关键词统计状态
+ * @param {*} id 关键词统计Id
+ * @param {*} status 统计状态
+ * @returns
+ */
+export function renewShopKeyword(params) {
+  return request({
+    url: '/user/customer/renewShopKeyword',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 删除关键词
+ * @param {*} id 关键词统计Id
+ * @returns
+ */
+export function delShopKeyword(id) {
+  return request({
+    url: '/user/customer/delShopKeyword/' + id,
+    method: 'get'
+  })
+}
+/**
+ * 供应商广告弹窗信息保存
+ * @param {*} id 关键词统计Id
+ * @param {*} shopId 供应商Id
+ * @param {*} image 弹窗图片
+ * @param {*} guidingOne 引导语1
+ * @param {*} guidingTwo 引导语2
+ * @param {*} addTime 添加时间
+ * @returns
+ */
+export function saveShopPopUp(data) {
+  return request({
+    url: '/user/customer/saveShopPopUp',
+    method: 'post',
+    data: data
+  })
+}
+/**
+ * 供应商广告弹窗样式回显
+ * @param {*} shopId 供应商Id
+ * @returns
+ */
+export function getShopPopUp(params) {
+  return request({
+    url: '/user/customer/getShopPopUp',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 供应商广告图列表
+ * @param {*} shopName 供应商名称
+ * @param {*} status 上架状态
+ * @param {*} pageNum 页码
+ * @param {*} pageSize 条数
+ * @returns
+ */
+export function getShopAdvertisingImage(params) {
+  return request({
+    url: '/user/customer/getShopAdvertisingImage',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 供应商广告图信息保存
+ * @param {*} id 广告Id
+ * @param {*} shopId 供应商Id
+ * @param {*} pcImage PC广告图
+ * @param {*} appImage 小程序广告图
+ * @param {*} jumpLink 跳转链接
+ * @param {*} status 状态
+ * @param {*} addTime 添加时间
+ * @returns
+ */
+export function saveShopAdvertisingImage(data) {
+  return request({
+    url: '/user/customer/saveShopAdvertisingImage',
+    method: 'post',
+    data: data
+  })
+}
+/**
+ * 供应商广告图信息回显
+ * @param {*} id 广告列表Id
+ * @returns
+ */
+export function getShopAdvertisingImageById(id) {
+  return request({
+    url: '/user/customer/getShopAdvertisingImageById/' + id,
+    method: 'get'
+  })
+}
+/**
+ * 供应商广告图排序
+ * @param {*} id 广告列表Id
+ * @param {*} sort 排序
+ * @returns
+ */
+export function renewShopAdvertisingImageSort(params) {
+  return request({
+    url: '/user/customer/renewShopAdvertisingImageSort',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 供应商广告图设置上下架状态
+ * @param {*} id 广告列表Id
+ * @param {*} status 状态
+ * @returns
+ */
+export function renewShopAdvertisingImageStatus(params) {
+  return request({
+    url: '/user/customer/renewShopAdvertisingImageStatus',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 删除广告
+ * @param {*} id 广告Id
+ * @returns
+ */
+export function delShopAdvertisingImage(id) {
+  return request({
+    url: '/user/customer/delShopAdvertisingImage/' + id,
+    method: 'get'
+  })
+}
+/**
+ * 供应商主页统计
+ * @param {*} shopId 供应商名称
+ * @param {*} startTime 统计开始时间
+ * @param {*} endTime 统计结束时间
+ * @param {*} pageNum 页码
+ * @param {*} pageSize 条数
+ * @returns
+ */
+export function getPageShop(params) {
+  return request({
+    url: '/user/customer/getPageShop',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 供应商商品统计
+ * @param {*} shopId 供应商名称
+ * @param {*} startTime 统计开始时间
+ * @param {*} endTime 统计结束时间
+ * @param {*} pageNum 页码
+ * @param {*} pageSize 条数
+ * @returns
+ */
+export function getPageShopProduct(params) {
+  return request({
+    url: '/user/customer/getPageShopProduct',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 供应商文章统计
+ * @param {*} shopId 供应商名称
+ * @param {*} startTime 统计开始时间
+ * @param {*} endTime 统计结束时间
+ * @param {*} pageNum 页码
+ * @param {*} pageSize 条数
+ * @returns
+ */
+export function getPageShopInfo(params) {
+  return request({
+    url: '/user/customer/getPageShopInfo',
+    method: 'get',
+    params
+  })
+}
+/**
+ * 供应商搜索词统计
+ * @param {*} shopId 供应商名称
+ * @param {*} startTime 统计开始时间
+ * @param {*} endTime 统计结束时间
+ * @param {*} pageNum 页码
+ * @param {*} pageSize 条数
+ * @returns
+ */
+export function getPageShopKeyword(params) {
+  return request({
+    url: '/user/customer/getPageShopKeyword',
+    method: 'get',
+    params
+  })
+}

+ 13 - 1
src/router/modules/keywordLibrary.js

@@ -43,7 +43,19 @@ const keywordLibraryRouter = {
           path: 'list',
           name: 'TagList',
           component: () => import('@/views/library/tag/list'),
-          meta: { title: '标签列表' }
+          meta: { title: '动态标签列表' }
+        },
+        {
+          path: 'static-list',
+          name: 'StaticList',
+          component: () => import('@/views/library/tag/static-list'),
+          meta: { title: '静态标签列表' }
+        },
+        {
+          path: 'priority-list',
+          name: 'PriorityList',
+          component: () => import('@/views/library/tag/priority-list'),
+          meta: { title: '优先展示标签' }
         }
       ]
     },

+ 110 - 1
src/router/modules/user.js

@@ -12,8 +12,8 @@ const userRouter = {
   children: [
     {
       path: 'record-list',
-      component: () => import('@/views/user/record/list'),
       name: 'RecordList',
+      component: () => import('@/views/user/record/list'),
       meta: { title: '用户行为记录', icon: 'international', activeMenu: '/user/list' }
     },
     {
@@ -22,6 +22,115 @@ const userRouter = {
       component: () => import('@/views/user/record/detail-list'),
       name: 'RecordDtails',
       meta: { title: '查看详情', noCache: true, activeMenu: '/user/list' }
+    },
+    {
+      path: 'customer',
+      name: 'CustomerMenu',
+      redirect: '/user/customer',
+      component: () => import('@/views/index'),
+      meta: { title: '潜客搜集' },
+      children: [
+        {
+          path: 'list',
+          name: 'CustomerList',
+          component: () => import('@/views/user/customer/list'),
+          meta: { title: '供应商列表' }
+        },
+        {
+          path: 'customer-stat-list',
+          name: 'CustomerStatsList',
+          component: () => import('@/views/user/customer/customer-stat-list'),
+          meta: { title: '潜客统计列表' },
+          hidden: true
+        },
+        {
+          path: 'customer-article-list',
+          name: 'CustomerArticleList',
+          component: () => import('@/views/user/customer/customer-article-list'),
+          meta: { title: '相关文章' },
+          hidden: true
+        },
+        {
+          path: 'customer-search-list',
+          name: 'CustomerSearchList',
+          component: () => import('@/views/user/customer/customer-search-list'),
+          meta: { title: '相关搜索词' },
+          hidden: true
+        },
+        {
+          path: 'customer-page-list',
+          name: 'CustomerPageList',
+          component: () => import('@/views/user/customer/customer-page-list'),
+          meta: { title: '页面访问统计' },
+          hidden: true
+        },
+        {
+          path: 'customer-popup-edit',
+          name: 'CustomerPopupEdit',
+          component: () => import('@/views/user/customer/customer-popup-edit'),
+          meta: { title: '弹窗样式编辑' },
+          hidden: true
+        },
+        {
+          path: 'advertis-list',
+          name: 'AdvertisList',
+          component: () => import('@/views/user/customer/advertis-list'),
+          meta: { title: '供应商广告图' }
+        },
+        {
+          path: 'advertis-edit',
+          name: 'AdvertisEdit',
+          component: () => import('@/views/user/customer/advertis-edit'),
+          meta: { title: '广告图添加' }
+        }
+      ]
+    },
+    {
+      path: 'consult',
+      name: 'ConsultMenu',
+      redirect: '/user/consult',
+      component: () => import('@/views/index'),
+      meta: { title: '咨询记录' },
+      children: [
+        {
+          path: 'list',
+          name: 'ConsultList',
+          component: () => import('@/views/user/consult/list'),
+          meta: { title: '用户咨询记录汇总' }
+        },
+        {
+          path: 'unreg-list',
+          name: 'UnregList',
+          component: () => import('@/views/user/consult/unreg-list'),
+          meta: { title: '未注册用户咨询记录' }
+        },
+        {
+          path: 'genre-list',
+          name: 'GenreList',
+          component: () => import('@/views/user/consult/genre-list'),
+          meta: { title: '咨询类别设置' }
+        },
+        {
+          path: 'report-list',
+          name: 'ReportList',
+          component: () => import('@/views/user/consult/report-list'),
+          meta: { title: '报备列表' }
+        },
+        {
+          path: 'detail',
+          name: 'ConsultDetail',
+          component: () => import('@/views/user/consult/detail'),
+          meta: { title: '详情' },
+          hidden: true
+        },
+        {
+          path: 'unreg-detail',
+          name: 'UnregDetail',
+          component: () => import('@/views/user/consult/unreg-detail'),
+          meta: { title: '信息详情' },
+          hidden: true
+        }
+      ]
     }
   ]
 }

+ 8 - 0
src/styles/index.scss

@@ -252,3 +252,11 @@ aside {
 .el-submenu [class^='el-icon-'] {
   font-size: 16px;
 }
+.uploader-tips {
+  position: absolute;
+  bottom: 0;
+  left: 160px;
+  line-height: 28px;
+  color: red;
+  margin: 0;
+}

+ 52 - 0
src/utils/time-picker.js

@@ -0,0 +1,52 @@
+// 时间picker
+const pickerOptions = {
+  shortcuts: [
+    {
+      text: '近1年',
+      onClick(picker) {
+        const end = new Date()
+        const start = new Date()
+        start.setTime(start.getTime() - 3600 * 1000 * 24 * 365)
+        picker.$emit('pick', [start, end])
+      }
+    },
+    {
+      text: '近半年',
+      onClick(picker) {
+        const end = new Date()
+        const start = new Date()
+        start.setTime(start.getTime() - 3600 * 1000 * 24 * 183)
+        picker.$emit('pick', [start, end])
+      }
+    },
+    {
+      text: '近1月',
+      onClick(picker) {
+        const end = new Date()
+        const start = new Date()
+        start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
+        picker.$emit('pick', [start, end])
+      }
+    },
+    {
+      text: '近1周',
+      onClick(picker) {
+        const end = new Date()
+        const start = new Date()
+        start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
+        picker.$emit('pick', [start, end])
+      }
+    },
+    {
+      text: '昨天',
+      onClick(picker) {
+        const end = new Date()
+        const start = new Date()
+        start.setTime(start.getTime() - 3600 * 1000 * 24)
+        picker.$emit('pick', [start, end])
+      }
+    }
+  ]
+}
+
+export default pickerOptions

+ 159 - 0
src/views/library/tag/components/label-dialog.vue

@@ -0,0 +1,159 @@
+<template>
+  <el-dialog title="选择标签" :visible.sync="visible" width="1200px" :close-on-click-modal="false" :show-close="false">
+    <el-tabs v-model="activeName" type="border-card" @tab-click="handleClick">
+      <el-tab-pane label="动态标签" name="first" />
+      <el-tab-pane label="静态标签" name="second" />
+      <div class="filter-container">
+        <div class="filter-control">
+          <span>搜索词:</span>
+          <el-input
+            v-model="listQuery.keyword"
+            placeholder="搜索词"
+            clearable
+            style="width: 160px"
+            @keyup.enter.native="getList"
+            @clear="getList"
+          />
+        </div>
+        <div class="filter-control">
+          <span>来源:</span>
+          <el-select v-model="listQuery.fromSearch" clearable @change="getList">
+            <el-option :value="1" label="单个添加" />
+            <el-option :value="2" label="系统推荐" />
+            <el-option :value="3" label="导入" />
+            <el-option :value="4" label="协销填写" />
+          </el-select>
+        </div>
+        <div class="filter-control">
+          <el-button type="primary" @click="getList"> 查询 </el-button>
+        </div>
+      </div>
+      <el-table
+        ref="table"
+        v-loading="isLoading"
+        :data="list"
+        height="380px"
+        border
+        @selection-change="handleSelectionChange"
+      >
+        <el-table-column type="selection" width="55" :selectable="selectable" />
+        <el-table-column label="标签词" prop="keyword" align="center" />
+        <el-table-column label="来源" align="center">
+          <template slot-scope="{ row }">
+            <span v-if="row.fromSearch === 1">单个添加</span>
+            <span v-else-if="row.fromSearch === 2">系统推荐</span>
+            <span v-else-if="row.fromSearch === 3">导入</span>
+            <span v-else>协销填写</span>
+          </template>
+        </el-table-column>
+      </el-table>
+      <!-- 页码 -->
+      <pagination
+        :total="total"
+        :page-sizes="[20]"
+        :page-size="20"
+        :page.sync="listQuery.pageNum"
+        :limit.sync="listQuery.pageSize"
+        @pagination="getPickKeyword"
+      />
+      <!-- 列表 -->
+    </el-tabs>
+    <div slot="footer">
+      <el-button @click="handleCanle"> 取 消 </el-button>
+      <el-button type="primary" :disabled="disabled" @click="handleConfirm"> 确 定 </el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+import { getPickKeyword } from '@/api/library/keyword'
+const defaultListQuery = {
+  keyword: '',
+  dynamicStatus: 0, // 0 动态标签 1 静态标签
+  fromSearch: '',
+  pageNum: 1,
+  pageSize: 20
+}
+export default {
+  name: 'LabelDialog',
+  filters: {},
+  props: {
+    maxLen: {
+      type: Number,
+      default: 0
+    }
+  },
+  data() {
+    return {
+      activeName: 'first',
+      visible: true,
+      listQuery: Object.assign({}, defaultListQuery),
+      list: [],
+      total: 0,
+      labelsRadio: null,
+      isLoading: true
+    }
+  },
+  computed: {
+    disabled() {
+      return this.labelsRadio === null
+    }
+  },
+  created() {
+    this.getList()
+  },
+  methods: {
+    // tab切换
+    handleClick(tab, event) {
+      if (tab.name === 'first') {
+        this.listQuery = Object.assign({}, defaultListQuery)
+        this.listQuery.dynamicStatus = 0
+        this.getList()
+      } else if (tab.name === 'second') {
+        this.listQuery = Object.assign({}, defaultListQuery)
+        this.listQuery.dynamicStatus = 1
+        this.getList()
+      }
+    },
+    // 获取所有供应商列表
+    async getList() {
+      this.list = []
+      this.listQuery.pageNum = 1
+      this.getPickKeyword()
+    },
+    // 获取所有供应商列表
+    async getPickKeyword() {
+      try {
+        const res = await getPickKeyword(this.listQuery)
+        this.list = res.data.results
+        this.total = res.data.totalRecord
+        this.isLoading = false
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 选择关键词
+    handleSelectionChange(row) {
+      this.labelsRadio = row
+      console.log('row', row)
+    },
+    // 确认选择关键词
+    handleConfirm() {
+      this.$emit('confirm', this.labelsRadio)
+    },
+    // 取消选择
+    handleCanle() {
+      this.$emit('cancel')
+    },
+    // 已选择的禁用勾选框
+    selectable(row) {
+      if (row.flag) {
+        return true
+      } else {
+        return false
+      }
+    }
+  }
+}
+</script>
+<style lang="scss" scoped></style>

+ 50 - 45
src/views/library/tag/list.vue

@@ -3,10 +3,10 @@
     <!-- 顶部操作区域 -->
     <div class="filter-container">
       <div class="filter-control">
-        <span>关键词:</span>
+        <span>标签:</span>
         <el-input
           v-model="listQuery.keyword"
-          placeholder="关键词"
+          placeholder="标签"
           clearable
           @keyup.enter.native="getList"
           @clear="getList"
@@ -18,9 +18,10 @@
           <el-option :value="1" label="单个添加" />
           <el-option :value="2" label="系统推荐" />
           <el-option :value="3" label="导入" />
+          <el-option :value="4" label="协销填写" />
         </el-select>
       </div>
-      <div class="filter-control">
+      <!-- <div class="filter-control">
         <span>搜索统计:</span>
         <el-date-picker
           v-model="time"
@@ -33,20 +34,24 @@
           value-format="yyyy-MM-dd"
           @change="getList"
         />
-      </div>
+      </div> -->
       <div class="filter-control">
-        <el-button type="primary" @click="getList">查询</el-button>
-        <el-button v-permission="'tag:list:add'" type="primary" @click="handleAddTag">添加标签</el-button>
+        <el-button type="primary" @click="getList"> 查询 </el-button>
+        <el-button v-permission="'tag:list:add'" type="primary" @click="handleAddTag"> 添加标签 </el-button>
         <el-button v-permission="'tag:list:del'" type="danger" :disabled="disabled" @click="handleDeleteTag">
           删除
         </el-button>
         <el-button v-permission="'tag:list:improt'" type="primary" @click="importDialog = true"> 导入 </el-button>
-        <el-button v-permission="'tag:list:export'" type="primary" :disabled="disabled" @click="handleExport">导出</el-button>
-        <el-button v-permission="'tag:list:improt'" type="primary" @click="handleDownloadTemp">下载导入模板</el-button>
+        <el-button v-permission="'tag:list:export'" type="primary" :disabled="disabled" @click="handleExport">
+          导出
+        </el-button>
+        <el-button v-permission="'tag:list:improt'" type="primary" @click="handleDownloadTemp">
+          下载导入模板
+        </el-button>
       </div>
     </div>
 
-    <!-- 关键词列表 -->
+    <!-- 标签列表 -->
     <!-- <el-table
       v-loading="isLoading"
       :data="list"
@@ -54,15 +59,10 @@
       :default-sort="{ prop: 'frequency', order: 'descending' }"
       @selection-change="handleSelectionChange"
     > -->
-    <el-table
-      v-loading="isLoading"
-      :data="list"
-      border
-      @selection-change="handleSelectionChange"
-    >
+    <el-table v-loading="isLoading" :data="list" border @selection-change="handleSelectionChange">
       <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="序号" :index="indexMethod" type="index" sortable="custom" align="center" width="80" />
-      <el-table-column prop="keyword" label="关键词" align="center" />
+      <el-table-column prop="keyword" label="标签" align="center" />
       <el-table-column prop="keyword" label="下拉搜索框联动" width="180" align="center">
         <template slot-scope="scope">
           <el-switch v-model="scope.row.linkageStatus" @change="handleStatusChange(scope.row)" />
@@ -80,25 +80,22 @@
         <template slot-scope="{ row }">
           <span v-if="row.fromSearch === 1">单个添加</span>
           <span v-else-if="row.fromSearch === 2">系统推荐</span>
-          <span v-else>导入</span>
-        </template>
-      </el-table-column>
-      <el-table-column label="最近搜索时间" align="center" width="200">
-        <template slot-scope="{ row }">
-          <span v-if="row.searchTime">{{ row.searchTime | parseTime }}</span>
-          <span v-else>-</span>
+          <span v-else-if="row.fromSearch === 3">导入</span>
+          <span v-else>协销填写</span>
         </template>
       </el-table-column>
       <el-table-column label="添加时间" align="center" width="200">
         <template slot-scope="{ row }">
-          <span v-if="row.searchTime">{{ row.searchTime | parseTime }}</span>
+          <span v-if="row.addTime">{{ row.addTime | parseTime }}</span>
           <span v-else>-</span>
         </template>
       </el-table-column>
       <el-table-column label="操作" align="center" width="240">
         <template slot-scope="{ row }">
-          <el-button v-permission="'tag:list:del'" type="danger" size="mini" @click="handleDeleteTag(row)">删除</el-button>
-          <el-button type="primary" size="mini" @click="handleSearch(row.keyword)">去搜索</el-button>
+          <el-button v-permission="'tag:list:del'" type="danger" size="mini" @click="handleDeleteTag(row)">
+            删除
+          </el-button>
+          <!-- <el-button type="primary" size="mini" @click="handleSearch(row.keyword)"> 去搜索 </el-button> -->
         </template>
       </el-table-column>
     </el-table>
@@ -132,8 +129,8 @@
         </el-form-item> -->
       </el-form>
       <div slot="footer">
-        <el-button @click="closeAddTagDialog">取 消</el-button>
-        <el-button type="primary" @click="handleAddTagConfirm">确 定</el-button>
+        <el-button @click="closeAddTagDialog"> 取 消 </el-button>
+        <el-button type="primary" @click="handleAddTagConfirm"> 确 定 </el-button>
       </div>
     </el-dialog>
 
@@ -158,15 +155,15 @@
             :on-change="handleUploadChange"
             :auto-upload="false"
           >
-            <el-button slot="trigger" size="small" type="primary">选取文件</el-button>
+            <el-button slot="trigger" size="small" type="primary"> 选取文件 </el-button>
             <div slot="tip" class="el-upload__tip">只能上传.xlsx, .xls文件</div>
           </el-upload>
-          <input v-show="false" v-model="importForm.fileUrl" type="text">
+          <input v-show="false" v-model="importForm.fileUrl" type="text" />
         </el-form-item>
       </el-form>
       <div slot="footer">
-        <el-button @click="closeImportDialog">取 消</el-button>
-        <el-button v-debounce="handleImportConfirm" type="primary">导 入</el-button>
+        <el-button @click="closeImportDialog"> 取 消 </el-button>
+        <el-button v-debounce="handleImportConfirm" type="primary"> 导 入 </el-button>
       </div>
     </el-dialog>
   </div>
@@ -175,7 +172,13 @@
 <script>
 import SearchModel from '@/components/SearchModel'
 import { downloadWithUrl, getYestodayTime, parseTime } from '@/utils'
-import { addKeyword, deleteKeyword, fetchKeywordList, importKeywordXlsx, findLinkageStatus } from '@/api/library/keyword'
+import {
+  addKeyword,
+  deleteKeyword,
+  fetchKeywordList,
+  importKeywordXlsx,
+  findLinkageStatus
+} from '@/api/library/keyword'
 import { export_json_to_excel } from '@/vendor/Export2Excel'
 export default {
   components: { SearchModel },
@@ -273,7 +276,7 @@ export default {
     this.getList()
   },
   methods: {
-    // 关键词下拉关联
+    // 标签下拉关联
     async handleStatusChange($event) {
       const res = await findLinkageStatus({ id: $event.id, linkageStatus: $event.linkageStatus ? 1 : 0 })
       if (res.code === 0) {
@@ -294,17 +297,19 @@ export default {
             confirmButtonText: '确定',
             cancelButtonText: '取消',
             type: 'warning'
-          }).then(() => {
-            $event.linkageStatus = !$event.linkageStatus
-          }).catch(() => {
-            $event.linkageStatus = !$event.linkageStatus
           })
+            .then(() => {
+              $event.linkageStatus = !$event.linkageStatus
+            })
+            .catch(() => {
+              $event.linkageStatus = !$event.linkageStatus
+            })
         }
         await this.fetchKeywordList()
       }
     },
 
-    // 获取关键词列表
+    // 获取标签列表
     getList() {
       this.listQuery.pageNum = 1
       if (this.time && this.time.length > 0) {
@@ -317,12 +322,12 @@ export default {
       this.fetchKeywordList()
     },
 
-    // 获取关键词列表
+    // 获取标签列表
     async fetchKeywordList() {
       try {
         this.isLoading = true
         const res = await fetchKeywordList(this.listQuery)
-        this.list = res.data.results.map(i => ({
+        this.list = res.data.results.map((i) => ({
           addTime: i.addTime,
           frequency: i.frequency,
           fromSearch: i.fromSearch,
@@ -404,23 +409,23 @@ export default {
       const ids = keywords.map((item) => item.id).join(',')
       try {
         await deleteKeyword({ id: ids })
-        this.$message.success('已忽略所选关键词')
+        this.$message.success('标签删除成功')
         this.getList()
       } catch (error) {
         console.log(error)
       }
     },
 
-    // 导入关键词
+    // 导入标签
     async handleImport() {},
 
-    // 导入关键词取消
+    // 导入标签取消
     closeImportDialog() {
       this.$refs.importForm.resetFields()
       this.importDialog = false
     },
 
-    // 导入关键词确定
+    // 导入标签确定
     async handleImportConfirm() {
       console.log(1)
       try {

+ 296 - 0
src/views/library/tag/priority-list.vue

@@ -0,0 +1,296 @@
+<template>
+  <div class="app-container">
+    <!-- 顶部操作区域 -->
+    <div class="filter-container">
+      <div class="filter-control">
+        <span>标签词:</span>
+        <el-input
+          v-model="listQuery.keyword"
+          placeholder="标签词"
+          clearable
+          @keyup.enter.native="getList"
+          @clear="getList"
+        />
+      </div>
+      <div class="filter-control">
+        <span>来源:</span>
+        <el-select v-model="listQuery.fromSearch" clearable @change="getList">
+          <el-option value="" label="请选择" />
+          <el-option :value="1" label="单个添加" />
+          <el-option :value="2" label="系统推荐" />
+          <el-option :value="3" label="导入" />
+          <el-option :value="4" label="协销填写" />
+        </el-select>
+      </div>
+      <div class="filter-control">
+        <span>类型:</span>
+        <el-select v-model="listQuery.dynamicStatus" clearable @change="getList">
+          <el-option value="" label="请选择" />
+          <el-option :value="0" label="动态标签" />
+          <el-option :value="1" label="静态标签" />
+        </el-select>
+      </div>
+      <div class="filter-control">
+        <el-button type="primary" @click="getList"> 查询 </el-button>
+        <el-button
+          v-permission="'tag:priority-list:add'"
+          type="primary"
+          :disabled="disabled1"
+          @click="labelDialogVisible = true"
+        >
+          添加标签
+        </el-button>
+        <el-button v-permission="'tag:priority-list:del'" type="danger" :disabled="disabled" @click="handleDeleteTag">
+          删除
+        </el-button>
+      </div>
+    </div>
+    <!-- 标签列表 -->
+    <el-table v-loading="isLoading" :data="list" border height="600" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="序号" :index="indexMethod" type="index" sortable="custom" align="center" width="60" />
+      <el-table-column prop="keyword" label="标签词" align="center" />
+      <el-table-column label="来源" align="center" width="180">
+        <template slot-scope="{ row }">
+          <span v-if="row.fromSearch === 1">单个添加</span>
+          <span v-else-if="row.fromSearch === 2">系统推荐</span>
+          <span v-else-if="row.fromSearch === 3">导入</span>
+          <span v-else>协销填写</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="类型" align="center" width="180">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.dynamicStatus === 0" type="primary" size="small">动态标签</el-tag>
+          <el-tag v-if="row.dynamicStatus === 1" type="success" size="small">静态标签</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="添加时间" align="center" width="200">
+        <template slot-scope="{ row }">
+          <span v-if="row.addTime">{{ row.addTime | parseTime }}</span>
+          <span v-else>-</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" width="150">
+        <template slot-scope="{ row }">
+          <el-button v-permission="'tag:priority-list:del'" type="danger" size="mini" @click="handleDeleteTag(row)">
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 页码 -->
+    <pagination
+      :page-sizes="[20]"
+      :page-size="20"
+      :total="total"
+      :page.sync="listQuery.pageNum"
+      :limit.sync="listQuery.pageSize"
+      @pagination="getPriorKeywordList"
+    />
+    <!-- 选择添加标签弹窗 -->
+    <LabelDialog
+      v-if="labelDialogVisible"
+      ref="labelDialog"
+      :max-len="total"
+      :keyword="visibleKeyword"
+      @confirm="handleConfirmLabel"
+      @cancel="handleCancel"
+    />
+  </div>
+</template>
+
+<script>
+import LabelDialog from './components/label-dialog'
+import { getYestodayTime } from '@/utils'
+import { delPriorKeyword, getPriorKeywordList, savePriorKeyword } from '@/api/library/keyword'
+export default {
+  components: { LabelDialog },
+  filters: {
+    dynamicStatusFilters(value) {
+      // 标签类型
+      console.log('value', value)
+      const map = {
+        0: '动态标签',
+        1: '静态标签'
+      }
+      return map[value]
+    }
+  },
+  data() {
+    const pickerOptions = {
+      shortcuts: [
+        {
+          text: '近1年',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 365)
+            picker.$emit('pick', [start, end])
+          }
+        },
+        {
+          text: '近半年',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 183)
+            picker.$emit('pick', [start, end])
+          }
+        },
+        {
+          text: '近1月',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
+            picker.$emit('pick', [start, end])
+          }
+        },
+        {
+          text: '近1周',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 6)
+            picker.$emit('pick', [start, end])
+          }
+        },
+        {
+          text: '昨天',
+          onClick(picker) {
+            const { start, end } = getYestodayTime()
+            picker.$emit('pick', [start, end])
+          }
+        }
+      ]
+    }
+    return {
+      isLoading: true,
+      pickerOptions,
+      time: '',
+      listQuery: {
+        keyword: '',
+        dynamicStatus: '', // 0 为动态标签 1 静态标签
+        fromSearch: '',
+        pageNum: 1,
+        pageSize: 20
+      },
+      list: [],
+      total: 0,
+      currentList: [],
+      labelDialogVisible: false,
+      visibleKeyword: '',
+      addTagDialog: false,
+      tagForm: {
+        keyword: ''
+      }
+    }
+  },
+  computed: {
+    disabled() {
+      return this.currentList.length === 0
+    },
+    disabled1() {
+      return this.total === 50
+    }
+  },
+  created() {
+    this.getList()
+  },
+  methods: {
+    // 获取标签列表
+    getList() {
+      this.listQuery.pageNum = 1
+      if (this.time && this.time.length > 0) {
+        this.listQuery.beginTime = this.time[0]
+        this.listQuery.endTime = this.time[1]
+      } else {
+        this.listQuery.beginTime = ''
+        this.listQuery.endTime = ''
+      }
+      this.getPriorKeywordList()
+    },
+
+    // 获取标签列表
+    async getPriorKeywordList() {
+      try {
+        this.isLoading = true
+        const res = await getPriorKeywordList(this.listQuery)
+        this.list = res.data.results
+        this.total = res.data.totalRecord
+        this.isLoading = false
+      } catch (error) {
+        console.log(error)
+      }
+    },
+
+    // 选中列表项
+    handleSelectionChange(current) {
+      this.currentList = current
+    },
+
+    // 确认选择标签
+    handleConfirmLabel(data) {
+      console.log('data', data)
+      const maxLeng = this.total + data.length
+      console.log('maxLeng', maxLeng)
+      if (maxLeng > 50) {
+        this.$message.warning('只支持展示50个标签,请删减再添加。')
+        return
+      }
+      const searchIds = []
+      data.forEach((ele) => {
+        searchIds.push(ele.id)
+      })
+      this.savePriorKeyword({ searchIds: searchIds.join(',') })
+    },
+    // 保存添加供应商关键词
+    async savePriorKeyword(params) {
+      try {
+        await savePriorKeyword(params)
+        this.$message.success('操作成功')
+        this.handleCancel()
+        this.getList()
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 取消选择标签
+    handleCancel() {
+      this.labelDialogVisible = false
+      this.$refs.labelDialog.visible = false
+    },
+    // 删除标签
+    async handleDeleteTag(row) {
+      try {
+        await this.$confirm('确定删除已选标签?', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        })
+        this.delPriorKeyword(row)
+      } catch (error) {
+        this.$message.info('已取消删除操作')
+      }
+    },
+    // 提交删除标签操作
+    async delPriorKeyword(row) {
+      const keywords = row instanceof Event ? this.currentList : [].concat(row)
+      const ids = keywords.map((item) => item.id).join(',')
+      try {
+        await delPriorKeyword({ ids: ids })
+        this.$message.success('标签删除成功')
+        this.getList()
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    indexMethod(index) {
+      return index + this.listQuery.pageSize * (this.listQuery.pageNum - 1) + 1
+    }
+  }
+}
+</script>
+
+<style></style>

+ 375 - 0
src/views/library/tag/static-list.vue

@@ -0,0 +1,375 @@
+<template>
+  <div class="app-container">
+    <!-- 顶部操作区域 -->
+    <div class="filter-container">
+      <div class="filter-control">
+        <span>标签词:</span>
+        <el-input
+          v-model="listQuery.keyword"
+          placeholder="标签词"
+          clearable
+          @keyup.enter.native="getList"
+          @clear="getList"
+        />
+      </div>
+      <div class="filter-control">
+        <span>来源:</span>
+        <el-select v-model="listQuery.fromSearch" clearable @change="getList">
+          <el-option :value="1" label="单个添加" />
+          <el-option :value="4" label="协销填写" />
+        </el-select>
+      </div>
+      <div class="filter-control">
+        <span>协销:</span>
+        <el-select v-model="listQuery.serviceProviderId" filterable @change="getList">
+          <el-option value="" label="请选择" />
+          <el-option
+            v-for="item in sellerList"
+            :key="item.serviceProviderId"
+            :label="item.linkMan"
+            :value="item.serviceProviderId"
+          />
+        </el-select>
+      </div>
+      <div class="filter-control">
+        <span>添加时间:</span>
+        <el-date-picker
+          v-model="time"
+          type="daterange"
+          unlink-panels
+          range-separator="至"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :picker-options="pickerOptions"
+          value-format="yyyy-MM-dd"
+          @change="getList"
+        />
+      </div>
+      <div class="filter-control">
+        <el-button type="primary" @click="getList"> 查询 </el-button>
+        <el-button v-permission="'tag:static-list:add'" type="primary" @click="handleAddTag"> 添加标签 </el-button>
+        <el-button v-permission="'tag:static-list:del'" type="danger" :disabled="disabled" @click="handleDeleteTag">
+          删除
+        </el-button>
+      </div>
+    </div>
+    <!-- 标签列表 -->
+    <el-table v-loading="isLoading" :data="list" border height="600" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="序号" :index="indexMethod" type="index" sortable="custom" align="center" width="80" />
+      <el-table-column prop="keyword" label="标签词" align="center" />
+      <el-table-column width="180" label="来源" align="center">
+        <template slot-scope="{ row }">
+          <span v-if="row.fromSearch === 1">单个添加</span>
+          <span v-else-if="row.fromSearch === 2">系统推荐</span>
+          <span v-else-if="row.fromSearch === 3">导入</span>
+          <span v-else>协销填写</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="添加时间" align="center" width="200">
+        <template slot-scope="{ row }">
+          <span v-if="row.addTime">{{ row.addTime | parseTime }}</span>
+          <span v-else>-</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" width="240">
+        <template slot-scope="{ row }">
+          <el-button v-permission="'tag:static-list:del'" type="danger" size="mini" @click="handleDeleteTag(row)">
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 页码 -->
+    <pagination
+      :total="total"
+      :page.sync="listQuery.pageNum"
+      :limit.sync="listQuery.pageSize"
+      @pagination="getServiceList"
+    />
+
+    <!-- 去搜索跳转 -->
+    <SearchModel v-model="searchDialog" :keyword="visibleKeyword" />
+
+    <!-- 添加标签 -->
+    <el-dialog
+      title="添加标签"
+      :visible.sync="addTagDialog"
+      width="460px"
+      :close-on-click-modal="false"
+      :show-close="false"
+    >
+      <el-form ref="tagForm" :model="tagForm" :rules="tagFormRules">
+        <el-form-item label="标签名:" prop="keyword">
+          <el-input v-model="tagForm.keyword" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer">
+        <el-button @click="closeAddTagDialog"> 取 消 </el-button>
+        <el-button type="primary" @click="handleAddTagConfirm"> 确 定 </el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import SearchModel from '@/components/SearchModel'
+import { getYestodayTime } from '@/utils'
+import {
+  getServiceList,
+  saveLabelByState,
+  deleteKeyword,
+  getStatekeywordList,
+  findLinkageStatus
+} from '@/api/library/keyword'
+export default {
+  components: { SearchModel },
+  data() {
+    const pickerOptions = {
+      shortcuts: [
+        {
+          text: '近1年',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 365)
+            picker.$emit('pick', [start, end])
+          }
+        },
+        {
+          text: '近半年',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 183)
+            picker.$emit('pick', [start, end])
+          }
+        },
+        {
+          text: '近1月',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
+            picker.$emit('pick', [start, end])
+          }
+        },
+        {
+          text: '近1周',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 6)
+            picker.$emit('pick', [start, end])
+          }
+        },
+        {
+          text: '昨天',
+          onClick(picker) {
+            const { start, end } = getYestodayTime()
+            picker.$emit('pick', [start, end])
+          }
+        }
+      ]
+    }
+    return {
+      isLoading: true,
+      pickerOptions,
+      time: '',
+      listQuery: {
+        keyword: '',
+        beginTime: '',
+        endTime: '',
+        serviceProviderId: '',
+        pageNum: 1,
+        pageSize: 10
+      },
+      list: [],
+      total: 0,
+      currentList: [],
+      searchDialog: false,
+      visibleKeyword: '',
+      addTagDialog: false,
+      tagForm: {
+        keyword: ''
+      },
+      tagFormRules: {
+        keyword: [{ required: true, message: '请输入标签名称', trigger: ['blur'] }]
+      },
+      exportKeywordList: [],
+      fileList: [],
+      importForm: {
+        fileUrl: ''
+      },
+      importFormRules: {
+        fileUrl: [{ required: true, message: '文件不能为空', trigger: ['change'] }]
+      },
+      sellerList: []
+    }
+  },
+  computed: {
+    disabled() {
+      return this.currentList.length === 0
+    }
+  },
+  created() {
+    this.getList()
+  },
+  methods: {
+    // 标签下拉关联
+    async handleStatusChange($event) {
+      const res = await findLinkageStatus({ id: $event.id, linkageStatus: $event.linkageStatus ? 1 : 0 })
+      if (res.code === 0) {
+        if (res.data === 0) {
+          await this.fetchKeywordList()
+          return this.$message({
+            type: 'success',
+            message: `${res.msg}`
+          })
+        }
+        if (res.msg.length < 5) {
+          this.$message({
+            type: 'success',
+            message: '开启成功!'
+          })
+        } else {
+          this.$confirm(`${res.msg}`, '提示', {
+            confirmButtonText: '确定',
+            cancelButtonText: '取消',
+            type: 'warning'
+          })
+            .then(() => {
+              $event.linkageStatus = !$event.linkageStatus
+            })
+            .catch(() => {
+              $event.linkageStatus = !$event.linkageStatus
+            })
+        }
+        await this.fetchKeywordList()
+      }
+    },
+
+    // 获取标签列表
+    getList() {
+      this.listQuery.pageNum = 1
+      if (this.time && this.time.length > 0) {
+        this.listQuery.beginTime = this.time[0]
+        this.listQuery.endTime = this.time[1]
+      } else {
+        this.listQuery.beginTime = ''
+        this.listQuery.endTime = ''
+      }
+      this.getServiceList()
+      this.getStatekeywordList()
+    },
+    // 获取协销列表选项
+    async getServiceList() {
+      try {
+        const res = await getServiceList()
+        this.sellerList = res.data
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 获取标签列表
+    async getStatekeywordList() {
+      try {
+        this.isLoading = true
+        const res = await getStatekeywordList(this.listQuery)
+        this.list = res.data.results.map((i) => ({
+          addTime: i.addTime,
+          frequency: i.frequency,
+          fromSearch: i.fromSearch,
+          id: i.id,
+          keyword: i.keyword,
+          labelStatus: i.labelStatus,
+          linkageStatus: i.linkageStatus === 1, // 0 关闭,1 打开
+          recommendTime: i.recommendTime,
+          searchTime: i.searchTime
+        }))
+        this.total = res.data.totalRecord
+        this.isLoading = false
+      } catch (error) {
+        console.log(error)
+      }
+    },
+
+    // 选中列表项
+    handleSelectionChange(current) {
+      this.currentList = current
+    },
+
+    // 去搜索
+    handleSearch(keyword) {
+      this.visibleKeyword = keyword
+      this.searchDialog = true
+    },
+
+    // 添加标签
+    handleAddTag() {
+      this.addTagDialog = true
+    },
+
+    // 添加标签取消
+    closeAddTagDialog() {
+      this.$refs.tagForm.resetFields()
+      this.addTagDialog = false
+    },
+
+    // 添加标签确定
+    async handleAddTagConfirm() {
+      try {
+        await this.$refs.tagForm.validate()
+        this.addTagSubmit()
+      } catch (error) {
+        console.log(error)
+      }
+    },
+
+    // 提交添加标签信息
+    async addTagSubmit() {
+      try {
+        await saveLabelByState(this.tagForm)
+        this.$message.success('添加标签成功')
+        this.getList()
+      } catch (error) {
+        console.log(error)
+      }
+      this.closeAddTagDialog()
+    },
+
+    // 删除标签
+    async handleDeleteTag(row) {
+      try {
+        await this.$confirm('确定删除已选标签?', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        })
+        this.deleteTagSubmit(row)
+      } catch (error) {
+        this.$message.info('已取消删除操作')
+      }
+    },
+
+    // 提交删除标签操作
+    async deleteTagSubmit(row) {
+      const keywords = row instanceof Event ? this.currentList : [].concat(row)
+      const ids = keywords.map((item) => item.id).join(',')
+      try {
+        await deleteKeyword({ id: ids })
+        this.$message.success('标签删除成功')
+        this.getList()
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    indexMethod(index) {
+      return index + this.listQuery.pageSize * (this.listQuery.pageNum - 1) + 1
+    }
+  }
+}
+</script>
+
+<style></style>

+ 25 - 28
src/views/member/product/list.vue

@@ -11,7 +11,7 @@
               v-model="listQuery.productId"
               placeholder="商品ID"
               clearable
-              @input="e => (listQuery.productId= checkedInput(e,1))"
+              @input="(e) => (listQuery.productId = checkedInput(e, 1))"
               @keyup.enter.native="getList"
               @clear="getList"
             />
@@ -22,7 +22,7 @@
               v-model="listQuery.productName"
               placeholder="商品名称"
               clearable
-              @input="e => (listQuery.productName= checkedInput(e,2))"
+              @input="(e) => (listQuery.productName = checkedInput(e, 2))"
               @keyup.enter.native="getList"
               @clear="getList"
             />
@@ -39,29 +39,24 @@
           </div>
           <div class="filter-control">
             <span>优惠状态:</span>
-            <el-select v-model="listQuery.status" style="width:120px;" clearable @change="getList">
+            <el-select v-model="listQuery.status" style="width: 120px" clearable @change="getList">
               <el-option value="" label="请选择" />
               <el-option :value="0" label="已上架" />
               <el-option :value="1" label="已下架" />
             </el-select>
           </div>
           <div class="filter-control">
-            <el-button type="primary" @click="getList">查询</el-button>
-            <el-button type="primary" @click="proDialogVisible =true">添加</el-button>
+            <el-button type="primary" @click="getList"> 查询 </el-button>
+            <el-button type="primary" @click="proDialogVisible = true"> 添加 </el-button>
           </div>
         </div>
         <el-table v-loading="isLoading" :data="tableData" border style="width: 100%">
           <el-table-column prop="productId" label="商品ID" align="center" />
           <el-table-column prop="coupon" label="商品图片" align="center">
             <template v-if="row.productId" slot-scope="{ row }">
-              <el-popover
-                placement="top-start"
-                title=""
-                width="180"
-                trigger="hover"
-              >
-                <img :src="row.productImage" alt="" style="width:100px;height:100px;">
-                <img slot="reference" :src="row.productImage" alt="" style="width:50px;height:50px;">
+              <el-popover placement="top-start" title="" width="180" trigger="hover">
+                <img :src="row.productImage" alt="" style="width: 100px; height: 100px" />
+                <img slot="reference" :src="row.productImage" alt="" style="width: 50px; height: 50px" />
               </el-popover>
             </template>
           </el-table-column>
@@ -70,7 +65,7 @@
           <el-table-column prop="price" label="机构价" align="center" />
           <el-table-column prop="discount" label="会员折扣" align="center">
             <template slot-scope="{ row }">
-              {{ row.priceType === 1 ? row.discount+'%' : '---' }}
+              {{ row.priceType === 1 ? row.discount + '%' : '---' }}
             </template>
           </el-table-column>
           <el-table-column prop="discountPrice" label="会员价" align="center">
@@ -79,25 +74,21 @@
             </template>
           </el-table-column>
           <el-table-column label="排序" width="80" align="center">
-            <template slot-scope="{row}">
+            <template slot-scope="{ row }">
               <el-input v-model="row.sort" maxlength="4" minlength="1" @blur="handleOnInputBlur(row)" />
             </template>
           </el-table-column>
           <el-table-column prop="status" label="优惠状态" align="center" width="100">
             <template slot-scope="{ row }">
-              <span v-if="row.status === 0" class="el-span-zero">
-                已上架
-              </span>
-              <span v-else class="el-span-one">
-                已下架
-              </span>
+              <span v-if="row.status === 0" class="el-span-zero"> 已上架 </span>
+              <span v-else class="el-span-one"> 已下架 </span>
             </template>
           </el-table-column>
           <el-table-column prop="addTime" label="添加时间" align="center" width="100" />
           <el-table-column label="操作" align="center" width="180">
             <template slot-scope="{ row }">
-              <el-button type="primary" size="mini" @click="handleEdit(row.id)">编辑</el-button>
-              <el-button type="danger" size="mini" @click="handeleDelPro(row.id)">删除</el-button>
+              <el-button type="primary" size="mini" @click="handleEdit(row.id)"> 编辑 </el-button>
+              <el-button type="danger" size="mini" @click="handeleDelPro(row.id)"> 删除 </el-button>
             </template>
           </el-table-column>
         </el-table>
@@ -113,10 +104,16 @@
         <!--  选择商品弹窗 -->
         <pro-dialog v-if="proDialogVisible" ref="proDialog" @confirm="handleAddProductConfirm" @cancel="handleCancel" />
         <!-- 商品编辑弹窗 -->
-        <pro-edit v-if="proEditVisible" ref="proEdit" :pro-id="handleProId" @confirm="handleEditConfirm" @cancel="handleEditCancel" />
+        <pro-edit
+          v-if="proEditVisible"
+          ref="proEdit"
+          :pro-id="handleProId"
+          @confirm="handleEditConfirm"
+          @cancel="handleEditCancel"
+        />
       </template>
       <template v-else>
-        <div class="club-container" style="width: 100%;height: 650px;padding-top: 40px;">
+        <div class="club-container" style="width: 100%; height: 650px; padding-top: 40px">
           <el-form ref="submitForm" class="doctor-edit-form" label-width="140px" :model="formData" :rules="rules">
             <el-form-item label="PC端:" prop="doctorImage">
               <div class="form-label-tip">宣传图</div>
@@ -141,8 +138,8 @@
               />
             </el-form-item>
           </el-form>
-          <div class="submit-btn" style="padding-left: 137px;">
-            <el-button type="primary" :disabled="disabled" @click="submitSave">保存</el-button>
+          <div class="submit-btn" style="padding-left: 137px">
+            <el-button type="primary" :disabled="disabled" @click="submitSave"> 保存 </el-button>
           </div>
         </div>
       </template>
@@ -208,7 +205,7 @@ export default {
     },
     handleOnInputBlur(row) {
       // 更新排序
-      updateSort({ id: row.id, sort: row.sort }).then(response => {
+      updateSort({ id: row.id, sort: row.sort }).then((response) => {
         this.$message({
           message: '操作成功',
           type: 'success',

+ 8 - 7
src/views/sys/login/index.vue

@@ -53,16 +53,15 @@
       <el-button
         :loading="loading"
         type="primary"
-        style="width: 100%; margin-bottom: 30px"
+        style="width: 100%; margin-bottom: 30px; padding: 15px 0"
         @click.native.prevent="handleLogin"
-      >登录</el-button>
+      >
+        登录
+      </el-button>
     </el-form>
 
     <el-dialog title="Or connect with" :visible.sync="showDialog">
       Can not be simulated on local, so please combine you own business simulation! ! !
-      <br>
-      <br>
-      <br>
     </el-dialog>
   </div>
 </template>
@@ -119,7 +118,7 @@ export default {
   },
   watch: {
     $route: {
-      handler: function(route) {
+      handler(route) {
         const query = route.query
         if (query) {
           this.redirect = query.redirect
@@ -259,6 +258,7 @@ $cursor: #fff;
     background: rgba(0, 0, 0, 0.1);
     border-radius: 5px;
     color: #454545;
+    margin-bottom: 30px;
   }
 }
 </style>
@@ -307,11 +307,12 @@ $light_gray: #eee;
     position: relative;
 
     .title {
-      font-size: 26px;
+      font-size: 30px;
       color: $light_gray;
       margin: 0px auto 40px auto;
       text-align: center;
       font-weight: bold;
+      font-family: '宋体';
     }
   }
 

+ 177 - 0
src/views/user/consult/components/datePicker.vue

@@ -0,0 +1,177 @@
+<template>
+  <div class="date-switch">
+    <div class="date-container">
+      <div class="date-item" @click="handlePrevClick">
+        <i class="el-icon-caret-left"></i>
+        <span>{{ prevDate }}</span>
+      </div>
+      <div class="date-item">
+        <!-- <el-date-picker
+          v-model="date"
+          type="date"
+          :editable="false"
+          format="yyyy 年 MM 月 dd 日"
+          value-format="yyyy-MM-dd"
+          style="color: #1890ff; font-size: 24px; width: 280px; font-weight: bold"
+          @prev-click="handlePrevClick"
+          @next-click="handleNextClick"
+        /> -->
+        <P style="color: #1890ff; font-size: 24px; width: 280px; font-weight: bold">
+          {{ dateTime }}
+          <span v-if="dateDay" style="color: #67c23a; padding: 0">({{ dateDay }})</span>
+        </P>
+      </div>
+      <div class="date-item" @click="handleNextClick">
+        <span>{{ nextDate }}</span>
+        <i class="el-icon-caret-right"></i>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'DateSwitch',
+  props: {
+    dates: {
+      type: String,
+      default: ''
+    }
+  },
+  data() {
+    return {
+      date: '',
+      dateDay: '',
+      dateTime: '',
+      prevDate: '',
+      nextDate: ''
+    }
+  },
+  created() {
+    const date = new Date()
+    this.date = new Date(date - 86400000)
+    this.dateDay = '昨天'
+    this.dateTime = this.formattedDate(this.date)
+    this.prevDate = this.formattedDate(new Date(this.date.getTime() - 86400000)) // 加上一天
+    this.nextDate = this.formattedDate(new Date(this.date.getTime() + 86400000)) // 加上一天
+  },
+  methods: {
+    handlePrevClick() {
+      this.date = new Date(this.date.getTime() - 86400000) // 减去一天
+      this.dateTime = this.formattedDate(this.date)
+      this.prevDate = this.formattedDate(new Date(this.date.getTime() - 86400000)) // 加上一天
+      this.nextDate = this.formattedDate(new Date(this.date.getTime() + 86400000)) // 加上一天
+      this.handleCheckdTime()
+      const data = this.formattedDateFn(this.date)
+      this.$emit('prev-month', data)
+    },
+    handleNextClick() {
+      this.date = new Date(this.date.getTime() + 86400000) // 加上一天
+      this.dateTime = this.formattedDate(this.date)
+      this.prevDate = this.formattedDate(new Date(this.date.getTime() - 86400000)) // 加上一天
+      this.nextDate = this.formattedDate(new Date(this.date.getTime() + 86400000)) // 加上一天
+      this.handleCheckdTime()
+      const data = this.formattedDateFn(this.date)
+      this.$emit('next-month', data)
+    },
+    handleCheckdTime() {
+      // 设置 今天 昨天 前天
+      const date = new Date() // 当前时间
+      const yesterday = new Date(date.getTime() - 86400000)
+      const beforeYesterday = new Date(date.getTime() - (86400000 + 86400000))
+      if (this.formattedDateFn(this.date) === this.formattedDateFn(date)) {
+        this.dateDay = '今天'
+      } else if (this.formattedDateFn(this.date) === this.formattedDateFn(yesterday)) {
+        this.dateDay = '昨天'
+      } else if (this.formattedDateFn(this.date) === this.formattedDateFn(beforeYesterday)) {
+        this.dateDay = '前天'
+      } else {
+        this.dateDay = ''
+      }
+    },
+    formattedDate(dateString) {
+      const date = new Date(dateString)
+      const formattedDate = `${date.getFullYear()}年${date.getMonth() + 1}月${date.getDate()}日`
+      return formattedDate
+    },
+    formattedDateFn(dateString) {
+      // 创建一个Date对象,将字符串解析为日期和时间
+      const date = new Date(dateString)
+      // 使用toISOString()方法将Date对象转换为ISO格式的字符串
+      const isoString = date.toISOString()
+      // 从ISO格式字符串中提取日期部分
+      const dateOnly = isoString.substring(0, isoString.indexOf('T'))
+      // 将日期格式化为"YYYY-MM-DD"格式
+      const formattedDate = dateOnly.replace(/-/g, '-')
+      return formattedDate
+    }
+  }
+}
+</script>
+
+<style>
+.date-switch {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  width: 100%;
+  padding: 10px;
+  margin: 10px 0;
+  background: #f7f7f7;
+}
+
+.date-container {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  width: 100%;
+  box-sizing: border-box;
+  padding: 0 100px;
+}
+
+.date-item {
+  text-align: center;
+  font-size: 16px;
+  cursor: pointer;
+  line-height: 45px;
+}
+.date-item span {
+  font-size: 20px;
+  line-height: 38px;
+  display: inline-block;
+  padding: 0 10px;
+  text-align: center;
+  color: rgba(24, 144, 255, 0.7);
+}
+.date-item.active {
+  font-weight: bold;
+}
+
+.date-item i {
+  font-size: 20px;
+}
+.date-item .el-icon-caret-left {
+  font-size: 20px;
+  font-weight: bold;
+  color: #1890ff;
+}
+.date-item .el-icon-caret-right {
+  font-size: 20px;
+  font-weight: bold;
+  color: #1890ff;
+}
+.date-item .el-input--medium .el-input__inner {
+  border: none !important;
+  color: #1890ff;
+  background: #f7f7f7;
+}
+.date-item .el-input__prefix {
+  display: none !important;
+}
+.date-item .el-input__suffix {
+  display: none !important;
+}
+.el-picker-panel.el-date-picker.el-popper {
+  display: none !important;
+}
+</style>

+ 516 - 0
src/views/user/consult/detail.vue

@@ -0,0 +1,516 @@
+<template>
+  <div class="app-container" style="padding: 0 20px 20px 20px">
+    <!-- 筛选项 -->
+    <div class="filter-container">
+      <div class="filter-control">
+        <span>标签词:</span>
+        <el-input
+          v-model="listQuery.remarks"
+          placeholder="标签词"
+          clearable
+          @keyup.enter.native="getList"
+          @clear="getList"
+        />
+      </div>
+      <div class="filter-control">
+        <span>机构名称:</span>
+        <el-input
+          v-model="listQuery.clubName"
+          placeholder="机构名称"
+          clearable
+          @keyup.enter.native="getList"
+          @clear="getList"
+        />
+      </div>
+      <div class="filter-control">
+        <span>咨询类别:</span>
+        <el-select v-model="listQuery.consult" clearable @change="getList">
+          <el-option value="" label="请选择" />
+          <el-option v-for="(item, index) in categoryList" :key="index" :label="item.className" :value="item.id" />
+        </el-select>
+      </div>
+      <div class="filter-control">
+        <span>新分配机构:</span>
+        <el-select v-model="listQuery.newDeal" clearable @change="getList">
+          <el-option :value="0" label="请选择" />
+          <el-option :value="1" label="是" />
+          <el-option :value="2" label="否" />
+        </el-select>
+      </div>
+      <div class="filter-control">
+        <span>添加日期:</span>
+        <el-date-picker
+          v-model="time"
+          type="daterange"
+          unlink-panels
+          range-separator="至"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          value-format="yyyy-MM-dd"
+          :picker-options="pickerOptions"
+          @change="getList"
+        />
+      </div>
+      <div class="filter-control">
+        <el-button type="primary" @click="getList"> 查询 </el-button>
+      </div>
+    </div>
+    <div class="filter-container">
+      <template v-if="isLoading">
+        <div class="list-loading">
+          <p style="color: #ffffff"><i class="el-icon-loading"></i></p>
+        </div>
+      </template>
+      <template v-else>
+        <div v-if="list.length === 0" class="list-main-empty">
+          <p style="color: #999999">暂无咨询记录</p>
+        </div>
+        <div v-for="(item, index) in list" v-else :key="index" class="list-main">
+          <div class="list-main-item">
+            <span class="list-time">{{ item.addTime }}</span>
+            <el-row :gutter="24" class="box-row">
+              <el-col v-if="item.clubName" :span="6"><b>机构:</b> {{ item.clubName }}</el-col>
+              <el-col :span="6"><b>咨询人:</b> {{ item.questionMan }}</el-col>
+              <el-col v-if="item.contractMobile" :span="12"><b>手机号:</b> {{ item.contractMobile }}</el-col>
+            </el-row>
+            <template v-if="item.product && item.product.length > 0">
+              <el-row :gutter="24" class="box-row">
+                <el-col :span="6"><b>咨询商品:</b></el-col>
+              </el-row>
+              <el-row :gutter="24" class="box-row">
+                <el-col :span="24">
+                  <el-table :data="item.product" border width="1000">
+                    <el-table-column prop="mainImage" label="商品图片" align="center" width="100">
+                      <template slot-scope="{ row }">
+                        <el-popover placement="top-start" title="" width="180" trigger="hover">
+                          <img :src="row.mainImage" alt="" style="width: 150px; height: 150px" />
+                          <img slot="reference" :src="row.mainImage" alt="" style="width: 30px; height: 30px" />
+                        </el-popover>
+                      </template>
+                    </el-table-column>
+                    <el-table-column prop="name" label="商品名称" align="center" />
+                    <el-table-column prop="shopName" label="供应商名称" align="center" />
+                  </el-table>
+                </el-col>
+              </el-row>
+            </template>
+            <template v-if="item.reports && item.reports.length > 0">
+              <el-row :gutter="24" class="box-row">
+                <el-col :span="6"><b>咨询报备:</b></el-col>
+              </el-row>
+              <el-row :gutter="24" class="box-row">
+                <el-col :span="24">
+                  <el-table :data="item.reports" border width="1000">
+                    <el-table-column prop="mainImage" label="商品图片" align="center" width="100">
+                      <template slot-scope="{ row }">
+                        <el-popover placement="top-start" title="" width="180" trigger="hover">
+                          <img :src="row.mainImage" alt="" style="width: 150px; height: 150px" />
+                          <img slot="reference" :src="row.mainImage" alt="" style="width: 30px; height: 30px" />
+                        </el-popover>
+                      </template>
+                    </el-table-column>
+                    <el-table-column prop="productName" label="商品名称" align="center" />
+                    <el-table-column prop="reportText" label="报备事由" align="center" />
+                    <el-table-column prop="status" label="审核状态" align="center" width="100">
+                      <template slot-scope="{ row }">
+                        <el-tag v-if="row.status === 1" type="warning" size="small">待审核</el-tag>
+                        <el-tag v-else-if="row.status === 2" type="success" size="small">已审核</el-tag>
+                        <el-tag v-else type="danger" size="small">审核未通过</el-tag>
+                      </template>
+                    </el-table-column>
+                    <el-table-column prop="auditName" label="审核人" align="center" width="100">
+                      <template slot-scope="{ row }">
+                        {{ row.auditName ? row.auditName : '---' }}
+                      </template>
+                    </el-table-column>
+                    <el-table-column prop="auditTime" label="审核时间" align="center">
+                      <template slot-scope="{ row }">
+                        {{ row.auditTime ? row.auditTime : '---' }}
+                      </template>
+                    </el-table-column>
+                    <el-table-column prop="auditText" label="备注" align="center">
+                      <template slot-scope="{ row }">
+                        {{ row.auditText ? row.auditText : '---' }}
+                      </template>
+                    </el-table-column>
+                    <el-table-column label="操作" align="center" width="200">
+                      <el-button
+                        type="primary"
+                        size="mini"
+                        style="margin: 2px"
+                        @click="handleDisassociation(item.remarksId, item.type)"
+                      >
+                        取消关联
+                      </el-button>
+                    </el-table-column>
+                  </el-table>
+                </el-col>
+              </el-row>
+            </template>
+            <el-row :gutter="24" class="box-row">
+              <el-col :span="6">
+                <b>沟通情况:</b>
+                <el-tag v-if="item.communicationSituation === 1" type="danger" size="small"> 联系不上 </el-tag>
+                <el-tag v-else type="success" size="small">
+                  已沟通
+                  <template v-if="item.communicationMethods === '1'"> (电话) </template>
+                  <template v-if="item.communicationMethods === '2'"> (微信) </template>
+                  <template v-if="item.communicationMethods === '1,2' || item.communicationMethods === '2,1'">
+                    (电话,微信)
+                  </template>
+                </el-tag>
+              </el-col>
+              <el-col v-if="item.customerSource !== null" :span="6">
+                <b>客户来源:</b>
+                <el-tag type="success" size="small">
+                  {{ item.customerSource | sourceActionsFilters }}
+                </el-tag>
+              </el-col>
+              <el-col v-if="item.customerGender !== null" :span="6">
+                <b>客户性别:</b>
+                <el-tag v-if="item.customerGender === 0" type="success" size="small"> 男 </el-tag>
+                <el-tag v-if="item.customerGender === 1" type="success" size="small"> 女 </el-tag>
+              </el-col>
+            </el-row>
+            <el-row :gutter="24" class="box-row">
+              <el-col v-if="item.customerAge" :span="6">
+                <b>客户年龄:</b>
+                <el-tag type="success" size="small"> {{ item.customerAge }} </el-tag>
+              </el-col>
+              <el-col v-if="item.groupAddition !== ''" :span="6">
+                <b>加群情况:</b>
+                <el-tag v-if="item.groupAddition === 0" type="success" size="small"> 已加群 </el-tag>
+                <el-tag v-else type="danger" size="small"> 未加群 </el-tag>
+              </el-col>
+              <el-col v-if="item.consultType" :span="12">
+                <b>咨询类别:</b>
+                <el-tag type="success" size="small"> {{ item.consultType }} </el-tag>
+              </el-col>
+            </el-row>
+            <el-row :gutter="24" class="box-row">
+              <el-col v-if="item.satisfied" :span="6">
+                <b>意向程度:</b>
+                <el-tag type="success" size="small"> {{ (item.satisfied * 1) | intenActionsFilters }} </el-tag>
+              </el-col>
+              <el-col v-if="item.pinceSensitve" :span="6">
+                <b>价格敏感度:</b>
+                <el-tag type="success" size="small"> {{ (item.pinceSensitve * 1) | pinceFilters }} </el-tag>
+              </el-col>
+              <el-col v-if="item.followup" :span="6">
+                <b>跟进状态:</b>
+                <el-tag type="success" size="small"> {{ (item.followup * 1) | followupFilters }} </el-tag>
+              </el-col>
+            </el-row>
+            <el-row v-if="item.remarks" :gutter="24" class="box-row">
+              <el-col :span="24">
+                <b>标签词:</b>
+                <el-tag type="success" size="small"> {{ item.remarks }} </el-tag>
+              </el-col>
+            </el-row>
+            <el-row v-if="item.extra" :gutter="24" class="box-row">
+              <el-col :span="24">
+                <b>额外说明:</b>
+                {{ item.extra }}
+              </el-col>
+            </el-row>
+            <el-row v-if="item.imageList.length > 0" :gutter="24" class="box-row">
+              <el-col :span="24">
+                <b>图片:</b>
+              </el-col>
+              <el-col :span="24">
+                <div
+                  v-for="(image, imageIndex) in item.imageList"
+                  :key="imageIndex"
+                  class="item-image"
+                  style="width: 100px; height: 100px; margin: 5px; float: left"
+                >
+                  <el-popover placement="top-start" title="" width="180" trigger="hover">
+                    <img :src="image" alt="" style="width: 150px; height: 150px" />
+                    <img slot="reference" :src="image" alt="" style="width: 100px; height: 100px" />
+                  </el-popover>
+                </div>
+              </el-col>
+            </el-row>
+            <el-row v-if="item.fileList.length > 0" :gutter="24" class="box-row">
+              <el-col :span="24">
+                <b>文件:</b>
+              </el-col>
+              <el-col :span="24">
+                <div v-for="(file, fileIndex) in item.fileList" :key="fileIndex" class="item-file">
+                  <el-tag type="warning" size="small"> {{ file.fileName }} </el-tag>
+                  <el-button type="primary" size="mini" style="margin: 5px 10px" @click="handlePreview(file)">
+                    预览
+                  </el-button>
+                  <el-button type="primary" size="mini" style="margin: 5px 10px" @click="handleDownload(file)">
+                    下载
+                  </el-button>
+                </div>
+              </el-col>
+            </el-row>
+          </div>
+        </div>
+      </template>
+    </div>
+    <!-- 页码 -->
+    <pagination
+      :total="total"
+      :page-sizes="[20]"
+      :page-size="20"
+      :page.sync="listQuery.pageNum"
+      :limit.sync="listQuery.pageSize"
+      @pagination="cmRegistReportList"
+    />
+  </div>
+</template>
+
+<script>
+import { downloadWithUrl } from '@/utils'
+import openWindow from '@/utils/open-window'
+import { getClassName, cmRegistReportList, getAudit } from '@/api/user/consult/consult'
+import pickerOptions from '@/utils/time-picker.js'
+export default {
+  name: 'ConsultDetail',
+  filters: {
+    followupFilters(value) {
+      // 跟进状态
+      const map = {
+        1: '跟进中',
+        2: '跟进完成',
+        3: '已放弃'
+      }
+      return map[value]
+    },
+    pinceFilters(value) {
+      // 价格敏感度
+      const map = {
+        1: '敏感',
+        2: '适中',
+        3: '不敏感',
+        4: '不明确'
+      }
+      return map[value]
+    },
+    intenActionsFilters(value) {
+      // 意向
+      const map = {
+        1: '意向强烈',
+        2: '意向一般',
+        3: '意向平淡',
+        4: '随便看看'
+      }
+      return map[value]
+    },
+    sourceActionsFilters(value) {
+      // 客户来源
+      const map = {
+        0: '网站',
+        1: '小程序',
+        2: '公众号',
+        3: '小红书',
+        4: '微博',
+        5: '搜狐',
+        6: '其他'
+      }
+      return map[value]
+    }
+  },
+  data() {
+    return {
+      pickerOptions,
+      time: '',
+      isLoading: true,
+      listQuery: {
+        reportId: this.$route.query.reportId, // 报备Id
+        remarks: '', // 标签词
+        consult: '', // 咨询类别
+        clubName: '', // 机构名称
+        newDeal: '', // 新分配机构状态 0 全部 1 是  2否
+        startAddTime: '', // 时间
+        endAddTime: '', // 协销Id
+        pageNum: 1,
+        pageSize: 100
+      },
+      list: [],
+      total: 0,
+      categoryList: [],
+      serviceList: []
+    }
+  },
+  computed: {},
+  created() {
+    this.getClassName()
+    this.getList()
+  },
+  mounted() {},
+  methods: {
+    // 获取行为记录列表
+    getList() {
+      this.listQuery.pageNum = 1
+      if (this.time && this.time.length > 0) {
+        this.listQuery.startTime = this.time[0]
+        this.listQuery.endTime = this.time[1]
+      } else {
+        this.listQuery.startTime = ''
+        this.listQuery.endTime = ''
+      }
+      this.cmRegistReportList()
+    },
+    // 获取咨询类别选项
+    async getClassName() {
+      try {
+        const res = await getClassName()
+        this.categoryList = res.data
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 获取报备详情
+    async cmRegistReportList() {
+      try {
+        this.isLoading = true
+        const res = await cmRegistReportList(this.listQuery)
+        this.list = res.data
+        this.total = res.data.totalRecord
+        this.isLoading = false
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 操作取消关联
+    async handleDisassociation(remarksId, type) {
+      try {
+        await this.$confirm('确定取消该咨询记录与此报备的关联吗?', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        })
+        this.getAudit(remarksId, type)
+      } catch (error) {
+        this.$message.info('已取消操作')
+      }
+    },
+    // 预览文件
+    handlePreview(file) {
+      const fileName = file.fileName
+      let url = `https://view.officeapps.live.com/op/view.aspx?src=${encodeURIComponent(file.fileUrl)}`
+      if (fileName.endsWith('.pdf') || fileName.endsWith('.doc')) {
+        url = file.fileUrl
+      }
+      openWindow(url, `${file.fileName}`, 800, 460)
+    },
+    // 下载文件
+    async handleDownload(file) {
+      const params = `fileName=${encodeURIComponent(file.fileName)}&ossName=${encodeURIComponent(file.ossName)}`
+      const url = process.env.VUE_APP_BASE_API + `/user/remarks/remarks/download?${params}`
+      downloadWithUrl(url, file.fileName)
+    },
+    // 取消关联
+    async getAudit(remarksId, type) {
+      try {
+        await getAudit({ remarksId: remarksId, type: type })
+        this.$message.success('操作成功')
+        this.getList()
+      } catch (error) {
+        console.log(error)
+      }
+    }
+  }
+}
+</script>
+
+<style>
+.filter-container {
+  padding: 10px;
+  background: #f7f7f7;
+  margin: 10px 0;
+}
+.span-labels {
+  font-size: 14px;
+  color: #666666;
+  margin-right: 50px;
+}
+.list-loading {
+  width: 100%;
+  height: 300px;
+  padding: 40px;
+  line-height: 220px;
+  box-sizing: border-box;
+  position: relative;
+  text-align: center;
+  background: #ffffff;
+}
+.list-loading .el-icon-loading {
+  font-size: 40px;
+  color: #409eff;
+}
+.list-main-empty {
+  width: 100%;
+  height: 300px;
+  padding: 40px;
+  line-height: 220px;
+  box-sizing: border-box;
+  position: relative;
+  text-align: center;
+}
+.list-main {
+  width: 100%;
+  height: auto;
+  padding: 24px 16px 24px 160px;
+  box-sizing: border-box;
+  position: relative;
+}
+.list-main::before {
+  content: '';
+  height: 100%;
+  border-left: 2px dashed #e1e1e1;
+  position: absolute;
+  left: 120px;
+  top: 0;
+}
+.list-main-item {
+  width: 94%;
+  min-height: 200px;
+  box-sizing: border-box;
+  padding: 24px 35px;
+  background: #e1e1e1;
+  background-size: cover;
+  position: relative;
+  border-radius: 16px;
+}
+.list-main-item::before {
+  content: '';
+  width: 20px;
+  height: 20px;
+  background: #999999;
+  border-radius: 50%;
+  background-size: cover;
+  position: absolute;
+  top: 30px;
+  left: -49px;
+}
+.list-main-item::after {
+  content: '';
+  width: 0;
+  height: 0;
+  border-width: 30px;
+  border-style: solid;
+  border-color: transparent #e1e1e1 transparent transparent;
+  position: absolute;
+  left: -55px;
+  top: 10px;
+}
+.list-main-item .list-time {
+  display: inline-block;
+  font-size: 20px;
+  color: #333333;
+  position: absolute;
+  top: 7px;
+  left: -164px;
+  font-weight: bold;
+  width: 120px;
+  text-align: center;
+}
+.box-row {
+  margin-bottom: 14px;
+}
+</style>

+ 237 - 0
src/views/user/consult/genre-list.vue

@@ -0,0 +1,237 @@
+<template>
+  <div class="app-container">
+    <!-- 顶部操作区域 -->
+    <div class="filter-container">
+      <div class="filter-control">
+        <span>类别名称:</span>
+        <el-input
+          v-model="listQuery.className"
+          placeholder="类别名称"
+          clearable
+          @keyup.enter.native="getList"
+          @clear="getList"
+        />
+      </div>
+      <div class="filter-control">
+        <span>状态:</span>
+        <el-select v-model="listQuery.status" style="width: 120px" clearable @change="getList">
+          <el-option value="" label="请选择" />
+          <el-option :value="1" label="启用" />
+          <el-option :value="2" label="停用" />
+        </el-select>
+      </div>
+      <div class="filter-control">
+        <el-button type="primary" @click="getList"> 查询 </el-button>
+        <el-button type="primary" @click="dialogFormVisible = true"> 添加类别 </el-button>
+        <el-button type="primary" @click="getList"> 一键排序 </el-button>
+      </div>
+    </div>
+    <!-- 列表 -->
+    <el-table v-loading="isLoading" :data="list" border style="width: 100%" :height="tableHeight">
+      <el-table-column label="序号" align="center" width="50">
+        <template slot-scope="scope">
+          {{ scope.$index + 1 }}
+        </template>
+      </el-table-column>
+      <el-table-column prop="className" label="咨询类别名称" align="center" />
+      <el-table-column prop="status" label="状态" align="center">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.status === 2" type="danger" size="small">已停用</el-tag>
+          <el-tag v-else type="success" size="small">已启用</el-tag>
+          <el-button v-if="row.status === 2" type="primary" size="mini" @click="handleShangeStatus(row.id, row.status)">
+            启用
+          </el-button>
+          <el-button v-else type="primary" size="mini" @click="handleShangeStatus(row.id, row.status)">
+            停用
+          </el-button>
+        </template>
+      </el-table-column>
+      <el-table-column label="排序" width="80" align="center">
+        <template slot-scope="{ row }">
+          <el-input v-model="row.sortNumber" maxlength="4" minlength="1" @blur="consultSort(row)" />
+        </template>
+      </el-table-column>
+      <el-table-column prop="addTime" label="创建时间" align="center">
+        <template slot-scope="{ row }">
+          {{ row.createdTime | parseTime }}
+        </template>
+      </el-table-column>
+      <el-table-column fixed="right" label="操作" align="center" width="200">
+        <template slot-scope="{ row }">
+          <el-button type="primary" size="mini" style="margin: 2px" @click="handleEdit(row)"> 编辑 </el-button>
+          <!-- <el-button type="danger" size="mini" style="margin: 2px" @click="handleDelete(row)"> 删除 </el-button> -->
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 页码 -->
+    <pagination
+      :total="total"
+      :page-sizes="[20]"
+      :page-size="20"
+      :page.sync="listQuery.pageNum"
+      :limit.sync="listQuery.pageSize"
+      @pagination="fetchRecordList"
+    />
+    <!-- 添加咨询类别 -->
+    <el-dialog title="咨询类别添加" :visible.sync="dialogFormVisible" width="500px">
+      <el-form ref="dataForm" :rules="rules" :model="form" label-position="right" label-width="120px">
+        <el-form-item label="咨询类别名称:" prop="className">
+          <el-input v-model="form.className" type="text" placeholder="咨询类别名称" maxlength="50" />
+        </el-form-item>
+        <el-form-item label="咨询类别排序:" prop="sortNumber">
+          <el-input v-model="form.sortNumber" type="text" placeholder="咨询类别排序" maxlength="10" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="closeDialog">取消</el-button>
+        <el-button type="primary" @click="handleSaveConsult">确定</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { getConsultList, saveConsult, deleteConsult, consultSort } from '@/api/user/consult/consult'
+const defaultListQuery = {
+  className: '', // 类别名称
+  status: '', // 状态 1启用,2停用,默认1
+  pageNum: 1,
+  pageSize: 20
+}
+export default {
+  name: 'GenreList',
+  filters: {},
+  data() {
+    return {
+      isLoading: true,
+      listQuery: Object.assign({}, defaultListQuery),
+      list: [],
+      total: 0,
+      dialogFormVisible: false,
+      form: {
+        className: '',
+        sortNumber: ''
+      },
+      rules: {
+        className: [{ required: true, message: '请填写咨询类别名称', trigger: 'blur' }],
+        sortNumber: [{ required: true, message: '请填写咨询类别排序', trigger: 'blur' }]
+      }
+    }
+  },
+  computed: {},
+  created() {
+    this.getList()
+  },
+  mounted() {},
+  methods: {
+    // 获取咨询类别列表
+    getList() {
+      this.listQuery.pageNum = 1
+      this.getConsultList()
+    },
+
+    // 获取咨询类别列表
+    async getConsultList() {
+      try {
+        this.isLoading = true
+        const res = await getConsultList(this.listQuery)
+        this.list = res.data.results
+        this.total = res.data.totalRecord
+        this.isLoading = false
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 操作启用停用
+    handleShangeStatus(id, status) {
+      let confirmTxt = ''
+      let paramsStatus
+      if (status === 1) {
+        confirmTxt = '确定停用该类别?'
+        paramsStatus = 2
+      } else {
+        confirmTxt = '确定启用该类别?'
+        paramsStatus = 1
+      }
+      this.$confirm(confirmTxt)
+        .then((_) => {
+          this.getConsultStatus(id, paramsStatus)
+        })
+        .catch(() => {
+          console.log('用户取消操作')
+        })
+    },
+    // 上下线轮播图
+    async getConsultStatus(id, paramsStatus) {
+      try {
+        await saveConsult({ id: id, status: paramsStatus })
+        this.$message.success('操作成功')
+        this.getList()
+      } catch (error) {
+        console.log('error', error)
+      }
+    },
+    // 确认保存类别
+    async handleSaveConsult() {
+      try {
+        await this.$refs.dataForm.validate()
+        this.saveConsult(this.form)
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 保存咨询类别
+    async saveConsult(params) {
+      await saveConsult(params)
+      this.$message.success('保存成功')
+      this.closeDialog()
+      this.getList()
+    },
+    // 添加标签取消
+    closeDialog() {
+      this.$refs.dataForm.resetFields()
+      this.dialogFormVisible = false
+    },
+    // 编辑类别
+    handleEdit(row) {
+      this.form = { ...this.form, ...row }
+      this.dialogFormVisible = true
+    },
+    // 操作删除类别
+    async handleDelete(row) {
+      try {
+        await this.$confirm('确定删除该类别吗?', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        })
+        this.deleteConsult(row)
+      } catch (error) {
+        this.$message.info('已取消删除操作')
+      }
+    },
+    // 调用删除类别
+    async deleteConsult(row) {
+      try {
+        await deleteConsult(row.id)
+        this.$message.success('操作成功')
+        this.getList()
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 咨询类别排序
+    async consultSort(row) {
+      try {
+        await consultSort({ id: row.id, sortNumber: row.sortNumber })
+        this.getList()
+      } catch (error) {
+        console.log(error)
+      }
+    }
+  }
+}
+</script>
+
+<style></style>

+ 599 - 0
src/views/user/consult/list.vue

@@ -0,0 +1,599 @@
+<template>
+  <div class="app-container" style="padding: 0 20px 20px 20px">
+    <!-- 顶部操作区域 -->
+    <date-picker @prev-month="handlePrevMonth" @next-month="handleNextMonth" />
+    <!-- 筛选项 -->
+    <div class="filter-container">
+      <div class="filter-control">
+        <span>标签词:</span>
+        <el-input
+          v-model="listQuery.remarks"
+          placeholder="标签词"
+          clearable
+          @keyup.enter.native="getList"
+          @clear="getList"
+        />
+      </div>
+      <div class="filter-control">
+        <span>机构名称:</span>
+        <el-input
+          v-model="listQuery.clubName"
+          placeholder="机构名称"
+          clearable
+          @keyup.enter.native="getList"
+          @clear="getList"
+        />
+      </div>
+      <div class="filter-control">
+        <span>咨询类别:</span>
+        <el-select v-model="listQuery.consult" clearable @change="getList">
+          <el-option value="" label="请选择" />
+          <el-option v-for="(item, index) in categoryList" :key="index" :label="item.className" :value="item.id" />
+        </el-select>
+      </div>
+      <div class="filter-control">
+        <span>是否注册:</span>
+        <el-select v-model="listQuery.isRegister" clearable @change="getList">
+          <el-option value="" label="请选择" />
+          <el-option :value="1" label="未注册" />
+          <el-option :value="2" label="已注册" />
+        </el-select>
+      </div>
+      <div class="filter-control">
+        <span>新分配机构:</span>
+        <el-select v-model="listQuery.newDeal" clearable @change="getList">
+          <el-option value="" label="请选择" />
+          <el-option :value="1" label="是" />
+          <el-option :value="2" label="否" />
+        </el-select>
+      </div>
+      <div class="filter-control">
+        <el-button type="primary" @click="getList"> 查询 </el-button>
+      </div>
+    </div>
+    <div class="filter-container">
+      <span class="span-labels">
+        当日咨询客户总数:
+        <el-tag type="primary" size="small">
+          {{ totalInfo.number }}
+        </el-tag>
+      </span>
+      <span class="span-labels">
+        已注册客户:
+        <el-tag type="primary" size="small">
+          {{ totalInfo.registeredNumber }}
+        </el-tag>
+      </span>
+      <span class="span-labels">
+        未注册客户:
+        <el-tag type="primary" size="small">
+          {{ totalInfo.unRegisteredNumber }}
+        </el-tag>
+      </span>
+    </div>
+    <div class="filter-container">
+      <span
+        v-for="(item, index) in serviceList"
+        :key="index"
+        style="margin-right: 15px; margin-bottom: 5px; display: inline-block"
+      >
+        <el-button :type="sellerTabsIndex === index ? 'primary' : ''" @click="handeleTabsClick(item, index)">
+          {{ item.linkMan }}:
+          {{ item.registeredNumber + item.unregisteredNumber }}
+          ({{ item.registeredNumber }} +{{ item.unregisteredNumber }})
+        </el-button>
+      </span>
+    </div>
+    <div class="filter-container">
+      <span class="span-labels">
+        <el-tag type="primary" size="small">{{ sellerTabsInfo.linkMan }}</el-tag>
+        当日咨询客户总数:
+        <el-tag type="primary" size="small">
+          {{ sellerTabsInfo.registeredNumber + sellerTabsInfo.unregisteredNumber }}
+        </el-tag>
+      </span>
+      <span class="span-labels">
+        已注册客户:
+        <el-tag type="primary" size="small">
+          {{ sellerTabsInfo.registeredNumber }}
+        </el-tag>
+      </span>
+      <span class="span-labels">
+        未注册客户:
+        <el-tag type="primary" size="small">
+          {{ sellerTabsInfo.unregisteredNumber }}
+        </el-tag>
+      </span>
+    </div>
+    <div class="filter-container">
+      <template v-if="isLoading">
+        <div class="list-loading">
+          <p style="color: #ffffff"><i class="el-icon-loading"></i></p>
+        </div>
+      </template>
+      <template v-else>
+        <div v-if="list.length === 0" class="list-main-empty">
+          <p style="color: #999999">暂无咨询记录</p>
+        </div>
+        <div v-for="(item, index) in list" v-else :key="index" class="list-main">
+          <div class="list-main-item consult-list">
+            <span class="list-time">{{ item.divisionTime }}</span>
+            <el-row :gutter="24" class="box-row">
+              <el-col v-if="item.clubName" :span="6"><b>机构:</b> {{ item.clubName }}</el-col>
+              <el-col :span="6"><b>咨询人:</b> {{ item.questionMan }}</el-col>
+              <el-col v-if="item.contractMobile" :span="12"><b>手机号:</b> {{ item.contractMobile }}</el-col>
+            </el-row>
+            <template v-if="item.product && item.product.length > 0">
+              <el-row :gutter="24" class="box-row">
+                <el-col :span="6"><b>咨询商品:</b></el-col>
+              </el-row>
+              <el-row :gutter="24" class="box-row">
+                <el-col :span="24">
+                  <el-table :data="item.product" border width="1000">
+                    <el-table-column prop="mainImage" label="商品图片" align="center" width="100">
+                      <template slot-scope="{ row }">
+                        <el-popover placement="top-start" title="" width="180" trigger="hover">
+                          <img :src="row.mainImage" alt="" style="width: 150px; height: 150px" />
+                          <img slot="reference" :src="row.mainImage" alt="" style="width: 30px; height: 30px" />
+                        </el-popover>
+                      </template>
+                    </el-table-column>
+                    <el-table-column prop="name" label="商品名称" align="center" />
+                    <el-table-column prop="shopName" label="供应商名称" align="center" />
+                  </el-table>
+                </el-col>
+              </el-row>
+            </template>
+            <template v-if="item.reports && item.reports.length > 0">
+              <el-row :gutter="24" class="box-row">
+                <el-col :span="6"><b>咨询报备:</b></el-col>
+              </el-row>
+              <el-row :gutter="24" class="box-row">
+                <el-col :span="24">
+                  <el-table :data="item.reports" border width="1000">
+                    <el-table-column prop="mainImage" label="商品图片" align="center" width="100">
+                      <template slot-scope="{ row }">
+                        <el-popover placement="top-start" title="" width="180" trigger="hover">
+                          <img :src="row.mainImage" alt="" style="width: 150px; height: 150px" />
+                          <img slot="reference" :src="row.mainImage" alt="" style="width: 30px; height: 30px" />
+                        </el-popover>
+                      </template>
+                    </el-table-column>
+                    <el-table-column prop="productName" label="商品名称" align="center" />
+                    <el-table-column prop="reportText" label="报备事由" align="center" />
+                    <el-table-column prop="status" label="审核状态" align="center" width="100">
+                      <template slot-scope="{ row }">
+                        <el-tag v-if="row.status === 1" type="warning" size="small">待审核</el-tag>
+                        <el-tag v-else-if="row.status === 2" type="success" size="small">已审核</el-tag>
+                        <el-tag v-else type="danger" size="small">审核未通过</el-tag>
+                      </template>
+                    </el-table-column>
+                    <el-table-column prop="auditName" label="审核人" align="center" width="100">
+                      <template slot-scope="{ row }">
+                        {{ row.auditName ? row.auditName : '---' }}
+                      </template>
+                    </el-table-column>
+                    <el-table-column prop="auditTime" label="审核时间" align="center">
+                      <template slot-scope="{ row }">
+                        {{ row.auditTime ? row.auditTime : '---' }}
+                      </template>
+                    </el-table-column>
+                    <el-table-column prop="auditText" label="备注" align="center">
+                      <template slot-scope="{ row }">
+                        {{ row.auditText ? row.auditText : '---' }}
+                      </template>
+                    </el-table-column>
+                  </el-table>
+                </el-col>
+              </el-row>
+            </template>
+            <el-row :gutter="24" class="box-row">
+              <el-col :span="6">
+                <b>沟通情况:</b>
+                <el-tag v-if="item.communicationSituation === 1" type="danger" size="small"> 联系不上 </el-tag>
+                <el-tag v-else type="success" size="small">
+                  已沟通
+                  <template v-if="item.communicationMethods === '1'"> (电话) </template>
+                  <template v-if="item.communicationMethods === '2'"> (微信) </template>
+                  <template v-if="item.communicationMethods === '1,2' || item.communicationMethods === '2,1'">
+                    (电话,微信)
+                  </template>
+                </el-tag>
+              </el-col>
+              <el-col v-if="item.customerSource !== null" :span="6">
+                <b>客户来源:</b>
+                <el-tag type="success" size="small">
+                  {{ item.customerSource | sourceActionsFilters }}
+                </el-tag>
+              </el-col>
+              <el-col v-if="item.customerGender !== null" :span="6">
+                <b>客户性别:</b>
+                <el-tag v-if="item.customerGender === 0" type="success" size="small"> 男 </el-tag>
+                <el-tag v-if="item.customerGender === 1" type="success" size="small"> 女 </el-tag>
+              </el-col>
+            </el-row>
+            <el-row :gutter="24" class="box-row">
+              <el-col v-if="item.customerAge" :span="6">
+                <b>客户年龄:</b>
+                <el-tag type="success" size="small"> {{ item.customerAge }} </el-tag>
+              </el-col>
+              <el-col :span="6">
+                <b>加群情况:</b>
+                <el-tag v-if="item.groupAddition === 0" type="success" size="small"> 已加群 </el-tag>
+                <el-tag v-else type="danger" size="small"> 未加群 </el-tag>
+              </el-col>
+              <el-col v-if="item.consultType" :span="12">
+                <b>咨询类别:</b>
+                <el-tag type="success" size="small"> {{ item.consultType }} </el-tag>
+              </el-col>
+            </el-row>
+            <el-row :gutter="24" class="box-row">
+              <el-col v-if="item.satisfied" :span="6">
+                <b>意向程度:</b>
+                <el-tag type="success" size="small"> {{ (item.satisfied * 1) | intenActionsFilters }} </el-tag>
+              </el-col>
+              <el-col v-if="item.pinceSensitve" :span="6">
+                <b>价格敏感度:</b>
+                <el-tag type="success" size="small"> {{ (item.pinceSensitve * 1) | pinceFilters }} </el-tag>
+              </el-col>
+              <el-col v-if="item.followup" :span="6">
+                <b>跟进状态:</b>
+                <el-tag type="success" size="small"> {{ (item.followup * 1) | followupFilters }} </el-tag>
+              </el-col>
+            </el-row>
+            <el-row v-if="item.remarks" :gutter="24" class="box-row">
+              <el-col :span="24">
+                <b>标签词:</b>
+                <el-tag type="success" size="small"> {{ item.remarks }} </el-tag>
+              </el-col>
+            </el-row>
+            <el-row v-if="item.extra" :gutter="24" class="box-row">
+              <el-col :span="24">
+                <b>额外说明:</b>
+                {{ item.extra }}
+              </el-col>
+            </el-row>
+            <el-row v-if="item.imageList.length > 0" :gutter="24" class="box-row">
+              <el-col :span="24">
+                <b>图片:</b>
+              </el-col>
+              <el-col :span="24">
+                <div
+                  v-for="(image, imageIndex) in item.imageList"
+                  :key="imageIndex"
+                  class="item-image"
+                  style="width: 100px; height: 100px; margin: 5px; float: left"
+                >
+                  <el-popover placement="top-start" title="" width="180" trigger="hover">
+                    <img :src="image" alt="" style="width: 150px; height: 150px" />
+                    <img slot="reference" :src="image" alt="" style="width: 100px; height: 100px" />
+                  </el-popover>
+                </div>
+              </el-col>
+            </el-row>
+            <el-row v-if="item.fileList.length > 0" :gutter="24" class="box-row">
+              <el-col :span="24">
+                <b>文件:</b>
+              </el-col>
+              <el-col :span="24">
+                <div v-for="(file, fileIndex) in item.fileList" :key="fileIndex" class="item-file">
+                  <el-tag type="warning" size="small"> {{ file.fileName }} </el-tag>
+                  <el-button type="primary" size="mini" style="margin: 5px 10px" @click="handlePreview(file)">
+                    预览
+                  </el-button>
+                  <el-button type="primary" size="mini" style="margin: 5px 10px" @click="handleDownload(file)">
+                    下载
+                  </el-button>
+                </div>
+              </el-col>
+            </el-row>
+          </div>
+        </div>
+      </template>
+    </div>
+    <!-- 页码 -->
+    <pagination
+      :total="total"
+      :page-sizes="[20]"
+      :page-size="20"
+      :page.sync="listQuery.pageNum"
+      :limit.sync="listQuery.pageSize"
+      @pagination="getRemarksRegistList"
+    />
+  </div>
+</template>
+
+<script>
+import { downloadWithUrl } from '@/utils'
+import openWindow from '@/utils/open-window'
+import { getClassName, getServiceList, getRemarksRegistList } from '@/api/user/consult/consult'
+import DatePicker from './components/datePicker'
+
+export default {
+  name: 'ConsultList',
+  components: {
+    DatePicker
+  },
+  filters: {
+    followupFilters(value) {
+      // 跟进状态
+      const map = {
+        1: '跟进中',
+        2: '跟进完成',
+        3: '已放弃'
+      }
+      return map[value]
+    },
+    pinceFilters(value) {
+      // 价格敏感度
+      const map = {
+        1: '敏感',
+        2: '适中',
+        3: '不敏感',
+        4: '不明确'
+      }
+      return map[value]
+    },
+    intenActionsFilters(value) {
+      // 意向
+      const map = {
+        1: '意向强烈',
+        2: '意向一般',
+        3: '意向平淡',
+        4: '随便看看'
+      }
+      return map[value]
+    },
+    sourceActionsFilters(value) {
+      // 客户来源
+      console.log('value', value)
+      const map = {
+        0: '网站',
+        1: '小程序',
+        2: '公众号',
+        3: '小红书',
+        4: '微博',
+        5: '搜狐',
+        6: '其他'
+      }
+      return map[value]
+    }
+  },
+  data() {
+    return {
+      isLoading: true,
+      listQuery: {
+        remarks: '', // 标签词
+        consult: '', // 咨询类别
+        clubName: '', // 机构名称
+        newDeal: '', // 新分配机构状态 0 全部 1 是  2否
+        isRegister: '', // 是否注册 0 全部 1 未注册 2已注册
+        todayTime: '', // 时间
+        serviceProviderId: '', // 协销Id
+        pageNum: 1,
+        pageSize: 20
+      },
+      freezeTimeText: '',
+      list: [],
+      total: 0,
+      categoryList: [],
+      totalInfo: {},
+      sellerTabsIndex: 0,
+      sellerTabsInfo: {},
+      serviceList: []
+    }
+  },
+  computed: {},
+  created() {
+    this.initDate()
+  },
+  mounted() {},
+  methods: {
+    initDate() {
+      // 初始化获取当前年月
+      const date = new Date()
+      this.getClassName()
+      this.listQuery.todayTime = this.formattedDateFn(new Date(date - 86400000))
+      this.getServiceList(this.listQuery.todayTime)
+      console.log('todayTime', this.listQuery.todayTime)
+    },
+    formattedDateFn(dateString) {
+      // 创建一个Date对象,将字符串解析为日期和时间
+      const date = new Date(dateString)
+      // 使用toISOString()方法将Date对象转换为ISO格式的字符串
+      const isoString = date.toISOString()
+      // 从ISO格式字符串中提取日期部分
+      const dateOnly = isoString.substring(0, isoString.indexOf('T'))
+      // 将日期格式化为"YYYY-MM-DD"格式
+      const formattedDate = dateOnly.replace(/-/g, '-')
+      return formattedDate
+    },
+    handleNextMonth(value) {
+      // 加日期
+      this.listQuery.todayTime = value
+      this.getServiceList(this.listQuery.todayTime)
+      this.getList()
+      console.log('todayTime', this.listQuery.todayTime)
+    },
+    handlePrevMonth(value) {
+      // 减日期
+      this.listQuery.todayTime = value
+      this.getServiceList(this.listQuery.todayTime)
+      this.getList()
+      console.log('todayTime', this.listQuery.todayTime)
+    },
+    handeleTabsClick(item, index) {
+      // 切换协销
+      console.log('item', item)
+      this.sellerTabsIndex = index
+      this.sellerTabsInfo = item
+      this.listQuery.serviceProviderId = item.serviceProviderId
+      this.listQuery.pageNum = 1
+      this.getList()
+    },
+    // 获取行为记录列表
+    getList() {
+      this.listQuery.pageNum = 1
+      this.getRemarksRegistList()
+    },
+    // 获取咨询类别选项
+    async getClassName() {
+      try {
+        const res = await getClassName()
+        this.categoryList = res.data
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 获取当天协销咨询记录信息
+    async getServiceList(accessDate) {
+      try {
+        const res = await getServiceList({ accessDate: accessDate })
+        this.serviceList = res.data.serviceList
+        this.totalInfo = { ...this.totalInfo, ...res.data }
+        this.sellerTabsInfo = this.serviceList[0]
+        this.listQuery.serviceProviderId = this.serviceList[0].serviceProviderId
+        this.getRemarksRegistList()
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 获取咨询记录
+    async getRemarksRegistList() {
+      try {
+        this.isLoading = true
+        const res = await getRemarksRegistList(this.listQuery)
+        this.list = res.data.results
+        this.total = res.data.totalRecord
+        this.isLoading = false
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 预览文件
+    handlePreview(file) {
+      const fileName = file.fileName
+      let url = `https://view.officeapps.live.com/op/view.aspx?src=${encodeURIComponent(file.fileUrl)}`
+      if (fileName.endsWith('.pdf') || fileName.endsWith('.doc')) {
+        url = file.fileUrl
+      }
+      openWindow(url, `${file.fileName}`, 800, 460)
+    },
+    // 下载文件
+    async handleDownload(file) {
+      const params = `fileName=${encodeURIComponent(file.fileName)}&ossName=${encodeURIComponent(file.ossName)}`
+      const url = process.env.VUE_APP_BASE_API + `/user/remarks/remarks/download?${params}`
+      downloadWithUrl(url, file.fileName)
+    },
+    // 机构跳转
+    handleClubHrefLink(row) {
+      return (
+        process.env.VUE_APP_ADMIN_URL +
+        `/a/user/jumpLink/toOldAdmin?type=1&clubId=${row.clubId}&clubName=${row.corporateName}`
+      )
+    },
+    // 查看详情
+    handleRecordDetail(row) {
+      this.$router.push({
+        path: '/user/detail-list',
+        query: { ip: row.ip, accessDate: row.accessDate, userId: row.userId }
+      })
+    }
+  }
+}
+</script>
+
+<style>
+.filter-container {
+  padding: 10px;
+  background: #f7f7f7;
+  margin: 10px 0;
+}
+.span-labels {
+  font-size: 14px;
+  color: #666666;
+  margin-right: 50px;
+}
+.list-loading {
+  width: 100%;
+  height: 300px;
+  padding: 40px;
+  line-height: 220px;
+  box-sizing: border-box;
+  position: relative;
+  text-align: center;
+  background: #ffffff;
+}
+.list-loading .el-icon-loading {
+  font-size: 40px;
+  color: #409eff;
+}
+.list-main-empty {
+  width: 100%;
+  height: 300px;
+  padding: 40px;
+  line-height: 220px;
+  box-sizing: border-box;
+  position: relative;
+  text-align: center;
+}
+.list-main {
+  width: 100%;
+  height: auto;
+  padding: 24px 16px 24px 160px;
+  box-sizing: border-box;
+  position: relative;
+}
+.list-main::before {
+  content: '';
+  height: 100%;
+  border-left: 2px dashed #e1e1e1;
+  position: absolute;
+  left: 120px;
+  top: 0;
+}
+.list-main-item {
+  width: 94%;
+  min-height: 200px;
+  box-sizing: border-box;
+  padding: 24px 35px;
+  background: #e1e1e1;
+  background-size: cover;
+  position: relative;
+  border-radius: 16px;
+}
+.list-main-item::before {
+  content: '';
+  width: 20px;
+  height: 20px;
+  background: #999999;
+  border-radius: 50%;
+  background-size: cover;
+  position: absolute;
+  top: 30px;
+  left: -49px;
+}
+.list-main-item::after {
+  content: '';
+  width: 0;
+  height: 0;
+  border-width: 30px;
+  border-style: solid;
+  border-color: transparent #e1e1e1 transparent transparent;
+  position: absolute;
+  left: -55px;
+  top: 10px;
+}
+.list-main-item.consult-list .list-time {
+  display: inline-block;
+  font-size: 20px;
+  color: #333333;
+  position: absolute;
+  top: 26px;
+  left: -140px;
+  font-weight: bold;
+}
+.box-row {
+  margin-bottom: 14px;
+}
+</style>

+ 292 - 0
src/views/user/consult/report-list.vue

@@ -0,0 +1,292 @@
+<template>
+  <div class="app-container">
+    <!-- 顶部操作区域 -->
+    <div class="filter-container">
+      <div class="filter-control">
+        <span>ID:</span>
+        <el-input
+          v-model="listQuery.reportId"
+          style="width: 120px"
+          placeholder="ID"
+          clearable
+          @input="(e) => (listQuery.reportId = checkedInput(e))"
+          @keyup.enter.native="getList"
+          @clear="getList"
+        />
+      </div>
+      <div class="filter-control">
+        <span>商品名称:</span>
+        <el-input
+          v-model="listQuery.productName"
+          placeholder="商品名称"
+          clearable
+          @keyup.enter.native="getList"
+          @clear="getList"
+        />
+      </div>
+      <div class="filter-control">
+        <span>机构名称:</span>
+        <el-input
+          v-model="listQuery.clubName"
+          placeholder="机构名称"
+          clearable
+          @keyup.enter.native="getList"
+          @clear="getList"
+        />
+      </div>
+      <div class="filter-control">
+        <span>报备人:</span>
+        <el-input
+          v-model="listQuery.reportName"
+          style="width: 120px"
+          placeholder="报备人"
+          clearable
+          @keyup.enter.native="getList"
+          @clear="getList"
+        />
+      </div>
+      <div class="filter-control">
+        <span>审核状态:</span>
+        <el-select v-model="listQuery.status" style="width: 120px" clearable @change="getList">
+          <el-option value="" label="请选择" />
+          <el-option :value="1" label="待审核" />
+          <el-option :value="2" label="审核通过" />
+          <el-option :value="3" label="审核未通过" />
+        </el-select>
+      </div>
+      <div class="filter-control">
+        <span>提交时间:</span>
+        <el-date-picker
+          v-model="time"
+          type="daterange"
+          unlink-panels
+          value-format="yyyy-MM-dd"
+          range-separator="至"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :picker-options="pickerOptions"
+          @change="getList"
+        />
+      </div>
+      <div class="filter-control">
+        <el-button type="primary" @click="getList"> 查询 </el-button>
+      </div>
+    </div>
+    <!-- 列表 -->
+    <el-table v-loading="isLoading" :data="list" border style="width: 100%" height="650">
+      <el-table-column prop="reportId" label="ID" align="center" width="50" />
+      <el-table-column prop="mainImage" label="商品图片" align="center" width="100">
+        <template v-if="row.mainImage" slot-scope="{ row }">
+          <el-popover placement="top-start" title="" width="180" trigger="hover">
+            <img :src="row.mainImage" alt="" style="width: 100px; height: 100px" />
+            <img slot="reference" :src="row.mainImage" alt="" style="width: 50px; height: 50px" />
+          </el-popover>
+        </template>
+      </el-table-column>
+      <el-table-column prop="productName" label="商品名称" align="center" width="200" />
+      <el-table-column prop="clubName" label="机构名称" align="center" width="180" />
+      <el-table-column prop="reportName" label="报备人" align="center" width="120" />
+      <el-table-column prop="reportText" label="报备事由" align="center" />
+      <el-table-column prop="addTime" label="创建时间" align="center" width="100">
+        <template slot-scope="{ row }">
+          {{ row.addTime ? row.addTime : '---' }}
+        </template>
+      </el-table-column>
+      <el-table-column prop="status" label="审核状态" align="center" width="100">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.status === 1" type="warning" size="small">待审核</el-tag>
+          <el-tag v-else-if="row.status === 2" type="success" size="small">已审核</el-tag>
+          <el-tag v-else type="danger" size="small">审核未通过</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column prop="auditName" label="审核人" align="center" width="120" />
+      <el-table-column prop="auditTime" label="审核时间" align="center" width="100">
+        <template slot-scope="{ row }">
+          {{ row.auditTime ? row.auditTime : '---' }}
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" width="220">
+        <template slot-scope="{ row }">
+          <el-button type="primary" size="mini" style="margin: 2px" @click="handleExamine(row)"> 审核 </el-button>
+          <el-button type="primary" size="mini" style="margin: 2px" @click="handleRecordDetail(row)"> 查看 </el-button>
+          <el-button type="danger" size="mini" style="margin: 2px" @click="handleDelete(row)"> 删除 </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 页码 -->
+    <pagination
+      :total="total"
+      :page-sizes="[20]"
+      :page-size="20"
+      :page.sync="listQuery.pageNum"
+      :limit.sync="listQuery.pageSize"
+      @pagination="getReportList"
+    />
+    <el-dialog title="审核" :visible.sync="dialogFormVisible" width="440px">
+      <el-form ref="dataForm" :rules="rules" :model="form" label-position="right">
+        <el-form-item label="状态:" prop="status">
+          <el-select v-model="form.status" placeholder="请选择">
+            <el-option label="请选择" value="" />
+            <el-option label="审核通过" :value="2" />
+            <el-option label="审核不通过" :value="3" />
+          </el-select>
+        </el-form-item>
+        <el-form-item prop="auditText">
+          <el-input
+            v-model="form.auditText"
+            type="textarea"
+            placeholder="请填写备注,200字以内"
+            maxlength="200"
+            :autosize="{ minRows: 5, maxRows: 5 }"
+          />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="closeDialog">取消</el-button>
+        <el-button type="primary" @click="handleReportCount">确定</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { getReportList, reportCount, deleteReport } from '@/api/user/consult/consult'
+import pickerOptions from '@/utils/time-picker.js'
+const defaultListQuery = {
+  reportId: '', // 报备Id
+  productName: '', // 咨询商品名称
+  clubName: '', // 机构名称
+  reportName: '', // 报备人
+  status: '', // 状态 1.已审核 2.待审核 3.审核未通过
+  startAddTime: '', // 开始时间
+  endAddTime: '', // 结束时间
+  pageNum: 1,
+  pageSize: 20
+}
+export default {
+  name: 'ReportList',
+  filters: {},
+  data() {
+    return {
+      isLoading: true,
+      pickerOptions,
+      time: '',
+      listQuery: Object.assign({}, defaultListQuery),
+      list: [],
+      total: 0,
+      dialogFormVisible: false,
+      form: {
+        reportId: '',
+        status: '',
+        auditText: ''
+      },
+      rules: {
+        status: [{ required: true, message: '请选择审核状态', trigger: 'blur' }],
+        auditText: [{ required: true, message: '请填写备注', trigger: 'blur' }]
+      }
+    }
+  },
+  computed: {},
+  created() {
+    this.getList()
+  },
+  mounted() {},
+  methods: {
+    // 获取行为记录列表
+    getList() {
+      this.listQuery.pageNum = 1
+      this.list = []
+      if (this.time && this.time.length > 0) {
+        this.listQuery.startAddTime = this.time[0]
+        this.listQuery.endAddTime = this.time[1]
+      } else {
+        this.listQuery.startAddTime = ''
+        this.listQuery.endAddTime = ''
+      }
+      this.getReportList()
+    },
+
+    // 获取关键词列表
+    async getReportList() {
+      try {
+        this.isLoading = true
+        const res = await getReportList(this.listQuery)
+        this.list = res.data.results
+        this.total = res.data.totalRecord
+        this.isLoading = false
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 审核报备
+    handleExamine(row) {
+      this.form.reportId = row.reportId
+      this.dialogFormVisible = true
+    },
+    // 确定审核
+    async handleReportCount() {
+      try {
+        await this.$refs.dataForm.validate()
+        this.reportCount(this.form)
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 调用审核报备
+    async reportCount(params) {
+      await reportCount(params)
+      this.$message.success('审核成功')
+      this.closeDialog()
+      this.getList()
+    },
+    // 添加标签取消
+    closeDialog() {
+      this.$refs.dataForm.resetFields()
+      this.dialogFormVisible = false
+    },
+    async handleDelete(row) {
+      try {
+        await this.$confirm('确定删除该报备吗?', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        })
+        this.deleteReport(row)
+      } catch (error) {
+        this.$message.info('已取消删除操作')
+      }
+    },
+    // 调用删除报备
+    async deleteReport(row) {
+      try {
+        await deleteReport(row.reportId)
+        this.$message.success('操作成功')
+        this.getList()
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 机构跳转
+    handleClubHrefLink(row) {
+      return (
+        process.env.VUE_APP_ADMIN_URL +
+        `/a/user/jumpLink/toOldAdmin?type=1&clubId=${row.clubId}&clubName=${row.corporateName}`
+      )
+    },
+    // 查看详情
+    handleRecordDetail(row) {
+      this.$router.push({
+        path: '/user/consult/detail',
+        query: { reportId: row.reportId }
+      })
+    },
+    checkedInput(event) {
+      const pattern = /[^0-9.]/g
+      return event.replace(pattern, '')
+    }
+  }
+}
+</script>
+
+<style></style>

+ 469 - 0
src/views/user/consult/unreg-detail.vue

@@ -0,0 +1,469 @@
+<template>
+  <div class="app-container" style="padding: 0 20px 20px 20px">
+    <!-- 筛选项 -->
+    <div class="filter-container">
+      <div class="filter-control">
+        <span>标签词:</span>
+        <el-input
+          v-model="listQuery.remarks"
+          placeholder="标签词"
+          clearable
+          @keyup.enter.native="getList"
+          @clear="getList"
+        />
+      </div>
+      <div class="filter-control">
+        <span>咨询类别:</span>
+        <el-select v-model="listQuery.consult" clearable @change="getList">
+          <el-option value="" label="请选择" />
+          <el-option v-for="(item, index) in categoryList" :key="index" :label="item.className" :value="item.id" />
+        </el-select>
+      </div>
+      <div class="filter-control">
+        <span>添加日期:</span>
+        <el-date-picker
+          v-model="time"
+          type="daterange"
+          unlink-panels
+          range-separator="至"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          value-format="yyyy-MM-dd"
+          :picker-options="pickerOptions"
+          @change="getList"
+        />
+      </div>
+      <div class="filter-control">
+        <el-button type="primary" @click="getList"> 查询 </el-button>
+      </div>
+    </div>
+    <div class="filter-container">
+      <template v-if="isLoading">
+        <div class="list-loading">
+          <p style="color: #ffffff"><i class="el-icon-loading"></i></p>
+        </div>
+      </template>
+      <template v-else>
+        <div v-if="list.length === 0" class="list-main-empty">
+          <p style="color: #999999">暂无咨询记录</p>
+        </div>
+        <div v-for="(item, index) in list" v-else :key="index" class="list-main">
+          <div class="list-main-item unreg">
+            <span class="list-time">{{ item.addTime }}</span>
+            <el-row :gutter="24" class="box-row">
+              <el-col :span="6"><b>咨询人:</b> {{ item.questionMan }}</el-col>
+              <el-col v-if="item.contractMobile" :span="12"><b>手机号:</b> {{ item.contractMobile }}</el-col>
+            </el-row>
+            <template v-if="item.product && item.product.length > 0">
+              <el-row :gutter="24" class="box-row">
+                <el-col :span="6"><b>咨询商品:</b></el-col>
+              </el-row>
+              <el-row :gutter="24" class="box-row">
+                <el-col :span="24">
+                  <el-table :data="item.product" border width="1000">
+                    <el-table-column prop="mainImage" label="商品图片" align="center" width="100">
+                      <template slot-scope="{ row }">
+                        <el-popover placement="top-start" title="" width="180" trigger="hover">
+                          <img :src="row.mainImage" alt="" style="width: 150px; height: 150px" />
+                          <img slot="reference" :src="row.mainImage" alt="" style="width: 30px; height: 30px" />
+                        </el-popover>
+                      </template>
+                    </el-table-column>
+                    <el-table-column prop="name" label="商品名称" align="center" />
+                    <el-table-column prop="shopName" label="供应商名称" align="center" />
+                  </el-table>
+                </el-col>
+              </el-row>
+            </template>
+            <template v-if="item.reports && item.reports.length > 0">
+              <el-row :gutter="24" class="box-row">
+                <el-col :span="6"><b>咨询报备:</b></el-col>
+              </el-row>
+              <el-row :gutter="24" class="box-row">
+                <el-col :span="24">
+                  <el-table :data="item.reports" border width="1000">
+                    <el-table-column prop="mainImage" label="商品图片" align="center" width="100">
+                      <template slot-scope="{ row }">
+                        <el-popover placement="top-start" title="" width="180" trigger="hover">
+                          <img :src="row.mainImage" alt="" style="width: 150px; height: 150px" />
+                          <img slot="reference" :src="row.mainImage" alt="" style="width: 30px; height: 30px" />
+                        </el-popover>
+                      </template>
+                    </el-table-column>
+                    <el-table-column prop="productName" label="商品名称" align="center" />
+                    <el-table-column prop="reportText" label="报备事由" align="center" />
+                    <el-table-column prop="status" label="审核状态" align="center" width="100">
+                      <template slot-scope="{ row }">
+                        <el-tag v-if="row.status === 1" type="warning" size="small">待审核</el-tag>
+                        <el-tag v-else-if="row.status === 2" type="success" size="small">已审核</el-tag>
+                        <el-tag v-else type="danger" size="small">审核未通过</el-tag>
+                      </template>
+                    </el-table-column>
+                    <el-table-column prop="auditName" label="审核人" align="center" width="100">
+                      <template slot-scope="{ row }">
+                        {{ row.auditName ? row.auditName : '---' }}
+                      </template>
+                    </el-table-column>
+                    <el-table-column prop="auditTime" label="审核时间" align="center">
+                      <template slot-scope="{ row }">
+                        {{ row.auditTime ? row.auditTime : '---' }}
+                      </template>
+                    </el-table-column>
+                    <el-table-column prop="auditText" label="备注" align="center">
+                      <template slot-scope="{ row }">
+                        {{ row.auditText ? row.auditText : '---' }}
+                      </template>
+                    </el-table-column>
+                  </el-table>
+                </el-col>
+              </el-row>
+            </template>
+            <el-row :gutter="24" class="box-row">
+              <el-col :span="6">
+                <b>沟通情况:</b>
+                <el-tag v-if="item.communicationSituation === 1" type="danger" size="small"> 联系不上 </el-tag>
+                <el-tag v-else type="success" size="small">
+                  已沟通
+                  <template v-if="item.communicationMethods === '1'"> (电话) </template>
+                  <template v-if="item.communicationMethods === '2'"> (微信) </template>
+                  <template v-if="item.communicationMethods === '1,2' || item.communicationMethods === '2,1'">
+                    (电话,微信)
+                  </template>
+                </el-tag>
+              </el-col>
+              <el-col v-if="item.customerSource !== null" :span="6">
+                <b>客户来源:</b>
+                <el-tag type="success" size="small">
+                  {{ item.customerSource | sourceActionsFilters }}
+                </el-tag>
+              </el-col>
+              <el-col v-if="item.customerGender !== null" :span="6">
+                <b>客户性别:</b>
+                <el-tag v-if="item.customerGender === 0" type="success" size="small"> 男 </el-tag>
+                <el-tag v-if="item.customerGender === 1" type="success" size="small"> 女 </el-tag>
+              </el-col>
+            </el-row>
+            <el-row :gutter="24" class="box-row">
+              <el-col v-if="item.customerAge" :span="6">
+                <b>客户年龄:</b>
+                <el-tag type="success" size="small"> {{ item.customerAge }} </el-tag>
+              </el-col>
+              <el-col v-if="item.groupAddition !== ''" :span="6">
+                <b>加群情况:</b>
+                <el-tag v-if="item.groupAddition === 0" type="success" size="small"> 已加群 </el-tag>
+                <el-tag v-else type="danger" size="small"> 未加群 </el-tag>
+              </el-col>
+              <el-col v-if="item.consultType" :span="12">
+                <b>咨询类别:</b>
+                <el-tag type="success" size="small"> {{ item.consultType }} </el-tag>
+              </el-col>
+            </el-row>
+            <el-row :gutter="24" class="box-row">
+              <el-col v-if="item.satisfied" :span="6">
+                <b>意向程度:</b>
+                <el-tag type="success" size="small"> {{ (item.satisfied * 1) | intenActionsFilters }} </el-tag>
+              </el-col>
+              <el-col v-if="item.pinceSensitve" :span="6">
+                <b>价格敏感度:</b>
+                <el-tag type="success" size="small"> {{ (item.pinceSensitve * 1) | pinceFilters }} </el-tag>
+              </el-col>
+              <el-col v-if="item.followup" :span="6">
+                <b>跟进状态:</b>
+                <el-tag type="success" size="small"> {{ (item.followup * 1) | followupFilters }} </el-tag>
+              </el-col>
+            </el-row>
+            <el-row v-if="item.remarks" :gutter="24" class="box-row">
+              <el-col :span="24">
+                <b>标签词:</b>
+                <el-tag type="success" size="small"> {{ item.remarks }} </el-tag>
+              </el-col>
+            </el-row>
+            <el-row v-if="item.extra" :gutter="24" class="box-row">
+              <el-col :span="24">
+                <b>额外说明:</b>
+                {{ item.extra }}
+              </el-col>
+            </el-row>
+            <el-row v-if="item.imageList.length > 0" :gutter="24" class="box-row">
+              <el-col :span="24">
+                <b>图片:</b>
+              </el-col>
+              <el-col :span="24">
+                <div
+                  v-for="(image, imageIndex) in item.imageList"
+                  :key="imageIndex"
+                  class="item-image"
+                  style="width: 100px; height: 100px; margin: 5px; float: left"
+                >
+                  <el-popover placement="top-start" title="" width="180" trigger="hover">
+                    <img :src="image" alt="" style="width: 150px; height: 150px" />
+                    <img slot="reference" :src="image" alt="" style="width: 100px; height: 100px" />
+                  </el-popover>
+                </div>
+              </el-col>
+            </el-row>
+            <el-row v-if="item.fileList.length > 0" :gutter="24" class="box-row">
+              <el-col :span="24">
+                <b>文件:</b>
+              </el-col>
+              <el-col :span="24">
+                <div v-for="(file, fileIndex) in item.fileList" :key="fileIndex" class="item-file">
+                  <el-tag type="warning" size="small"> {{ file.fileName }} </el-tag>
+                  <el-button type="primary" size="mini" style="margin: 5px 10px" @click="handlePreview(file)">
+                    预览
+                  </el-button>
+                  <el-button type="primary" size="mini" style="margin: 5px 10px" @click="handleDownload(file)">
+                    下载
+                  </el-button>
+                </div>
+              </el-col>
+            </el-row>
+          </div>
+        </div>
+      </template>
+    </div>
+    <!-- 页码 -->
+    <pagination
+      :total="total"
+      :page-sizes="[20]"
+      :page-size="20"
+      :page.sync="listQuery.pageNum"
+      :limit.sync="listQuery.pageSize"
+      @pagination="remarksList"
+    />
+  </div>
+</template>
+
+<script>
+import { downloadWithUrl } from '@/utils'
+import openWindow from '@/utils/open-window'
+import { getClassName, remarksList } from '@/api/user/consult/consult'
+import pickerOptions from '@/utils/time-picker.js'
+export default {
+  name: 'UnregDetail',
+  filters: {
+    followupFilters(value) {
+      // 跟进状态
+      const map = {
+        1: '跟进中',
+        2: '跟进完成',
+        3: '已放弃'
+      }
+      return map[value]
+    },
+    pinceFilters(value) {
+      // 价格敏感度
+      const map = {
+        1: '敏感',
+        2: '适中',
+        3: '不敏感',
+        4: '不明确'
+      }
+      return map[value]
+    },
+    intenActionsFilters(value) {
+      // 意向
+      const map = {
+        1: '意向强烈',
+        2: '意向一般',
+        3: '意向平淡',
+        4: '随便看看'
+      }
+      return map[value]
+    },
+    sourceActionsFilters(value) {
+      // 客户来源
+      const map = {
+        0: '网站',
+        1: '小程序',
+        2: '公众号',
+        3: '小红书',
+        4: '微博',
+        5: '搜狐',
+        6: '其他'
+      }
+      return map[value]
+    }
+  },
+  data() {
+    return {
+      pickerOptions,
+      time: '',
+      isLoading: true,
+      listQuery: {
+        clubId: '', // 机构Id
+        questionManId: '', // 咨询人Id
+        remarks: '', // 标签词
+        consult: '', // 咨询类别
+        startAddTime: '', // 时间
+        endAddTime: '', // 时间
+        pageNum: 1,
+        pageSize: 20
+      },
+      list: [],
+      total: 0,
+      categoryList: [],
+      queryType: ''
+    }
+  },
+  computed: {},
+  created() {
+    this.queryType = this.$route.query.type
+    if (this.queryType === 1) {
+      this.listQuery.clubId = this.$route.query.clubId
+    } else {
+      this.listQuery.questionManId = this.$route.query.questionManId
+    }
+    this.getClassName()
+    this.getList()
+  },
+  mounted() {},
+  methods: {
+    // 获取行为记录列表
+    getList() {
+      this.listQuery.pageNum = 1
+      if (this.time && this.time.length > 0) {
+        this.listQuery.startAddTime = this.time[0]
+        this.listQuery.endAddTime = this.time[1]
+      } else {
+        this.listQuery.startAddTime = ''
+        this.listQuery.endAddTime = ''
+      }
+      this.remarksList()
+    },
+    // 获取咨询类别选项
+    async getClassName() {
+      try {
+        const res = await getClassName()
+        this.categoryList = res.data
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 未注册用户已同步数据详情
+    async remarksList() {
+      try {
+        this.isLoading = true
+        const res = await remarksList(this.listQuery)
+        this.list = res.data.results
+        this.total = res.data.totalRecord
+        this.isLoading = false
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 预览文件
+    handlePreview(file) {
+      const fileName = file.fileName
+      let url = `https://view.officeapps.live.com/op/view.aspx?src=${encodeURIComponent(file.fileUrl)}`
+      if (fileName.endsWith('.pdf') || fileName.endsWith('.doc')) {
+        url = file.fileUrl
+      }
+      openWindow(url, `${file.fileName}`, 800, 460)
+    },
+    // 下载文件
+    async handleDownload(file) {
+      const params = `fileName=${encodeURIComponent(file.fileName)}&ossName=${encodeURIComponent(file.ossName)}`
+      const url = process.env.VUE_APP_BASE_API + `/user/remarks/remarks/download?${params}`
+      downloadWithUrl(url, file.fileName)
+    }
+  }
+}
+</script>
+
+<style>
+.filter-container {
+  padding: 10px;
+  background: #f7f7f7;
+  margin: 10px 0;
+}
+.span-labels {
+  font-size: 14px;
+  color: #666666;
+  margin-right: 50px;
+}
+.list-loading {
+  width: 100%;
+  height: 300px;
+  padding: 40px;
+  line-height: 220px;
+  box-sizing: border-box;
+  position: relative;
+  text-align: center;
+  background: #ffffff;
+}
+.list-loading .el-icon-loading {
+  font-size: 40px;
+  color: #409eff;
+}
+.list-main-empty {
+  width: 100%;
+  height: 300px;
+  padding: 40px;
+  line-height: 220px;
+  box-sizing: border-box;
+  position: relative;
+  text-align: center;
+}
+.list-main {
+  width: 100%;
+  height: auto;
+  padding: 24px 16px 24px 160px;
+  box-sizing: border-box;
+  position: relative;
+}
+.list-main::before {
+  content: '';
+  height: 100%;
+  border-left: 2px dashed #e1e1e1;
+  position: absolute;
+  left: 120px;
+  top: 0;
+}
+.list-main-item {
+  width: 94%;
+  min-height: 200px;
+  box-sizing: border-box;
+  padding: 24px 35px;
+  background: #e1e1e1;
+  background-size: cover;
+  position: relative;
+  border-radius: 16px;
+}
+.list-main-item::before {
+  content: '';
+  width: 20px;
+  height: 20px;
+  background: #999999;
+  border-radius: 50%;
+  background-size: cover;
+  position: absolute;
+  top: 30px;
+  left: -49px;
+}
+.list-main-item::after {
+  content: '';
+  width: 0;
+  height: 0;
+  border-width: 30px;
+  border-style: solid;
+  border-color: transparent #e1e1e1 transparent transparent;
+  position: absolute;
+  left: -55px;
+  top: 10px;
+}
+.list-main-item.unreg .list-time {
+  display: inline-block;
+  font-size: 20px;
+  color: #333333;
+  position: absolute;
+  top: 7px;
+  left: -164px;
+  font-weight: bold;
+  width: 120px;
+  text-align: center;
+}
+.box-row {
+  margin-bottom: 14px;
+}
+</style>

+ 168 - 0
src/views/user/consult/unreg-list.vue

@@ -0,0 +1,168 @@
+<template>
+  <div class="app-container">
+    <!-- 顶部操作区域 -->
+    <div class="filter-container">
+      <div class="filter-control">
+        <span>咨询人:</span>
+        <el-input
+          v-model="listQuery.questionMan"
+          placeholder="咨询人"
+          clearable
+          @keyup.enter.native="getList"
+          @clear="getList"
+        />
+      </div>
+      <div class="filter-control">
+        <span>所属协销:</span>
+        <el-select v-model="listQuery.serviceProviderId" clearable @change="getList">
+          <el-option value="" label="请选择" />
+          <el-option
+            v-for="item in sellerList"
+            :key="item.serviceProviderId"
+            :label="item.linkMan"
+            :value="item.serviceProviderId"
+          />
+        </el-select>
+      </div>
+      <div class="filter-control">
+        <span>同步至机构:</span>
+        <el-select v-model="listQuery.concat" style="width: 120px" clearable @change="getList">
+          <el-option value="" label="请选择" />
+          <el-option :value="1" label="已同步" />
+          <el-option :value="2" label="未同步" />
+        </el-select>
+      </div>
+      <div class="filter-control">
+        <el-button type="primary" @click="getList"> 查询 </el-button>
+      </div>
+    </div>
+    <!-- 列表 -->
+    <el-table v-loading="isLoading" :data="list" border style="width: 100%" height="600">
+      <el-table-column prop="questionMan" label="咨询人" align="center" width="150" />
+      <el-table-column prop="serviceName" label="所属协销" align="center" width="150">
+        <template slot-scope="{ row }">
+          {{ row.serviceName ? row.serviceName : '---' }}
+        </template>
+      </el-table-column>
+      <el-table-column prop="clubId" label="同步至机构" align="center">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.clubId" type="success" size="small">已同步({{ row.clubName }})</el-tag>
+          <el-tag v-else type="danger" size="small">未同步</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column prop="addTime" label="创建时间" align="center">
+        <template slot-scope="{ row }">
+          {{ row.addTime ? row.addTime : '---' }}
+        </template>
+      </el-table-column>
+      <el-table-column prop="concactTime" label="同步时间" align="center">
+        <template slot-scope="{ row }">
+          {{ row.concactTime ? row.concactTime : '---' }}
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" width="200">
+        <template slot-scope="{ row }">
+          <el-button type="primary" size="mini" style="margin: 2px" @click="handleRecordDetail(row)">
+            查看信息
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 页码 -->
+    <pagination
+      :total="total"
+      :page-sizes="[20]"
+      :page-size="20"
+      :page.sync="listQuery.pageNum"
+      :limit.sync="listQuery.pageSize"
+      @pagination="visitRemarkList"
+    />
+  </div>
+</template>
+
+<script>
+import { visitRemarkList } from '@/api/user/consult/consult'
+import { getServiceList } from '@/api/library/keyword'
+const defaultListQuery = {
+  questionMan: '', // 咨询人
+  serviceProviderId: '', // 协销Id
+  concat: '', //  是否同步 1已同步2未同步
+  pageNum: 1,
+  pageSize: 20
+}
+export default {
+  name: 'RecordList',
+  filters: {},
+  data() {
+    return {
+      isLoading: true,
+      time: '',
+      listQuery: Object.assign({}, defaultListQuery),
+      sellerList: [],
+      list: [],
+      total: 0
+    }
+  },
+  computed: {},
+  created() {
+    this.getServiceList()
+    this.getList()
+  },
+  mounted() {},
+  methods: {
+    // 获取行为记录列表
+    getList() {
+      this.listQuery.pageNum = 1
+      this.list = []
+      if (this.time && this.time.length > 0) {
+        this.listQuery.startTime = this.time[0]
+        this.listQuery.endTime = this.time[1]
+      } else {
+        this.listQuery.startTime = ''
+        this.listQuery.endTime = ''
+      }
+      this.visitRemarkList()
+    },
+
+    // 获取关键词列表
+    async visitRemarkList() {
+      try {
+        this.isLoading = true
+        const res = await visitRemarkList(this.listQuery)
+        this.list = res.data.results
+        this.total = res.data.totalRecord
+        this.isLoading = false
+      } catch (error) {
+        console.log(error)
+      }
+    },
+
+    // 获取协销列表
+    async getServiceList() {
+      try {
+        const res = await getServiceList(this.shopListQuery)
+        this.sellerList = res.data
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 查看信息详情
+    handleRecordDetail(row) {
+      const type = row.clubId ? 1 : 2
+      let query = {}
+      if (row.clubId) {
+        query = { clubId: row.clubId, type: type }
+      } else {
+        query = { questionManId: row.questionManId, type: type }
+      }
+      this.$router.push({
+        path: '/user/consult/unreg-detail',
+        query: query
+      })
+    }
+  }
+}
+</script>
+
+<style></style>

+ 300 - 0
src/views/user/customer/advertis-edit.vue

@@ -0,0 +1,300 @@
+<template>
+  <div class="app-container" style="width: 800px; margin: 0 auto">
+    <el-form ref="bannerForm" :model="form" label-width="100px">
+      <el-form-item label="PC图:" prop="pcImage" :rules="rules.pcImage" style="margin-bottom: 40px">
+        <div class="form-el-upload" style="width: 148px; height: 148px">
+          <el-upload
+            class="avatar-uploader"
+            :action="actionUrl"
+            :headers="getToken"
+            :show-file-list="false"
+            :on-success="handleSuccessPcImage"
+            :before-upload="beforeUpload"
+          >
+            <div v-loading="loadPcImageLoading" class="avatar" style="width: 142px; height: 177px; display: block">
+              <img
+                v-if="form.pcImage"
+                :src="form.pcImage"
+                style="width: 142px; height: 177px; display: block"
+                @error="reloadImage"
+                @load="loadPcImageSucess"
+              />
+              <i
+                v-else
+                class="el-icon-plus avatar-uploader-icon"
+                style="width: 142px; height: 177x; line-height: 177px"
+              ></i>
+            </div>
+          </el-upload>
+          <p class="uploader-tips">注:请尽量上传284*343(px)尺寸的图片。</p>
+        </div>
+      </el-form-item>
+      <el-form-item label="移动端图:" prop="appImage" :rules="rules.appImage" style="margin-bottom: 40px">
+        <div class="form-el-upload" style="width: 142px; height: 177px">
+          <el-upload
+            class="avatar-uploader"
+            :action="actionUrl"
+            :headers="getToken"
+            :show-file-list="false"
+            :on-success="handleSuccessAppImage"
+            :before-upload="beforeUpload"
+          >
+            <div v-loading="loadImgLoading" class="avatar" style="width: 142px; height: 177px; display: block">
+              <img
+                v-if="form.appImage"
+                :src="form.appImage"
+                style="width: 142px; height: 177px; display: block"
+                @error="reloadImage"
+                @load="loadSucess"
+              />
+              <i
+                v-else
+                class="el-icon-plus avatar-uploader-icon"
+                style="width: 142px; height: 177px; line-height: 177px"
+              ></i>
+            </div>
+          </el-upload>
+          <p class="uploader-tips">注:请尽量上传284*343(px)尺寸的图片。</p>
+        </div>
+      </el-form-item>
+      <el-form-item label="供应商" prop="shops" :rules="rules.shops">
+        <template v-if="form.shops && form.shops.length === 0">
+          <el-button type="primary" autofocussize="mini" size="mini" icon="el-icon-plus" @click="handleDialogVisible">
+            选择供应商
+          </el-button>
+          <el-checkbox-group v-show="false" v-model="form.shops" />
+        </template>
+        <template v-else>
+          <el-table :data="form.shops" border width="1000">
+            <el-table-column prop="shopName" label="供应商名称" align="center" />
+            <el-table-column prop="linkMan" label="联系人" align="center" />
+            <el-table-column prop="mobile" label="手机号" align="center" />
+            <el-table-column label="操作" align="center">
+              <el-button type="text" @click="deleteShop"> 删除 </el-button>
+            </el-table-column>
+          </el-table>
+        </template>
+      </el-form-item>
+      <el-form-item label="跳转链接:" prop="jumpLink" :rules="rules.jumpLink">
+        <el-input v-model="form.jumpLink" placeholder="请输入跳转链接" maxlength="200" style="width: 600px" />
+      </el-form-item>
+      <el-form-item label="状态:" prop="status" :rules="rules.status">
+        <el-select v-model="form.status" placeholder="请选择">
+          <el-option label="上架" :value="0" />
+          <el-option label="下架" :value="1" />
+        </el-select>
+      </el-form-item>
+    </el-form>
+    <div class="el-dialog__footer" style="text-align: center">
+      <el-button type="primary" @click="onSubmit('bannerForm')"> 保存 </el-button>
+      <el-button plain @click="backToList"> 返回 </el-button>
+    </div>
+    <!-- 供应商弹框 -->
+    <shop-dialog v-if="shopDialogVisible" ref="shopDialog" @confirm="handleAddShopConfirm" @cancel="handleCancel" />
+  </div>
+</template>
+
+<script>
+import { getShopAdvertisingImageById, saveShopAdvertisingImage } from '@/api/user/customer/customer'
+import ShopDialog from './components/shop-advertis-dialog'
+
+export default {
+  name: 'AdvertisEdit',
+  components: { ShopDialog },
+  data() {
+    const defaultForm = () => {
+      return {
+        id: '',
+        shopId: this.$route.query.shopId,
+        pcImage: '', // PC广告图
+        appImage: '', // 小程序广告图
+        jumpLink: '', // 跳转链接
+        status: 0, // 上下架状态 0 上架 1 下架
+        addTime: '', // 添加时间
+        shops: []
+      }
+    }
+    return {
+      form: defaultForm(),
+      editType: 'add',
+      // 商品列表
+      shopDialogVisible: false,
+      loadImgLoading: false,
+      loadPcImageLoading: false,
+      rules: {
+        pcImage: [{ required: true, message: '请上传PC广告图', trigger: 'blur' }],
+        appImage: [{ required: true, message: '请上传小程序广告图', trigger: 'blur' }],
+        shops: [{ required: true, type: 'array', message: '请添加供应商', trigger: ['change'] }],
+        jumpLink: [{ required: true, message: '请填写跳转链接', trigger: 'blur' }],
+        sort: [{ required: true, message: '排序值不能为空', trigger: 'blur' }],
+        status: [{ required: true, message: '请选择状态', trigger: 'blur' }]
+      }
+    }
+  },
+  computed: {
+    getToken() {
+      return {
+        token: this.$store.getters.token
+      }
+    },
+    actionUrl() {
+      return process.env.VUE_APP_BASE_API + '/formData/MultiPictareaddData'
+    }
+  },
+  created() {
+    this.editType = this.$route.query.type || 'edit'
+    if (this.editType === 'edit') {
+      console.log('edit')
+      this.getShopAdvertisingImageById(this.$route.query.id)
+    }
+  },
+  methods: {
+    async getShopAdvertisingImageById(id) {
+      // 获取菜单详情
+      try {
+        const res = await getShopAdvertisingImageById(id)
+        this.form = { ...this.form, ...res.data }
+      } catch (error) {
+        console.log('error', error)
+      }
+    },
+    // 显示选择商品弹窗
+    handleDialogVisible() {
+      this.shopDialogVisible = true
+    },
+    handleGoodDialogVisible(index) {
+      // 显示选择商品弹窗
+      this.addIndex = index
+      this.dialogGoodVisible = true
+    },
+    deleteShop() {
+      // 清除供应商
+      this.form.shopId = ''
+      this.form.shops = []
+    },
+    handleAddShopConfirm(data) {
+      // 确认选择商品
+      this.form.shopId = data.shopId
+      this.form.shops.push(data)
+      this.handleCancel()
+    },
+    onSubmit(formName) {
+      this.$refs[formName].validate((valid) => {
+        if (valid) {
+          this.$confirm('是否提交数据', '提示', {
+            confirmButtonText: '确定',
+            cancelButtonText: '取消',
+            type: 'warning'
+          }).then(() => {
+            console.log('form', this.form)
+            this.saveShopAdvertisingImage(this.form)
+          })
+        } else {
+          return false
+        }
+      })
+    },
+    async saveShopAdvertisingImage(params) {
+      // 保存
+      await saveShopAdvertisingImage(params)
+      this.$message.success('保存成功')
+      setTimeout(() => {
+        this.$router.push({ path: '/user/customer/advertis-list' })
+      }, 1000)
+    },
+    // 取消选择商品
+    handleCancel() {
+      this.shopDialogVisible = false
+      this.$refs.shopDialog.visible = false
+    },
+    // 上传PC广告图事件
+    handleSuccessPcImage(response, file) {
+      this.loadPcImageLoading = true
+      this.$nextTick(() => {
+        setTimeout(() => {
+          this.form.pcImage = response.data
+        }, 1000 * 2)
+      })
+    },
+    // 上传小程序广告图事件
+    handleSuccessAppImage(response, file) {
+      this.loadImgLoading = true
+      this.$nextTick(() => {
+        setTimeout(() => {
+          this.form.appImage = response.data
+        }, 1000 * 2)
+      })
+    },
+    // 对上传图片的大小、格式进行限制
+    beforeUpload(file) {
+      const isJPG = file.type === 'image/jpeg'
+      const isJPG2 = file.type === 'image/jpg'
+      const isPNG = file.type === 'image/png'
+      const isLt5M = file.size / 1024 / 1024 < 5
+      if (!isJPG && !isJPG2 && !isPNG) {
+        this.$message.error('只支持jpg或png格式图片')
+      }
+      if (!isLt5M) {
+        this.$message.error('请上传5MB以内的图片!')
+      }
+      return (isJPG || isJPG2 || isPNG) && isLt5M
+    },
+    reloadImage() {
+      this.loadImgLoading = true
+      setTimeout(() => {
+        this.temp.classifyImage = this.temp.classifyImage.split('?')[0] + '?r=' + Math.floor(Math.random() * 1000)
+      }, 1000 * 2)
+    },
+    loadPcImageSucess() {
+      this.loadPcImageLoading = false
+    },
+    loadSucess() {
+      this.loadImgLoading = false
+    },
+    backToList() {
+      this.$store.dispatch('tagsView/delView', this.$route).then(() => {
+        this.$nextTick(() => {
+          this.$router.replace({ path: '/user/customer/advertis-list' })
+        })
+      })
+    }
+  }
+}
+</script>
+
+<style>
+.avatar-uploader .el-upload {
+  border: 1px dashed #d9d9d9;
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+  float: left;
+}
+.avatar-uploader .el-upload:hover {
+  border-color: #409eff;
+}
+.avatar-uploader-icon {
+  font-size: 30px;
+  color: #999999;
+}
+.el-form-item__label {
+  text-align: right !important;
+}
+.el-upload__tip {
+  line-height: 20px;
+  color: red;
+  text-align: left;
+  position: absolute;
+  right: -50%;
+  bottom: 0;
+}
+.span_tip {
+  font-size: 12px;
+  color: red;
+  margin-left: 5px;
+}
+.filter-item-temp {
+  width: 100px;
+}
+</style>

+ 262 - 0
src/views/user/customer/advertis-list.vue

@@ -0,0 +1,262 @@
+<template>
+  <div class="app-container">
+    <!-- 顶部操作区域 -->
+    <div class="filter-container">
+      <div class="filter-control">
+        <span>供应商名称:</span>
+        <el-input
+          v-model="listQuery.shopName"
+          placeholder="供应商名称"
+          clearable
+          @keyup.enter.native="getList"
+          @clear="getList"
+        />
+      </div>
+      <div class="filter-control">
+        <span>广告状态:</span>
+        <el-select v-model="listQuery.status" style="width: 120px" clearable @change="getList">
+          <el-option value="" label="请选择" />
+          <el-option :value="0" label="已上架" />
+          <el-option :value="1" label="已下架" />
+        </el-select>
+      </div>
+      <div class="filter-control">
+        <el-button type="primary" @click="getList"> 查询 </el-button>
+        <el-button type="primary" @click="handleoOerate('add')"> 添加 </el-button>
+        <el-button type="primary" @click="getList"> 一键排序 </el-button>
+      </div>
+    </div>
+    <!-- 列表 -->
+    <el-table v-loading="isLoading" :data="list" border style="width: 100%" height="600">
+      <el-table-column label="序号" align="center" width="50">
+        <template slot-scope="scope">
+          {{ scope.$index + 1 }}
+        </template>
+      </el-table-column>
+      <el-table-column prop="pcImage" label="PC广告图" align="center" width="120">
+        <template slot-scope="{ row }">
+          <el-popover placement="top-start" title="" width="120" trigger="hover">
+            <img :src="row.pcImage" alt="" style="width: 100px; height: 100px" />
+            <img slot="reference" :src="row.pcImage" alt="" style="width: 50px; height: 50px" />
+          </el-popover>
+        </template>
+      </el-table-column>
+      <el-table-column prop="appImage" label="小程序广告图" align="center" width="120">
+        <template slot-scope="{ row }">
+          <el-popover placement="top-start" title="" width="120" trigger="hover">
+            <img :src="row.appImage" alt="" style="width: 100px; height: 100px" />
+            <img slot="reference" :src="row.appImage" alt="" style="width: 50px; height: 50px" />
+          </el-popover>
+        </template>
+      </el-table-column>
+      <el-table-column prop="status" label="状态" align="center" width="100">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.status === 0" type="success" size="small">已上架</el-tag>
+          <el-tag v-if="row.status === 1" type="danger" size="small">已下架</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column prop="jumpLink" label="跳转链接" align="center">
+        <template slot-scope="{ row }">
+          <a style="color: #2fa4e7" target="_blank" :href="row.jumpLink">
+            {{ row.jumpLink ? row.jumpLink : '---' }}
+          </a>
+        </template>
+      </el-table-column>
+      <el-table-column prop="shopName" label="供应商名称" align="center" />
+      <el-table-column label="排序" width="60" align="center">
+        <template slot-scope="{ row }">
+          <el-input v-model="row.sort" maxlength="4" minlength="1" @blur="handleOnInputBlur(row)" />
+        </template>
+      </el-table-column>
+      <el-table-column prop="addTime" label="添加时间" align="center">
+        <template slot-scope="{ row }">
+          {{ row.addTime ? row.addTime : '---' }}
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" width="220">
+        <template slot-scope="{ row }">
+          <el-button type="primary" size="mini" style="margin: 2px" @click="handleoOerate('edit', row)">
+            编辑
+          </el-button>
+          <el-button
+            v-if="row.status === 1"
+            type="success"
+            size="mini"
+            style="margin: 2px"
+            @click="handleOffShelf(row)"
+          >
+            上架
+          </el-button>
+          <el-button
+            v-if="row.status === 0"
+            type="primary"
+            size="mini"
+            style="margin: 2px"
+            @click="handleOffShelf(row)"
+          >
+            下架
+          </el-button>
+          <el-button type="danger" size="mini" style="margin: 2px" @click="handleDelete(row)"> 删除 </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 页码 -->
+    <pagination
+      :total="total"
+      :page-sizes="[20]"
+      :page-size="20"
+      :page.sync="listQuery.pageNum"
+      :limit.sync="listQuery.pageSize"
+      @pagination="getShopAdvertisingImage"
+    />
+  </div>
+</template>
+
+<script>
+import {
+  getShopAdvertisingImage,
+  renewShopAdvertisingImageStatus,
+  delShopAdvertisingImage,
+  renewShopAdvertisingImageSort
+} from '@/api/user/customer/customer'
+import pickerOptions from '@/utils/time-picker.js'
+const defaultListQuery = {
+  shopName: '', // 供应商名称
+  status: '', // 上下架状态 0 已上架 1 已下架
+  pageNum: 1,
+  pageSize: 20
+}
+export default {
+  name: 'AdvertisList',
+  filters: {},
+  data() {
+    return {
+      isLoading: true,
+      pickerOptions,
+      time: '',
+      listQuery: Object.assign({}, defaultListQuery),
+      list: [],
+      total: 0
+    }
+  },
+  computed: {},
+  watch: {},
+  created() {
+    this.getList()
+  },
+  mounted() {},
+  methods: {
+    // 获取行为记录列表
+    getList() {
+      this.listQuery.pageNum = 1
+      this.list = []
+      if (this.time && this.time.length > 0) {
+        this.listQuery.startTime = this.time[0]
+        this.listQuery.endTime = this.time[1]
+      } else {
+        this.listQuery.startTime = ''
+        this.listQuery.endTime = ''
+      }
+      this.getShopAdvertisingImage()
+    },
+
+    // 获取关键词列表
+    async getShopAdvertisingImage() {
+      try {
+        this.isLoading = true
+        const res = await getShopAdvertisingImage(this.listQuery)
+        this.list = res.data.results
+        this.total = res.data.totalRecord
+        this.isLoading = false
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 添加广告图
+    handleoOerate(type, row) {
+      if (type === 'add') {
+        this.$router.push({
+          path: '/user/customer/advertis-edit',
+          query: { type: type }
+        })
+      } else {
+        this.$router.push({
+          path: '/user/customer/advertis-edit',
+          query: { id: row.id, type: type }
+        })
+      }
+    },
+    // 操作下架
+    handleOffShelf(row) {
+      let confirmTxt = ''
+      let status = ''
+      if (row.status === 0) {
+        confirmTxt = '确定下架该广告图吗?'
+        status = 1
+      } else {
+        confirmTxt = '确定上架该广告图吗?'
+        status = 0
+      }
+      this.$confirm(confirmTxt)
+        .then((_) => {
+          this.renewShopAdvertisingImageStatus({ id: row.id, status: status })
+        })
+        .catch(() => {
+          this.getList()
+        })
+    },
+    // 上下加供应商广告
+    async renewShopAdvertisingImageStatus(id) {
+      try {
+        await renewShopAdvertisingImageStatus(id)
+        this.$message.success('操作成功')
+        this.getList()
+      } catch (error) {
+        console.log('error', error)
+      }
+    },
+    // 操作删除广告图
+    async handleDelete(row) {
+      try {
+        await this.$confirm('确定删除该广告图吗?', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        })
+        this.delShopAdvertisingImage(row)
+      } catch (error) {
+        this.$message.info('已取消删除操作')
+      }
+    },
+    // 调用删除广告图
+    async delShopAdvertisingImage(row) {
+      try {
+        await delShopAdvertisingImage(row.id)
+        this.$message.success('操作成功')
+        this.getList()
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 广告图排序
+    async handleOnInputBlur(row) {
+      try {
+        await renewShopAdvertisingImageSort({ id: row.id, sort: row.sort })
+        this.getList()
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 机构跳转
+    handleClubHrefLink(row) {
+      return (
+        process.env.VUE_APP_ADMIN_URL +
+        `/a/user/jumpLink/toOldAdmin?type=1&clubId=${row.clubId}&clubName=${row.corporateName}`
+      )
+    }
+  }
+}
+</script>
+
+<style></style>

+ 151 - 0
src/views/user/customer/components/article-dialog.vue

@@ -0,0 +1,151 @@
+<template>
+  <el-dialog title="添加文章" :visible.sync="visible" width="1200px" :close-on-click-modal="false" :show-close="false">
+    <div class="filter-container">
+      <div class="filter-control">
+        <span>ID:</span>
+        <el-input
+          v-model="listQuery.id"
+          placeholder="ID"
+          clearable
+          @input="(e) => (listQuery.id = checkedInput(e))"
+          @keyup.enter.native="getList"
+          @clear="getList"
+        />
+      </div>
+      <div class="filter-control">
+        <span>标题:</span>
+        <el-input
+          v-model="listQuery.title"
+          placeholder="标题"
+          clearable
+          style="width: 160px"
+          @keyup.enter.native="getList"
+          @clear="getList"
+        />
+      </div>
+      <div class="filter-control">
+        <el-button type="primary" @click="getList"> 查询 </el-button>
+      </div>
+    </div>
+    <el-table
+      ref="table"
+      v-loading="isLoading"
+      :data="list"
+      height="400px"
+      border
+      @selection-change="handleSelectionChange"
+    >
+      <el-table-column type="selection" width="55" :selectable="selectable" />
+      <el-table-column label="ID" prop="id" align="center" width="100" />
+      <el-table-column label="引导图" prop="guidanceImage" align="center" width="100">
+        <template slot-scope="{ row }">
+          <el-popover placement="top-start" title="" width="80" trigger="hover">
+            <img :src="row.guidanceImage" alt="" style="width: 100px; height: 100px" />
+            <img slot="reference" :src="row.guidanceImage" alt="" style="width: 50px; height: 50px" />
+          </el-popover>
+        </template>
+      </el-table-column>
+      <el-table-column label="文章标题" prop="title" align="center" />
+      <el-table-column label="发布时间" prop="pubdateString" align="center">
+        <template slot-scope="{ row }">
+          {{ row.pubdateString ? row.pubdateString : '---' }}
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 页码 -->
+    <pagination
+      :total="total"
+      :page-sizes="[20]"
+      :page-size="20"
+      :page.sync="listQuery.pageNum"
+      :limit.sync="listQuery.pageSize"
+      @pagination="getList"
+    />
+    <div slot="footer">
+      <el-button @click="handleCanle"> 取 消 </el-button>
+      <el-button type="primary" :disabled="disabled" @click="handleConfirm"> 确 定 </el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+import { getInfoList } from '@/api/user/customer/customer'
+
+export default {
+  name: 'ArticleDialog',
+  filters: {
+    NumFormat(value) {
+      // 处理金额
+      return Number(value).toFixed(2)
+    }
+  },
+  data() {
+    return {
+      visible: true,
+      listQuery: {
+        pageNum: 1, // 页码
+        pageSize: 20, // 页面数据数
+        id: '', // 文章Id
+        title: '' // 文章标题
+      },
+      list: [],
+      total: 0,
+      acticleRadio: null,
+      isLoading: true
+    }
+  },
+  computed: {
+    disabled() {
+      return this.acticleRadio === null
+    }
+  },
+  created() {
+    this.getList()
+  },
+  methods: {
+    // 获取所有供应商列表
+    async getList() {
+      this.list = []
+      this.listQuery.pageNum = 1
+      this.getInfoList()
+    },
+    // 获取所有供应商列表
+    async getInfoList() {
+      try {
+        const res = await getInfoList(this.listQuery)
+        this.list = res.data.results
+        this.total = res.data.totalRecord
+        this.isLoading = false
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 选择文章
+    handleSelectionChange(row) {
+      this.acticleRadio = row
+      console.log('row', row)
+    },
+    // 确认选择文章
+    handleConfirm() {
+      this.$emit('confirm', this.acticleRadio)
+    },
+    handleCanle() {
+      // 取消弹窗
+      this.$emit('cancel')
+    },
+    // 已选择的禁用勾选框
+    selectable(row) {
+      if (row.flag) {
+        return true
+      } else {
+        return false
+      }
+    },
+    checkedInput(event) {
+      const pattern = /[^0-9.]/g
+      return event.replace(pattern, '')
+    }
+  }
+}
+</script>
+<style lang="scss" scoped></style>

+ 174 - 0
src/views/user/customer/components/article.vue

@@ -0,0 +1,174 @@
+<template>
+  <div class="app-container">
+    <div class="filter-container">
+      <div class="filter-control">
+        <span>统计时间:</span>
+        <el-date-picker
+          v-model="time"
+          type="daterange"
+          unlink-panels
+          value-format="yyyy-MM-dd"
+          range-separator="至"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :picker-options="pickerOptions"
+          @change="getList"
+        />
+      </div>
+      <div class="filter-control">
+        <el-button type="primary" @click="getList"> 查询 </el-button>
+      </div>
+    </div>
+    <el-table v-loading="isLoading" :data="list" border style="width: 100%" height="600">
+      <el-table-column prop="infoId" fixed label="文章ID" align="center" width="80" />
+      <el-table-column prop="guidanceImage" label="引导图" align="center" width="120">
+        <template v-if="row.guidanceImage" slot-scope="{ row }">
+          <el-popover placement="top-start" title="" width="120" trigger="hover">
+            <img :src="row.guidanceImage" alt="" style="width: 100px; height: 100px" />
+            <img slot="reference" :src="row.guidanceImage" alt="" style="width: 50px; height: 50px" />
+          </el-popover>
+        </template>
+      </el-table-column>
+      <el-table-column prop="title" label="文章标题" align="center" />
+      <el-table-column prop="link" label="文章链接" align="center">
+        <template slot-scope="{ row }">
+          <a style="color: #2fa4e7" target="_blank" :href="row.link">
+            {{ row.link ? row.link : '---' }}
+          </a>
+        </template>
+      </el-table-column>
+      <el-table-column prop="onlineStatus" label="文章状态" align="center" width="150">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.onlineStatus === 1" type="warning" size="small">待上线</el-tag>
+          <el-tag v-if="row.onlineStatus === 2" type="success" size="small">已上线</el-tag>
+          <el-tag v-if="row.onlineStatus === 3" type="danger" size="small">已下线</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column prop="accessNumber" label="访问次数" align="center" width="150">
+        <template slot-scope="{ row }">
+          {{ row.accessNumber }}
+        </template>
+      </el-table-column>
+      <el-table-column prop="average" label="平均访问时长" align="center" width="150">
+        <template slot-scope="{ row }">
+          {{ row.average }}
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 页码 -->
+    <pagination
+      :total="total"
+      :page-sizes="[20]"
+      :page-size="20"
+      :page.sync="listQuery.pageNum"
+      :limit.sync="listQuery.pageSize"
+      @pagination="getPageShopInfo"
+    />
+  </div>
+</template>
+
+<script>
+import { getPageShopInfo } from '@/api/user/customer/customer'
+
+export default {
+  name: 'Article',
+  filters: {},
+  data() {
+    const pickerOptions = {
+      shortcuts: [
+        {
+          text: '近1年',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 365)
+            picker.$emit('pick', [start, end])
+          }
+        },
+        {
+          text: '近半年',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 183)
+            picker.$emit('pick', [start, end])
+          }
+        },
+        {
+          text: '近1月',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
+            picker.$emit('pick', [start, end])
+          }
+        },
+        {
+          text: '近1周',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
+            picker.$emit('pick', [start, end])
+          }
+        },
+        {
+          text: '昨天',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24)
+            picker.$emit('pick', [start, end])
+          }
+        }
+      ]
+    }
+    return {
+      pickerOptions,
+      time: '',
+      listQuery: {
+        shopId: this.$route.query.shopId, // 供应商Id
+        startTime: '', // 统计开始时间
+        endTime: '', // 统计结束时间
+        pageNum: 1,
+        pageSize: 20
+      },
+      isLoading: true,
+      list: [],
+      total: 0
+    }
+  },
+  computed: {},
+  created() {
+    this.getList()
+  },
+  methods: {
+    // 商品列表
+    async getList() {
+      this.listQuery.pageNum = 1
+      this.list = []
+      if (this.time && this.time.length > 0) {
+        this.listQuery.startTime = this.time[0]
+        this.listQuery.endTime = this.time[1]
+      } else {
+        this.listQuery.startTime = ''
+        this.listQuery.endTime = ''
+      }
+      this.getPageShopInfo()
+    },
+    // 供应商文章统计列表
+    async getPageShopInfo() {
+      try {
+        this.isLoading = true
+        const res = await getPageShopInfo(this.listQuery)
+        this.list = res.data.results
+        this.total = res.data.totalRecord
+        this.isLoading = false
+      } catch (error) {
+        console.log(error)
+      }
+    }
+  }
+}
+</script>
+<style lang="scss" scoped></style>

+ 188 - 0
src/views/user/customer/components/product.vue

@@ -0,0 +1,188 @@
+<template>
+  <div class="app-container">
+    <div class="filter-container">
+      <div class="filter-control">
+        <span>统计时间:</span>
+        <el-date-picker
+          v-model="time"
+          type="daterange"
+          unlink-panels
+          value-format="yyyy-MM-dd"
+          range-separator="至"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :picker-options="pickerOptions"
+          @change="getList"
+        />
+      </div>
+      <div class="filter-control">
+        <el-button type="primary" @click="getList"> 查询 </el-button>
+      </div>
+    </div>
+    <el-table v-loading="isLoading" :data="list" border style="width: 100%" height="600">
+      <el-table-column prop="productId" label="商品ID" align="center" width="80" />
+      <el-table-column prop="mainImage" label="商品图片" align="center" width="120">
+        <template v-if="row.mainImage" slot-scope="{ row }">
+          <el-popover placement="top-start" title="" width="120" trigger="hover">
+            <img :src="row.mainImage" alt="" style="width: 100px; height: 100px" />
+            <img slot="reference" :src="row.mainImage" alt="" style="width: 50px; height: 50px" />
+          </el-popover>
+        </template>
+      </el-table-column>
+      <el-table-column prop="productName" label="商品名称" align="center" />
+      <el-table-column prop="validFlag" label="商品状态" align="center" width="120">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.validFlag === 1" type="warning" size="small">待审核</el-tag>
+          <el-tag v-else-if="row.validFlag === 2" type="success" size="small">已上架</el-tag>
+          <el-tag v-else type="danger" size="small">{{ row.validFlag | validFlagFilters }}</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column prop="link" label="链接" align="center">
+        <template slot-scope="{ row }">
+          <a style="color: #2fa4e7" target="_blank" :href="row.link">
+            {{ row.link ? row.link : '---' }}
+          </a>
+        </template>
+      </el-table-column>
+      <el-table-column prop="phoneNumber" label="访问次数" align="center" width="150">
+        <template slot-scope="{ row }">
+          {{ row.accessNumber }}
+        </template>
+      </el-table-column>
+      <el-table-column prop="average" label="平均访问时长" align="center" width="150">
+        <template slot-scope="{ row }">
+          {{ row.average }}
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 页码 -->
+    <pagination
+      :total="total"
+      :page-sizes="[20]"
+      :page-size="20"
+      :page.sync="listQuery.pageNum"
+      :limit.sync="listQuery.pageSize"
+      @pagination="getPageShopProduct"
+    />
+  </div>
+</template>
+
+<script>
+import { getPageShopProduct } from '@/api/user/customer/customer'
+
+export default {
+  name: 'Product',
+  filters: {
+    validFlagFilters(value) {
+      // 客户来源
+      const map = {
+        0: '删除',
+        1: '待审核',
+        2: '已上架',
+        3: '已下架',
+        8: '审核未通过',
+        9: '已隐身',
+        10: '已冻结'
+      }
+      return map[value]
+    }
+  },
+  data() {
+    const pickerOptions = {
+      shortcuts: [
+        {
+          text: '近1年',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 365)
+            picker.$emit('pick', [start, end])
+          }
+        },
+        {
+          text: '近半年',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 183)
+            picker.$emit('pick', [start, end])
+          }
+        },
+        {
+          text: '近1月',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
+            picker.$emit('pick', [start, end])
+          }
+        },
+        {
+          text: '近1周',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
+            picker.$emit('pick', [start, end])
+          }
+        },
+        {
+          text: '昨天',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24)
+            picker.$emit('pick', [start, end])
+          }
+        }
+      ]
+    }
+    return {
+      pickerOptions,
+      time: '',
+      listQuery: {
+        shopId: this.$route.query.shopId, // 供应商Id
+        startTime: '', // 统计开始时间
+        endTime: '', // 统计结束时间
+        pageNum: 1,
+        pageSize: 20
+      },
+      isLoading: true,
+      list: [],
+      total: 0
+    }
+  },
+  computed: {},
+  created() {
+    this.getList()
+  },
+  methods: {
+    // 商品列表
+    async getList() {
+      this.listQuery.pageNum = 1
+      this.list = []
+      if (this.time && this.time.length > 0) {
+        this.listQuery.startTime = this.time[0]
+        this.listQuery.endTime = this.time[1]
+      } else {
+        this.listQuery.startTime = ''
+        this.listQuery.endTime = ''
+      }
+      this.getPageShopProduct()
+    },
+    // 供应商商品统计列表
+    async getPageShopProduct() {
+      try {
+        this.isLoading = true
+        const res = await getPageShopProduct(this.listQuery)
+        this.list = res.data.results
+        this.total = res.data.totalRecord
+        this.isLoading = false
+      } catch (error) {
+        console.log(error)
+      }
+    }
+  }
+}
+</script>
+<style lang="scss" scoped></style>

+ 124 - 0
src/views/user/customer/components/search-dialog.vue

@@ -0,0 +1,124 @@
+<template>
+  <el-dialog
+    title="添加搜索词"
+    :visible.sync="visible"
+    width="1200px"
+    :close-on-click-modal="false"
+    :show-close="false"
+  >
+    <div class="filter-container">
+      <div class="filter-control">
+        <span>搜索词:</span>
+        <el-input
+          v-model="listQuery.keyword"
+          placeholder="搜索词"
+          clearable
+          style="width: 160px"
+          @keyup.enter.native="getList"
+          @clear="getList"
+        />
+      </div>
+      <div class="filter-control">
+        <el-button type="primary" @click="getList"> 查询 </el-button>
+      </div>
+    </div>
+    <el-table
+      ref="table"
+      v-loading="isLoading"
+      :data="list"
+      height="400px"
+      border
+      @selection-change="handleSelectionChange"
+    >
+      <el-table-column type="selection" width="55" :selectable="selectable" />
+      <el-table-column label="关键词" prop="keyword" align="center" />
+      <el-table-column label="搜索次数" prop="frequency" align="center" width="150" />
+      <el-table-column label="最近搜索时间" prop="searchTime" align="center" width="200" />
+    </el-table>
+    <!-- 页码 -->
+    <pagination
+      :total="total"
+      :page-sizes="[20]"
+      :page-size="20"
+      :page.sync="listQuery.pageNum"
+      :limit.sync="listQuery.pageSize"
+      @pagination="getSearchFrequencyList"
+    />
+    <div slot="footer">
+      <el-button @click="handleCanle"> 取 消 </el-button>
+      <el-button type="primary" :disabled="disabled" @click="handleConfirm"> 确 定 </el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+import { getSearchFrequencyList } from '@/api/user/customer/customer'
+
+export default {
+  name: 'SearchDialog',
+  filters: {},
+  data() {
+    return {
+      visible: true,
+      listQuery: {
+        pageNum: 1, // 页码
+        pageSize: 20, // 页面数据数
+        keyword: '' // 关键词
+      },
+      list: [],
+      total: 0,
+      productRadio: null,
+      isLoading: true
+    }
+  },
+  computed: {
+    disabled() {
+      return this.productRadio === null
+    }
+  },
+  created() {
+    this.getList()
+  },
+  methods: {
+    // 获取所有供应商列表
+    async getList() {
+      this.list = []
+      this.listQuery.pageNum = 1
+      this.getSearchFrequencyList()
+    },
+    // 获取所有供应商列表
+    async getSearchFrequencyList() {
+      try {
+        const res = await getSearchFrequencyList(this.listQuery)
+        this.list = res.data.results
+        this.total = res.data.totalRecord
+        this.isLoading = false
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 选择关键词
+    handleSelectionChange(row) {
+      this.productRadio = row
+      console.log('row', row)
+    },
+    // 确认选择关键词
+    handleConfirm() {
+      this.$emit('confirm', this.productRadio)
+    },
+    // 取消选择
+    handleCanle() {
+      this.$emit('cancel')
+    },
+    // 已选择的禁用勾选框
+    selectable(row) {
+      if (row.flag) {
+        return true
+      } else {
+        return false
+      }
+    }
+  }
+}
+</script>
+<style lang="scss" scoped></style>

+ 158 - 0
src/views/user/customer/components/search.vue

@@ -0,0 +1,158 @@
+<template>
+  <div class="app-container">
+    <div class="filter-container">
+      <div class="filter-control">
+        <span>统计时间:</span>
+        <el-date-picker
+          v-model="time"
+          type="daterange"
+          unlink-panels
+          value-format="yyyy-MM-dd"
+          range-separator="至"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :picker-options="pickerOptions"
+          @change="getList"
+        />
+      </div>
+      <div class="filter-control">
+        <el-button type="primary" @click="getList"> 查询 </el-button>
+      </div>
+    </div>
+    <el-table v-loading="isLoading" :data="list" border style="width: 100%" height="600">
+      <el-table-column prop="keyword" fixed label="搜索词" align="center" width="300" />
+      <el-table-column prop="link" label="搜索链接" align="center">
+        <template v-if="row.link" slot-scope="{ row }">
+          <a style="color: #2fa4e7" target="_blank" :href="row.link">
+            {{ row.link ? row.link : '---' }}
+          </a>
+        </template>
+      </el-table-column>
+      <el-table-column prop="accessNumber" label="访问次数" align="center" width="200">
+        <template slot-scope="{ row }">
+          {{ row.accessNumber }}
+        </template>
+      </el-table-column>
+      <el-table-column prop="average" label="平均访问时长" align="center" width="200">
+        <template slot-scope="{ row }">
+          {{ row.average }}
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 页码 -->
+    <pagination
+      :total="total"
+      :page-sizes="[20]"
+      :page-size="20"
+      :page.sync="listQuery.pageNum"
+      :limit.sync="listQuery.pageSize"
+      @pagination="getPageShopKeyword"
+    />
+  </div>
+</template>
+
+<script>
+import { getPageShopKeyword } from '@/api/user/customer/customer'
+
+export default {
+  name: 'Search',
+  filters: {},
+  data() {
+    const pickerOptions = {
+      shortcuts: [
+        {
+          text: '近1年',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 365)
+            picker.$emit('pick', [start, end])
+          }
+        },
+        {
+          text: '近半年',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 183)
+            picker.$emit('pick', [start, end])
+          }
+        },
+        {
+          text: '近1月',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
+            picker.$emit('pick', [start, end])
+          }
+        },
+        {
+          text: '近1周',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
+            picker.$emit('pick', [start, end])
+          }
+        },
+        {
+          text: '昨天',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24)
+            picker.$emit('pick', [start, end])
+          }
+        }
+      ]
+    }
+    return {
+      pickerOptions,
+      time: '',
+      listQuery: {
+        shopId: this.$route.query.shopId, // 供应商Id
+        startTime: '', // 统计开始时间
+        endTime: '', // 统计结束时间
+        pageNum: 1,
+        pageSize: 20
+      },
+      isLoading: true,
+      list: [],
+      total: 0
+    }
+  },
+  computed: {},
+  created() {
+    this.getList()
+  },
+  methods: {
+    // 商品列表
+    async getList() {
+      this.listQuery.pageNum = 1
+      this.list = []
+      if (this.time && this.time.length > 0) {
+        this.listQuery.startTime = this.time[0]
+        this.listQuery.endTime = this.time[1]
+      } else {
+        this.listQuery.startTime = ''
+        this.listQuery.endTime = ''
+      }
+      this.getPageShopKeyword()
+    },
+    // 供应商搜索词统计列表
+    async getPageShopKeyword() {
+      try {
+        this.isLoading = true
+        const res = await getPageShopKeyword(this.listQuery)
+        this.list = res.data.results
+        this.total = res.data.totalRecord
+        this.isLoading = false
+      } catch (error) {
+        console.log(error)
+      }
+    }
+  }
+}
+</script>
+<style lang="scss" scoped></style>

+ 139 - 0
src/views/user/customer/components/shop-advertis-dialog.vue

@@ -0,0 +1,139 @@
+<template>
+  <el-dialog
+    title="添加供应商"
+    :visible.sync="visible"
+    width="1200px"
+    :close-on-click-modal="false"
+    :show-close="false"
+  >
+    <div class="filter-container">
+      <div class="filter-control">
+        <span>供应商名称:</span>
+        <el-input
+          v-model="listQuery.shopName"
+          placeholder="供应商名称"
+          clearable
+          style="width: 160px"
+          @keyup.enter.native="getList"
+          @clear="getList"
+        />
+      </div>
+      <div class="filter-control">
+        <el-button type="primary" @click="getList"> 查询 </el-button>
+      </div>
+    </div>
+    <el-table ref="table" v-loading="isLoading" :data="list" height="380px" border @select="handleSelect">
+      <el-table-column type="selection" width="55" :selectable="selectable" />
+      <el-table-column label="供应商名称" prop="shopName" align="center" />
+      <el-table-column label="联系人" prop="linkMan" align="center" />
+      <el-table-column label="手机号" prop="mobile" align="center">
+        <template slot-scope="{ row }">
+          {{ row.mobile ? row.mobile : '---' }}
+        </template>
+      </el-table-column>
+      <el-table-column label="供应商状态" prop="shopStatus" align="center">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.shopStatus === 90" type="success" size="small">已上线</el-tag>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 页码 -->
+    <pagination
+      :total="total"
+      :page-sizes="[100, 200]"
+      :page-size="100"
+      :page.sync="listQuery.pageNum"
+      :limit.sync="listQuery.pageSize"
+      @pagination="getCustomerShopList"
+    />
+    <div slot="footer">
+      <el-button @click="handleCanle"> 取 消 </el-button>
+      <el-button type="primary" :disabled="disabled" @click="handleConfirm"> 确 定 </el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+import { getCustomerShopList } from '@/api/user/customer/customer'
+
+export default {
+  name: 'ShopAdvertisDialog',
+  filters: {
+    NumFormat(value) {
+      // 处理金额
+      return Number(value).toFixed(2)
+    }
+  },
+  data() {
+    return {
+      visible: true,
+      listQuery: {
+        pageNum: 1, // 页码
+        pageSize: 100, // 页面数据数
+        shopName: '' // 供应商公司名称
+      },
+      list: [],
+      total: 0,
+      shopsRadio: null,
+      isLoading: true
+    }
+  },
+  computed: {
+    disabled() {
+      return this.shopsRadio === null
+    }
+  },
+  created() {
+    this.getList()
+  },
+  methods: {
+    // 获取所有供应商列表
+    async getList() {
+      this.list = []
+      this.listQuery.pageNum = 1
+      this.getCustomerShopList()
+    },
+    // 获取所有供应商列表
+    async getCustomerShopList() {
+      try {
+        const res = await getCustomerShopList(this.listQuery)
+        this.list = res.data.results
+        this.total = res.data.totalRecord
+        this.isLoading = false
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 选择供应商
+    handleSelect(selection, row) {
+      this.$refs.table.clearSelection()
+      this.$refs.table.toggleRowSelection(row)
+      this.shopsRadio = row
+      console.log('row', row)
+    },
+    // 确认选择供应商
+    handleConfirm() {
+      this.$emit('confirm', this.shopsRadio)
+    },
+    handleCanle() {
+      // 取消弹窗
+      this.$emit('cancel')
+    },
+    // 已选择的禁用勾选框
+    selectable(row) {
+      if (row.status === 0) {
+        return true
+      } else {
+        return false
+      }
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+::v-deep {
+  thead .el-checkbox {
+    display: none !important;
+  }
+}
+</style>

+ 150 - 0
src/views/user/customer/components/shop-dialog.vue

@@ -0,0 +1,150 @@
+<template>
+  <el-dialog
+    title="添加供应商"
+    :visible.sync="visible"
+    width="1200px"
+    :close-on-click-modal="false"
+    :show-close="false"
+  >
+    <div class="filter-container">
+      <div class="filter-control">
+        <span>供应商名称:</span>
+        <el-input
+          v-model="listQuery.shopName"
+          placeholder="供应商名称"
+          clearable
+          style="width: 160px"
+          @keyup.enter.native="getList"
+          @clear="getList"
+        />
+      </div>
+      <div class="filter-control">
+        <el-button type="primary" @click="getList"> 查询 </el-button>
+      </div>
+    </div>
+    <el-table
+      ref="table"
+      v-loading="isLoading"
+      :data="list"
+      height="400px"
+      border
+      @selection-change="handleSelectionChange"
+    >
+      <el-table-column type="selection" width="55" :selectable="selectable" />
+      <el-table-column label="供应商名称" prop="name" align="center" />
+      <el-table-column label="联系人" prop="linkMan" align="center" />
+      <el-table-column label="手机号" prop="contractMobile" align="center">
+        <template slot-scope="{ row }">
+          {{ row.contractMobile ? row.contractMobile : '---' }}
+        </template>
+      </el-table-column>
+      <el-table-column label="供应商状态" prop="status" align="center">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.status === 90" type="success" size="small">已上线</el-tag>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 页码 -->
+    <pagination
+      :total="total"
+      :page-sizes="[100, 200]"
+      :page-size="100"
+      :page.sync="listQuery.pageNum"
+      :limit.sync="listQuery.pageSize"
+      @pagination="getShopList"
+    />
+    <div slot="footer">
+      <el-button @click="handleCanle"> 取 消 </el-button>
+      <el-button type="primary" :disabled="disabled" @click="handleConfirm"> 确 定 </el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+import { getShopList } from '@/api/user/customer/customer'
+
+export default {
+  name: 'ShopDialog',
+  filters: {
+    NumFormat(value) {
+      // 处理金额
+      return Number(value).toFixed(2)
+    }
+  },
+  data() {
+    return {
+      visible: true,
+      listQuery: {
+        pageNum: 1, // 页码
+        pageSize: 100, // 页面数据数
+        shopName: '' // 供应商公司名称
+      },
+      list: [],
+      total: 0,
+      shopsRadio: null,
+      isLoading: true
+    }
+  },
+  computed: {
+    disabled() {
+      return this.shopsRadio === null
+    }
+  },
+  created() {
+    this.getList()
+  },
+  methods: {
+    // 获取所有供应商列表
+    async getList() {
+      this.list = []
+      this.listQuery.pageNum = 1
+      this.getShopList()
+    },
+    // 获取所有供应商列表
+    async getShopList() {
+      try {
+        const res = await getShopList(this.listQuery)
+        this.list = res.data.results
+        this.total = res.data.totalRecord
+        this.isLoading = false
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 选择供应商
+    handleSelectionChange(row) {
+      this.shopsRadio = row
+      console.log('row', row)
+    },
+    // 确认选择供应商
+    handleConfirm() {
+      this.$emit('confirm', this.shopsRadio)
+    },
+    handleCanle() {
+      // 取消弹窗
+      this.$emit('cancel')
+    },
+    // 已选择的禁用勾选框
+    selectable(row) {
+      if (row.flag) {
+        return true
+      } else {
+        return false
+      }
+    },
+    checkedInput(event, type) {
+      let pattern = ''
+      switch (type) {
+        case 1:
+          pattern = /[^\d]/g
+          break
+        case 2:
+          pattern = /[^u4E00-u9FA5|d|a-zA-Z|rns,.?!,。?!…—&$=()-+/*{}[]]|s/g
+          break
+      }
+      return event.replace(pattern, '')
+    }
+  }
+}
+</script>
+<style lang="scss" scoped></style>

+ 162 - 0
src/views/user/customer/components/shop.vue

@@ -0,0 +1,162 @@
+<template>
+  <div class="app-container">
+    <div class="filter-container">
+      <div class="filter-control">
+        <span>统计时间:</span>
+        <el-date-picker
+          v-model="time"
+          type="daterange"
+          unlink-panels
+          value-format="yyyy-MM-dd"
+          range-separator="至"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :picker-options="pickerOptions"
+          @change="getList"
+        />
+      </div>
+      <div class="filter-control">
+        <el-button type="primary" @click="getList"> 查询 </el-button>
+      </div>
+    </div>
+    <el-table v-loading="isLoading" :data="list" border style="width: 100%" height="600">
+      <el-table-column prop="shopName" fixed label="供应商名称" align="center" />
+      <el-table-column prop="shopLink" label="主页链接" align="center">
+        <template slot-scope="{ row }">
+          <a style="color: #2fa4e7" target="_blank" :href="row.shopLink">
+            {{ row.shopLink ? row.shopLink : '---' }}
+          </a>
+        </template>
+      </el-table-column>
+      <el-table-column prop="accessNumber" label="访问次数" align="center" width="150">
+        <template slot-scope="{ row }">
+          {{ row.accessNumber }}
+        </template>
+      </el-table-column>
+      <el-table-column prop="average" label="平均访问时长" align="center" width="150">
+        <template slot-scope="{ row }">
+          {{ row.average }}
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 页码 -->
+    <pagination
+      :total="total"
+      :page-sizes="[20]"
+      :page-size="20"
+      :page.sync="listQuery.pageNum"
+      :limit.sync="listQuery.pageSize"
+      @pagination="getPageShop"
+    />
+  </div>
+</template>
+
+<script>
+import { getPageShop } from '@/api/user/customer/customer'
+
+export default {
+  name: 'Shop',
+  filters: {},
+  data() {
+    const pickerOptions = {
+      shortcuts: [
+        {
+          text: '近1年',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 365)
+            picker.$emit('pick', [start, end])
+          }
+        },
+        {
+          text: '近半年',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 183)
+            picker.$emit('pick', [start, end])
+          }
+        },
+        {
+          text: '近1月',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
+            picker.$emit('pick', [start, end])
+          }
+        },
+        {
+          text: '近1周',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
+            picker.$emit('pick', [start, end])
+          }
+        },
+        {
+          text: '昨天',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24)
+            picker.$emit('pick', [start, end])
+          }
+        }
+      ]
+    }
+    return {
+      pickerOptions,
+      time: '',
+      listQuery: {
+        shopId: this.$route.query.shopId, // 供应商Id
+        startTime: '', // 统计开始时间
+        endTime: '', // 统计结束时间
+        pageNum: 1,
+        pageSize: 20
+      },
+      isLoading: true,
+      list: [],
+      total: 0
+    }
+  },
+  computed: {},
+  created() {
+    this.getList()
+  },
+  methods: {
+    // 商品列表
+    async getList() {
+      this.list = []
+      this.listQuery.pageNum = 1
+      if (this.time && this.time.length > 0) {
+        this.listQuery.startTime = this.time[0]
+        this.listQuery.endTime = this.time[1]
+      } else {
+        this.listQuery.startTime = ''
+        this.listQuery.endTime = ''
+      }
+      this.getPageShop()
+    },
+    // 供应商主页统计列表
+    async getPageShop() {
+      try {
+        this.isLoading = true
+        const res = await getPageShop(this.listQuery)
+        this.list = res.data.results
+        this.total = res.data.totalRecord
+        this.isLoading = false
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 跳转
+    handleOpenHrefLink(url) {
+      window.open(url, '_blank')
+    }
+  }
+}
+</script>
+<style lang="scss" scoped></style>

+ 248 - 0
src/views/user/customer/customer-article-list.vue

@@ -0,0 +1,248 @@
+<template>
+  <div class="app-container">
+    <!-- 顶部操作区域 -->
+    <div class="filter-container">
+      <div class="filter-control">
+        <span>ID:</span>
+        <el-input
+          v-model="listQuery.infoId"
+          placeholder="ID"
+          clearable
+          @input="(e) => (listQuery.infoId = checkedInput(e))"
+          @keyup.enter.native="getList"
+          @clear="getList"
+        />
+      </div>
+      <div class="filter-control">
+        <span>文章标题:</span>
+        <el-input
+          v-model="listQuery.title"
+          placeholder="文章标题"
+          clearable
+          @keyup.enter.native="getList"
+          @clear="getList"
+        />
+      </div>
+      <div class="filter-control">
+        <span>统计状态:</span>
+        <el-select v-model="listQuery.status" style="width: 120px" clearable @change="getList">
+          <el-option value="" label="请选择" />
+          <el-option :value="0" label="统计中" />
+          <el-option :value="1" label="暂停统计" />
+        </el-select>
+      </div>
+      <div class="filter-control">
+        <el-button type="primary" @click="getList"> 查询 </el-button>
+        <el-button type="primary" @click="articleDialogVisible = true"> 添加文章 </el-button>
+      </div>
+    </div>
+    <!-- 列表 -->
+    <el-table v-loading="isLoading" :data="list" border style="width: 100%" height="600">
+      <el-table-column prop="infoId" fixed label="ID" align="center" width="80" />
+      <el-table-column label="引导图" prop="guidanceImage" align="center" width="100">
+        <template slot-scope="{ row }">
+          <el-popover placement="top-start" title="" width="80" trigger="hover">
+            <img :src="row.guidanceImage" alt="" style="width: 100px; height: 100px" />
+            <img slot="reference" :src="row.guidanceImage" alt="" style="width: 50px; height: 50px" />
+          </el-popover>
+        </template>
+      </el-table-column>
+      <el-table-column prop="title" label="文章标题" align="center" />
+      <el-table-column prop="status" label="统计状态" align="center" width="100">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.status === 0" type="success" size="small">统计中</el-tag>
+          <el-tag v-if="row.status === 1" type="danger" size="small">暂停统计</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column prop="pubdateString" label="发布时间" align="center" width="200">
+        <template slot-scope="{ row }">
+          {{ row.pubdateString ? row.pubdateString : '---' }}
+        </template>
+      </el-table-column>
+      <el-table-column prop="addTime" label="添加时间" align="center" width="200">
+        <template slot-scope="{ row }">
+          {{ row.addTime ? row.addTime : '---' }}
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" width="220">
+        <template slot-scope="{ row }">
+          <el-button type="primary" size="mini" style="margin: 2px" @click="handleSitting(row)">
+            设置统计状态
+          </el-button>
+          <el-button type="danger" size="mini" style="margin: 2px" @click="handleDelete(row)"> 删除 </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 页码 -->
+    <pagination
+      :total="total"
+      :page-sizes="[20]"
+      :page-size="20"
+      :page.sync="listQuery.pageNum"
+      :limit.sync="listQuery.pageSize"
+      @pagination="getShopInfoList"
+    />
+    <!--  选择文章弹窗 -->
+    <article-dialog
+      v-if="articleDialogVisible"
+      ref="articleDialog"
+      @confirm="handleArticleConfirm"
+      @cancel="handleCancel"
+    />
+    <!-- 设置统计状态 -->
+    <el-dialog title="设置统计状态" :visible.sync="dialogFormVisible" width="500px">
+      <el-form ref="dataForm" :model="renewCustome" label-position="right">
+        <el-form-item prop="status">
+          <el-radio v-model="renewCustome.status" :label="0">统计中</el-radio>
+          <el-radio v-model="renewCustome.status" :label="1">暂停统计</el-radio>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="dialogFormVisible = false">取消</el-button>
+        <el-button type="primary" @click="handleConfirm">确定</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { getShopInfoList, saveShopInfo, renewShopInfo, delShopInfo } from '@/api/user/customer/customer'
+import ArticleDialog from './components/article-dialog'
+export default {
+  name: 'CustomerArticleList',
+  components: {
+    ArticleDialog
+  },
+  filters: {},
+  data() {
+    return {
+      isLoading: true,
+      listQuery: {
+        shopId: this.$route.query.shopId,
+        infoId: '',
+        title: '',
+        status: '',
+        pageNum: 1,
+        pageSize: 20
+      },
+      list: [],
+      total: 0,
+      articleDialogVisible: false,
+      dialogFormVisible: false,
+      renewCustome: {
+        id: '',
+        status: ''
+      },
+      rules: {
+        status: [{ required: true, message: '请设置统计状态', trigger: 'blur' }]
+      }
+    }
+  },
+  computed: {},
+  created() {
+    this.getList()
+  },
+  mounted() {},
+  methods: {
+    // 获取供应商相关文章列表
+    async getList() {
+      this.list = []
+      this.listQuery.pageNum = 1
+      this.getShopInfoList()
+    },
+    // 获取供应商相关文章列表
+    async getShopInfoList() {
+      try {
+        this.isLoading = true
+        const res = await getShopInfoList(this.listQuery)
+        this.list = res.data.results
+        this.total = res.data.totalRecord
+        this.isLoading = false
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 确认选择供文章
+    handleArticleConfirm(data) {
+      console.log('data', data)
+      const infoIds = []
+      data.forEach((ele) => {
+        infoIds.push(ele.id)
+      })
+      this.saveShopInfo({ shopId: this.listQuery.shopId, infoIds: infoIds.join(',') })
+    },
+    // 保存添加供应商文章
+    async saveShopInfo(params) {
+      try {
+        await saveShopInfo(params)
+        this.articleDialogVisible = false
+        this.$message.success('操作成功')
+        this.getList()
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    handleCancel() {
+      // 取消选择供应商
+      this.articleDialogVisible = false
+      this.$refs.articleDialog.visible = false
+    },
+    // 设置统计状态
+    handleSitting(row) {
+      this.renewCustome.id = row.id
+      this.renewCustome.status = row.status
+      this.dialogFormVisible = true
+    },
+    // 确认设置统计状态
+    handleConfirm() {
+      this.$refs['dataForm'].validate((valid) => {
+        if (valid) {
+          this.renewShopInfo(this.renewCustome)
+        } else {
+          return false
+        }
+      })
+    },
+    // 调用统计状态API
+    async renewShopInfo(params) {
+      try {
+        await renewShopInfo(params)
+        this.dialogFormVisible = false
+        this.$message.success('操作成功')
+        this.getList()
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 操作删除文章
+    async handleDelete(row) {
+      try {
+        await this.$confirm('确定删除该文章吗?', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        })
+        this.delShopInfo(row)
+      } catch (error) {
+        this.$message.info('已取消删除操作')
+      }
+    },
+    // 调用删除文章
+    async delShopInfo(row) {
+      try {
+        await delShopInfo(row.id)
+        this.$message.success('操作成功')
+        this.getList()
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    checkedInput(event) {
+      const pattern = /[^0-9.]/g
+      return event.replace(pattern, '')
+    }
+  }
+}
+</script>
+
+<style></style>

+ 58 - 0
src/views/user/customer/customer-page-list.vue

@@ -0,0 +1,58 @@
+<template>
+  <div class="app-container">
+    <!-- 顶部操作区域 -->
+    <el-tabs v-model="activeName" type="border-card" @tab-click="handleClick">
+      <el-tab-pane label="供应商主页" name="first" />
+      <el-tab-pane label="商品详情" name="second" />
+      <el-tab-pane label="文章详情" name="third" />
+      <el-tab-pane label="搜索列表" name="fourth" />
+      <!-- 列表 -->
+      <template v-if="activeName === 'first'">
+        <shop />
+      </template>
+      <template v-if="activeName === 'second'">
+        <product />
+      </template>
+      <template v-if="activeName === 'third'">
+        <Article />
+      </template>
+      <template v-if="activeName === 'fourth'">
+        <search />
+      </template>
+    </el-tabs>
+  </div>
+</template>
+
+<script>
+import Shop from './components/shop'
+import Product from './components/product'
+import Article from './components/article'
+import Search from './components/search'
+export default {
+  name: 'CustomerPageList',
+  components: {
+    Shop,
+    Product,
+    Article,
+    Search
+  },
+  filters: {},
+  data() {
+    return {
+      activeName: 'first',
+      isLoading: true,
+      list: [],
+      total: 0
+    }
+  },
+  computed: {},
+  created() {},
+  mounted() {},
+  methods: {
+    // tab切换
+    handleClick(tab, event) {}
+  }
+}
+</script>
+
+<style></style>

+ 207 - 0
src/views/user/customer/customer-popup-edit.vue

@@ -0,0 +1,207 @@
+<template>
+  <div class="app-container" style="width: 800px; margin: 0 auto">
+    <el-form ref="bannerForm" :model="form" label-width="100px">
+      <el-form-item label="弹窗图片:" prop="image" :rules="rules.image" style="margin-bottom: 40px">
+        <div class="form-el-upload" style="width: 148px; height: 148px">
+          <el-upload
+            class="avatar-uploader"
+            :action="actionUrl"
+            :headers="getToken"
+            :show-file-list="false"
+            :on-success="handleSuccess"
+            :before-upload="beforeUpload"
+          >
+            <div v-loading="loadImgLoading" class="avatar" style="width: 148px; height: 148px; display: block">
+              <img
+                v-if="form.image"
+                :src="form.image"
+                style="width: 148px; height: 148px; display: block"
+                @error="reloadImage"
+                @load="loadSucess"
+              />
+              <i
+                v-else
+                class="el-icon-plus avatar-uploader-icon"
+                style="width: 148px; height: 148px; line-height: 148px"
+              ></i>
+            </div>
+          </el-upload>
+          <p class="uploader-tips">注:请尽量上传260*260(px)尺寸的图片。</p>
+        </div>
+      </el-form-item>
+      <el-form-item label="引导语1:" prop="guidingOne" :rules="rules.guidingOne">
+        <el-input
+          v-model="form.guidingOne"
+          placeholder="请输入第一句引导语,不多余15个汉字"
+          maxlength="15"
+          style="width: 350px"
+        />
+      </el-form-item>
+      <el-form-item label="引导语2:" prop="guidingTwo" :rules="rules.guidingTwo">
+        <el-input
+          v-model="form.guidingTwo"
+          placeholder="请输入第二句引导语,不多余15个汉字"
+          maxlength="15"
+          style="width: 350px"
+        />
+      </el-form-item>
+    </el-form>
+    <div class="el-dialog__footer" style="text-align: center">
+      <el-button type="primary" @click="onSubmit('bannerForm')"> 保存 </el-button>
+      <el-button plain @click="backToList"> 返回 </el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+import { saveShopPopUp, getShopPopUp } from '@/api/user/customer/customer'
+
+export default {
+  name: 'CustomerPopupEdit',
+  data() {
+    const defaultForm = () => {
+      return {
+        id: '',
+        shopId: this.$route.query.shopId,
+        image: '', // 弹窗图片
+        guidingOne: '', // 引导语1
+        guidingTwo: '', // 引导语2
+        addTime: ''
+      }
+    }
+    return {
+      form: defaultForm(),
+      loadImgLoading: false,
+      rules: {
+        image: [{ required: true, message: '请上传弹窗图片', trigger: 'blur' }],
+        guidingOne: [{ required: true, message: '请填写引导语', trigger: 'blur' }],
+        guidingTwo: [{ required: true, message: '请填写引导语', trigger: 'blur' }]
+      }
+    }
+  },
+  computed: {
+    getToken() {
+      return {
+        token: this.$store.getters.token
+      }
+    },
+    actionUrl() {
+      return process.env.VUE_APP_BASE_API + '/formData/MultiPictareaddData'
+    }
+  },
+  created() {
+    this.getShopPopUp({ shopId: this.$route.query.shopId })
+  },
+  methods: {
+    // 获取供应商弹窗详情
+    async getShopPopUp(params) {
+      try {
+        const res = await getShopPopUp(params)
+        this.form = { ...this.form, ...res.data }
+      } catch (error) {
+        console.log('error', error)
+      }
+    },
+    onSubmit(formName) {
+      this.$refs[formName].validate((valid) => {
+        if (valid) {
+          this.$confirm('是否提交保存信息', '提示', {
+            confirmButtonText: '确定',
+            cancelButtonText: '取消',
+            type: 'warning'
+          }).then(() => {
+            console.log('form', this.form)
+            this.saveShopPopUp(this.form)
+          })
+        } else {
+          return false
+        }
+      })
+    },
+    async saveShopPopUp(params) {
+      // 保存
+      await saveShopPopUp(params)
+      this.$message.success('保存成功')
+      setTimeout(() => {
+        this.$router.push({ path: '/user/customer/list' })
+      }, 1000)
+    },
+    // 上传图标事件
+    handleSuccess(res, file) {
+      this.loadImgLoading = true
+      this.$nextTick(() => {
+        setTimeout(() => {
+          this.form.image = res.data
+        }, 1000 * 2)
+      })
+    },
+    // 对上传图片的大小、格式进行限制
+    beforeUpload(file) {
+      const isJPG = file.type === 'image/jpeg'
+      const isJPG2 = file.type === 'image/jpg'
+      const isPNG = file.type === 'image/png'
+      const isLt5M = file.size / 1024 / 1024 < 5
+      if (!isJPG && !isJPG2 && !isPNG) {
+        this.$message.error('只支持jpg或png格式图片')
+      }
+      if (!isLt5M) {
+        this.$message.error('请上传5MB以内的图片!')
+      }
+      return (isJPG || isJPG2 || isPNG) && isLt5M
+    },
+    reloadImage() {
+      this.loadImgLoading = true
+      setTimeout(() => {
+        this.temp.classifyImage = this.temp.classifyImage.split('?')[0] + '?r=' + Math.floor(Math.random() * 1000)
+      }, 1000 * 2)
+    },
+    loadSucess() {
+      this.loadImgLoading = false
+    },
+    backToList() {
+      this.$store.dispatch('tagsView/delView', this.$route).then(() => {
+        this.$nextTick(() => {
+          this.$router.replace({ path: '/user/customer/list' })
+        })
+      })
+    }
+  }
+}
+</script>
+
+<style>
+.avatar-uploader .el-upload {
+  border: 1px dashed #d9d9d9;
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+  float: left;
+}
+.avatar-uploader .el-upload:hover {
+  border-color: #409eff;
+}
+.avatar-uploader-icon {
+  font-size: 30px;
+  color: #999999;
+}
+.el-form-item__label {
+  text-align: right !important;
+}
+.el-upload__tip {
+  line-height: 20px;
+  color: red;
+  text-align: left;
+  position: absolute;
+  right: -50%;
+  bottom: 0;
+}
+.span_tip {
+  font-size: 12px;
+  color: red;
+  margin-left: 5px;
+}
+.filter-item-temp {
+  width: 100px;
+}
+</style>

+ 225 - 0
src/views/user/customer/customer-search-list.vue

@@ -0,0 +1,225 @@
+<template>
+  <div class="app-container">
+    <!-- 顶部操作区域 -->
+    <div class="filter-container">
+      <div class="filter-control">
+        <span>搜索词:</span>
+        <el-input
+          v-model="listQuery.keyword"
+          placeholder="搜索词"
+          clearable
+          @keyup.enter.native="getList"
+          @clear="getList"
+        />
+      </div>
+      <div class="filter-control">
+        <span>统计状态:</span>
+        <el-select v-model="listQuery.status" style="width: 120px" clearable @change="getList">
+          <el-option value="" label="请选择" />
+          <el-option :value="0" label="统计中" />
+          <el-option :value="1" label="暂停统计" />
+        </el-select>
+      </div>
+      <div class="filter-control">
+        <el-button type="primary" @click="getList"> 查询 </el-button>
+        <el-button type="primary" @click="searchDialogVisible = true"> 添加搜索词 </el-button>
+      </div>
+    </div>
+    <!-- 列表 -->
+    <el-table v-loading="isLoading" :data="list" border style="width: 100%" height="600">
+      <el-table-column prop="keyword" fixed label="搜索词" align="center" />
+      <el-table-column prop="number" fixed label="搜索次数" align="center" width="100" />
+      <el-table-column prop="status" label="统计状态" align="center" width="100">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.status === 0" type="success" size="small">统计中</el-tag>
+          <el-tag v-if="row.status === 1" type="danger" size="small">暂停统计</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column prop="searchTime" label="最近搜索时间" align="center" width="200">
+        <template slot-scope="{ row }">
+          {{ row.searchTime ? row.searchTime : '---' }}
+        </template>
+      </el-table-column>
+      <el-table-column prop="addTime" label="添加时间" align="center" width="200">
+        <template slot-scope="{ row }">
+          {{ row.addTime ? row.addTime : '---' }}
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" width="200">
+        <template slot-scope="{ row }">
+          <el-button type="primary" size="mini" style="margin: 2px" @click="handleSitting(row)">
+            设置统计状态
+          </el-button>
+          <el-button type="danger" size="mini" style="margin: 2px" @click="handleDelete(row)"> 删除 </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 页码 -->
+    <pagination
+      :total="total"
+      :page-sizes="[100]"
+      :page-size="100"
+      :page.sync="listQuery.pageNum"
+      :limit.sync="listQuery.pageSize"
+      @pagination="getShopKeywordList"
+    />
+    <!--  选择搜索词弹窗 -->
+    <search-dialog
+      v-if="searchDialogVisible"
+      ref="searchDialog"
+      @confirm="handleSearchConfirm"
+      @cancel="handleCancel"
+    />
+    <!-- 设置统计状态 -->
+    <el-dialog title="设置统计状态" :visible.sync="dialogFormVisible" width="500px">
+      <el-form ref="dataForm" :model="renewCustome" label-position="right">
+        <el-form-item prop="auditNote">
+          <el-radio v-model="renewCustome.status" :label="0">统计中</el-radio>
+          <el-radio v-model="renewCustome.status" :label="1">暂停统计</el-radio>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="dialogFormVisible = false">取消</el-button>
+        <el-button type="primary" @click="handleConfirm">确定</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { getShopKeywordList, saveShopKeyword, renewShopKeyword, delShopKeyword } from '@/api/user/customer/customer'
+import SearchDialog from './components/search-dialog'
+export default {
+  name: 'CustomerSearchList',
+  components: {
+    SearchDialog
+  },
+  filters: {},
+  data() {
+    return {
+      isLoading: true,
+      time: '',
+      listQuery: {
+        shopId: this.$route.query.shopId,
+        keyword: '',
+        status: '',
+        pageNum: 1,
+        pageSize: 20
+      },
+      list: [],
+      total: 0,
+      searchDialogVisible: false,
+      dialogFormVisible: false,
+      renewCustome: {
+        id: '',
+        status: ''
+      },
+      rules: {
+        status: [{ required: true, message: '请设置统计状态', trigger: 'blur' }]
+      }
+    }
+  },
+  computed: {},
+  created() {
+    this.getList()
+  },
+  mounted() {},
+  methods: {
+    // 获取供应商关键词列表
+    async getList() {
+      this.list = []
+      this.listQuery.pageNum = 1
+      this.getShopKeywordList()
+    },
+    // 获取供应商关键词列表
+    async getShopKeywordList() {
+      try {
+        this.isLoading = true
+        const res = await getShopKeywordList(this.listQuery)
+        this.list = res.data.results
+        this.total = res.data.totalRecord
+        this.isLoading = false
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 确认选择供应商关键词
+    handleSearchConfirm(data) {
+      console.log('data', data)
+      const keyWordIds = []
+      data.forEach((ele) => {
+        keyWordIds.push(ele.id)
+      })
+      this.saveShopKeyword({ shopId: this.listQuery.shopId, keyWordIds: keyWordIds.join(',') })
+    },
+    // 保存添加供应商关键词
+    async saveShopKeyword(params) {
+      try {
+        await saveShopKeyword(params)
+        this.searchDialogVisible = false
+        this.$message.success('操作成功')
+        this.getList()
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 取消选择供应商关键词
+    handleCancel() {
+      this.searchDialogVisible = false
+      this.$refs.searchDialog.visible = false
+    },
+    // 设置状态
+    handleSitting(row) {
+      this.renewCustome.id = row.id
+      this.renewCustome.status = row.status
+      this.dialogFormVisible = true
+    },
+    // 确认设置统计状态
+    handleConfirm() {
+      this.$refs['dataForm'].validate((valid) => {
+        if (valid) {
+          this.renewShopKeyword(this.renewCustome)
+        } else {
+          return false
+        }
+      })
+    },
+    // 调用关键词统计状态API
+    async renewShopKeyword(params) {
+      try {
+        await renewShopKeyword(params)
+        this.dialogFormVisible = false
+        this.$message.success('操作成功')
+        this.getList()
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    async handleDelete(row) {
+      try {
+        await this.$confirm('确定删除该搜索词吗?', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        })
+        this.delShopKeyword(row)
+      } catch (error) {
+        this.$message.info('已取消删除操作')
+      }
+    },
+    // 调用删除文章
+    async delShopKeyword(row) {
+      try {
+        await delShopKeyword(row.id)
+        this.$message.success('操作成功')
+        this.getList()
+      } catch (error) {
+        console.log(error)
+      }
+    }
+  }
+}
+</script>
+
+<style></style>

+ 174 - 0
src/views/user/customer/customer-stat-list.vue

@@ -0,0 +1,174 @@
+<template>
+  <div class="app-container">
+    <!-- 顶部操作区域 -->
+    <div class="filter-container">
+      <div class="filter-control">
+        <span>姓名:</span>
+        <el-input
+          v-model="listQuery.consultName"
+          placeholder="姓名"
+          clearable
+          @keyup.enter.native="getList"
+          @clear="getList"
+        />
+      </div>
+      <div class="filter-control">
+        <span>手机号:</span>
+        <el-input
+          v-model="listQuery.consultMobile"
+          placeholder="手机号"
+          clearable
+          @keyup.enter.native="getList"
+          @clear="getList"
+        />
+      </div>
+      <div class="filter-control">
+        <span>跟进状态:</span>
+        <el-select v-model="listQuery.followUpStatus" style="width: 120px" clearable @change="getList">
+          <el-option value="" label="请选择" />
+          <el-option :value="0" label="已跟进" />
+          <el-option :value="1" label="未跟进" />
+        </el-select>
+      </div>
+      <div class="filter-control">
+        <el-button type="primary" @click="getList"> 查询 </el-button>
+      </div>
+    </div>
+    <!-- 列表 -->
+    <el-table v-loading="isLoading" :data="list" border style="width: 100%" height="600">
+      <el-table-column prop="consultName" fixed label="姓名" align="center" />
+      <el-table-column prop="consultMobile" label="手机号" align="center">
+        <template slot-scope="{ row }">
+          {{ row.consultMobile ? row.consultMobile : '---' }}
+        </template>
+      </el-table-column>
+      <el-table-column prop="createTime" label="登记时间" align="center">
+        <template slot-scope="{ row }">
+          {{ row.createTime ? row.createTime : '---' }}
+        </template>
+      </el-table-column>
+      <el-table-column prop="followUpStatus" label="跟进状态" align="center">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.followUpStatus === 0" type="success" size="small">已跟进</el-tag>
+          <el-tag v-if="row.followUpStatus === 1" type="warning" size="small">未跟进</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" width="200">
+        <template slot-scope="{ row }">
+          <el-button type="primary" size="mini" style="margin: 2px" @click="handleSitting(row)">
+            设置跟进状态
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 页码 -->
+    <pagination
+      :total="total"
+      :page-sizes="[100]"
+      :page-size="100"
+      :page.sync="listQuery.pageNum"
+      :limit.sync="listQuery.pageSize"
+      @pagination="getCmInformationList"
+    />
+    <!-- 设置跟进状态 -->
+    <el-dialog title="设置跟进状态" :visible.sync="dialogFormVisible" width="500px">
+      <el-form ref="dataForm" :model="renewCustome" label-position="right">
+        <el-form-item prop="auditNote">
+          <el-radio v-model="renewCustome.followUpStatus" :label="0">已跟进</el-radio>
+          <el-radio v-model="renewCustome.followUpStatus" :label="1">未跟进</el-radio>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="dialogFormVisible = false">取消</el-button>
+        <el-button type="primary" @click="handleConfirm">确定</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { getCmInformationList, renewFollowUpStatus } from '@/api/user/customer/customer'
+export default {
+  name: 'CustomerStatList',
+  filters: {},
+  data() {
+    return {
+      activeName: 'first',
+      isLoading: true,
+      time: '',
+      listQuery: {
+        shopId: this.$route.query.shopId,
+        consultName: '',
+        consultMobile: '',
+        pageNum: 1,
+        pageSize: 100
+      },
+      list: [],
+      total: 0,
+      dialogFormVisible: false,
+      renewCustome: {
+        id: '',
+        followUpStatus: ''
+      },
+      rules: {
+        status: [{ required: true, message: '请设置跟进状态', trigger: 'blur' }]
+      }
+    }
+  },
+  computed: {},
+  created() {
+    this.getList()
+  },
+  mounted() {},
+  methods: {
+    // 获取潜客统计列表
+    async getList() {
+      this.list = []
+      this.listQuery.pageNum = 1
+      this.getCmInformationList()
+    },
+    // 获取潜客统计列表
+    async getCmInformationList() {
+      try {
+        this.isLoading = true
+        const res = await getCmInformationList(this.listQuery)
+        this.list = res.data.results
+        this.total = res.data.totalRecord
+        this.isLoading = false
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 确认设置跟进状态
+    handleConfirm() {
+      this.$refs['dataForm'].validate((valid) => {
+        if (valid) {
+          this.renewFollowUpStatus(this.renewCustome)
+        } else {
+          return false
+        }
+      })
+    },
+    // 设置状态
+    handleSitting(row) {
+      this.renewCustome.id = row.id
+      this.renewCustome.followUpStatus = row.followUpStatus
+      this.dialogFormVisible = true
+    },
+    // 调用跟进状态API
+    async renewFollowUpStatus(params) {
+      try {
+        await renewFollowUpStatus(params)
+        this.dialogFormVisible = false
+        this.$message.success('操作成功')
+        this.getList()
+      } catch (error) {
+        console.log(error)
+      }
+    }
+  }
+}
+</script>
+
+<style></style>

+ 247 - 0
src/views/user/customer/list.vue

@@ -0,0 +1,247 @@
+<template>
+  <div class="app-container">
+    <!-- 顶部操作区域 -->
+    <div class="filter-container">
+      <div class="filter-control">
+        <span>供应商名称:</span>
+        <el-input
+          v-model="listQuery.shopName"
+          placeholder="供应商名称"
+          clearable
+          @keyup.enter.native="getList"
+          @clear="getList"
+        />
+      </div>
+      <div class="filter-control">
+        <span>统计状态:</span>
+        <el-select v-model="listQuery.status" style="width: 120px" clearable @change="getList">
+          <el-option value="" label="请选择" />
+          <el-option :value="0" label="统计中" />
+          <el-option :value="1" label="暂停统计" />
+        </el-select>
+      </div>
+      <div class="filter-control">
+        <el-button type="primary" @click="getList"> 查询 </el-button>
+        <el-button type="primary" @click="shopDialogVisible = true"> 添加供应商 </el-button>
+      </div>
+    </div>
+    <!-- 列表 -->
+    <el-table v-loading="isLoading" :data="list" border style="width: 100%" height="660">
+      <el-table-column prop="shopName" fixed label="供应商名称" align="center" />
+      <el-table-column prop="linkMan" label="联系人" align="center" />
+      <el-table-column prop="mobile" label="手机号" align="center">
+        <template slot-scope="{ row }">
+          {{ row.mobile ? row.mobile : '---' }}
+        </template>
+      </el-table-column>
+      <el-table-column prop="shopStatus" label="供应商状态" align="center">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.shopStatus === 90" type="success" size="small">已上线</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column prop="status" label="统计状态" align="center">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.status === 0" type="success" size="small">统计中</el-tag>
+          <el-tag v-if="row.status === 1" type="danger" size="small">暂停统计</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column prop="addTime" label="添加时间" align="center">
+        <template slot-scope="{ row }">
+          {{ row.addTime ? row.addTime : '---' }}
+        </template>
+      </el-table-column>
+      <el-table-column fixed="right" label="操作" align="center" width="400">
+        <template slot-scope="{ row }">
+          <el-button type="primary" size="mini" style="margin: 4px" @click="handleRecordDetail(1, row)">
+            潜客统计列表
+          </el-button>
+          <el-button type="primary" size="mini" style="margin: 4px" @click="handleRecordDetail(2, row)">
+            相关文章
+          </el-button>
+          <el-button type="primary" size="mini" style="margin: 4px" @click="handleRecordDetail(3, row)">
+            相关搜索词
+          </el-button>
+          <el-button type="success" size="mini" style="margin: 4px" @click="handleRecordDetail(4, row)">
+            页面访问统计
+          </el-button>
+          <el-button type="success" size="mini" style="margin: 4px" @click="handleRecordDetail(5, row)">
+            弹窗样式
+          </el-button>
+          <el-button type="warning" size="mini" style="margin: 4px" @click="handleRecordDetail(6, row)">
+            设置统计状态
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 页码 -->
+    <pagination
+      :total="total"
+      :page-sizes="[100]"
+      :page-size="100"
+      :page.sync="listQuery.pageNum"
+      :limit.sync="listQuery.pageSize"
+      @pagination="getCustomerShopList"
+    />
+    <!--  选择供应商弹窗 -->
+    <shop-dialog v-if="shopDialogVisible" ref="shopDialog" @confirm="handleAddShopConfirm" @cancel="handleCancel" />
+    <!-- 设置统计状态 -->
+    <el-dialog title="设置统计状态" :visible.sync="dialogFormVisible" width="500px">
+      <el-form ref="dataForm" :model="renewCustome" :rules="rules" label-position="right">
+        <el-form-item prop="status">
+          <el-radio v-model="renewCustome.status" :label="0">统计中</el-radio>
+          <el-radio v-model="renewCustome.status" :label="1">暂停统计</el-radio>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="dialogFormVisible = false">取消</el-button>
+        <el-button type="primary" @click="handleConfirm">确定</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { getCustomerShopList, saveCustomerShop, renewCustomerShop } from '@/api/user/customer/customer'
+import ShopDialog from './components/shop-dialog'
+export default {
+  name: 'RecordList',
+  components: { ShopDialog },
+  filters: {},
+  data() {
+    return {
+      isLoading: true,
+      listQuery: {
+        shopName: '',
+        status: '',
+        pageNum: 1,
+        pageSize: 20
+      },
+      list: [],
+      total: 0,
+      shopDialogVisible: false,
+      dialogFormVisible: false,
+      renewCustome: {
+        id: '',
+        status: ''
+      },
+      rules: {
+        status: [{ required: true, message: '请设置统计状态', trigger: 'blur' }]
+      }
+    }
+  },
+  computed: {},
+  created() {
+    this.getList()
+  },
+  mounted() {},
+  methods: {
+    // 获取行为记录列表
+    getList() {
+      this.list = []
+      this.listQuery.pageNum = 1
+      this.getCustomerShopList()
+    },
+    // 确认选择供应商
+    handleAddShopConfirm(data) {
+      console.log('data', data)
+      const shopIds = []
+      data.forEach((ele) => {
+        shopIds.push(ele.shopId)
+      })
+      this.saveCustomerShop({ shopIds: shopIds.join(',') })
+    },
+    // 取消选择供应商
+    handleCancel() {
+      this.shopDialogVisible = false
+      this.$refs.shopDialog.visible = false
+    },
+    // 确认设置统计状态
+    handleConfirm() {
+      this.$refs['dataForm'].validate((valid) => {
+        if (valid) {
+          this.renewCustomerShop(this.renewCustome)
+        } else {
+          return false
+        }
+      })
+    },
+    // 获取潜客搜集供应商列表
+    async getCustomerShopList() {
+      try {
+        this.isLoading = true
+        const res = await getCustomerShopList(this.listQuery)
+        this.list = res.data.results
+        this.total = res.data.totalRecord
+        this.isLoading = false
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 保存添加统计供应商
+    async saveCustomerShop(params) {
+      try {
+        await saveCustomerShop(params)
+        this.shopDialogVisible = false
+        this.$message.success('操作成功')
+        this.getList()
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 统计状态
+    async renewCustomerShop(params) {
+      try {
+        await renewCustomerShop(params)
+        this.dialogFormVisible = false
+        this.$message.success('操作成功')
+        this.getList()
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 查看详情
+    handleRecordDetail(type, row) {
+      switch (type) {
+        case 1: // 潜客统计列表
+          this.$router.push({
+            path: '/user/customer/customer-stat-list',
+            query: { shopId: row.shopId }
+          })
+          break
+        case 2: // 相关文章
+          this.$router.push({
+            path: '/user/customer/customer-article-list',
+            query: { shopId: row.shopId }
+          })
+          break
+        case 3: // 相关搜索词
+          this.$router.push({
+            path: '/user/customer/customer-search-list',
+            query: { shopId: row.shopId }
+          })
+          break
+        case 4: // 页面访问
+          this.$router.push({
+            path: '/user/customer/customer-page-list',
+            query: { shopId: row.shopId }
+          })
+          break
+        case 5: // 弹窗样式
+          this.$router.push({
+            path: '/user/customer/customer-popup-edit',
+            query: { shopId: row.shopId }
+          })
+          break
+        case 6:
+          this.renewCustome.id = row.id
+          this.renewCustome.status = row.status
+          console.log('renewCustome', this.renewCustome)
+          this.dialogFormVisible = true
+          break
+      }
+    }
+  }
+}
+</script>
+
+<style></style>