wangxiaogang 3 лет назад
Родитель
Сommit
1f0dcf6936
56 измененных файлов с 3060 добавлено и 598 удалено
  1. 2 1
      README.md
  2. 23 0
      config/cdn.js
  3. 8 0
      config/index.js
  4. 87 0
      config/proxy.js
  5. 12 0
      src/App.vue
  6. 43 0
      src/api/modules/dataExport.js
  7. 1 0
      src/api/modules/index.js
  8. BIN
      src/assets/images/big/1-big.png
  9. BIN
      src/assets/images/big/8-big.png
  10. BIN
      src/assets/images/big/88-big.png
  11. BIN
      src/assets/images/big/bg/1-bg.png
  12. BIN
      src/assets/images/icon/collect.png
  13. BIN
      src/assets/images/icon/collected.png
  14. BIN
      src/assets/images/icon/export.png
  15. BIN
      src/assets/images/icon/tab-list.png
  16. BIN
      src/assets/images/icon/tab-table.png
  17. BIN
      src/assets/images/vip/010.png
  18. BIN
      src/assets/images/vip/1.png
  19. BIN
      src/assets/images/vip/7.png
  20. BIN
      src/assets/images/vip/bg/mask/02.png
  21. BIN
      src/assets/images/vip/bg/mask/10.png
  22. 3 2
      src/assets/js/selector.js
  23. 13 0
      src/assets/style/reset-ele.scss
  24. 1 1
      src/components/article-item/ArticleItem.vue
  25. 196 0
      src/components/chart/ProChart.vue
  26. 129 41
      src/components/chart/ProgressChart.vue
  27. 67 17
      src/components/collect-info/CollectInfo.vue
  28. 114 58
      src/components/contact-info/ContactInfo.vue
  29. 36 16
      src/components/forecast/ForeCast.vue
  30. 14 5
      src/components/home/HomeList.vue
  31. 11 4
      src/components/mask-card/MaskCard.vue
  32. 45 3
      src/components/push-list/ProjectProgressList.vue
  33. 22 2
      src/components/push-list/PushList.vue
  34. 1 0
      src/main.js
  35. 17 1
      src/store/user.js
  36. 28 0
      src/utils/functions/syncSessionStorage.js
  37. 1 1
      src/utils/globalFunctions.js
  38. 1 0
      src/utils/index.js
  39. 0 0
      src/utils/mixins/index.js
  40. 69 0
      src/utils/mixins/visited.js
  41. 2 2
      src/views/bid-forecast/BidForecastLimit.vue
  42. 23 5
      src/views/ent-intel/MyClient.vue
  43. 131 110
      src/views/portrayal/EntPortrayal.vue
  44. 132 165
      src/views/portrayal/EntSearchPortrayal.vue
  45. 95 64
      src/views/portrayal/UnitPortrayal.vue
  46. 1336 0
      src/views/portrayal/components/DynamicList.vue
  47. 179 0
      src/views/portrayal/components/DynamicListItem.vue
  48. 55 31
      src/views/portrayal/components/EntChart.vue
  49. 1 1
      src/views/portrayal/components/EntSubVipChart.vue
  50. 30 3
      src/views/portrayal/components/ProActive.vue
  51. 46 23
      src/views/portrayal/components/UnitChart.vue
  52. 22 5
      src/views/portrayal/components/UnitList.vue
  53. 2 2
      src/views/reportData/pageMonth.vue
  54. 2 2
      src/views/reportData/pageWeek.vue
  55. 54 7
      src/views/work-desktop/WorkDesktop.vue
  56. 6 26
      vue.config.js

+ 2 - 1
README.md

@@ -1,6 +1,7 @@
 ## 剑鱼大会员PC端
 v1.4.4
 增加消息中心曝光率
+
 ##### 无顶部底部开发
 
 0. ```yarn run serve:alone```
@@ -13,6 +14,6 @@ v1.4.4
 
 2. 修改`systemjs-importmap`中app对应的请求地址
 
-    > 文件地址 /src/web/templates/frontRouter/pc/docs/sess/index.html
+    > 文件地址 /src/web/templates/frontRouter/pc/page_big_pc/sess/index.html
 
 3. 访问`/swordfish/docs/index`

+ 23 - 0
config/cdn.js

@@ -0,0 +1,23 @@
+exports.cdn = {
+  css: [
+    // '//unpkg.com/element-ui@2.10.1/lib/theme-chalk/index.css'
+  ],
+  jsdelivr: [
+    '//cdn.jsdelivr.net/npm/vue@2.6.11/dist/vue.min.js',
+    '//cdn.jsdelivr.net/npm/vue-router@3.1.5/dist/vue-router.min.js',
+    '//cdn.jsdelivr.net/npm/vuex@3.4.0/dist/vuex.min.js',
+    '//cdn.jsdelivr.net/npm/axios@0.19.2/dist/axios.min.js',
+    '//cdn.jsdelivr.net/npm/echarts@4.8.0/dist/echarts.min.js',
+    '//cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js',
+    '//cdn.jsdelivr.net/npm/moment@2.29.1/moment.min.js'
+  ],
+  js: [
+    '//cdn-common.jianyu360.cn/cdn/lib/vue/2.6.11/vue.min.js',
+    '//cdn-common.jianyu360.cn/cdn/lib/vue-router/3.1.5/vue-router.min.js',
+    '//cdn-common.jianyu360.cn/cdn/lib/vuex/3.4.0/vuex.min.js',
+    '//cdn-common.jianyu360.cn/cdn/lib/axios/0.19.2/axios.min.js',
+    '//cdn-common.jianyu360.cn/cdn/lib/echarts/4.8.0/echarts.min.js',
+    '//cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js',
+    '//cdn.jsdelivr.net/npm/moment@2.29.1/moment.min.js'
+  ]
+}

+ 8 - 0
config/index.js

@@ -0,0 +1,8 @@
+const { cdn } = require('./cdn')
+const { getProxyOfDomain, getProxyOfIp } = require('./proxy')
+
+module.exports = {
+  cdn,
+  getProxyOfDomain,
+  getProxyOfIp
+}

+ 87 - 0
config/proxy.js

@@ -0,0 +1,87 @@
+exports.getProxyOfDomain = function (domain) {
+  return {
+    // 反爬虫接口代理
+    // '/subVipPortrait/winner': {
+    //   target: domain,
+    //   changeOrigin: true,
+    //   logLevel: 'debug'
+    // },
+    '^/bigmember': {
+      target: domain,
+      changeOrigin: true,
+      logLevel: 'debug',
+      pathRewrite: {
+        '^/bigmember': '/bigmember'
+      }
+    },
+    '^/jypay': {
+      target: domain,
+      changeOrigin: true,
+      logLevel: 'debug'
+    },
+    '^/publicapply': {
+      target: domain,
+      changeOrigin: true,
+      logLevel: 'debug'
+    },
+    '^/subscribepay': {
+      target: domain,
+      changeOrigin: true,
+      logLevel: 'debug'
+    },
+    '^/salesLeads': {
+      target: domain,
+      changeOrigin: true,
+      logLevel: 'debug'
+    },
+    '^/privatedata': {
+      target: domain,
+      changeOrigin: true,
+      logLevel: 'debug'
+    }
+  }
+}
+
+exports.getProxyOfIp = function (ip) {
+  return {
+    // 反爬虫接口代理
+    // '/subVipPortrait/winner': {
+    //   target: ip + ':8800',
+    //   changeOrigin: true,
+    //   logLevel: 'debug'
+    // },
+    '^/bigmember': {
+      target: ip + ':814',
+      changeOrigin: true,
+      logLevel: 'debug',
+      pathRewrite: {
+        '^/bigmember': '/bigmember'
+      }
+    },
+    '^/jypay': {
+      target: ip + ':86',
+      changeOrigin: true,
+      logLevel: 'debug'
+    },
+    '^/publicapply': {
+      target: ip + ':828',
+      changeOrigin: true,
+      logLevel: 'debug'
+    },
+    '^/subscribepay': {
+      target: ip + ':86',
+      changeOrigin: true,
+      logLevel: 'debug'
+    },
+    '^/salesLeads': {
+      target: ip + ':8881',
+      changeOrigin: true,
+      logLevel: 'debug'
+    },
+    '^/privatedata': {
+      target: ip + ':829',
+      changeOrigin: true,
+      logLevel: 'debug'
+    }
+  }
+}

+ 12 - 0
src/App.vue

@@ -40,4 +40,16 @@ export default {
   top: 63px;
   z-index: 99;
 }
+.visited {
+  .visited-hd,
+  td {
+    color: #999!important;
+  }
+  .hover:hover {
+    color: #2cb7ca!important;
+  }
+  .visited-ft {
+    color: #9B9CA3!important;
+  }
+}
 </style>

+ 43 - 0
src/api/modules/dataExport.js

@@ -0,0 +1,43 @@
+import request from '@/api'
+import qs from 'qs'
+
+// 通用选择导出
+// param
+// selectIds:多个加密三级页id【,】分割
+// from:来源页面
+// return:id
+export function getDataExportOrderId (data) {
+  data = qs.stringify(data)
+  return request({
+    baseURL: '/publicapply',
+    url: '/dataexpoet/bySelects',
+    method: 'post',
+    data
+  })
+}
+
+// 画像动态导出
+// isMember bool 是否是大会员
+// isWinner bool false 采购单位画像;true 中标企业画像
+export function getPortrayalSearchExportId (isMember, isWinner, data) {
+  let url = ''
+  if (isMember) {
+    if (isWinner) {
+      url = '/portrait/winner/winnerNewMsgExport'
+    } else {
+      url = '/portrait/buyer/getNewMsgExport'
+    }
+  } else {
+    if (isWinner) {
+      url = '/portrait/subVipPortrait/winnerNewMsgExport'
+    } else {
+      url = '/subVipPortrait/buyer/getNewMsgExport'
+    }
+  }
+  data = qs.stringify(data)
+  return request({
+    url: url,
+    method: 'post',
+    data
+  })
+}

+ 1 - 0
src/api/modules/index.js

@@ -11,3 +11,4 @@ export * from './coupon'
 export * from './svip'
 export * from './file'
 export * from './customer'
+export * from './dataExport'

BIN
src/assets/images/big/1-big.png


BIN
src/assets/images/big/8-big.png


BIN
src/assets/images/big/88-big.png


BIN
src/assets/images/big/bg/1-bg.png


BIN
src/assets/images/icon/collect.png


BIN
src/assets/images/icon/collected.png


BIN
src/assets/images/icon/export.png


BIN
src/assets/images/icon/tab-list.png


BIN
src/assets/images/icon/tab-table.png


BIN
src/assets/images/vip/010.png


BIN
src/assets/images/vip/1.png


BIN
src/assets/images/vip/7.png


BIN
src/assets/images/vip/bg/mask/02.png


BIN
src/assets/images/vip/bg/mask/10.png


+ 3 - 2
src/assets/js/selector.js

@@ -493,7 +493,7 @@ export const industryJson = [
 
 // 职位
 export const jobJson = [
-  '总裁', 
+  '总裁',
   '总经理',
   '总监',
   '经理',
@@ -516,5 +516,6 @@ export const branchJson = [
   '市场',
   '产品',
   '销售',
-  '渠道'
+  '渠道',
+  '其他'
 ]

+ 13 - 0
src/assets/style/reset-ele.scss

@@ -34,6 +34,19 @@
     border-color: $color-text--highlight;
   }
 
+  .el-checkbox__inner {
+    width: 16px;
+    height: 16px;
+    border-radius: 3px;
+    &::after {
+      border-width: 2px;
+      left: 5px;
+      top: 1px;
+    }
+  }
+
+
+
   .el-button--main {
     font-family: Microsoft YaHei, Microsoft YaHei-Regular;
     border-color: $color-text--highlight;

+ 1 - 1
src/components/article-item/ArticleItem.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="article-item" :class="{'style-for-gray': config.gray, 'style-for-table': config.table }">
     <input v-if="config.collect" @click.stop class="custom-checkbox title-text-checkbox" name="bid-list" type="checkbox" :dataid="article._id">
-    <div class="a-i-left ellipsis" @click="onClick" v-html="calcTitle"></div>
+    <div class="a-i-left ellipsis visited-hd" @click="onClick" v-html="calcTitle"></div>
     <div class="a-i-right">
       <div class="tags">
         <span class="tag" v-if="article.area">{{ article.area }}</span>

+ 196 - 0
src/components/chart/ProChart.vue

@@ -0,0 +1,196 @@
+<template>
+  <div class="progess-chart">
+    <div class="client-list" >
+      <div class="c-thead" v-if="type == 'unit'">
+        <span class="c-name">企业名称</span>
+        <span class="c-count">行业</span>
+        <span class="c-count">项目数量</span>
+        <span class="c-count">平均节支率</span>
+        <span class="c-time">最近合作日期</span>
+      </div>
+      <div class="c-thead" v-if="type == 'ent'">
+        <span class="c-name">企业名称</span>
+        <span class="c-count">行业</span>
+        <span class="c-count">项目数量</span>
+        <span class="c-count">平均节支率</span>
+        <span class="c-time">最近合作日期</span>
+      </div>
+      <div class="progress-bar-container">
+        <div class="progress-bar-item" v-for="(item,i) in datas" :key="i">
+          <div class="item-label" v-if="type == 'unit'">
+            <span :class="!ishref ? 'no-href' : ''" class="ellipsis-2 item-name" @click="goEnt(item.id)">{{item.name}}</span>
+            <span class="item-count">{{item.business?item.business:"--"}}</span>
+            <span class="item-count">{{item.total}}个</span>
+            <span v-if="item.rate == 0" class="item-count">0%</span>
+            <span v-else class="item-count">{{item.rate?(item.rate * 100).toFixed(2)+"%":"--"}}</span>
+            <span class="item-time">{{item.lastTime}}</span>
+          </div>
+          <div class="item-label" v-if="type == 'ent'">
+            <span :class="!ishref ? 'no-href' : ''" class="ellipsis-2 item-name" @click="goEnt(item.id)">{{item.name}}</span>
+            <span class="item-count">{{item.business?item.business:"--"}}</span>
+            <span class="item-count">{{item.total}}个</span>
+            <span v-if="item.rate == 0" class="item-count">0%</span>
+            <span v-else class="item-count">{{item.rate?(item.rate * 100).toFixed(2)+"%":"--"}}</span>
+            <span class="item-time">{{item.lastTime}}</span>
+          </div>
+          <div class="item-progress">
+            <span class="item-money" v-if="item.amount">中标金额:{{moneyFormat(item.amount)}}</span>
+            <span class="item-money" v-if="item.money">{{moneyFormat(item.money)}}</span>
+            <span class="item-progress-count active-progress" :style="{width: item.parent}"></span>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+<script>
+import { moneyUnit } from '@/utils/'
+import { mapState } from 'vuex'
+export default {
+  name: 'progess-chart',
+  props: {
+    type: String,
+    // 传入的数据
+    datas: Array,
+    ishref: {
+      type: Boolean,
+      default () {
+        return true
+      }
+    }
+  },
+  data () {
+    return {}
+  },
+  computed: {
+    ...mapState({
+      info: state => state.user.info
+    })
+    // computedClientList () {
+    //   return this.datas.map((v) => {
+    //     v.topData = v.topData.filter((s) => {
+    //       return s.winnerName && s.winnerName.trim().length
+    //     })
+    //     return v
+    //   }).filter(function (v, i) {
+    //     return v.topData.length
+    //   })
+    // }
+  },
+  watch: {},
+  mounted () {},
+  methods: {
+    moneyFormat (money) {
+      return moneyUnit(money)
+    },
+    goEntInfo (name) {
+      window.open('/swordfish/page_big_pc/unit_portrayal/' + encodeURIComponent(name))
+    },
+    goEnt (id) {
+      if (!this.ishref) return
+      if (this.info.power.indexOf(5) > -1) {
+        window.open('/swordfish/page_big_pc/ent_portrait/' + id)
+      } else {
+        window.open('/swordfish/page_big_pc/svip/ent_ser_portrait/' + id)
+      }
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+.client-list{
+  margin-top: 16px;
+  background-color: #fff;
+.c-thead{
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  line-height: 22px;
+}
+.c-name,.item-name{
+  font-size: 14px;
+  color: #1D1D1D;
+  flex: 7;
+}
+.item-name{
+  cursor: pointer;
+}
+.no-href {
+  text-decoration: none!important;
+  cursor: auto;
+}
+.c-count,.item-count,.c-time,.item-time{
+  flex: 1;
+  min-width: 100px;
+  font-size: 12px;
+  text-align: center;
+  white-space: nowrap;
+}
+.c-rate,.item-rate{
+  font-size: 12px;
+  text-align: center;
+}
+.c-name{
+  /*font-weight: bold;*/
+  font-size: 12px;
+  line-height: 40px;
+  color: #686868;
+}
+.c-count,.c-rate,.c-time{
+  color: #686868;
+  white-space: nowrap;
+}
+.progress-bar-container {
+  background-color: #fff;
+}
+.progress-bar-item {
+  display: flex;
+  flex-direction: column;
+  justify-content: space-around;
+  margin-bottom: 14px;
+}
+.item-label {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  line-height: 20px;
+  padding-bottom: 6px;
+}
+.item-name {
+  color: #171826;
+  text-decoration: underline;
+}
+.item-count {
+  font-size: 12px;
+  color: #171826;
+}
+.item-progress {
+  position: relative;
+  height: 20px;
+  line-height: 20px;
+  background-color: #EDEFF2;
+  border-radius: 0 10px 10px 0;
+  overflow: hidden;
+}
+.item-money{
+  position: absolute;
+  left: 16px;
+  top: 50%;
+  transform: translateY(-50%);
+  color: #8F5828;
+  font-size: 14px;
+  z-index: 10;
+}
+.item-progress-count {
+  position: absolute;
+  top: 0;
+  left: 0;
+  height: 100%;
+  border-radius: 0 10px 10px 0;
+  z-index: 9;
+}
+.active-progress{
+  background: #FAE7CA;
+}
+}
+</style>

+ 129 - 41
src/components/chart/ProgressChart.vue

@@ -1,45 +1,75 @@
 <template>
   <div class="progess-chart">
     <div class="client-list" v-for="(c,i) in datas" :key="i">
-      <div class="c-thead" v-if="type == 'unit'">
-          <strong class="c-name">{{c.class}}</strong>
-          <span class="c-count">项目数量</span>
-          <span class="c-time">最近合作日期</span>
+      <div class="c-top">
+        <strong class="c-itemName">{{ c.buyerclass }}</strong>
+        <div class="top-switch">
+          <div :class="{active: !showLabels[c.buyerclass]}" @click="toggleShow(c,false)">重点客户</div>
+          <div :class="{active: showLabels[c.buyerclass]}" @click="toggleShow(c,true)">首次合作客户</div>
         </div>
-        <div class="c-thead" v-if="type == 'ent'">
-          <strong class="c-name" >{{c.buyerclass}}</strong>
+      </div>
+      <div class="progress-bar-container" v-show="!showLabels[c.buyerclass]">
+        <div class="c-thead">
+          <span class="c-name">客户名称</span>
           <span class="c-count">中标数量</span>
           <span class="c-count">平均折扣率</span>
           <span class="c-time">最近合作日期</span>
         </div>
-        <div class="progress-bar-container">
-          <div class="progress-bar-item" v-for="(item,index) in c.topData" :key="index">
-            <div class="item-label" v-if="type == 'unit'">
-              <span :class="!ishref ? 'no-href' : ''" class="ellipsis-2 item-name" @click="goEnt(item.entId)">{{item.winnerName}}</span>
-              <span class="item-count">{{item.countProject}}个</span>
-              <span class="item-time">{{item.lastTime}}</span>
-            </div>
-            <div class="item-label" v-if="type == 'ent'">
-              <span @click="goEntInfo(item.name)" class="ellipsis-2 item-name">{{item.name}}</span>
-              <span class="item-count">{{item.count ? item.count + '个' : item.count}}</span>
-              <span class="item-count">{{(item.rate != null) ? item.rate + '%' : '--'}}</span>
-              <span class="item-time">{{item.time}}</span>
+        <div class="progress-bar-item" v-for="(item,index) in c.topData" :key="index">
+          <div class="item-label">
+            <span @click="goEntInfo(item.name)" class="ellipsis-2 item-name">{{ item.name }}</span>
+            <span class="item-count">{{ item.count ? item.count + '个' : item.count }}</span>
+            <span class="item-count">{{ (item.rate != null) ? item.rate + '%' : '--' }}</span>
+            <span class="item-time">{{ item.time }}</span>
+          </div>
+          <div class="item-progress">
+            <span class="item-money" v-if="item.countMoney">{{ moneyFormat(item.countMoney) }}</span>
+            <span class="item-money" v-if="item.money">{{ moneyFormat(item.money) }}</span>
+            <span class="item-progress-count active-progress" :style="{width: item.parent}"></span>
+          </div>
+        </div>
+      </div>
+      <div class="progress-bar-container" v-show="showLabels[c.buyerclass]">
+        <div v-if="c.firstData&&c.firstData.length>0">
+          <div class="c-thead">
+            <span class="c-name">客户名称</span>
+            <span class="c-count">中标数量</span>
+            <span class="c-count">平均折扣率</span>
+            <span class="c-time">最近合作日期</span>
+          </div>
+          <div class="progress-bar-item" v-for="(item,index) in c.firstData" :key="index">
+            <div class="item-label">
+              <span @click="goEntInfo(item.name)" class="ellipsis-2 item-name">{{ item.name }}</span>
+              <span class="item-count">{{ item.count ? item.count + '个' : item.count }}</span>
+              <span class="item-count">{{ (item.rate != null) ? item.rate + '%' : '--' }}</span>
+              <span class="item-time">{{ item.time }}</span>
             </div>
             <div class="item-progress">
-              <span class="item-money" v-if="item.countMoney">{{moneyFormat(item.countMoney)}}</span>
-              <span class="item-money" v-if="item.money">{{moneyFormat(item.money)}}</span>
+              <span class="item-money" v-if="item.countMoney">{{ moneyFormat(item.countMoney) }}</span>
+              <span class="item-money" v-if="item.money">{{ moneyFormat(item.money) }}</span>
               <span class="item-progress-count active-progress" :style="{width: item.parent}"></span>
             </div>
           </div>
         </div>
+        <empty :images="require('@/assets/images/empty/jy-back.png')" v-else>
+          <div class="flex-c-c center">
+            <span>该时间范围暂无首次合作过的客户</span>
+          </div>
+        </empty>
+      </div>
     </div>
   </div>
 </template>
 <script>
 import { moneyUnit } from '@/utils/'
 import { mapState } from 'vuex'
+import Empty from '@/components/common/Empty.vue'
+
 export default {
   name: 'progess-chart',
+  components: {
+    Empty
+  },
   props: {
     type: String,
     // 传入的数据
@@ -52,30 +82,34 @@ export default {
     }
   },
   data () {
-    return {}
+    return {
+      showLabels: {}
+    }
   },
   computed: {
     ...mapState({
       info: state => state.user.info
     }),
     computedClientList () {
-      return this.datas.map((v) => {
-        v.topData = v.topData.filter((s) => {
-          return s.winnerName && s.winnerName.trim().length
-        })
-        return v
-      }).filter(function (v, i) {
+      return this.datas.filter(function (v, i) {
         return v.topData.length
       })
     }
   },
   watch: {},
-  mounted () {},
+  mounted () {
+  },
   methods: {
+    toggleShow (c, type) {
+      this.$set(this.showLabels, c.buyerclass, type)
+    },
     moneyFormat (money) {
       return moneyUnit(money)
     },
     goEntInfo (name) {
+      if (name === '') {
+        return
+      }
       window.open('/swordfish/page_big_pc/unit_portrayal/' + encodeURIComponent(name))
     },
     goEnt (id) {
@@ -90,57 +124,101 @@ export default {
 }
 </script>
 <style lang="scss" scoped>
-.client-list{
+.client-list {
   margin-top: 16px;
   background-color: #fff;
-  .c-thead{
+
+  .c-thead {
     display: flex;
     justify-content: space-between;
     align-items: center;
     line-height: 22px;
+    margin-top: 12px;
   }
-  .c-name,.item-name{
+
+  .c-name, .item-name {
     font-size: 14px;
     color: #1D1D1D;
     flex: 7;
   }
-  .item-name{
+
+  .item-name {
     cursor: pointer;
   }
+
   .no-href {
-    text-decoration: none!important;
+    text-decoration: none !important;
     cursor: auto;
   }
-  .c-count,.item-count,.c-time,.item-time{
+
+  .c-count, .item-count, .c-time, .item-time {
     flex: 1;
     min-width: 100px;
     font-size: 12px;
     text-align: center;
     white-space: nowrap;
   }
-  .c-rate,.item-rate{
+
+  .c-rate, .item-rate {
     font-size: 12px;
     text-align: center;
   }
-  .c-name{
-    font-weight: bold;
+
+  .c-top, .top-switch {
+    display: flex;
+    flex-direction: row;
     font-size: 16px;
-    line-height: 40px;
+    line-height: 24px;
+    height: 24px;
+    justify-content: space-between;
+  }
+
+  .top-switch {
+    font-size: 14px;
+    margin-right: 10px;
+  }
+
+  .top-switch div {
+    width: 100px;
+    height: 26px;
+    border-radius: 2px 2px 2px 2px;
+    text-align: center;
+    margin: 0 4px;
+    cursor: pointer;
+  }
+
+  .top-switch div.active {
+    background: #2CB7CA;
+    color: #FFFFFF;
+  }
+
+  .top-switch div:not(active) {
+    border: 1px solid #E0E0E0;
+    color: #1D1D1D;
+  }
+
+  .c-itemName {
+    font-weight: bold;
+
     color: #1D1D1D;
   }
-  .c-count,.c-rate,.c-time{
+
+  .c-count, .c-rate, .c-time, .c-name {
     color: #686868;
     white-space: nowrap;
   }
+
   .progress-bar-container {
     background-color: #fff;
   }
+
   .progress-bar-item {
     display: flex;
     flex-direction: column;
     justify-content: space-around;
     margin-bottom: 14px;
   }
+
   .item-label {
     display: flex;
     justify-content: space-between;
@@ -148,14 +226,17 @@ export default {
     line-height: 20px;
     padding-bottom: 6px;
   }
+
   .item-name {
     color: #171826;
     text-decoration: underline;
   }
+
   .item-count {
     font-size: 12px;
     color: #171826;
   }
+
   .item-progress {
     position: relative;
     height: 20px;
@@ -164,7 +245,8 @@ export default {
     border-radius: 0 10px 10px 0;
     overflow: hidden;
   }
-  .item-money{
+
+  .item-money {
     position: absolute;
     left: 16px;
     top: 50%;
@@ -173,6 +255,7 @@ export default {
     font-size: 14px;
     z-index: 10;
   }
+
   .item-progress-count {
     position: absolute;
     top: 0;
@@ -181,8 +264,13 @@ export default {
     border-radius: 0 10px 10px 0;
     z-index: 9;
   }
-  .active-progress{
+
+  .active-progress {
     background: #FAE7CA;
   }
+
+  .empty-container.mtb60 {
+    margin: 0 auto;
+  }
 }
 </style>

+ 67 - 17
src/components/collect-info/CollectInfo.vue

@@ -36,20 +36,20 @@
                       placeholder="请选择省份城市" clearable></el-cascader>
                   </el-form-item>
                 </div> -->
-                <div class="short-control fr" v-if="moduleShow.industry">
+                <!-- <div class="short-control fr" v-if="moduleShow.industry">
                   <el-form-item label="行业 :">
                     <el-cascader popper-class="custom-cascader" v-model="form.industry" class="data-short-input item-input" :options="industryData"
                       placeholder="请选择所属行业" :show-all-levels="false" clearable></el-cascader>
                   </el-form-item>
-                </div>
-                <div class="short-control fr" v-if="moduleShow.mold">
+                </div> -->
+                <!-- <div class="short-control fr" v-if="moduleShow.mold">
                   <el-form-item label="受雇类型 :">
                     <el-select v-model="form.mold" class="data-short-input item-input">
                       <el-option v-for="item in moldData" :key="item.value" :label="item.label" :value="item.value">
                       </el-option>
                     </el-select>
                   </el-form-item>
-                </div>
+                </div> -->
               </div>
             </div>
             <div class="company clearfix">
@@ -66,7 +66,7 @@
                       v-html="item"></div>
                   </div>
                 </div>
-                <div class="long-control" v-if="moduleShow.companyType">
+                <!-- <div class="long-control" v-if="moduleShow.companyType">
                   <el-form-item label="公司类型 :" class="company-type">
                     <el-checkbox-group v-model="form.companyType">
                       <el-checkbox label="投标企业"></el-checkbox>
@@ -78,7 +78,7 @@
                       <el-checkbox label="其他"></el-checkbox>
                     </el-checkbox-group>
                   </el-form-item>
-                </div>
+                </div> -->
                 <div class="long-control">
                   <el-form-item label="职位 :" prop="job">
                     <el-select popper-class="custom-select" v-model="form.job" placeholder="请选择职位" class="data-short-input item-input job-input" clearable>
@@ -98,24 +98,24 @@
                     </el-select>
                   </el-form-item>
                 </div>
-                <div class="long-control" v-if="moduleShow.scale">
+                <!-- <div class="long-control" v-if="moduleShow.scale">
                   <el-form-item label="公司规模 :">
                     <el-select v-model="form.scale" placeholder="请选择公司规模" class="data-short-input item-input" clearable>
                       <el-option v-for="item in scaleData" :key="item.value" :label="item.label" :value="item.value">
                       </el-option>
                     </el-select>
                   </el-form-item>
-                </div>
-                <div class="long-control" v-if="moduleShow.business">
+                </div> -->
+                <!-- <div class="long-control" v-if="moduleShow.business">
                   <el-form-item label="业务范围 :">
                     <el-input type="textarea" autosize resize="none" v-model="form.business" placeholder="请输入业务范围,让合作伙伴充分了解公司业务内容"></el-input>
                   </el-form-item>
-                </div>
-                <div class="long-control" v-if="moduleShow.need">
+                </div> -->
+                <!-- <div class="long-control" v-if="moduleShow.need">
                   <el-form-item label="合作需求 :">
                     <el-input type="textarea" autosize resize="none" v-model="form.need" placeholder="请输入合作需求,从而创造并匹配更多合作交流机会"></el-input>
                   </el-form-item>
-                </div>
+                </div> -->
               </div>
             </div>
             <div class="agree-service" v-if="moduleShow.agree">
@@ -146,6 +146,39 @@ import { industryJson, jobJson, companyScaleJson, branchJson } from '@/assets/js
 import { Form, FormItem, Button, CheckboxGroup, Checkbox, Select, Input, Option, Cascader } from 'element-ui'
 import { mapState } from 'vuex'
 import { debounce } from '@/utils/'
+/**
+ * 根据keys校验object必填项
+ * @param {Array} keys - 待校验字段keys
+ * @param {Object} target - 待校验object
+ * @returns {boolean} - 是否通过
+ */
+function checkRequiredKeys (keys, target) {
+  try {
+    // 职位/部门特殊处理, 满足时移除部门校验
+    if (keys.indexOf('branch') !== -1 && keys.indexOf('position') !== -1) {
+      if (target.position === '总裁' || target.position === '总经理') {
+        keys.splice(keys.indexOf('branch'), 1)
+      }
+    }
+    return !keys.some(function (k) {
+      var tempValue = target[k]
+      var result = false
+      if (typeof tempValue === 'number') {
+        tempValue = tempValue.toString()
+      }
+      if (typeof tempValue === 'string') {
+        result = tempValue.trim() !== ''
+      }
+      if (typeof tempValue === 'boolean') {
+        result = true
+      }
+      return !result
+    })
+  } catch (e) {
+    console.warn(e)
+    return false
+  }
+}
 /* eslint-disable */
 export default {
   name: 'collect-info',
@@ -317,6 +350,7 @@ export default {
         buyer_portrait_withAreaData_freeuser: '请留下联系方式,立即免费体验【采购单位全景分析】1次,帮你全面洞察采购单位,开发新客户!',
         buyer_portrait_topAgencyData_freeuser: '请留下联系方式,立即免费体验【采购单位全景分析】1次,帮你全面洞察采购单位,开发新客户!',
         buyer_portrait_contacts_freeuser: '请留下联系方式,立即免费体验【采购单位全景分析】1次,帮你全面洞察采购单位,开发新客户!',
+        buyer_portrait_firstShow_freeuser: '请留下联系方式,立即免费体验【采购单位全景分析】1次,帮你全面洞察采购单位,开发新客户!',
         ent_portrait_: '请留下联系方式,我们会尽快联系您!体验企业画像分析,帮你透视企业!',
         buyer_portrait_: '请留下联系方式,我们会尽快联系您!体验采购单位画像分析,为你挖掘客户!',
         member_attach: '请留下联系方式,我们会尽快联系您!体验附件下载特权,挖掘更多项目情报!',
@@ -409,7 +443,6 @@ export default {
     // 不需要调留资接口 弹出留资弹框回调方法
     noCallApiFn: function(source, isRefresh) {
       this.source = source
-      this.showForm = true
       this.calcTitleText(source)
       this.getOldInfo()
       this.isRefresh = isRefresh
@@ -423,7 +456,7 @@ export default {
           break
         }
       }
-      
+
       if (text) {
         if (source.indexOf('_freeuser') > -1 && text.indexOf('【') > -1) {
           var r = text.match(/\【(.+?)\】/g)
@@ -474,6 +507,13 @@ export default {
           source: source
         },
         success: function (res) {
+          // 判断当前信息否在其他页面留资  如果全部留资 直接弹窗提交成功
+          const result = checkRequiredKeys(['name', 'phone', 'company', 'branch', 'position'], res.info)
+          if (result) {
+            callback && callback()
+            return true
+          }
+
           if (res.data) {
             if (res.data.retainedCapital) {
               _this.showForm = true
@@ -537,8 +577,11 @@ export default {
       var _this = this
       $.ajax({
         type: 'POST',
-        url: '/salesLeads/echoInfo?t=' + Date.now(),
+        url: `/salesLeads/retainedCapital?source=${this.source}`,
         success: function (res) {
+          if (res && res.info) {
+            res.data = res.info
+          }
           if (res.data) {
             _this.form.name = res.data.name ? res.data.name : ''
             _this.form.phone = res.data.phone ? res.data.phone : ''
@@ -571,6 +614,13 @@ export default {
             _this.form.need = res.data.partnerNeeds ? res.data.partnerNeeds : ''
             _this.form.agreeChecked = res.data.agree === undefined ? true : res.data.agree
             _this.form.branch = res.data.branch
+            // 判断当前信息否在其他页面留资  如果全部留资 直接弹窗提交成功
+            const result = checkRequiredKeys(['name', 'phone', 'company', 'branch', 'position'], res.data)
+            if (result) {
+              _this.formAjax(_this.source)
+            } else {
+              _this.showForm = true
+            }
           }
         }
       })
@@ -822,8 +872,8 @@ export default {
     position: fixed;
     left: 50%;
     top: 50%;
-    width: 752px;
-    max-height: 680px;
+    width: 768px;
+    max-height: 780px;
     margin: 0 auto;
     padding: 32px;
     background: #fff;

+ 114 - 58
src/components/contact-info/ContactInfo.vue

@@ -1,17 +1,27 @@
 <template>
   <div class="contact" v-if="showContact">
-    <div class="d-title">{{titlename}}</div>
+    <div class="d-title" :class="{unit: titlename === '采购单位通讯录'}">{{ titlename }}</div>
     <div class="d-content">
-      <div class="d-list" v-for="item in currentShowList" :key="item.id">
-        <div class="d-title">{{item.projectname}}</div>
-        <div class="d-contact">
-          <p class="d-contact-list" v-for="(value, label, index) in item.contacts" :key="index">
-            <span class="c-list-name" v-if="value">联系人: {{value}}</span>
-            <span class="c-list-phone" v-if="label">联系方式:<em class="icon-phone">{{label}}</em></span>
-          </p>
-        </div>
-        <div class="deal-time" v-if="item.date">成交时间:{{item.date}}</div>
-      </div>
+      <table>
+        <thead>
+        <tr>
+          <td>序号</td>
+          <td>联系人</td>
+          <td>联系方式</td>
+          <td>关联项目</td>
+          <td>成交时间</td>
+        </tr>
+        </thead>
+        <tbody>
+        <tr v-for="(item,index) in currentShowList" :key="index">
+          <td>{{ (currentPage - 1) * pageSize + index + 1 }}</td>
+          <td><span v-if="item.persion">{{ item.persion }}</span></td>
+          <td><span v-if="item.contacts">{{ item.contacts }}</span></td>
+          <td><span  @click="toDetail(item.id)">{{ item.projectname }}</span></td>
+          <td><span>{{ item.date || '--' }}</span></td>
+        </tr>
+        </tbody>
+      </table>
       <div class="pages">
         <el-pagination
           background
@@ -30,6 +40,7 @@
 import { getBuyerHistoryContact, getWinnerHistoryContact, vipBuyerHistoryContact } from '@/api/modules/'
 import { Pagination } from 'element-ui'
 import { mapState } from 'vuex'
+
 export default {
   name: 'contact',
   components: {
@@ -65,7 +76,8 @@ export default {
   created () {
     this.getContactList()
   },
-  mounted () {},
+  mounted () {
+  },
   methods: {
     async getContactList () {
       const params = {}
@@ -107,71 +119,115 @@ export default {
     },
     handleCurrentChange (currentPage) {
       this.currentPage = currentPage
+    },
+    toDetail (id) {
+      window.open(`/article/content/${id}.html`)
     }
   }
 }
 </script>
 <style lang="scss" scoped>
-.contact{
+.contact {
   margin-top: 12px;
   background: #fff;
-  .d-title{
+  position: relative;
+
+  .d-title {
     margin-bottom: 16px;
     font-size: 18px;
     color: #1d1d1d;
     line-height: 28px;
   }
-  .d-list{
-    padding: 18px 0;
-    border-bottom: 1px solid #ECECEC;
-    .d-title{
-      font-size: 16px;
-      line-height: 24px;
-      color: #1D1D1D;
-    }
-    .d-info{
-      display: flex;
-      align-items: center;
-      justify-content: space-between;
-    }
-    .d-contact{
-      margin-top: 8px;
-    }
-    .d-contact-list{
-      display: flex;
-      align-items: center;
-      padding: 8px 24px;
-      background: #f9fafb;
-      border-radius: 4px;
-      font-size: 12px;
-      color: #686868;
-      line-height: 20px;
-      .c-list-name{
-        min-width: 80px;
-        margin-right: 32px;
+  .d-title.unit::after{
+    left: 0;
+  }
+  .d-title::after{
+    content: "";
+    position: absolute;
+    left: -32px;
+    width: 3px;
+    height: 24px;
+    background: #2cb7ca;
+    border-radius: 0px 2px 2px 0px;
+  }
+  .d-content {
+    margin-top: 8px;
+
+    table {
+      border-right: 1px solid #ECECEC;
+      border-bottom: 1px solid #ECECEC;
+
+      td {
+        border-left: 1px solid #ECECEC;
+        border-top: 1px solid #ECECEC;
+        border-spacing: 0;
+        text-align: center;
       }
-      .c-list-phone{
-        display: flex;
-        align-items: center;
+
+      thead tr {
+        td {
+          height: 48px;
+          font-weight: 400;
+          line-height: 48px;
+          font-size: 14px;
+          background: #F9FAFB;
+          color: #686868;
+        }
+
+        td:nth-child(1) {
+          width: 60px;
+        }
+
+        td:nth-child(2) {
+          width: 90px;
+        }
+
+        td:nth-child(3) {
+          width: 150px;
+        }
+
+        td:nth-child(4) {
+          width: 430px;
+        }
+
+        td:nth-child(5) {
+          width: 110px;
+        }
       }
-      .icon-phone{
-        display: inline-block;
-        padding-left: 18px;
-        background: url('~@/assets/images/icon/icon-tel.png') no-repeat center left;
-        background-size: 16px 16px;
-        color: #2CB7CA;
+
+      tbody tr {
+        td {
+          height: 22px;
+          font-size: 14px;
+          font-weight: 400;
+          color: #1D1D1D;
+          line-height: 22px;
+          padding: 13px;
+          display: table-cell;
+          vertical-align: middle;
+          cursor: pointer;
+        }
+
+        td:nth-child(3) {
+          color: #2CB7CA;
+        }
+
+        td:nth-child(4) {
+          text-align: left;
+        }
+
+        td:nth-child(5) {
+          word-break: keep-all;
+          white-space: nowrap;
+        }
       }
     }
-    .deal-time{
-      padding: 16px 24px 0;
-      color: #686868;
-      font-size: 12px;
-      line-height: 20px;
-    }
   }
-  .pages{
+
+  .pages {
     margin-top: 16px;
     text-align: center;
   }
+
 }
 </style>

+ 36 - 16
src/components/forecast/ForeCast.vue

@@ -82,26 +82,31 @@
         <span style="width:100px;">操作</span>
       </div>
       <ul class="listData_ul" :style="{'padding-bottom': getShowPagination?'': '48px'}">
-        <li class="list_li" style="padding:24px 0 26px;display:flex;align-items: center;cursor: default;" v-for="(item, index) in getMyData.listState.list" :key="index">
+        <li
+          class="list_li"
+          style="padding:24px 0 26px;display:flex;align-items: center;cursor: default;"
+          :class="{ visited: item.visited }"
+          v-for="(item, index) in getMyData.listState.list"
+          :key="index">
           <div style="padding: 0 12px;width:810px;cursor: pointer" @click="goViewEnt(item.s_entId, item)">
-            <div class="list_name ent_li_name">{{item.s_entname}}<span class="red_point" v-if="item.i_apppushunread == 1"></span>
+            <div class="list_name ent_li_name visited-hd">{{item.s_entname}}<span class="red_point" v-if="item.i_apppushunread == 1"></span>
             </div>
             <div class="list_unit">
               <div class="pur_unit">
                 <span class="unit_label">成立日期:</span>
-                <span class="unit_name entname">{{item.l_establishdate?dateFormatter(item.l_establishdate*1000, 'yyyy-MM-dd'):'--'}}</span>
+                <span class="unit_name entname visited-ft">{{item.l_establishdate?dateFormatter(item.l_establishdate*1000, 'yyyy-MM-dd'):'--'}}</span>
               </div>
               <div class="pur_unit">
                 <span class="unit_label">注册资本:</span>
-                <span class="unit_name entname">{{item.f_capital?moneyUnit(item.f_capital*10000):'--'}}</span>
+                <span class="unit_name entname visited-ft">{{item.f_capital?moneyUnit(item.f_capital*10000):'--'}}</span>
               </div>
               <div class="pur_unit">
                 <span class="unit_label">企业地址:</span>
-                <span class="unit_name entname">{{item.s_area?item.s_area:'--'}}{{item.s_city?item.s_city:''}}</span>
+                <span class="unit_name entname visited-ft">{{item.s_area?item.s_area:'--'}}{{item.s_city?item.s_city:''}}</span>
               </div>
               <div class="pur_unit">
                 <span class="unit_label">企业联系方式:</span>
-                <span class="unit_name entname">{{item.s_phone?item.s_phone:'--'}}</span>
+                <span class="unit_name entname visited-ft">{{item.s_phone?item.s_phone:'--'}}</span>
               </div>
             </div>
           </div>
@@ -266,7 +271,7 @@
 <script>
 import { Pagination, Progress, Message, Tooltip, Dialog, Button } from 'element-ui'
 import { mapState } from 'vuex'
-// import { getPushList } from '@/api/modules/'
+import { mixinVisited } from '@/utils/mixins/visited'
 import Empty from '@/components/common/Empty.vue'
 import GroupCard from '@/components/selector/GroupSelector.vue'
 import { moneyUnit, dateFormatter } from '@/utils'
@@ -274,6 +279,7 @@ import { setFollowEnt, setCancelEnt, changeEntGroup } from '@/api/modules'
 export default {
   props: ['type', 'title', 'mydata', 'myDataObj', 'resData', 'myPolicydata', 'potenObj', 'potenResult', 'entSearch', 'entSearchRes'],
   name: 'listData',
+  mixins: [mixinVisited],
   components: {
     [Pagination.name]: Pagination,
     [Progress.name]: Progress,
@@ -337,7 +343,18 @@ export default {
   },
   watch: {
     'myDataObj.list' (newVal) {
-      this.getMyData.listState.list = newVal
+      this.getMyData.listState.list = newVal.map(item => {
+        const visited = this.pathVisited(
+          this.createPathItem(
+            '/ent_portrait/*',
+            `id=${item.s_entId}`
+          )
+        )
+        return {
+          ...item,
+          visited
+        }
+      })
       this.getEntListTips()
     },
     mydata (newVal, oldVal) {
@@ -486,12 +503,6 @@ export default {
     // 企业搜索
     entSearchData (list) {
       if (list && list.length !== 0) {
-        // const that = this
-        // list.forEach(function (item) {
-        //   console.log(that.getFollow(item.s_id))
-        //   // let isfollow = that.getFollow(item.s_id)
-        //   // item.isentFollow = isfollow
-        // })
         this.listState.list = list
         this.listState.total = list.length
       } else {
@@ -580,6 +591,15 @@ export default {
       if (item.i_apppushunread) {
         item.i_apppushunread = null
       }
+      if (this.type === 'entintel') {
+        item.visited = true
+        this.pathVisiting(
+          this.createPathItem(
+            '/ent_portrait/*',
+            `id=${id}`
+          )
+        )
+      }
       const routeUrl = this.$router.resolve({
         path: `/ent_portrait/${id}`
       })
@@ -705,10 +725,10 @@ export default {
       location.href = '/jylab/entSearch/index.html'
     },
     getEntListTips () {
-      if (!this.myDataObj.match && !this.myDataObj.group && this.myDataObj.initTotal === 0) {
+      if (this.myDataObj && !this.myDataObj.match && !this.myDataObj.group && this.myDataObj.initTotal === 0) {
         this.tips = '暂无企业情报信息,前往企业搜索关注企业'
         this.tipimages = require('@/assets/images/empty/jy-back.png')
-      } else if (this.myDataObj.list.length === 0 && this.myDataObj.initTotal !== 0) {
+      } else if (this.myDataObj && this.myDataObj.list.length === 0 && this.myDataObj.initTotal !== 0) {
         this.tips = '暂无匹配数据'
         this.tipimages = require('@/assets/images/empty/jy-back.png')
       }

+ 14 - 5
src/components/home/HomeList.vue

@@ -10,21 +10,30 @@
       </div>
     </div>
     <div class="h-content" v-loading="loading" v-if="!reportModule && getlist.length !== 0  && model !== 'model-4'">
-      <div class="h-content-l" :class="getlist.length-1===index&&getlist.length>=5?'lastLine':''" v-for="(item, index) in getlist" :key="index">
-        <div class="h-title-l" @click="getDetail(item)">{{item.projectName}}<span class="red-spot" v-if="spotRedShow && item.unread && item.unread !== 0"></span></div>
+      <div
+        class="h-content-l hover"
+        :class="{ lastLine: getlist.length - 1 === index && getlist.length >= 5, visited: item.visited }"
+        v-for="(item, index) in getlist" :key="index">
+        <div class="h-title-l visited-hd hover" @click="getDetail(item)">{{item.projectName}}<span class="red-spot" v-if="spotRedShow && item.unread && item.unread !== 0"></span></div>
         <div class="h-time-r">{{dateFormatter(item.publishtime*1000, 'yyyy-MM-dd')}}</div>
       </div>
     </div>
     <div class="h-content" v-loading="loading"  v-if="!reportModule && getlist.length !== 0 && model === 'model-4'">
       <PoverTimeLine @show="thisAnnouncement(item)" v-for="(item, index) in getlist" :key="index" :stepList="item.stepList" poperWidth="470">
-        <div class="h-content-l" :class="getlist.length-1===index&&getlist.length>=5?'lastLine':''" slot="content">
-          <div class="h-title-l" @click="getDetail(item)">{{item.projectName}}<span class="red-spot" v-if="spotRedShow && item.unread && item.unread !== 0"></span></div>
+        <div
+          class="h-content-l"
+          :class="{ lastLine: getlist.length - 1 === index && getlist.length >= 5, visited: item.visited }"
+          slot="content">
+          <div class="h-title-l visited-hd hover" @click="getDetail(item)">{{item.projectName}}<span class="red-spot" v-if="spotRedShow && item.unread && item.unread !== 0"></span></div>
           <div class="h-time-r">{{dateFormatter(item.publishtime*1000, 'yyyy-MM-dd')}}</div>
         </div>
       </PoverTimeLine>
     </div>
     <div class="h-content report-content" v-loading="loading" v-if="reportModule && getlist.length !== 0">
-      <div class="h-content-l" v-for="(item, index) in getlist" :key="index">
+      <div
+        class="h-content-l"
+        v-for="(item, index) in getlist"
+        :key="index">
         <div class="h-title-l r-title-l" @click="getDetail(item)">
           <span class="report-round" :class="timeSection==='周'?'yellow':'blue'">{{timeSection}}</span>
           <span>{{dateFormatter(item.startdate*1000, 'MM月dd日')}}-{{dateFormatter(item.enddate*1000, 'MM月dd日')}}</span>

+ 11 - 4
src/components/mask-card/MaskCard.vue

@@ -1,10 +1,7 @@
 <template>
   <div class="upgrade-mask-group">
-    <div v-if="k === '项目动态'" style="padding: 32px 40px 0px;margin: 40px 0 32px;">
-      <slot></slot>
-    </div>
     <div>
-      <h6>{{k}}</h6>
+      <h6 :class="{hasLeftBlue: k==='采购单位通讯录 '}">{{k}}</h6>
       <img class="upgrade-mask-bg" :src="item.bg" :alt="k">
       <div class="flex-c-c center upgrade-module-group">
         <div class="module-img-card">
@@ -50,6 +47,16 @@ export default {
       margin-bottom: 16px;
       margin-left: 40px;
     }
+
+    .hasLeftBlue::after{
+      content: "";
+      position: absolute;
+      left: 0px;
+      width: 3px;
+      height: 24px;
+      background: #2cb7ca;
+      border-radius: 0px 2px 2px 0px;
+    }
     .upgrade-mask-bg {
       width: 100%;
       height: auto;

+ 45 - 3
src/components/push-list/ProjectProgressList.vue

@@ -14,7 +14,7 @@
         @show="thisAnnouncement(item)">
         <template v-slot:content>
           <article-item
-            :class="item.i_apppushunread !== 0 && item.i_apppushunread? 'item_class' : ''"
+            :class="{ item_class: item.i_apppushunread !== 0 && item.i_apppushunread, visited: item.visited }"
             :index="(listState.pageSize * (listState.pageNum - 1)) +  index + 1"
             :article="sortItemInfo(item)"
             @onClick="toDetail(item, index)"
@@ -56,9 +56,11 @@ import Empty from '@/components/common/Empty.vue'
 import ArticleItem from '@/components/article-item/ArticleItem.vue'
 import { dateFromNow, dateFormatter, replaceKeyword } from '@/utils/'
 import { getFollowProjectList, setFollowRemove30Day, showAnnouncement } from '@/api/modules/'
+import { mixinVisited } from '@/utils/mixins/visited'
 import PoverTimeLine from '@/components/time-line/PoverTimeLine.vue'
 export default {
   name: 'project-list',
+  mixins: [mixinVisited],
   components: {
     [Pagination.name]: Pagination,
     [Card.name]: Card,
@@ -148,7 +150,18 @@ export default {
       const start = this.listState.pageSize * (this.listState.pageNum - 1)
       const end = this.listState.pageSize * this.listState.pageNum
       thisList = this.thisDataList.slice(start, end)
-      this.listState.list = thisList
+      this.listState.list = thisList.map(item => {
+        const visited = this.pathVisited(
+          this.createPathItem(
+            '/pro_follow_detail/*',
+            `id=${item.sid}`
+          )
+        )
+        return {
+          ...item,
+          visited
+        }
+      })
     },
     areaItem (name) {
       this.activeArea = name
@@ -157,7 +170,18 @@ export default {
       const start = this.listState.pageSize * (this.listState.pageNum - 1)
       const end = this.listState.pageSize * this.listState.pageNum
       thisList = this.thisDataList.slice(start, end)
-      this.listState.list = thisList
+      this.listState.list = thisList.map(item => {
+        const visited = this.pathVisited(
+          this.createPathItem(
+            '/pro_follow_detail/*',
+            `id=${item.sid}`
+          )
+        )
+        return {
+          ...item,
+          visited
+        }
+      })
     }
   },
   methods: {
@@ -221,6 +245,17 @@ export default {
 
       if (res.error_code === 0) {
         this.listState.total = res.data.total
+        if (Array.isArray(res.data.List)) {
+          res.data.List.forEach(item => {
+            const visited = this.pathVisited(
+              this.createPathItem(
+                '/pro_follow_detail/*',
+                `id=${item.sid}`
+              )
+            )
+            this.$set(item, 'visited', visited)
+          })
+        }
         this.listState.list = res.data.List || []
       } else {
         this.listState.total = 0
@@ -229,6 +264,13 @@ export default {
     },
     toDetail (item, index) {
       const { sid, fid } = item
+      item.visited = true
+      this.pathVisiting(
+        this.createPathItem(
+          '/pro_follow_detail/*',
+          `id=${sid}`
+        )
+      )
       const link = this.$router.resolve({
         path: '/pro_follow_detail',
         query: {

+ 22 - 2
src/components/push-list/PushList.vue

@@ -31,6 +31,7 @@
       <article-item
         class="list-item"
         v-for="(item, index) in listState.list"
+        :class="{ visited: item.visited }"
         :key="index"
         :index="(listState.pageSize * (listState.pageNum - 1)) +  index + 1"
         :article="item"
@@ -67,7 +68,7 @@
         </tr>
         </thead>
         <tbody>
-        <tr v-for="(item, index) in tableList" :key="index + '_' + item._id" @click="toDetail(item)">
+        <tr v-for="(item, index) in tableList" :class="{ visited: item.visited }" :key="index + '_' + item._id" @click="toDetail(item)">
           <td width="48">{{ index + 1 }}</td>
           <td width="315" class="tt-l" v-html="calcTitle(item, index)"></td>
           <td width="84">{{ item.type }}</td>
@@ -131,9 +132,11 @@ import Empty from '@/components/common/Empty.vue'
 import ArticleItem from '@/components/article-item/ArticleItem.vue'
 import { getPushList, getExportPushList } from '@/api/modules/'
 import { moneyUnit, dateFromNow, replaceKeyword } from '@/utils/'
+import { mixinVisited } from '@/utils/mixins/visited'
 /* eslint-disable */
 export default {
   name: 'push-list',
+  mixins: [mixinVisited],
   components: {
     [Pagination.name]: Pagination,
     [Card.name]: Card,
@@ -326,7 +329,17 @@ export default {
       const res = await getPushList(query)
       this.listState.loading = false
       this.listState.loaded = true
-      console.log(res, 'res')
+      if (Array.isArray(res.data)) {
+        res.data.forEach(item => {
+          const visited = this.pathVisited(
+            this.createPathItem(
+              '/article/content/*.html',
+              `id=${item._id}`
+            )
+          )
+          this.$set(item, 'visited', visited)
+        })
+      }
       if (query.pageNum === 1) {
         this.tableList = res.data || []
       }
@@ -343,6 +356,13 @@ export default {
     },
     toDetail (item) {
       const { _id } = item
+      item.visited = true
+      this.pathVisiting(
+        this.createPathItem(
+          '/article/content/*.html',
+          `id=${_id}`
+        )
+      )
       window.open(`/article/content/${_id}.html`)
     },
     onPageChange (p) {

+ 1 - 0
src/main.js

@@ -18,6 +18,7 @@ Vue.use(Toast)
 Vue.prototype.$message = Message
 Vue.prototype.$echarts = echarts
 Vue.prototype.$alert = MessageBox.alert
+Vue.prototype.$confirm = MessageBox.confirm
 Vue.config.productionTip = false
 
 // 正式环境下屏蔽console.log

+ 17 - 1
src/store/user.js

@@ -19,7 +19,9 @@ export default {
     // 业务范围是否全部删除
     isDeleteAllScope: defaultLocalPageData('bigmember-login-clear-DELETE_SCOPE', false),
     // 采购内容是否全部删除
-    isDeleteAllBuyClass: defaultLocalPageData('bigmember-login-clear-DELETE_BUY_CLASS', false)
+    isDeleteAllBuyClass: defaultLocalPageData('bigmember-login-clear-DELETE_BUY_CLASS', false),
+    // 用户访问灰显记录列表
+    visitedList: defaultLocalPageData('visited-path-list', [])
   }),
   mutations: {
     setUserInfo (state, info) {
@@ -54,6 +56,20 @@ export default {
     clearBuyClass (state, data) {
       state.isDeleteAllScope = data
       localStorage.setItem('bigmember-login-clear-DELETE_BUY_CLASS', data)
+    },
+    refreshVisited (state) {
+      const expiresTime = 3 * 24 * 60 * 60 * 1000
+      const now = Date.now()
+      const list = JSON.parse(localStorage.getItem('visited-path-list')) || []
+      state.visitedList = list.filter(item => {
+        return now - item.timestamp <= expiresTime
+      })
+      localStorage.setItem('visited-path-list', JSON.stringify(state.visitedList))
+    },
+    // 访问添加 visitedList
+    addVisited (state, list) {
+      state.visitedList = list
+      localStorage.setItem('visited-path-list', JSON.stringify(state.visitedList))
     }
   },
   actions: {

+ 28 - 0
src/utils/functions/syncSessionStorage.js

@@ -0,0 +1,28 @@
+const syncKey = 'syncSessionStorage'
+const sessKey = 'sessionStorage'
+// 实时同步 sessionStorage 的 key
+const syncKeyList = ['visited-path-list']
+
+// 新打开一个tab标签页并通知其他标签页同步sessionStorage的数据到本标签页
+if (!sessionStorage.length) {
+  // 这个调用能触发storage事件,从而达到共享数据的目的
+  localStorage.setItem(syncKey, Date.now())
+}
+
+window.addEventListener('storage', function (e) {
+  if (e.key === syncKey) {
+    // 已存在的标签页会收到这个事件
+    localStorage.setItem(sessKey, JSON.stringify(sessionStorage))
+    localStorage.removeItem(sessKey)
+  } else if (e.key === sessKey && !sessionStorage.length) {
+    // 新开启的标签页会收到这个事件
+    const data = JSON.parse(e.newValue)
+    for (const k in data) {
+      sessionStorage.setItem(k, data[k])
+    }
+  } else if (syncKeyList.indexOf(e.key) !== -1) {
+    // if (e.newValue) {
+    //   sessionStorage.setItem(e.key, e.newValue)
+    // }
+  }
+})

+ 1 - 1
src/utils/globalFunctions.js

@@ -274,7 +274,7 @@ export function formatSize (size, pointLength, units) {
 // 金额类型转换
 export function moneyUnit (m, type = 'string', lv = 0) {
   const mUnit = {
-    levelArr: ['元', '万', '亿', '万亿'],
+    levelArr: ['元', '万', '亿', '万亿'],
     test (num, type, lv) {
       if (num === 0) {
         if (type === 'string') {

+ 1 - 0
src/utils/index.js

@@ -1,4 +1,5 @@
 import './globalDirectives'
 import './globalFilters'
+import './functions/syncSessionStorage'
 
 export * from './globalFunctions'

+ 0 - 0
src/utils/mixins.js → src/utils/mixins/index.js


+ 69 - 0
src/utils/mixins/visited.js

@@ -0,0 +1,69 @@
+import { mapState } from 'vuex'
+
+class VisitedPathItem {
+  constructor (path, search) {
+    this.path = path
+    this.search = search
+    this.timestamp = Date.now()
+  }
+}
+
+export const mixinVisited = {
+  computed: {
+    ...mapState({
+      visitedList: state => state.user.visitedList
+    })
+  },
+  created () {
+    this.$store.commit('user/refreshVisited')
+  },
+  methods: {
+    createPathItem (path, search) {
+      return new VisitedPathItem(path, search)
+    },
+    // 从判断 path 是否访问过
+    // 参数path为 VisitedPathItem new 出来的实例
+    pathVisitedIndex (path) {
+      const list = this.visitedList
+      let sameIndex = -1
+      if (list) {
+        for (let i = 0; i < list.length; i++) {
+          const same = this.comparePath(list[i], path)
+          if (same) {
+            sameIndex = i
+            break
+          }
+        }
+      }
+      return sameIndex
+    },
+    comparePath (basePath, newPath) {
+      const pathSame = basePath.path === newPath.path
+      const searchSame = basePath.search === newPath.search
+
+      return pathSame && searchSame
+    },
+    pathVisited (path) {
+      return this.pathVisitedIndex(path) !== -1
+    },
+    // 保存一条历史
+    // 参数path为 VisitedPathItem new出来的实例
+    pathVisiting (path) {
+      if (!path) return
+      // 判断是否重复
+      const index = this.pathVisitedIndex(path)
+      const visitedList = JSON.parse(JSON.stringify(this.visitedList))
+      if (index >= 0) {
+        // 已存在
+        const itemArr = visitedList.splice(index, 1)
+        const item = itemArr[0]
+        item.timestamp = Date.now()
+        visitedList.unshift(item)
+      } else {
+        visitedList.unshift(path)
+      }
+      // 全量替换
+      this.$store.commit('user/addVisited', visitedList)
+    }
+  }
+}

+ 2 - 2
src/views/bid-forecast/BidForecastLimit.vue

@@ -218,7 +218,7 @@ export default {
       if (getcity.length !== 0) {
         aloneCity = getcity[0]
       } else {
-        aloneCity = ''
+        aloneCity = Object.keys(data.area)[0] + ''
       }
       const item = {
         appVersion: '',
@@ -236,7 +236,7 @@ export default {
       const res = await getForWData(item)
       if (res.error_code === 0) {
         // -1:预测失败;0:默认;1:有未查看得预测数据并返回id;2:正在预测中
-        if (res.data.status === 1) {
+        if (res.data.status === 1 || res.data.status === 3) {
           this.fid = res.data.id
           this.getProForWResult(res.data.id)
         } else if (res.data.status === 2) {

+ 23 - 5
src/views/ent-intel/MyClient.vue

@@ -27,18 +27,19 @@
             </div>
             <div class="l-tbody" v-loading="loading" element-loading-background="#fff" v-if="client.list && client.list.length > 0">
               <ul class="items">
-                <li class="item" v-for="(item, index) in client.list" :key="'00' + index">
+                <li class="item" :class="{ visited: item.visited }" v-for="(item, index) in client.list" :key="'00' + index">
                   <div class="item-info w-800">
-                    <div class="info-name" @click="goUnit(item.name)">{{item.name}}</div>
+                    <div class="info-name visited-hd" @click="goUnit(item)">{{item.name}}</div>
                     <div class="info-other">
                       <span class="other-list" v-if="item.province">
                         <i class="area-icon"></i>
-                        <em class="text-label">所在地:</em>{{item.province}}
+                        <em class="text-label">所在地:</em>
+                        <span class="visited-ft">{{item.province}}</span>
                       </span>
                       <span class="other-list" v-if="item.buyerclass">
                         <i class="type-icon"></i>
                         <em class="text-label">采购单位类型:</em>
-                        {{item.buyerclass}}
+                        <span class="visited-ft">{{item.buyerclass}}</span>
                       </span>
                     </div>
                   </div>
@@ -83,10 +84,12 @@ import { Input, Button, Pagination } from 'element-ui'
 import forLayOut from '@/components/forecast/ForLayout.vue'
 import TabHeader from '@/components/common/TabHeader.vue'
 import Empty from '@/components/common/Empty.vue'
+import { mixinVisited } from '@/utils/mixins/visited'
 import { mapState } from 'vuex'
 import { followClientList, setStatusCustomer } from '@/api/modules'
 export default {
   name: 'ent-intel',
+  mixins: [mixinVisited],
   components: {
     [Input.name]: Input,
     [Button.name]: Button,
@@ -142,6 +145,13 @@ export default {
             if (v.followdate) {
               v.followdate = v.followdate.replace(/\//g, '-')
             }
+            const visited = this.pathVisited(
+              this.createPathItem(
+                '/unit_portrayal/*',
+                `id=${v.name}`
+              )
+            )
+            this.$set(v, 'visited', visited)
           })
           this.client.list = res.data.list
           this.client.total = res.data.count
@@ -165,7 +175,15 @@ export default {
     clearHandle () {
       this.getClientList()
     },
-    goUnit (name) {
+    goUnit (item) {
+      var name = item.name
+      item.visited = true
+      this.pathVisiting(
+        this.createPathItem(
+          '/unit_portrayal/*',
+          `id=${item.name}`
+        )
+      )
       const routeUrl = this.$router.resolve({
         path: `/unit_portrayal/${name}`
       })

+ 131 - 110
src/views/portrayal/EntPortrayal.vue

@@ -1,10 +1,10 @@
 <template>
   <Layout class="ent-portrayal">
     <div class="ent-header">
-      <div class="name">{{entName}}</div>
+      <div class="name">{{ entName }}</div>
       <div class="ent_follow" @click="setFollow()">
         <span :class="follow.classActive"></span>
-        <span class="follow_text">{{follow.text}}</span>
+        <span class="follow_text">{{ follow.text }}</span>
       </div>
     </div>
     <!-- 关注分组选择dialog -->
@@ -29,49 +29,54 @@
         <a :class="[activeName == '2' ? 'active' : '']" @click="handleClick('2')">中标信息</a>
       </div>
       <div class="tab-content" style="padding:0 32px 40px;">
-          <div id="entInfo" class="tab-content-item">
-            <!-- 占位dom 解决锚点tab有fixed定位 scrollview位置会偏移 -->
-            <div v-show="navFixed" style="height:80px;"></div>
-            <EntForm :id="eId" @entname="entname"></EntForm>
-            <EntHistoryForm v-if="showConf12" :id="eId" key="history"></EntHistoryForm>
-            <div v-else key="history">
-              <MaskCard @click="openBigPage(EntHistoryTip)" k="企业情报历史记录" :item="EntHistoryTip"></MaskCard>
-            </div>
-            <ContactList v-if="showContact" name="winner" titlename="企业通讯录"></ContactList>
-            <MaskCard v-if="!showContact" @click="openBigPage(EntHistoryTip)" k="企业情报历史记录" :item="EntHistoryTip"></MaskCard>
+        <div id="entInfo" class="tab-content-item">
+          <!-- 占位dom 解决锚点tab有fixed定位 scrollview位置会偏移 -->
+          <div v-show="navFixed" style="height:80px;"></div>
+          <EntForm :id="eId" @entname="entname"></EntForm>
+          <EntHistoryForm v-if="showConf12" :id="eId" key="history"></EntHistoryForm>
+          <div v-else key="history">
+            <MaskCard @click="openBigPage(EntHistoryTip)" k="企业情报历史记录" :item="EntHistoryTip"></MaskCard>
           </div>
-          <div id="chartInfo" class="tab-content-item">
-            <!-- 占位dom 解决锚点tab有fixed定位 scrollview位置会偏移 同时作为tab1和tab2的间距 -->
-            <div style="height:80px;"></div>
-            <div>
-              <div class="bidcomp">
-                <BidInfoActive whichPor="entpor" @onPageChange="onLimitChange" :canselect="canSelect" title="中标信息"></BidInfoActive>
-              </div>
-              <div class="pro_info" v-if="!emptyShow">
-                <ul class="pro_info_ul">
-                  <li class="pro_list" v-for="(item, index) in proData" :key="index">
-                    <div class="pro_li_con">{{item.count}}</div>
-                    <div class="pro_li_label">{{item.label}}</div>
-                  </li>
-                </ul>
-                <div v-if="isConf4" class="pro_info_tip">数据统计范围:{{dateRange.start}}-{{dateRange.end}}</div>
-              </div>
-              <div :style="{margin: !isConf4 ? '40px 40px 0' : '64px 0 0'}" v-if="showConf13 && !emptyShow">
-                <ProActive :isactive="isActive" ref="myList" title="项目动态" @onPageChange="getProActivcList" :screenList="ScreenList" :projectData="project"></ProActive>
-              </div>
-              <ent-chart @showEmpty="showEmpty" @loadingChart="loadingChart" :params="bidInfoParams" v-on:entInfo="getEntInfo"></ent-chart>
-              <!-- 遮罩主要是商机版、自定义版没有画像权限的用户显示 -->
-              <div v-if="!isConf4 && !emptyShow">
-                <MaskCard @click="openBigPage(item)" v-for="(item, k) in getVipUpgradeMap" :key="k + item.button + item.title" :k="k" :item="item"></MaskCard>
-              </div>
-              <Empty v-show="emptyShow" :images="require('@/assets/images/empty/jy-chagrin.png')">
-                <div slot="default" style="text-align:center">
-                  <span>对不起,没有匹配到相关信息,</span><br/>
-                  <span>修改时间范围或换个搜索词试试吧</span>
-                </div>
-              </Empty>
+          <ContactList v-if="showContact" name="winner" titlename="企业通讯录"></ContactList>
+          <MaskCard v-if="!showContact" @click="openBigPage(EntHistoryTip)" k="企业情报历史记录"
+                    :item="EntHistoryTip"></MaskCard>
+        </div>
+        <div id="chartInfo" class="tab-content-item">
+          <!-- 占位dom 解决锚点tab有fixed定位 scrollview位置会偏移 同时作为tab1和tab2的间距 -->
+          <div style="height:80px;"></div>
+          <div>
+            <div class="bidcomp">
+              <BidInfoActive whichPor="entpor" @onPageChange="onLimitChange" :canselect="canSelect" title="中标信息"></BidInfoActive>
             </div>
+            <div class="pro_info" v-if="!emptyShow">
+              <ul class="pro_info_ul">
+                <li class="pro_list" v-for="(item, index) in proData" :key="index">
+                  <div class="pro_li_con">{{ item.count }}</div>
+                  <div class="pro_li_label">{{ item.label }}</div>
+                </li>
+              </ul>
+              <div class="pro_info_tip">数据统计范围:{{ dateRange.start }}-{{ dateRange.end }}</div>
+            </div>
+            <div :style="{margin: !isConf4 ? '40px 40px 0' : '64px 0 0'}" v-show="showConf13 && !emptyShow">
+              <Dynamic-list :key="dynamicKey" :filters="ScreenParams"
+                            :config="{baseParam:{entId: decodeURIComponent(this.$route.params.eId)},isWinner:true}"
+                            style="width: 856px"></Dynamic-list>
+            </div>
+            <ent-chart @showEmpty="showEmpty"  v-show="!emptyShow" @loadingChart="loadingChart" :params="bidInfoParams"
+                       v-on:entInfo="getEntInfo"></ent-chart>
+            <!-- 遮罩主要是商机版、自定义版没有画像权限的用户显示 -->
+            <div v-if="!isConf4 && !emptyShow">
+              <MaskCard @click="openBigPage(item)" v-for="(item, k) in getVipUpgradeMap"
+                        :key="k + item.button + item.title" :k="k" :item="item"></MaskCard>
+            </div>
+            <Empty v-show="emptyShow" :images="require('@/assets/images/empty/jy-chagrin.png')">
+              <div slot="default" style="text-align:center">
+                <span>对不起,没有匹配到相关信息,</span><br/>
+                <span>修改时间范围或换个搜索词试试吧</span>
+              </div>
+            </Empty>
           </div>
+        </div>
       </div>
     </div>
   </Layout>
@@ -81,19 +86,21 @@ import EntChart from './components/EntChart'
 import EntForm from './components/EntForm'
 import EntHistoryForm from './components/EntHistoryForm'
 import Layout from '@/components/common/ContentLayout.vue'
-import ProActive from './components/ProActive'
 import BidInfoActive from './components/BidInfoActive'
 import ContactList from '@/components/contact-info/ContactInfo'
 import MaskCard from '@/components/mask-card/MaskCard.vue'
 import GroupSelector from '@/components/selector/GroupSelector.vue'
 import Empty from '@/components/common/Empty'
+import DynamicList from './components/DynamicList'
 import { mapState } from 'vuex'
-import { Tabs, TabPane, Input, Dialog } from 'element-ui'
-import { moneyUnit, dateFormatter } from '@/utils'
-import { setFollowEnt, setCancelEnt, getNewMsg, getfollowCheck, getEntWinnerSelect } from '@/api/modules'
+import { Dialog, Input, TabPane, Tabs } from 'element-ui'
+import { dateFormatter, moneyUnit } from '@/utils'
+import { getEntWinnerSelect, getfollowCheck, setCancelEnt, setFollowEnt } from '@/api/modules'
+
 function getImgForVipUpgrade (name, bg = false, suffix = '.png') {
   return require('@/assets/images/vip/' + (bg ? 'bg/mask/' : '') + name + suffix)
 }
+
 export default {
   name: 'ent-portrayal',
   components: {
@@ -105,18 +112,19 @@ export default {
     EntForm,
     EntHistoryForm,
     Layout,
-    ProActive,
     BidInfoActive,
     ContactList,
     MaskCard,
     GroupSelector,
-    Empty
+    Empty,
+    DynamicList
   },
   data () {
     return {
       loading: false,
       activeName: '1',
       proData: [],
+      dynamicKey: new Date().getTime(), // 筛选重新渲染动态数据
       project: {
         proActiveList: [],
         count: 0
@@ -145,7 +153,7 @@ export default {
       vipUpgradeMap: {
         企业通讯录: {
           title: '开通大会员',
-          subtitle: '获取企业通讯录信息,直接与甲方或渠道商项目负责人对接!',
+          subtitle: '获取企业联系人信息,一键拨打!',
           button: '免费体验',
           source: 'ent_portrait_contacts',
           img: getImgForVipUpgrade('010'),
@@ -191,7 +199,7 @@ export default {
           img: getImgForVipUpgrade('6'),
           bg: getImgForVipUpgrade('07', true)
         },
-        重点客户: {
+        重点及首次合作客户: {
           title: '开通大会员',
           button: '去开通',
           subtitle: '通过挖掘企业重点客户,直观了解采购单位与供应商关系远近,辅助投标决策!',
@@ -264,7 +272,6 @@ export default {
     this.getSelect()
   },
   mounted () {
-    this.getProActivcList()
     this.$nextTick(() => {
       window.addEventListener('scroll', this.watchScroll)
     })
@@ -304,7 +311,11 @@ export default {
     handleClick (index) {
       this.activeName = index
       const blocks = document.querySelectorAll('.tab-content-item')
-      blocks[index - 1].scrollIntoView({ behavior: 'smooth', block: 'start', inline: 'nearest' })
+      blocks[index - 1].scrollIntoView({
+        behavior: 'smooth',
+        block: 'start',
+        inline: 'nearest'
+      })
     },
     entname (data) {
       this.entName = data
@@ -312,7 +323,9 @@ export default {
     // 中标信息-筛选
     onLimitChange (data) {
       this.bidInfoParams = JSON.parse(data)
-      this.getProActivcList()
+      // 刷新动态组件
+      this.ScreenParams = Object.assign(this.ScreenParams, this.bidInfoParams)
+      this.dynamicKey = new Date().getTime()
     },
     getSelect () {
       getEntWinnerSelect({ entId: this.$route.params.eId }).then(res => {
@@ -335,30 +348,6 @@ export default {
         }
       })
     },
-    getProActivcList (p) {
-      this.ScreenParams.pageNum = p
-      Object.assign(this.ScreenParams, this.bidInfoParams)
-      getNewMsg(this.ScreenParams).then(res => {
-        this.loading = false
-        if (res.error_code === 0) {
-          if (!res.data.list) {
-            this.chartShowArr.push(false)
-          } else {
-            this.chartShowArr.push(true)
-          }
-          this.project.proActiveList = res.data.list
-          if (res.data.count !== -1) {
-            this.project.count = res.data.count
-          }
-          if (this.$refs.myList) {
-            this.$refs.myList.initData(this.project)
-            this.$refs.myList.$forceUpdate()
-          }
-        } else {
-          this.chartShowArr.push(false)
-        }
-      })
-    },
     getEntInfo (data) {
       this.proData = [
         {
@@ -402,7 +391,10 @@ export default {
     setFollowConfirmed (data) {
       if (this.follow.loading) return
       this.follow.loading = true
-      setFollowEnt({ entId: this.eId, group: data }).then(res => {
+      setFollowEnt({
+        entId: this.eId,
+        group: data
+      }).then(res => {
         if (res.error_code === 0) {
           // 关闭弹窗
           this.setFollowCancel()
@@ -440,31 +432,37 @@ export default {
 }
 </script>
 <style lang="scss" scoped>
-::v-deep .sub-dialog{
+::v-deep .sub-dialog {
   background-color: transparent;
   box-shadow: none;
+
   .el-dialog__header,
-  .el-dialog__body{
+  .el-dialog__body {
     padding: 0;
   }
 }
-.ent-portrayal{
+
+.ent-portrayal {
   margin: 32px auto;
-  .ent-header{
+
+  .ent-header {
     display: flex;
     justify-content: space-between;
     align-items: center;
     padding: 32px 40px;
     background: #fff;
-    .name{
+
+    .name {
       font-size: 24px;
       color: #171826;
     }
-    .ent_follow{
+
+    .ent_follow {
       display: flex;
       align-items: center;
       cursor: pointer;
-      .icon_heart_gray{
+
+      .icon_heart_gray {
         margin-right: 4px;
         display: flex;
         width: 18px;
@@ -472,7 +470,8 @@ export default {
         background: url('~@/assets/images/icon/icon-heart.png') no-repeat;
         background-size: contain;
       }
-      .icon_heart_red{
+
+      .icon_heart_red {
         margin-right: 4px;
         display: flex;
         width: 18px;
@@ -480,7 +479,8 @@ export default {
         background: url('~@/assets/images/icon/icon-favorite.png') no-repeat;
         background-size: contain;
       }
-      .follow_text{
+
+      .follow_text {
         font-size: 14px;
         font-family: Microsoft YaHei, Microsoft YaHei-Regular;
         font-weight: 400;
@@ -489,26 +489,31 @@ export default {
       }
     }
   }
-  .tab-header{
+
+  .tab-header {
     height: 48px;
     line-height: 48px;
     border-bottom: 1px solid #ececec;
-    a{
+
+    a {
       text-decoration: none;;
       display: inline-block;
       padding: 0 20px;
       font-size: 14px;
       cursor: pointer;
       color: #303133;
-      &:hover{
+
+      &:hover {
         color: #2cb7ca;
       }
     }
-    .active{
+
+    .active {
       position: relative;
       color: #2cb7ca;
     }
-    .active::after{
+
+    .active::after {
       content: '';
       position: absolute;
       bottom: 0;
@@ -516,13 +521,14 @@ export default {
       width: 56px;
       height: 2px;
       background-color: #2cb7ca;
-      transition: transform .3s cubic-bezier(.645,.045,.355,1),-webkit-transform .3s cubic-bezier(.645,.045,.355,1);
+      transition: transform .3s cubic-bezier(.645, .045, .355, 1), -webkit-transform .3s cubic-bezier(.645, .045, .355, 1);
       list-style: none;
       z-index: 1;
       transform: translateX(-50%);
     }
   }
-  .fixed-nav{
+
+  .fixed-nav {
     position: fixed;
     top: 64px;
     width: calc(1200px - 280px);
@@ -532,39 +538,49 @@ export default {
     transform: translateX(-50%);
     z-index: 99;
   }
-  .ent-content{
+
+  .ent-content {
     margin-top: 16px;
     background: #fff;
-    ::v-deep.el-tabs__header{
+
+    ::v-deep.el-tabs__header {
       margin: 0;
     }
-    ::v-deep.el-tabs__item{
+
+    ::v-deep.el-tabs__item {
       padding: 0 20px;
       height: 48px;
       line-height: 48px;
     }
-    ::v-deep.el-tabs__item.is-active,::v-deep.el-tabs__item:hover{
+
+    ::v-deep.el-tabs__item.is-active, ::v-deep.el-tabs__item:hover {
       color: #2CB7CA;
     }
-    ::v-deep.el-tabs__active-bar{
+
+    ::v-deep.el-tabs__active-bar {
       background-color: #2CB7CA;
     }
-    ::v-deep.el-tabs__nav-wrap::after{
+
+    ::v-deep.el-tabs__nav-wrap::after {
       height: 1px;
       background-color: #ECECEC;
     }
-    ::v-deep.el-tabs__content{
+
+    ::v-deep.el-tabs__content {
       padding: 0 40px 32px;
     }
-    .pro_info{
+
+    .pro_info {
       width: 100%;
       height: 171px;
-      .pro_info_ul{
+
+      .pro_info_ul {
         display: flex;
         justify-content: space-between;
         width: 100%;
         background: #fff;
-        .pro_list{
+
+        .pro_list {
           position: relative;
           display: flex;
           flex-direction: column;
@@ -573,14 +589,16 @@ export default {
           margin-top: 32px;
           width: 210px;
           height: 78px;
-          .pro_li_con{
+
+          .pro_li_con {
             font-size: 20px;
             font-family: Microsoft YaHei, Microsoft YaHei-Regular;
             font-weight: 400;
             color: #2cb7ca;
             line-height: 32px;
           }
-          .pro_li_label{
+
+          .pro_li_label {
             font-size: 14px;
             font-family: Microsoft YaHei, Microsoft YaHei-Regular;
             font-weight: 400;
@@ -588,7 +606,8 @@ export default {
             line-height: 22px;
           }
         }
-        .pro_list:after{
+
+        .pro_list:after {
           content: '';
           position: absolute;
           right: 0;
@@ -596,7 +615,8 @@ export default {
           height: 46px;
           border: 0.5px solid #ececec;
         }
-        .pro_list:nth-child(4)::after{
+
+        .pro_list:nth-child(4)::after {
           content: '';
           position: absolute;
           right: 0;
@@ -605,11 +625,12 @@ export default {
           border: 0px solid #ececec;
         }
       }
-      .pro_info_tip{
+
+      .pro_info_tip {
         display: flex;
         justify-content: center;
         align-items: center;
-        margin-top: 12px;
+        margin-top: 40px;
         width: 840px;
         height: 17px;
         font-size: 12px;

+ 132 - 165
src/views/portrayal/EntSearchPortrayal.vue

@@ -1,7 +1,7 @@
 <template>
   <Layout class="ent-portrayal">
     <div class="ent-header">
-      <div class="name">{{entName}}</div>
+      <div class="name">{{ entName }}</div>
     </div>
     <div class="ent-content" v-loading="loading">
       <div class="tab-header" :class="{'fixed-nav': navFixed}" id="entTabNav">
@@ -42,36 +42,42 @@
             <!-- 占位dom 解决锚点tab有fixed定位 scrollview位置会偏移 同时作为tab1和tab2的间距 -->
             <div style="height:80px;"></div>
             <div class="bidcomp">
-                <BidInfoActive whichPor="entpor" @onPageChange="onLimitChange" :canselect="canSelect" title="中标信息"></BidInfoActive>
-              </div>
-            <div class="pro_info" v-if="showConf4 && !emptyShow">
+              <BidInfoActive whichPor="entpor" @onPageChange="onLimitChange" :canselect="canSelect"
+                             title="中标信息"></BidInfoActive>
+            </div>
+            <div class="pro_info" v-if="!emptyShow">
               <ul class="pro_info_ul">
                 <li class="pro_list" v-for="(item, index) in proData" :key="index">
-                  <div class="pro_li_con">{{item.count}}</div>
-                  <div class="pro_li_label">{{item.label}}</div>
+                  <div class="pro_li_con">{{ item.count }}</div>
+                  <div class="pro_li_label">{{ item.label }}</div>
                 </li>
               </ul>
-              <div class="pro_info_tip">数据统计范围:{{dateRange.start}}-{{dateRange.end}}</div>
+              <div class="pro_info_tip">数据统计范围:{{ dateRange.start }}-{{ dateRange.end }}</div>
             </div>
-            <ProActive :isactive="isActive" v-if="!emptyShow" title="项目动态" ref="myList" @onScreenChange="getScreenChange" :screenList="ScreenList" @onPageChange="getProActivcList" :projectData="project"></ProActive>
-            <ent-chart @showEmpty="showEmpty" @loadingChart="loadingChart" :params="bidInfoParams" v-if="showConf4" :active="activeName" v-on:entInfo="getEntInfo"></ent-chart>
+            <Dynamic-list :key="dynamicKey" :filters="ScreenParams"
+                          :config="{baseParam:{entId: decodeURIComponent($route.params.eId)},isWinner:true}"
+                          style="width: 856px"></Dynamic-list>
+            <ent-chart @showEmpty="showEmpty" @loadingChart="loadingChart" :params="bidInfoParams"
+                       :active="activeName" v-on:entInfo="getEntInfo"></ent-chart>
           </div>
           <div class="ent-vip-upgrade-group" v-else key="tab2" style="margin-top:60px">
             <!-- 占位dom 解决锚点tab有fixed定位 scrollview位置会偏移 同时作为tab1和tab2的间距 -->
-            <BidInfoActive whichPor="entpor" @onPageChange="onLimitChange" :canselect="canSelect" title="中标信息"></BidInfoActive>
+            <BidInfoActive whichPor="entpor" @onPageChange="onLimitChange" :canselect="canSelect"
+                           title="中标信息"></BidInfoActive>
             <div style="height:0;"></div>
-            <img src="@/assets/images/vip/bg/mask/01.png">
-            <MaskCard @click="openVipPage(item)" v-for="(item, k) in getVipUpgradeMap" :key="k + item.button + item.title" :k="k" :item="item">
-              <!-- 如果是新超级订阅 也可显示项目动态 -->
-            <ProActive title="项目动态" ref="myList" @onScreenChange="getScreenChange" :screenList="ScreenList" @onPageChange="getProActivcList" v-if="showProActive && project.proActiveList && project.proActiveList.length > 0 && !emptyShow" :projectData="project"></ProActive>
+            <div class="pro_info" v-if="!emptyShow">
+              <ul class="pro_info_ul">
+                <li class="pro_list" v-for="(item, index) in proData" :key="index">
+                  <div class="pro_li_con">{{ item.count }}</div>
+                  <div class="pro_li_label">{{ item.label }}</div>
+                </li>
+              </ul>
+              <div class="pro_info_tip">数据统计范围:{{ dateRange.start }}-{{ dateRange.end }}</div>
+            </div>
+            <MaskCard @click="openVipPage(item)" v-for="(item, k) in getVipUpgradeMap"
+                      :key="k + item.button + item.title" :k="k" :item="item">
             </MaskCard>
           </div>
-          <Empty v-show="emptyShow" :images="require('@/assets/images/empty/jy-chagrin.png')">
-            <div slot="default" style="text-align:center">
-              <span>对不起,没有匹配到相关信息,</span><br/>
-              <span>修改时间范围或换个搜索词试试吧</span>
-            </div>
-          </Empty>
         </div>
       </div>
       <!-- 留资弹窗 -->
@@ -85,20 +91,20 @@ import EntSubVipForm from './components/EntSubVipForm'
 import BidInfoActive from './components/BidInfoActive'
 import EntHistoryForm from './components/EntHistoryForm'
 import Layout from '@/components/common/ContentLayout.vue'
-import ProActive from './components/ProActive'
 import MaskCard from '@/components/mask-card/MaskCard.vue'
 import FreeExpBanner from './components/FreeExpBanner.vue'
 import ContactList from '@/components/contact-info/ContactInfo'
 import CollectInfo from '@/components/collect-info/CollectInfo.vue'
-import Empty from '@/components/common/Empty'
+import DynamicList from './components/DynamicList'
 import { mapState } from 'vuex'
-import { Tabs, TabPane } from 'element-ui'
-import { moneyUnit, dateFormatter } from '@/utils'
-import { getEntSearchPower, getSvipNewMsg, getUsage, getNewMsg, getsubVipPortraitSelect, getUserPower, getSvipMsgSelects, getSubVipEntChart } from '@/api/modules'
+import { TabPane, Tabs } from 'element-ui'
+import { dateFormatter, moneyUnit } from '@/utils'
+import { getEntSearchPower, getSubVipEntChart, getsubVipPortraitSelect, getUsage, getUserPower } from '@/api/modules'
 
 function getImgForVipUpgrade (name, bg = false, suffix = '.png') {
   return require('@/assets/images/vip/' + (bg ? 'bg/mask/' : '') + name + suffix)
 }
+
 export default {
   name: 'ent-portrayal',
   components: {
@@ -109,17 +115,17 @@ export default {
     BidInfoActive,
     EntHistoryForm,
     Layout,
-    ProActive,
     MaskCard,
     CollectInfo,
     ContactList,
     FreeExpBanner,
-    Empty
+    DynamicList
   },
   data () {
     return {
       loading: false,
       isInit: false,
+      dynamicKey: new Date().getTime(), // 筛选重新渲染动态数据
       activeName: '1',
       proData: [],
       project: {
@@ -153,7 +159,7 @@ export default {
       },
       entContactTip: {
         title: '开通大会员',
-        subtitle: '获取企业通讯录信息,直接与甲方或渠道商项目负责人对接!',
+        subtitle: '获取企业联系人信息,一键拨打!',
         button: '免费体验',
         source: 'ent_portrait_contacts',
         img: getImgForVipUpgrade('010'),
@@ -207,7 +213,7 @@ export default {
           img: getImgForVipUpgrade('6'),
           bg: getImgForVipUpgrade('07', true)
         },
-        重点客户: {
+        重点及首次合作客户: {
           title: '超级订阅',
           button: '去开通',
           subtitle: '通过挖掘企业重点客户,直观了解采购单位与供应商关系远近,辅助投标决策!',
@@ -307,10 +313,6 @@ export default {
       var freeTrail = this.hasTrailPower
       return this.powerInfo.vip > 1 || (this.info.memberStatus > 0 && this.info.power.indexOf(13) !== -1) || freeHave || freeTrail
     },
-    // 是否显示4
-    showConf4 () {
-      return this.powerInfo.vip > 1 || this.info.power.indexOf(4) !== -1 || this.hasTrailPower
-    },
     showTab2Content () {
       // 显示tab2
       // 1.开通了超级订阅升级版
@@ -325,7 +327,7 @@ export default {
     // 监听计算属性是否显示项目动态 如果显示就执行项目动态请求
     showProActive (newVal, oldVal) {
       if (newVal) {
-        this.getProActivcList()
+        // this.getProActivcList()
       }
     },
     bidInfoParams (newval) {
@@ -334,7 +336,7 @@ export default {
       }
     },
     chartShowArr (newval) {
-      console.log(newval, newval.indexOf(true), '企业画像')
+      // console.log(newval, newval.indexOf(true), '企业画像')
       if (newval.indexOf(true) !== -1) {
         this.emptyShow = false
       } else {
@@ -348,21 +350,25 @@ export default {
   },
   created () {
     this.getPower()
-    this.getSelect()
     this.checkShowExp((res) => {
-      if (res && res.isFree) {
+      if (res && !(res.vipStatus > 0 || res.memberStatus > 0)) {
+        this.getSelect()
         getSubVipEntChart({ entId: this.$route.params.eId }).then(res => {
-          if (res && res.data && res.data.onTrial) {
-            this.freeTrialStatus = true
+          if (res && res.data) {
+            if (res.data.onTrial) {
+              this.freeTrialStatus = true
+            }
+            this.getEntInfo(res.data)
           }
         })
       } else {
-        this.getUserForPagePower()
+        this.getUserForPagePower().then(() => {
+          this.getSelect()
+        })
       }
     })
   },
   mounted () {
-    this.getProActivcList()
     this.$nextTick(() => {
       window.addEventListener('scroll', this.watchScroll)
     })
@@ -370,17 +376,6 @@ export default {
   destroyed () {
     window.removeEventListener('scroll', this.watchScroll)
   },
-  // 路由组件内导航守卫
-  // beforeRouteEnter (to, from, next) {
-  //   next(vm => {
-  //     if (vm.info.memberStatus > 0 && vm.info.vipStatus > 1 && vm.info.viper && vm.pagePowerInfo.usage >= vm.pagePowerInfo.total) {
-  //       vm.$router.push({
-  //         path: `/ent_portrait/${encodeURIComponent(to.params.eId)}`,
-  //         replace: true
-  //       })
-  //     }
-  //   })
-  // },
   methods: {
     checkShowExp (callback) {
       getUserPower().then(res => {
@@ -448,28 +443,28 @@ export default {
     handleClick (index) {
       this.activeName = index
       const blocks = document.querySelectorAll('.tab-content-item')
-      blocks[index - 1].scrollIntoView({ behavior: 'smooth', block: 'start', inline: 'nearest' })
+      blocks[index - 1].scrollIntoView({
+        behavior: 'smooth',
+        block: 'start',
+        inline: 'nearest'
+      })
     },
     async getPower () {
-      const { error_code: code, data } = await getEntSearchPower()
+      const {
+        error_code: code,
+        data
+      } = await getEntSearchPower()
       if (code === 0 && data) {
         Object.assign(this.powerInfo, data)
       }
     },
-    // changeTabs (tabs) {
-    //   if (!this.isInit) {
-    //     this.isInit = true
-    //     if (this.showProActive) {
-    //       this.getProActivcList()
-    //     }
-    //   }
-    // },
     entname (data) {
       this.entName = data
     },
     // 中标信息-筛选项
     onLimitChange (data) {
       this.bidInfoParams = JSON.parse(data)
+      this.dynamicKey = new Date().getTime()
       this.getProActivcList()
     },
     getSelect () {
@@ -480,38 +475,12 @@ export default {
       })
     },
     getUserForPagePower () {
-      getUsage({ entId: this.eId }).then(res => {
+      return getUsage({ entId: this.eId }).then(res => {
         if (res.error_code === 0) {
           this.pagePowerInfo = res.data
         }
       })
     },
-    // 中标动态-检索
-    getScreenList () {
-      getSvipMsgSelects({ entId: this.eId }).then(res => {
-        if (res.error_code === 0) {
-          this.ScreenList = res.data
-          if (res.data.timeRange && res.data.timeRange.length !== 0) {
-            this.ScreenParams.pushTime = res.data.timeRange[0]
-          }
-          // this.$refs.businessScopeSelector.setState(defaultArr)
-        }
-        const checkListArr = this.$refs.myList.checkList
-        const selectListArr = []
-        if (checkListArr.indexOf('标题') !== -1) {
-          selectListArr.push('title')
-        }
-        if (checkListArr.indexOf('正文') !== -1) {
-          selectListArr.push('content')
-        }
-        this.ScreenParams.matchType = selectListArr.join(',')
-        this.$nextTick(() => {
-          if (this.showProActive) {
-            this.getProActivcList()
-          }
-        })
-      })
-    },
     getScreenChange (data) {
       if (data.pushTime === '') {
         data.pushTime = this.ScreenParams.pushTime
@@ -524,48 +493,7 @@ export default {
     getProActivcList (p) {
       this.ScreenParams.pageNum = p
       Object.assign(this.ScreenParams, this.bidInfoParams)
-      if (this.info.memberStatus > 0 && this.info.power.indexOf(13) !== -1) {
-        getNewMsg(this.ScreenParams).then(res => {
-          this.loading = false
-          if (res.error_code === 0) {
-            if (!res.data.list) {
-              this.chartShowArr.push(false)
-            } else {
-              this.chartShowArr.push(true)
-            }
-            this.project.proActiveList = res.data.list
-            if (res.data.count !== -1) {
-              this.project.count = res.data.count
-            }
-            if (this.$refs.myList) {
-              this.$refs.myList.initData(this.project)
-              this.$refs.myList.$forceUpdate()
-            }
-          } else {
-            this.chartShowArr.push(false)
-          }
-        })
-      } else {
-        getSvipNewMsg(this.ScreenParams).then(res => {
-          if (res.error_code === 0) {
-            if (!res.data.list) {
-              this.chartShowArr.push(false)
-            } else {
-              this.chartShowArr.push(true)
-            }
-            this.project.proActiveList = res.data.list
-            if (res.data.count !== -1) {
-              this.project.count = res.data.count
-            }
-            if (this.$refs.myList) {
-              this.$refs.myList.initData(this.project)
-              this.$refs.myList.$forceUpdate()
-            }
-          } else {
-            this.chartShowArr.push(false)
-          }
-        })
-      }
+      return false
     },
     getEntInfo (data) {
       this.proData = [
@@ -635,6 +563,7 @@ export default {
 <style lang="scss" scoped>
 .before-give-text {
   position: relative;
+
   &::before {
     content: "赠送";
     position: absolute;
@@ -653,31 +582,37 @@ export default {
     background: linear-gradient(104deg, #D69C06 0%, #B16C05 100%);
   }
 }
-.fixedBanner{
+
+.fixedBanner {
   position: fixed;
   top: 111px;
   left: 50%;
   width: 920px;
-  margin-left: -140px!important;
+  margin-left: -140px !important;
   transform: translateX(-50%);
   z-index: 9999;
 }
-.ent-portrayal{
+
+.ent-portrayal {
   margin: 32px auto;
-  .ent-header{
+
+  .ent-header {
     display: flex;
     justify-content: space-between;
     align-items: center;
     padding: 32px 40px;
     background: #fff;
-    .name{
+
+    .name {
       font-size: 24px;
       color: #171826;
     }
-    .ent_follow{
+
+    .ent_follow {
       display: flex;
       cursor: pointer;
-      .icon_heart_gray{
+
+      .icon_heart_gray {
         margin-right: 4px;
         display: flex;
         width: 18px;
@@ -685,7 +620,8 @@ export default {
         background: url('~@/assets/images/icon/icon-heart.png') no-repeat;
         background-size: contain;
       }
-      .icon_heart_red{
+
+      .icon_heart_red {
         margin-right: 4px;
         display: flex;
         width: 18px;
@@ -693,7 +629,8 @@ export default {
         background: url('~@/assets/images/icon/icon-favorite.png') no-repeat;
         background-size: contain;
       }
-      .follow_text{
+
+      .follow_text {
         font-size: 14px;
         font-family: Microsoft YaHei, Microsoft YaHei-Regular;
         font-weight: 400;
@@ -702,26 +639,31 @@ export default {
       }
     }
   }
-  .tab-header{
+
+  .tab-header {
     height: 48px;
     line-height: 48px;
     border-bottom: 1px solid #ececec;
-    a{
+
+    a {
       text-decoration: none;;
       display: inline-block;
       padding: 0 20px;
       font-size: 14px;
       cursor: pointer;
       color: #303133;
-      &:hover{
+
+      &:hover {
         color: #2cb7ca;
       }
     }
-    .active{
+
+    .active {
       position: relative;
       color: #2cb7ca;
     }
-    .active::after{
+
+    .active::after {
       content: '';
       position: absolute;
       bottom: 0;
@@ -729,13 +671,14 @@ export default {
       width: 56px;
       height: 2px;
       background-color: #2cb7ca;
-      transition: transform .3s cubic-bezier(.645,.045,.355,1),-webkit-transform .3s cubic-bezier(.645,.045,.355,1);
+      transition: transform .3s cubic-bezier(.645, .045, .355, 1), -webkit-transform .3s cubic-bezier(.645, .045, .355, 1);
       list-style: none;
       z-index: 1;
       transform: translateX(-50%);
     }
   }
-  .fixed-nav{
+
+  .fixed-nav {
     position: fixed;
     top: 64px;
     width: calc(1200px - 280px);
@@ -745,39 +688,49 @@ export default {
     transform: translateX(-50%);
     z-index: 99;
   }
+
   .ent-tab2-content {
     margin: 40px 0 32px;
   }
-  .ent-content{
+
+  .ent-content {
     margin-top: 16px;
     background: #fff;
-    ::v-deep.el-tabs__header{
+
+    ::v-deep.el-tabs__header {
       margin: 0;
     }
-    ::v-deep.el-tabs__item{
+
+    ::v-deep.el-tabs__item {
       padding: 0 20px;
       height: 48px;
       line-height: 48px;
     }
-    ::v-deep.el-tabs__item.is-active,::v-deep.el-tabs__item:hover{
+
+    ::v-deep.el-tabs__item.is-active, ::v-deep.el-tabs__item:hover {
       color: #2CB7CA;
     }
-    ::v-deep.el-tabs__active-bar{
+
+    ::v-deep.el-tabs__active-bar {
       background-color: #2CB7CA;
     }
-    ::v-deep.el-tabs__nav-wrap::after{
+
+    ::v-deep.el-tabs__nav-wrap::after {
       height: 1px;
       background-color: #ECECEC;
     }
-    .pro_info{
+
+    .pro_info {
       width: 100%;
       height: 171px;
-      .pro_info_ul{
+
+      .pro_info_ul {
         display: flex;
         justify-content: space-between;
         width: 100%;
         background: #fff;
-        .pro_list{
+
+        .pro_list {
           position: relative;
           display: flex;
           flex-direction: column;
@@ -786,14 +739,16 @@ export default {
           margin-top: 32px;
           width: 210px;
           height: 78px;
-          .pro_li_con{
+
+          .pro_li_con {
             font-size: 20px;
             font-family: Microsoft YaHei, Microsoft YaHei-Regular;
             font-weight: 400;
             color: #2cb7ca;
             line-height: 32px;
           }
-          .pro_li_label{
+
+          .pro_li_label {
             font-size: 14px;
             font-family: Microsoft YaHei, Microsoft YaHei-Regular;
             font-weight: 400;
@@ -801,7 +756,8 @@ export default {
             line-height: 22px;
           }
         }
-        .pro_list:after{
+
+        .pro_list:after {
           content: '';
           position: absolute;
           right: 0;
@@ -809,7 +765,8 @@ export default {
           height: 46px;
           border: 0.5px solid #ececec;
         }
-        .pro_list:nth-child(4)::after{
+
+        .pro_list:nth-child(4)::after {
           content: '';
           position: absolute;
           right: 0;
@@ -818,11 +775,12 @@ export default {
           border: 0px solid #ececec;
         }
       }
-      .pro_info_tip{
+
+      .pro_info_tip {
         display: flex;
         justify-content: center;
         align-items: center;
-        margin-top: 12px;
+        margin-top: 40px;
         width: 840px;
         height: 17px;
         font-size: 12px;
@@ -832,21 +790,26 @@ export default {
       }
     }
   }
+
   .tab-content {
     padding-left: 0 !important;
     padding-right: 0 !important;
+
     & > div {
       margin-left: 32px;
       margin-right: 32px;
     }
   }
 }
+
 .ent-tab2-content.mask {
   position: relative;
   margin: 0;
-  &>img {
+
+  & > img {
     width: 100%;
   }
+
   .m-banner {
     position: absolute;
     top: 60px;
@@ -858,13 +821,15 @@ export default {
     background-size: 100% 100%;
     border-radius: 9px;
     text-align: center;
-    box-shadow: 0px 0px 28px 0px rgba(0,0,0,0.08);
+    box-shadow: 0px 0px 28px 0px rgba(0, 0, 0, 0.08);
+
     .banner-header {
       padding: 28px 0;
       color: #fff;
       font-size: 16px;
       line-height: 24px;
     }
+
     .banner-content {
       margin-top: 40px;
       margin-bottom: 16px;
@@ -872,6 +837,7 @@ export default {
       color: #686868;
       line-height: 22px;
     }
+
     .button-confirm {
       display: inline-block;
       padding: 6px 42px;
@@ -881,12 +847,13 @@ export default {
       background-color: #2cb7ca;
       border-radius: 6px;
       text-align: center;
-      box-shadow: 0px 0px 28px 0px rgba(0,0,0,0.08);
+      box-shadow: 0px 0px 28px 0px rgba(0, 0, 0, 0.08);
       cursor: pointer;
       user-select: none;
     }
   }
 }
+
 .ent-big-upgrade-group {
   margin-top: 32px;
   margin-bottom: 16px;

+ 95 - 64
src/views/portrayal/UnitPortrayal.vue

@@ -28,12 +28,13 @@
           <div class="unlock-btn" @click="goUnlock('去解锁')">去解锁>></div>
         </div>
         <div class="supervip-bg" v-if="vipStatusNoMember">
-          <div class="vip-balance">当月采购单位画像余额:<em class="highlight-text">{{usageInfo.surplus}}</em></div>
-          <div class="update-btn" @click.stop="goUpdate">{{vipStatusBtn}}</div>
+          <div class="vip-balance">当月采购单位画像余额:<em class="highlight-text">{{ usageInfo.surplus }}</em></div>
+          <div class="update-btn" @click.stop="goUpdate">{{ vipStatusBtn }}</div>
         </div>
       </div>
-      <div >
-        <div class="free-bg" :class="showFreeOpen ? 'fixedBanner' : ''" v-if="userInfo.isFree && userInfo.freeBuyerPort != 0">
+      <div>
+        <div class="free-bg" :class="showFreeOpen ? 'fixedBanner' : ''"
+             v-if="userInfo.isFree && userInfo.freeBuyerPort != 0">
           <div class="free-text">如需查看更多【采购单位全景分析】,请开通超级订阅</div>
           <div class="unlock-btn" @click="goUnlock('去开通')">去开通>></div>
         </div>
@@ -41,11 +42,14 @@
       <!-- 采购单位通讯录 -->
       <ContactList name="buyer" titlename="采购单位通讯录" style="padding:32px 40px 32px;" v-if="!noBuyerAuth"></ContactList>
       <div class="mask-bg-group" v-else>
-        <MaskCard @click="openBigPage('采购单位通讯录', getEntContactMap)" k="采购单位通讯录 " :key="'采购单位通讯录' + getEntContactMap.button + getEntContactMap.title" :item="getEntContactMap"></MaskCard>
+        <MaskCard @click="openBigPage('采购单位通讯录', getEntContactMap)" k="采购单位通讯录 "
+                  :key="'采购单位通讯录' + getEntContactMap.button + getEntContactMap.title"
+                  :item="getEntContactMap"></MaskCard>
       </div>
       <div class="unit-info">
         <div class="bidcomp">
-          <BidInfoActive whichPor="unitpor" @onPageChange="onLimitChange" :canselect="canSelect" title="采购单位分析"></BidInfoActive>
+          <BidInfoActive whichPor="unitpor" @onPageChange="onLimitChange" :canselect="canSelect"
+                         title="采购单位分析"></BidInfoActive>
         </div>
         <div class="u-i-box" v-if="baseShow">
           <div class="b-item">
@@ -72,10 +76,15 @@
         <div class="u-i-tip" v-if="baseShow">数据统计范围:{{ info.start }}-{{ info.end }}</div>
       </div>
       <!-- 招标动态 -->
-      <unit-list :noauth="noBuyerAuth" :usage="usageInfo" :bidparams="bidInfoParams" v-if="unitlistshow" @list="getList" @click="openCheckPop" @onClickUnlock="goEmitClick"></unit-list>
-      <unit-chart @isTrial="getIsTrail" @baseInfoBool="baseInfoBool" @showEmpty="showEmpty" :params="bidInfoParams" v-on:baseInfo="getBaseInfo"></unit-chart>
+      <Dynamic-list :key="dynamicKey"  v-show="!emptyShow" @onClickUnlock="goEmitClick" :noBuyerAuth="noBuyerAuth" :usage="usageInfo"
+                    :config="{baseParam:{buyer: decodeURIComponent(this.$route.params.entName)},isWinner:false}"
+                    :filters="bidInfoParams" style="padding: 32px 40px 0;width: 936px"></Dynamic-list>
+      <!-- <unit-list :noauth="noBuyerAuth" :usage="usageInfo" :bidparams="bidInfoParams" v-if="unitlistshow" @list="getList" @click="openCheckPop" @onClickUnlock="goEmitClick"></unit-list>-->
+      <unit-chart @isTrial="getIsTrail" @baseInfoBool="baseInfoBool" @showEmpty="showEmpty" :params="bidInfoParams"
+                  v-on:baseInfo="getBaseInfo"></unit-chart>
       <div class="unit-big-upgrade-group" v-if="noBuyerAuth && !emptyShow">
-        <MaskCard @click="openBigPage(k, item)" v-for="(item, k) in getBigUpgradeMap" :key="k + item.button + item.title"
+        <MaskCard @click="openBigPage(k, item)" v-for="(item, k) in getBigUpgradeMap"
+                  :key="k + item.button + item.title"
                   :k="k" :item="item"></MaskCard>
       </div>
       <Empty v-show="emptyShow" :images="require('@/assets/images/empty/jy-chagrin.png')">
@@ -99,19 +108,28 @@
 import Layout from '@/components/common/ContentLayout'
 import UnitChart from './components/UnitChart'
 import UnitList from './components/UnitList'
+import DynamicList from './components/DynamicList'
 import BidInfoActive from './components/BidInfoActive'
 import ContactList from '@/components/contact-info/ContactInfo'
 import MaskCard from '@/components/mask-card/MaskCard.vue'
 import CollectInfo from '@/components/collect-info/CollectInfo.vue'
 import Empty from '@/components/common/Empty'
 import { Dialog } from 'element-ui'
-import { setLogs, getStatusCustomer, setStatusCustomer, getBuyerSelect, getVipBuyerSelect, getUsage } from '@/api/modules'
+import {
+  getBuyerSelect,
+  getStatusCustomer,
+  getUsage,
+  getVipBuyerSelect,
+  setLogs,
+  setStatusCustomer
+} from '@/api/modules'
 import { mapState } from 'vuex'
 
 function getImgForBigUpgrade (name, bg = false, suffix = '.png') {
   const temp = (bg ? 'bg/' : '') + name + suffix
   return require('@/assets/images/big/' + temp)
 }
+
 /* eslint-disable */
 export default {
   name: 'unit-portrayal',
@@ -123,6 +141,7 @@ export default {
     MaskCard,
     CollectInfo,
     BidInfoActive,
+    DynamicList,
     [Dialog.name]: Dialog,
     Empty
   },
@@ -130,6 +149,7 @@ export default {
     return {
       isDialogShow: false,
       loading: true,
+      dynamicKey: new Date().getTime(),//筛选重新渲染动态数据
       info: {
         buyerName: '',
         province: '',
@@ -153,34 +173,13 @@ export default {
       },
       entContactTip: {
         title: '开通大会员',
-        subtitle: '获取采购单位类似项目联系人、联系方式等,一键拨打!',
+        subtitle: '获取采购单位联系人信息,一键拨打!',
         button: '免费体验',
         source: 'buyer_portrait_contacts_freeuser',
         img: getImgForBigUpgrade('1-big'),
         bg: getImgForBigUpgrade('1-bg', true)
       },
       bigUpgradeMap: {
-        // 合作企业注册资本分布: {
-        //   title: '开通大会员',
-        //   subtitle: '通过分析合作企业注册资本、采购项目规模、利润率,全面洞察采购单位合作企业!',
-        //   img: getImgForBigUpgrade('9-big'),
-        //   bg: getImgForBigUpgrade('9-bg', true),
-        //   source: 'buyer_portrait_withCapitalData'
-        // },
-        // 合作企业年龄分布: {
-        //   title: '开通大会员',
-        //   subtitle: '通过分析合作企业年龄、数量、规模分布情况,全面洞察采购单位合作企业!',
-        //   img: getImgForBigUpgrade('10-big'),
-        //   bg: getImgForBigUpgrade('10-bg', true),
-        //   source: 'buyer_portrait_withEstablishData'
-        // },
-        // 合作企业注册地分布: {
-        //   title: '开通大会员',
-        //   subtitle: '通过分析合作企业的地址、数量、采购规模,了解采购单位营商环境,辅助投标决策!',
-        //   img: getImgForBigUpgrade('11-big'),
-        //   bg: getImgForBigUpgrade('11-bg', true),
-        //   source: 'buyer_portrait_withAreaData'
-        // },
         年度项目统计: {
           title: '开通大会员',
           subtitle: '采购单位年度项目规模、增长趋势一目了然,快速分析市场!',
@@ -223,6 +222,13 @@ export default {
           bg: getImgForBigUpgrade('12-bg', true),
           source: 'buyer_portrait_topAgencyData_freeuser'
         },
+        各行业项目规模占比: {
+          title: '开通大会员',
+          subtitle: '通过行业采购项目的规模、数量、利润率,洞悉采购单位的采购状况!',
+          img: getImgForBigUpgrade('7-big'),
+          bg: getImgForBigUpgrade('7-bg', true),
+          source: 'buyer_portrait_top12_freeuser'
+        },
         重点合作企业: {
           title: '开通大会员',
           subtitle: '通过挖掘重点合作企业,直观了解采购单位与企业关系远近,辅助投标决策!',
@@ -230,12 +236,12 @@ export default {
           bg: getImgForBigUpgrade('8-bg', true),
           source: 'buyer_portrait_topShow_freeuser'
         },
-        各行业项目规模占比: {
+        首次合作企业: {
           title: '开通大会员',
-          subtitle: '通过行业采购项目的规模、数量、利润率,洞悉采购单位的采购状况!',
-          img: getImgForBigUpgrade('7-big'),
-          bg: getImgForBigUpgrade('7-bg', true),
-          source: 'buyer_portrait_top12_freeuser'
+          subtitle: '通过挖掘首次合作企业,直观了解采购单位现阶段密切合作企业,辅助投标决策!',
+          img: getImgForBigUpgrade('88-big'),
+          bg: getImgForBigUpgrade('8-bg', true),
+          source: 'buyer_portrait_firstShow_freeuser'
         }
       },
       bidInfoParams: {},
@@ -297,7 +303,7 @@ export default {
       const freePort = info.isFree && info.freeBuyerPort > 0
       // 免费用户 体验过期 浏览过
       const freeTail = info.isFree && info.freeBuyerPort < 0
-      return bigMember || svip  || svipTrial || freePort || freeTail
+      return bigMember || svip || svipTrial || freePort || freeTail
     },
     // 可以查看画像权限,显示遮罩
     noBuyerAuth () {
@@ -305,7 +311,7 @@ export default {
       const usage = this.usageInfo
       const isFreeAuth = info.isFree && info.freeBuyerPort > 0
       const isVipAuth = info.vipStatus > 0 && info.viper && usage.surplus > 0
-      const isMember = info.power.indexOf(5)  !== -1
+      const isMember = info.power.indexOf(5) !== -1
       // 超级订阅用户是否访问过该画像
       const vipTrial = info.vipStatus > 0 && info.viper && usage.surplus === 0 && usage.visited
       // 免费用户是否查看过该画像
@@ -352,7 +358,7 @@ export default {
         // console.log(this.shadeBottomBtnText)
         this.bigUpgradeMap[v].button = this.shadeBottomBtnText
       }
-      return  this.bigUpgradeMap
+      return this.bigUpgradeMap
     },
     // 遮罩按钮对应文案
     shadeBottomBtnText () {
@@ -401,8 +407,8 @@ export default {
     this.info.buyerName = decodeURIComponent(this.$route.params.entName)
     // this.getBigUpgradeMap()
     this.getFollowState()
-    this.getSelect()
     this.getBuyerUsage()
+    var _this = this
     $.ajax({
       url: '/publicapply/bidcoll/power',
       type: 'POST',
@@ -427,6 +433,7 @@ export default {
         if (tempType === '') {
           tempType = '0'
         }
+        _this.getSelect()
         setLogs({
           platform: 'P',
           userType: tempType
@@ -485,6 +492,7 @@ export default {
       this.unitlistshow = true
       this.loading = true
       this.bidInfoParams = JSON.parse(data)
+      this.dynamicKey = new Date().getTime()
     },
     showEmpty (data) {
       this.chartShowArr = data
@@ -507,7 +515,7 @@ export default {
         button: this.shadeBottomBtnText
       })
     },
-    
+
     openBigPage (k, item) {
       try {
         // eslint-disable-next-line no-undef
@@ -608,10 +616,11 @@ export default {
 /* eslint-enable */
 </script>
 <style lang="scss" scoped>
-::v-deep{
-  .release_main{
-    position:relative;
-    .el-input__inner{
+::v-deep {
+  .release_main {
+    position: relative;
+
+    .el-input__inner {
       background: #fff;
       cursor: pointer;
       color: #1D1D1D;
@@ -619,6 +628,7 @@ export default {
     }
   }
 }
+
 .icon_heart_gray,
 .icon_heart_red {
   margin-right: 4px;
@@ -626,11 +636,13 @@ export default {
   width: 18px;
   height: 18px;
 }
-.icon_heart_gray{
+
+.icon_heart_gray {
   background: url('~@/assets/images/icon/icon-heart.png') no-repeat;
   background-size: contain;
 }
-.icon_heart_red{
+
+.icon_heart_red {
   background: url('~@/assets/images/icon/icon-favorite.png') no-repeat;
   background-size: contain;
 }
@@ -641,12 +653,14 @@ export default {
     margin: 0 auto;
     padding: 0 0 60px 0;
   }
+
   // width: 1200px;
   .mask-bg-group {
     margin-top: 16px;
     background: #fff;
     padding-top: 20px;
   }
+
   .unit-big-upgrade-group {
     padding-top: 32px;
     background: #fff;
@@ -659,11 +673,13 @@ export default {
         background: #ffffff;
         border-radius: 8px;
       }
+
       .el-dialog__header {
         text-align: center;
         padding: 32px;
         padding-bottom: 20px;
       }
+
       .el-dialog__body {
         padding: 32px;
         padding-top: 0;
@@ -674,6 +690,7 @@ export default {
         color: #686868;
         line-height: 22px;
       }
+
       .el-dialog__title {
         font-size: 18px;
         font-family: Microsoft YaHei, Microsoft YaHei-Regular;
@@ -681,10 +698,12 @@ export default {
         color: #1d1d1d;
         line-height: 28px;
       }
+
       .el-dialog__footer {
         padding: 0;
       }
     }
+
     .unit-dialog-footer {
       display: flex;
       flex-direction: row;
@@ -692,12 +711,14 @@ export default {
       justify-content: space-between;
       padding: 32px;
       padding-top: 0;
+
       ::v-deep {
         .el-button--default {
           border: 1px solid #e0e0e0;
           color: #686868;
           background: #fff;
         }
+
         .el-button {
           width: 132px;
           height: 36px;
@@ -712,6 +733,7 @@ export default {
           border-radius: 6px;
 
         }
+
         .el-button--primary {
           background: #2cb7ca;
           color: #ffffff;
@@ -744,6 +766,7 @@ export default {
       align-items: center;
       justify-content: space-between;
       cursor: pointer;
+
       .follow-text {
         margin-left: 2px;
         font-size: 14px;
@@ -830,25 +853,26 @@ export default {
     color: #999999;
     text-align: center;
   }
+
   ::v-deep {
-    .collect-dialog{
+    .collect-dialog {
       position: fixed;
       top: 50%;
       left: 50%;
       margin-top: 0;
       transform: translate(-50%, -50%);
     }
-    .el-dialog{
+
+    .el-dialog {
       border-radius: 8px;
     }
-    .el-dialog__header{
-      padding: 0;
-    }
-    .el-dialog__body{
+
+    .el-dialog__header {
       padding: 0;
     }
   }
-  .free-bg{
+
+  .free-bg {
     position: relative;
     display: flex;
     align-items: center;
@@ -859,7 +883,8 @@ export default {
     background: url('~@/assets/images/free-bg.png') no-repeat center center;
     background-size: 100% 100%;
     border-radius: 8px;
-    .give-tip{
+
+    .give-tip {
       position: absolute;
       top: 0;
       left: 0;
@@ -872,23 +897,26 @@ export default {
       color: #fff;
       text-align: center;
     }
-    .free-text{
+
+    .free-text {
       margin-right: 32px;
       font-size: 18px;
       color: #663600;
     }
-    .unlock-btn{
+
+    .unlock-btn {
       width: 110px;
       height: 30px;
       line-height: 30px;
       text-align: center;
       background: linear-gradient(104deg, #D69C06 0%, #B16C05 100%);
       border-radius: 20px;
-      color:#fff;
+      color: #fff;
       cursor: pointer;
     }
   }
-  .supervip-bg{
+
+  .supervip-bg {
     display: flex;
     align-items: center;
     justify-content: space-between;
@@ -899,23 +927,26 @@ export default {
     background: url('~@/assets/images/vip-bg.png') no-repeat center center;
     background-size: 100% 100%;
     border-radius: 8px;
-    .vip-balance{
+
+    .vip-balance {
       font-size: 14px;
       color: #686868;
     }
-    .update-btn{
+
+    .update-btn {
       width: 90px;
       height: 30px;
       line-height: 30px;
       text-align: center;
       background: #2CB7CA;
       border-radius: 4px;
-      color:#fff;
+      color: #fff;
       font-size: 14px;
       cursor: pointer;
     }
   }
-  .fixedBanner{
+
+  .fixedBanner {
     position: fixed;
     top: 63px;
     left: 50%;

Разница между файлами не показана из-за своего большого размера
+ 1336 - 0
src/views/portrayal/components/DynamicList.vue


+ 179 - 0
src/views/portrayal/components/DynamicListItem.vue

@@ -0,0 +1,179 @@
+<template>
+  <div class="article-item">
+    <input @click.stop class="custom-checkbox title-text-checkbox" name="bid-list" type="checkbox" :dataid="article.id">
+    <div class="item-right">
+      <div class="row-1">
+        <div class="a-i-left ellipsis visited-hd" @click="onClick" v-html="calcTitle"></div>
+        <i class="icon-collect" @click.stop="collectChange(article, $event)" :class="{'checked': article.collection}"
+           :dataid="article.id"></i>
+      </div>
+      <div class="row-2">
+        <div class="tags">
+          <span class="tag" v-if="article.area">{{ article.area }}</span>
+          <span class="tag" v-if="article.bidstatus">{{ article.bidstatus }}</span>
+          <span class="tag" v-if="calcBudget">{{ calcBudget }}</span>
+        </div>
+        <span class="time-text">
+          <slot name="right-time">{{ dateFromNow(article.firsttime * 1000) }}</slot>
+        </span>
+      </div>
+    </div>
+  </div>
+</template>
+<script>
+import { Tag } from 'element-ui'
+import { moneyUnit, dateFromNow } from '@/utils/'
+
+export default {
+  name: 'portrayal-article-item',
+  components: {
+    [Tag.name]: Tag
+  },
+  props: {
+    index: {
+      type: [String, Number],
+      default: '1'
+    },
+    article: {
+      type: Object,
+      default () {
+        return {
+          title: '', // 标题
+          area: '', // 区域
+          bidstatus: '', // 类型
+          firsttime: 0, // 时间
+          budget: 0, // 预算金额
+          bidamount: 0 // 中标金额
+        }
+      }
+    }
+  },
+  computed: {
+    calcBudget () {
+      var cNum = 0
+      if (this.article.bidamount) {
+        cNum = this.article.bidamount
+      } else {
+        cNum = this.article.budget
+      }
+      if (cNum) {
+        return moneyUnit(cNum)
+      }
+      return ''
+    },
+    calcTitle () {
+      return `${this.article.title}`
+    }
+  },
+  methods: {
+    dateFromNow,
+    onClick () {
+      this.$emit('onClick')
+    },
+    collectChange (item, event) {
+      this.$emit('onCollect', {
+        item: item,
+        event: event
+      })
+    }
+  }
+}
+</script>
+<style>
+.custom-toast .toast-container {
+  /* display: none; */
+  position: fixed;
+  top: 50%;
+  left: 50%;
+  width: auto;
+  padding: 16px 32px;
+  font-size: 16px;
+  background: rgba(0, 0, 0, 0.65);
+  border-radius: 8px;
+  color: #fff;
+  transform: translateX(-50%) translateY(-50%);
+  z-index: 99;
+}
+</style>
+<style lang="scss" scoped>
+$border-color: #ECECEC;
+@include diy-icon('time', 20, 20);
+
+.article-item {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 22px 16px;
+  border-bottom: 1px solid $border-color;
+  cursor: pointer;
+
+  .item-right {
+    width: 100%;
+    display: flex;
+    flex-direction: column;
+    overflow: hidden;
+
+    .row-1, .row-2 {
+      display: flex;
+      flex-direction: row;
+      justify-content: space-between;
+    }
+
+    .row-2 {
+      padding-top: 8px;
+    }
+  }
+
+  &:first-of-type,
+  &:border-top {
+    border-top: 1px solid $border-color;
+  }
+
+  .icon-collect {
+    display: inline-block;
+    width: 20px;
+    height: 20px;
+    margin-left: 6px;
+    background: transparent url(https://cdn-ali.jianyu360.com/images/collect.png) center no-repeat;
+    background-size: contain;
+    cursor: pointer;
+    vertical-align: sub;
+  }
+
+  .icon-collect.checked {
+    background: transparent url(https://cdn-ali.jianyu360.com/images/collected.png) center no-repeat;
+    background-size: contain;
+  }
+
+  .a-i-left {
+    flex: 1;
+  }
+
+  .a-i-right,
+  .tags,
+  .time-container {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+  }
+
+  .tag {
+    display: flex;
+    align-items: center;
+    padding: 1px 6px;
+    margin-right: 14px;
+    color: #2ABED1;
+    font-size: 13px;
+    line-height: 20px;
+    background: rgba(44, 183, 202, 0.08);
+    border-radius: 3px;
+  }
+
+  .time-text {
+    margin-left: 6px;
+    font-size: 14px;
+    color: #797a7e;
+    line-height: 24px;
+  }
+}
+</style>

+ 55 - 31
src/views/portrayal/components/EntChart.vue

@@ -31,7 +31,7 @@
     </div>
     <!-- 重点客户 -->
     <div v-if="keyClient.show">
-      <div class="chart-title">重点客户</div>
+      <div class="chart-title">重点及首次合作客户</div>
       <progress-chart type="ent" :datas="keyClient.data"></progress-chart>
     </div>
   </div>
@@ -44,6 +44,7 @@ import PieChart from '@/components/chart/PieChart'
 import ProgressChart from '@/components/chart/ProgressChart'
 import { getEntChart } from '@/api/modules/'
 import { bSort, moneyUnit } from '@/utils/'
+
 export default {
   name: 'ent-chart',
   props: {
@@ -76,9 +77,18 @@ export default {
           colors: [new this.$echarts.graphic.LinearGradient(
             0, 1, 0, 0,
             [
-              { offset: 0, color: '#2ABED1' },
-              { offset: 0.5, color: '#2ABED1' },
-              { offset: 1, color: '#8DE0EB' }
+              {
+                offset: 0,
+                color: '#2ABED1'
+              },
+              {
+                offset: 0.5,
+                color: '#2ABED1'
+              },
+              {
+                offset: 1,
+                color: '#8DE0EB'
+              }
             ], false
           ), '#FF9F40'],
           settings: {
@@ -168,20 +178,9 @@ export default {
       },
       deep: true
     }
-    // active: {
-    //   handler (newVal) {
-    //     if (newVal === '2') {
-    //       this.$nextTick(() => {
-    //         // 初始化图表
-    //         // this.initChartsData()
-    //         this.getChartData()
-    //       })
-    //     }
-    //   },
-    //   deep: true
-    // }
   },
-  created () {},
+  created () {
+  },
   mounted () {
     this.$nextTick(() => {
       // 初始化图表
@@ -294,7 +293,9 @@ export default {
           allNum.push(data[key][n])
         }
       }
-      yearArr.sort((a, b) => { return a - b })
+      yearArr.sort((a, b) => {
+        return a - b
+      })
       // 2. 循环12个月份,并进行处理
       yearArr.forEach((item) => {
         columns.push(item + '年')
@@ -316,7 +317,9 @@ export default {
         })
         rows.push(columnsItem)
       }
-      const maxNum = Math.max.apply(Math, allNum.map((o) => { return o }))
+      const maxNum = Math.max.apply(Math, allNum.map((o) => {
+        return o
+      }))
       console.log('数据最大值为:', maxNum)
       if (count !== 0 && maxNum !== 0) {
         this.monthZb.show = true
@@ -375,7 +378,9 @@ export default {
       for (const key in data['全部客户']) {
         yearArr.push(key)
       }
-      yearArr.sort((a, b) => { return a - b })
+      yearArr.sort((a, b) => {
+        return a - b
+      })
       yearArr.forEach((item) => {
         const rowsItem = {
           '日期': item + '年' // eslint-disable-line
@@ -445,8 +450,10 @@ export default {
         data.forEach((list) => {
           const i1 = {
             buyerclass: list.buyerclass,
-            topData: []
+            topData: [],
+            firstData: []
           }
+          // 重点客户
           if (list.topData && $.isArray(list.topData)) {
             list.topData.forEach((item) => {
               i1.topData.push({
@@ -459,16 +466,27 @@ export default {
               })
             })
           }
-          if (!list.buyerclass || ($.isArray(list.topData) && list.topData.length === 0)) {
-            // console.log('此数据为空')
-            this.keyClient.show = false
-          } else {
+          // 首次合作客户
+          if (list.firstData && $.isArray(list.firstData)) {
+            list.firstData.forEach((item) => {
+              i1.firstData.push({
+                name: item.BuyerName,
+                money: item.CountMoney,
+                count: item.CountProject,
+                rate: item.AvgRate ? (item.AvgRate * 100).fixed(2) : item.AvgRate,
+                time: new Date(item.lastTime * 1000).pattern('yyyy/MM/dd'),
+                parent: item.CountMoney / list.firstData[0].CountMoney * 100 + '%'
+              })
+            })
+          }
+          // 重点客户无数据时,首次合作客户必无数据
+          if (list.buyerclass && ($.isArray(list.topData) && list.topData.length > 0)) {
             arr.push(i1)
           }
         })
       }
       this.keyClient.data = arr
-      this.keyClient.show = true
+      this.keyClient.show = arr.length > 0
     },
     /* *********** 配置项 *********** */
     // 1. 年度项目统计图表单独配置
@@ -540,8 +558,12 @@ export default {
     areaFbConfig (options) {
       const arr = this.areaFb.data.rows
       // 最大值、最小值
-      const maxNum = Math.max.apply(Math, arr.map((o) => { return o.value }))
-      const minNum = Math.min.apply(Math, arr.map((o) => { return o.value }))
+      const maxNum = Math.max.apply(Math, arr.map((o) => {
+        return o.value
+      }))
+      const minNum = Math.min.apply(Math, arr.map((o) => {
+        return o.value
+      }))
       options.visualMap.min = minNum
       options.visualMap.max = maxNum < 100 ? 100 : maxNum
       // 设置最大值
@@ -603,16 +625,18 @@ export default {
 }
 </script>
 <style lang="scss" scoped>
-.ent-chart{
+.ent-chart {
   background: #fff;
-  .chart-title{
+
+  .chart-title {
     padding: 32px 0 16px;
     font-size: 18px;
     color: #1d1d1d;
     line-height: 28px;
     font-family: 'Microsoft YaHei, Microsoft YaHei-Regular';
   }
-  .chart-tips{
+
+  .chart-tips {
     padding: 10px 0 32px;
     font-size: 12px;
     color: #999999;

+ 1 - 1
src/views/portrayal/components/EntSubVipChart.vue

@@ -31,7 +31,7 @@
     </div>
     <!-- 重点客户 -->
     <div v-if="keyClient.show">
-      <div class="chart-title">重点客户</div>
+      <div class="chart-title">重点及首次合作客户</div>
       <progress-chart type="ent" :datas="keyClient.data"></progress-chart>
     </div>
   </div>

+ 30 - 3
src/views/portrayal/components/ProActive.vue

@@ -4,8 +4,8 @@
       {{title}}
     </div>
     <div class="pro_ul" v-if="!isShow">
-      <div class="pro_list" v-for="(item, index) in getList" :key="index">
-        <div class="pro_li_title" @click="setLink(item)">{{item.projectname || item.title}}</div>
+      <div class="pro_list" :class="{ visited: item.visited }" v-for="(item, index) in getList" :key="index">
+        <div class="pro_li_title visited-hd" @click="setLink(item)">{{item.projectname || item.title}}</div>
         <div class="pro_li_info">
           <div class="li_left">
             <span class="tags">{{item.area}}</span>
@@ -38,9 +38,11 @@
 import { Pagination } from 'element-ui'
 import Empty from '@/components/common/Empty'
 import { moneyUnit, dateFormatter } from '@/utils'
+import { mixinVisited } from '@/utils/mixins/visited'
 export default {
   props: ['projectData', 'title', 'type', 'isactive'],
   name: 'proactive',
+  mixins: [mixinVisited],
   components: {
     [Pagination.name]: Pagination,
     Empty
@@ -84,7 +86,18 @@ export default {
     dateFormatter,
     initData (obj) {
       if (obj.proActiveList && obj.proActiveList.length !== 0) {
-        this.listState.list = obj.proActiveList
+        this.listState.list = obj.proActiveList.map(item => {
+          const visited = this.pathVisited(
+            this.createPathItem(
+              '/article/content/*.html',
+              `id=${item.id}`
+            )
+          )
+          return {
+            ...item,
+            visited
+          }
+        })
         this.listState.total = obj.count
         this.isShow = false
       } else if (obj.buyerHistroyList && obj.buyerHistroyList !== 0) {
@@ -96,7 +109,14 @@ export default {
       }
     },
     setLink (data) {
+      data.visited = true
       if (data.title && data.id) {
+        this.pathVisiting(
+          this.createPathItem(
+            '/article/content/*.html',
+            `id=${data.id}`
+          )
+        )
         window.open(`/article/content/${data.id}.html`, '_blank')
         return
       }
@@ -107,6 +127,13 @@ export default {
           // fid: data._id
         }
       })
+      this.pathVisiting(
+        this.createPathItem(
+          '/pro_follow_detail/*',
+          `id=${data.infoid}`
+        )
+      )
+
       return window.open(routeUrl.href, '_blank')
     },
     onPageChange (p) {

+ 46 - 23
src/views/portrayal/components/UnitChart.vue

@@ -38,7 +38,12 @@
     <!-- 重点合作企业 -->
     <div v-if="client.data.length > 0">
       <div class="chart-title">重点合作企业</div>
-      <progress-chart type="unit"  :datas="client.data"></progress-chart>
+      <pro-chart type="unit"  :datas="client.data"></pro-chart>
+    </div>
+    <!-- 首次合作企业 -->
+    <div v-if="firhz.data.length > 0">
+      <div class="chart-title">首次合作企业</div>
+      <pro-chart type="ent"  :datas="firhz.data"></pro-chart>
     </div>
     <!-- 合作企业注册资本分布 -->
     <div v-if="capital.show">
@@ -68,7 +73,7 @@ import HotChart from '@/components/chart/HotChart'
 import LineChart from '@/components/chart/LineChart'
 import DoubleBarChart from '@/components/chart/DoubleBarChart'
 import PieChart from '@/components/chart/PieChart'
-import ProgressChart from '@/components/chart/ProgressChart'
+import ProChart from '@/components/chart/ProChart'
 import MapChart from '@/components/chart/MapChart'
 import BlueProgressChart from '@/components/chart/BlueProgressChart'
 import { getUnitChart, getVipUnitChart } from '@/api/modules/'
@@ -81,7 +86,7 @@ export default {
     LineChart,
     DoubleBarChart,
     PieChart,
-    ProgressChart,
+    ProChart,
     MapChart,
     BlueProgressChart
   },
@@ -182,6 +187,12 @@ export default {
         flag: false,
         data: []
       },
+      // 重点合作企业
+      firhz: {
+        show: false,
+        flag: false,
+        data: []
+      },
       // 合作企业注册资本分布
       capital: {
         show: false,
@@ -282,12 +293,14 @@ export default {
         // 各行业项目平均节支率
         this.formatSavingsRateData(res.rate)
         // 各行业项目规模占比
-        this.formatProjectScaleData(res.top12)
+        this.formatProjectScaleData(res.withBusinessData)
         // 重点合作代理机构
         this.formatAgencyData(res.topAgencyData)
       } else if (flag === 'b') {
         // 重点合作企业
-        this.formatClientData(res.topShow)
+        this.formatClientData(res.topWinner)
+        // 首次合作企业
+        this.formatFirhzData(res.firstWinner)
       } else if (flag === 'c') {
         // 合作企业注册资本分布
         this.formatCapitalData(res.withCapitalData)
@@ -309,9 +322,11 @@ export default {
         // 各行业项目平均节支率
         this.formatSavingsRateData(res.rate)
         // 各行业项目规模占比
-        this.formatProjectScaleData(res.top12)
+        this.formatProjectScaleData(res.withBusinessData)
         // 重点合作企业
-        this.formatClientData(res.topShow)
+        this.formatClientData(res.topWinner)
+        // 首次合作企业
+        this.formatFirhzData(res.firstWinner)
         // 合作企业注册资本分布
         this.formatCapitalData(res.withCapitalData)
         // 合作企业年龄分布
@@ -843,12 +858,12 @@ export default {
         const arr = []
         // 降序排列
         data.sort((a, b) => {
-          return b.bidamount_share - a.bidamount_share
+          return b.money_prop - a.money_prop
         })
         data.forEach((item) => {
-          item.bidamount_share = item.bidamount_share !== null && !isNaN(item.bidamount_share) ? (item.bidamount_share * 100).fixed(2) + '%' : '--'
+          item.money_prop = item.money_prop !== null && !isNaN(item.money_prop) ? (item.money_prop * 100).fixed(2) + '%' : '--'
           item.rate_avg = item.rate_avg !== null && !isNaN(item.rate_avg) ? (item.rate_avg * 100).fixed(2) + '%' : '--'
-          arr.push(item.scopeclassName, item.bidamount_share, item.bidamount_count, item.project_count, item.rate_avg)
+          arr.push(item.business_name, item.money_prop, item.money_count, item.project_count, item.rate_avg)
         })
         const normal = ['行业', '采购规模占比', '采购规模', '采购项目数量', '平均节支率']
         var newArr = this.arrTrans(5, arr)
@@ -988,20 +1003,10 @@ export default {
     formatClientData (data) {
       if (data && data.length > 0) {
         data.forEach((v, i) => {
-          v.topData.forEach((s, j) => {
-            s.parent = s.countMoney / v.topData[0].countMoney * 100 + '%'
-            s.lastTime = new Date(Number(s.lastTime + '000')).pattern('yyyy/MM/dd')
-          })
-        })
-        const newData = data.map((v) => {
-          v.topData = v.topData.filter((s) => {
-            return s.winnerName && s.winnerName.trim().length
-          })
-          return v
-        }).filter(function (v, i) {
-          return v.topData.length
+          v.parent = v.amount / data[0].amount * 100 + '%'
+          v.lastTime = new Date(Number(v.firstTime + '000')).pattern('yyyy/MM/dd')
         })
-        this.client.data = newData
+        this.client.data = data
         this.client.flag = true
         this.client.show = true
         this.allBool.push(true)
@@ -1012,6 +1017,24 @@ export default {
         this.client.show = false
       }
     },
+    // 格式化首次合作企业数据
+    formatFirhzData (data) {
+      if (data && data.length > 0) {
+        data.forEach((v, i) => {
+          v.parent = v.amount / data[0].amount * 100 + '%'
+          v.lastTime = new Date(Number(v.firstTime + '000')).pattern('yyyy/MM/dd')
+        })
+        this.firhz.data = data
+        this.firhz.flag = true
+        this.firhz.show = true
+        this.allBool.push(true)
+      } else {
+        this.allBool.push(false)
+        this.firhz.data = []
+        this.firhz.flag = false
+        this.firhz.show = false
+      }
+    },
     // 格式化重点合作代理机构数据
     formatAgencyData (data) {
       if (data && data.length > 0) {

+ 22 - 5
src/views/portrayal/components/UnitList.vue

@@ -2,8 +2,8 @@
   <div class="dynamic" v-show="domShow">
     <div class="d-title">招标动态</div>
     <div class="d-content" v-if="showDt">
-      <div class="d-list" v-for="item in dt.list" :key="item.id" @click="goDetail(item.id)">
-        <div class="d-title">{{item.title}}</div>
+      <div class="d-list" :class="{ visited: item.visited }" v-for="item in dt.list" :key="item.id" @click="goDetail(item)">
+        <div class="d-title visited-hd">{{item.title}}</div>
         <div class="d-info">
           <p class="i-main">
             <span v-if="item.area" class="i-area">{{item.area}}</span>
@@ -29,8 +29,8 @@
       :title="getDialogInfo.title"
       :visible.sync="isDialogShow"
     >
-        <div class="unit-dialog-content">{{getDialogInfo.content}}</div>
-        <span slot="footer" class="unit-dialog-footer">
+      <div class="unit-dialog-content">{{getDialogInfo.content}}</div>
+      <span slot="footer" class="unit-dialog-footer">
           <el-button type="primary" @click="openBigPage">{{getButtonTip}}</el-button>
           <el-button @click="isDialogShow = false">取消</el-button>
         </span>
@@ -59,9 +59,11 @@ import { getUnitDt, getVipUnitDt } from '@/api/modules/'
 import { moneyUnit } from '@/utils/'
 import Empty from '@/components/common/Empty'
 import { Pagination, Dialog, Button } from 'element-ui'
+import { mixinVisited } from '@/utils/mixins/visited'
 import { mapState } from 'vuex'
 export default {
   name: 'dynamic',
+  mixins: [mixinVisited],
   components: {
     [Pagination.name]: Pagination,
     [Dialog.name]: Dialog,
@@ -202,6 +204,13 @@ export default {
           res.data.list.forEach((v, i) => {
             v.firsttime = new Date(Number(v.firsttime + '000')).pattern('yyyy/MM/dd')
             v.bidamount = v.bidamount ? moneyUnit(v.bidamount) : ''
+            const visited = this.pathVisited(
+              this.createPathItem(
+                '/article/content/*.html',
+                `id=${v.id}`
+              )
+            )
+            this.$set(v, 'visited', visited)
           })
           this.showDt = true
           if (res.data.count >= 0) {
@@ -248,7 +257,15 @@ export default {
       this.dt.pageNum = currentPage
       this.getUnitDtFn(this.bidataparams)
     },
-    goDetail (id) {
+    goDetail (item) {
+      const id = item.id
+      item.visited = true
+      this.pathVisiting(
+        this.createPathItem(
+          '/article/content/*.html',
+          `id=${id}`
+        )
+      )
       return window.open('/article/content/' + id + '.html')
     },
     closeDialog (data) {

+ 2 - 2
src/views/reportData/pageMonth.vue

@@ -21,8 +21,8 @@
             </div>
             <div class="data_line"></div>
             <div class="data_item">
-              <p class="item_handle">数据来源:已为您推送的招标项目信息</p>
-              <p class="item_handle">项目预算/项目规模:少量预算金额、中标金额未公开或为空的项目,将通过剑鱼标讯预测模型进行填补,可能会与实际项目预算、项目规模略有差距;</p>
+              <p class="item_handle">数据来源:基于您当前订阅条件所关联的招标项目数据;</p>
+              <p class="item_handle">项目预算/项目规模:少量预算金额、中标金额未公开或为空的项目,在计算项目总预算、总规模时不参与统计;</p>
               <p class="item_handle">项目重复统计:一个招标项目可能同属于多个关键词组,故各关键词组的数据统计之和可能大于整体市场的统计。</p>
             </div>
           </div>

+ 2 - 2
src/views/reportData/pageWeek.vue

@@ -41,8 +41,8 @@
           </div>
           <div class="data_line"></div>
           <div class="data_item">
-            <p class="item_handle">数据来源:已为您推送的招标项目信息</p>
-            <p class="item_handle">项目预算/项目规模:少量预算金额、中标金额未公开或为空的项目,将通过剑鱼标讯预测模型进行填补,可能会与实际项目预算、项目规模略有差距;</p>
+            <p class="item_handle">数据来源:基于您当前订阅条件所关联的招投标公告数据;</p>
+            <p class="item_handle">项目预算/项目规模:少量预算金额、中标金额未公开或为空的项目,在计算项目总预算、总规模时不参与统计;</p>
             <p class="item_handle">项目重复统计:一个招标项目可能同属于多个关键词组,故各关键词组的数据统计之和可能大于整体市场的统计。</p>
           </div>
         </div>

+ 54 - 7
src/views/work-desktop/WorkDesktop.vue

@@ -67,8 +67,10 @@ import HomePotenList from '@/components/home/HomePotenList.vue'
 import { dateFormatter, replaceKeyword } from '@/utils/'
 import { getPushList, getProjectHistory, getDeskFollowList, getEntCollectionList, getFollowProjectList, getReportList, getIndexCorList, setStatusCustomer, setFollowEnt, setRemoveEnt, setRemoveCustomer } from '@/api/modules/'
 import { mapState } from 'vuex'
+import { mixinVisited } from '@/utils/mixins/visited'
 export default {
   name: 'work-desktop',
+  mixins: [mixinVisited],
   components: {
     UserInfo,
     MessageTips,
@@ -115,8 +117,16 @@ export default {
     initData () {
       // 订阅信息
       getPushList({ pageNum: 1, pageSize: 5, format: 'table', area: '', time: '' }).then(res => {
-        console.log(res)
-        if (res && res.data) {
+        if (res && Array.isArray(res.data)) {
+          res.data.forEach(item => {
+            const visited = this.pathVisited(
+              this.createPathItem(
+                '/article/content/*.html',
+                `id=${item._id}`
+              )
+            )
+            this.$set(item, 'visited', visited)
+          })
           this.getList = res.data
           this.$refs.sublist1.haskey = res.haskey
           this.$refs.sublist1.isSubCount = this.info.isSubCount
@@ -128,12 +138,19 @@ export default {
       // 企业情报监控
       getDeskFollowList({ pageNum: 0, pageSize: 5 }).then(res => {
         if (res.error_code === 0 && res.data) {
-          if (res.data.list) {
+          if (Array.isArray(res.data.list)) {
             this.entList = res.data.list.map(item => {
+              const visited = this.pathVisited(
+                this.createPathItem(
+                  '/ent_portrait/*',
+                  `id=${item.s_entId}`
+                )
+              )
               return Object.assign(item, {
                 _id: item.s_entId,
                 projectName: item.s_entname,
                 publishtime: item.l_lastpushtime,
+                visited,
                 unread: item.i_apppushunread
               })
             })
@@ -157,9 +174,16 @@ export default {
       }).then(res => {
         if (res && res.error_code === 0 && res.data) {
           this.collectionList = res.data.res.map(item => {
+            const visited = this.pathVisited(
+              this.createPathItem(
+                '/article/content/*.html',
+                `id=${item._id}`
+              )
+            )
             return Object.assign(item, {
               _id: item._id,
               projectName: item.title,
+              visited,
               publishtime: item.publishtime
             })
           })
@@ -178,9 +202,16 @@ export default {
         if (res.error_code === 0 && res.data) {
           if (!res.data.List) return
           this.followList = res.data.List.map(item => {
+            const visited = this.pathVisited(
+              this.createPathItem(
+                '/pro_follow_detail/*',
+                `id=${item.sid}`
+              )
+            )
             return Object.assign(item, {
               projectName: item.title,
               publishtime: item.l_lastpushtime,
+              visited,
               unread: item.i_apppushunread
             })
           })
@@ -349,19 +380,35 @@ export default {
     },
     // 点击标题跳转
     getDetail (data) {
-      console.log(data)
+      data.item.visited = true
       let link = ''
       switch (data.model) {
         case 'model-1':
+        case 'model-3':
+          this.pathVisiting(
+            this.createPathItem(
+              '/article/content/*.html',
+              `id=${data.item._id}`
+            )
+          )
           link = '/article/content/' + data.item._id + '.html'
           break
         case 'model-2':
+          this.pathVisiting(
+            this.createPathItem(
+              '/ent_portrait/*',
+              `id=${data.item._id}`
+            )
+          )
           link = this.resolveLink('/ent_portrait/' + data.item._id)
           break
-        case 'model-3':
-          link = '/article/content/' + data.item._id + '.html'
-          break
         case 'model-4':
+          this.pathVisiting(
+            this.createPathItem(
+              '/pro_follow_detail/*',
+              `id=${data.item.sid}`
+            )
+          )
           link = this.resolveLink('/pro_follow_detail?sid=' + data.item.sid + '&fid=' + data.item.fid)
           break
         case 'model-week':

+ 6 - 26
vue.config.js

@@ -1,27 +1,4 @@
-const cdn = {
-  css: [
-    // '//unpkg.com/element-ui@2.10.1/lib/theme-chalk/index.css'
-  ],
-  jsdelivr: [
-    '//cdn.jsdelivr.net/npm/vue@2.6.11/dist/vue.min.js',
-    '//cdn.jsdelivr.net/npm/vue-router@3.1.5/dist/vue-router.min.js',
-    '//cdn.jsdelivr.net/npm/vuex@3.4.0/dist/vuex.min.js',
-    '//cdn.jsdelivr.net/npm/axios@0.19.2/dist/axios.min.js',
-    '//cdn.jsdelivr.net/npm/echarts@4.8.0/dist/echarts.min.js',
-    '//cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js',
-    '//cdn.jsdelivr.net/npm/moment@2.29.1/moment.min.js'
-  ],
-  js: [
-    '//cdn-common.jianyu360.cn/cdn/lib/vue/2.6.11/vue.min.js',
-    '//cdn-common.jianyu360.cn/cdn/lib/vue-router/3.1.5/vue-router.min.js',
-    '//cdn-common.jianyu360.cn/cdn/lib/vuex/3.4.0/vuex.min.js',
-    '//cdn-common.jianyu360.cn/cdn/lib/axios/0.19.2/axios.min.js',
-    '//cdn-common.jianyu360.cn/cdn/lib/echarts/4.8.0/echarts.min.js',
-    '//cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js',
-    '//cdn.jsdelivr.net/npm/moment@2.29.1/moment.min.js'
-  ]
-}
-
+const { cdn, getProxyOfDomain, getProxyOfIp } = require('./config')
 module.exports = {
   parallel: false,
   productionSourceMap: false,
@@ -29,7 +6,6 @@ module.exports = {
   publicPath: process.env.VUE_APP_BASE_PUBLIC,
   lintOnSave: true,
   devServer: {
-    port: '8080',
     disableHostCheck: true,
     proxy: {
       // 反爬虫接口代理
@@ -83,7 +59,11 @@ module.exports = {
         changeOrigin: true,
         logLevel: 'debug'
       }
-    }
+    },
+    headers: {
+      'Access-Control-Allow-Origin': '*'
+    },
+    proxy: getProxyOfDomain('https://web2-jytest.jydev.jianyu360.com') || getProxyOfIp('http://127.0.0.1')
   },
   css: {
     loaderOptions: {

Некоторые файлы не были показаны из-за большого количества измененных файлов