소스 검색

Merge branch 'master' into dev1.4.4

lianbingjie 3 년 전
부모
커밋
1001035423
38개의 변경된 파일2655개의 추가작업 그리고 591개의 파일을 삭제
  1. 23 0
      config/cdn.js
  2. 8 0
      config/index.js
  3. 87 0
      config/proxy.js
  4. 43 0
      src/api/modules/dataExport.js
  5. 1 0
      src/api/modules/index.js
  6. BIN
      src/assets/images/big/1-big.png
  7. BIN
      src/assets/images/big/8-big.png
  8. BIN
      src/assets/images/big/88-big.png
  9. BIN
      src/assets/images/big/bg/1-bg.png
  10. BIN
      src/assets/images/icon/collect.png
  11. BIN
      src/assets/images/icon/collected.png
  12. BIN
      src/assets/images/icon/export.png
  13. BIN
      src/assets/images/icon/tab-list.png
  14. BIN
      src/assets/images/icon/tab-table.png
  15. BIN
      src/assets/images/vip/010.png
  16. BIN
      src/assets/images/vip/1.png
  17. BIN
      src/assets/images/vip/7.png
  18. BIN
      src/assets/images/vip/bg/mask/02.png
  19. BIN
      src/assets/images/vip/bg/mask/10.png
  20. 3 2
      src/assets/js/selector.js
  21. 13 0
      src/assets/style/reset-ele.scss
  22. 196 0
      src/components/chart/ProChart.vue
  23. 129 41
      src/components/chart/ProgressChart.vue
  24. 67 17
      src/components/collect-info/CollectInfo.vue
  25. 114 58
      src/components/contact-info/ContactInfo.vue
  26. 11 4
      src/components/mask-card/MaskCard.vue
  27. 1 0
      src/main.js
  28. 1 1
      src/utils/globalFunctions.js
  29. 131 110
      src/views/portrayal/EntPortrayal.vue
  30. 132 165
      src/views/portrayal/EntSearchPortrayal.vue
  31. 95 64
      src/views/portrayal/UnitPortrayal.vue
  32. 1312 0
      src/views/portrayal/components/DynamicList.vue
  33. 179 0
      src/views/portrayal/components/DynamicListItem.vue
  34. 55 31
      src/views/portrayal/components/EntChart.vue
  35. 1 1
      src/views/portrayal/components/EntSubVipChart.vue
  36. 46 23
      src/views/portrayal/components/UnitChart.vue
  37. 2 2
      src/views/portrayal/components/UnitList.vue
  38. 5 72
      vue.config.js

+ 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'
+    }
+  }
+}

+ 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;

+ 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>

+ 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;

+ 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

+ 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') {

+ 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%;

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1312 - 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" @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>

+ 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) {

+ 2 - 2
src/views/portrayal/components/UnitList.vue

@@ -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>

+ 5 - 72
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,55 +6,11 @@ module.exports = {
   publicPath: process.env.VUE_APP_BASE_PUBLIC,
   lintOnSave: true,
   devServer: {
-    port: '8080',
     disableHostCheck: true,
-    proxy: {
-      // 反爬虫接口代理
-      // '/subVipPortrait/winner': {
-      //   target: 'http://192.168.20.178:8800',
-      //   changeOrigin: true,
-      //   logLevel: 'debug'
-      // },
-      '^/bigmember': {
-        // target: 'https://web2-jytest.jydev.jianyu360.com',
-        target: 'http://127.0.0.1:814',
-        changeOrigin: true,
-        logLevel: 'debug',
-        pathRewrite: {
-          '^/bigmember': '/bigmember'
-        }
-      },
-      '^/jypay': {
-        // target: 'https://web2-jytest.jydev.jianyu360.com',
-        target: 'http://127.0.0.1:86',
-        changeOrigin: true,
-        logLevel: 'debug'
-      },
-      '^/publicapply': {
-        // target: 'https://web2-jytest.jydev.jianyu360.com',
-        target: 'http://127.0.0.1:828',
-        changeOrigin: true,
-        logLevel: 'debug'
-      },
-      '^/subscribepay': {
-        // target: 'https://web2-jytest.jydev.jianyu360.com',
-        target: 'http://127.0.0.1:86',
-        changeOrigin: true,
-        logLevel: 'debug'
-      },
-      '^/salesLeads': {
-        // target: 'https://web2-jytest.jydev.jianyu360.com',
-        target: 'http://127.0.0.1:8881',
-        changeOrigin: true,
-        logLevel: 'debug'
-      },
-      '^/privatedata': {
-        // target: 'https://web2-jytest.jydev.jianyu360.com',
-        target: 'http://127.0.0.1:829',
-        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: {

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.