Przeglądaj źródła

中标、投标预测

TANGSHIZHE 4 lat temu
rodzic
commit
731d51c66d

+ 31 - 1
src/api/modules/forecast.js

@@ -55,7 +55,37 @@ export function getBidAssociation (data) {
 export function getBidProjectInfo (data) {
   data = qs.stringify(data)
   return request({
-    url: '/search/analysis/projectInfo',
+    url: '/analysis/projectInfo',
+    method: 'post',
+    data: data
+  })
+}
+
+// 中标预测预测数据接口
+export function getForWData (data) {
+  // data = qs.stringify(data)
+  return request({
+    url: '/forecast/forWData',
+    method: 'post',
+    data: data
+  })
+}
+
+// 中标预测数据状态接口
+export function getForWStatus (data) {
+  data = qs.stringify(data)
+  return request({
+    url: '/forecast/forWStatus',
+    method: 'post',
+    data: data
+  })
+}
+
+// 中标预测数据状态接口
+export function getForWResult (data) {
+  data = qs.stringify(data)
+  return request({
+    url: '/forecast/forWResult',
     method: 'post',
     data: data
   })

+ 20 - 37
src/components/forecast/ForLimit.vue

@@ -9,7 +9,7 @@
         <div class="pur_con_label">采购内容:</div>
         <div class="pur_con_value">
           <div class="con_ipt_complete" v-for="(item, index) in content" :key="index">
-            <span type="text" class="con_val">{{item}}<span class="con_del" @click="conDel(index)"></span></span>
+            <span class="con_val">{{item}}<span class="con_del" @click="conDel(index)"></span></span>
           </div>
           <div class="con_ipt" v-if="isAdd">
             <input type="text" class="con_val" placeholder="请输入采购内容" v-model="unitContent" @change="setPurContent()">
@@ -31,7 +31,7 @@
         </div>
         <div class="pur_budget pur_common">
           <div class="pur_bud_label pur_common_label">项目预算:</div>
-          <input type="text" placeholder="请输入项目预算"  class="pur_bud_ipt">
+          <input type="text" placeholder="请输入项目预算" v-model="unitBudget"  class="pur_bud_ipt">
           <span class="pur_bud_unit">万元</span>
         </div>
       </div>
@@ -39,6 +39,8 @@
       <AreaSelector
         ref="areaSelector"
         selectorType="line"
+        :singleChoice="true"
+        @onChange="onChange"
       />
       <!-- 提示 -->
       <div class="limit_tips">请确保以上所有内容的准确性,以免信息不够完善造成预测失败,从而浪费预测额度。</div>
@@ -62,30 +64,15 @@ export default {
   data () {
     return {
       content: [],
+      area: {},
       isAdd: true,
       isShow: false,
       unitContent: '',
       unitValue: '',
+      unitBudget: '',
       AssoList: [],
       ptid: '', // 项目加密id
-      sourceinfoid: '', // 信息加密id
-      params: {
-        // pname: '园林景观工程',
-        // id: 'ABCY2FdcS4/GSsvNGtyZ1woMSRfFSNjdn9iKzgvIC5FZFZzbx1UCkY=',
-        // infoid: 'ABCY2EEfy4oJyg7NH92c2UoDScoGj10XFJ%2BKCgCOS4eZFNwBQFUCPs%3D',
-        // buyerContent: [
-        //   '花草',
-        //   '景观'
-        // ],
-        // buyer: '柳州市龙建投资发展有限责任公司',
-        // budget: 22.5,
-        // area: '河南',
-        // city: '郑州市',
-        // agency: '招标代理机构',
-        // buyertel: '采购联系电话',
-        // buyerperson: '采购联系人',
-        // redisFKey: ''
-      }
+      sourceinfoid: '' // 信息加密id
     }
   },
   created () {
@@ -123,6 +110,11 @@ export default {
         this.getAssociation(this.unitValue)
       }
     },
+    // 地区
+    onChange (data) {
+      console.log(data)
+      this.area = data
+    },
     getAssociation (pname) {
       getBidAssociation({ name: pname }).then(res => {
         if (res.error_code === 0) {
@@ -138,23 +130,14 @@ export default {
     startFore () {
       const areaObj = this.$refs.areaSelector.getSelectedCity()
       console.log(areaObj)
-      this.params = {
-        pname: '园林景观工程',
-        id: 'ABCY2FdcS4/GSsvNGtyZ1woMSRfFSNjdn9iKzgvIC5FZFZzbx1UCkY=',
-        infoid: 'ABCY2EEfy4oJyg7NH92c2UoDScoGj10XFJ%2BKCgCOS4eZFNwBQFUCPs%3D',
-        buyerContent: [
-          '花草',
-          '景观'
-        ],
-        buyer: '柳州市龙建投资发展有限责任公司',
-        budget: 22.5,
-        area: '河南',
-        city: '郑州市',
-        agency: '招标代理机构',
-        buyertel: '采购联系电话',
-        buyerperson: '采购联系人',
-        redisFKey: ''
+      const limitparams = {
+        buyerContent: this.content,
+        buyer: this.unitValue,
+        budget: this.unitBudget,
+        area: this.area
       }
+      console.log(this)
+      this.$emit('getLimit', limitparams)
     }
   }
 }
@@ -162,7 +145,7 @@ export default {
 
 <style lang="scss" scoped>
   .forlimit{
-    margin-top: 32px;
+    margin: 32px auto;
     padding: 32px 40px;
     width: 1200px;
     background: #ffffff;

+ 123 - 4
src/components/forecast/ForeCast.vue

@@ -1,7 +1,51 @@
 <template>
   <div class="listData">
     <div class="listData_title">{{ title }}</div>
-    <!-- 中标企业预测、投标决策分析 -->
+    <!-- 中标企业预测-->
+    <ul class="listData_ul" v-if="type=='bidfor'">
+      <li class="list_li" v-for="(item, index) in listState.list.slice((listState.pageNum - 1) * listState.pageSize, listState.pageNum * listState.pageSize)" :key="index" @click="goBidForcast(item.s_id, item.sourceinfoid)">
+        <div class="list_name">{{item.projectname}}</div>
+        <div class="list_unit">
+          <div class="pur_unit">
+            <span class="unit_label">采购单位:</span>
+            <span class="unit_name">{{item.buyer}}</span>
+          </div>
+          <div class="pur_unit">
+            <span class="unit_label">采购时间:</span>
+            <span class="unit_name">{{item.firsttime}}</span>
+          </div>
+        </div>
+      </li>
+    </ul>
+    <!-- 中标企业预测>预测结果>预测项目列表-->
+    <ul class="listData_ul" v-if="type=='bidforResult'">
+      <li class="list_li_result list_li" v-for="(item, index) in listState.list.slice((listState.pageNum - 1)* listState.pageSize, listState.pageNum * listState.pageSize)" :key="index" @click="goBidForcast(item.s_id, item.sourceinfoid)">
+        <div class="list_li_left">
+          <div class="result_chart">
+            <el-progress type="circle" :show-text="true"  :color="activeColor(index)" :width="44" :stroke-width="4" :percentage="50"></el-progress>
+            <div class="bidrete_text">中标概率</div>
+          </div>
+        </div>
+        <div class="list_li_right">
+          <div class="list_name">北京市工商行政管理局朝阳分局</div>
+          <div class="list_unit">
+            <div class="pur_unit">
+              <span class="unit_label">成立日期:</span>
+              <span class="unit_name">2014-03-04</span>
+            </div>
+            <div class="pur_unit">
+              <span class="unit_label">注册资本:</span>
+              <span class="unit_name">135000万元</span>
+            </div>
+            <div class="pur_unit">
+              <span class="unit_label">员工人数:</span>
+              <span class="unit_name">124人</span>
+            </div>
+          </div>
+        </div>
+      </li>
+    </ul>
+    <!-- 投标决策分析  -->
     <ul class="listData_ul" v-if="type=='bidfor'">
       <li class="list_li" v-for="(item, index) in listState.list.slice((listState.pageNum - 1) * listState.pageSize, listState.pageNum * listState.pageSize)" :key="index" @click="goForcast(item.s_id, item.sourceinfoid)">
         <div class="list_name">{{item.projectname}}</div>
@@ -119,13 +163,14 @@
 </template>
 
 <script>
-import { Pagination } from 'element-ui'
+import { Pagination, Progress } from 'element-ui'
 // import { getPushList } from '@/api/modules/'
 export default {
   props: ['type', 'title', 'mydata', 'myDataObj'],
   name: 'listData',
   components: {
-    [Pagination.name]: Pagination
+    [Pagination.name]: Pagination,
+    [Progress.name]: Progress
   },
   data () {
     return {
@@ -151,15 +196,35 @@ export default {
       this.entInitData(newVal)
     }
   },
+  computed: {
+    activeColor () {
+      return function (item) {
+        const val = Number(item)
+        console.log(val)
+        if (val === 0) {
+          return '#FF9F40'
+        } else if (val < 2 && val > 0) {
+          return '#0BD991'
+        } else if (val < 3 && val > 1) {
+          return '#0987FF'
+        } else {
+          return '#C0C4CC'
+        }
+      }
+    }
+  },
   methods: {
     initData (list) {
       this.listState.list = list
-      this.listState.total = list.length
+      // this.listState.total = list.length
     },
     entInitData (obj) {
       this.listState.list = obj.list
       this.listState.total = obj.total
     },
+    goBidForcast (id, sid) {
+      this.$router.push(`/bidforlimit/${id}/${sid}`)
+    },
     goForcast (id, sid) {
       this.$router.push(`/analysis/result/${id}/${sid}`)
     },
@@ -228,6 +293,60 @@ export default {
         }
       }
     }
+    // 中标预测--预测项目
+    .list_li_result{
+      padding: 14px 40px;
+      display: flex;
+      align-items: center;
+      width: 100%;
+      height: 108px;
+      .list_li_left{
+        display: flex;
+        flex-direction: column;
+        justify-content: center;
+        align-items: center;
+        width: 76px;
+        height: 100%;
+        .result_chart{
+          display: flex;
+          flex-direction: column;
+          justify-content: center;
+          align-items: center;
+          width: 100%;
+          .bidrete_text{
+            margin-top: 10px;
+            font-size: 14px;
+            color: #737278;
+          }
+        }
+        // .result_chart  ::v-deep svg>path:nth-child(2) {
+        //   stroke: #120D65;
+        // }
+      }
+      .list_li_right{
+        margin-left: 30px;
+        display: flex;
+        flex-direction: column;
+        justify-content: center;
+        .list_name{
+          font-size: 16px;
+          font-family: Microsoft YaHei, Microsoft YaHei-Regular;
+          font-weight: 400;
+          text-align: LEFT;
+          color: #1d1d1d;
+          line-height: 24px;
+          text-shadow: 0px -1px 0px 0px rgba(0,0,0,0.05) inset;
+        }
+        .list_unit{
+          display: flex;
+          align-items: center;
+          margin-top: 12px;
+          .pur_unit{
+            margin-right: 40px;
+          }
+        }
+      }
+    }
     // 潜在项目预测样式
     .poten_li{
       .list_name{

+ 2 - 1
src/components/selector/AreaSelector.vue

@@ -31,7 +31,7 @@ export default {
       default: 'card' // card/line
     },
     singleChoice: { // 是是否单选? 只有在selectorType=line下才会生效
-      type: Boolean,
+      // type: Boolean,
       default: false
     },
     // 初始化城市数据
@@ -59,6 +59,7 @@ export default {
       this.$emit('onConfirm', selectedCity)
     },
     onChange (selected) {
+      console.log(selected)
       this.$emit('onChange', selected)
     }
   }

+ 1 - 1
src/router.js

@@ -49,7 +49,7 @@ export default new Router({
     },
     // 中标企业预测-预测
     {
-      path: '/bidforlimit/:id',
+      path: '/bidforlimit/:ptid/:sourceinfoid',
       name: 'bidforlimit',
       component: () => import('@/views/bid-forecast/BidForecastLimit.vue')
     },

+ 3 - 0
src/views/bid-forecast/BidForecast.vue

@@ -33,6 +33,9 @@ export default {
 <style lang="scss" scoped>
 .bid-forcast{
   width: 100%;
+  ::v-deep .for_main{
+    background: #fff;
+  }
   .icon_ai{
     display: flex;
     align-items: center;

+ 196 - 8
src/views/bid-forecast/BidForecastLimit.vue

@@ -1,41 +1,229 @@
 <template>
   <div class="bid-forcast-limit">
-    <ForLimit></ForLimit>
+    <ForLimit :baseInfo="baseInfo" @getLimit="getLimit"></ForLimit>
+    <!-- 项目摘要 -->
+    <div class="bid_abstract">
+      <div class="bid_abs_title">项目摘要</div>
+      <div class="bid_abs_content">
+        <div class="bid_abs_inforone">
+          <span class="bid_unitText">采购单位</span>
+          <span class="bid_unitname">{{baseInfo.projectname}}</span>
+          <button class="bid_view_unit">查看采购单位画像</button>
+        </div>
+        <div class="bid_abs_infortwo">
+          <div class="bid_abs_base">
+            <span class="base_label">地区:</span>
+            <span class="base_main">{{baseInfo.area}}</span>
+          </div>
+          <div class="bid_abs_base">
+            <span class="base_label">采购联系人:</span>
+            <span class="base_main">琴月间 - 13332165469</span>
+          </div>
+          <div class="bid_abs_base">
+            <span class="base_label">地区招标代理机构:</span>
+            <span class="base_main">{{baseInfo.agency}}</span>
+          </div>
+        </div>
+      </div>
+    </div>
+    <ForeCast type="bidforResult" title="预测项目" :mydata="resData"></ForeCast>
   </div>
 </template>
 
 <script>
 import ForLimit from '@/components/forecast/ForLimit.vue'
-import { getResultDetail } from '@/api/modules'
+import { getResultDetail, getProjectInfo, getForWData, getForWStatus, getForWResult } from '@/api/modules'
+import ForeCast from '@/components/forecast/ForeCast'
 export default {
   name: 'bid-forcast-limit',
   components: {
-    ForLimit
+    ForLimit,
+    ForeCast
   },
   data () {
     return {
       paramlist: {
-        id: this.$route.params.id,
+        ptid: this.$route.path.split('/')[this.$route.path.split('/').length - 2], // 项目加密id
+        sid: this.$route.path.split('/')[this.$route.path.split('/').length - 1], // 信息加密id
         buyerContent: [],
         budget: 0
-      }
+      },
+      // 刚开始隐藏项目摘要和tab切换
+      proShow: false,
+      baseInfo: {}, // 项目摘要及类似项目分析基础数据(渲染页面及需传给子组件使用)
+      fid: '', // 预测成功返回的id
+      resData: []
     }
   },
   created () {
-    this.getData()
+    // this.getData()
+    this.getBaseInfo()
   },
   methods: {
     getData () {
       getResultDetail({ id: this.paramlist.id }).then(res => {
         console.log(res)
       })
+    },
+    // 获取项目基本信息
+    async getBaseInfo () {
+      const data = {
+        ptid: this.paramlist.ptid,
+        sourceinfoid: this.paramlist.sid,
+        D: 'detail'
+      }
+      const res = await getProjectInfo(data)
+      if (res.error_code === 0 && res.data) {
+        if (res.data.s_subscopeclass) {
+          if (res.data.s_subscopeclass.indexOf('_') > -1) {
+            res.data.s_subscopeclass = res.data.s_subscopeclass.substring(0, res.data.s_subscopeclass.indexOf('_'))
+          }
+        }
+        this.baseInfo = res.data
+      } else {
+        console.log(res.error_code)
+      }
+    },
+    // 获取筛选条件
+    getLimit (data) {
+      this.getProForWData(data)
+    },
+    async getProForWData (data) {
+      const item = {
+        appVersion: '',
+        area: data.area,
+        budget: data.budget,
+        buyer: data.buyer,
+        buyerContent: data.buyerContent,
+        city: '',
+        id: this.baseInfo.id,
+        infoid: this.baseInfo.infoid,
+        mobileModel: '',
+        pname: this.baseInfo.projectname,
+        type: ''
+      }
+      const res = await getForWData(item)
+      if (res.error_code === 0) {
+        // -1:预测失败;0:默认;1:有未查看得预测数据并返回id;2:正在预测中
+        if (res.data.status === 1) {
+          this.fid = res.data.id
+          this.getProForWResult(res.data.id)
+        } else if (res.data.status === 2) {
+          this.getProForWStatus()
+        } else {
+          this.$message.error('预测失败')
+        }
+      }
+    },
+    getProForWStatus () {
+      const timer = setInterval(() => {
+        getForWStatus().then(res => {
+          console.log(res)
+          if (res.error_code === 0) {
+            if (res.data.success) {
+              this.fid = res.data.id
+              this.getProForWResult(res.data.id)
+              clearInterval(timer)
+            }
+          }
+        })
+      }, 5000)
+    },
+    getProForWResult (id) {
+      getForWResult({ id: id }).then(res => {
+        console.log(res)
+        if (res.error_code === 0) {
+          this.resData = res.data.responseData
+        }
+      })
     }
   }
 }
 </script>
 
 <style lang="scss" scoped>
-.bid-forcast{
-  width: 100%;
+.bid-forcast-limit{
+  margin: 0 auto;
+  width: 1200px;
+  ::v-deep .listData{
+    margin-top: 20px;
+    background: #fff;
+  }
+  .bid_abstract{
+    padding: 32px 40px;
+    width: 100%;
+    background: #ffffff;
+    border-radius: 4px;
+    .bid_abs_title{
+      font-size: 18px;
+      font-family: Microsoft YaHei, Microsoft YaHei-Regular;
+      font-weight: 400;
+      text-align: LEFT;
+      color: #1d1d1d;
+      line-height: 28px;
+    }
+    .bid_abs_content{
+      border-top: 1px solid #ececec;
+      .bid_abs_inforone, .bid_abs_infortwo{
+        margin-top: 21px;
+      }
+      .bid_abs_inforone{
+        .bid_unitText{
+          padding: 2px 8px;
+          border-radius: 2px;
+          background: #FEF0E5;
+          font-size: 13px;
+          font-family: Microsoft YaHei, Microsoft YaHei-Regular;
+          font-weight: 400;
+          text-align: LEFT;
+          color: #f56500;
+          line-height: 20px;
+        }
+        .bid_unitname{
+          margin-left: 16px;
+          font-size: 18px;
+          font-family: Microsoft YaHei, Microsoft YaHei-Regular;
+          font-weight: 400;
+          text-align: LEFT;
+          color: #1d1d1d;
+          line-height: 28px;
+        }
+        .bid_view_unit{
+          margin-left: 20px;
+          width: 144px;
+          height: 32px;
+          opacity: 1;
+          background: #2cb7ca;
+          border-radius: 4px;
+          font-size: 14px;
+          font-family: Microsoft YaHei, Microsoft YaHei-Regular;
+          font-weight: 400;
+          text-align: CENTER;
+          color: #ffffff;
+          line-height: 32px;
+        }
+      }
+      .bid_abs_infortwo{
+        display: flex;
+        align-items: center;
+        .bid_abs_base{
+          margin-right: 40px;
+          display: flex;
+          align-items: center;
+          .base_label{
+            font-size: 13px;
+            font-family: Microsoft YaHei, Microsoft YaHei-Regular;
+            font-weight: 400;
+            text-align: LEFT;
+            color: #999999;
+            line-height: 20px;
+          }
+          .base_main{
+            color: #1D1D1D;
+          }
+        }
+      }
+    }
+  }
 }
 </style>

+ 29 - 18
src/views/bid-policy/AnalysisResult.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="analysis-result">
-    <ForLimit :baseInfo="baseInfo"></ForLimit>
-    <div class="digest">
+    <ForLimit :baseInfo="baseInfo" @getLimit="getLimit"></ForLimit>
+    <div class="digest" v-show="proShow">
       <div class="digest_head">项目摘要</div>
       <ul class="digest_ul">
         <li class="digest_list">
@@ -27,16 +27,18 @@
         </li>
       </ul>
     </div>
-    <div class="result">
+    <div class="result" v-show="proShow">
       <el-tabs v-model="activeName" @tab-click="handleClick">
         <el-tab-pane label="类似项目分析" name="1">
           <div class="tab-item">
-            <AnalysisDetailList></AnalysisDetailList>
+            <AnalysisDetailList :PDeatils="propsDetails" v-if="flag.details"></AnalysisDetailList>
+            <Empty v-if="!flag.details"></Empty>
           </div>
         </el-tab-pane>
         <el-tab-pane label="类似项目明细" name="2">
           <div class="tab-item">
             <analysis-chart v-if="flag.charts" :active="activeName" :datas="propAnalysis" :info="baseInfo"></analysis-chart>
+            <Empty v-if="!flag.charts"></Empty>
           </div>
         </el-tab-pane>
       </el-tabs>
@@ -47,6 +49,7 @@
 import AnalysisChart from '../portrayal/components/AnalysisChart'
 import AnalysisDetailList from '../portrayal/components/AnalysisDetailList'
 import ForLimit from '@/components/forecast/ForLimit'
+import Empty from '@/components/common/Empty'
 import { Tabs, TabPane } from 'element-ui'
 // 该页面需要调用的接口
 import { getFollowInfo, addFollow, cancelFollow, getProjectInfo, getAnalysisResult } from '@/api/modules/' // eslint-disable-line
@@ -57,7 +60,8 @@ export default {
     [TabPane.name]: TabPane,
     AnalysisChart,
     ForLimit,
-    AnalysisDetailList
+    AnalysisDetailList,
+    Empty
   },
   data () {
     return {
@@ -72,14 +76,16 @@ export default {
         charts: false,
         details: false
       },
-      ptid: this.$route.path.split('/')[3], // 项目加密id
-      sid: this.$route.path.split('/')[4] // 信息加密id
+      // 刚开始隐藏项目摘要和tab切换
+      proShow: false,
+      ptid: this.$route.path.split('/')[this.$route.path.split('/').length - 2], // 项目加密id
+      sid: this.$route.path.split('/')[this.$route.path.split('/').length - 1] // 信息加密id
     }
   },
   computed: {},
   created () {
     this.getBaseInfo()
-    this.getResult()
+    // this.getResult()
   },
   mounted () {},
   methods: {
@@ -88,7 +94,6 @@ export default {
     },
     // 获取项目基本信息
     async getBaseInfo () {
-      console.log(this.$route.path.split('/')[3])
       const data = {
         ptid: this.ptid,
         sourceinfoid: this.sid,
@@ -106,41 +111,47 @@ export default {
         console.log(res.error_code)
       }
     },
+    // 获取筛选条件
+    getLimit (data) {
+      this.getResult(data)
+    },
     // 获取分析结果
-    async getResult () {
+    async getResult (item) {
       const data = {
         appVersion: '',
-        area: {},
-        buyer: '河南省人民医院',
+        area: item.area,
+        buyer: item.buyer,
         buyerClass: [],
         buyerContent: [{ key: ['医药'], appendkey: [], notkey: [] }, { key: ['器械'], appendkey: [], notkey: [] }, { key: ['办公'], appendkey: [], notkey: [] }, { key: ['绿化'], appendkey: [], notkey: [] }, { key: ['器材'], appendkey: [], notkey: [] }, { key: ['设备'], appendkey: [], notkey: [] }],
         industry: '',
         maxPrice: '',
         minPrice: '',
         mobileModel: '',
-        pid: 'ABCY2FdcC4vIyM7NFV2dXJaJCQCTBFgV3NiKDg7LyEdfFZzcytUCiE%3D',
-        pname: '河南省人民医院',
-        sid: 'ABCY2EFYy4eAjg7JFphcHUJJzACHj1mZnB%2FKSg0PC9Fa3xwTwFUCVk%3D'
+        pid: this.baseInfo.id,
+        pname: this.baseInfo.projectname,
+        sid: this.baseInfo.infoid
       }
       const res = await getAnalysisResult(data)
       if (res.error_code === 0) {
+        this.proShow = true
         if (res.data.status === -2) {
           console.log('不展示')
-          this.showDetails = false
+          this.flag.details = false
           this.showChart = false
         }
         // 类似项目明细数据
         if (res.data.PDeatils) {
+          this.flag.details = true
           this.propsDetails = res.data.PDeatils
         } else {
-          this.showDetails = false
+          this.flag.details = false
         }
         // 类似项目分析
         if (res.data.PAnalysis && Object.keys(res.data.PAnalysis).length > 0) {
           this.propAnalysis = res.data.PAnalysis
           this.flag.charts = true
         } else {
-          this.showChart = false
+          this.flag.charts = false
         }
       }
     }

+ 19 - 3
src/views/portrayal/EntPortrayal.vue

@@ -23,7 +23,7 @@
             </ul>
             <div class="pro_info_tip">数据统计范围:{{dateRange.start}}-{{dateRange.end}}</div>
           </div>
-          <ProActive></ProActive>
+          <ProActive title="项目动态" :projectData="project"></ProActive>
           <ent-chart :active="activeName" v-on:entInfo="getEntInfo"></ent-chart>
         </el-tab-pane>
       </el-tabs>
@@ -36,8 +36,8 @@ import EntForm from './components/EntForm'
 import EntHistoryForm from './components/EntHistoryForm'
 import ProActive from './components/ProActive'
 import { Tabs, TabPane } from 'element-ui'
-import { moneyUnit, dateFormatter } from '@/utils'
-import { setFollowEnt, setCancelEnt } from '@/api/modules'
+import { getParam, moneyUnit, dateFormatter } from '@/utils'
+import { setFollowEnt, setCancelEnt, getNewMsg } from '@/api/modules'
 export default {
   name: 'ent-portrayal',
   components: {
@@ -52,6 +52,10 @@ export default {
     return {
       activeName: '1',
       proData: [],
+      project: {
+        proActiveList: [],
+        count: 0
+      },
       dateRange: { // 数据统计范围
         start: 0,
         end: 0
@@ -63,12 +67,24 @@ export default {
     }
   },
   computed: {},
+  created () {
+    this.getProActivcList()
+  },
   mounted () {
   },
   methods: {
     handleClick () {
       console.log(this.activeName)
     },
+    getProActivcList () {
+      getNewMsg({ entId: decodeURIComponent(getParam('eId')), pageSize: 5 }).then(res => {
+        console.log(res)
+        if (res.error_code === 0) {
+          this.project.proActiveList = res.data.list
+          this.project.count = res.data.count
+        }
+      })
+    },
     getEntInfo (data) {
       console.log(data)
       this.proData = [

+ 104 - 2
src/views/portrayal/components/AnalysisChart.vue

@@ -1,5 +1,16 @@
 <template>
   <div class="analysis-chart">
+    <div class="pro_info">
+      <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">数据统计范围:2018/01/01至今</div>
+    </div>
+    <!-- 中国移动通信集团终端有限公司类似项目采购历史 -->
+    <ProActive title="中国移动通信集团终端有限公司类似项目采购历史" :projectData="datas"></ProActive>
     <!-- 类似项目标书编制周期分布 -->
     <div v-if="bidCycle.show">
       <div class="chart-title">类似项目标书编制周期分布</div>
@@ -46,9 +57,10 @@ import ColumnBarChart from '@/components/chart/ColumnBarChart'
 import HotChart from '@/components/chart/HotChart'
 import MapChart from '@/components/chart/MapChart'
 import PieChart from '@/components/chart/PieChart'
+import ProActive from './ProActive'
 import HotWinList from './AnalysisList'
 import BlueProgressChart from '@/components/chart/BlueProgressChart'
-import { moneyUnit } from '@/utils/'
+import { moneyUnit, dateFormatter } from '@/utils/'
 export default {
   name: 'analysis-chart',
   props: ['active', 'datas', 'info'],
@@ -57,11 +69,13 @@ export default {
     HotChart,
     MapChart,
     PieChart,
+    ProActive,
     HotWinList,
     BlueProgressChart
   },
   data () {
     return {
+      proData: [],
       // 类似项目标书编制周期分布
       bidCycle: {
         show: false,
@@ -128,6 +142,9 @@ export default {
       }
     }
   },
+  created () {
+    this.getEntInfo(this.datas)
+  },
   watch: {
     active: {
       handler (newVal) {
@@ -136,12 +153,35 @@ export default {
         }
       },
       deep: true
+    },
+    datas (newVal, oldVal) {
+      this.getEntInfo(newVal)
     }
   },
   computed: {},
-  created () {},
   mounted () {},
   methods: {
+    getEntInfo (data) {
+      console.log(data)
+      this.proData = [
+        {
+          label: '项目数量',
+          count: data.all_counts + '个'
+        },
+        {
+          label: '项目金额',
+          count: moneyUnit(data.all_money)
+        },
+        {
+          label: '涉及中标企业',
+          count: data.all_winners + '个'
+        },
+        {
+          label: '涉及评标专家',
+          count: data.all_review_experts + '人'
+        }
+      ]
+    },
     // 处理图表数据
     initChartData () {
       this.formatBidCycleData(this.datas.bidcycle_ranges)
@@ -418,5 +458,67 @@ export default {
     line-height: 20px;
     text-align: center;
   }
+  .pro_info{
+      width: 100%;
+      height: 171px;
+      .pro_info_ul{
+        display: flex;
+        justify-content: space-between;
+        width: 100%;
+        background: #fff;
+        .pro_list{
+          position: relative;
+          display: flex;
+          flex-direction: column;
+          align-items: center;
+          justify-content: center;
+          margin-top: 32px;
+          width: 210px;
+          height: 78px;
+          .pro_li_con{
+            font-size: 20px;
+            font-family: Microsoft YaHei, Microsoft YaHei-Regular;
+            font-weight: 400;
+            color: #2cb7ca;
+            line-height: 32px;
+          }
+          .pro_li_label{
+            font-size: 14px;
+            font-family: Microsoft YaHei, Microsoft YaHei-Regular;
+            font-weight: 400;
+            color: #686868;
+            line-height: 22px;
+          }
+        }
+        .pro_list:after{
+          content: '';
+          position: absolute;
+          right: 0;
+          width: 0px;
+          height: 46px;
+          border: 0.5px solid #ececec;
+        }
+        .pro_list:nth-child(4)::after{
+          content: '';
+          position: absolute;
+          right: 0;
+          width: 0px;
+          height: 46px;
+          border: 0px solid #ececec;
+        }
+      }
+      .pro_info_tip{
+        margin: 27px auto;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        width: 840px;
+        height: 17px;
+        font-size: 12px;
+        font-family: Microsoft YaHei, Microsoft YaHei-Regular;
+        font-weight: 400;
+        color: #999999;
+      }
+    }
 }
 </style>

+ 113 - 62
src/views/portrayal/components/AnalysisDetailList.vue

@@ -1,42 +1,55 @@
 <template>
   <div class="analysis-list">
-    <div class="analysis-list_main" v-for="(data, i) in 3" :key="i">
+    <div class="analysis-list_main" v-for="(data, i) in listState.list.slice((listState.pageNum - 1) * listState.pageSize, listState.pageNum * listState.pageSize)" :key="i">
       <div class="analy_head">
-        <div class="analy_head_title">福州市市场监督管理局福州市市场监管综合业务平台服务类采购项目</div>
+        <div class="analy_head_title">{{data.projectname}}</div>
         <div class="analy_head_infone">
           <div class="infone_type">
             <span class="infone_type_label">采购方式:</span>
-            <span class="infone_type_answer">招标</span>
+            <span class="infone_type_answer">{{data.bidtype?data.bidtype:'--'}}</span>
           </div>
           <div class="infone_type">
             <span class="infone_type_label">项目时间:</span>
-            <span class="infone_type_answer">2020-07-06</span>
+            <span class="infone_type_answer">{{data.firsttime?dateFormatter(data.firsttime*1000, 'yyyy-MM-dd'):'--'}}</span>
           </div>
           <div class="infone_type">
             <span class="infone_type_label">评审专家:</span>
-            <span class="infone_type_answer">吴碧文,宁正元,杨荣华,林军,许清,郑茜颖</span>
+            <span class="infone_type_answer">
+              {{data.review_experts?data.review_experts + '':'--'}}
+            </span>
           </div>
         </div>
         <div class="analy_head_infone">
           <div class="infone_type">
             <span class="infone_type_label">中标企业:</span>
-            <span class="infone_type_after">新东网科技有限公司</span>
-            <span class="infone_type_other">福建通信信息报社有限责任公司</span>
+            <div class="infone_type_list">
+              <span class="infone_type_after" v-for="(s_winner, index) in data.s_winner" :key="index">{{s_winner}}</span>
+            </div>
           </div>
         </div>
       </div>
       <div class="pro_info">
         <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 class="pro_list">
+            <div class="pro_li_con">{{data.budget}}</div>
+            <div class="pro_li_label">预算 (万元)</div>
+          </li>
+          <li class="pro_list">
+            <div class="pro_li_con">{{data.bidamount}}</div>
+            <div class="pro_li_label">中标价 (万元)</div>
+          </li>
+          <li class="pro_list">
+            <div class="pro_li_con">{{data.project_rate}}</div>
+            <div class="pro_li_label">折扣率</div>
           </li>
         </ul>
         <div class="pro_info_footer">
           <span class="infone_type_label">中标候选人:</span>
-          <span class="infone_type_after">深圳天源迪科信息技术股份有限公司</span>
-          <span class="infone_type_after">福建三元达科技有限公司</span>
-          <span class="infone_type_other">福建宏创科技信息有限公司</span>
+          <div class="infone_type_list">
+            <span class="infone_type_after" v-for="(winner, index) in data.winnerorder" :key="index">{{winner}}</span>
+          </div>
+          <!-- <span class="infone_type_after">福建三元达科技有限公司</span>
+          <span class="infone_type_other">福建宏创科技信息有限公司</span> -->
         </div>
       </div>
     </div>
@@ -59,55 +72,61 @@
 import { moneyUnit, dateFormatter } from '@/utils'
 import { Pagination } from 'element-ui'
 export default {
+  props: ['PDeatils'],
   name: 'analysis-list',
   components: {
     [Pagination.name]: Pagination
   },
   data () {
     return {
-      proData: [
-        {
-          label: '预算 (万元)',
-          count: 222
-        },
-        {
-          label: '中标价 (万元)',
-          count: 222
-        },
-        {
-          label: '折扣率',
-          count: 222
-        }
-      ],
       listState: {
         loaded: true, // 是否已经搜索过
         loading: false,
         pageNum: 1, // 当前页
         pageSize: 10, // 每页多少条数据
-        total: 20, // 一共多少条数据
+        total: 0, // 一共多少条数据
         list: [] // 查询请求返回的数据
       }
     }
   },
+  created () {
+    this.initData(this.PDeatils)
+  },
+  watch: {
+    PDeatils (newVal, oldVal) {
+      this.initData(newVal)
+    }
+  },
   methods: {
-    getEntInfo (data) {
-      console.log(data)
-      this.proData = [
-        {
-          label: '预算 (万元)',
-          count: data.project_count
-        },
-        {
-          label: '中标价 (万元)',
-          count: moneyUnit(data.bidamount_count)
-        },
-        {
-          label: '折扣率',
-          count: data.area_count
+    dateFormatter,
+    moneyUnit,
+    initData (list) {
+      list.forEach(function (item, index) {
+        let entBid = []
+        if (!item.s_winner) {
+          entBid = item.s_winner.split(',')
+          list[index].s_winner = entBid
+        } else {
+          list[index].s_winner = []
+        }
+        if (item.budget) {
+          item.budget = moneyUnit(item.budget).substring(0, (moneyUnit(item.budget) + '').length - 2)
+        } else {
+          item.budget = '--'
+        }
+        if (item.bidamount) {
+          item.bidamount = moneyUnit(item.bidamount).substring(0, (moneyUnit(item.bidamount) + '').length - 2)
+        } else {
+          item.bidamount = '--'
         }
-      ]
-      this.dateRange.start = dateFormatter(data.timeRange.start * 1000, 'yyyy/MM/dd')
-      this.dateRange.end = dateFormatter(data.timeRange.end * 1000, 'yyyy/MM/dd')
+        if (item.project_rate) {
+          item.project_rate = Number((item.project_rate * 100)).toFixed(2) + '%'
+        } else {
+          item.project_rate = '--'
+        }
+      })
+      this.listState.list = list
+      this.listState.total = list.length
     },
     onPageChange (p) {
       this.listState.pageNum = p
@@ -147,10 +166,19 @@ export default {
           color: #9b9ca3;
           line-height: 20px;
           text-shadow: 0px -1px 0px 0px rgba(0,0,0,0.05) inset;
+          .infone_type_list{
+            flex: 1;
+            display: flex;
+            align-items: flex-start;
+            flex-wrap: wrap;
+            height: 100%;
+            line-height: 20px;
+          }
           .infone_type_answer, .infone_type_after, .infone_type_other{
             color: #2ABED1;
           }
           .infone_type_after{
+            margin-right: 10px;
             padding-right: 10px;
             position: relative;
             display: flex;
@@ -164,15 +192,19 @@ export default {
             height: 14px;
             border-right: 1px solid #E3E4E5;
           }
-          .infone_type_other{
-            margin-left: 10px;
+          .infone_type_after:last-of-type::after {
+            content: '';
+            position: absolute;
+            right: 0;
+            width: 0px;
+            height: 12px;
+            border: 0px solid #ececec;
           }
         }
       }
     }
     .pro_info{
       width: 100%;
-      height: 128px;
       .pro_info_ul{
         display: flex;
         justify-content: space-between;
@@ -222,30 +254,49 @@ export default {
       }
       .pro_info_footer{
         display: flex;
-        align-items: center;
+        align-items: flex-start;
         margin-top: 12px;
         width: 100%;
-        height: 20px;
+        min-height: 20px;
         font-size: 12px;
         font-family: Microsoft YaHei, Microsoft YaHei-Regular;
         font-weight: 400;
         color: #5F5E64;
+        // line-height: 20px;
         .infone_type_label{
+          line-height: 20px;
           color: #9B9CA3;
         }
-        .infone_type_after{
-          position: relative;
+        .infone_type_list{
+          flex: 1;
           display: flex;
-          padding-right: 10px;
-          margin-right: 10px;
-        }
-        .infone_type_after::after{
-          content: '';
-          position: absolute;
-          right: 0;
-          width: 0px;
-          height: 12px;
-          border: 0.5px solid #ececec;
+          align-items: flex-start;
+          flex-wrap: wrap;
+          height: 100%;
+          line-height: 20px;
+          .infone_type_after{
+            position: relative;
+            display: flex;
+            padding-right: 10px;
+            margin-right: 10px;
+          }
+          .infone_type_after::after{
+            content: '';
+            position: absolute;
+            top: 4px;
+            right: 0;
+            width: 0px;
+            height: 12px;
+            border: 0.5px solid #ececec;
+          }
+          .infone_type_after:last-of-type::after {
+            content: '';
+            position: absolute;
+            right: 0;
+            width: 0px;
+            height: 12px;
+            border: 0px solid #ececec;
+          }
         }
       }
     }

+ 29 - 21
src/views/portrayal/components/ProActive.vue

@@ -1,10 +1,10 @@
 <template>
   <div class="proactive">
     <div class="pro_active_head">
-      项目动态
+      {{title}}
     </div>
-    <div class="pro_ul">
-      <div class="pro_list" v-for="(item, index) in listState.list" :key="index">
+    <div class="pro_ul" v-if="!isShow">
+      <div class="pro_list" v-for="(item, index) in listState.list.slice((listState.pageNum - 1) * listState.pageSize, listState.pageNum * listState.pageSize)" :key="index">
         <div class="pro_li_title">{{item.title}}</div>
         <div class="pro_li_info">
           <div class="li_left">
@@ -30,17 +30,19 @@
       >
       </el-pagination>
     </div>
+    <Empty v-if="isShow"></Empty>
   </div>
 </template>
 
 <script>
 import { Pagination } from 'element-ui'
-import { getNewMsg } from '@/api/modules'
-import { getParam, moneyUnit, dateFormatter } from '@/utils/'
+import Empty from '@/components/common/Empty'
 export default {
+  props: ['projectData', 'title'],
   name: 'proactive',
   components: {
-    [Pagination.name]: Pagination
+    [Pagination.name]: Pagination,
+    Empty
   },
   data () {
     return {
@@ -48,28 +50,34 @@ export default {
         loaded: true, // 是否已经搜索过
         loading: false,
         pageNum: 1, // 当前页
-        pageSize: 10, // 每页多少条数据
+        pageSize: 5, // 每页多少条数据
         total: 0, // 一共多少条数据
         list: [] // 查询请求返回的数据
-      }
+      },
+      isShow: false
     }
   },
   created () {
-    this.getProActivcList()
+    this.initData(this.projectData)
+  },
+  watch: {
+    projectData (newVal, oldVal) {
+      this.initData(newVal)
+    }
   },
   methods: {
-    moneyUnit,
-    dateFormatter,
-    getProActivcList () {
-      // let paramas = {
-      // }
-      getNewMsg({ entId: decodeURIComponent(getParam('eId')), pageSize: 5 }).then(res => {
-        console.log(res)
-        if (res.error_code === 0) {
-          this.listState.list = res.data.list
-          this.listState.total = res.data.count
-        }
-      })
+    initData (obj) {
+      if (obj.proActiveList && obj.proActiveList.length !== 0) {
+        this.listState.list = obj.proActiveList
+        this.listState.total = obj.count
+        this.isShow = false
+      } else if (obj.buyerHistroyList && obj.buyerHistroyList !== 0) {
+        this.listState.list = obj.buyerHistroyList
+        this.listState.total = obj.buyerHistroyList.length
+        this.isShow = false
+      } else {
+        this.isShow = true
+      }
     },
     onPageChange (p) {
       this.listState.pageNum = p